@lifesg/react-design-system 3.4.0 → 3.5.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/e-signature/e-signature-canvas.js +1 -1
- package/cjs/e-signature/e-signature-canvas.js.map +1 -1
- package/cjs/e-signature/e-signature.styles.js +19 -15
- package/cjs/e-signature/e-signature.styles.js.map +1 -1
- package/cjs/file-download/file-list-card/file-list-card.styles.js +1 -1
- package/cjs/file-download/file-list-card/file-list-card.styles.js.map +1 -1
- package/cjs/file-upload/file-item-edit.js +1 -1
- package/cjs/file-upload/file-item-edit.js.map +1 -1
- package/cjs/file-upload/file-item-edit.styles.js +12 -7
- package/cjs/file-upload/file-item-edit.styles.js.map +1 -1
- package/cjs/file-upload/file-list-item/file-list-item.js +1 -1
- package/cjs/file-upload/file-list-item/file-list-item.js.map +1 -1
- package/cjs/file-upload/file-list-item/file-list-item.styles.js +74 -52
- package/cjs/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
- package/cjs/file-upload/file-list.js +1 -1
- package/cjs/file-upload/file-list.js.map +1 -1
- package/cjs/file-upload/file-list.styles.js +4 -11
- package/cjs/file-upload/file-list.styles.js.map +1 -1
- package/cjs/file-upload/file-upload.js +1 -1
- package/cjs/file-upload/file-upload.js.map +1 -1
- package/cjs/form/form-label.style.js +11 -8
- package/cjs/form/form-label.style.js.map +1 -1
- package/cjs/theme/font-spec/specs/bookingsg-font-spec-set.js +1 -1
- package/cjs/theme/font-spec/specs/bookingsg-font-spec-set.js.map +1 -1
- package/cjs/theme/font-spec/specs/default-font-spec-set.js +1 -1
- package/cjs/theme/font-spec/specs/default-font-spec-set.js.map +1 -1
- package/cjs/theme/font-spec/specs/sgw-digital-lobby-font-spec-set.js +1 -1
- package/cjs/theme/font-spec/specs/sgw-digital-lobby-font-spec-set.js.map +1 -1
- package/cjs/typography/typography.styles.js +6 -6
- package/cjs/typography/typography.styles.js.map +1 -1
- package/e-signature/e-signature-canvas.js +1 -1
- package/e-signature/e-signature-canvas.js.map +1 -1
- package/e-signature/e-signature.styles.js +20 -16
- package/e-signature/e-signature.styles.js.map +1 -1
- package/file-download/file-list-card/file-list-card.styles.js +1 -1
- package/file-download/file-list-card/file-list-card.styles.js.map +1 -1
- package/file-upload/file-item-edit.d.ts +4 -1
- package/file-upload/file-item-edit.js +1 -1
- package/file-upload/file-item-edit.js.map +1 -1
- package/file-upload/file-item-edit.styles.js +21 -16
- package/file-upload/file-item-edit.styles.js.map +1 -1
- package/file-upload/file-list-item/file-list-item.d.ts +3 -1
- package/file-upload/file-list-item/file-list-item.js +1 -1
- package/file-upload/file-list-item/file-list-item.js.map +1 -1
- package/file-upload/file-list-item/file-list-item.styles.d.ts +14 -0
- package/file-upload/file-list-item/file-list-item.styles.js +67 -45
- package/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
- package/file-upload/file-list.d.ts +3 -0
- package/file-upload/file-list.js +1 -1
- package/file-upload/file-list.js.map +1 -1
- package/file-upload/file-list.styles.js +4 -11
- package/file-upload/file-list.styles.js.map +1 -1
- package/file-upload/file-upload.d.ts +1 -1
- package/file-upload/file-upload.js +1 -1
- package/file-upload/file-upload.js.map +1 -1
- package/file-upload/types.d.ts +5 -0
- package/form/form-label.style.js +12 -9
- package/form/form-label.style.js.map +1 -1
- package/package.json +1 -1
- package/theme/font-spec/specs/bookingsg-font-spec-set.js +1 -1
- package/theme/font-spec/specs/bookingsg-font-spec-set.js.map +1 -1
- package/theme/font-spec/specs/default-font-spec-set.js +1 -1
- package/theme/font-spec/specs/default-font-spec-set.js.map +1 -1
- package/theme/font-spec/specs/sgw-digital-lobby-font-spec-set.js +1 -1
- package/theme/font-spec/specs/sgw-digital-lobby-font-spec-set.js.map +1 -1
- package/typography/typography.styles.js +4 -4
- package/typography/typography.styles.js.map +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
"use strict";var e=require("styled-components"),i=require("@lifesg/react-icons/drag-handle"),o=require("@lifesg/react-icons/exclamation-circle-fill"),
|
|
1
|
+
"use strict";var e=require("styled-components"),i=require("@lifesg/react-icons/drag-handle"),o=require("@lifesg/react-icons/exclamation-circle-fill"),t=require("../../icon-button/icon-button.js"),r=require("../../theme/index.js"),n=require("../../typography/typography.js");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s=a(e);const l=s.default.li`
|
|
2
2
|
display: flex;
|
|
3
3
|
align-items: center;
|
|
4
4
|
width: 100%;
|
|
5
5
|
border: none;
|
|
6
6
|
|
|
7
7
|
&:not(:last-child) {
|
|
8
|
-
margin-bottom: ${
|
|
8
|
+
margin-bottom: ${r.Spacing["spacing-16"]};
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
${i=>i.$disabled&&"none"===i.$focusType?e.css`
|
|
@@ -23,42 +23,42 @@
|
|
|
23
23
|
// https://docs.dndkit.com/api-documentation/sensors/touch#recommendations
|
|
24
24
|
touch-action: manipulation;
|
|
25
25
|
`:void 0}
|
|
26
|
-
`,
|
|
27
|
-
margin-right: ${
|
|
26
|
+
`,d=s.default(i.DragHandleIcon)`
|
|
27
|
+
margin-right: ${r.Spacing["spacing-16"]};
|
|
28
28
|
height: 1.5rem;
|
|
29
29
|
width: 1.5rem;
|
|
30
|
-
color: ${
|
|
30
|
+
color: ${r.Colour.icon};
|
|
31
31
|
|
|
32
32
|
${i=>i.$active?e.css`
|
|
33
|
-
color: ${
|
|
33
|
+
color: ${r.Colour["icon-primary"]};
|
|
34
34
|
`:i.$disabled?e.css`
|
|
35
|
-
color: ${
|
|
35
|
+
color: ${r.Colour["icon-disabled"]};
|
|
36
36
|
`:void 0};
|
|
37
37
|
`,c=s.default.div`
|
|
38
|
-
background: ${
|
|
39
|
-
border: ${
|
|
40
|
-
border-radius: ${
|
|
41
|
-
padding: ${
|
|
38
|
+
background: ${r.Colour["bg-primary-subtlest"]};
|
|
39
|
+
border: ${r.Border["width-010"]} ${r.Border.solid} ${r.Colour.border};
|
|
40
|
+
border-radius: ${r.Radius.sm};
|
|
41
|
+
padding: ${r.Spacing["spacing-16"]} ${r.Spacing["spacing-32"]};
|
|
42
42
|
display: flex;
|
|
43
43
|
align-items: center;
|
|
44
44
|
width: 100%;
|
|
45
45
|
|
|
46
|
-
${
|
|
47
|
-
padding: ${
|
|
46
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
47
|
+
padding: ${r.Spacing["spacing-16"]};
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
${i=>i.$focused?e.css`
|
|
51
|
-
border-color: ${
|
|
52
|
-
box-shadow: ${
|
|
51
|
+
border-color: ${r.Colour["border-focus"]};
|
|
52
|
+
box-shadow: ${r.Shadow["xs-focus-strong"]};
|
|
53
53
|
`:i.$disabled?e.css`
|
|
54
|
-
border-color: ${
|
|
54
|
+
border-color: ${r.Colour["border-disabled"]};
|
|
55
55
|
`:i.$error?e.css`
|
|
56
|
-
background: ${
|
|
57
|
-
border-color: ${
|
|
56
|
+
background: ${r.Colour["bg-error"]};
|
|
57
|
+
border-color: ${r.Colour["border-error"]};
|
|
58
58
|
`:void 0}
|
|
59
59
|
|
|
60
60
|
${i=>{if(!i.$error&&(i.$loading||i.$editable))return e.css`
|
|
61
|
-
${
|
|
61
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
62
62
|
flex-direction: column;
|
|
63
63
|
align-items: flex-start;
|
|
64
64
|
}
|
|
@@ -68,14 +68,14 @@
|
|
|
68
68
|
flex: 1;
|
|
69
69
|
align-items: center;
|
|
70
70
|
|
|
71
|
-
${
|
|
71
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
72
72
|
flex-direction: column;
|
|
73
73
|
width: 100%;
|
|
74
74
|
align-items: flex-start;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
${i=>{if(i.$hasThumbnail)return e.css`
|
|
78
|
-
${
|
|
78
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
79
79
|
flex-direction: row;
|
|
80
80
|
align-items: center;
|
|
81
81
|
}
|
|
@@ -88,85 +88,107 @@
|
|
|
88
88
|
`,u=s.default.div`
|
|
89
89
|
display: flex;
|
|
90
90
|
flex: 1;
|
|
91
|
-
|
|
91
|
+
flex-direction: column;
|
|
92
|
+
align-items: flex-start;
|
|
92
93
|
|
|
93
|
-
${
|
|
94
|
-
flex-direction: column;
|
|
95
|
-
align-items: flex-start;
|
|
94
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
96
95
|
width: 100%;
|
|
97
96
|
}
|
|
98
|
-
|
|
97
|
+
`,$=s.default.div`
|
|
99
98
|
display: flex;
|
|
100
99
|
width: 5rem;
|
|
101
|
-
margin-left: ${
|
|
100
|
+
margin-left: ${r.Spacing["spacing-8"]};
|
|
102
101
|
justify-content: flex-end;
|
|
103
102
|
|
|
104
|
-
${
|
|
103
|
+
${u} > & {
|
|
104
|
+
width: auto;
|
|
105
|
+
margin-left: 0;
|
|
106
|
+
margin-top: ${r.Spacing["spacing-16"]};
|
|
107
|
+
justify-content: flex-start;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
105
111
|
${i=>i.$hideInMobile?e.css`
|
|
106
112
|
display: none;
|
|
107
113
|
visibility: hidden;
|
|
108
114
|
`:e.css`
|
|
109
115
|
width: 100%;
|
|
110
116
|
margin-left: 0;
|
|
111
|
-
margin-top: ${
|
|
117
|
+
margin-top: ${r.Spacing["spacing-8"]};
|
|
112
118
|
justify-content: flex-start;
|
|
113
119
|
`}
|
|
114
120
|
}
|
|
115
121
|
`,f=s.default(n.Typography.BodyMD)`
|
|
116
|
-
color: ${
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
color: ${r.Colour["text-subtler"]};
|
|
123
|
+
`,m=s.default(n.Typography.BodyMD)`
|
|
124
|
+
color: ${r.Colour["text-subtler"]};
|
|
125
|
+
margin-top: ${r.Spacing["spacing-16"]};
|
|
126
|
+
`,x=s.default(n.Typography.BodyMD)``,h=s.default.span`
|
|
127
|
+
${r.Font["form-label"]}
|
|
128
|
+
font-weight: ${r.Font.Spec["weight-semibold"]};
|
|
129
|
+
color: ${r.Colour["text-subtle"]};
|
|
130
|
+
display: block;
|
|
131
|
+
margin-top: ${r.Spacing["spacing-16"]};
|
|
132
|
+
`,y=s.default(x)`
|
|
133
|
+
margin-top: ${r.Spacing["spacing-4"]};
|
|
134
|
+
`,b=s.default(o.ExclamationCircleFillIcon)`
|
|
120
135
|
height: 1lh;
|
|
121
136
|
width: 1em;
|
|
122
137
|
flex-shrink: 0;
|
|
123
|
-
color: ${
|
|
124
|
-
`,
|
|
125
|
-
color: ${
|
|
126
|
-
`,
|
|
127
|
-
margin-top: ${
|
|
138
|
+
color: ${r.Colour["icon-error-strong"]};
|
|
139
|
+
`,S=s.default(n.Typography.BodySM)`
|
|
140
|
+
color: ${r.Colour["text-error"]};
|
|
141
|
+
`,M=s.default(S)`
|
|
142
|
+
margin-top: ${r.Spacing["spacing-4"]};
|
|
128
143
|
display: flex;
|
|
129
|
-
gap: ${
|
|
144
|
+
gap: ${r.Spacing["spacing-4"]};
|
|
130
145
|
|
|
131
|
-
${
|
|
146
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
132
147
|
display: none;
|
|
133
148
|
visibility: hidden;
|
|
134
149
|
}
|
|
135
|
-
`,
|
|
150
|
+
`,w=s.default(S)`
|
|
136
151
|
display: none;
|
|
137
152
|
visibility: hidden;
|
|
138
153
|
|
|
139
|
-
${
|
|
154
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
140
155
|
display: flex;
|
|
141
|
-
gap: ${
|
|
156
|
+
gap: ${r.Spacing["spacing-4"]};
|
|
142
157
|
visibility: visible;
|
|
143
|
-
margin-top: ${
|
|
158
|
+
margin-top: ${r.Spacing["spacing-8"]};
|
|
144
159
|
}
|
|
145
|
-
`,
|
|
160
|
+
`,v=s.default.div`
|
|
146
161
|
width: 6rem;
|
|
147
|
-
margin-left: ${
|
|
162
|
+
margin-left: ${r.Spacing["spacing-32"]};
|
|
148
163
|
display: flex;
|
|
149
164
|
justify-content: flex-end;
|
|
150
165
|
align-items: center;
|
|
151
166
|
|
|
152
|
-
${
|
|
167
|
+
${i=>{if(i.$hasDescription&&i.$editable&&!i.$error&&!i.$loading)return e.css`
|
|
168
|
+
width: 100%;
|
|
169
|
+
margin-left: 0;
|
|
170
|
+
margin-top: ${r.Spacing["spacing-16"]};
|
|
171
|
+
justify-content: flex-end;
|
|
172
|
+
`}}
|
|
173
|
+
|
|
174
|
+
${r.MediaQuery.MaxWidth.md} {
|
|
153
175
|
width: fit-content;
|
|
154
176
|
|
|
155
177
|
${i=>i.$loading&&!i.$error?e.css`
|
|
156
178
|
margin-left: 0;
|
|
157
|
-
margin-top: ${
|
|
179
|
+
margin-top: ${r.Spacing["spacing-16"]};
|
|
158
180
|
width: 100%;
|
|
159
181
|
`:i.$editable&&!i.$error?e.css`
|
|
160
182
|
margin-left: 0;
|
|
161
|
-
margin-top: ${
|
|
183
|
+
margin-top: ${r.Spacing["spacing-16"]};
|
|
162
184
|
align-self: flex-end;
|
|
163
185
|
`:void 0}
|
|
164
186
|
}
|
|
165
|
-
`,
|
|
187
|
+
`,C=s.default(t.IconButton)`
|
|
166
188
|
min-width: unset;
|
|
167
189
|
|
|
168
190
|
&:not(:last-child) {
|
|
169
|
-
margin-right: ${
|
|
191
|
+
margin-right: ${r.Spacing["spacing-8"]};
|
|
170
192
|
}
|
|
171
|
-
`;exports.ActionContainer=
|
|
193
|
+
`;exports.ActionContainer=v,exports.BaseErrorMessage=S,exports.Box=c,exports.ContentSection=p,exports.DescriptionFileSizeText=m,exports.DesktopErrorMessage=M,exports.DragHandleIcon=d,exports.ErrorIcon=b,exports.ExtendedNameSection=u,exports.FileSizeSection=$,exports.FileSizeText=f,exports.IconButton=C,exports.Item=l,exports.ItemDescriptionLabel=h,exports.ItemDescriptionText=y,exports.ItemText=x,exports.MobileErrorMessage=w,exports.NameSection=g;
|
|
172
194
|
//# sourceMappingURL=file-list-item.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-list-item.styles.js","sources":["../../../../src/file-upload/file-list-item/file-list-item.styles.tsx"],"sourcesContent":["import styled, { css } from \"styled-components\";\nimport { DragHandleIcon as DSDragHandleIcon } from \"@lifesg/react-icons/drag-handle\";\nimport { ExclamationCircleFillIcon } from \"@lifesg/react-icons/exclamation-circle-fill\";\nimport { IconButton as DSIconButton } from \"../../icon-button\";\nimport {\n Border,\n Colour,\n MediaQuery,\n Radius,\n Shadow,\n Spacing,\n} from \"../../theme\";\nimport { Typography } from \"../../typography\";\n\n// =============================================================================\n// STYLE INTERFACES\n// =============================================================================\nexport type ItemFocusType = \"self\" | \"others\" | \"none\";\ninterface ItemStyleProps {\n $sortable: boolean;\n $disabled?: boolean | undefined;\n $focusType: ItemFocusType;\n}\n\ninterface DragHandleIconStyleProps {\n $disabled?: boolean | undefined;\n $active?: boolean | undefined;\n}\n\ninterface BoxStyleProps {\n $error?: boolean | undefined;\n $disabled?: boolean | undefined;\n $focused?: boolean | undefined;\n $loading?: boolean | undefined;\n $editable?: boolean | undefined;\n}\n\ninterface ContentSectionStyleProps {\n $hasThumbnail?: boolean | undefined;\n}\n\ninterface ActionContainerStyleProps {\n $editable?: boolean | undefined;\n $error?: boolean | undefined;\n $loading?: boolean | undefined;\n}\n\ninterface FileSizeSectionStyleProps {\n $hideInMobile?: boolean | undefined;\n}\n\n// =============================================================================\n// STYLING\n// =============================================================================\nexport const Item = styled.li<ItemStyleProps>`\n display: flex;\n align-items: center;\n width: 100%;\n border: none;\n\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n\n ${(props) => {\n if (props.$disabled && props.$focusType === \"none\") {\n // Show disabled cursor only if no dragging is happening\n return css`\n cursor: not-allowed;\n `;\n } else if (props.$sortable && props.$focusType === \"self\") {\n return css`\n cursor: grabbing;\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n `;\n } else if (props.$sortable) {\n return css`\n &:hover {\n cursor: grab;\n }\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n `;\n }\n }}\n`;\n\nexport const DragHandleIcon = styled(\n DSDragHandleIcon\n)<DragHandleIconStyleProps>`\n margin-right: ${Spacing[\"spacing-16\"]};\n height: 1.5rem;\n width: 1.5rem;\n color: ${Colour[\"icon\"]};\n\n ${(props) => {\n if (props.$active) {\n return css`\n color: ${Colour[\"icon-primary\"]};\n `;\n }\n\n if (props.$disabled) {\n return css`\n color: ${Colour[\"icon-disabled\"]};\n `;\n }\n }};\n`;\n\nexport const Box = styled.div<BoxStyleProps>`\n background: ${Colour[\"bg-primary-subtlest\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-32\"]};\n display: flex;\n align-items: center;\n width: 100%;\n\n ${MediaQuery.MaxWidth.md} {\n padding: ${Spacing[\"spacing-16\"]};\n }\n\n ${(props) => {\n if (props.$focused) {\n return css`\n border-color: ${Colour[\"border-focus\"]};\n box-shadow: ${Shadow[\"xs-focus-strong\"]};\n `;\n } else if (props.$disabled) {\n return css`\n border-color: ${Colour[\"border-disabled\"]};\n `;\n } else if (props.$error) {\n return css`\n background: ${Colour[\"bg-error\"]};\n border-color: ${Colour[\"border-error\"]};\n `;\n }\n }}\n\n ${(props) => {\n if (!props.$error && (props.$loading || props.$editable)) {\n return css`\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n align-items: flex-start;\n }\n `;\n }\n }}\n`;\n\nexport const ContentSection = styled.div<ContentSectionStyleProps>`\n display: flex;\n flex: 1;\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n width: 100%;\n align-items: flex-start;\n }\n\n ${(props) => {\n if (props.$hasThumbnail) {\n return css`\n ${MediaQuery.MaxWidth.md} {\n flex-direction: row;\n align-items: center;\n }\n `;\n }\n }}\n`;\n\nexport const NameSection = styled.div`\n display: flex;\n flex: 1;\n flex-direction: column;\n width: 100%;\n`;\n\nexport const ExtendedNameSection = styled.div`\n display: flex;\n flex: 1;\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n }\n`;\n\nexport const FileSizeSection = styled.div<FileSizeSectionStyleProps>`\n display: flex;\n width: 5rem;\n margin-left: ${Spacing[\"spacing-8\"]};\n justify-content: flex-end;\n\n ${MediaQuery.MaxWidth.md} {\n ${(props) => {\n if (props.$hideInMobile) {\n return css`\n display: none;\n visibility: hidden;\n `;\n } else {\n return css`\n width: 100%;\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-8\"]};\n justify-content: flex-start;\n `;\n }\n }}\n }\n`;\n\nexport const FileSizeText = styled(Typography.BodyMD)`\n color: ${Colour[\"text-subtler\"]};\n`;\n\nexport const ItemText = styled(Typography.BodyMD)``;\n\nexport const ItemDescriptionText = styled(ItemText)`\n margin-top: ${Spacing[\"spacing-4\"]};\n`;\n\nexport const ErrorIcon = styled(ExclamationCircleFillIcon)`\n height: 1lh;\n width: 1em;\n flex-shrink: 0;\n color: ${Colour[\"icon-error-strong\"]};\n`;\n\nexport const BaseErrorMessage = styled(Typography.BodySM)`\n color: ${Colour[\"text-error\"]};\n`;\n\nexport const DesktopErrorMessage = styled(BaseErrorMessage)`\n margin-top: ${Spacing[\"spacing-4\"]};\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n\n ${MediaQuery.MaxWidth.md} {\n display: none;\n visibility: hidden;\n }\n`;\n\nexport const MobileErrorMessage = styled(BaseErrorMessage)`\n display: none;\n visibility: hidden;\n\n ${MediaQuery.MaxWidth.md} {\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n visibility: visible;\n margin-top: ${Spacing[\"spacing-8\"]};\n }\n`;\n\nexport const ActionContainer = styled.div<ActionContainerStyleProps>`\n width: 6rem;\n margin-left: ${Spacing[\"spacing-32\"]};\n display: flex;\n justify-content: flex-end;\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n width: fit-content;\n\n ${(props) => {\n if (props.$loading && !props.$error) {\n return css`\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n width: 100%;\n `;\n } else if (props.$editable && !props.$error) {\n return css`\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n align-self: flex-end;\n `;\n }\n }}\n }\n`;\n\nexport const IconButton = styled(DSIconButton)`\n min-width: unset;\n\n &:not(:last-child) {\n margin-right: ${Spacing[\"spacing-16\"]};\n }\n`;\n"],"names":["Item","styled","li","Spacing","props","$disabled","$focusType","css","$sortable","DragHandleIcon","DSDragHandleIcon","Colour","$active","Box","div","Border","Radius","MediaQuery","MaxWidth","md","$focused","Shadow","$error","$loading","$editable","ContentSection","$hasThumbnail","NameSection","ExtendedNameSection","FileSizeSection","$hideInMobile","FileSizeText","Typography","BodyMD","ItemText","ItemDescriptionText","ErrorIcon","ExclamationCircleFillIcon","BaseErrorMessage","BodySM","DesktopErrorMessage","MobileErrorMessage","ActionContainer","IconButton","DSIconButton"],"mappings":"qWAsDO,MAAMA,EAAOC,EAAAA,QAAOC,EAAkB;;;;;;;yBAOpBC,EAAAA,QAAQ;;;MAG1BC,GACKA,EAAMC,WAAkC,SAArBD,EAAME,WAElBC,KAAG;;cAGHH,EAAMI,WAAkC,SAArBJ,EAAME,WACzBC,KAAG;;;;;cAMHH,EAAMI,UACND,KAAG;;;;;;;mBADP;EAaFE,EAAiBR,EAAAA,QAC1BS,EAAAA,eACuB;oBACPP,EAAAA,QAAQ;;;aAGfQ,EAAAA,OAAa;;MAEnBP,GACKA,EAAMQ,QACCL,KAAG;yBACGI,EAAAA,OAAO;cAIpBP,EAAMC,UACCE,KAAG;yBACGI,EAAAA,OAAO;mBAFxB;EAQKE,EAAMZ,EAAAA,QAAOa,GAAkB;kBAC1BH,EAAAA,OAAO;cACXI,EAAAA,OAAO,gBAAgBA,EAAAA,OAAc,SAAKJ,SAAe;qBAClDK,EAAAA,OAAW;eACjBb,EAAAA,QAAQ,iBAAiBA,EAAAA,QAAQ;;;;;MAK1Cc,EAAAA,WAAWC,SAASC;mBACPhB,EAAAA,QAAQ;;;MAGpBC,GACKA,EAAMgB,SACCb,KAAG;gCACUI,EAAAA,OAAO;8BACTU,EAAAA,OAAO;cAElBjB,EAAMC,UACNE,KAAG;gCACUI,EAAAA,OAAO;cAEpBP,EAAMkB,OACNf,KAAG;8BACQI,EAAAA,OAAO;gCACLA,EAAAA,OAAO;mBAHxB;;MAQRP,IACC,IAAKA,EAAMkB,SAAWlB,EAAMmB,UAAYnB,EAAMoB,WAC1C,OAAOjB,KAAG;kBACJU,EAAAA,WAAWC,SAASC;;;;aAK9B;EAIKM,EAAiBxB,EAAAA,QAAOa,GAA6B;;;;;MAK5DG,EAAAA,WAAWC,SAASC;;;;;;MAMnBf,IACC,GAAIA,EAAMsB,cACN,OAAOnB,KAAG;kBACJU,EAAAA,WAAWC,SAASC;;;;aAK9B;EAIKQ,EAAc1B,EAAAA,QAAOa,GAAG;;;;;EAOxBc,EAAsB3B,EAAAA,QAAOa,GAAG;;;;;MAKvCG,EAAAA,WAAWC,SAASC;;;;;EAObU,EAAkB5B,EAAAA,QAAOa,GAA8B;;;mBAGjDX,EAAAA,QAAQ;;;MAGrBc,EAAAA,WAAWC,SAASC;UACff,GACKA,EAAM0B,cACCvB,KAAG;;;kBAKHA,KAAG;;;kCAGQJ,EAAAA,QAAQ;;;;EAQ7B4B,EAAe9B,EAAAA,QAAO+B,aAAWC,OAAO;aACxCtB,EAAAA,OAAO;EAGPuB,EAAWjC,EAAAA,QAAO+B,aAAWC,OAAO,GAEpCE,EAAsBlC,EAAAA,QAAOiC,EAAS;kBACjC/B,EAAAA,QAAQ;EAGbiC,EAAYnC,EAAAA,QAAOoC,EAAAA,0BAA0B;;;;aAI7C1B,EAAAA,OAAO;EAGP2B,EAAmBrC,EAAAA,QAAO+B,aAAWO,OAAO;aAC5C5B,EAAAA,OAAO;EAGP6B,EAAsBvC,EAAAA,QAAOqC,EAAiB;kBACzCnC,EAAAA,QAAQ;;WAEfA,EAAAA,QAAQ;;MAEbc,EAAAA,WAAWC,SAASC;;;;EAMbsB,EAAqBxC,EAAAA,QAAOqC,EAAiB;;;;MAIpDrB,EAAAA,WAAWC,SAASC;;eAEXhB,EAAAA,QAAQ;;sBAEDA,EAAAA,QAAQ;;EAIjBuC,EAAkBzC,EAAAA,QAAOa,GAA8B;;mBAEjDX,EAAAA,QAAQ;;;;;MAKrBc,EAAAA,WAAWC,SAASC;;;UAGff,GACKA,EAAMmB,WAAanB,EAAMkB,OAClBf,KAAG;;kCAEQJ,EAAAA,QAAQ;;kBAGnBC,EAAMoB,YAAcpB,EAAMkB,OAC1Bf,KAAG;;kCAEQJ,EAAAA,QAAQ;;uBAHvB;;EAWNwC,EAAa1C,EAAAA,QAAO2C,EAAAA,WAAa;;;;wBAItBzC,EAAAA,QAAQ;;"}
|
|
1
|
+
{"version":3,"file":"file-list-item.styles.js","sources":["../../../../src/file-upload/file-list-item/file-list-item.styles.tsx"],"sourcesContent":["import styled, { css } from \"styled-components\";\nimport { DragHandleIcon as DSDragHandleIcon } from \"@lifesg/react-icons/drag-handle\";\nimport { ExclamationCircleFillIcon } from \"@lifesg/react-icons/exclamation-circle-fill\";\nimport { IconButton as DSIconButton } from \"../../icon-button\";\nimport {\n Border,\n Colour,\n Font,\n MediaQuery,\n Radius,\n Shadow,\n Spacing,\n} from \"../../theme\";\nimport { Typography } from \"../../typography\";\n\n// =============================================================================\n// STYLE INTERFACES\n// =============================================================================\nexport type ItemFocusType = \"self\" | \"others\" | \"none\";\ninterface ItemStyleProps {\n $sortable: boolean;\n $disabled?: boolean | undefined;\n $focusType: ItemFocusType;\n}\n\ninterface DragHandleIconStyleProps {\n $disabled?: boolean | undefined;\n $active?: boolean | undefined;\n}\n\ninterface BoxStyleProps {\n $error?: boolean | undefined;\n $disabled?: boolean | undefined;\n $focused?: boolean | undefined;\n $loading?: boolean | undefined;\n $editable?: boolean | undefined;\n $hasDescription?: boolean | undefined;\n}\n\ninterface ContentSectionStyleProps {\n $hasThumbnail?: boolean | undefined;\n}\n\ninterface ActionContainerStyleProps {\n $editable?: boolean | undefined;\n $error?: boolean | undefined;\n $loading?: boolean | undefined;\n $hasDescription?: boolean | undefined;\n}\n\ninterface FileSizeSectionStyleProps {\n $hideInMobile?: boolean | undefined;\n}\n\n// =============================================================================\n// STYLING\n// =============================================================================\nexport const Item = styled.li<ItemStyleProps>`\n display: flex;\n align-items: center;\n width: 100%;\n border: none;\n\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n\n ${(props) => {\n if (props.$disabled && props.$focusType === \"none\") {\n // Show disabled cursor only if no dragging is happening\n return css`\n cursor: not-allowed;\n `;\n } else if (props.$sortable && props.$focusType === \"self\") {\n return css`\n cursor: grabbing;\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n `;\n } else if (props.$sortable) {\n return css`\n &:hover {\n cursor: grab;\n }\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n `;\n }\n }}\n`;\n\nexport const DragHandleIcon = styled(\n DSDragHandleIcon\n)<DragHandleIconStyleProps>`\n margin-right: ${Spacing[\"spacing-16\"]};\n height: 1.5rem;\n width: 1.5rem;\n color: ${Colour[\"icon\"]};\n\n ${(props) => {\n if (props.$active) {\n return css`\n color: ${Colour[\"icon-primary\"]};\n `;\n }\n\n if (props.$disabled) {\n return css`\n color: ${Colour[\"icon-disabled\"]};\n `;\n }\n }};\n`;\n\nexport const Box = styled.div<BoxStyleProps>`\n background: ${Colour[\"bg-primary-subtlest\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-32\"]};\n display: flex;\n align-items: center;\n width: 100%;\n\n ${MediaQuery.MaxWidth.md} {\n padding: ${Spacing[\"spacing-16\"]};\n }\n\n ${(props) => {\n if (props.$focused) {\n return css`\n border-color: ${Colour[\"border-focus\"]};\n box-shadow: ${Shadow[\"xs-focus-strong\"]};\n `;\n } else if (props.$disabled) {\n return css`\n border-color: ${Colour[\"border-disabled\"]};\n `;\n } else if (props.$error) {\n return css`\n background: ${Colour[\"bg-error\"]};\n border-color: ${Colour[\"border-error\"]};\n `;\n }\n }}\n\n ${(props) => {\n if (!props.$error && (props.$loading || props.$editable)) {\n return css`\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n align-items: flex-start;\n }\n `;\n }\n }}\n`;\n\nexport const ContentSection = styled.div<ContentSectionStyleProps>`\n display: flex;\n flex: 1;\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n width: 100%;\n align-items: flex-start;\n }\n\n ${(props) => {\n if (props.$hasThumbnail) {\n return css`\n ${MediaQuery.MaxWidth.md} {\n flex-direction: row;\n align-items: center;\n }\n `;\n }\n }}\n`;\n\nexport const NameSection = styled.div`\n display: flex;\n flex: 1;\n flex-direction: column;\n width: 100%;\n`;\n\nexport const ExtendedNameSection = styled.div`\n display: flex;\n flex: 1;\n flex-direction: column;\n align-items: flex-start;\n\n ${MediaQuery.MaxWidth.md} {\n width: 100%;\n }\n`;\n\nexport const FileSizeSection = styled.div<FileSizeSectionStyleProps>`\n display: flex;\n width: 5rem;\n margin-left: ${Spacing[\"spacing-8\"]};\n justify-content: flex-end;\n\n ${ExtendedNameSection} > & {\n width: auto;\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n justify-content: flex-start;\n }\n\n ${MediaQuery.MaxWidth.md} {\n ${(props) => {\n if (props.$hideInMobile) {\n return css`\n display: none;\n visibility: hidden;\n `;\n } else {\n return css`\n width: 100%;\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-8\"]};\n justify-content: flex-start;\n `;\n }\n }}\n }\n`;\n\nexport const FileSizeText = styled(Typography.BodyMD)`\n color: ${Colour[\"text-subtler\"]};\n`;\n\nexport const DescriptionFileSizeText = styled(Typography.BodyMD)`\n color: ${Colour[\"text-subtler\"]};\n margin-top: ${Spacing[\"spacing-16\"]};\n`;\n\nexport const ItemText = styled(Typography.BodyMD)``;\n\nexport const ItemDescriptionLabel = styled.span`\n ${Font[\"form-label\"]}\n font-weight: ${Font.Spec[\"weight-semibold\"]};\n color: ${Colour[\"text-subtle\"]};\n display: block;\n margin-top: ${Spacing[\"spacing-16\"]};\n`;\n\nexport const ItemDescriptionText = styled(ItemText)`\n margin-top: ${Spacing[\"spacing-4\"]};\n`;\n\nexport const ErrorIcon = styled(ExclamationCircleFillIcon)`\n height: 1lh;\n width: 1em;\n flex-shrink: 0;\n color: ${Colour[\"icon-error-strong\"]};\n`;\n\nexport const BaseErrorMessage = styled(Typography.BodySM)`\n color: ${Colour[\"text-error\"]};\n`;\n\nexport const DesktopErrorMessage = styled(BaseErrorMessage)`\n margin-top: ${Spacing[\"spacing-4\"]};\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n\n ${MediaQuery.MaxWidth.md} {\n display: none;\n visibility: hidden;\n }\n`;\n\nexport const MobileErrorMessage = styled(BaseErrorMessage)`\n display: none;\n visibility: hidden;\n\n ${MediaQuery.MaxWidth.md} {\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n visibility: visible;\n margin-top: ${Spacing[\"spacing-8\"]};\n }\n`;\n\nexport const ActionContainer = styled.div<ActionContainerStyleProps>`\n width: 6rem;\n margin-left: ${Spacing[\"spacing-32\"]};\n display: flex;\n justify-content: flex-end;\n align-items: center;\n\n ${(props) => {\n if (\n props.$hasDescription &&\n props.$editable &&\n !props.$error &&\n !props.$loading\n ) {\n return css`\n width: 100%;\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n justify-content: flex-end;\n `;\n }\n }}\n\n ${MediaQuery.MaxWidth.md} {\n width: fit-content;\n\n ${(props) => {\n if (props.$loading && !props.$error) {\n return css`\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n width: 100%;\n `;\n } else if (props.$editable && !props.$error) {\n return css`\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n align-self: flex-end;\n `;\n }\n }}\n }\n`;\n\nexport const IconButton = styled(DSIconButton)`\n min-width: unset;\n\n &:not(:last-child) {\n margin-right: ${Spacing[\"spacing-8\"]};\n }\n`;\n"],"names":["Item","styled","li","Spacing","props","$disabled","$focusType","css","$sortable","DragHandleIcon","DSDragHandleIcon","Colour","$active","Box","div","Border","Radius","MediaQuery","MaxWidth","md","$focused","Shadow","$error","$loading","$editable","ContentSection","$hasThumbnail","NameSection","ExtendedNameSection","FileSizeSection","$hideInMobile","FileSizeText","Typography","BodyMD","DescriptionFileSizeText","ItemText","ItemDescriptionLabel","span","Font","Spec","ItemDescriptionText","ErrorIcon","ExclamationCircleFillIcon","BaseErrorMessage","BodySM","DesktopErrorMessage","MobileErrorMessage","ActionContainer","$hasDescription","IconButton","DSIconButton"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react/jsx-runtime"),r=require("../external/@dnd-kit/core/dist/core.esm.js"),t=require("../external/@dnd-kit/sortable/dist/sortable.esm.js"),s=require("react"),i=require("../external/react-resize-detector/build/index.esm.js"),n=require("./context.js"),o=require("./custom-sensors.js"),l=require("./file-item-edit.js"),a=require("./file-list-item/file-list-item.js"),d=require("./file-list.styles.js"),
|
|
1
|
+
"use strict";var e=require("react/jsx-runtime"),r=require("../external/@dnd-kit/core/dist/core.esm.js"),t=require("../external/@dnd-kit/sortable/dist/sortable.esm.js"),s=require("react"),i=require("../external/react-resize-detector/build/index.esm.js"),n=require("./context.js"),o=require("./custom-sensors.js"),l=require("./file-item-edit.js"),a=require("./file-list-item/file-list-item.js"),d=require("./file-list.styles.js"),c=require("./helper.js"),u=require("../shared/accessibility/index.js");const p=s.forwardRef((function({fileItems:p=[],editableFileItems:f,fileDescriptionMaxLength:g,descriptionRequired:m,descriptionLabel:h,sortable:b,disabled:j,readOnly:y,onItemUpdate:v,onItemDelete:x,onSort:S},I){const[q,$]=s.useState({}),{setActiveId:M}=s.useContext(n.FileUploadContext),[O,C]=s.useState(""),D=s.useRef({});s.useImperativeHandle(I,(()=>({focus:()=>{var e;null===(e=L.current)||void 0===e||e.focus()}})));const{width:F=0,ref:L}=i.useResizeDetector(),E=s.useRef({}),R=r.useSensors(r.useSensor(o.MouseSensor,{activationConstraint:{distance:8}}),r.useSensor(r.TouchSensor,{activationConstraint:{delay:150,tolerance:5}}),r.useSensor(r.KeyboardSensor,{coordinateGetter:t.sortableKeyboardCoordinates})),w=e=>{delete E.current[e]};s.useEffect((()=>{const e=G(p);((e,r)=>{const t=Object.keys(e),s=Object.keys(r);if(t.length!==s.length)return!1;for(const t of s)if(e[t]!==r[t])return!1;return!0})(q,e)||$(e)}),[p,f,y]),s.useEffect((()=>{var e;if(!p||0===p.length)return void C("");const r=Date.now(),t=[];for(const s of p){const i=D.current[s.id];if(s.errorMessage)"error"!==(null==i?void 0:i.status)&&(t.push("string"==typeof s.errorMessage?`Error uploading ${s.name}: ${s.errorMessage}`:`Error uploading ${s.name}`),D.current[s.id]={progress:null!==(e=s.progress)&&void 0!==e?e:1,timestamp:r,status:"error"});else if(void 0!==s.progress)if(s.progress>=1)"complete"!==(null==i?void 0:i.status)&&(t.push(`${s.name} upload is complete`),D.current[s.id]={progress:1,timestamp:r,status:"complete"});else if("number"==typeof s.progress&&s.progress<1){(!i||"in-progress"!==i.status)&&(t.push(`Starting upload of ${s.name}`),D.current[s.id]={progress:s.progress,timestamp:r,status:"in-progress"})}}t.length>0&&C(t.join(", "))}),[p]);const k=e=>r=>{N(e.id,"display"),w(e.id);const t=Object.assign(Object.assign({},e),{description:r});v(t)},A=e=>r=>{E.current[e.id]=r},H=e=>()=>{e.description&&0!==e.description.length?N(e.id,"display"):x(e),w(e.id)},U=e=>()=>{N(e.id,"edit")},W=e=>()=>{x(e),L.current&&L.current.focus()},z=e=>{if(S&&p){const{active:r,over:s}=e;if(s&&r.id!==s.id){const e=p.findIndex((e=>e.id===r.id)),i=p.findIndex((e=>e.id===s.id)),n=t.arrayMove(p,e,i);S(n)}}M(void 0)},B=e=>{const{active:r}=e;M(r.id)},K=e=>f&&c.FileUploadHelper.isSupportedImageType(e.type),T=e=>!e.errorMessage&&!y&&!("number"==typeof e.progress&&e.progress<1)&&K(e)&&!e.description,G=e=>{if(!e||0===e.length)return{};const r={};for(const t of e)t.errorMessage?r[t.id]="error":q[t.id]?r[t.id]=q[t.id]:r[t.id]=T(t)?"edit":"display";return r},N=(e,r)=>{$((t=>Object.assign(Object.assign({},t),{[e]:r})))},V=()=>p&&p.length>1&&b&&Object.values(q).every((e=>"display"===e)),J=()=>{if(0===p.length)return"No files uploaded";const e=p.filter((e=>!(null==e?void 0:e.errorMessage)&&(1===e.progress||void 0===e.progress))).length,r=p.filter((e=>"number"==typeof e.progress&&e.progress<1)).length,t=p.filter((e=>e.errorMessage)).length;if(0===e&&0===r&&0===t)return"File list";const s=[e>0?`${e} completed files`:"",r>0?`${r} file in progress`:"",t>0?`${t} ${t>1?"files":"file"} with error`:""].filter(Boolean);return`${y?"Read-only file list":"File list"}. ${s.join(", ")}`},P=()=>{const r=((e,r)=>{if(!e||0===e.length)return[];const t=[];for(const s of e)if("edit"===r[s.id]){const e=t[t.length-1];Array.isArray(e)?e.push(s):t.push([s])}else t.push(s);return t})(p,q);return 0===r.length?null:r.map(((r,t)=>Array.isArray(r)?((r,t)=>{const s=r.map((r=>{const t=Object.assign({},r);return void 0!==E.current[r.id]&&(t.description=E.current[r.id]),e.jsx(l.FileItemEdit,{fileItem:t,wrapperWidth:F,fileDescriptionMaxLength:g,descriptionRequired:m,descriptionLabel:h,onSave:k(r),onCancel:H(r),onBlur:A(r)},r.id)}));return e.jsx(d.EditableItemsContainer,{children:e.jsx("ul",{children:s})},`editable-${t}`)})(r,t):e.jsx(a.FileListItem,{fileItem:r,editable:K(r),wrapperWidth:F,sortable:V(),disabled:j,readOnly:y,descriptionLabel:h,onDelete:W(r),onEditClick:U(r)},r.id)))},Q=()=>e.jsxs(e.Fragment,{children:[e.jsx(u.VisuallyHidden,{"aria-live":"polite","aria-atomic":"true",children:O}),e.jsx(d.ListWrapper,{tabIndex:-1,$readOnly:y,ref:L,"aria-label":J(),children:P()})]});return j||y||!V()?Q():e.jsx(r.DndContext,{sensors:R,onDragEnd:z,onDragStart:B,children:e.jsx(t.SortableContext,{items:p,strategy:t.verticalListSortingStrategy,children:Q()})})}));exports.FileList=p;
|
|
2
2
|
//# sourceMappingURL=file-list.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-list.js","sources":["../../../src/file-upload/file-list.tsx"],"sourcesContent":["import {\n DndContext,\n DragEndEvent,\n DragStartEvent,\n KeyboardSensor,\n TouchSensor,\n useSensor,\n useSensors,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n arrayMove,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\";\nimport React, {\n forwardRef,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { useResizeDetector } from \"react-resize-detector\";\nimport { FileUploadContext } from \"./context\";\nimport { MouseSensor } from \"./custom-sensors\";\nimport { FileItemEdit } from \"./file-item-edit\";\nimport { FileListItem } from \"./file-list-item\";\nimport { EditableItemsContainer, ListWrapper } from \"./file-list.styles\";\nimport { FileUploadHelper } from \"./helper\";\nimport { FileItemProps } from \"./types\";\nimport { VisuallyHidden } from \"../shared/accessibility\";\n\n// =============================================================================\n// INTERFACES\n// =============================================================================\ntype RenderMode = \"edit\" | \"display\" | \"error\";\n\ntype FileItemRenderModes = Record<string, RenderMode>;\ntype FileEditedDescriptions = Record<string, string>;\n\ntype RenderItem = FileItemProps | FileItemProps[];\n\ninterface Props {\n fileItems: FileItemProps[] | undefined;\n editableFileItems: boolean;\n fileDescriptionMaxLength?: number | undefined;\n sortable?: boolean | undefined;\n disabled?: boolean | undefined;\n readOnly?: boolean | undefined;\n onItemUpdate: (item: FileItemProps) => void;\n onItemDelete: (item: FileItemProps) => void;\n onSort?: ((reorderedFileItems: FileItemProps[]) => void) | undefined;\n}\n\ntype AnnouncementProgress = Record<\n string,\n {\n progress: number;\n timestamp: number;\n status: \"in-progress\" | \"complete\" | \"error\";\n }\n>;\n\nexport interface FileListRef {\n focus: () => void;\n}\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nfunction Component(\n {\n fileItems = [],\n editableFileItems,\n fileDescriptionMaxLength,\n sortable,\n disabled,\n readOnly,\n onItemUpdate,\n onItemDelete,\n onSort,\n }: Props,\n ref: React.Ref<FileListRef>\n) {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const [renderModes, setRenderModes] = useState<FileItemRenderModes>({});\n const { setActiveId } = useContext(FileUploadContext);\n\n // Progress announcement state (for aria-live) - announces start and completion only\n const [progressAnnouncement, setProgressAnnouncement] = useState(\"\");\n const lastAnnouncedRef = useRef<AnnouncementProgress>({});\n\n useImperativeHandle(ref, () => ({\n focus: () => {\n wrapperRef.current?.focus();\n },\n }));\n const { width: wrapperWidth = 0, ref: wrapperRef } = useResizeDetector();\n\n // Keep track of edited description without re-rendering\n const descriptionsValueRef = useRef<FileEditedDescriptions>({});\n\n /**\n * As the default drag sensors interfere with click events\n * on the file items, we'll need to configure the sensor to\n * only activate the drag if the mouse moves a certain distance\n */\n const sensors = useSensors(\n useSensor(MouseSensor, {\n activationConstraint: {\n distance: 8, // mouse drag of 8px then activate the drag event\n },\n }),\n useSensor(TouchSensor, {\n activationConstraint: {\n delay: 150,\n tolerance: 5,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n })\n );\n\n // =========================================================================\n // REF METHODS\n // =========================================================================\n const removeDescription = (itemId: string) => {\n delete descriptionsValueRef.current[itemId];\n };\n\n const shallowCompareRenderModes = (\n prev: FileItemRenderModes,\n next: FileItemRenderModes\n ) => {\n const prevKeys = Object.keys(prev);\n const nextKeys = Object.keys(next);\n if (prevKeys.length !== nextKeys.length) {\n return false;\n }\n for (const k of nextKeys) {\n if (prev[k] !== next[k]) {\n return false;\n }\n }\n return true;\n };\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n const nextModes = getItemsRenderMode(fileItems);\n const prevModes = renderModes;\n // We perform shallowCompare to avoid infinite re-render loop\n if (shallowCompareRenderModes(prevModes, nextModes)) {\n return;\n }\n setRenderModes(nextModes);\n }, [fileItems, editableFileItems, readOnly]);\n\n // Progress announcements only at start and completion\n useEffect(() => {\n if (!fileItems || fileItems.length === 0) {\n setProgressAnnouncement(\"\");\n return;\n }\n const now = Date.now();\n const messages: string[] = [];\n\n for (const item of fileItems) {\n const fileStatus = lastAnnouncedRef.current[item.id];\n\n if (item.errorMessage) {\n if (fileStatus?.status !== \"error\") {\n messages.push(\n typeof item.errorMessage === \"string\"\n ? `Error uploading ${item.name}: ${item.errorMessage}`\n : `Error uploading ${item.name}`\n );\n lastAnnouncedRef.current[item.id] = {\n progress: item.progress ?? 1,\n timestamp: now,\n status: \"error\",\n };\n }\n continue;\n }\n\n if (item.progress === undefined) {\n continue;\n }\n\n if (item.progress >= 1) {\n if (fileStatus?.status !== \"complete\") {\n messages.push(`${item.name} upload is complete`);\n lastAnnouncedRef.current[item.id] = {\n progress: 1,\n timestamp: now,\n status: \"complete\",\n };\n }\n continue;\n }\n\n // In progress - only announce start, not progress updates\n if (typeof item.progress === \"number\" && item.progress < 1) {\n // Only announce when starting upload (no previous status or status was not in-progress)\n const shouldAnnounce =\n !fileStatus || fileStatus.status !== \"in-progress\";\n\n if (shouldAnnounce) {\n messages.push(`Starting upload of ${item.name}`);\n lastAnnouncedRef.current[item.id] = {\n progress: item.progress,\n timestamp: now,\n status: \"in-progress\",\n };\n }\n }\n }\n\n if (messages.length > 0) {\n // Update aria-live region once with aggregated message\n setProgressAnnouncement(messages.join(\", \"));\n }\n }, [fileItems]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleSaveEdit = (item: FileItemProps) => (description: string) => {\n updateRenderModes(item.id, \"display\");\n removeDescription(item.id);\n\n const updatedItem = { ...item, description };\n onItemUpdate(updatedItem);\n };\n\n const handleBlurEdit = (item: FileItemProps) => (value: string) => {\n descriptionsValueRef.current[item.id] = value;\n };\n\n const handleCancel = (item: FileItemProps) => () => {\n if (!item.description || item.description.length === 0) {\n // New addition\n onItemDelete(item);\n } else {\n updateRenderModes(item.id, \"display\");\n }\n removeDescription(item.id);\n };\n\n const handleInitiateEdit = (item: FileItemProps) => () => {\n updateRenderModes(item.id, \"edit\");\n };\n\n const handleDelete = (item: FileItemProps) => () => {\n onItemDelete(item);\n if (wrapperRef.current) {\n wrapperRef.current.focus();\n }\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n if (onSort && fileItems) {\n const { active, over } = event;\n\n if (over && active.id !== over.id) {\n const oldIndex = fileItems.findIndex(\n (item) => item.id === active.id\n );\n const newIndex = fileItems.findIndex(\n (item) => item.id === over.id\n );\n\n const updatedFileItems = arrayMove(\n fileItems,\n oldIndex,\n newIndex\n );\n\n onSort(updatedFileItems);\n }\n }\n\n setActiveId(undefined);\n };\n\n const handleDragStart = (event: DragStartEvent) => {\n const { active } = event;\n setActiveId(active.id as string);\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const checkEditable = (item: FileItemProps) => {\n return (\n editableFileItems &&\n FileUploadHelper.isSupportedImageType(item.type)\n );\n };\n\n const shouldRenderEditMode = (item: FileItemProps) => {\n return (\n !item.errorMessage &&\n !readOnly &&\n !(typeof item.progress === \"number\" && item.progress < 1) &&\n checkEditable(item) &&\n !item.description\n );\n };\n\n const getItemsRenderMode = (\n fileItems: FileItemProps[] | undefined\n ): FileItemRenderModes => {\n if (!fileItems || fileItems.length === 0) return {};\n\n const newRenderModes: FileItemRenderModes = {};\n\n for (const item of fileItems) {\n if (item.errorMessage) {\n newRenderModes[item.id] = \"error\";\n } else if (!renderModes[item.id]) {\n newRenderModes[item.id] = shouldRenderEditMode(item)\n ? \"edit\"\n : \"display\";\n } else {\n newRenderModes[item.id] = renderModes[item.id];\n }\n }\n\n return newRenderModes;\n };\n\n const updateRenderModes = (itemId: string, mode: RenderMode) => {\n setRenderModes((prevRenderModes) => {\n return {\n ...prevRenderModes,\n [itemId]: mode,\n };\n });\n };\n\n /**\n * Due to a UI requirement, we will render the items\n * with edit modes as a group\n */\n const getArrangedItems = (\n fileItems: FileItemProps[] | undefined,\n renderModes: FileItemRenderModes\n ) => {\n if (!fileItems || fileItems.length === 0) return [];\n\n const arrangedItems: RenderItem[] = [];\n\n for (const fileItem of fileItems) {\n if (renderModes[fileItem.id] === \"edit\") {\n const previousElement = arrangedItems[arrangedItems.length - 1];\n if (Array.isArray(previousElement)) {\n previousElement.push(fileItem);\n } else {\n arrangedItems.push([fileItem]);\n }\n } else {\n arrangedItems.push(fileItem);\n }\n }\n\n return arrangedItems;\n };\n\n const areAllItemsInDisplayViews = () => {\n return Object.values(renderModes).every((mode) => mode === \"display\");\n };\n\n const shouldEnableSort = () => {\n return (\n fileItems &&\n fileItems.length > 1 &&\n sortable &&\n areAllItemsInDisplayViews()\n );\n };\n\n /**\n * If there are no files, return \"No files uploaded\".\n * If readOnly is true, return \"Read-only file list\".\n * If there are files, return a summary of the file statuses.\n * For example, \"File list. 2 completed files, 1 file in progress, 1 file with error\".\n *\n * @returns aria label\n */\n const getWrapperAriaLabel = () => {\n if (fileItems.length === 0) {\n return \"No files uploaded\";\n }\n const completedCount = fileItems.filter(\n (item) =>\n !item?.errorMessage &&\n (item.progress === 1 || item.progress === undefined)\n ).length;\n const inProgressCount = fileItems.filter(\n (item) => typeof item.progress === \"number\" && item.progress < 1\n ).length;\n const errorCount = fileItems.filter((item) => item.errorMessage).length;\n if (completedCount === 0 && inProgressCount === 0 && errorCount === 0) {\n return `File list`;\n }\n const completedText =\n completedCount > 0 ? `${completedCount} completed files` : \"\";\n const inProgressText =\n inProgressCount > 0 ? `${inProgressCount} file in progress` : \"\";\n const errorText =\n errorCount > 0\n ? `${errorCount} ${\n errorCount > 1 ? \"files\" : \"file\"\n } with error`\n : \"\";\n const parts = [completedText, inProgressText, errorText].filter(\n Boolean\n );\n const prefix = readOnly ? \"Read-only file list\" : \"File list\";\n return `${prefix}. ${parts.join(\", \")}`;\n };\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderItemsInEditMode = (\n fileItems: FileItemProps[],\n keyToUse: number\n ) => {\n const itemsToRender = fileItems.map((item) => {\n const updatedFileItem = { ...item };\n if (descriptionsValueRef.current[item.id] !== undefined) {\n updatedFileItem.description =\n descriptionsValueRef.current[item.id];\n }\n\n return (\n <FileItemEdit\n key={item.id}\n fileItem={updatedFileItem}\n wrapperWidth={wrapperWidth}\n fileDescriptionMaxLength={fileDescriptionMaxLength}\n onSave={handleSaveEdit(item)}\n onCancel={handleCancel(item)}\n onBlur={handleBlurEdit(item)}\n />\n );\n });\n\n return (\n <EditableItemsContainer key={`editable-${keyToUse}`}>\n <ul>{itemsToRender}</ul>\n </EditableItemsContainer>\n );\n };\n\n const renderItems = () => {\n const arrangedItems = getArrangedItems(fileItems, renderModes);\n\n if (arrangedItems.length === 0) return null;\n\n return arrangedItems.map((item, index) => {\n if (Array.isArray(item)) {\n return renderItemsInEditMode(item, index);\n } else {\n return (\n <FileListItem\n key={item.id}\n fileItem={item}\n editable={checkEditable(item)}\n wrapperWidth={wrapperWidth}\n sortable={shouldEnableSort()}\n disabled={disabled}\n readOnly={readOnly}\n onDelete={handleDelete(item)}\n onEditClick={handleInitiateEdit(item)}\n />\n );\n }\n });\n };\n\n /**\n * Renders the progress status of each file upload.\n * In progress: 25% complete for uploading filename.pdf\n * Complete: filename.pdf upload is complete\n * Error: Error uploading filename.pdf: error message\n *\n * @returns A visually hidden element announcing the progress status.\n */\n const renderProgressStatus = () => (\n <VisuallyHidden aria-live=\"polite\" aria-atomic=\"true\">\n {progressAnnouncement}\n </VisuallyHidden>\n );\n\n const renderItemsWithWrapper = () => {\n return (\n <>\n {renderProgressStatus()}\n <ListWrapper\n tabIndex={-1}\n $readOnly={readOnly}\n ref={wrapperRef}\n aria-label={getWrapperAriaLabel()}\n >\n {renderItems()}\n </ListWrapper>\n </>\n );\n };\n\n if (disabled || readOnly || !shouldEnableSort()) {\n return renderItemsWithWrapper();\n } else {\n return (\n <DndContext\n sensors={sensors}\n onDragEnd={handleDragEnd}\n onDragStart={handleDragStart}\n >\n <SortableContext\n items={fileItems}\n strategy={verticalListSortingStrategy}\n >\n {renderItemsWithWrapper()}\n </SortableContext>\n </DndContext>\n );\n }\n}\n\nexport const FileList = forwardRef<FileListRef, Props>(Component);\n"],"names":["FileList","forwardRef","fileItems","editableFileItems","fileDescriptionMaxLength","sortable","disabled","readOnly","onItemUpdate","onItemDelete","onSort","ref","renderModes","setRenderModes","useState","setActiveId","useContext","FileUploadContext","progressAnnouncement","setProgressAnnouncement","lastAnnouncedRef","useRef","useImperativeHandle","focus","_a","wrapperRef","current","width","wrapperWidth","useResizeDetector","descriptionsValueRef","sensors","useSensors","useSensor","MouseSensor","activationConstraint","distance","TouchSensor","delay","tolerance","KeyboardSensor","coordinateGetter","sortableKeyboardCoordinates","removeDescription","itemId","useEffect","nextModes","getItemsRenderMode","prev","next","prevKeys","Object","keys","nextKeys","length","k","shallowCompareRenderModes","now","Date","messages","item","fileStatus","id","errorMessage","status","push","name","progress","timestamp","undefined","join","handleSaveEdit","description","updateRenderModes","updatedItem","assign","handleBlurEdit","value","handleCancel","handleInitiateEdit","handleDelete","handleDragEnd","event","active","over","oldIndex","findIndex","newIndex","updatedFileItems","arrayMove","handleDragStart","checkEditable","FileUploadHelper","isSupportedImageType","type","shouldRenderEditMode","newRenderModes","mode","prevRenderModes","shouldEnableSort","values","every","getWrapperAriaLabel","completedCount","filter","inProgressCount","errorCount","parts","Boolean","renderItems","arrangedItems","fileItem","previousElement","Array","isArray","getArrangedItems","map","index","keyToUse","itemsToRender","updatedFileItem","_jsx","FileItemEdit","onSave","onCancel","onBlur","EditableItemsContainer","children","renderItemsInEditMode","FileListItem","editable","onDelete","onEditClick","renderItemsWithWrapper","_jsxs","_Fragment","VisuallyHidden","ListWrapper","tabIndex","$readOnly","DndContext","onDragEnd","onDragStart","SortableContext","items","strategy","verticalListSortingStrategy"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"file-list.js","sources":["../../../src/file-upload/file-list.tsx"],"sourcesContent":["import {\n DndContext,\n DragEndEvent,\n DragStartEvent,\n KeyboardSensor,\n TouchSensor,\n useSensor,\n useSensors,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n arrayMove,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\";\nimport React, {\n forwardRef,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { useResizeDetector } from \"react-resize-detector\";\nimport { FileUploadContext } from \"./context\";\nimport { MouseSensor } from \"./custom-sensors\";\nimport { FileItemEdit } from \"./file-item-edit\";\nimport { FileListItem } from \"./file-list-item\";\nimport { EditableItemsContainer, ListWrapper } from \"./file-list.styles\";\nimport { FileUploadHelper } from \"./helper\";\nimport { FileItemProps } from \"./types\";\nimport { FormLabelProps } from \"../form/types\";\nimport { VisuallyHidden } from \"../shared/accessibility\";\n\n// =============================================================================\n// INTERFACES\n// =============================================================================\ntype RenderMode = \"edit\" | \"display\" | \"error\";\n\ntype FileItemRenderModes = Record<string, RenderMode>;\ntype FileEditedDescriptions = Record<string, string>;\n\ntype RenderItem = FileItemProps | FileItemProps[];\n\ninterface Props {\n fileItems: FileItemProps[] | undefined;\n editableFileItems: boolean;\n fileDescriptionMaxLength?: number | undefined;\n descriptionRequired?: boolean | undefined;\n descriptionLabel?: FormLabelProps | undefined;\n sortable?: boolean | undefined;\n disabled?: boolean | undefined;\n readOnly?: boolean | undefined;\n onItemUpdate: (item: FileItemProps) => void;\n onItemDelete: (item: FileItemProps) => void;\n onSort?: ((reorderedFileItems: FileItemProps[]) => void) | undefined;\n}\n\ntype AnnouncementProgress = Record<\n string,\n {\n progress: number;\n timestamp: number;\n status: \"in-progress\" | \"complete\" | \"error\";\n }\n>;\n\nexport interface FileListRef {\n focus: () => void;\n}\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nfunction Component(\n {\n fileItems = [],\n editableFileItems,\n fileDescriptionMaxLength,\n descriptionRequired,\n descriptionLabel,\n sortable,\n disabled,\n readOnly,\n onItemUpdate,\n onItemDelete,\n onSort,\n }: Props,\n ref: React.Ref<FileListRef>\n) {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const [renderModes, setRenderModes] = useState<FileItemRenderModes>({});\n const { setActiveId } = useContext(FileUploadContext);\n\n // Progress announcement state (for aria-live) - announces start and completion only\n const [progressAnnouncement, setProgressAnnouncement] = useState(\"\");\n const lastAnnouncedRef = useRef<AnnouncementProgress>({});\n\n useImperativeHandle(ref, () => ({\n focus: () => {\n wrapperRef.current?.focus();\n },\n }));\n const { width: wrapperWidth = 0, ref: wrapperRef } = useResizeDetector();\n\n // Keep track of edited description without re-rendering\n const descriptionsValueRef = useRef<FileEditedDescriptions>({});\n\n /**\n * As the default drag sensors interfere with click events\n * on the file items, we'll need to configure the sensor to\n * only activate the drag if the mouse moves a certain distance\n */\n const sensors = useSensors(\n useSensor(MouseSensor, {\n activationConstraint: {\n distance: 8, // mouse drag of 8px then activate the drag event\n },\n }),\n useSensor(TouchSensor, {\n activationConstraint: {\n delay: 150,\n tolerance: 5,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n })\n );\n\n // =========================================================================\n // REF METHODS\n // =========================================================================\n const removeDescription = (itemId: string) => {\n delete descriptionsValueRef.current[itemId];\n };\n\n const shallowCompareRenderModes = (\n prev: FileItemRenderModes,\n next: FileItemRenderModes\n ) => {\n const prevKeys = Object.keys(prev);\n const nextKeys = Object.keys(next);\n if (prevKeys.length !== nextKeys.length) {\n return false;\n }\n for (const k of nextKeys) {\n if (prev[k] !== next[k]) {\n return false;\n }\n }\n return true;\n };\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n const nextModes = getItemsRenderMode(fileItems);\n const prevModes = renderModes;\n // We perform shallowCompare to avoid infinite re-render loop\n if (shallowCompareRenderModes(prevModes, nextModes)) {\n return;\n }\n setRenderModes(nextModes);\n }, [fileItems, editableFileItems, readOnly]);\n\n // Progress announcements only at start and completion\n useEffect(() => {\n if (!fileItems || fileItems.length === 0) {\n setProgressAnnouncement(\"\");\n return;\n }\n const now = Date.now();\n const messages: string[] = [];\n\n for (const item of fileItems) {\n const fileStatus = lastAnnouncedRef.current[item.id];\n\n if (item.errorMessage) {\n if (fileStatus?.status !== \"error\") {\n messages.push(\n typeof item.errorMessage === \"string\"\n ? `Error uploading ${item.name}: ${item.errorMessage}`\n : `Error uploading ${item.name}`\n );\n lastAnnouncedRef.current[item.id] = {\n progress: item.progress ?? 1,\n timestamp: now,\n status: \"error\",\n };\n }\n continue;\n }\n\n if (item.progress === undefined) {\n continue;\n }\n\n if (item.progress >= 1) {\n if (fileStatus?.status !== \"complete\") {\n messages.push(`${item.name} upload is complete`);\n lastAnnouncedRef.current[item.id] = {\n progress: 1,\n timestamp: now,\n status: \"complete\",\n };\n }\n continue;\n }\n\n // In progress - only announce start, not progress updates\n if (typeof item.progress === \"number\" && item.progress < 1) {\n // Only announce when starting upload (no previous status or status was not in-progress)\n const shouldAnnounce =\n !fileStatus || fileStatus.status !== \"in-progress\";\n\n if (shouldAnnounce) {\n messages.push(`Starting upload of ${item.name}`);\n lastAnnouncedRef.current[item.id] = {\n progress: item.progress,\n timestamp: now,\n status: \"in-progress\",\n };\n }\n }\n }\n\n if (messages.length > 0) {\n // Update aria-live region once with aggregated message\n setProgressAnnouncement(messages.join(\", \"));\n }\n }, [fileItems]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleSaveEdit = (item: FileItemProps) => (description: string) => {\n updateRenderModes(item.id, \"display\");\n removeDescription(item.id);\n\n const updatedItem = { ...item, description };\n onItemUpdate(updatedItem);\n };\n\n const handleBlurEdit = (item: FileItemProps) => (value: string) => {\n descriptionsValueRef.current[item.id] = value;\n };\n\n const handleCancel = (item: FileItemProps) => () => {\n if (!item.description || item.description.length === 0) {\n // New addition\n onItemDelete(item);\n } else {\n updateRenderModes(item.id, \"display\");\n }\n removeDescription(item.id);\n };\n\n const handleInitiateEdit = (item: FileItemProps) => () => {\n updateRenderModes(item.id, \"edit\");\n };\n\n const handleDelete = (item: FileItemProps) => () => {\n onItemDelete(item);\n if (wrapperRef.current) {\n wrapperRef.current.focus();\n }\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n if (onSort && fileItems) {\n const { active, over } = event;\n\n if (over && active.id !== over.id) {\n const oldIndex = fileItems.findIndex(\n (item) => item.id === active.id\n );\n const newIndex = fileItems.findIndex(\n (item) => item.id === over.id\n );\n\n const updatedFileItems = arrayMove(\n fileItems,\n oldIndex,\n newIndex\n );\n\n onSort(updatedFileItems);\n }\n }\n\n setActiveId(undefined);\n };\n\n const handleDragStart = (event: DragStartEvent) => {\n const { active } = event;\n setActiveId(active.id as string);\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const checkEditable = (item: FileItemProps) => {\n return (\n editableFileItems &&\n FileUploadHelper.isSupportedImageType(item.type)\n );\n };\n\n const shouldRenderEditMode = (item: FileItemProps) => {\n return (\n !item.errorMessage &&\n !readOnly &&\n !(typeof item.progress === \"number\" && item.progress < 1) &&\n checkEditable(item) &&\n !item.description\n );\n };\n\n const getItemsRenderMode = (\n fileItems: FileItemProps[] | undefined\n ): FileItemRenderModes => {\n if (!fileItems || fileItems.length === 0) return {};\n\n const newRenderModes: FileItemRenderModes = {};\n\n for (const item of fileItems) {\n if (item.errorMessage) {\n newRenderModes[item.id] = \"error\";\n } else if (!renderModes[item.id]) {\n newRenderModes[item.id] = shouldRenderEditMode(item)\n ? \"edit\"\n : \"display\";\n } else {\n newRenderModes[item.id] = renderModes[item.id];\n }\n }\n\n return newRenderModes;\n };\n\n const updateRenderModes = (itemId: string, mode: RenderMode) => {\n setRenderModes((prevRenderModes) => {\n return {\n ...prevRenderModes,\n [itemId]: mode,\n };\n });\n };\n\n /**\n * Due to a UI requirement, we will render the items\n * with edit modes as a group\n */\n const getArrangedItems = (\n fileItems: FileItemProps[] | undefined,\n renderModes: FileItemRenderModes\n ) => {\n if (!fileItems || fileItems.length === 0) return [];\n\n const arrangedItems: RenderItem[] = [];\n\n for (const fileItem of fileItems) {\n if (renderModes[fileItem.id] === \"edit\") {\n const previousElement = arrangedItems[arrangedItems.length - 1];\n if (Array.isArray(previousElement)) {\n previousElement.push(fileItem);\n } else {\n arrangedItems.push([fileItem]);\n }\n } else {\n arrangedItems.push(fileItem);\n }\n }\n\n return arrangedItems;\n };\n\n const areAllItemsInDisplayViews = () => {\n return Object.values(renderModes).every((mode) => mode === \"display\");\n };\n\n const shouldEnableSort = () => {\n return (\n fileItems &&\n fileItems.length > 1 &&\n sortable &&\n areAllItemsInDisplayViews()\n );\n };\n\n /**\n * If there are no files, return \"No files uploaded\".\n * If readOnly is true, return \"Read-only file list\".\n * If there are files, return a summary of the file statuses.\n * For example, \"File list. 2 completed files, 1 file in progress, 1 file with error\".\n *\n * @returns aria label\n */\n const getWrapperAriaLabel = () => {\n if (fileItems.length === 0) {\n return \"No files uploaded\";\n }\n const completedCount = fileItems.filter(\n (item) =>\n !item?.errorMessage &&\n (item.progress === 1 || item.progress === undefined)\n ).length;\n const inProgressCount = fileItems.filter(\n (item) => typeof item.progress === \"number\" && item.progress < 1\n ).length;\n const errorCount = fileItems.filter((item) => item.errorMessage).length;\n if (completedCount === 0 && inProgressCount === 0 && errorCount === 0) {\n return `File list`;\n }\n const completedText =\n completedCount > 0 ? `${completedCount} completed files` : \"\";\n const inProgressText =\n inProgressCount > 0 ? `${inProgressCount} file in progress` : \"\";\n const errorText =\n errorCount > 0\n ? `${errorCount} ${\n errorCount > 1 ? \"files\" : \"file\"\n } with error`\n : \"\";\n const parts = [completedText, inProgressText, errorText].filter(\n Boolean\n );\n const prefix = readOnly ? \"Read-only file list\" : \"File list\";\n return `${prefix}. ${parts.join(\", \")}`;\n };\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderItemsInEditMode = (\n fileItems: FileItemProps[],\n keyToUse: number\n ) => {\n const itemsToRender = fileItems.map((item) => {\n const updatedFileItem = { ...item };\n if (descriptionsValueRef.current[item.id] !== undefined) {\n updatedFileItem.description =\n descriptionsValueRef.current[item.id];\n }\n\n return (\n <FileItemEdit\n key={item.id}\n fileItem={updatedFileItem}\n wrapperWidth={wrapperWidth}\n fileDescriptionMaxLength={fileDescriptionMaxLength}\n descriptionRequired={descriptionRequired}\n descriptionLabel={descriptionLabel}\n onSave={handleSaveEdit(item)}\n onCancel={handleCancel(item)}\n onBlur={handleBlurEdit(item)}\n />\n );\n });\n\n return (\n <EditableItemsContainer key={`editable-${keyToUse}`}>\n <ul>{itemsToRender}</ul>\n </EditableItemsContainer>\n );\n };\n\n const renderItems = () => {\n const arrangedItems = getArrangedItems(fileItems, renderModes);\n\n if (arrangedItems.length === 0) return null;\n\n return arrangedItems.map((item, index) => {\n if (Array.isArray(item)) {\n return renderItemsInEditMode(item, index);\n } else {\n return (\n <FileListItem\n key={item.id}\n fileItem={item}\n editable={checkEditable(item)}\n wrapperWidth={wrapperWidth}\n sortable={shouldEnableSort()}\n disabled={disabled}\n readOnly={readOnly}\n descriptionLabel={descriptionLabel}\n onDelete={handleDelete(item)}\n onEditClick={handleInitiateEdit(item)}\n />\n );\n }\n });\n };\n\n /**\n * Renders the progress status of each file upload.\n * In progress: 25% complete for uploading filename.pdf\n * Complete: filename.pdf upload is complete\n * Error: Error uploading filename.pdf: error message\n *\n * @returns A visually hidden element announcing the progress status.\n */\n const renderProgressStatus = () => (\n <VisuallyHidden aria-live=\"polite\" aria-atomic=\"true\">\n {progressAnnouncement}\n </VisuallyHidden>\n );\n\n const renderItemsWithWrapper = () => {\n return (\n <>\n {renderProgressStatus()}\n <ListWrapper\n tabIndex={-1}\n $readOnly={readOnly}\n ref={wrapperRef}\n aria-label={getWrapperAriaLabel()}\n >\n {renderItems()}\n </ListWrapper>\n </>\n );\n };\n\n if (disabled || readOnly || !shouldEnableSort()) {\n return renderItemsWithWrapper();\n } else {\n return (\n <DndContext\n sensors={sensors}\n onDragEnd={handleDragEnd}\n onDragStart={handleDragStart}\n >\n <SortableContext\n items={fileItems}\n strategy={verticalListSortingStrategy}\n >\n {renderItemsWithWrapper()}\n </SortableContext>\n </DndContext>\n );\n }\n}\n\nexport const FileList = forwardRef<FileListRef, Props>(Component);\n"],"names":["FileList","forwardRef","fileItems","editableFileItems","fileDescriptionMaxLength","descriptionRequired","descriptionLabel","sortable","disabled","readOnly","onItemUpdate","onItemDelete","onSort","ref","renderModes","setRenderModes","useState","setActiveId","useContext","FileUploadContext","progressAnnouncement","setProgressAnnouncement","lastAnnouncedRef","useRef","useImperativeHandle","focus","_a","wrapperRef","current","width","wrapperWidth","useResizeDetector","descriptionsValueRef","sensors","useSensors","useSensor","MouseSensor","activationConstraint","distance","TouchSensor","delay","tolerance","KeyboardSensor","coordinateGetter","sortableKeyboardCoordinates","removeDescription","itemId","useEffect","nextModes","getItemsRenderMode","prev","next","prevKeys","Object","keys","nextKeys","length","k","shallowCompareRenderModes","now","Date","messages","item","fileStatus","id","errorMessage","status","push","name","progress","timestamp","undefined","join","handleSaveEdit","description","updateRenderModes","updatedItem","assign","handleBlurEdit","value","handleCancel","handleInitiateEdit","handleDelete","handleDragEnd","event","active","over","oldIndex","findIndex","newIndex","updatedFileItems","arrayMove","handleDragStart","checkEditable","FileUploadHelper","isSupportedImageType","type","shouldRenderEditMode","newRenderModes","mode","prevRenderModes","shouldEnableSort","values","every","getWrapperAriaLabel","completedCount","filter","inProgressCount","errorCount","parts","Boolean","renderItems","arrangedItems","fileItem","previousElement","Array","isArray","getArrangedItems","map","index","keyToUse","itemsToRender","updatedFileItem","_jsx","FileItemEdit","onSave","onCancel","onBlur","EditableItemsContainer","children","renderItemsInEditMode","FileListItem","editable","onDelete","onEditClick","renderItemsWithWrapper","_jsxs","_Fragment","VisuallyHidden","ListWrapper","tabIndex","$readOnly","DndContext","onDragEnd","onDragStart","SortableContext","items","strategy","verticalListSortingStrategy"],"mappings":"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"}
|
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
"use strict";var t=require("styled-components"),e=require("../theme/index.js");function
|
|
1
|
+
"use strict";var t=require("styled-components"),e=require("../theme/index.js");function n(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var i=n(t);const a=i.default.ul`
|
|
2
2
|
list-style-type: none;
|
|
3
3
|
margin-bottom: ${t=>t.$readOnly?"0":e.Spacing["spacing-32"]};
|
|
4
|
-
`,
|
|
5
|
-
border-top: ${e.Border["width-010"]} ${e.Border.solid} ${e.Colour.border};
|
|
6
|
-
border-bottom: ${e.Border["width-010"]} ${e.Border.solid} ${e.Colour.border};
|
|
7
|
-
|
|
4
|
+
`,r=i.default.li`
|
|
8
5
|
&:not(:last-child) {
|
|
9
|
-
margin-bottom: ${e.Spacing["spacing-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
&:not(:first-child) {
|
|
13
|
-
margin-top: ${e.Spacing["spacing-32"]};
|
|
6
|
+
margin-bottom: ${e.Spacing["spacing-16"]};
|
|
14
7
|
}
|
|
15
8
|
|
|
16
9
|
ul {
|
|
17
10
|
list-style-type: none;
|
|
18
11
|
}
|
|
19
|
-
`;exports.EditableItemsContainer=
|
|
12
|
+
`;exports.EditableItemsContainer=r,exports.ListWrapper=a;
|
|
20
13
|
//# sourceMappingURL=file-list.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-list.styles.js","sources":["../../../src/file-upload/file-list.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport {
|
|
1
|
+
{"version":3,"file":"file-list.styles.js","sources":["../../../src/file-upload/file-list.styles.tsx"],"sourcesContent":["import styled from \"styled-components\";\nimport { Spacing } from \"../theme\";\n\n// =============================================================================\n// STYLE INTERFACE\n// =============================================================================\ninterface ListWrapperStyleProps {\n $readOnly?: boolean | undefined;\n}\n\n// =============================================================================\n// STYLING\n// =============================================================================\nexport const ListWrapper = styled.ul<ListWrapperStyleProps>`\n list-style-type: none;\n margin-bottom: ${(props) =>\n props.$readOnly ? \"0\" : Spacing[\"spacing-32\"]};\n`;\n\nexport const EditableItemsContainer = styled.li`\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n\n ul {\n list-style-type: none;\n }\n`;\n"],"names":["ListWrapper","styled","ul","props","$readOnly","Spacing","EditableItemsContainer","li"],"mappings":"kKAaO,MAAMA,EAAcC,EAAAA,QAAOC,EAAyB;;qBAErCC,GACdA,EAAMC,UAAY,IAAMC,EAAAA,QAAQ;EAG3BC,EAAyBL,EAAAA,QAAOM,EAAE;;yBAEtBF,EAAAA,QAAQ;;;;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react/jsx-runtime"),t=require("react"),r=require("./context.js"),
|
|
1
|
+
"use strict";var e=require("react/jsx-runtime"),t=require("react"),r=require("./context.js"),i=require("./dropzone.js"),l=require("./file-list.js"),n=require("./file-upload.styles.js");exports.FileUpload=({styleType:o="bordered",fileItems:s,title:d,description:a,maxFiles:c,warning:u,className:p,name:x,id:h,"data-testid":j,accept:b,capture:m,multiple:f,disabled:g,sortable:y=!1,fileDescriptionMaxLength:v,editableFileItems:D=!1,descriptionRequired:q=!0,descriptionLabel:C,errorMessage:F,readOnly:I,customLabels:U,onChange:L,onDelete:B,onEdit:T,onSort:z})=>{const R={uploadButton:(null==U?void 0:U.uploadButtonLabel)||"Upload files"},w=t.useRef(null),A=t.useRef(null),[M,S]=t.useState(),E=()=>!(!c||!s)&&s.length>=c;return e.jsx(r.FileUploadContext.Provider,{value:{activeId:M,setActiveId:S},children:e.jsxs(i.FileUploadDropzone,{ref:w,onChange:e=>{var t;!g&&L&&(L(e),null===(t=A.current)||void 0===t||t.focus())},id:h?`${h}-dropzone`:"dropzone",accept:b,capture:m,border:"bordered"===o,className:p,"data-testid":j,name:x,multiple:f,disabled:g||E()||I,children:[!(!d&&!a)&&e.jsxs(n.TextContainer,{children:[d?"string"==typeof d?e.jsx(n.Title,{children:d}):e.jsx(n.TitleContainer,{children:d}):null,a?"string"==typeof a?e.jsx(n.Description,{children:a}):e.jsx(n.DescriptionContainer,{children:a}):null]}),!!u&&e.jsx(n.WarningAlert,{type:"warning",children:u}),e.jsx(l.FileList,{ref:A,fileItems:s,editableFileItems:D,descriptionRequired:q,descriptionLabel:C,fileDescriptionMaxLength:v,sortable:y,disabled:g,readOnly:I,onItemDelete:e=>{var t;B&&(B(e),null===(t=A.current)||void 0===t||t.focus())},onItemUpdate:e=>{T&&T(e)},onSort:e=>{z&&z(e)}}),F&&e.jsx(n.ErrorAlert,{type:"error",children:F}),!I&&e.jsxs(n.UploadButtonContainer,{children:[e.jsx(n.UploadButton,{type:"button",styleType:"secondary",disabled:!!M||g||E(),onClick:e=>{g||(e.preventDefault(),w.current&&w.current.openFileDialog())},children:R.uploadButton}),e.jsx(n.UploadButtonText,{weight:"semibold",children:"or drop them here"})]})]})})};
|
|
2
2
|
//# sourceMappingURL=file-upload.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-upload.js","sources":["../../../src/file-upload/file-upload.tsx"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport { FileUploadContext } from \"./context\";\nimport { DropzoneElement, FileUploadDropzone } from \"./dropzone\";\nimport { FileList, FileListRef } from \"./file-list\";\nimport {\n Description,\n DescriptionContainer,\n ErrorAlert,\n TextContainer,\n Title,\n TitleContainer,\n UploadButton,\n UploadButtonContainer,\n UploadButtonText,\n WarningAlert,\n} from \"./file-upload.styles\";\nimport { FileItemProps, FileUploadProps } from \"./types\";\n\nexport const FileUpload = ({\n styleType = \"bordered\",\n fileItems,\n title,\n description,\n maxFiles,\n warning,\n className,\n name,\n id,\n \"data-testid\": testId,\n accept,\n capture,\n multiple,\n disabled,\n sortable = false,\n fileDescriptionMaxLength,\n editableFileItems = false,\n errorMessage,\n readOnly,\n customLabels,\n onChange,\n onDelete,\n onEdit,\n onSort,\n}: FileUploadProps) => {\n const labels = {\n uploadButton: customLabels?.uploadButtonLabel || \"Upload files\",\n };\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const dropzoneRef = useRef<DropzoneElement>(null);\n const fileListRef = useRef<FileListRef>(null);\n const [activeId, setActiveId] = useState<string>();\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleChange = (files: File[]) => {\n if (!disabled && onChange) {\n onChange(files);\n fileListRef.current?.focus();\n }\n };\n\n const handleItemDelete = (item: FileItemProps) => {\n if (onDelete) {\n onDelete(item);\n fileListRef.current?.focus();\n }\n };\n\n const handleUploadButtonClick = (\n event: React.MouseEvent<HTMLButtonElement>\n ) => {\n if (!disabled) {\n event.preventDefault();\n if (dropzoneRef.current) {\n dropzoneRef.current.openFileDialog();\n }\n }\n };\n\n const handleItemUpdate = (updatedItem: FileItemProps) => {\n if (onEdit) {\n onEdit(updatedItem);\n }\n };\n\n const handleSort = (updatedItems: FileItemProps[]) => {\n if (onSort) {\n onSort(updatedItems);\n }\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const reachedMaxFiles = () => {\n return maxFiles && fileItems ? fileItems.length >= maxFiles : false;\n };\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderTitle = () => {\n if (!title) {\n return null;\n }\n\n if (typeof title === \"string\") {\n return <Title>{title}</Title>;\n }\n\n return <TitleContainer>{title}</TitleContainer>;\n };\n\n const renderDescription = () => {\n if (!description) {\n return null;\n }\n\n if (typeof description === \"string\") {\n return <Description>{description}</Description>;\n }\n\n return <DescriptionContainer>{description}</DescriptionContainer>;\n };\n\n return (\n <FileUploadContext.Provider value={{ activeId, setActiveId }}>\n <FileUploadDropzone\n ref={dropzoneRef}\n onChange={handleChange}\n id={id ? `${id}-dropzone` : \"dropzone\"}\n accept={accept}\n capture={capture}\n border={styleType === \"bordered\"}\n className={className}\n data-testid={testId}\n name={name}\n multiple={multiple}\n disabled={disabled || reachedMaxFiles() || readOnly}\n >\n {!!(title || description) && (\n <TextContainer>\n {renderTitle()}\n {renderDescription()}\n </TextContainer>\n )}\n {!!warning && (\n <WarningAlert type=\"warning\">{warning}</WarningAlert>\n )}\n <FileList\n ref={fileListRef}\n fileItems={fileItems}\n editableFileItems={editableFileItems}\n fileDescriptionMaxLength={fileDescriptionMaxLength}\n sortable={sortable}\n disabled={disabled}\n readOnly={readOnly}\n onItemDelete={handleItemDelete}\n onItemUpdate={handleItemUpdate}\n onSort={handleSort}\n />\n {errorMessage && (\n <ErrorAlert type=\"error\">{errorMessage}</ErrorAlert>\n )}\n {!readOnly && (\n <UploadButtonContainer>\n <UploadButton\n type=\"button\"\n styleType=\"secondary\"\n disabled={\n !!activeId || disabled || reachedMaxFiles()\n }\n onClick={handleUploadButtonClick}\n >\n {labels.uploadButton}\n </UploadButton>\n <UploadButtonText weight=\"semibold\">\n or drop them here\n </UploadButtonText>\n </UploadButtonContainer>\n )}\n </FileUploadDropzone>\n </FileUploadContext.Provider>\n );\n};\n"],"names":["styleType","fileItems","title","description","maxFiles","warning","className","name","id","testId","accept","capture","multiple","disabled","sortable","fileDescriptionMaxLength","editableFileItems","errorMessage","readOnly","customLabels","onChange","onDelete","onEdit","onSort","labels","uploadButton","uploadButtonLabel","dropzoneRef","useRef","fileListRef","activeId","setActiveId","useState","reachedMaxFiles","length","_jsx","FileUploadContext","Provider","value","children","_jsxs","FileUploadDropzone","ref","files","_a","current","focus","border","TextContainer","Title","TitleContainer","Description","DescriptionContainer","WarningAlert","type","FileList","onItemDelete","item","onItemUpdate","updatedItem","updatedItems","ErrorAlert","UploadButtonContainer","UploadButton","onClick","event","preventDefault","openFileDialog","UploadButtonText","weight"],"mappings":"4MAkB0B,EACtBA,YAAY,WACZC,YACAC,QACAC,cACAC,WACAC,UACAC,YACAC,OACAC,KACA,cAAeC,EACfC,SACAC,UACAC,WACAC,WACAC,YAAW,EACXC,2BACAC,qBAAoB,EACpBC,eACAC,WACAC,eACAC,WACAC,WACAC,SACAC,aAEA,MAAMC,EAAS,CACXC,cAAcN,eAAAA,EAAcO,oBAAqB,gBAK/CC,EAAcC,EAAAA,OAAwB,MACtCC,EAAcD,EAAAA,OAAoB,OACjCE,EAAUC,GAAeC,aA6C1BC,EAAkB,
|
|
1
|
+
{"version":3,"file":"file-upload.js","sources":["../../../src/file-upload/file-upload.tsx"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport { FileUploadContext } from \"./context\";\nimport { DropzoneElement, FileUploadDropzone } from \"./dropzone\";\nimport { FileList, FileListRef } from \"./file-list\";\nimport {\n Description,\n DescriptionContainer,\n ErrorAlert,\n TextContainer,\n Title,\n TitleContainer,\n UploadButton,\n UploadButtonContainer,\n UploadButtonText,\n WarningAlert,\n} from \"./file-upload.styles\";\nimport { FileItemProps, FileUploadProps } from \"./types\";\n\nexport const FileUpload = ({\n styleType = \"bordered\",\n fileItems,\n title,\n description,\n maxFiles,\n warning,\n className,\n name,\n id,\n \"data-testid\": testId,\n accept,\n capture,\n multiple,\n disabled,\n sortable = false,\n fileDescriptionMaxLength,\n editableFileItems = false,\n descriptionRequired = true,\n descriptionLabel,\n errorMessage,\n readOnly,\n customLabels,\n onChange,\n onDelete,\n onEdit,\n onSort,\n}: FileUploadProps) => {\n const labels = {\n uploadButton: customLabels?.uploadButtonLabel || \"Upload files\",\n };\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const dropzoneRef = useRef<DropzoneElement>(null);\n const fileListRef = useRef<FileListRef>(null);\n const [activeId, setActiveId] = useState<string>();\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleChange = (files: File[]) => {\n if (!disabled && onChange) {\n onChange(files);\n fileListRef.current?.focus();\n }\n };\n\n const handleItemDelete = (item: FileItemProps) => {\n if (onDelete) {\n onDelete(item);\n fileListRef.current?.focus();\n }\n };\n\n const handleUploadButtonClick = (\n event: React.MouseEvent<HTMLButtonElement>\n ) => {\n if (!disabled) {\n event.preventDefault();\n if (dropzoneRef.current) {\n dropzoneRef.current.openFileDialog();\n }\n }\n };\n\n const handleItemUpdate = (updatedItem: FileItemProps) => {\n if (onEdit) {\n onEdit(updatedItem);\n }\n };\n\n const handleSort = (updatedItems: FileItemProps[]) => {\n if (onSort) {\n onSort(updatedItems);\n }\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const reachedMaxFiles = () => {\n return maxFiles && fileItems ? fileItems.length >= maxFiles : false;\n };\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderTitle = () => {\n if (!title) {\n return null;\n }\n\n if (typeof title === \"string\") {\n return <Title>{title}</Title>;\n }\n\n return <TitleContainer>{title}</TitleContainer>;\n };\n\n const renderDescription = () => {\n if (!description) {\n return null;\n }\n\n if (typeof description === \"string\") {\n return <Description>{description}</Description>;\n }\n\n return <DescriptionContainer>{description}</DescriptionContainer>;\n };\n\n return (\n <FileUploadContext.Provider value={{ activeId, setActiveId }}>\n <FileUploadDropzone\n ref={dropzoneRef}\n onChange={handleChange}\n id={id ? `${id}-dropzone` : \"dropzone\"}\n accept={accept}\n capture={capture}\n border={styleType === \"bordered\"}\n className={className}\n data-testid={testId}\n name={name}\n multiple={multiple}\n disabled={disabled || reachedMaxFiles() || readOnly}\n >\n {!!(title || description) && (\n <TextContainer>\n {renderTitle()}\n {renderDescription()}\n </TextContainer>\n )}\n {!!warning && (\n <WarningAlert type=\"warning\">{warning}</WarningAlert>\n )}\n <FileList\n ref={fileListRef}\n fileItems={fileItems}\n editableFileItems={editableFileItems}\n descriptionRequired={descriptionRequired}\n descriptionLabel={descriptionLabel}\n fileDescriptionMaxLength={fileDescriptionMaxLength}\n sortable={sortable}\n disabled={disabled}\n readOnly={readOnly}\n onItemDelete={handleItemDelete}\n onItemUpdate={handleItemUpdate}\n onSort={handleSort}\n />\n {errorMessage && (\n <ErrorAlert type=\"error\">{errorMessage}</ErrorAlert>\n )}\n {!readOnly && (\n <UploadButtonContainer>\n <UploadButton\n type=\"button\"\n styleType=\"secondary\"\n disabled={\n !!activeId || disabled || reachedMaxFiles()\n }\n onClick={handleUploadButtonClick}\n >\n {labels.uploadButton}\n </UploadButton>\n <UploadButtonText weight=\"semibold\">\n or drop them here\n </UploadButtonText>\n </UploadButtonContainer>\n )}\n </FileUploadDropzone>\n </FileUploadContext.Provider>\n );\n};\n"],"names":["styleType","fileItems","title","description","maxFiles","warning","className","name","id","testId","accept","capture","multiple","disabled","sortable","fileDescriptionMaxLength","editableFileItems","descriptionRequired","descriptionLabel","errorMessage","readOnly","customLabels","onChange","onDelete","onEdit","onSort","labels","uploadButton","uploadButtonLabel","dropzoneRef","useRef","fileListRef","activeId","setActiveId","useState","reachedMaxFiles","length","_jsx","FileUploadContext","Provider","value","children","_jsxs","FileUploadDropzone","ref","files","_a","current","focus","border","TextContainer","Title","TitleContainer","Description","DescriptionContainer","WarningAlert","type","FileList","onItemDelete","item","onItemUpdate","updatedItem","updatedItems","ErrorAlert","UploadButtonContainer","UploadButton","onClick","event","preventDefault","openFileDialog","UploadButtonText","weight"],"mappings":"4MAkB0B,EACtBA,YAAY,WACZC,YACAC,QACAC,cACAC,WACAC,UACAC,YACAC,OACAC,KACA,cAAeC,EACfC,SACAC,UACAC,WACAC,WACAC,YAAW,EACXC,2BACAC,qBAAoB,EACpBC,uBAAsB,EACtBC,mBACAC,eACAC,WACAC,eACAC,WACAC,WACAC,SACAC,aAEA,MAAMC,EAAS,CACXC,cAAcN,eAAAA,EAAcO,oBAAqB,gBAK/CC,EAAcC,EAAAA,OAAwB,MACtCC,EAAcD,EAAAA,OAAoB,OACjCE,EAAUC,GAAeC,aA6C1BC,EAAkB,OACb/B,IAAYH,IAAYA,EAAUmC,QAAUhC,EA8BvD,OACIiC,EAAAA,IAACC,EAAAA,kBAAkBC,UAASC,MAAO,CAAER,WAAUC,eAAaQ,SACxDC,EAAAA,KAACC,EAAAA,mBAAkB,CACfC,IAAKf,EACLP,SA3EUuB,WACbhC,GAAYS,IACbA,EAASuB,GACU,QAAnBC,EAAAf,EAAYgB,eAAO,IAAAD,GAAAA,EAAEE,QACzB,EAwEQxC,GAAIA,EAAK,GAAGA,aAAgB,WAC5BE,OAAQA,EACRC,QAASA,EACTsC,OAAsB,aAAdjD,EACRM,UAAWA,gBACEG,EACbF,KAAMA,EACNK,SAAUA,EACVC,SAAUA,GAAYsB,KAAqBf,EAAQqB,SAAA,IAE/CvC,IAASC,IACTuC,EAAAA,KAACQ,EAAAA,cAAa,CAAAT,SAAA,CAvCrBvC,EAIgB,iBAAVA,EACAmC,EAAAA,IAACc,EAAAA,MAAK,CAAAV,SAAEvC,IAGZmC,EAAAA,IAACe,EAAAA,eAAc,CAAAX,SAAEvC,IAPb,KAWNC,EAIsB,iBAAhBA,EACAkC,EAAAA,IAACgB,EAAAA,YAAW,CAAAZ,SAAEtC,IAGlBkC,EAAAA,IAACiB,EAAAA,qBAAoB,CAAAb,SAAEtC,IAPnB,UA+BAE,GACCgC,MAACkB,EAAAA,aAAY,CAACC,KAAK,UAASf,SAAEpC,IAElCgC,EAAAA,IAACoB,YACGb,IAAKb,EACL9B,UAAWA,EACXe,kBAAmBA,EACnBC,oBAAqBA,EACrBC,iBAAkBA,EAClBH,yBAA0BA,EAC1BD,SAAUA,EACVD,SAAUA,EACVO,SAAUA,EACVsC,aAlGUC,UAClBpC,IACAA,EAASoC,GACU,QAAnBb,EAAAf,EAAYgB,eAAO,IAAAD,GAAAA,EAAEE,QACzB,EA+FYY,aAjFUC,IAClBrC,GACAA,EAAOqC,EACX,EA+EYpC,OA5EIqC,IACZrC,GACAA,EAAOqC,EACX,IA2ES3C,GACGkB,EAAAA,IAAC0B,EAAAA,WAAU,CAACP,KAAK,QAAOf,SAAEtB,KAE5BC,GACEsB,EAAAA,KAACsB,EAAAA,sBAAqB,CAAAvB,SAAA,CAClBJ,EAAAA,IAAC4B,EAAAA,aAAY,CACTT,KAAK,SACLxD,UAAU,YACVa,WACMmB,GAAYnB,GAAYsB,IAE9B+B,QAzGpBC,IAEKtD,IACDsD,EAAMC,iBACFvC,EAAYkB,SACZlB,EAAYkB,QAAQsB,iBAE5B,EAkGoD5B,SAE/Bf,EAAOC,eAEZU,EAAAA,IAACiC,EAAAA,iBAAgB,CAACC,OAAO,WAAU9B,SAAA,6BAMtB"}
|
|
@@ -1,29 +1,32 @@
|
|
|
1
|
-
"use strict";var e=require("styled-components"),
|
|
1
|
+
"use strict";var e=require("styled-components"),o=require("@lifesg/react-icons/exclamation-circle-fill"),t=require("../shared/html-content/html-content.js"),r=require("../theme/index.js");function l(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var i=l(e);const n=i.default.div`
|
|
2
2
|
margin-bottom: ${r.Spacing["spacing-8"]};
|
|
3
|
-
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: ${r.Spacing["spacing-4"]};
|
|
6
|
+
`,a=i.default.label`
|
|
4
7
|
color: ${r.Colour["text-subtle"]};
|
|
5
8
|
display: inline-block;
|
|
6
9
|
|
|
7
10
|
${r.Font["form-label"]}
|
|
8
|
-
${
|
|
11
|
+
${t.applyHtmlContentStyle()}
|
|
9
12
|
font-weight: ${r.Font.Spec["weight-semibold"]};
|
|
10
|
-
`,s=
|
|
13
|
+
`,s=i.default(o.ExclamationCircleFillIcon)`
|
|
11
14
|
height: 1lh;
|
|
12
15
|
width: 1em;
|
|
13
16
|
flex-shrink: 0;
|
|
14
17
|
color: ${r.Colour["icon-error-strong"]};
|
|
15
|
-
`,c=
|
|
18
|
+
`,c=i.default.div`
|
|
16
19
|
${r.Font["body-sm-semibold"]}
|
|
17
20
|
display: flex;
|
|
18
21
|
gap: ${r.Spacing["spacing-4"]};
|
|
19
22
|
margin-top: ${r.Spacing["spacing-8"]};
|
|
20
|
-
`,p=
|
|
23
|
+
`,p=i.default.p`
|
|
21
24
|
color: ${r.Colour["text-error"]};
|
|
22
25
|
margin-bottom: 0;
|
|
23
26
|
outline: none;
|
|
24
|
-
`,u=
|
|
27
|
+
`,u=i.default.span`
|
|
25
28
|
${r.Font["form-description"]}
|
|
26
29
|
color: ${r.Colour["text-subtler"]};
|
|
27
30
|
display: block;
|
|
28
|
-
`;exports.ErrorIcon=s,exports.ErrorMessage=p,exports.ErrorMessageContainer=c,exports.Label=a,exports.LabelContainer=
|
|
31
|
+
`;exports.ErrorIcon=s,exports.ErrorMessage=p,exports.ErrorMessageContainer=c,exports.Label=a,exports.LabelContainer=n,exports.Subtitle=u;
|
|
29
32
|
//# sourceMappingURL=form-label.style.js.map
|