@fibery/ui-kit 1.40.3 → 1.41.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 (174) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/eslint.config.mjs +16 -0
  3. package/package.json +11 -13
  4. package/src/a11y-color.test.ts +162 -0
  5. package/src/a11y-color.ts +13 -20
  6. package/src/actions-menu/actions-menu-item.tsx +9 -12
  7. package/src/actions-menu/context-actions-menu.tsx +8 -3
  8. package/src/ai/model.tsx +0 -1
  9. package/src/ai/temperature.tsx +0 -1
  10. package/src/animated-height-container.tsx +3 -3
  11. package/src/antd/ant-modal.tsx +10 -5
  12. package/src/antd/index.tsx +3 -0
  13. package/src/antd/input.tsx +0 -1
  14. package/src/antd/styles.ts +15 -15
  15. package/src/app-icon-with-fallback.tsx +6 -6
  16. package/src/app-icon-wrapper.tsx +2 -3
  17. package/src/app-icon.tsx +4 -4
  18. package/src/avatar.tsx +3 -3
  19. package/src/button/base-button.tsx +0 -1
  20. package/src/button/button.tsx +1 -0
  21. package/src/button/make-button-colors.ts +5 -13
  22. package/src/checkbox.tsx +2 -2
  23. package/src/collapsible-section.tsx +11 -1
  24. package/src/color-picker/ColorPickerOrLoader.js +2 -2
  25. package/src/color-utils.test.ts +307 -0
  26. package/src/color-utils.ts +215 -0
  27. package/src/command-menu/index.tsx +1 -0
  28. package/src/comment.tsx +3 -2
  29. package/src/context-menu/index.tsx +12 -7
  30. package/src/date-picker/contexts.ts +2 -2
  31. package/src/date-picker/date-range-picker.tsx +3 -4
  32. package/src/date-picker/single-date-picker.tsx +147 -119
  33. package/src/date-picker/types.ts +4 -3
  34. package/src/day-select/iso-week-day-select.tsx +2 -2
  35. package/src/day-select/week-day-select.tsx +2 -2
  36. package/src/delayed.tsx +0 -1
  37. package/src/design-system/alpha.test.ts +59 -0
  38. package/src/design-system/alpha.ts +41 -0
  39. package/src/design-system/animation.ts +10 -0
  40. package/src/design-system/colors-css.test.ts +39 -0
  41. package/src/design-system/colors-css.ts +25 -0
  42. package/src/design-system/colors-js.test.ts +232 -0
  43. package/src/design-system/colors-js.ts +107 -0
  44. package/src/design-system/colors.test.ts +74 -0
  45. package/src/design-system/colors.ts +759 -0
  46. package/src/design-system/date.ts +3 -0
  47. package/src/design-system/layout.ts +106 -0
  48. package/src/design-system/theme.test.ts +94 -0
  49. package/src/design-system/theme.ts +93 -0
  50. package/src/design-system/typography.ts +179 -0
  51. package/src/design-system/vars.test.ts +1679 -0
  52. package/src/design-system/vars.ts +52 -0
  53. package/src/design-system.test.ts +45 -22
  54. package/src/design-system.ts +25 -1339
  55. package/src/dropdown-menu/index.tsx +21 -16
  56. package/src/emoji-picker/app-icon-picker.tsx +5 -5
  57. package/src/emoji-picker/emoji-picker-content-with-color.tsx +4 -4
  58. package/src/emoji-picker/icon-emoji-picker.tsx +3 -3
  59. package/src/favorites-icon.tsx +1 -1
  60. package/src/fibermoji-placeholder.tsx +3 -3
  61. package/src/field-container.tsx +11 -2
  62. package/src/file-item/file-icon.tsx +169 -0
  63. package/src/file-item/file-menu-items.tsx +68 -0
  64. package/src/file-item/file-preview-actions.tsx +38 -0
  65. package/src/file-item/file-title.tsx +48 -0
  66. package/src/file-item/types.ts +27 -0
  67. package/src/file-item/use-register-in-image-gallery.tsx +70 -0
  68. package/src/file-item-2.tsx +32 -348
  69. package/src/file-item.tsx +6 -3
  70. package/src/hue-shift.test.ts +91 -0
  71. package/src/icons/ast/ChatBubble.ts +8 -0
  72. package/src/icons/ast/ChatFloat.ts +8 -0
  73. package/src/icons/ast/ChatSidebar.ts +8 -0
  74. package/src/icons/ast/FileCounter.ts +8 -0
  75. package/src/icons/ast/FileMultiple.ts +8 -0
  76. package/src/icons/ast/FileOther.ts +8 -0
  77. package/src/icons/ast/NoBorder.ts +8 -0
  78. package/src/icons/ast/NoFill.ts +8 -0
  79. package/src/icons/ast/ValueEdit.ts +8 -0
  80. package/src/icons/ast/index.tsx +9 -0
  81. package/src/icons/react/ChatBubble.tsx +13 -0
  82. package/src/icons/react/ChatFloat.tsx +13 -0
  83. package/src/icons/react/ChatSidebar.tsx +13 -0
  84. package/src/icons/react/FileCounter.tsx +13 -0
  85. package/src/icons/react/FileMultiple.tsx +13 -0
  86. package/src/icons/react/FileOther.tsx +13 -0
  87. package/src/icons/react/NoBorder.tsx +13 -0
  88. package/src/icons/react/NoFill.tsx +13 -0
  89. package/src/icons/react/ValueEdit.tsx +13 -0
  90. package/src/icons/react/index.tsx +9 -0
  91. package/src/icons/svg/chat-bubble.svg +4 -0
  92. package/src/icons/svg/chat-float.svg +4 -0
  93. package/src/icons/svg/chat-sidebar.svg +4 -0
  94. package/src/icons/svg/file-counter.svg +3 -0
  95. package/src/icons/svg/file-multiple.svg +3 -0
  96. package/src/icons/svg/file-other.svg +3 -0
  97. package/src/icons/svg/no-border.svg +17 -0
  98. package/src/icons/svg/no-fill.svg +4 -0
  99. package/src/icons/svg/value-edit.svg +3 -0
  100. package/src/images-gallery/images-gallery.tsx +8 -6
  101. package/src/images-gallery/slide-buttons.tsx +4 -11
  102. package/src/is-iOS.ts +0 -1
  103. package/src/is-in-popup.ts +2 -1
  104. package/src/lists/actions-menu-row-surface.tsx +7 -7
  105. package/src/loading-sausage.tsx +2 -2
  106. package/src/media-query-utils.ts +1 -2
  107. package/src/mobile-keyboard-aware-popup.tsx +6 -5
  108. package/src/modal-menu/modal-menu-content.tsx +2 -2
  109. package/src/number-input/decimal.js +9 -7
  110. package/src/number-input/{number-inline-input-with-autosize.tsx → number-input-inline-with-autosize.tsx} +20 -41
  111. package/src/number-input/number-input-inline.tsx +118 -0
  112. package/src/number-input/{index.test.js → number-input.test.tsx} +38 -43
  113. package/src/number-input/number-input.tsx +63 -121
  114. package/src/number-input/types.ts +19 -0
  115. package/src/number-input/utils.ts +61 -0
  116. package/src/online-users.tsx +2 -2
  117. package/src/palette-generator.test.ts +309 -0
  118. package/src/palette-generator.ts +160 -0
  119. package/src/palettes/_.ts +72 -0
  120. package/src/palettes/slate-arch.colors-snapshot.test.ts +1689 -0
  121. package/src/palettes/slate-arch.ts +188 -0
  122. package/src/palettes/slate-user.colors-snapshot.test.ts +1689 -0
  123. package/src/palettes/slate-user.ts +187 -0
  124. package/src/palettes/warm-arch.colors-snapshot.test.ts +1689 -0
  125. package/src/palettes/warm-arch.ts +222 -0
  126. package/src/palettes/warm-user.colors-snapshot.test.ts +1689 -0
  127. package/src/palettes/warm-user.ts +222 -0
  128. package/src/platform.ts +0 -3
  129. package/src/popover/get-element-ref.ts +28 -0
  130. package/src/popover/index.tsx +236 -339
  131. package/src/popover/{mobile-popup-context.tsx → mobile-popover-context.tsx} +7 -7
  132. package/src/popover/mobile-popover.tsx +169 -0
  133. package/src/popover/modifiers.tsx +2 -2
  134. package/src/popover/popup-stack-context.tsx +8 -9
  135. package/src/progress.tsx +2 -2
  136. package/src/reactions/reaction-button.tsx +12 -6
  137. package/src/root-theme-provider.test.tsx +411 -0
  138. package/src/scale-generator.ts +356 -0
  139. package/src/select/components/menu-list-virtualized.tsx +12 -25
  140. package/src/select/components/menu.tsx +12 -2
  141. package/src/select/index.tsx +6 -5
  142. package/src/select/select.tsx +38 -39
  143. package/src/select/styles.ts +0 -1
  144. package/src/select/util.ts +1 -1
  145. package/src/static-palettes.ts +356 -0
  146. package/src/thematic-color-picker.tsx +266 -0
  147. package/src/thematic-constants.tsx +27 -0
  148. package/src/thematic-controls.tsx +144 -0
  149. package/src/thematic-scales.tsx +122 -0
  150. package/src/thematic-state.ts +370 -0
  151. package/src/thematic.tsx +386 -0
  152. package/src/theme-provider.test.tsx +820 -0
  153. package/src/theme-provider.tsx +158 -92
  154. package/src/theme-settings.ts +67 -12
  155. package/src/theme-styles.ts +58 -6
  156. package/src/toast/toast-action.tsx +1 -1
  157. package/src/toast/toast.tsx +1 -2
  158. package/src/toggle-on-off.tsx +2 -2
  159. package/src/toggle.tsx +7 -8
  160. package/src/tooltip.tsx +14 -10
  161. package/src/type-badge.tsx +7 -14
  162. package/src/unit/styles.ts +2 -25
  163. package/src/unit/unit-with-tooltip.tsx +3 -2
  164. package/src/use-is-phone.tsx +7 -2
  165. package/src/use-long-press.tsx +2 -2
  166. package/src/use-on-screen-keyboard-data.tsx +2 -2
  167. package/src/with-data.tsx +4 -3
  168. package/src/workflow-progress-icon.tsx +2 -2
  169. package/.eslintignore +0 -3
  170. package/.eslintrc +0 -14
  171. package/src/__mocks__/createInlineTheme.js +0 -3
  172. package/src/create-inline-theme.ts +0 -66
  173. package/src/number-input/index.js +0 -191
  174. package/src/palette.ts +0 -237
@@ -0,0 +1,386 @@
1
+ import {css} from "@linaria/core";
2
+ import {createPortal} from "react-dom";
3
+ import {border, space, themeVars} from "./design-system";
4
+ import {ThemeProvider} from "./theme-provider";
5
+ import {toOKLCH, toRGB} from "./color-utils";
6
+ import {useThematicState} from "./thematic-state";
7
+ import {IconButton} from "./button/icon-button";
8
+ import Refresh from "./icons/react/Refresh";
9
+ import Lab from "./icons/react/Lab";
10
+ import Restore from "./icons/react/Restore";
11
+ import ColorCoding from "./icons/react/ColorCoding";
12
+ import Close from "./icons/react/Close";
13
+ import CollapseAll from "./icons/react/CollapseAll";
14
+ import FileDownload from "./icons/react/FileDownload";
15
+ import FileUpload from "./icons/react/FileUpload";
16
+ import {themeIcons} from "./thematic-constants";
17
+ import {ArrayEditor, ArraySlider, controlRowCss, Slider} from "./thematic-controls";
18
+ import {scaleCss, ScalePair, ScaleRow, sectionLabelCss, sectionSeparatorCss} from "./thematic-scales";
19
+ import {SwatchWithPicker} from "./thematic-color-picker";
20
+
21
+ const panelCss = css`
22
+ position: fixed;
23
+ bottom: 0;
24
+ left: 0;
25
+ background: ${themeVars.colorBgPopup};
26
+ box-shadow: ${themeVars.shadow400};
27
+ padding: ${space.s12}px;
28
+ border-top-right-radius: ${border.radius8}px;
29
+ z-index: 99999;
30
+ font-size: 12px;
31
+ `;
32
+
33
+ const buttonsCss = css`
34
+ display: flex;
35
+ gap: ${space.s8}px;
36
+ margin-top: ${space.s12}px;
37
+ `;
38
+
39
+ export function Thematic() {
40
+ const {
41
+ palette,
42
+ isAltPressed,
43
+ collapsed,
44
+ setCollapsed,
45
+ visible,
46
+ setVisible,
47
+ themePref,
48
+ isModified,
49
+ showLight,
50
+ showDark,
51
+ isAuto,
52
+ prefsPresent,
53
+ staticPalette,
54
+ baseCurves,
55
+ setBaseCurves,
56
+ accentCurves,
57
+ setAccentCurves,
58
+ update,
59
+ randomize,
60
+ cycleStaticPalettes,
61
+ cycleTheme,
62
+ reset,
63
+ updateScaleColor,
64
+ highlightScale,
65
+ clearHighlight,
66
+ exportState,
67
+ importState,
68
+ } = useThematicState();
69
+
70
+ const handleExport = () => {
71
+ const data = exportState();
72
+ const blob = new Blob([JSON.stringify(data, null, 2)], {type: "application/json"});
73
+ const url = URL.createObjectURL(blob);
74
+ const a = document.createElement("a");
75
+ a.href = url;
76
+ const hasLight = "base" in data;
77
+ const hasDark = "baseDark" in data;
78
+ const modes = [hasLight && "light", hasDark && "dark"].filter(Boolean).join("&");
79
+ const now = new Date().toISOString().replaceAll(/\D+/g, "");
80
+ a.download = `palette-${modes}-${now}.json`;
81
+ a.click();
82
+ URL.revokeObjectURL(url);
83
+ };
84
+
85
+ const handleImport = () => {
86
+ const input = document.createElement("input");
87
+ input.type = "file";
88
+ input.accept = ".json";
89
+ input.onchange = () => {
90
+ input.files?.[0]?.text().then((json) => {
91
+ try {
92
+ importState(JSON.parse(json));
93
+ } catch {
94
+ /* ignore invalid */
95
+ }
96
+ });
97
+ };
98
+ input.click();
99
+ };
100
+
101
+ if (!visible) {
102
+ return null;
103
+ }
104
+
105
+ const panel = (
106
+ <div className={panelCss}>
107
+ {collapsed ? (
108
+ <IconButton size="small" variant="ghost" color="neutral" onClick={() => setCollapsed(false)} title="Thematic">
109
+ <ColorCoding />
110
+ </IconButton>
111
+ ) : (
112
+ <>
113
+ <IconButton
114
+ size="small"
115
+ variant="ghost"
116
+ color="neutral"
117
+ onClick={() => setVisible(false)}
118
+ title="Close"
119
+ style={{position: "absolute", top: space.s4, right: space.s4}}
120
+ >
121
+ <Close />
122
+ </IconButton>
123
+ <ScalePair
124
+ name="base"
125
+ label="base"
126
+ light={palette.base}
127
+ dark={palette.baseDark}
128
+ showLight={showLight}
129
+ showDark={showDark}
130
+ onLightColorChange={(i, c) => updateScaleColor("base", i, c)}
131
+ onDarkColorChange={(i, c) => updateScaleColor("baseDark", i, c)}
132
+ onLightHighlight={highlightScale("base")}
133
+ onDarkHighlight={highlightScale("baseDark")}
134
+ onHighlightEnd={clearHighlight}
135
+ isAltPressed={isAltPressed}
136
+ />
137
+ {!isAuto && (
138
+ <div className={controlRowCss}>
139
+ <ArrayEditor
140
+ label="L"
141
+ values={baseCurves.lightness}
142
+ onChange={(L) => setBaseCurves({...baseCurves, lightness: L})}
143
+ />
144
+ </div>
145
+ )}
146
+ <ArraySlider
147
+ label="C"
148
+ values={baseCurves.chroma}
149
+ onValuesChange={isAuto ? undefined : (C) => setBaseCurves({...baseCurves, chroma: C})}
150
+ sliderValue={prefsPresent.baseChroma ?? 0}
151
+ onSliderChange={(v) => update({baseChroma: v})}
152
+ min={0}
153
+ max={0.25}
154
+ step={0.001}
155
+ />
156
+ <Slider
157
+ label="H"
158
+ value={prefsPresent.baseHue ?? 0}
159
+ min={0}
160
+ max={360}
161
+ step={1}
162
+ onChange={(v) => update({baseHue: v})}
163
+ />
164
+
165
+ <div className={sectionSeparatorCss} />
166
+
167
+ <ScalePair
168
+ name="accent"
169
+ label="accent"
170
+ light={palette.accent}
171
+ dark={palette.accentDark}
172
+ showLight={showLight}
173
+ showDark={showDark}
174
+ onLightColorChange={(i, c) => updateScaleColor("accent", i, c)}
175
+ onDarkColorChange={(i, c) => updateScaleColor("accentDark", i, c)}
176
+ onLightHighlight={highlightScale("accent")}
177
+ onDarkHighlight={highlightScale("accentDark")}
178
+ onHighlightEnd={clearHighlight}
179
+ isAltPressed={isAltPressed}
180
+ />
181
+ {!isAuto && (
182
+ <div className={controlRowCss}>
183
+ <ArrayEditor
184
+ label="L"
185
+ values={accentCurves.lightness}
186
+ onChange={(L) => setAccentCurves({...accentCurves, lightness: L})}
187
+ />
188
+ </div>
189
+ )}
190
+ <ArraySlider
191
+ label="C"
192
+ values={accentCurves.chroma}
193
+ onValuesChange={isAuto ? undefined : (C) => setAccentCurves({...accentCurves, chroma: C})}
194
+ sliderValue={prefsPresent.accentChroma}
195
+ onSliderChange={(v) => update({accentChroma: v})}
196
+ min={0.05}
197
+ max={0.25}
198
+ step={0.001}
199
+ />
200
+ <Slider
201
+ label="H"
202
+ value={prefsPresent.accentHue}
203
+ min={0}
204
+ max={360}
205
+ step={1}
206
+ onChange={(v) => update({accentHue: v})}
207
+ />
208
+
209
+ <div className={sectionSeparatorCss} />
210
+
211
+ <ScalePair
212
+ name="red"
213
+ light={palette.red}
214
+ dark={palette.redDark}
215
+ showLight={showLight}
216
+ showDark={showDark}
217
+ onLightColorChange={(i, c) => updateScaleColor("red", i, c)}
218
+ onDarkColorChange={(i, c) => updateScaleColor("redDark", i, c)}
219
+ onLightHighlight={highlightScale("red")}
220
+ onDarkHighlight={highlightScale("redDark")}
221
+ onHighlightEnd={clearHighlight}
222
+ isAltPressed={isAltPressed}
223
+ />
224
+ <ScalePair
225
+ name="teal"
226
+ light={palette.teal}
227
+ dark={palette.tealDark}
228
+ showLight={showLight}
229
+ showDark={showDark}
230
+ onLightColorChange={(i, c) => updateScaleColor("teal", i, c)}
231
+ onDarkColorChange={(i, c) => updateScaleColor("tealDark", i, c)}
232
+ onLightHighlight={highlightScale("teal")}
233
+ onDarkHighlight={highlightScale("tealDark")}
234
+ onHighlightEnd={clearHighlight}
235
+ isAltPressed={isAltPressed}
236
+ />
237
+ <ScalePair
238
+ name="yellow"
239
+ light={palette.yellow}
240
+ dark={palette.yellowDark}
241
+ showLight={showLight}
242
+ showDark={showDark}
243
+ onLightColorChange={(i, c) => updateScaleColor("yellow", i, c)}
244
+ onDarkColorChange={(i, c) => updateScaleColor("yellowDark", i, c)}
245
+ onLightHighlight={highlightScale("yellow")}
246
+ onDarkHighlight={highlightScale("yellowDark")}
247
+ onHighlightEnd={clearHighlight}
248
+ isAltPressed={isAltPressed}
249
+ />
250
+
251
+ <Slider
252
+ label="contrast"
253
+ value={prefsPresent.contrast ?? 1}
254
+ min={0.7}
255
+ max={1.3}
256
+ step={0.01}
257
+ onChange={(v) => update({contrast: v})}
258
+ />
259
+
260
+ <div className={sectionSeparatorCss} />
261
+
262
+ <div className={sectionLabelCss}>lights & shades</div>
263
+ <div className={scaleCss}>
264
+ <div style={{border: "1px solid #888", borderRadius: 5}}>
265
+ <SwatchWithPicker
266
+ color={palette.white}
267
+ title={`white\n${toRGB(palette.white)}\n${toOKLCH(palette.white)}`}
268
+ onChange={(c) => updateScaleColor("white", 0, c)}
269
+ isAltPressed={isAltPressed}
270
+ />
271
+ </div>
272
+ <div style={{border: "1px solid #888", borderRadius: 5}}>
273
+ <SwatchWithPicker
274
+ color={palette.black}
275
+ title={`black\n${toRGB(palette.black)}\n${toOKLCH(palette.black)}`}
276
+ onChange={(c) => updateScaleColor("black", 0, c)}
277
+ isAltPressed={isAltPressed}
278
+ />
279
+ </div>
280
+ </div>
281
+
282
+ <ScaleRow
283
+ name="whiteA"
284
+ scale={palette.whiteA}
285
+ onColorChange={(i, c) => updateScaleColor("whiteA", i, c)}
286
+ onHighlight={highlightScale("whiteA")}
287
+ onHighlightEnd={clearHighlight}
288
+ isAltPressed={isAltPressed}
289
+ />
290
+ <Slider
291
+ label="L"
292
+ value={prefsPresent.whiteLuminosity ?? 1}
293
+ min={0.5}
294
+ max={1.5}
295
+ step={0.01}
296
+ onChange={(v) => update({whiteLuminosity: v})}
297
+ />
298
+ <Slider
299
+ label="C"
300
+ value={prefsPresent.whiteChroma ?? 1}
301
+ min={0}
302
+ max={3}
303
+ step={0.01}
304
+ onChange={(v) => update({whiteChroma: v})}
305
+ />
306
+
307
+ <ScaleRow
308
+ name="blackA"
309
+ scale={palette.blackA}
310
+ onColorChange={(i, c) => updateScaleColor("blackA", i, c)}
311
+ onHighlight={highlightScale("blackA")}
312
+ onHighlightEnd={clearHighlight}
313
+ isAltPressed={isAltPressed}
314
+ />
315
+ <Slider
316
+ label="L"
317
+ value={prefsPresent.blackLuminosity ?? 1}
318
+ min={0.5}
319
+ max={1.5}
320
+ step={0.01}
321
+ onChange={(v) => update({blackLuminosity: v})}
322
+ />
323
+ <Slider
324
+ label="C"
325
+ value={prefsPresent.blackChroma ?? 1}
326
+ min={0}
327
+ max={3}
328
+ step={0.01}
329
+ onChange={(v) => update({blackChroma: v})}
330
+ />
331
+
332
+ <div className={buttonsCss} style={{justifyContent: "space-between"}}>
333
+ <div style={{display: "flex", gap: space.s4}}>
334
+ <IconButton
335
+ size="small"
336
+ variant="ghost"
337
+ color="neutral"
338
+ onClick={() => setCollapsed(true)}
339
+ title="Collapse"
340
+ >
341
+ <CollapseAll />
342
+ </IconButton>
343
+ {isAltPressed ? (
344
+ <IconButton
345
+ size="small"
346
+ variant={staticPalette ? "solid" : "soft"}
347
+ color="error"
348
+ onClick={cycleStaticPalettes}
349
+ title="Beware"
350
+ >
351
+ <Lab />
352
+ </IconButton>
353
+ ) : (
354
+ <IconButton size="small" variant="soft" color="accent" onClick={randomize} title="Shuffle">
355
+ <Refresh />
356
+ </IconButton>
357
+ )}
358
+ <IconButton size="small" variant="ghost" color="neutral" onClick={handleExport} title="Export">
359
+ <FileDownload />
360
+ </IconButton>
361
+ <IconButton size="small" variant="ghost" color="neutral" onClick={handleImport} title="Import">
362
+ <FileUpload />
363
+ </IconButton>
364
+ {isModified && (
365
+ <IconButton size="small" variant="ghost" color="neutral" onClick={reset} title="Defaults">
366
+ <Restore />
367
+ </IconButton>
368
+ )}
369
+ </div>
370
+ <IconButton
371
+ size="small"
372
+ variant="ghost"
373
+ color="neutral"
374
+ onClick={cycleTheme}
375
+ title={isAltPressed ? "auto" : themePref}
376
+ >
377
+ {themeIcons[isAltPressed ? "auto" : themePref]}
378
+ </IconButton>
379
+ </div>
380
+ </>
381
+ )}
382
+ </div>
383
+ );
384
+
385
+ return createPortal(<ThemeProvider portal>{panel}</ThemeProvider>, document.body);
386
+ }