Skip to content

Commit 5af590e

Browse files
MagnusrmlassopicassoOle Martin Handelandcoderabbitai[bot]
authored
Feat/image-upload-component (#3654)
* Image upload component wip * update cropping component * add circle config * move eventlisteners to canvas * explicit use of constrainToArea * further refactor image upload component * add common utils for draw and handlecrop functions + variable viewport (#3657) * add common utils for draw and handlecrop functions + variable viewportsimplify mouse dragging and support touch dragging (#3656) * extract functions to utils (#3663) * implement cropAsConfig prop into viewport config (#3662) * prevent scrolling (#3658) * Feat/refine image upload buttons according to design (#3660) * reuse dropzonecomponent and display only when imgsrc is not defined * bring back the reset button * move controller section to its own file * Move the image cropper into a card (#3665) * move image cropper into card wip * working cropping component in card * conforrm to styling naming in repo * canvas height adjustment --------- Co-authored-by: lassopicasso <[email protected]> * clean up css and style closer to figma design (#3669) * clean up css and style closer to figma design * added save and cancel buttons with functionality (some left for save fn) (#3668) * added save and cancel buttons with functionality (some left for save fn) * Adding AttachmentsPlugin to ImageUpload component (it needs to be defined as a form component for this to work, which is more fitting) * save cropped image to backend * feedback * small fix --------- Co-authored-by: Ole Martin Handeland <[email protected]> * Redesign slider + buttons in img controller (#3671) * added save and cancel buttons with functionality (some left for save fn) * Adding AttachmentsPlugin to ImageUpload component (it needs to be defined as a form component for this to work, which is more fitting) * save cropped image to backend * redesign slider + buttons --------- Co-authored-by: Ole Martin Handeland <[email protected]> * Extract canvas and effects into its own component (#3674) * wip * revert unneccesary change * clean up * feat/ handle saved image and new display when image is saved (#3675) * add hook that handles the saved image and controllers buttons when saved * add check at higher level for stored image (#3680) * zoom to the center of viewport (#3681) * Feat/custom crop area config + renaming (#3682) * support custom config * support mismatch of height and width if type is circle * Feat/remove-dropzone-icon-and-change-background (#3679) * remove dropzone icon and refactor css * replace look of placeholder * remove unused css * remove focus for now * fix zooming limits (#3684) * fix: active pointer canvas and keyboard support on change image (#3683) * cursor change to grabbing when active in canvas * make change image button support keyboard * update icons * Add validationmessages for imageupload size and types (#3687) * add validationmessages for imageupload size and types * clear validationmessages on cancel * Feat/use-language-for-component-texts (#3689) * add language texts and use them throughout the component * change wording slightly and remove unused text * make file-endings the same * Display uploaded image+more (#3690) * push branch * utilize storedImage * adjustments * refactor: calculations (#3697) * remove imageSrc, imageRef takes its place * add handle cancel function * add new utilities * move validation to a utility and connect better the logic for image state * feat: Support config (#3700) * support config * remove rendudant useEffect * small adjustment * change config from one object to 3 props * New dropzone using the new figma design (#3708) * rename imagecropper to match filename * merge dropzone with placeholder wip * add border to placeholder * create image dropzone with new design * Update src/layout/ImageUpload/ImageDropzone.module.css Co-authored-by: Lars <[email protected]> --------- Co-authored-by: Lars <[email protected]> * clean up comment, fix text-alignment * remove redundant css class * fix cropped preview * feat: Handle canvas size based on grid or mobile viewport and use filename (#3706) * handle canvas on mobile viewport * save filename * canvas width is decided by container, so it supports grid behavior as well * add unit tests and fix validation (#3714) * add unit tests and fix validation * feedback * Add displaydata expression test to ImageUpload (#3719) * adjust to equal height and width if circle and they are uneven * fix duplicate ids and use ref instead of getElementById * clean up css * fix sizing * use unique id, remove preventDefault for dropzone * remove a type-casting * add accesible title to reset zoom button * remove redundant css * fix change image button * add cypress tests for image upload component (#3721) * make filetypes the same Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * make filetypes match Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * support summary2 (#3725) * support summary2 * small adjustments * support validFileEndings config * replace chess background when image is saved * fix edge case where canvas gets too low between 1160-1200px when grid is used half of width * simplify responsivness and keep fixed size of the canvas * set min zoom as default * remove error message when save * add tests for imageupload in summary2 * reverse validfileendings config support * add cypress test where replacing image * react recommendations * add utility tests * remove some comments * add specific image types to be allowed * small adjustment * new summary of image upload, show image * some text changes * update tests for new summary of image upload * check for possible animation file type and inform user that only first frame is used * support readOnly config * fix test * rabbit feedback * rename config from square to rectangle * make useFileUploaderDataBindingsValidation support ImageUpload as well * Better error message for imageUpload is not supported in summary component * check that allowedContentTypes in app meta data is valid when rendering image upload * remove emojis in css comments * move logic out of jsx into a function * rename css class * text resource to aria-label * move existing canvas files into own folder * refactor image canvas * move zoom calculation to a utility helper * refactor imageCropper * --ds-color-neutral-background-tinted * adjust zoom behavior * reverse change in fileTable, not needed anymore * update config to use oneOf and update code related to this * rabbit feedback - ensure draw after image is completly uploaded to browser * rabbit feedback - !!readOnly is redudant - keep only readOnly * rabbit feedback - ensure better quality on saved image with imageSmoothing from canvas * rabbit feedback - not necessary, but adding a fallback to imageType * move useImageFile to hooks folder * move imageUploadSummary2 into a folder * rabbit feedback - naming type * small adjustment * adjust the size of slider --------- Co-authored-by: Lars <[email protected]> Co-authored-by: lassopicasso <[email protected]> Co-authored-by: Ole Martin Handeland <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 928c63b commit 5af590e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2049
-20
lines changed

src/app-components/Card/Card.module.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
.mediaCard {
22
padding: 0;
3-
margin-bottom: -7px;
43
}
54
.mediaCard img {
65
object-fit: cover;

src/app-components/Card/Card.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ type AppCardProps = {
1313
color?: Parameters<typeof Card>[0]['color'];
1414
children?: React.ReactNode;
1515
variant?: 'tinted' | 'default';
16+
className?: string;
17+
ref?: React.Ref<HTMLDivElement>;
1618
};
1719

1820
export function AppCard({
@@ -24,11 +26,15 @@ export function AppCard({
2426
mediaPosition = 'top',
2527
children,
2628
variant = 'tinted',
29+
className,
30+
ref,
2731
}: AppCardProps) {
2832
return (
2933
<Card
3034
data-color={color}
3135
variant={variant}
36+
className={className}
37+
ref={ref}
3238
>
3339
{media && mediaPosition === 'top' && <Card.Block className={classes.mediaCard}>{media}</Card.Block>}
3440
<Card.Block>

src/app-components/Dropzone/Dropzone.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,21 @@ import type { FileRejection } from 'react-dropzone';
66
import cn from 'classnames';
77

88
import classes from 'src/app-components/Dropzone/Dropzone.module.css';
9-
import { mapExtensionToAcceptMime } from 'src/app-components/Dropzone/mapExtensionToAcceptMime';
109

1110
type MaxFileSize = {
1211
sizeInMB: number;
1312
text: string;
1413
};
1514

16-
export type IDropzoneComponentProps = {
15+
export type IDropzoneProps = {
1716
id: string;
1817
maxFileSize?: MaxFileSize;
1918
readOnly: boolean;
20-
onClick: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
19+
onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
2120
onDrop: (acceptedFiles: File[], rejectedFiles: FileRejection[]) => void;
21+
onDragActiveChange?: (isDragActive: boolean) => void;
2222
hasValidationMessages: boolean;
23-
hasCustomFileEndings?: boolean;
24-
validFileEndings?: string | string[];
23+
acceptedFiles?: { [key: string]: string[] };
2524
labelId?: string;
2625
describedBy?: string;
2726
className?: string;
@@ -35,15 +34,15 @@ export function Dropzone({
3534
readOnly,
3635
onClick,
3736
onDrop,
37+
onDragActiveChange,
3838
hasValidationMessages,
39-
hasCustomFileEndings,
40-
validFileEndings,
39+
acceptedFiles,
4140
labelId,
4241
children,
4342
className,
4443
describedBy,
4544
...rest
46-
}: IDropzoneComponentProps): React.JSX.Element {
45+
}: IDropzoneProps): React.JSX.Element {
4746
const maxSizeLabelId = `file-upload-max-size-${id}`;
4847
const describedby =
4948
[describedBy, maxFileSize?.sizeInMB ? maxSizeLabelId : undefined].filter(Boolean).join(' ') || undefined;
@@ -52,9 +51,16 @@ export function Dropzone({
5251
onDrop,
5352
maxSize: maxFileSize && maxFileSize.sizeInMB * bytesInOneMB,
5453
disabled: readOnly,
55-
accept:
56-
hasCustomFileEndings && validFileEndings !== undefined ? mapExtensionToAcceptMime(validFileEndings) : undefined,
54+
accept: acceptedFiles,
5755
});
56+
57+
// set drag active state in parent component if callback is provided
58+
React.useEffect(() => {
59+
if (onDragActiveChange) {
60+
onDragActiveChange(isDragActive);
61+
}
62+
}, [isDragActive, onDragActiveChange]);
63+
5864
return (
5965
<div>
6066
{maxFileSize && (
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "Display value of FileUpload component",
3+
"expression": [
4+
"displayValue",
5+
"image"
6+
],
7+
"context": {
8+
"component": "image",
9+
"currentLayout": "Page"
10+
},
11+
"expects": "my-image.jpg",
12+
"layouts": {
13+
"Page": {
14+
"$schema": "https://altinncdn.no/schemas/json/layout/layout.schema.v1.json",
15+
"data": {
16+
"layout": [
17+
{
18+
"id": "image",
19+
"type": "ImageUpload"
20+
}
21+
]
22+
}
23+
}
24+
},
25+
"instanceDataElements": [
26+
{
27+
"id": "bb2b2222-2b22-2b22-222b-222222222222",
28+
"instanceGuid": "aa1a1111-1a11-1a11-111a-111111111111",
29+
"dataType": "image",
30+
"filename": "my-image.jpg",
31+
"contentType": "image/jpeg",
32+
"blobStoragePath": "",
33+
"size": 100,
34+
"locked": false,
35+
"refs": [],
36+
"created": "2021-01-01T00:00:00.000Z",
37+
"createdBy": "testUser",
38+
"lastChanged": "2021-01-01T00:00:00.000Z",
39+
"lastChangedBy": "testUser"
40+
}
41+
]
42+
}

src/language/texts/en.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,17 @@ export function en() {
208208
'iframe_component.unsupported_browser_title': 'Your browser is unsupported',
209209
'iframe_component.unsupported_browser':
210210
'Your browser does not support iframes that use srcdoc. This may result in not being able to see all the content intended to be displayed here. We recommend trying a different browser.',
211+
'image_upload_component.animated_warning': 'If the image is animated, only the first frame will be shown.',
212+
'image_upload_component.button_change': 'Change image',
213+
'image_upload_component.button_delete': 'Delete image',
214+
'image_upload_component.button_save': 'Save image',
215+
'image_upload_component.crop_area': 'Crop area',
216+
'image_upload_component.slider_zoom': 'Zoom',
217+
'image_upload_component.summary_empty': "You haven't uploaded an image",
218+
'image_upload_component.reset': 'Reset position and zoom',
219+
'image_upload_component.error_invalid_file_type': 'Invalid file format. Please upload an image file.',
220+
'image_upload_component.error_file_size_exceeded': 'File size exceeds 10MB limit.',
221+
'image_upload_component.valid_file_types': 'Image files only',
211222
'input_components.remaining_characters': 'You have %d characters left',
212223
'input_components.exceeded_max_limit': 'You have exceeded the maximum limit with %d characters',
213224
'instance_selection.changed_by': 'Changed by',

src/language/texts/nb.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function nb() {
7070
'form_filler.file_upload_valid_file_format_all': 'alle',
7171
'form_filler.file_uploader_add_attachment': 'Legg til flere vedlegg',
7272
'form_filler.file_uploader_drag': 'Dra og slipp eller',
73-
'form_filler.file_uploader_find': 'let etter fil',
73+
'form_filler.file_uploader_find': 'finn fil',
7474
'form_filler.file_uploader_list_delete': 'Slett vedlegg',
7575
'form_filler.file_uploader_delete_warning': 'Er du sikker på at du vil slette dette vedlegget?',
7676
'form_filler.file_uploader_delete_button_confirm': 'Ja, slett vedlegg',
@@ -209,6 +209,17 @@ export function nb() {
209209
'iframe_component.unsupported_browser_title': 'Nettleseren din støttes ikke',
210210
'iframe_component.unsupported_browser':
211211
'Nettleseren du bruker støtter ikke iframes som benytter seg av srcdoc. Dette kan føre til at du ikke ser all innholdet som er ment å vises her. Vi anbefaler deg å prøve en annen nettleser.',
212+
'image_upload_component.animated_warning': 'Hvis bildet er animert, vises bare det første bildet.',
213+
'image_upload_component.button_change': 'Bytt bilde',
214+
'image_upload_component.button_delete': 'Slett bildet',
215+
'image_upload_component.button_save': 'Lagre bilde',
216+
'image_upload_component.crop_area': 'Beskjæringsområde',
217+
'image_upload_component.slider_zoom': 'Tilpass bildet',
218+
'image_upload_component.summary_empty': 'Du har ikke lastet opp noe bilde',
219+
'image_upload_component.reset': 'Tilbakestill zoom og plassering',
220+
'image_upload_component.error_invalid_file_type': 'Ugyldig filformat. Last opp en bildefil.',
221+
'image_upload_component.error_file_size_exceeded': 'Filen er for stor. Største tillatte filstørrelse er 10MB.',
222+
'image_upload_component.valid_file_types': 'Bildefiler er tillatt',
212223
'input_components.remaining_characters': 'Du har %d tegn igjen',
213224
'input_components.exceeded_max_limit': 'Du har overskredet maks antall tegn med %d',
214225
'instance_selection.changed_by': 'Endret av',

src/language/texts/nn.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function nn() {
7070
'form_filler.file_upload_valid_file_format_all': 'alle',
7171
'form_filler.file_uploader_add_attachment': 'Legg til fleire vedlegg',
7272
'form_filler.file_uploader_drag': 'Dra og slepp eller',
73-
'form_filler.file_uploader_find': 'leit etter fil',
73+
'form_filler.file_uploader_find': 'finn fil',
7474
'form_filler.file_uploader_list_delete': 'Slett vedlegg',
7575
'form_filler.file_uploader_delete_warning': 'Er du sikker på at du vil sletta dette vedlegget?',
7676
'form_filler.file_uploader_delete_button_confirm': 'Ja, slett vedlegg',
@@ -209,6 +209,17 @@ export function nn() {
209209
'iframe_component.unsupported_browser_title': 'Nettlesaren din støttas ikkje',
210210
'iframe_component.unsupported_browser':
211211
'Nettlesaren di støttar ikkje iframes som brukar srcdoc. Dette kan føre til at du ikkje ser all innhaldet som er meint å visast her. Vi anbefalar deg å prøve ein annan nettlesar.',
212+
'image_upload_component.animated_warning': 'Hvis bildet er animert, vises bare det første bildet.',
213+
'image_upload_component.button_change': 'Bytt bilde',
214+
'image_upload_component.button_delete': 'Slett bildet',
215+
'image_upload_component.button_save': 'Lagre bilde',
216+
'image_upload_component.slider_zoom': 'Tilpass bildet',
217+
'image_upload_component.crop_area': 'Beskjæringsområde',
218+
'image_upload_component.summary_empty': 'Du har ikkje lasta opp noko bilde',
219+
'image_upload_component.reset': 'Tilbakestill zoom og plassering',
220+
'image_upload_component.error_invalid_file_type': 'Ugyldig filformat. Last opp ein bildefil.',
221+
'image_upload_component.error_file_size_exceeded': 'Fila er for stor. Største tillatte filstorleik er 10MB.',
222+
'image_upload_component.valid_file_types': 'Bildefiler er tillatne',
212223
'input_components.remaining_characters': 'Du har %d teikn igjen',
213224
'input_components.exceeded_max_limit': 'Du har overskride maks teikn med %d',
214225
'instance_selection.changed_by': 'Endra av',

src/layout/Cards/Cards.module.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ video {
1111
.cardMedia:last-of-type {
1212
margin-top: auto;
1313
}
14+
15+
.mediaCard {
16+
margin-bottom: -7px;
17+
}

src/layout/Cards/Cards.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AppCard } from 'src/app-components/Card/Card';
55
import { Flex } from 'src/app-components/Flex/Flex';
66
import { Lang } from 'src/features/language/Lang';
77
import { CardProvider } from 'src/layout/Cards/CardContext';
8+
import classes from 'src/layout/Cards/Cards.module.css';
89
import { ComponentStructureWrapper } from 'src/layout/ComponentStructureWrapper';
910
import { GenericComponent } from 'src/layout/GenericComponent';
1011
import { useHasCapability } from 'src/utils/layout/canRenderIn';
@@ -117,6 +118,7 @@ function CardItem({ baseComponentId, parentBaseId, isMedia, minMediaHeight }: Ca
117118
<div
118119
data-componentid={id}
119120
data-componentbaseid={baseComponentId}
121+
className={classes.mediaCard}
120122
>
121123
<GenericComponent
122124
baseComponentId={baseComponentId}

src/layout/FileUpload/FileUploadComponent.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ describe('File uploading components', () => {
473473
});
474474

475475
expect(screen.getByRole('presentation', { name: /attachment-title/i }).textContent).toMatch(
476-
'Dra og slipp eller let etter filTillatte filformater er: alle',
476+
'Dra og slipp eller finn filTillatte filformater er: alle',
477477
);
478478
});
479479

0 commit comments

Comments
 (0)