@lifesg/react-design-system 3.5.0-canary.7 → 3.5.0

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.
Files changed (133) hide show
  1. package/_virtual/_tslib.js +1 -1
  2. package/accordion/accordion-item.js +1 -1
  3. package/accordion/accordion-item.js.map +1 -1
  4. package/accordion/types.d.ts +7 -0
  5. package/button/button.style.js +20 -19
  6. package/button/button.style.js.map +1 -1
  7. package/cjs/_virtual/_tslib.js +1 -1
  8. package/cjs/accordion/accordion-item.js +1 -1
  9. package/cjs/accordion/accordion-item.js.map +1 -1
  10. package/cjs/button/button.style.js +3 -2
  11. package/cjs/button/button.style.js.map +1 -1
  12. package/cjs/external/@govtechsg/sgds-web-component/base/sgds-element.js +2 -0
  13. package/cjs/external/@govtechsg/sgds-web-component/base/sgds-element.js.map +1 -0
  14. package/cjs/external/@govtechsg/sgds-web-component/base/sgds-element2.js +2 -0
  15. package/cjs/external/@govtechsg/sgds-web-component/base/sgds-element2.js.map +1 -0
  16. package/cjs/external/@govtechsg/sgds-web-component/components/Masthead/index.js +2 -0
  17. package/cjs/external/@govtechsg/sgds-web-component/components/Masthead/index.js.map +1 -0
  18. package/cjs/external/@govtechsg/sgds-web-component/components/Masthead/masthead.js +2 -0
  19. package/cjs/external/@govtechsg/sgds-web-component/components/Masthead/masthead.js.map +1 -0
  20. package/cjs/external/@govtechsg/sgds-web-component/components/Masthead/sgds-masthead.js +154 -0
  21. package/cjs/external/@govtechsg/sgds-web-component/components/Masthead/sgds-masthead.js.map +1 -0
  22. package/cjs/external/@govtechsg/sgds-web-component/styles/anchor.js +2 -0
  23. package/cjs/external/@govtechsg/sgds-web-component/styles/anchor.js.map +1 -0
  24. package/cjs/external/@govtechsg/sgds-web-component/styles/svg.js +2 -0
  25. package/cjs/external/@govtechsg/sgds-web-component/styles/svg.js.map +1 -0
  26. package/cjs/external/@govtechsg/sgds-web-component/themes/day.css.js +1 -1
  27. package/cjs/external/@govtechsg/sgds-web-component/themes/night.css.js +1 -1
  28. package/cjs/external/@govtechsg/sgds-web-component/utils/ce-registry.js +2 -0
  29. package/cjs/external/@govtechsg/sgds-web-component/utils/ce-registry.js.map +1 -0
  30. package/cjs/external/@lit/reactive-element/css-tag.js +7 -0
  31. package/cjs/external/@lit/reactive-element/css-tag.js.map +1 -0
  32. package/cjs/external/@lit/reactive-element/decorators/property.js +7 -0
  33. package/cjs/external/@lit/reactive-element/decorators/property.js.map +1 -0
  34. package/cjs/external/@lit/reactive-element/decorators/state.js +7 -0
  35. package/cjs/external/@lit/reactive-element/decorators/state.js.map +1 -0
  36. package/cjs/external/@lit/reactive-element/reactive-element.js +7 -0
  37. package/cjs/external/@lit/reactive-element/reactive-element.js.map +1 -0
  38. package/cjs/external/lit-element/lit-element.js +8 -0
  39. package/cjs/external/lit-element/lit-element.js.map +1 -0
  40. package/cjs/external/lit-html/lit-html.js +7 -0
  41. package/cjs/external/lit-html/lit-html.js.map +1 -0
  42. package/cjs/file-download/file-download.js +1 -1
  43. package/cjs/file-download/file-download.js.map +1 -1
  44. package/cjs/file-download/file-list-card/file-list-card.js +1 -1
  45. package/cjs/file-download/file-list-card/file-list-card.js.map +1 -1
  46. package/cjs/file-download/file-list-card/file-list-card.styles.js +75 -59
  47. package/cjs/file-download/file-list-card/file-list-card.styles.js.map +1 -1
  48. package/cjs/file-upload/helper.js +1 -1
  49. package/cjs/file-upload/helper.js.map +1 -1
  50. package/cjs/fullscreen-image-carousel/fullscreen-image-carousel.js +1 -1
  51. package/cjs/fullscreen-image-carousel/fullscreen-image-carousel.js.map +1 -1
  52. package/cjs/fullscreen-image-carousel/fullscreen-image-carousel.style.js +19 -19
  53. package/cjs/fullscreen-image-carousel/fullscreen-image-carousel.style.js.map +1 -1
  54. package/cjs/masthead/masthead.js +1 -1
  55. package/cjs/masthead/masthead.js.map +1 -1
  56. package/cjs/navbar/menu.js +1 -1
  57. package/cjs/navbar/menu.js.map +1 -1
  58. package/cjs/navbar/menu.styles.js +1 -1
  59. package/cjs/navbar/menu.styles.js.map +1 -1
  60. package/cjs/navbar/navbar-items.js +1 -1
  61. package/cjs/navbar/navbar-items.js.map +1 -1
  62. package/cjs/navbar/navbar-items.styles.js +20 -21
  63. package/cjs/navbar/navbar-items.styles.js.map +1 -1
  64. package/cjs/notification-banner/notification-banner-hoc.js +1 -1
  65. package/cjs/notification-banner/notification-banner-hoc.js.map +1 -1
  66. package/codemods/run-codemod.js +10 -3
  67. package/codemods/run-codemod.js.map +1 -1
  68. package/codemods/run-codemod.ts +12 -4
  69. package/external/@govtechsg/sgds-web-component/base/sgds-element.js +2 -0
  70. package/external/@govtechsg/sgds-web-component/base/sgds-element.js.map +1 -0
  71. package/external/@govtechsg/sgds-web-component/base/sgds-element2.js +2 -0
  72. package/external/@govtechsg/sgds-web-component/base/sgds-element2.js.map +1 -0
  73. package/external/@govtechsg/sgds-web-component/components/Masthead/index.js +2 -0
  74. package/external/@govtechsg/sgds-web-component/components/Masthead/index.js.map +1 -0
  75. package/external/@govtechsg/sgds-web-component/components/Masthead/masthead.js +2 -0
  76. package/external/@govtechsg/sgds-web-component/components/Masthead/masthead.js.map +1 -0
  77. package/external/@govtechsg/sgds-web-component/components/Masthead/sgds-masthead.js +154 -0
  78. package/external/@govtechsg/sgds-web-component/components/Masthead/sgds-masthead.js.map +1 -0
  79. package/external/@govtechsg/sgds-web-component/styles/anchor.js +2 -0
  80. package/external/@govtechsg/sgds-web-component/styles/anchor.js.map +1 -0
  81. package/external/@govtechsg/sgds-web-component/styles/svg.js +2 -0
  82. package/external/@govtechsg/sgds-web-component/styles/svg.js.map +1 -0
  83. package/external/@govtechsg/sgds-web-component/themes/day.css.js +1 -1
  84. package/external/@govtechsg/sgds-web-component/themes/night.css.js +1 -1
  85. package/external/@govtechsg/sgds-web-component/utils/ce-registry.js +2 -0
  86. package/external/@govtechsg/sgds-web-component/utils/ce-registry.js.map +1 -0
  87. package/external/@lit/reactive-element/css-tag.js +7 -0
  88. package/external/@lit/reactive-element/css-tag.js.map +1 -0
  89. package/external/@lit/reactive-element/decorators/property.js +7 -0
  90. package/external/@lit/reactive-element/decorators/property.js.map +1 -0
  91. package/external/@lit/reactive-element/decorators/state.js +7 -0
  92. package/external/@lit/reactive-element/decorators/state.js.map +1 -0
  93. package/external/@lit/reactive-element/reactive-element.js +7 -0
  94. package/external/@lit/reactive-element/reactive-element.js.map +1 -0
  95. package/external/lit-element/lit-element.js +7 -0
  96. package/external/lit-element/lit-element.js.map +1 -0
  97. package/external/lit-html/lit-html.js +7 -0
  98. package/external/lit-html/lit-html.js.map +1 -0
  99. package/file-download/file-download.d.ts +1 -1
  100. package/file-download/file-download.js +1 -1
  101. package/file-download/file-download.js.map +1 -1
  102. package/file-download/file-list-card/file-list-card.d.ts +1 -1
  103. package/file-download/file-list-card/file-list-card.js +1 -1
  104. package/file-download/file-list-card/file-list-card.js.map +1 -1
  105. package/file-download/file-list-card/file-list-card.styles.d.ts +8 -0
  106. package/file-download/file-list-card/file-list-card.styles.js +53 -37
  107. package/file-download/file-list-card/file-list-card.styles.js.map +1 -1
  108. package/file-download/file-list-card/types.d.ts +2 -1
  109. package/file-download/types.d.ts +7 -0
  110. package/file-upload/helper.d.ts +30 -0
  111. package/file-upload/helper.js +1 -1
  112. package/file-upload/helper.js.map +1 -1
  113. package/fullscreen-image-carousel/fullscreen-image-carousel.d.ts +1 -1
  114. package/fullscreen-image-carousel/fullscreen-image-carousel.js +1 -1
  115. package/fullscreen-image-carousel/fullscreen-image-carousel.js.map +1 -1
  116. package/fullscreen-image-carousel/fullscreen-image-carousel.style.d.ts +7 -0
  117. package/fullscreen-image-carousel/fullscreen-image-carousel.style.js +21 -21
  118. package/fullscreen-image-carousel/fullscreen-image-carousel.style.js.map +1 -1
  119. package/fullscreen-image-carousel/types.d.ts +16 -0
  120. package/masthead/masthead.js +1 -1
  121. package/masthead/masthead.js.map +1 -1
  122. package/navbar/menu.d.ts +2 -1
  123. package/navbar/menu.js +1 -1
  124. package/navbar/menu.js.map +1 -1
  125. package/navbar/menu.styles.js +3 -3
  126. package/navbar/menu.styles.js.map +1 -1
  127. package/navbar/navbar-items.js +1 -1
  128. package/navbar/navbar-items.js.map +1 -1
  129. package/navbar/navbar-items.styles.js +30 -31
  130. package/navbar/navbar-items.styles.js.map +1 -1
  131. package/notification-banner/notification-banner-hoc.js +1 -1
  132. package/notification-banner/notification-banner-hoc.js.map +1 -1
  133. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e}from"@lifesg/react-icons/exclamation-circle-fill";import{IconButton as t}from"../../icon-button/icon-button.js";import{ComponentLoadingSpinner as n}from"../../shared/component-loading-spinner/component-loading-spinner.js";import{ImageWithFallback as o}from"../../shared/image-with-fallback/image-with-fallback.js";import{lineClampCss as a}from"../../shared/styles/index.js";import{Spacing as l,Colour as d,Border as s,Radius as g,MediaQuery as c,Font as m}from"../../theme/index.js";const p=i.li`
1
+ import i,{css as e}from"styled-components";import{ExclamationCircleFillIcon as r}from"@lifesg/react-icons/exclamation-circle-fill";import{IconButton as t}from"../../icon-button/icon-button.js";import{ComponentLoadingSpinner as o}from"../../shared/component-loading-spinner/component-loading-spinner.js";import{ImageWithFallback as n}from"../../shared/image-with-fallback/image-with-fallback.js";import{lineClampCss as a}from"../../shared/styles/index.js";import{Spacing as l,Colour as d,Border as s,Radius as c,MediaQuery as g,Font as p}from"../../theme/index.js";const m=i.li`
2
2
  display: flex;
3
3
  align-items: center;
4
4
 
@@ -8,7 +8,12 @@ import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e
8
8
  &:not(:last-child) {
9
9
  margin-bottom: ${l["spacing-16"]};
10
10
  }
11
- `,$=i.div`
11
+ `,$=i.button`
12
+ appearance: none;
13
+ padding: 0;
14
+ background: none;
15
+ border: none;
16
+ `,h=i.div`
12
17
  display: flex;
13
18
  align-items: center;
14
19
 
@@ -18,9 +23,9 @@ import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e
18
23
 
19
24
  background: ${d["bg-primary-subtlest"]};
20
25
  border: ${s["width-010"]} ${s.solid} ${d.border};
21
- border-radius: ${g.sm};
26
+ border-radius: ${c.sm};
22
27
 
23
- ${c.MaxWidth.lg} {
28
+ ${g.MaxWidth.lg} {
24
29
  padding: ${l["spacing-16"]};
25
30
  }
26
31
 
@@ -28,32 +33,41 @@ import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e
28
33
  background: ${d["bg-hover"]};
29
34
  }
30
35
 
31
- ${i=>{if(i.$error)return r`
36
+ &:has(${$}:focus-visible) {
37
+ outline: 2px solid ${d["focus-ring"]};
38
+ outline-offset: -2px;
39
+ }
40
+
41
+ ${i=>{if(i.$error)return e`
32
42
  background: ${d["bg-error"]};
33
43
  border-color: ${d["border-error"]};
34
44
 
35
45
  &:hover {
36
46
  background: ${d["bg-error"]};
37
47
  }
48
+
49
+ &:has(${$}:focus-visible) {
50
+ outline-color: ${d["border-error-focus"]};
51
+ }
38
52
  `}}
39
- `,h=i.div`
53
+ `,f=i.div`
40
54
  display: flex;
41
55
  flex: 1;
42
56
  align-items: center;
43
57
 
44
- ${c.MaxWidth.lg} {
58
+ ${g.MaxWidth.lg} {
45
59
  flex-direction: column;
46
60
  align-items: flex-start;
47
61
  width: 100%;
48
62
  }
49
63
 
50
- ${i=>{if(i.$hasThumbnail)return r`
51
- ${c.MaxWidth.lg} {
64
+ ${i=>{if(i.$hasThumbnail)return e`
65
+ ${g.MaxWidth.lg} {
52
66
  flex-direction: row;
53
67
  align-items: center;
54
68
  }
55
69
  `}}
56
- `,f=i.div`
70
+ `,x=i.div`
57
71
  display: flex;
58
72
  flex: 1;
59
73
  flex-direction: column;
@@ -63,27 +77,27 @@ import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e
63
77
  overflow-wrap: break-word;
64
78
  word-break: break-all;
65
79
  white-space: normal;
66
- `,x=i.div`
80
+ `,b=i.div`
67
81
  display: flex;
68
82
  flex: 1;
69
83
  align-items: center;
70
84
 
71
- ${c.MaxWidth.lg} {
85
+ ${g.MaxWidth.lg} {
72
86
  flex-direction: column;
73
87
  align-items: flex-start;
74
88
  width: 100%;
75
89
  }
76
- `,b=i.div`
90
+ `,u=i.div`
77
91
  display: flex;
78
92
  justify-content: flex-end;
79
93
 
80
94
  width: 5rem;
81
95
  margin-left: ${l["spacing-8"]};
82
96
 
83
- ${m["body-md-regular"]}
97
+ ${p["body-md-regular"]}
84
98
  color: ${d.text};
85
99
 
86
- ${c.MaxWidth.lg} {
100
+ ${g.MaxWidth.lg} {
87
101
  justify-content: flex-start;
88
102
 
89
103
  width: 100%;
@@ -92,62 +106,62 @@ import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e
92
106
 
93
107
  ${a(2)}
94
108
  }
95
- `,u=i.div`
96
- ${m["body-md-regular"]}
109
+ `,y=i.div`
110
+ ${p["body-md-regular"]}
97
111
  color: ${d.text};
98
112
 
99
- ${c.MaxWidth.lg} {
113
+ ${g.MaxWidth.lg} {
100
114
  ${a(2)}
101
115
  }
102
- `;i(u)`
103
- ${m["body-md-regular"]}
116
+ `;i(y)`
117
+ ${p["body-md-regular"]}
104
118
  margin-top: ${l["spacing-4"]};
105
- `;const y=i(e)`
119
+ `;const w=i(r)`
106
120
  height: 1lh;
107
121
  width: 1em;
108
122
  flex-shrink: 0;
109
123
  color: ${d["icon-error-strong"]};
110
- `,w=i.div`
111
- ${m["body-sm-semibold"]}
124
+ `,v=i.div`
125
+ ${p["body-sm-semibold"]}
112
126
  color: ${d["text-error"]};
113
- `,v=i(w)`
127
+ `,k=i(v)`
114
128
  margin-top: ${l["spacing-8"]};
115
129
  display: flex;
116
130
  gap: ${l["spacing-4"]};
117
131
 
118
- ${c.MaxWidth.lg} {
132
+ ${g.MaxWidth.lg} {
119
133
  display: none;
120
134
  visibility: hidden;
121
135
  }
122
- `,k=i(w)`
136
+ `,M=i(v)`
123
137
  display: none;
124
138
  visibility: hidden;
125
139
 
126
- ${c.MaxWidth.lg} {
140
+ ${g.MaxWidth.lg} {
127
141
  display: flex;
128
142
  gap: ${l["spacing-4"]};
129
143
  visibility: visible;
130
144
  margin-top: ${l["spacing-8"]};
131
145
  }
132
- `,M=i(n)`
146
+ `,W=i(o)`
133
147
  color: ${d["icon-primary"]};
134
- `,W=i.div`
148
+ `,j=i.div`
135
149
  display: flex;
136
150
  justify-content: flex-end;
137
151
  align-items: center;
138
152
 
139
153
  margin-left: ${l["spacing-32"]};
140
154
 
141
- ${c.MaxWidth.lg} {
155
+ ${g.MaxWidth.lg} {
142
156
  margin-left: ${l["spacing-16"]};
143
157
  }
144
- `,j=i(t)`
158
+ `,B=i(t)`
145
159
  min-width: unset;
146
160
 
147
161
  &:not(:last-child) {
148
162
  margin-right: ${l["spacing-16"]};
149
163
  }
150
- `,B=i.div`
164
+ `,I=i.div`
151
165
  width: auto;
152
166
  margin-right: ${l["spacing-32"]};
153
167
 
@@ -156,11 +170,11 @@ import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e
156
170
  flex-direction: column;
157
171
  justify-content: center;
158
172
 
159
- ${c.MaxWidth.lg} {
173
+ ${g.MaxWidth.lg} {
160
174
  margin-right: ${l["spacing-16"]};
161
175
  }
162
- `,I=i(o)`
163
- border-radius: ${g.sm};
176
+ `,T=i(n)`
177
+ border-radius: ${c.sm};
164
178
  border: ${s["width-010"]} ${s.solid} ${d.border};
165
179
 
166
180
  width: 96px;
@@ -168,9 +182,11 @@ import i,{css as r}from"styled-components";import{ExclamationCircleFillIcon as e
168
182
  aspect-ratio: 1;
169
183
  object-fit: cover;
170
184
 
171
- ${c.MaxWidth.lg} {
185
+ ${g.MaxWidth.lg} {
172
186
  width: 64px;
173
187
  height: 64px;
174
188
  }
175
- `;export{W as ActionContainer,$ as Box,h as ContentSection,v as DesktopErrorMessage,y as ErrorIcon,x as ExtendedNameSection,b as FileSizeSection,j as IconButton,p as Item,u as ItemNameText,k as MobileErrorMessage,f as NameSection,M as Spinner,I as Thumbnail,B as ThumbnailContainer};
189
+ `,q=i(T)`
190
+ border: none;
191
+ `;export{j as ActionContainer,h as Box,$ as CardButton,f as ContentSection,k as DesktopErrorMessage,w as ErrorIcon,b as ExtendedNameSection,u as FileSizeSection,B as IconButton,m as Item,y as ItemNameText,M as MobileErrorMessage,x as NameSection,q as PdfThumbnail,W as Spinner,T as Thumbnail,I as ThumbnailContainer};
176
192
  //# sourceMappingURL=file-list-card.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-list-card.styles.js","sources":["../../../src/file-download/file-list-card/file-list-card.styles.tsx"],"sourcesContent":["import styled, { css } from \"styled-components\";\nimport { ExclamationCircleFillIcon } from \"@lifesg/react-icons/exclamation-circle-fill\";\nimport { IconButton as DSIconButton } from \"../../icon-button\";\nimport { ComponentLoadingSpinner } from \"../../shared/component-loading-spinner\";\nimport { ImageWithFallback } from \"../../shared/image-with-fallback/image-with-fallback\";\nimport { lineClampCss } from \"../../shared/styles\";\nimport { Border, Colour, Font, MediaQuery, Radius, Spacing } from \"../../theme\";\n\n// =============================================================================\n// STYLE INTERFACES\n// =============================================================================\n\ninterface BoxStyleProps {\n $error?: boolean | undefined;\n}\n\ninterface ContentSectionStyleProps {\n $hasThumbnail?: boolean | undefined;\n}\n\n// =============================================================================\n// STYLING\n// =============================================================================\nexport const Item = styled.li`\n display: flex;\n align-items: center;\n\n width: 100%;\n border: none;\n\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n`;\n\nexport const Box = styled.div<BoxStyleProps>`\n display: flex;\n align-items: center;\n\n width: 100%;\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-32\"]};\n cursor: pointer;\n\n background: ${Colour[\"bg-primary-subtlest\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n padding: ${Spacing[\"spacing-16\"]};\n }\n\n &:hover {\n background: ${Colour[\"bg-hover\"]};\n }\n\n ${(props) => {\n if (props.$error) {\n return css`\n background: ${Colour[\"bg-error\"]};\n border-color: ${Colour[\"border-error\"]};\n\n &:hover {\n background: ${Colour[\"bg-error\"]};\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.lg} {\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n }\n\n ${(props) => {\n if (props.$hasThumbnail) {\n return css`\n ${MediaQuery.MaxWidth.lg} {\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\n width: 100%;\n\n overflow-wrap: break-word;\n word-break: break-all;\n white-space: normal;\n`;\n\nexport const ExtendedNameSection = styled.div`\n display: flex;\n flex: 1;\n align-items: center;\n\n ${MediaQuery.MaxWidth.lg} {\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n }\n`;\n\nexport const FileSizeSection = styled.div`\n display: flex;\n justify-content: flex-end;\n\n width: 5rem;\n margin-left: ${Spacing[\"spacing-8\"]};\n\n ${Font[\"body-md-regular\"]}\n color: ${Colour[\"text\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n justify-content: flex-start;\n\n width: 100%;\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-8\"]};\n\n ${lineClampCss(2)}\n }\n`;\n\nexport const ItemNameText = styled.div`\n ${Font[\"body-md-regular\"]}\n color: ${Colour[\"text\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n ${lineClampCss(2)}\n }\n`;\n\nexport const ItemDescriptionText = styled(ItemNameText)`\n ${Font[\"body-md-regular\"]}\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\nconst BaseErrorMessage = styled.div`\n ${Font[\"body-sm-semibold\"]}\n color: ${Colour[\"text-error\"]};\n`;\n\nexport const DesktopErrorMessage = styled(BaseErrorMessage)`\n margin-top: ${Spacing[\"spacing-8\"]};\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n display: none;\n visibility: hidden;\n }\n`;\n\nexport const MobileErrorMessage = styled(BaseErrorMessage)`\n display: none;\n visibility: hidden;\n\n ${MediaQuery.MaxWidth.lg} {\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n visibility: visible;\n margin-top: ${Spacing[\"spacing-8\"]};\n }\n`;\n\nexport const Spinner = styled(ComponentLoadingSpinner)`\n color: ${Colour[\"icon-primary\"]};\n`;\n\nexport const ActionContainer = styled.div`\n display: flex;\n justify-content: flex-end;\n align-items: center;\n\n margin-left: ${Spacing[\"spacing-32\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n margin-left: ${Spacing[\"spacing-16\"]};\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\nexport const ThumbnailContainer = styled.div`\n width: auto;\n margin-right: ${Spacing[\"spacing-32\"]};\n\n display: flex;\n flex-shrink: 0;\n flex-direction: column;\n justify-content: center;\n\n ${MediaQuery.MaxWidth.lg} {\n margin-right: ${Spacing[\"spacing-16\"]};\n }\n`;\n\nexport const Thumbnail = styled(ImageWithFallback)`\n border-radius: ${Radius[\"sm\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n width: 96px;\n height: 96px;\n aspect-ratio: 1;\n object-fit: cover;\n\n ${MediaQuery.MaxWidth.lg} {\n width: 64px;\n height: 64px;\n }\n`;\n"],"names":["Item","styled","li","Spacing","Box","div","Colour","Border","Radius","MediaQuery","MaxWidth","lg","props","$error","css","ContentSection","$hasThumbnail","NameSection","ExtendedNameSection","FileSizeSection","Font","lineClampCss","ItemNameText","ErrorIcon","ExclamationCircleFillIcon","BaseErrorMessage","DesktopErrorMessage","MobileErrorMessage","Spinner","ComponentLoadingSpinner","ActionContainer","IconButton","DSIconButton","ThumbnailContainer","Thumbnail","ImageWithFallback"],"mappings":"ojBAuBO,MAAMA,EAAOC,EAAOC,EAAE;;;;;;;;yBAQJC,EAAQ;;EAIpBC,EAAMH,EAAOI,GAAkB;;;;;eAK7BF,EAAQ,iBAAiBA,EAAQ;;;kBAG9BG,EAAO;cACXC,EAAO,gBAAgBA,EAAc,SAAKD,EAAe;qBAClDE,EAAW;;MAE1BC,EAAWC,SAASC;mBACPR,EAAQ;;;;sBAILG,EAAO;;;MAGtBM,IACC,GAAIA,EAAMC,OACN,OAAOC,CAAG;8BACQR,EAAO;gCACLA,EAAO;;;kCAGLA,EAAO;;aAGjC;EAIKS,EAAiBd,EAAOI,GAA6B;;;;;MAK5DI,EAAWC,SAASC;;;;;;MAMnBC,IACC,GAAIA,EAAMI,cACN,OAAOF,CAAG;kBACJL,EAAWC,SAASC;;;;aAK9B;EAIKM,EAAchB,EAAOI,GAAG;;;;;;;;;;EAYxBa,EAAsBjB,EAAOI,GAAG;;;;;MAKvCI,EAAWC,SAASC;;;;;EAObQ,EAAkBlB,EAAOI,GAAG;;;;;mBAKtBF,EAAQ;;MAErBiB,EAAK;aACEd,EAAa;;MAEpBG,EAAWC,SAASC;;;;;sBAKJR,EAAQ;;UAEpBkB,EAAa;;EAIVC,EAAerB,EAAOI,GAAG;MAChCe,EAAK;aACEd,EAAa;;MAEpBG,EAAWC,SAASC;UAChBU,EAAa;;EAIYpB,EAAOqB,EAAa;MACjDF,EAAK;kBACOjB,EAAQ;QAGboB,EAAYtB,EAAOuB,EAA0B;;;;aAI7ClB,EAAO;EAGdmB,EAAmBxB,EAAOI,GAAG;MAC7Be,EAAK;aACEd,EAAO;EAGPoB,EAAsBzB,EAAOwB,EAAiB;kBACzCtB,EAAQ;;WAEfA,EAAQ;;MAEbM,EAAWC,SAASC;;;;EAMbgB,EAAqB1B,EAAOwB,EAAiB;;;;MAIpDhB,EAAWC,SAASC;;eAEXR,EAAQ;;sBAEDA,EAAQ;;EAIjByB,EAAU3B,EAAO4B,EAAwB;aACzCvB,EAAO;EAGPwB,EAAkB7B,EAAOI,GAAG;;;;;mBAKtBF,EAAQ;;MAErBM,EAAWC,SAASC;uBACHR,EAAQ;;EAIlB4B,EAAa9B,EAAO+B,EAAa;;;;wBAItB7B,EAAQ;;EAInB8B,EAAqBhC,EAAOI,GAAG;;oBAExBF,EAAQ;;;;;;;MAOtBM,EAAWC,SAASC;wBACFR,EAAQ;;EAInB+B,EAAYjC,EAAOkC,EAAkB;qBAC7B3B,EAAW;cAClBD,EAAO,gBAAgBA,EAAc,SAAKD,EAAe;;;;;;;MAOjEG,EAAWC,SAASC;;;;"}
1
+ {"version":3,"file":"file-list-card.styles.js","sources":["../../../src/file-download/file-list-card/file-list-card.styles.tsx"],"sourcesContent":["import styled, { css } from \"styled-components\";\nimport { ExclamationCircleFillIcon } from \"@lifesg/react-icons/exclamation-circle-fill\";\nimport { IconButton as DSIconButton } from \"../../icon-button\";\nimport { ComponentLoadingSpinner } from \"../../shared/component-loading-spinner\";\nimport { ImageWithFallback } from \"../../shared/image-with-fallback/image-with-fallback\";\nimport { lineClampCss } from \"../../shared/styles\";\nimport { Border, Colour, Font, MediaQuery, Radius, Spacing } from \"../../theme\";\n\n// =============================================================================\n// STYLE INTERFACES\n// =============================================================================\n\ninterface BoxStyleProps {\n $error?: boolean | undefined;\n}\n\ninterface ContentSectionStyleProps {\n $hasThumbnail?: boolean | undefined;\n}\n\n// =============================================================================\n// STYLING\n// =============================================================================\nexport const Item = styled.li`\n display: flex;\n align-items: center;\n\n width: 100%;\n border: none;\n\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n`;\n\nexport const CardButton = styled.button`\n appearance: none;\n padding: 0;\n background: none;\n border: none;\n`;\n\nexport const Box = styled.div<BoxStyleProps>`\n display: flex;\n align-items: center;\n\n width: 100%;\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-32\"]};\n cursor: pointer;\n\n background: ${Colour[\"bg-primary-subtlest\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n padding: ${Spacing[\"spacing-16\"]};\n }\n\n &:hover {\n background: ${Colour[\"bg-hover\"]};\n }\n\n &:has(${CardButton}:focus-visible) {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: -2px;\n }\n\n ${(props) => {\n if (props.$error) {\n return css`\n background: ${Colour[\"bg-error\"]};\n border-color: ${Colour[\"border-error\"]};\n\n &:hover {\n background: ${Colour[\"bg-error\"]};\n }\n\n &:has(${CardButton}:focus-visible) {\n outline-color: ${Colour[\"border-error-focus\"]};\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.lg} {\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n }\n\n ${(props) => {\n if (props.$hasThumbnail) {\n return css`\n ${MediaQuery.MaxWidth.lg} {\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\n width: 100%;\n\n overflow-wrap: break-word;\n word-break: break-all;\n white-space: normal;\n`;\n\nexport const ExtendedNameSection = styled.div`\n display: flex;\n flex: 1;\n align-items: center;\n\n ${MediaQuery.MaxWidth.lg} {\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n }\n`;\n\nexport const FileSizeSection = styled.div`\n display: flex;\n justify-content: flex-end;\n\n width: 5rem;\n margin-left: ${Spacing[\"spacing-8\"]};\n\n ${Font[\"body-md-regular\"]}\n color: ${Colour[\"text\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n justify-content: flex-start;\n\n width: 100%;\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-8\"]};\n\n ${lineClampCss(2)}\n }\n`;\n\nexport const ItemNameText = styled.div`\n ${Font[\"body-md-regular\"]}\n color: ${Colour[\"text\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n ${lineClampCss(2)}\n }\n`;\n\nexport const ItemDescriptionText = styled(ItemNameText)`\n ${Font[\"body-md-regular\"]}\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\nconst BaseErrorMessage = styled.div`\n ${Font[\"body-sm-semibold\"]}\n color: ${Colour[\"text-error\"]};\n`;\n\nexport const DesktopErrorMessage = styled(BaseErrorMessage)`\n margin-top: ${Spacing[\"spacing-8\"]};\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n display: none;\n visibility: hidden;\n }\n`;\n\nexport const MobileErrorMessage = styled(BaseErrorMessage)`\n display: none;\n visibility: hidden;\n\n ${MediaQuery.MaxWidth.lg} {\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n visibility: visible;\n margin-top: ${Spacing[\"spacing-8\"]};\n }\n`;\n\nexport const Spinner = styled(ComponentLoadingSpinner)`\n color: ${Colour[\"icon-primary\"]};\n`;\n\nexport const ActionContainer = styled.div`\n display: flex;\n justify-content: flex-end;\n align-items: center;\n\n margin-left: ${Spacing[\"spacing-32\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n margin-left: ${Spacing[\"spacing-16\"]};\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\nexport const ThumbnailContainer = styled.div`\n width: auto;\n margin-right: ${Spacing[\"spacing-32\"]};\n\n display: flex;\n flex-shrink: 0;\n flex-direction: column;\n justify-content: center;\n\n ${MediaQuery.MaxWidth.lg} {\n margin-right: ${Spacing[\"spacing-16\"]};\n }\n`;\n\nexport const Thumbnail = styled(ImageWithFallback)`\n border-radius: ${Radius[\"sm\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n width: 96px;\n height: 96px;\n aspect-ratio: 1;\n object-fit: cover;\n\n ${MediaQuery.MaxWidth.lg} {\n width: 64px;\n height: 64px;\n }\n`;\n\nexport const PdfThumbnail = styled(Thumbnail)`\n border: none;\n`;\n"],"names":["Item","styled","li","Spacing","CardButton","button","Box","div","Colour","Border","Radius","MediaQuery","MaxWidth","lg","props","$error","css","ContentSection","$hasThumbnail","NameSection","ExtendedNameSection","FileSizeSection","Font","lineClampCss","ItemNameText","ErrorIcon","ExclamationCircleFillIcon","BaseErrorMessage","DesktopErrorMessage","MobileErrorMessage","Spinner","ComponentLoadingSpinner","ActionContainer","IconButton","DSIconButton","ThumbnailContainer","Thumbnail","ImageWithFallback","PdfThumbnail"],"mappings":"ojBAuBO,MAAMA,EAAOC,EAAOC,EAAE;;;;;;;;yBAQJC,EAAQ;;EAIpBC,EAAaH,EAAOI,MAAM;;;;;EAO1BC,EAAML,EAAOM,GAAkB;;;;;eAK7BJ,EAAQ,iBAAiBA,EAAQ;;;kBAG9BK,EAAO;cACXC,EAAO,gBAAgBA,EAAc,SAAKD,EAAe;qBAClDE,EAAW;;MAE1BC,EAAWC,SAASC;mBACPV,EAAQ;;;;sBAILK,EAAO;;;YAGjBJ;6BACiBI,EAAO;;;;MAI7BM,IACC,GAAIA,EAAMC,OACN,OAAOC,CAAG;8BACQR,EAAO;gCACLA,EAAO;;;kCAGLA,EAAO;;;wBAGjBJ;qCACaI,EAAO;;aAGpC;EAIKS,EAAiBhB,EAAOM,GAA6B;;;;;MAK5DI,EAAWC,SAASC;;;;;;MAMnBC,IACC,GAAIA,EAAMI,cACN,OAAOF,CAAG;kBACJL,EAAWC,SAASC;;;;aAK9B;EAIKM,EAAclB,EAAOM,GAAG;;;;;;;;;;EAYxBa,EAAsBnB,EAAOM,GAAG;;;;;MAKvCI,EAAWC,SAASC;;;;;EAObQ,EAAkBpB,EAAOM,GAAG;;;;;mBAKtBJ,EAAQ;;MAErBmB,EAAK;aACEd,EAAa;;MAEpBG,EAAWC,SAASC;;;;;sBAKJV,EAAQ;;UAEpBoB,EAAa;;EAIVC,EAAevB,EAAOM,GAAG;MAChCe,EAAK;aACEd,EAAa;;MAEpBG,EAAWC,SAASC;UAChBU,EAAa;;EAIYtB,EAAOuB,EAAa;MACjDF,EAAK;kBACOnB,EAAQ;QAGbsB,EAAYxB,EAAOyB,EAA0B;;;;aAI7ClB,EAAO;EAGdmB,EAAmB1B,EAAOM,GAAG;MAC7Be,EAAK;aACEd,EAAO;EAGPoB,EAAsB3B,EAAO0B,EAAiB;kBACzCxB,EAAQ;;WAEfA,EAAQ;;MAEbQ,EAAWC,SAASC;;;;EAMbgB,EAAqB5B,EAAO0B,EAAiB;;;;MAIpDhB,EAAWC,SAASC;;eAEXV,EAAQ;;sBAEDA,EAAQ;;EAIjB2B,EAAU7B,EAAO8B,EAAwB;aACzCvB,EAAO;EAGPwB,EAAkB/B,EAAOM,GAAG;;;;;mBAKtBJ,EAAQ;;MAErBQ,EAAWC,SAASC;uBACHV,EAAQ;;EAIlB8B,EAAahC,EAAOiC,EAAa;;;;wBAItB/B,EAAQ;;EAInBgC,EAAqBlC,EAAOM,GAAG;;oBAExBJ,EAAQ;;;;;;;MAOtBQ,EAAWC,SAASC;wBACFV,EAAQ;;EAInBiC,EAAYnC,EAAOoC,EAAkB;qBAC7B3B,EAAW;cAClBD,EAAO,gBAAgBA,EAAc,SAAKD,EAAe;;;;;;;MAOjEG,EAAWC,SAASC;;;;EAMbyB,EAAerC,EAAOmC,EAAU;;"}
@@ -1,5 +1,6 @@
1
- import { FileItemDownloadProps } from "../types";
1
+ import type { FileItemDownloadProps } from "../types";
2
2
  export interface FileListItemProps {
3
3
  fileItem: FileItemDownloadProps;
4
4
  onDownload: (file: FileItemDownloadProps) => void | Promise<void>;
5
+ onClick?: ((file: FileItemDownloadProps) => void) | undefined;
5
6
  }
@@ -16,6 +16,8 @@ export interface FileItemDownloadProps {
16
16
  truncateText?: boolean | undefined;
17
17
  /** Indicate if file is ready for download, defaults to true */
18
18
  ready?: boolean | undefined;
19
+ /** Name for the card, used when `FileDownload` is given an `onClick`. */
20
+ clickLabel?: string | undefined;
19
21
  }
20
22
  export type FileDownloadStyle = "bordered" | "no-border";
21
23
  export interface FileDownloadProps {
@@ -30,4 +32,9 @@ export interface FileDownloadProps {
30
32
  id?: string | undefined;
31
33
  /** Called when file item is clicked */
32
34
  onDownload: (file: FileItemDownloadProps) => void | Promise<void>;
35
+ /**
36
+ * Called when a file card itself is activated, as opposed to its download button.
37
+ * When omitted, activating the card triggers `onDownload` instead.
38
+ */
39
+ onClick?: ((file: FileItemDownloadProps) => void) | undefined;
33
40
  }
@@ -1,6 +1,36 @@
1
+ /**
2
+ * How a file's thumbnail slot should be rendered.
3
+ *
4
+ * - `image` — a thumbnail was supplied; render it at `src`
5
+ * - `pdf-icon` — a PDF with no thumbnail; render the PDF badge borderless
6
+ * - `none` — nothing to show; render no thumbnail slot at all
7
+ */
8
+ export type FileThumbnailDisplay = {
9
+ type: "image";
10
+ src: string;
11
+ } | {
12
+ type: "pdf-icon";
13
+ } | {
14
+ type: "none";
15
+ };
1
16
  export declare namespace FileUploadHelper {
2
17
  const PDF_MIME_TYPE = "application/pdf";
3
18
  const PDF_ICON_URL = "https://assets.life.gov.sg/react-design-system/img/upload/pdf.svg";
4
19
  const formatFileSizeDisplay: (size?: number) => string;
5
20
  const isSupportedImageType: (type: string) => boolean;
21
+ /**
22
+ * Decides how a file's thumbnail slot should render, given its MIME type
23
+ * and any thumbnail the consumer supplied.
24
+ *
25
+ * Lives on `FileUploadHelper` so `FileUpload` can adopt it later. Today
26
+ * only `FileDownload` calls it: `FileUpload` still decides this inline in
27
+ * `file-list-item-thumbnail.tsx`, and the two do NOT yet agree — for a
28
+ * non-PDF with no thumbnail this returns `"none"` while `FileUpload`
29
+ * renders an `<img>` with an empty `src`. Do not read this as an invariant
30
+ * the two components already share.
31
+ *
32
+ * Callers render the result with their own markup, because their thumbnails
33
+ * change size at different breakpoints.
34
+ */
35
+ const resolveThumbnailDisplay: (mimeType: string | undefined, thumbnailImageDataUrl: string | undefined) => FileThumbnailDisplay;
6
36
  }
@@ -1,2 +1,2 @@
1
- var e;!function(e){e.PDF_MIME_TYPE="application/pdf",e.PDF_ICON_URL="https://assets.life.gov.sg/react-design-system/img/upload/pdf.svg",e.formatFileSizeDisplay=e=>{if(!e||0===e)return"0 KB";const i=Math.floor(Math.log(e)/Math.log(1024));return`${Number(e/Math.pow(1024,i)).toFixed(0)} ${["B","KB","MB","GB","TB","PB","EB","ZB","YB"][i]}`},e.isSupportedImageType=e=>["image/avif","image/gif","image/jpeg","image/png","image/svg+xml","image/webp"].includes(e)}(e||(e={}));export{e as FileUploadHelper};
1
+ var e;!function(e){e.PDF_MIME_TYPE="application/pdf",e.PDF_ICON_URL="https://assets.life.gov.sg/react-design-system/img/upload/pdf.svg",e.formatFileSizeDisplay=e=>{if(!e||0===e)return"0 KB";const i=Math.floor(Math.log(e)/Math.log(1024));return`${Number(e/Math.pow(1024,i)).toFixed(0)} ${["B","KB","MB","GB","TB","PB","EB","ZB","YB"][i]}`},e.isSupportedImageType=e=>["image/avif","image/gif","image/jpeg","image/png","image/svg+xml","image/webp"].includes(e),e.resolveThumbnailDisplay=(i,a)=>a?{type:"image",src:a}:i===e.PDF_MIME_TYPE?{type:"pdf-icon"}:{type:"none"}}(e||(e={}));export{e as FileUploadHelper};
2
2
  //# sourceMappingURL=helper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.js","sources":["../../src/file-upload/helper.ts"],"sourcesContent":["export namespace FileUploadHelper {\n export const PDF_MIME_TYPE = \"application/pdf\";\n export const PDF_ICON_URL =\n \"https://assets.life.gov.sg/react-design-system/img/upload/pdf.svg\";\n\n // Adapted from https://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-size-to-kb-mb-gb-in-javascript\n export const formatFileSizeDisplay = (size?: number) => {\n if (!size || size === 0) return \"0 KB\";\n\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n\n const index: number = Math.floor(Math.log(size) / Math.log(1024));\n\n const value = Number(size / Math.pow(1024, index)).toFixed(0);\n const measurement = sizes[index];\n\n return `${value} ${measurement}`;\n };\n\n export const isSupportedImageType = (type: string) => {\n /** Currently only images supported by html <img> */\n const acceptedImageTypes = [\n \"image/avif\",\n \"image/gif\",\n \"image/jpeg\",\n \"image/png\",\n \"image/svg+xml\",\n \"image/webp\",\n ];\n\n return acceptedImageTypes.includes(type);\n };\n}\n"],"names":["FileUploadHelper","PDF_MIME_TYPE","PDF_ICON_URL","formatFileSizeDisplay","size","index","Math","floor","log","Number","pow","toFixed","isSupportedImageType","type","includes"],"mappings":"AAAM,IAAWA,GAAjB,SAAiBA,GACAA,EAAAC,cAAgB,kBAChBD,EAAAE,aACT,oEAGSF,EAAAG,sBAAyBC,IAClC,IAAKA,GAAiB,IAATA,EAAY,MAAO,OAEhC,MAEMC,EAAgBC,KAAKC,MAAMD,KAAKE,IAAIJ,GAAQE,KAAKE,IAAI,OAK3D,MAAO,GAHOC,OAAOL,EAAOE,KAAKI,IAAI,KAAML,IAAQM,QAAQ,MAJ7C,CAAC,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAKpCN,IAEM,EAGvBL,EAAAY,qBAAwBC,GAEN,CACvB,aACA,YACA,aACA,YACA,gBACA,cAGsBC,SAASD,EAE1C,CAhCD,CAAiBb,IAAAA,EAAgB,CAAA"}
1
+ {"version":3,"file":"helper.js","sources":["../../src/file-upload/helper.ts"],"sourcesContent":["/**\n * How a file's thumbnail slot should be rendered.\n *\n * - `image` — a thumbnail was supplied; render it at `src`\n * - `pdf-icon` — a PDF with no thumbnail; render the PDF badge borderless\n * - `none` — nothing to show; render no thumbnail slot at all\n */\nexport type FileThumbnailDisplay =\n | { type: \"image\"; src: string }\n | { type: \"pdf-icon\" }\n | { type: \"none\" };\n\nexport namespace FileUploadHelper {\n export const PDF_MIME_TYPE = \"application/pdf\";\n export const PDF_ICON_URL =\n \"https://assets.life.gov.sg/react-design-system/img/upload/pdf.svg\";\n\n // Adapted from https://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-size-to-kb-mb-gb-in-javascript\n export const formatFileSizeDisplay = (size?: number) => {\n if (!size || size === 0) return \"0 KB\";\n\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n\n const index: number = Math.floor(Math.log(size) / Math.log(1024));\n\n const value = Number(size / Math.pow(1024, index)).toFixed(0);\n const measurement = sizes[index];\n\n return `${value} ${measurement}`;\n };\n\n export const isSupportedImageType = (type: string) => {\n /** Currently only images supported by html <img> */\n const acceptedImageTypes = [\n \"image/avif\",\n \"image/gif\",\n \"image/jpeg\",\n \"image/png\",\n \"image/svg+xml\",\n \"image/webp\",\n ];\n\n return acceptedImageTypes.includes(type);\n };\n\n /**\n * Decides how a file's thumbnail slot should render, given its MIME type\n * and any thumbnail the consumer supplied.\n *\n * Lives on `FileUploadHelper` so `FileUpload` can adopt it later. Today\n * only `FileDownload` calls it: `FileUpload` still decides this inline in\n * `file-list-item-thumbnail.tsx`, and the two do NOT yet agree — for a\n * non-PDF with no thumbnail this returns `\"none\"` while `FileUpload`\n * renders an `<img>` with an empty `src`. Do not read this as an invariant\n * the two components already share.\n *\n * Callers render the result with their own markup, because their thumbnails\n * change size at different breakpoints.\n */\n export const resolveThumbnailDisplay = (\n mimeType: string | undefined,\n thumbnailImageDataUrl: string | undefined\n ): FileThumbnailDisplay => {\n if (thumbnailImageDataUrl) {\n return { type: \"image\", src: thumbnailImageDataUrl };\n }\n\n if (mimeType === PDF_MIME_TYPE) {\n return { type: \"pdf-icon\" };\n }\n\n return { type: \"none\" };\n };\n}\n"],"names":["FileUploadHelper","PDF_MIME_TYPE","PDF_ICON_URL","formatFileSizeDisplay","size","index","Math","floor","log","Number","pow","toFixed","isSupportedImageType","type","includes","resolveThumbnailDisplay","mimeType","thumbnailImageDataUrl","src"],"mappings":"AAYM,IAAWA,GAAjB,SAAiBA,GACAA,EAAAC,cAAgB,kBAChBD,EAAAE,aACT,oEAGSF,EAAAG,sBAAyBC,IAClC,IAAKA,GAAiB,IAATA,EAAY,MAAO,OAEhC,MAEMC,EAAgBC,KAAKC,MAAMD,KAAKE,IAAIJ,GAAQE,KAAKE,IAAI,OAK3D,MAAO,GAHOC,OAAOL,EAAOE,KAAKI,IAAI,KAAML,IAAQM,QAAQ,MAJ7C,CAAC,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAKpCN,IAEM,EAGvBL,EAAAY,qBAAwBC,GAEN,CACvB,aACA,YACA,aACA,YACA,gBACA,cAGsBC,SAASD,GAiB1Bb,EAAAe,wBAA0B,CACnCC,EACAC,IAEIA,EACO,CAAEJ,KAAM,QAASK,IAAKD,GAG7BD,IAAahB,EAAAC,cACN,CAAEY,KAAM,YAGZ,CAAEA,KAAM,OAEtB,CA7DD,CAAiBb,IAAAA,EAAgB,CAAA"}
@@ -1,3 +1,3 @@
1
1
  import { FullscreenImageCarouselProps, FullscreenImageCarouselRef } from "./types";
2
- export declare const Component: ({ items, initialActiveItemIndex, hideThumbnail, hideNavigation, hideCounter, hideMagnifier, onDelete, onClose, insets, show, ...otherProps }: FullscreenImageCarouselProps, ref: React.Ref<FullscreenImageCarouselRef>) => import("react/jsx-runtime").JSX.Element;
2
+ export declare const Component: ({ items, initialActiveItemIndex, hideThumbnail, hideNavigation, hideCounter, hideMagnifier, customActions, onDelete, onClose, insets, topBarRef, show, ...otherProps }: FullscreenImageCarouselProps, ref: React.Ref<FullscreenImageCarouselRef>) => import("react/jsx-runtime").JSX.Element;
3
3
  export declare const FullscreenImageCarousel: (props: FullscreenImageCarouselProps & import("react").RefAttributes<FullscreenImageCarouselRef>) => React.ReactElement | null;
@@ -1,2 +1,2 @@
1
- import{__rest as e}from"../_virtual/_tslib.js";import{jsx as i,jsxs as t,Fragment as n}from"react/jsx-runtime";import{ChevronLeftIcon as l,ChevronRightIcon as r,MagnifierPlusIcon as o,MagnifierMinusIcon as a,CrossIcon as d}from"@lifesg/react-icons";import{BinIcon as s}from"@lifesg/react-icons/bin";import{clearAnnouncer as c,announce as u}from"@react-aria/live-announcer";import{forwardRef as h,useState as m,useRef as v,useMemo as f,useCallback as g,useImperativeHandle as p,useEffect as b}from"react";import{TransformWrapper as $,TransformComponent as I}from"react-zoom-pan-pinch";import{ModalV2 as C}from"../modal-v2/index.js";import{useStateCallback as w}from"../shared/hooks/use-state-callback.js";import"../util/calendar-helper.js";import"../util/date-helper.js";import"../util/date-input-helper.js";import"../util/simple-id-generator.js";import"../util/string-helper.js";import{useEventListener as j}from"../util/use-event-listener.js";import{CarouselModalContent as T,ImageGalleryContainer as k,ImageGalleryWrapper as x,ImageGallerySwipe as y,ArrowButton as L,BoxChip as S,Chip as N,TopActionButtons as D,MagnifierButton as M,DeleteButton as z,CloseButton as A,ImageGallerySlides as R,ImageGallerySlide as Z,FocusableImageRegion as O,SlidePlaceholderImage as W,SlideImage as X,ThumbnailContainer as E,ThumbnailWrapper as F,ThumbnailItemContainer as P,ThumbnailItem as V,ThumbnailImage as _,FileInfoTextWrapper as B,FileInfoFileName as H,FileInfoFileSize as q}from"./fullscreen-image-carousel.style.js";const G=e=>!!e&&"custom"===e.type,J=(h,J)=>{var K,{items:Q,initialActiveItemIndex:U,hideThumbnail:Y=!1,hideNavigation:ee=!1,hideCounter:ie=!1,hideMagnifier:te=!1,onDelete:ne,onClose:le,insets:re,show:oe}=h,ae=e(h,["items","initialActiveItemIndex","hideThumbnail","hideNavigation","hideCounter","hideMagnifier","onDelete","onClose","insets","show"]);const[de,se]=w(null!=U?U:0),[ce,ue]=m({}),[he,me]=m(1),[ve,fe]=m(),[ge,pe]=m(),be=v(null),$e=v([]),Ie=v([]),Ce=v(null),we=ve&&ge?ve-ge:0,je=Q[de],Te=Q.some((e=>{var i;return G(e)&&!!(null===(i=e.itemLabel)||void 0===i?void 0:i.trim())})),ke=Te?"item":"image",xe=f((()=>Q.some((e=>{var i,t;return(null===(i=e.fileName)||void 0===i?void 0:i.trim())||(null===(t=e.fileSize)||void 0===t?void 0:t.trim())}))),[Q]),ye=g((e=>{var i,t;const n=Q[e],l=Te?"Item":"Image",r=G(n)?(null===(i=n.itemLabel)||void 0===i?void 0:i.trim())||"":(null===(t=n.alt)||void 0===t?void 0:t.trim())||"",o=`${l} ${e+1} of ${Q.length}.`;return r?`${r}. ${o}`:o}),[Q,Te]);p(J,(()=>({currentItemIndex:de,setCurrentItem:ze,goToPrevItem:De,goToNextItem:Me}))),j("keydown",(function(e){"ArrowRight"===e.key?Me():"ArrowLeft"===e.key?De():"Escape"===e.key&&(null==le||le())}),"document"),b((()=>{var e;oe&&(null===(e=Ce.current)||void 0===e||e.focus())}),[oe]),b((()=>{0!==Q.length?de>Q.length-1&&se(Q.length-1):se(0)}),[de,Q.length,se]),b((()=>{var e,i;null===(i=null===(e=$e.current)||void 0===e?void 0:e[de])||void 0===i||i.scrollIntoView({behavior:"smooth",inline:"center"}),me(1)}),[de]);const Le=e=>{me(e.state.scale)};const Se=({src:e,height:i,width:t})=>{ue((n=>Object.assign(Object.assign({},n),{[e]:{height:i,width:t}})))},Ne=()=>{if(!je||G(je))return;const e=ce[je.src];if(be.current&&e){const{clientHeight:i,clientWidth:t}=be.current,{width:n,height:l}=e,r=l/n<i/t;return n<t&&l<i?r?t/n:i/l:r?i/(l/(n/t)):t/(n/(l/i))}},De=()=>{var e,i;null===(i=null===(e=Ie.current)||void 0===e?void 0:e[de])||void 0===i||i.resetTransform(),se((e=>0===e?Q.length-1:e-1),(e=>{c("polite"),u(ye(e),"polite")}))},Me=()=>{var e,i;null===(i=null===(e=Ie.current)||void 0===e?void 0:e[de])||void 0===i||i.resetTransform(),se((e=>e===Q.length-1?0:e+1),(e=>{c("polite"),u(ye(e),"polite")}))},ze=e=>{var i,t;null===(t=null===(i=Ie.current)||void 0===i?void 0:i[de])||void 0===t||t.resetTransform(),se(e)};return i(C,Object.assign({},ae,{"data-testid":"image-carousel-modal","aria-label":Te?"Carousel":"Image carousel",show:oe,disableInitialFocus:!0,children:t(T,{children:[t(k,{children:[t(x,{children:[i(y,{ref:be,onTouchStart:e=>{he<=1&&fe(e.touches[0].clientX)},onTouchMove:e=>{!ve||he>1||pe(e.touches[0].clientX)},onTouchEnd:()=>{be.current&&(Math.abs(we)>be.current.offsetWidth/3&&(we>0?Me():De()),fe(void 0),pe(void 0))},children:i(R,{style:{transform:`translateX(calc(${100*-de}% - ${we}px))`},children:Q.map(((e,t)=>{const n=t===de,l=Math.abs(t-de)<=1||0===de&&t===Q.length-1||de===Q.length-1&&0===t;return i(Z,{"data-testid":"slide-item",children:i(O,{ref:n?Ce:null,tabIndex:n?0:-1,children:G(e)?l?e.renderContent():i(W,{}):i($,{ref:e=>Ie.current[t]=e,panning:{disabled:he<=1},initialScale:1,onZoom:Le,onZoomStop:Le,onWheel:Le,children:i(I,{children:i(X,{src:e.src,alt:ye(t),placeholder:i(W,{}),fit:"scale-down",retrieveImageDimension:!0,setDimension:Se})})})})},t)}))})}),!ee&&t(n,{children:[i(L,{"aria-label":`Previous ${ke}`,"data-testid":"prev-btn",$position:"left",onClick:De,$insetLeft:null==re?void 0:re.left,$insetRight:null==re?void 0:re.right,children:i(l,{"aria-hidden":!0})}),i(L,{"aria-label":`Next ${ke}`,"data-testid":"forward-btn",$position:"right",onClick:Me,$insetLeft:null==re?void 0:re.left,$insetRight:null==re?void 0:re.right,children:i(r,{"aria-hidden":!0})})]}),!ie&&i(S,{"aria-hidden":"true",children:i(N,{weight:"semibold",children:`${de+1}/${Q.length}`})})]}),!Y&&i(E,{$insetBottom:null==re?void 0:re.bottom,"aria-hidden":"true",children:i(F,{children:Q.map(((e,t)=>{var n;const l=G(e)?e.thumbnailSrc:null!==(n=e.thumbnailSrc)&&void 0!==n?n:e.src;return i(P,{children:i(V,{"data-testid":"thumbnail-item",$active:t===de,onClick:()=>ze(t),ref:e=>$e.current[t]=e,children:l?i(_,{src:l,alt:`Thumbnail ${t+1}`,fit:"cover"}):i(W,{})})},t)}))})})]}),t(D,{$hasFileInfo:xe,$insetTop:null==re?void 0:re.top,$insetLeft:null==re?void 0:re.left,$insetRight:null==re?void 0:re.right,children:[xe&&(()=>{const{fileName:e,fileSize:n}=null!=je?je:{},l=null==e?void 0:e.trim(),r=null==n?void 0:n.trim();return t(B,{$centerContent:!r,"aria-live":"polite","aria-atomic":"true","data-testid":"file-info-bar",children:[l&&i(H,{weight:"semibold","data-testid":"file-info-name",children:l}),r&&i(q,{"data-testid":"file-info-size",children:r})]})})(),!te&&!G(je)&&i(M,{"aria-label":1===he?"Zoom in":"Zoom out",onClick:()=>{var e,i,t,n;if(1===he){const t=Ne();null===(i=null===(e=Ie.current)||void 0===e?void 0:e[de])||void 0===i||i.centerView(t),me(null!=t?t:1)}else me(1),null===(n=null===(t=Ie.current)||void 0===t?void 0:t[de])||void 0===n||n.resetTransform()},children:i(1===he?o:a,{"aria-hidden":!0})}),ne&&i(z,{"aria-label":`Delete ${G(je)&&(null===(K=je.itemLabel)||void 0===K?void 0:K.trim())||"image"}`,"data-testid":"delete-btn",onClick:()=>{je&&ne&&ne(je,de)},children:i(s,{"aria-hidden":!0})}),i(A,{"aria-label":Te?"Close carousel":"Close image carousel",onClick:le,children:i(d,{"aria-hidden":!0})})]})]})}))},K=h(J);export{J as Component,K as FullscreenImageCarousel};
1
+ import{__rest as e}from"../_virtual/_tslib.js";import{jsx as i,jsxs as t,Fragment as n}from"react/jsx-runtime";import{ChevronLeftIcon as l,ChevronRightIcon as r,MagnifierPlusIcon as o,MagnifierMinusIcon as a,CrossIcon as d}from"@lifesg/react-icons";import{BinIcon as s}from"@lifesg/react-icons/bin";import{clearAnnouncer as c,announce as u}from"@react-aria/live-announcer";import{forwardRef as h,useState as m,useRef as v,useMemo as f,useCallback as g,useImperativeHandle as p,useEffect as b,cloneElement as $}from"react";import{TransformWrapper as C,TransformComponent as I}from"react-zoom-pan-pinch";import{ModalV2 as w}from"../modal-v2/index.js";import{useStateCallback as j}from"../shared/hooks/use-state-callback.js";import"../util/calendar-helper.js";import"../util/date-helper.js";import"../util/date-input-helper.js";import"../util/simple-id-generator.js";import"../util/string-helper.js";import{useEventListener as k}from"../util/use-event-listener.js";import{CarouselModalContent as T,ImageGalleryContainer as x,ImageGalleryWrapper as L,ImageGallerySwipe as y,ArrowButton as A,BoxChip as S,Chip as N,ImageGallerySlides as R,ImageGallerySlide as D,FocusableImageRegion as M,SlidePlaceholderImage as z,SlideImage as Z,ThumbnailContainer as B,ThumbnailWrapper as O,ThumbnailItemContainer as W,ThumbnailItem as X,ThumbnailImage as E,TopActionButtons as F,CustomActionButton as P,MagnifierButton as V,DeleteButton as _,CloseButton as H,FileInfoTextWrapper as q,FileInfoFileName as G,FileInfoFileSize as J}from"./fullscreen-image-carousel.style.js";const K=e=>!!e&&"custom"===e.type,Q=(h,Q)=>{var U,Y,{items:ee,initialActiveItemIndex:ie,hideThumbnail:te=!1,hideNavigation:ne=!1,hideCounter:le=!1,hideMagnifier:re=!1,customActions:oe,onDelete:ae,onClose:de,insets:se,topBarRef:ce,show:ue}=h,he=e(h,["items","initialActiveItemIndex","hideThumbnail","hideNavigation","hideCounter","hideMagnifier","customActions","onDelete","onClose","insets","topBarRef","show"]);const[me,ve]=j(null!=ie?ie:0),[fe,ge]=m({}),[pe,be]=m(1),[$e,Ce]=m(),[Ie,we]=m(),je=v(null),ke=v([]),Te=v([]),xe=v(null),Le=$e&&Ie?$e-Ie:0,ye=ee[me],Ae=null!==(Y=null!==(U=null==ye?void 0:ye.customActions)&&void 0!==U?U:oe)&&void 0!==Y?Y:[],Se=ee.some((e=>{var i;return K(e)&&!!(null===(i=e.itemLabel)||void 0===i?void 0:i.trim())})),Ne=Se?"item":"image",Re=f((()=>ee.some((e=>{var i,t;return(null===(i=e.fileName)||void 0===i?void 0:i.trim())||(null===(t=e.fileSize)||void 0===t?void 0:t.trim())}))),[ee]),De=g((e=>{var i,t;const n=ee[e],l=Se?"Item":"Image",r=K(n)?(null===(i=n.itemLabel)||void 0===i?void 0:i.trim())||"":(null===(t=n.alt)||void 0===t?void 0:t.trim())||"",o=`${l} ${e+1} of ${ee.length}.`;return r?`${r}. ${o}`:o}),[ee,Se]);p(Q,(()=>({currentItemIndex:me,setCurrentItem:Ee,goToPrevItem:We,goToNextItem:Xe}))),k("keydown",(function(e){"ArrowRight"===e.key?Xe():"ArrowLeft"===e.key?We():"Escape"===e.key&&(null==de||de())}),"document"),b((()=>{var e;ue&&(null===(e=xe.current)||void 0===e||e.focus())}),[ue]),b((()=>{0!==ee.length?me>ee.length-1&&ve(ee.length-1):ve(0)}),[me,ee.length,ve]),b((()=>{var e,i;null===(i=null===(e=ke.current)||void 0===e?void 0:e[me])||void 0===i||i.scrollIntoView({behavior:"smooth",inline:"center"}),be(1)}),[me]);const Me=e=>{be(e.state.scale)},ze=()=>{ye&&ae&&ae(ye,me)};const Ze=()=>{var e,i,t,n;if(1===pe){const t=Oe();null===(i=null===(e=Te.current)||void 0===e?void 0:e[me])||void 0===i||i.centerView(t),be(null!=t?t:1)}else be(1),null===(n=null===(t=Te.current)||void 0===t?void 0:t[me])||void 0===n||n.resetTransform()},Be=({src:e,height:i,width:t})=>{ge((n=>Object.assign(Object.assign({},n),{[e]:{height:i,width:t}})))},Oe=()=>{if(!ye||K(ye))return;const e=fe[ye.src];if(je.current&&e){const{clientHeight:i,clientWidth:t}=je.current,{width:n,height:l}=e,r=l/n<i/t;return n<t&&l<i?r?t/n:i/l:r?i/(l/(n/t)):t/(n/(l/i))}},We=()=>{var e,i;null===(i=null===(e=Te.current)||void 0===e?void 0:e[me])||void 0===i||i.resetTransform(),ve((e=>0===e?ee.length-1:e-1),(e=>{c("polite"),u(De(e),"polite")}))},Xe=()=>{var e,i;null===(i=null===(e=Te.current)||void 0===e?void 0:e[me])||void 0===i||i.resetTransform(),ve((e=>e===ee.length-1?0:e+1),(e=>{c("polite"),u(De(e),"polite")}))},Ee=e=>{var i,t;null===(t=null===(i=Te.current)||void 0===i?void 0:i[me])||void 0===t||t.resetTransform(),ve(e)},Fe=()=>{const{fileName:e,fileSize:n}=null!=ye?ye:{},l=null==e?void 0:e.trim(),r=null==n?void 0:n.trim();return t(q,{$centerContent:!r,"aria-live":"polite","aria-atomic":"true","data-testid":"file-info-bar",children:[l&&i(G,{weight:"semibold","data-testid":"file-info-name",children:l}),r&&i(J,{"data-testid":"file-info-size",children:r})]})};return i(w,Object.assign({},he,{"data-testid":"image-carousel-modal","aria-label":Se?"Carousel":"Image carousel",show:ue,disableInitialFocus:!0,children:t(T,{children:[t(x,{children:[t(L,{children:[i(y,{ref:je,onTouchStart:e=>{pe<=1&&Ce(e.touches[0].clientX)},onTouchMove:e=>{!$e||pe>1||we(e.touches[0].clientX)},onTouchEnd:()=>{je.current&&(Math.abs(Le)>je.current.offsetWidth/3&&(Le>0?Xe():We()),Ce(void 0),we(void 0))},children:i(R,{style:{transform:`translateX(calc(${100*-me}% - ${Le}px))`},children:ee.map(((e,t)=>{const n=t===me,l=Math.abs(t-me)<=1||0===me&&t===ee.length-1||me===ee.length-1&&0===t;return i(D,{"data-testid":"slide-item",children:i(M,{ref:n?xe:null,tabIndex:n?0:-1,children:K(e)?l?e.renderContent():i(z,{}):i(C,{ref:e=>Te.current[t]=e,panning:{disabled:pe<=1},initialScale:1,onZoom:Me,onZoomStop:Me,onWheel:Me,children:i(I,{children:i(Z,{src:e.src,alt:De(t),placeholder:i(z,{}),fit:"scale-down",retrieveImageDimension:!0,setDimension:Be})})})})},t)}))})}),!ne&&t(n,{children:[i(A,{"aria-label":`Previous ${Ne}`,"data-testid":"prev-btn",$position:"left",onClick:We,$insetLeft:null==se?void 0:se.left,$insetRight:null==se?void 0:se.right,children:i(l,{"aria-hidden":!0})}),i(A,{"aria-label":`Next ${Ne}`,"data-testid":"forward-btn",$position:"right",onClick:Xe,$insetLeft:null==se?void 0:se.left,$insetRight:null==se?void 0:se.right,children:i(r,{"aria-hidden":!0})})]}),!le&&i(S,{"aria-hidden":"true",children:i(N,{weight:"semibold",children:`${me+1}/${ee.length}`})})]}),!te&&i(B,{$insetBottom:null==se?void 0:se.bottom,"aria-hidden":"true",children:i(O,{children:ee.map(((e,t)=>{var n;const l=K(e)?e.thumbnailSrc:null!==(n=e.thumbnailSrc)&&void 0!==n?n:e.src;return i(W,{children:i(X,{"data-testid":"thumbnail-item",$active:t===me,onClick:()=>Ee(t),ref:e=>ke.current[t]=e,children:l?i(E,{src:l,alt:`Thumbnail ${t+1}`,fit:"cover"}):i(z,{})})},t)}))})})]}),(()=>{var e;return t(F,{ref:ce,$hasFileInfo:Re,$insetTop:null==se?void 0:se.top,$insetLeft:null==se?void 0:se.left,$insetRight:null==se?void 0:se.right,children:[Re&&Fe(),Ae.map(((e,t)=>i(P,{"aria-label":e.ariaLabel,"data-testid":e["data-testid"],onClick:()=>(e=>{ye&&e.onClick(ye,me)})(e),children:$(e.icon,{"aria-hidden":!0})},t))),!re&&!K(ye)&&i(V,{"aria-label":1===pe?"Zoom in":"Zoom out",onClick:Ze,children:i(1===pe?o:a,{"aria-hidden":!0})}),ae&&i(_,{"aria-label":`Delete ${K(ye)&&(null===(e=ye.itemLabel)||void 0===e?void 0:e.trim())||"image"}`,"data-testid":"delete-btn",onClick:ze,children:i(s,{"aria-hidden":!0})}),i(H,{"aria-label":Se?"Close carousel":"Close image carousel",onClick:de,children:i(d,{"aria-hidden":!0})})]})})()]})}))},U=h(Q);export{Q as Component,U as FullscreenImageCarousel};
2
2
  //# sourceMappingURL=fullscreen-image-carousel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fullscreen-image-carousel.js","sources":["../../src/fullscreen-image-carousel/fullscreen-image-carousel.tsx"],"sourcesContent":["import {\n ChevronLeftIcon,\n ChevronRightIcon,\n CrossIcon,\n MagnifierMinusIcon,\n MagnifierPlusIcon,\n} from \"@lifesg/react-icons\";\nimport { BinIcon } from \"@lifesg/react-icons/bin\";\nimport { announce, clearAnnouncer } from \"@react-aria/live-announcer\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n ReactZoomPanPinchContentRef,\n ReactZoomPanPinchRef,\n TransformComponent,\n TransformWrapper,\n} from \"react-zoom-pan-pinch\";\nimport { ModalV2 } from \"../modal-v2\";\nimport { useStateCallback } from \"../shared/hooks\";\nimport { useEventListener } from \"../util\";\nimport {\n ArrowButton,\n BoxChip,\n CarouselModalContent,\n Chip,\n CloseButton,\n DeleteButton,\n FileInfoFileName,\n FileInfoFileSize,\n FileInfoTextWrapper,\n FocusableImageRegion,\n ImageGalleryContainer,\n ImageGallerySlide,\n ImageGallerySlides,\n ImageGallerySwipe,\n ImageGalleryWrapper,\n MagnifierButton,\n SlideImage,\n SlidePlaceholderImage,\n ThumbnailContainer,\n ThumbnailImage,\n ThumbnailItem,\n ThumbnailItemContainer,\n ThumbnailWrapper,\n TopActionButtons,\n} from \"./fullscreen-image-carousel.style\";\nimport {\n FullscreenImageCarouselCustomItemProps,\n FullscreenImageCarouselItemProps,\n FullscreenImageCarouselProps,\n FullscreenImageCarouselRef,\n ImageDimension,\n} from \"./types\";\n\nconst isCustomItem = (\n item: FullscreenImageCarouselItemProps | undefined\n): item is FullscreenImageCarouselCustomItemProps =>\n !!item && item.type === \"custom\";\n\nexport const Component = (\n {\n items,\n initialActiveItemIndex,\n hideThumbnail = false,\n hideNavigation = false,\n hideCounter = false,\n hideMagnifier = false,\n onDelete,\n onClose,\n insets,\n show,\n ...otherProps\n }: FullscreenImageCarouselProps,\n ref: React.Ref<FullscreenImageCarouselRef>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const [currentSlide, setCurrentSlide] = useStateCallback(\n initialActiveItemIndex ?? 0\n );\n const [imagesDimension, setImageDimension] = useState<\n Record<string, ImageDimension>\n >({});\n const [zoom, setZoom] = useState(1);\n const [startX, setStartX] = useState<number | undefined>();\n const [endX, setEndX] = useState<number | undefined>();\n const containerRef = useRef<HTMLDivElement>(null);\n const thumbnailRefs = useRef<(HTMLDivElement | null)[]>([]);\n const zoomRefs = useRef<(ReactZoomPanPinchContentRef | null)[]>([]);\n const imageRef = useRef<HTMLDivElement>(null);\n const diff = startX && endX ? startX - endX : 0;\n const currentItem = items[currentSlide];\n const hasAnyItemLabel = items.some(\n (item) => isCustomItem(item) && !!item.itemLabel?.trim()\n );\n const carouselItemNoun = hasAnyItemLabel ? \"item\" : \"image\";\n const hasFileInfo = useMemo(\n () =>\n items.some(\n (item) => item.fileName?.trim() || item.fileSize?.trim()\n ),\n [items]\n );\n\n const getItemAriaLabel = useCallback(\n (index: number) => {\n const item = items[index];\n const itemTypeLabel = hasAnyItemLabel ? \"Item\" : \"Image\";\n const prefix = isCustomItem(item)\n ? item.itemLabel?.trim() || \"\"\n : item.alt?.trim() || \"\";\n const positionLabel = `${itemTypeLabel} ${index + 1} of ${\n items.length\n }.`;\n\n return prefix ? `${prefix}. ${positionLabel}` : positionLabel;\n },\n [items, hasAnyItemLabel]\n );\n\n useImperativeHandle<FullscreenImageCarouselRef, FullscreenImageCarouselRef>(\n ref,\n () => ({\n currentItemIndex: currentSlide,\n setCurrentItem: goToSlide,\n goToPrevItem: goToPrevSlide,\n goToNextItem: goToNextSlide,\n })\n );\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEventListener(\"keydown\", handleKeyDown, \"document\");\n\n useEffect(() => {\n if (show) {\n imageRef.current?.focus();\n }\n }, [show]);\n\n useEffect(() => {\n if (items.length === 0) {\n setCurrentSlide(0);\n return;\n }\n\n if (currentSlide > items.length - 1) {\n setCurrentSlide(items.length - 1);\n }\n }, [currentSlide, items.length, setCurrentSlide]);\n\n useEffect(() => {\n thumbnailRefs.current?.[currentSlide]?.scrollIntoView({\n behavior: \"smooth\",\n inline: \"center\",\n });\n setZoom(1);\n }, [currentSlide]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleTouchStart = (e: React.TouchEvent) => {\n if (zoom <= 1) setStartX(e.touches[0].clientX);\n };\n\n const handleTouchMove = (e: React.TouchEvent) => {\n if (!startX || zoom > 1) return;\n setEndX(e.touches[0].clientX);\n };\n\n const handleTouchEnd = () => {\n if (!containerRef.current) return;\n if (Math.abs(diff) > containerRef.current.offsetWidth / 3) {\n if (diff > 0) {\n goToNextSlide();\n } else {\n goToPrevSlide();\n }\n }\n setStartX(undefined);\n setEndX(undefined);\n };\n\n const handleZoom = (e: ReactZoomPanPinchRef) => {\n setZoom(e.state.scale);\n };\n\n const handleDelete = () => {\n if (currentItem && onDelete) {\n onDelete(currentItem, currentSlide);\n }\n };\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"ArrowRight\") {\n goToNextSlide();\n } else if (e.key === \"ArrowLeft\") {\n goToPrevSlide();\n } else if (e.key === \"Escape\") {\n onClose?.();\n }\n }\n\n const handleMagnifier = () => {\n if (zoom === 1) {\n const zoomRatio = getZoomRatio();\n zoomRefs.current?.[currentSlide]?.centerView(zoomRatio);\n setZoom(zoomRatio ?? 1);\n } else {\n setZoom(1);\n zoomRefs.current?.[currentSlide]?.resetTransform();\n }\n };\n\n const setDimension = ({\n src,\n height,\n width,\n }: {\n src: string;\n height: number;\n width: number;\n }) => {\n setImageDimension((oldState) => {\n return { ...oldState, [src]: { height, width } };\n });\n };\n\n const getZoomRatio = () => {\n if (!currentItem || isCustomItem(currentItem)) {\n return;\n }\n\n const imageDimension = imagesDimension[currentItem.src];\n\n if (containerRef.current && !!imageDimension) {\n const { clientHeight, clientWidth } = containerRef.current;\n const { width, height } = imageDimension;\n const isSmallImg = width < clientWidth && height < clientHeight;\n\n const isImgLandscapeRelativeToDevice =\n height / width < clientHeight / clientWidth;\n\n if (isSmallImg) {\n return isImgLandscapeRelativeToDevice\n ? clientWidth / width\n : clientHeight / height;\n }\n\n return isImgLandscapeRelativeToDevice\n ? clientHeight / (height / (width / clientWidth))\n : clientWidth / (width / (height / clientHeight));\n }\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const goToPrevSlide = () => {\n zoomRefs.current?.[currentSlide]?.resetTransform();\n setCurrentSlide(\n (prev) => (prev === 0 ? items.length - 1 : prev - 1),\n (slide) => {\n clearAnnouncer(\"polite\");\n announce(getItemAriaLabel(slide), \"polite\");\n }\n );\n };\n\n const goToNextSlide = () => {\n zoomRefs.current?.[currentSlide]?.resetTransform();\n setCurrentSlide(\n (prev) => (prev === items.length - 1 ? 0 : prev + 1),\n (slide) => {\n clearAnnouncer(\"polite\");\n announce(getItemAriaLabel(slide), \"polite\");\n }\n );\n };\n\n const goToSlide = (index: number) => {\n zoomRefs.current?.[currentSlide]?.resetTransform();\n setCurrentSlide(index);\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderSlides = () => {\n return (\n <ImageGallerySlides\n style={{\n transform: `translateX(calc(${\n -currentSlide * 100\n }% - ${diff}px))`,\n }}\n >\n {items.map((item, index) => {\n const isActive = index === currentSlide;\n const isActiveOrAdjacent =\n Math.abs(index - currentSlide) <= 1 ||\n (currentSlide === 0 && index === items.length - 1) ||\n (currentSlide === items.length - 1 && index === 0);\n\n return (\n <ImageGallerySlide key={index} data-testid=\"slide-item\">\n <FocusableImageRegion\n ref={isActive ? imageRef : null}\n tabIndex={isActive ? 0 : -1}\n >\n {isCustomItem(item) ? (\n isActiveOrAdjacent ? (\n item.renderContent()\n ) : (\n <SlidePlaceholderImage />\n )\n ) : (\n <TransformWrapper\n ref={(el) =>\n (zoomRefs.current[index] = el)\n }\n panning={{\n disabled: zoom <= 1,\n }}\n initialScale={1}\n onZoom={handleZoom}\n onZoomStop={handleZoom}\n onWheel={handleZoom}\n >\n <TransformComponent>\n <SlideImage\n src={item.src}\n alt={getItemAriaLabel(index)}\n placeholder={\n <SlidePlaceholderImage />\n }\n fit=\"scale-down\"\n retrieveImageDimension\n setDimension={setDimension}\n />\n </TransformComponent>\n </TransformWrapper>\n )}\n </FocusableImageRegion>\n </ImageGallerySlide>\n );\n })}\n </ImageGallerySlides>\n );\n };\n\n const renderFileInfo = () => {\n const { fileName, fileSize } = currentItem ?? {};\n const trimmedName = fileName?.trim();\n const trimmedSize = fileSize?.trim();\n\n return (\n <FileInfoTextWrapper\n $centerContent={!trimmedSize}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n data-testid=\"file-info-bar\"\n >\n {trimmedName && (\n <FileInfoFileName\n weight=\"semibold\"\n data-testid=\"file-info-name\"\n >\n {trimmedName}\n </FileInfoFileName>\n )}\n {trimmedSize && (\n <FileInfoFileSize data-testid=\"file-info-size\">\n {trimmedSize}\n </FileInfoFileSize>\n )}\n </FileInfoTextWrapper>\n );\n };\n\n const renderThumbnails = () => {\n return (\n <ThumbnailContainer\n $insetBottom={insets?.bottom}\n aria-hidden=\"true\"\n >\n <ThumbnailWrapper>\n {items.map((item, index) => {\n const src = isCustomItem(item)\n ? item.thumbnailSrc\n : item.thumbnailSrc ?? item.src;\n return (\n <ThumbnailItemContainer key={index}>\n <ThumbnailItem\n data-testid=\"thumbnail-item\"\n $active={index === currentSlide}\n onClick={() => goToSlide(index)}\n ref={(el) =>\n (thumbnailRefs.current[index] = el)\n }\n >\n {src ? (\n <ThumbnailImage\n src={src}\n alt={`Thumbnail ${index + 1}`}\n fit=\"cover\"\n />\n ) : (\n <SlidePlaceholderImage />\n )}\n </ThumbnailItem>\n </ThumbnailItemContainer>\n );\n })}\n </ThumbnailWrapper>\n </ThumbnailContainer>\n );\n };\n\n return (\n <ModalV2\n {...otherProps}\n data-testid=\"image-carousel-modal\"\n aria-label={hasAnyItemLabel ? \"Carousel\" : \"Image carousel\"}\n show={show}\n disableInitialFocus\n >\n <CarouselModalContent>\n <ImageGalleryContainer>\n <ImageGalleryWrapper>\n <ImageGallerySwipe\n ref={containerRef}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n {renderSlides()}\n </ImageGallerySwipe>\n\n {!hideNavigation && (\n <>\n <ArrowButton\n aria-label={`Previous ${carouselItemNoun}`}\n data-testid=\"prev-btn\"\n $position=\"left\"\n onClick={goToPrevSlide}\n $insetLeft={insets?.left}\n $insetRight={insets?.right}\n >\n <ChevronLeftIcon aria-hidden />\n </ArrowButton>\n <ArrowButton\n aria-label={`Next ${carouselItemNoun}`}\n data-testid=\"forward-btn\"\n $position=\"right\"\n onClick={goToNextSlide}\n $insetLeft={insets?.left}\n $insetRight={insets?.right}\n >\n <ChevronRightIcon aria-hidden />\n </ArrowButton>\n </>\n )}\n\n {!hideCounter && (\n <BoxChip aria-hidden=\"true\">\n <Chip weight=\"semibold\">{`${currentSlide + 1}/${\n items.length\n }`}</Chip>\n </BoxChip>\n )}\n </ImageGalleryWrapper>\n\n {!hideThumbnail && renderThumbnails()}\n </ImageGalleryContainer>\n <TopActionButtons\n $hasFileInfo={hasFileInfo}\n $insetTop={insets?.top}\n $insetLeft={insets?.left}\n $insetRight={insets?.right}\n >\n {hasFileInfo && renderFileInfo()}\n {!hideMagnifier && !isCustomItem(currentItem) && (\n <MagnifierButton\n aria-label={zoom === 1 ? \"Zoom in\" : \"Zoom out\"}\n onClick={handleMagnifier}\n >\n {zoom === 1 ? (\n <MagnifierPlusIcon aria-hidden />\n ) : (\n <MagnifierMinusIcon aria-hidden />\n )}\n </MagnifierButton>\n )}\n\n {onDelete && (\n <DeleteButton\n aria-label={`Delete ${\n (isCustomItem(currentItem) &&\n currentItem.itemLabel?.trim()) ||\n \"image\"\n }`}\n data-testid=\"delete-btn\"\n onClick={handleDelete}\n >\n <BinIcon aria-hidden />\n </DeleteButton>\n )}\n\n <CloseButton\n aria-label={\n hasAnyItemLabel\n ? \"Close carousel\"\n : \"Close image carousel\"\n }\n onClick={onClose}\n >\n <CrossIcon aria-hidden />\n </CloseButton>\n </TopActionButtons>\n </CarouselModalContent>\n </ModalV2>\n );\n};\n\nexport const FullscreenImageCarousel = forwardRef<\n FullscreenImageCarouselRef,\n FullscreenImageCarouselProps\n>(Component);\n"],"names":["isCustomItem","item","type","Component","_a","ref","items","initialActiveItemIndex","hideThumbnail","hideNavigation","hideCounter","hideMagnifier","onDelete","onClose","insets","show","otherProps","__rest","currentSlide","setCurrentSlide","useStateCallback","imagesDimension","setImageDimension","useState","zoom","setZoom","startX","setStartX","endX","setEndX","containerRef","useRef","thumbnailRefs","zoomRefs","imageRef","diff","currentItem","hasAnyItemLabel","some","itemLabel","trim","carouselItemNoun","hasFileInfo","useMemo","fileName","fileSize","_b","getItemAriaLabel","useCallback","index","itemTypeLabel","prefix","alt","positionLabel","length","useImperativeHandle","currentItemIndex","setCurrentItem","goToSlide","goToPrevItem","goToPrevSlide","goToNextItem","goToNextSlide","useEventListener","e","key","useEffect","current","focus","scrollIntoView","behavior","inline","handleZoom","state","scale","setDimension","src","height","width","oldState","Object","assign","getZoomRatio","imageDimension","clientHeight","clientWidth","isImgLandscapeRelativeToDevice","resetTransform","prev","slide","clearAnnouncer","announce","_jsx","ModalV2","disableInitialFocus","children","_jsxs","CarouselModalContent","ImageGalleryContainer","ImageGalleryWrapper","ImageGallerySwipe","onTouchStart","touches","clientX","onTouchMove","onTouchEnd","Math","abs","offsetWidth","undefined","ImageGallerySlides","style","transform","map","isActive","isActiveOrAdjacent","ImageGallerySlide","FocusableImageRegion","tabIndex","renderContent","SlidePlaceholderImage","TransformWrapper","el","panning","disabled","initialScale","onZoom","onZoomStop","onWheel","TransformComponent","SlideImage","placeholder","fit","retrieveImageDimension","_Fragment","ArrowButton","$position","onClick","$insetLeft","left","$insetRight","right","ChevronLeftIcon","ChevronRightIcon","BoxChip","Chip","weight","ThumbnailContainer","$insetBottom","bottom","ThumbnailWrapper","thumbnailSrc","ThumbnailItemContainer","ThumbnailItem","$active","ThumbnailImage","TopActionButtons","$hasFileInfo","$insetTop","top","trimmedName","trimmedSize","FileInfoTextWrapper","FileInfoFileName","FileInfoFileSize","renderFileInfo","MagnifierButton","zoomRatio","centerView","_d","_c","MagnifierPlusIcon","MagnifierMinusIcon","DeleteButton","BinIcon","CloseButton","CrossIcon","FullscreenImageCarousel","forwardRef"],"mappings":"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"}
1
+ {"version":3,"file":"fullscreen-image-carousel.js","sources":["../../src/fullscreen-image-carousel/fullscreen-image-carousel.tsx"],"sourcesContent":["import {\n ChevronLeftIcon,\n ChevronRightIcon,\n CrossIcon,\n MagnifierMinusIcon,\n MagnifierPlusIcon,\n} from \"@lifesg/react-icons\";\nimport { BinIcon } from \"@lifesg/react-icons/bin\";\nimport { announce, clearAnnouncer } from \"@react-aria/live-announcer\";\nimport {\n cloneElement,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n ReactZoomPanPinchContentRef,\n ReactZoomPanPinchRef,\n TransformComponent,\n TransformWrapper,\n} from \"react-zoom-pan-pinch\";\nimport { ModalV2 } from \"../modal-v2\";\nimport { useStateCallback } from \"../shared/hooks\";\nimport { useEventListener } from \"../util\";\nimport {\n ArrowButton,\n BoxChip,\n CarouselModalContent,\n Chip,\n CloseButton,\n CustomActionButton,\n DeleteButton,\n FileInfoFileName,\n FileInfoFileSize,\n FileInfoTextWrapper,\n FocusableImageRegion,\n ImageGalleryContainer,\n ImageGallerySlide,\n ImageGallerySlides,\n ImageGallerySwipe,\n ImageGalleryWrapper,\n MagnifierButton,\n SlideImage,\n SlidePlaceholderImage,\n ThumbnailContainer,\n ThumbnailImage,\n ThumbnailItem,\n ThumbnailItemContainer,\n ThumbnailWrapper,\n TopActionButtons,\n} from \"./fullscreen-image-carousel.style\";\nimport {\n FullscreenImageCarouselCustomAction,\n FullscreenImageCarouselCustomItemProps,\n FullscreenImageCarouselItemProps,\n FullscreenImageCarouselProps,\n FullscreenImageCarouselRef,\n ImageDimension,\n} from \"./types\";\n\nconst isCustomItem = (\n item: FullscreenImageCarouselItemProps | undefined\n): item is FullscreenImageCarouselCustomItemProps =>\n !!item && item.type === \"custom\";\n\nexport const Component = (\n {\n items,\n initialActiveItemIndex,\n hideThumbnail = false,\n hideNavigation = false,\n hideCounter = false,\n hideMagnifier = false,\n customActions,\n onDelete,\n onClose,\n insets,\n topBarRef,\n show,\n ...otherProps\n }: FullscreenImageCarouselProps,\n ref: React.Ref<FullscreenImageCarouselRef>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const [currentSlide, setCurrentSlide] = useStateCallback(\n initialActiveItemIndex ?? 0\n );\n const [imagesDimension, setImageDimension] = useState<\n Record<string, ImageDimension>\n >({});\n const [zoom, setZoom] = useState(1);\n const [startX, setStartX] = useState<number | undefined>();\n const [endX, setEndX] = useState<number | undefined>();\n const containerRef = useRef<HTMLDivElement>(null);\n const thumbnailRefs = useRef<(HTMLDivElement | null)[]>([]);\n const zoomRefs = useRef<(ReactZoomPanPinchContentRef | null)[]>([]);\n const imageRef = useRef<HTMLDivElement>(null);\n const diff = startX && endX ? startX - endX : 0;\n const currentItem = items[currentSlide];\n const resolvedCustomActions =\n currentItem?.customActions ?? customActions ?? [];\n const hasAnyItemLabel = items.some(\n (item) => isCustomItem(item) && !!item.itemLabel?.trim()\n );\n const carouselItemNoun = hasAnyItemLabel ? \"item\" : \"image\";\n const hasFileInfo = useMemo(\n () =>\n items.some(\n (item) => item.fileName?.trim() || item.fileSize?.trim()\n ),\n [items]\n );\n\n const getItemAriaLabel = useCallback(\n (index: number) => {\n const item = items[index];\n const itemTypeLabel = hasAnyItemLabel ? \"Item\" : \"Image\";\n const prefix = isCustomItem(item)\n ? item.itemLabel?.trim() || \"\"\n : item.alt?.trim() || \"\";\n const positionLabel = `${itemTypeLabel} ${index + 1} of ${\n items.length\n }.`;\n\n return prefix ? `${prefix}. ${positionLabel}` : positionLabel;\n },\n [items, hasAnyItemLabel]\n );\n\n useImperativeHandle<FullscreenImageCarouselRef, FullscreenImageCarouselRef>(\n ref,\n () => ({\n currentItemIndex: currentSlide,\n setCurrentItem: goToSlide,\n goToPrevItem: goToPrevSlide,\n goToNextItem: goToNextSlide,\n })\n );\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEventListener(\"keydown\", handleKeyDown, \"document\");\n\n useEffect(() => {\n if (show) {\n imageRef.current?.focus();\n }\n }, [show]);\n\n useEffect(() => {\n if (items.length === 0) {\n setCurrentSlide(0);\n return;\n }\n\n if (currentSlide > items.length - 1) {\n setCurrentSlide(items.length - 1);\n }\n }, [currentSlide, items.length, setCurrentSlide]);\n\n useEffect(() => {\n thumbnailRefs.current?.[currentSlide]?.scrollIntoView({\n behavior: \"smooth\",\n inline: \"center\",\n });\n setZoom(1);\n }, [currentSlide]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleTouchStart = (e: React.TouchEvent) => {\n if (zoom <= 1) setStartX(e.touches[0].clientX);\n };\n\n const handleTouchMove = (e: React.TouchEvent) => {\n if (!startX || zoom > 1) return;\n setEndX(e.touches[0].clientX);\n };\n\n const handleTouchEnd = () => {\n if (!containerRef.current) return;\n if (Math.abs(diff) > containerRef.current.offsetWidth / 3) {\n if (diff > 0) {\n goToNextSlide();\n } else {\n goToPrevSlide();\n }\n }\n setStartX(undefined);\n setEndX(undefined);\n };\n\n const handleZoom = (e: ReactZoomPanPinchRef) => {\n setZoom(e.state.scale);\n };\n\n const handleDelete = () => {\n if (currentItem && onDelete) {\n onDelete(currentItem, currentSlide);\n }\n };\n\n const handleCustomAction = (\n action: FullscreenImageCarouselCustomAction\n ) => {\n if (currentItem) {\n action.onClick(currentItem, currentSlide);\n }\n };\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"ArrowRight\") {\n goToNextSlide();\n } else if (e.key === \"ArrowLeft\") {\n goToPrevSlide();\n } else if (e.key === \"Escape\") {\n onClose?.();\n }\n }\n\n const handleMagnifier = () => {\n if (zoom === 1) {\n const zoomRatio = getZoomRatio();\n zoomRefs.current?.[currentSlide]?.centerView(zoomRatio);\n setZoom(zoomRatio ?? 1);\n } else {\n setZoom(1);\n zoomRefs.current?.[currentSlide]?.resetTransform();\n }\n };\n\n const setDimension = ({\n src,\n height,\n width,\n }: {\n src: string;\n height: number;\n width: number;\n }) => {\n setImageDimension((oldState) => {\n return { ...oldState, [src]: { height, width } };\n });\n };\n\n const getZoomRatio = () => {\n if (!currentItem || isCustomItem(currentItem)) {\n return;\n }\n\n const imageDimension = imagesDimension[currentItem.src];\n\n if (containerRef.current && !!imageDimension) {\n const { clientHeight, clientWidth } = containerRef.current;\n const { width, height } = imageDimension;\n const isSmallImg = width < clientWidth && height < clientHeight;\n\n const isImgLandscapeRelativeToDevice =\n height / width < clientHeight / clientWidth;\n\n if (isSmallImg) {\n return isImgLandscapeRelativeToDevice\n ? clientWidth / width\n : clientHeight / height;\n }\n\n return isImgLandscapeRelativeToDevice\n ? clientHeight / (height / (width / clientWidth))\n : clientWidth / (width / (height / clientHeight));\n }\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const goToPrevSlide = () => {\n zoomRefs.current?.[currentSlide]?.resetTransform();\n setCurrentSlide(\n (prev) => (prev === 0 ? items.length - 1 : prev - 1),\n (slide) => {\n clearAnnouncer(\"polite\");\n announce(getItemAriaLabel(slide), \"polite\");\n }\n );\n };\n\n const goToNextSlide = () => {\n zoomRefs.current?.[currentSlide]?.resetTransform();\n setCurrentSlide(\n (prev) => (prev === items.length - 1 ? 0 : prev + 1),\n (slide) => {\n clearAnnouncer(\"polite\");\n announce(getItemAriaLabel(slide), \"polite\");\n }\n );\n };\n\n const goToSlide = (index: number) => {\n zoomRefs.current?.[currentSlide]?.resetTransform();\n setCurrentSlide(index);\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderSlides = () => {\n return (\n <ImageGallerySlides\n style={{\n transform: `translateX(calc(${\n -currentSlide * 100\n }% - ${diff}px))`,\n }}\n >\n {items.map((item, index) => {\n const isActive = index === currentSlide;\n const isActiveOrAdjacent =\n Math.abs(index - currentSlide) <= 1 ||\n (currentSlide === 0 && index === items.length - 1) ||\n (currentSlide === items.length - 1 && index === 0);\n\n return (\n <ImageGallerySlide key={index} data-testid=\"slide-item\">\n <FocusableImageRegion\n ref={isActive ? imageRef : null}\n tabIndex={isActive ? 0 : -1}\n >\n {isCustomItem(item) ? (\n isActiveOrAdjacent ? (\n item.renderContent()\n ) : (\n <SlidePlaceholderImage />\n )\n ) : (\n <TransformWrapper\n ref={(el) =>\n (zoomRefs.current[index] = el)\n }\n panning={{\n disabled: zoom <= 1,\n }}\n initialScale={1}\n onZoom={handleZoom}\n onZoomStop={handleZoom}\n onWheel={handleZoom}\n >\n <TransformComponent>\n <SlideImage\n src={item.src}\n alt={getItemAriaLabel(index)}\n placeholder={\n <SlidePlaceholderImage />\n }\n fit=\"scale-down\"\n retrieveImageDimension\n setDimension={setDimension}\n />\n </TransformComponent>\n </TransformWrapper>\n )}\n </FocusableImageRegion>\n </ImageGallerySlide>\n );\n })}\n </ImageGallerySlides>\n );\n };\n\n const renderFileInfo = () => {\n const { fileName, fileSize } = currentItem ?? {};\n const trimmedName = fileName?.trim();\n const trimmedSize = fileSize?.trim();\n\n return (\n <FileInfoTextWrapper\n $centerContent={!trimmedSize}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n data-testid=\"file-info-bar\"\n >\n {trimmedName && (\n <FileInfoFileName\n weight=\"semibold\"\n data-testid=\"file-info-name\"\n >\n {trimmedName}\n </FileInfoFileName>\n )}\n {trimmedSize && (\n <FileInfoFileSize data-testid=\"file-info-size\">\n {trimmedSize}\n </FileInfoFileSize>\n )}\n </FileInfoTextWrapper>\n );\n };\n\n const renderThumbnails = () => {\n return (\n <ThumbnailContainer\n $insetBottom={insets?.bottom}\n aria-hidden=\"true\"\n >\n <ThumbnailWrapper>\n {items.map((item, index) => {\n const src = isCustomItem(item)\n ? item.thumbnailSrc\n : item.thumbnailSrc ?? item.src;\n return (\n <ThumbnailItemContainer key={index}>\n <ThumbnailItem\n data-testid=\"thumbnail-item\"\n $active={index === currentSlide}\n onClick={() => goToSlide(index)}\n ref={(el) =>\n (thumbnailRefs.current[index] = el)\n }\n >\n {src ? (\n <ThumbnailImage\n src={src}\n alt={`Thumbnail ${index + 1}`}\n fit=\"cover\"\n />\n ) : (\n <SlidePlaceholderImage />\n )}\n </ThumbnailItem>\n </ThumbnailItemContainer>\n );\n })}\n </ThumbnailWrapper>\n </ThumbnailContainer>\n );\n };\n\n const renderTopActions = () => {\n return (\n <TopActionButtons\n ref={topBarRef}\n $hasFileInfo={hasFileInfo}\n $insetTop={insets?.top}\n $insetLeft={insets?.left}\n $insetRight={insets?.right}\n >\n {hasFileInfo && renderFileInfo()}\n\n {resolvedCustomActions.map((action, index) => (\n <CustomActionButton\n key={index}\n aria-label={action.ariaLabel}\n data-testid={action[\"data-testid\"]}\n onClick={() => handleCustomAction(action)}\n >\n {cloneElement(action.icon, { \"aria-hidden\": true })}\n </CustomActionButton>\n ))}\n\n {!hideMagnifier && !isCustomItem(currentItem) && (\n <MagnifierButton\n aria-label={zoom === 1 ? \"Zoom in\" : \"Zoom out\"}\n onClick={handleMagnifier}\n >\n {zoom === 1 ? (\n <MagnifierPlusIcon aria-hidden />\n ) : (\n <MagnifierMinusIcon aria-hidden />\n )}\n </MagnifierButton>\n )}\n\n {onDelete && (\n <DeleteButton\n aria-label={`Delete ${\n (isCustomItem(currentItem) &&\n currentItem.itemLabel?.trim()) ||\n \"image\"\n }`}\n data-testid=\"delete-btn\"\n onClick={handleDelete}\n >\n <BinIcon aria-hidden />\n </DeleteButton>\n )}\n\n <CloseButton\n aria-label={\n hasAnyItemLabel\n ? \"Close carousel\"\n : \"Close image carousel\"\n }\n onClick={onClose}\n >\n <CrossIcon aria-hidden />\n </CloseButton>\n </TopActionButtons>\n );\n };\n\n return (\n <ModalV2\n {...otherProps}\n data-testid=\"image-carousel-modal\"\n aria-label={hasAnyItemLabel ? \"Carousel\" : \"Image carousel\"}\n show={show}\n disableInitialFocus\n >\n <CarouselModalContent>\n <ImageGalleryContainer>\n <ImageGalleryWrapper>\n <ImageGallerySwipe\n ref={containerRef}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n {renderSlides()}\n </ImageGallerySwipe>\n\n {!hideNavigation && (\n <>\n <ArrowButton\n aria-label={`Previous ${carouselItemNoun}`}\n data-testid=\"prev-btn\"\n $position=\"left\"\n onClick={goToPrevSlide}\n $insetLeft={insets?.left}\n $insetRight={insets?.right}\n >\n <ChevronLeftIcon aria-hidden />\n </ArrowButton>\n <ArrowButton\n aria-label={`Next ${carouselItemNoun}`}\n data-testid=\"forward-btn\"\n $position=\"right\"\n onClick={goToNextSlide}\n $insetLeft={insets?.left}\n $insetRight={insets?.right}\n >\n <ChevronRightIcon aria-hidden />\n </ArrowButton>\n </>\n )}\n\n {!hideCounter && (\n <BoxChip aria-hidden=\"true\">\n <Chip weight=\"semibold\">{`${currentSlide + 1}/${\n items.length\n }`}</Chip>\n </BoxChip>\n )}\n </ImageGalleryWrapper>\n\n {!hideThumbnail && renderThumbnails()}\n </ImageGalleryContainer>\n {renderTopActions()}\n </CarouselModalContent>\n </ModalV2>\n );\n};\n\nexport const FullscreenImageCarousel = forwardRef<\n FullscreenImageCarouselRef,\n FullscreenImageCarouselProps\n>(Component);\n"],"names":["isCustomItem","item","type","Component","_a","ref","items","initialActiveItemIndex","hideThumbnail","hideNavigation","hideCounter","hideMagnifier","customActions","onDelete","onClose","insets","topBarRef","show","otherProps","__rest","currentSlide","setCurrentSlide","useStateCallback","imagesDimension","setImageDimension","useState","zoom","setZoom","startX","setStartX","endX","setEndX","containerRef","useRef","thumbnailRefs","zoomRefs","imageRef","diff","currentItem","resolvedCustomActions","_c","_b","hasAnyItemLabel","some","itemLabel","trim","carouselItemNoun","hasFileInfo","useMemo","fileName","fileSize","getItemAriaLabel","useCallback","index","itemTypeLabel","prefix","alt","positionLabel","length","useImperativeHandle","currentItemIndex","setCurrentItem","goToSlide","goToPrevItem","goToPrevSlide","goToNextItem","goToNextSlide","useEventListener","e","key","useEffect","current","focus","scrollIntoView","behavior","inline","handleZoom","state","scale","handleDelete","handleMagnifier","zoomRatio","getZoomRatio","centerView","_d","resetTransform","setDimension","src","height","width","oldState","Object","assign","imageDimension","clientHeight","clientWidth","isImgLandscapeRelativeToDevice","prev","slide","clearAnnouncer","announce","renderFileInfo","trimmedName","trimmedSize","_jsxs","FileInfoTextWrapper","_jsx","FileInfoFileName","weight","children","FileInfoFileSize","ModalV2","disableInitialFocus","CarouselModalContent","ImageGalleryContainer","ImageGalleryWrapper","ImageGallerySwipe","onTouchStart","touches","clientX","onTouchMove","onTouchEnd","Math","abs","offsetWidth","undefined","ImageGallerySlides","style","transform","map","isActive","isActiveOrAdjacent","ImageGallerySlide","FocusableImageRegion","tabIndex","renderContent","SlidePlaceholderImage","TransformWrapper","el","panning","disabled","initialScale","onZoom","onZoomStop","onWheel","TransformComponent","SlideImage","placeholder","fit","retrieveImageDimension","_Fragment","ArrowButton","$position","onClick","$insetLeft","left","$insetRight","right","ChevronLeftIcon","ChevronRightIcon","BoxChip","Chip","ThumbnailContainer","$insetBottom","bottom","ThumbnailWrapper","thumbnailSrc","ThumbnailItemContainer","ThumbnailItem","$active","ThumbnailImage","TopActionButtons","$hasFileInfo","top","action","CustomActionButton","ariaLabel","handleCustomAction","cloneElement","icon","MagnifierButton","MagnifierPlusIcon","MagnifierMinusIcon","DeleteButton","BinIcon","CloseButton","CrossIcon","renderTopActions","FullscreenImageCarousel","forwardRef"],"mappings":"ihDAgEA,MAAMA,EACFC,KAEEA,GAAsB,WAAdA,EAAKC,KAENC,EAAY,CACrBC,EAeAC,cAfAC,MACIA,GAAKC,uBACLA,GAAsBC,cACtBA,IAAgB,EAAKC,eACrBA,IAAiB,EAAKC,YACtBA,IAAc,EAAKC,cACnBA,IAAgB,EAAKC,cACrBA,GAAaC,SACbA,GAAQC,QACRA,GAAOC,OACPA,GAAMC,UACNA,GAASC,KACTA,IAAIb,EACDc,GAAUC,EAAAf,EAbjB,oKAoBA,MAAOgB,GAAcC,IAAmBC,EACpCf,SAAAA,GAA0B,IAEvBgB,GAAiBC,IAAqBC,EAE3C,CAAA,IACKC,GAAMC,IAAWF,EAAS,IAC1BG,GAAQC,IAAaJ,KACrBK,GAAMC,IAAWN,IAClBO,GAAeC,EAAuB,MACtCC,GAAgBD,EAAkC,IAClDE,GAAWF,EAA+C,IAC1DG,GAAWH,EAAuB,MAClCI,GAAOT,IAAUE,GAAOF,GAASE,GAAO,EACxCQ,GAAchC,GAAMc,IACpBmB,GACyC,QAA3CC,EAA0B,QAA1BC,EAAAH,cAAW,EAAXA,GAAa1B,qBAAa,IAAA6B,EAAAA,EAAI7B,UAAa,IAAA4B,EAAAA,EAAI,GAC7CE,GAAkBpC,GAAMqC,MACzB1C,IAAQ,IAAAG,EAAC,OAAAJ,EAAaC,OAAyB,QAAdG,EAAAH,EAAK2C,iBAAS,IAAAxC,OAAA,EAAAA,EAAEyC,OAAM,IAEtDC,GAAmBJ,GAAkB,OAAS,QAC9CK,GAAcC,GAChB,IACI1C,GAAMqC,MACD1C,YAAS,OAAa,UAAbA,EAAKgD,gBAAQ,IAAA7C,OAAA,EAAAA,EAAEyC,UAAuB,UAAb5C,EAAKiD,gBAAQ,IAAAT,OAAA,EAAAA,EAAEI,OAAM,KAEhE,CAACvC,KAGC6C,GAAmBC,GACpBC,YACG,MAAMpD,EAAOK,GAAM+C,GACbC,EAAgBZ,GAAkB,OAAS,QAC3Ca,EAASvD,EAAaC,IACR,QAAdG,EAAAH,EAAK2C,iBAAS,IAAAxC,OAAA,EAAAA,EAAEyC,SAAU,IAClB,QAARJ,EAAAxC,EAAKuD,WAAG,IAAAf,OAAA,EAAAA,EAAEI,SAAU,GACpBY,EAAgB,GAAGH,KAAiBD,EAAQ,QAC9C/C,GAAMoD,UAGV,OAAOH,EAAS,GAAGA,MAAWE,IAAkBA,CAAa,GAEjE,CAACnD,GAAOoC,KAGZiB,EACItD,GACA,KAAA,CACIuD,iBAAkBxC,GAClByC,eAAgBC,GAChBC,aAAcC,GACdC,aAAcC,OAOtBC,EAAiB,WAsEjB,SAAuBC,GACL,eAAVA,EAAEC,IACFH,KACiB,cAAVE,EAAEC,IACTL,KACiB,WAAVI,EAAEC,MACTvD,UAAAA,KAER,GA9E2C,YAE3CwD,GAAU,WACFrD,KACgB,QAAhBb,EAAAgC,GAASmC,eAAO,IAAAnE,GAAAA,EAAEoE,QACtB,GACD,CAACvD,KAEJqD,GAAU,KACe,IAAjBhE,GAAMoD,OAKNtC,GAAed,GAAMoD,OAAS,GAC9BrC,GAAgBf,GAAMoD,OAAS,GAL/BrC,GAAgB,EAMpB,GACD,CAACD,GAAcd,GAAMoD,OAAQrC,KAEhCiD,GAAU,aAC+B,QAArC7B,UAAArC,EAAA8B,GAAcqC,8BAAUnD,WAAa,IAAAqB,GAAAA,EAAEgC,eAAe,CAClDC,SAAU,SACVC,OAAQ,WAEZhD,GAAQ,EAAE,GACX,CAACP,KAKJ,MAsBMwD,GAAcR,IAChBzC,GAAQyC,EAAES,MAAMC,MAAM,EAGpBC,GAAe,KACbzC,IAAezB,IACfA,GAASyB,GAAalB,GAC1B,EAqBJ,MAAM4D,GAAkB,iBACpB,GAAa,IAATtD,GAAY,CACZ,MAAMuD,EAAYC,KACc,QAAhCzC,EAAgB,QAAhBrC,EAAA+B,GAASoC,eAAO,IAAAnE,OAAA,EAAAA,EAAGgB,WAAa,IAAAqB,GAAAA,EAAE0C,WAAWF,GAC7CtD,GAAQsD,QAAAA,EAAa,EACzB,MACItD,GAAQ,GACwB,QAAhCyD,EAAgB,QAAhB5C,EAAAL,GAASoC,eAAO,IAAA/B,OAAA,EAAAA,EAAGpB,WAAa,IAAAgE,GAAAA,EAAEC,gBACtC,EAGEC,GAAe,EACjBC,MACAC,SACAC,YAMAjE,IAAmBkE,GACfC,OAAAC,OAAAD,OAAAC,OAAA,CAAA,EAAYF,GAAQ,CAAEH,CAACA,GAAM,CAAEC,SAAQC,YACzC,EAGAP,GAAe,KACjB,IAAK5C,IAAetC,EAAasC,IAC7B,OAGJ,MAAMuD,EAAiBtE,GAAgBe,GAAYiD,KAEnD,GAAIvD,GAAauC,SAAasB,EAAgB,CAC1C,MAAMC,aAAEA,EAAYC,YAAEA,GAAgB/D,GAAauC,SAC7CkB,MAAEA,EAAKD,OAAEA,GAAWK,EAGpBG,EACFR,EAASC,EAAQK,EAAeC,EAEpC,OALmBN,EAAQM,GAAeP,EAASM,EAMxCE,EACDD,EAAcN,EACdK,EAAeN,EAGlBQ,EACDF,GAAgBN,GAAUC,EAAQM,IAClCA,GAAeN,GAASD,EAASM,GAC3C,GAME9B,GAAgB,aACc,QAAhCvB,EAAgB,QAAhBrC,EAAA+B,GAASoC,eAAO,IAAAnE,OAAA,EAAAA,EAAGgB,WAAa,IAAAqB,GAAAA,EAAE4C,iBAClChE,IACK4E,GAAmB,IAATA,EAAa3F,GAAMoD,OAAS,EAAIuC,EAAO,IACjDC,IACGC,EAAe,UACfC,EAASjD,GAAiB+C,GAAQ,SAAS,GAElD,EAGChC,GAAgB,aACc,QAAhCzB,EAAgB,QAAhBrC,EAAA+B,GAASoC,eAAO,IAAAnE,OAAA,EAAAA,EAAGgB,WAAa,IAAAqB,GAAAA,EAAE4C,iBAClChE,IACK4E,GAAUA,IAAS3F,GAAMoD,OAAS,EAAI,EAAIuC,EAAO,IACjDC,IACGC,EAAe,UACfC,EAASjD,GAAiB+C,GAAQ,SAAS,GAElD,EAGCpC,GAAaT,YACiB,QAAhCZ,EAAgB,QAAhBrC,EAAA+B,GAASoC,eAAO,IAAAnE,OAAA,EAAAA,EAAGgB,WAAa,IAAAqB,GAAAA,EAAE4C,iBAClChE,GAAgBgC,EAAM,EAqEpBgD,GAAiB,KACnB,MAAMpD,SAAEA,EAAQC,SAAEA,GAAaZ,SAAAA,GAAe,CAAA,EACxCgE,EAAcrD,eAAAA,EAAUJ,OACxB0D,EAAcrD,eAAAA,EAAUL,OAE9B,OACI2D,EAACC,mBACoBF,cACP,SAAQ,cACN,OAAM,cACN,0BAEXD,GACGI,EAACC,GACGC,OAAO,WAAU,cACL,iBAAgBC,SAE3BP,IAGRC,GACGG,EAACI,EAAgB,CAAA,cAAa,iBAAgBD,SACzCN,MAGS,EA0G9B,OACIG,EAACK,mBACO7F,GAAU,CAAA,cACF,uBAAsB,aACtBwB,GAAkB,WAAa,iBAC3CzB,KAAMA,GACN+F,qBAAmB,EAAAH,SAEnBL,EAACS,EAAoB,CAAAJ,SAAA,CACjBL,EAACU,EAAqB,CAAAL,SAAA,CAClBL,EAACW,EAAmB,CAAAN,SAAA,CAChBH,EAACU,EAAiB,CACd/G,IAAK2B,GACLqF,aAtVEjD,IAClB1C,IAAQ,GAAGG,GAAUuC,EAAEkD,QAAQ,GAAGC,QAAQ,EAsV1BC,YAnVCpD,KAChBxC,IAAUF,GAAO,GACtBK,GAAQqC,EAAEkD,QAAQ,GAAGC,QAAQ,EAkVTE,WA/UD,KACdzF,GAAauC,UACdmD,KAAKC,IAAItF,IAAQL,GAAauC,QAAQqD,YAAc,IAChDvF,GAAO,EACP6B,KAEAF,MAGRnC,QAAUgG,GACV9F,QAAQ8F,GAAU,WAsHdnB,EAACoB,EAAkB,CACfC,MAAO,CACHC,UAAW,mBACS,KAAf5G,SACEiB,UACVwE,SAEAvG,GAAM2H,KAAI,CAAChI,EAAMoD,KACd,MAAM6E,EAAW7E,IAAUjC,GACrB+G,EACFT,KAAKC,IAAItE,EAAQjC,KAAiB,GAChB,IAAjBA,IAAsBiC,IAAU/C,GAAMoD,OAAS,GAC/CtC,KAAiBd,GAAMoD,OAAS,GAAe,IAAVL,EAE1C,OACIqD,EAAC0B,iBAA0C,aAAYvB,SACnDH,EAAC2B,EAAoB,CACjBhI,IAAK6H,EAAW9F,GAAW,KAC3BkG,SAAUJ,EAAW,GAAI,EAAErB,SAE1B7G,EAAaC,GACVkI,EACIlI,EAAKsI,gBAEL7B,EAAC8B,EAAqB,CAAA,GAG1B9B,EAAC+B,EAAgB,CACbpI,IAAMqI,GACDvG,GAASoC,QAAQlB,GAASqF,EAE/BC,QAAS,CACLC,SAAUlH,IAAQ,GAEtBmH,aAAc,EACdC,OAAQlE,GACRmE,WAAYnE,GACZoE,QAASpE,GAAUiC,SAEnBH,EAACuC,EAAkB,CAAApC,SACfH,EAACwC,EAAU,CACP3D,IAAKtF,EAAKsF,IACV/B,IAAKL,GAAiBE,GACtB8F,YACIzC,EAAC8B,EAAqB,IAE1BY,IAAI,aACJC,wBAAsB,EACtB/D,aAAcA,YAjCdjC,EAuCJ,SA8JlB5C,IACE+F,EAAA8C,EAAA,CAAAzC,SAAA,CACIH,EAAC6C,EAAW,CAAA,aACI,YAAYzG,mBACZ,WAAU0G,UACZ,OACVC,QAASzF,GAAa0F,WACV3I,gBAAAA,GAAQ4I,KAAIC,YACX7I,cAAM,EAANA,GAAQ8I,MAAKhD,SAE1BH,EAACoD,EAAe,CAAA,eAAA,MAEpBpD,EAAC6C,EAAW,CAAA,aACI,QAAQzG,KAAkB,cAC1B,cAAa0G,UACf,QACVC,QAASvF,GAAawF,WACV3I,gBAAAA,GAAQ4I,KAAIC,YACX7I,cAAM,EAANA,GAAQ8I,eAErBnD,EAACqD,4BAKXrJ,IACEgG,EAACsD,iBAAoB,OAAMnD,SACvBH,EAACuD,EAAI,CAACrD,OAAO,oBAAY,GAAGxF,GAAe,KACvCd,GAAMoD,iBAMpBlD,IA1JVkG,EAACwD,EAAkB,CAAAC,aACDpJ,cAAM,EAANA,GAAQqJ,OAAM,cAChB,gBAEZ1D,EAAC2D,EAAgB,CAAAxD,SACZvG,GAAM2H,KAAI,CAAChI,EAAMoD,WACd,MAAMkC,EAAMvF,EAAaC,GACnBA,EAAKqK,aACY,UAAjBrK,EAAKqK,oBAAY,IAAAlK,EAAAA,EAAIH,EAAKsF,IAChC,OACImB,EAAC6D,EAAsB,CAAA1D,SACnBH,EAAC8D,EAAa,CAAA,cACE,iBAAgBC,QACnBpH,IAAUjC,GACnBqI,QAAS,IAAM3F,GAAUT,GACzBhD,IAAMqI,GACDxG,GAAcqC,QAAQlB,GAASqF,EAAG7B,SAGtCtB,EACGmB,EAACgE,EAAc,CACXnF,IAAKA,EACL/B,IAAK,aAAaH,EAAQ,IAC1B+F,IAAI,UAGR1C,EAAC8B,SAhBgBnF,EAmBJ,WAQxB,YACrB,OACImD,EAACmE,EAAgB,CACbtK,IAAKW,GAAS4J,aACA7H,aACHhC,cAAM,EAANA,GAAQ8J,IAAGnB,WACV3I,cAAM,EAANA,GAAQ4I,KAAIC,YACX7I,gBAAAA,GAAQ8I,MAAKhD,SAAA,CAEzB9D,IAAesD,KAEf9D,GAAsB0F,KAAI,CAAC6C,EAAQzH,IAChCqD,EAACqE,gBAEeD,EAAOE,UAAS,cACfF,EAAO,eACpBrB,QAAS,IA1PF,CACvBqB,IAEIxI,IACAwI,EAAOrB,QAAQnH,GAAalB,GAChC,EAqP+B6J,CAAmBH,GAAOjE,SAExCqE,EAAaJ,EAAOK,KAAM,CAAE,eAAe,KALvC9H,MASX1C,KAAkBX,EAAasC,KAC7BoE,EAAC0E,EAAe,CAAA,aACS,IAAT1J,GAAa,UAAY,WACrC+H,QAASzE,GAAe6B,SAGpBH,EADM,IAAThF,GACI2J,EAEAC,EAFiB,CAAA,eAAA,MAO7BzK,IACG6F,EAAC6E,gBACe,UACPvL,EAAasC,cACVlC,EAAAkC,GAAYM,gCAAWC,SAC3B,UACF,cACU,aACZ4G,QAAS1E,GAAY8B,SAErBH,EAAC8E,wBAIT9E,EAAC+E,gBAEO/I,GACM,iBACA,uBAEV+G,QAAS3I,GAAO+F,SAEhBH,EAACgF,EAAS,CAAA,eAAA,QAEC,EA4DdC,QAEC,EAILC,EAA0BC,EAGrC1L"}
@@ -33,6 +33,13 @@ export declare const MagnifierButton: import("styled-components/dist/types").ISt
33
33
  as?: import("styled-components").WebTarget | undefined;
34
34
  forwardedAs?: import("styled-components").WebTarget | undefined;
35
35
  }, never>>> & string;
36
+ export declare const CustomActionButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("../shared/clickable-icon").ClickableIconProps & import("react").RefAttributes<HTMLButtonElement>, never> & Partial<Pick<import("../shared/clickable-icon").ClickableIconProps & import("react").RefAttributes<HTMLButtonElement>, never>> & {
37
+ as?: import("styled-components").WebTarget | undefined;
38
+ forwardedAs?: import("styled-components").WebTarget | undefined;
39
+ }, never> & Partial<Pick<import("styled-components").FastOmit<import("../shared/clickable-icon").ClickableIconProps & import("react").RefAttributes<HTMLButtonElement>, never> & Partial<Pick<import("../shared/clickable-icon").ClickableIconProps & import("react").RefAttributes<HTMLButtonElement>, never>> & {
40
+ as?: import("styled-components").WebTarget | undefined;
41
+ forwardedAs?: import("styled-components").WebTarget | undefined;
42
+ }, never>>> & string;
36
43
  export declare const ArrowButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("../shared/clickable-icon").ClickableIconProps & import("react").RefAttributes<HTMLButtonElement>, never> & Partial<Pick<import("../shared/clickable-icon").ClickableIconProps & import("react").RefAttributes<HTMLButtonElement>, never>> & {
37
44
  as?: import("styled-components").WebTarget | undefined;
38
45
  forwardedAs?: import("styled-components").WebTarget | undefined;