@noya-app/noya-designsystem 0.0.2

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 (73) hide show
  1. package/.turbo/turbo-build.log +17 -0
  2. package/CHANGELOG.md +7 -0
  3. package/README.md +1 -0
  4. package/dist/index.d.mts +1178 -0
  5. package/dist/index.d.ts +1178 -0
  6. package/dist/index.js +15651 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.mjs +15684 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/package.json +49 -0
  11. package/src/__tests__/__snapshots__/fuzzyScorer.test.ts.snap +41 -0
  12. package/src/__tests__/fuzzyScorer.test.ts +85 -0
  13. package/src/components/ActivityIndicator.tsx +44 -0
  14. package/src/components/Avatar.tsx +64 -0
  15. package/src/components/Button.tsx +209 -0
  16. package/src/components/Chip.tsx +214 -0
  17. package/src/components/ContextMenu.tsx +224 -0
  18. package/src/components/Dialog.tsx +143 -0
  19. package/src/components/Divider.tsx +40 -0
  20. package/src/components/DropdownMenu.tsx +208 -0
  21. package/src/components/FillInputField.tsx +43 -0
  22. package/src/components/FillPreviewBackground.tsx +132 -0
  23. package/src/components/GradientPicker.tsx +88 -0
  24. package/src/components/Grid.tsx +54 -0
  25. package/src/components/GridView.tsx +468 -0
  26. package/src/components/IconButton.tsx +46 -0
  27. package/src/components/InputField.tsx +568 -0
  28. package/src/components/InputFieldWithCompletions.tsx +477 -0
  29. package/src/components/Label.tsx +62 -0
  30. package/src/components/LabeledElementView.tsx +185 -0
  31. package/src/components/ListView.tsx +950 -0
  32. package/src/components/Popover.tsx +113 -0
  33. package/src/components/Progress.tsx +57 -0
  34. package/src/components/RadioGroup.tsx +163 -0
  35. package/src/components/ScrollArea.tsx +70 -0
  36. package/src/components/Select.tsx +152 -0
  37. package/src/components/Slider.tsx +82 -0
  38. package/src/components/Sortable.tsx +296 -0
  39. package/src/components/Spacer.tsx +29 -0
  40. package/src/components/Stack.tsx +142 -0
  41. package/src/components/Switch.tsx +67 -0
  42. package/src/components/Text.tsx +164 -0
  43. package/src/components/Toast.tsx +86 -0
  44. package/src/components/Tooltip.tsx +43 -0
  45. package/src/components/TreeView.tsx +85 -0
  46. package/src/components/internal/Menu.tsx +222 -0
  47. package/src/components/internal/TextInput.tsx +296 -0
  48. package/src/components/internal/__tests__/TextInput.test.tsx +144 -0
  49. package/src/contexts/DesignSystemConfiguration.tsx +57 -0
  50. package/src/contexts/DialogContext.tsx +190 -0
  51. package/src/contexts/GlobalInputBlurContext.tsx +61 -0
  52. package/src/contexts/ImageDataContext.tsx +44 -0
  53. package/src/hooks/__tests__/mergeEventHandlers.test.ts +47 -0
  54. package/src/hooks/mergeEventHandlers.ts +55 -0
  55. package/src/hooks/useHover.ts +173 -0
  56. package/src/hooks/useObjectURL.ts +22 -0
  57. package/src/hooks/usePlatform.ts +13 -0
  58. package/src/index.tsx +77 -0
  59. package/src/mediaQuery.ts +13 -0
  60. package/src/theme/dark.ts +37 -0
  61. package/src/theme/index.ts +17 -0
  62. package/src/theme/light.ts +178 -0
  63. package/src/utils/breakpoints.ts +45 -0
  64. package/src/utils/completions.ts +21 -0
  65. package/src/utils/createSectionedMenu.ts +38 -0
  66. package/src/utils/fuzzyScorer.ts +105 -0
  67. package/src/utils/getGradientBackground.tsx +33 -0
  68. package/src/utils/handleNudge.ts +30 -0
  69. package/src/utils/mouseEvent.ts +7 -0
  70. package/src/utils/sketchColor.ts +34 -0
  71. package/src/utils/sketchPattern.ts +29 -0
  72. package/src/utils/withSeparatorElements.ts +31 -0
  73. package/tsconfig.json +3 -0
@@ -0,0 +1,568 @@
1
+ import { CaretDownIcon } from '@noya-app/noya-icons';
2
+ import { memoize } from '@noya-app/noya-utils';
3
+ import { Property } from 'csstype';
4
+ import React, {
5
+ Children,
6
+ createContext,
7
+ ForwardedRef,
8
+ forwardRef,
9
+ isValidElement,
10
+ memo,
11
+ ReactNode,
12
+ useCallback,
13
+ useContext,
14
+ useEffect,
15
+ useLayoutEffect,
16
+ useMemo,
17
+ } from 'react';
18
+ import styled from 'styled-components';
19
+ import handleNudge from '../utils/handleNudge';
20
+ import { Button } from './Button';
21
+ import { DropdownMenu } from './DropdownMenu';
22
+ import { MenuItem } from './internal/Menu';
23
+ import TextInput, { TextInputProps } from './internal/TextInput';
24
+ import { Popover } from './Popover';
25
+ import { Stack } from './Stack';
26
+
27
+ type LabelPosition = 'start' | 'end';
28
+
29
+ export type InputFieldSize = 'small' | 'medium' | 'large';
30
+
31
+ type InputFieldContextValue = {
32
+ labelPosition: LabelPosition;
33
+ labelSize: number;
34
+ hasLabel: boolean;
35
+ hasDropdown: boolean;
36
+ size: InputFieldSize;
37
+ isFocused: boolean;
38
+ onFocusChange: (isFocused: boolean) => void;
39
+ inputRef?: ForwardedRef<HTMLInputElement>;
40
+ setInputRef?: (ref: ForwardedRef<HTMLInputElement>) => void;
41
+ };
42
+
43
+ const InputFieldContext = createContext<InputFieldContextValue>({
44
+ labelPosition: 'end',
45
+ labelSize: 6,
46
+ hasLabel: false,
47
+ hasDropdown: false,
48
+ size: 'medium',
49
+ isFocused: false,
50
+ onFocusChange: () => {},
51
+ });
52
+
53
+ /* ----------------------------------------------------------------------------
54
+ * Label
55
+ * ------------------------------------------------------------------------- */
56
+
57
+ const LabelContainer = styled.label<{
58
+ pointerEvents: Property.PointerEvents;
59
+ labelPosition: LabelPosition;
60
+ hasDropdown: boolean;
61
+ }>(({ theme, labelPosition, hasDropdown, pointerEvents }) => ({
62
+ color: theme.colors.textDisabled,
63
+ position: 'absolute',
64
+ top: 0,
65
+ right: labelPosition === 'end' ? 0 : undefined,
66
+ bottom: 0,
67
+ left: labelPosition === 'start' ? 0 : undefined,
68
+ display: 'flex',
69
+ alignItems: 'center',
70
+ pointerEvents,
71
+ fontWeight: 'bold',
72
+ fontSize: '60%',
73
+ userSelect: 'none',
74
+ ...(labelPosition === 'start'
75
+ ? { justifyContent: 'flex-start', paddingLeft: '6px' }
76
+ : {
77
+ justifyContent: 'flex-end',
78
+ paddingRight: hasDropdown ? '16px' : '6px',
79
+ }),
80
+ }));
81
+
82
+ interface InputFieldLabelProps {
83
+ children?: ReactNode;
84
+ pointerEvents?: Property.PointerEvents;
85
+ }
86
+
87
+ const InputFieldLabel = memo(function InputFieldLabel({
88
+ children = false,
89
+ pointerEvents = 'none',
90
+ }: InputFieldLabelProps) {
91
+ const { labelPosition, hasDropdown } = useContext(InputFieldContext);
92
+
93
+ return (
94
+ <LabelContainer
95
+ pointerEvents={pointerEvents}
96
+ labelPosition={labelPosition}
97
+ hasDropdown={hasDropdown}
98
+ >
99
+ {children}
100
+ </LabelContainer>
101
+ );
102
+ });
103
+
104
+ /* ----------------------------------------------------------------------------
105
+ * Dropdown
106
+ * ------------------------------------------------------------------------- */
107
+
108
+ const DropdownContainer = styled.span(({ theme }) => ({
109
+ position: 'absolute',
110
+ top: 0,
111
+ right: 0,
112
+ bottom: 0,
113
+ display: 'flex',
114
+ flexDirection: 'column',
115
+ }));
116
+
117
+ interface InputFieldDropdownProps<T extends string> {
118
+ id?: string;
119
+ items: MenuItem<T>[];
120
+ onSelect: (value: T) => void;
121
+ children?: ReactNode;
122
+ }
123
+
124
+ const InputFieldDropdownMenu = memo(function InputFieldDropdownMenu<
125
+ T extends string,
126
+ >({ id, items, onSelect, children }: InputFieldDropdownProps<T>) {
127
+ const { size } = useContext(InputFieldContext);
128
+
129
+ const contentStyle = useMemo(
130
+ () => ({
131
+ margin: '-4px 0',
132
+ minHeight: size === 'small' ? '15px' : undefined,
133
+ }),
134
+ [size],
135
+ );
136
+
137
+ return (
138
+ <DropdownContainer>
139
+ <DropdownMenu<T> items={items} onSelect={onSelect}>
140
+ {children || (
141
+ <Button id={id} variant="thin" flex="1" contentStyle={contentStyle}>
142
+ <CaretDownIcon />
143
+ </Button>
144
+ )}
145
+ </DropdownMenu>
146
+ </DropdownContainer>
147
+ );
148
+ });
149
+
150
+ /* ----------------------------------------------------------------------------
151
+ * Button
152
+ * ------------------------------------------------------------------------- */
153
+
154
+ const ButtonContainer = styled.span<{ size: InputFieldSize }>(
155
+ ({ theme, size }) => ({
156
+ position: 'absolute',
157
+ right: size === 'large' ? '9px' : size === 'medium' ? '4px' : '2px',
158
+ top: size === 'large' ? '8px' : size === 'medium' ? '4px' : '2px',
159
+ }),
160
+ );
161
+
162
+ const InputFieldButton = memo(function InputFieldButton({
163
+ children,
164
+ onClick,
165
+ }: {
166
+ children?: ReactNode;
167
+ onClick?: () => void;
168
+ }) {
169
+ const { size, inputRef } = useContext(InputFieldContext);
170
+
171
+ const defaultHandleClick = useCallback(
172
+ (event: React.MouseEvent) => {
173
+ if (inputRef && typeof inputRef !== 'function') {
174
+ inputRef.current?.focus();
175
+ // Select all text
176
+ inputRef.current?.setSelectionRange(0, inputRef.current.value.length);
177
+ }
178
+
179
+ event.preventDefault();
180
+ event.stopPropagation();
181
+ },
182
+ [inputRef],
183
+ );
184
+
185
+ const handlePointerDown = useCallback((event: React.PointerEvent) => {
186
+ event.preventDefault();
187
+ event.stopPropagation();
188
+ }, []);
189
+
190
+ return (
191
+ <ButtonContainer size={size}>
192
+ <Button
193
+ variant="floating"
194
+ onClick={onClick ?? defaultHandleClick}
195
+ onPointerDown={handlePointerDown}
196
+ tabIndex={-1}
197
+ >
198
+ {children}
199
+ </Button>
200
+ </ButtonContainer>
201
+ );
202
+ });
203
+
204
+ /* ----------------------------------------------------------------------------
205
+ * Input
206
+ * ------------------------------------------------------------------------- */
207
+
208
+ const createCrossSVGString = memoize(
209
+ (color: string) =>
210
+ `<svg width='15' height='15' viewBox='0 0 15 15' fill='${color}' xmlns='http://www.w3.org/2000/svg'>
211
+ <path d='M0.877075 7.49988C0.877075 3.84219 3.84222 0.877045 7.49991 0.877045C11.1576 0.877045 14.1227 3.84219 14.1227 7.49988C14.1227 11.1575 11.1576 14.1227 7.49991 14.1227C3.84222 14.1227 0.877075 11.1575 0.877075 7.49988ZM7.49991 1.82704C4.36689 1.82704 1.82708 4.36686 1.82708 7.49988C1.82708 10.6329 4.36689 13.1727 7.49991 13.1727C10.6329 13.1727 13.1727 10.6329 13.1727 7.49988C13.1727 4.36686 10.6329 1.82704 7.49991 1.82704ZM9.85358 5.14644C10.0488 5.3417 10.0488 5.65829 9.85358 5.85355L8.20713 7.49999L9.85358 9.14644C10.0488 9.3417 10.0488 9.65829 9.85358 9.85355C9.65832 10.0488 9.34173 10.0488 9.14647 9.85355L7.50002 8.2071L5.85358 9.85355C5.65832 10.0488 5.34173 10.0488 5.14647 9.85355C4.95121 9.65829 4.95121 9.3417 5.14647 9.14644L6.79292 7.49999L5.14647 5.85355C4.95121 5.65829 4.95121 5.3417 5.14647 5.14644C5.34173 4.95118 5.65832 4.95118 5.85358 5.14644L7.50002 6.79289L9.14647 5.14644C9.34173 4.95118 9.65832 4.95118 9.85358 5.14644Z' fill-rule='evenodd' clip-rule='evenodd'></path>
212
+ </svg>`,
213
+ );
214
+
215
+ type InputFieldVariant = 'normal' | 'bare';
216
+
217
+ const ignoredProps = new Set([
218
+ 'labelPosition',
219
+ 'labelSize',
220
+ 'hasLabel',
221
+ 'hasDropdown',
222
+ 'textAlign',
223
+ 'variant',
224
+ 'onNudge',
225
+ ]);
226
+
227
+ export const InputElement = styled(TextInput).withConfig({
228
+ shouldForwardProp: (prop) => (ignoredProps.has(prop) ? false : true),
229
+ })<{
230
+ labelPosition: LabelPosition;
231
+ labelSize: number;
232
+ hasLabel: boolean;
233
+ hasDropdown: boolean;
234
+ textAlign?: Property.TextAlign;
235
+ disabled?: boolean;
236
+ variant?: InputFieldVariant;
237
+ readOnly?: boolean;
238
+ size: InputFieldSize;
239
+ }>(
240
+ ({
241
+ theme,
242
+ labelPosition,
243
+ labelSize,
244
+ hasDropdown,
245
+ textAlign,
246
+ disabled,
247
+ hasLabel,
248
+ readOnly,
249
+ variant = 'normal',
250
+ size,
251
+ }) => ({
252
+ // placeholder
253
+ '&::placeholder': {
254
+ color: theme.colors.textDisabled,
255
+ },
256
+ ...theme.textStyles.small,
257
+ color: readOnly
258
+ ? theme.colors.textMuted
259
+ : disabled
260
+ ? theme.colors.textDisabled
261
+ : theme.colors.text,
262
+ ...(size === 'small' && {
263
+ fontSize: '11px',
264
+ }),
265
+ width: '0px', // Reset intrinsic width
266
+ flex: '1 1 0px',
267
+ position: 'relative',
268
+ border: '0',
269
+ outline: 'none',
270
+ minWidth: '0',
271
+ textAlign: textAlign ?? 'left',
272
+ alignSelf: 'stretch',
273
+ borderRadius: '4px',
274
+ paddingTop: size === 'large' ? '10px' : size === 'medium' ? '4px' : '1px',
275
+ paddingBottom:
276
+ size === 'large' ? '10px' : size === 'medium' ? '4px' : '1px',
277
+ paddingLeft:
278
+ (size === 'large' ? 10 : size === 'medium' ? 6 : 4) +
279
+ (hasLabel && labelPosition === 'start' ? 6 + labelSize : 0) +
280
+ 'px',
281
+ paddingRight:
282
+ (size === 'large' ? 10 : size === 'medium' ? 6 : 4) +
283
+ (hasLabel && labelPosition === 'end' ? 6 + labelSize : 0) +
284
+ (hasDropdown ? 11 : 0) +
285
+ 'px',
286
+ background: theme.colors.inputBackground,
287
+ '&:focus': {
288
+ boxShadow: `0 0 0 2px ${theme.colors.primary}`,
289
+ },
290
+ ...(variant === 'bare' && {
291
+ paddingTop: '4px',
292
+ paddingRight: '4px',
293
+ paddingBottom: '4px',
294
+ paddingLeft: '4px',
295
+ marginTop: '-4px',
296
+ marginRight: '-4px',
297
+ marginBottom: '-4px',
298
+ marginLeft: '-4px',
299
+ }),
300
+
301
+ '&[type="search"]::-webkit-search-cancel-button': {
302
+ appearance: 'none',
303
+ height: '15px',
304
+ width: '15px',
305
+ background: `url("data:image/svg+xml;utf8,${createCrossSVGString(
306
+ theme.colors.icon,
307
+ )}") no-repeat`,
308
+ },
309
+ }),
310
+ );
311
+
312
+ const InputFieldInput = forwardRef(function InputFieldInput(
313
+ // onFocusChange should only be passed from the root, never directly
314
+ props: TextInputProps & {
315
+ textAlign?: Property.TextAlign;
316
+ variant?: 'bare';
317
+ },
318
+ forwardedRef: ForwardedRef<HTMLInputElement>,
319
+ ) {
320
+ const {
321
+ labelPosition,
322
+ labelSize,
323
+ hasDropdown,
324
+ hasLabel,
325
+ size,
326
+ onFocusChange,
327
+ setInputRef,
328
+ } = useContext(InputFieldContext);
329
+
330
+ const handleFocusChange = useCallback(
331
+ (isFocused: boolean) => {
332
+ onFocusChange(isFocused);
333
+ },
334
+ [onFocusChange],
335
+ );
336
+
337
+ useLayoutEffect(() => {
338
+ setInputRef?.(forwardedRef);
339
+ }, [forwardedRef, setInputRef]);
340
+
341
+ return (
342
+ <InputElement
343
+ ref={forwardedRef}
344
+ labelPosition={labelPosition}
345
+ labelSize={labelSize}
346
+ hasLabel={hasLabel}
347
+ hasDropdown={hasDropdown}
348
+ size={size}
349
+ onFocusChange={handleFocusChange}
350
+ {...props}
351
+ />
352
+ );
353
+ });
354
+
355
+ /* ----------------------------------------------------------------------------
356
+ * NumberInput
357
+ * ------------------------------------------------------------------------- */
358
+
359
+ type InputFieldNumberInputProps = Omit<
360
+ TextInputProps,
361
+ 'value' | 'onChange' | 'onKeyDown' | 'onSubmit'
362
+ > & {
363
+ value: number | undefined;
364
+ onNudge?: (value: number) => void;
365
+ variant?: 'bare';
366
+ } & (
367
+ | {
368
+ onChange: (value: number) => void;
369
+ }
370
+ | {
371
+ onSubmit: (value: number) => void;
372
+ }
373
+ );
374
+
375
+ function parseNumber(value: string) {
376
+ return value ? Number(value) : NaN;
377
+ }
378
+
379
+ function InputFieldNumberInput(props: InputFieldNumberInputProps) {
380
+ const { value, placeholder, onNudge } = props;
381
+ const onSubmit = 'onSubmit' in props ? props.onSubmit : undefined;
382
+ const onChange = 'onChange' in props ? props.onChange : undefined;
383
+
384
+ const handleSubmit = useCallback(
385
+ (value: string) => {
386
+ const newValue = parseNumber(value);
387
+
388
+ if (!isNaN(newValue)) {
389
+ onSubmit?.(newValue);
390
+ }
391
+ },
392
+ [onSubmit],
393
+ );
394
+
395
+ const handleKeyDown = useCallback(
396
+ (event: React.KeyboardEvent<HTMLInputElement>) => {
397
+ const amount = handleNudge(event);
398
+
399
+ if (!amount) return;
400
+
401
+ onNudge?.(amount);
402
+
403
+ event.preventDefault();
404
+ event.stopPropagation();
405
+ },
406
+ [onNudge],
407
+ );
408
+
409
+ const handleChange = useCallback(
410
+ (value: string) => {
411
+ onChange?.(parseNumber(value));
412
+ },
413
+ [onChange],
414
+ );
415
+
416
+ return (
417
+ <InputFieldInput
418
+ {...props}
419
+ value={value === undefined ? '' : String(value)}
420
+ placeholder={placeholder}
421
+ onKeyDown={handleKeyDown}
422
+ {...('onChange' in props
423
+ ? { onChange: handleChange }
424
+ : { onSubmit: handleSubmit })}
425
+ />
426
+ );
427
+ }
428
+
429
+ /* ----------------------------------------------------------------------------
430
+ * Root
431
+ * ------------------------------------------------------------------------- */
432
+
433
+ const RootContainer = styled.div<{ width?: number; flex?: string }>(
434
+ ({ theme, flex, width }) => ({
435
+ flex: flex ?? '1',
436
+ display: 'flex',
437
+ flexDirection: 'row',
438
+ position: 'relative',
439
+ maxWidth: typeof width === 'number' ? `${width}px` : undefined,
440
+ }),
441
+ );
442
+
443
+ interface InputFieldRootProps {
444
+ id?: string;
445
+ flex?: string;
446
+ children?: ReactNode;
447
+ width?: number;
448
+ labelPosition?: LabelPosition;
449
+ labelSize?: number;
450
+ hasDropdown?: boolean;
451
+ size?: InputFieldSize;
452
+ renderPopoverContent?: (options: { width: number }) => ReactNode;
453
+ onFocusChange?: (isFocused: boolean) => void;
454
+ }
455
+
456
+ function InputFieldRoot({
457
+ id,
458
+ flex,
459
+ children,
460
+ width,
461
+ labelPosition = 'end',
462
+ labelSize = 6,
463
+ size = 'medium',
464
+ renderPopoverContent,
465
+ onFocusChange,
466
+ }: InputFieldRootProps) {
467
+ const childrenArray = Children.toArray(children);
468
+
469
+ const hasDropdown = childrenArray.some(
470
+ (child) => isValidElement(child) && child.type === InputFieldDropdownMenu,
471
+ );
472
+ const hasLabel = childrenArray.some(
473
+ (child) => isValidElement(child) && child.type === InputFieldLabel,
474
+ );
475
+
476
+ const [isFocused, setIsFocused] = React.useState(false);
477
+
478
+ const [measuredWidth, setMeasuredWidth] = React.useState<number>();
479
+
480
+ const handleFocusChange = useCallback(
481
+ (isFocused: boolean) => {
482
+ setIsFocused(isFocused);
483
+ onFocusChange?.(isFocused);
484
+ },
485
+ [onFocusChange],
486
+ );
487
+
488
+ const [inputRef, setInputRef] =
489
+ React.useState<ForwardedRef<HTMLInputElement>>();
490
+
491
+ useEffect(() => {
492
+ if (inputRef && typeof inputRef !== 'function') {
493
+ setMeasuredWidth?.(
494
+ isFocused
495
+ ? inputRef?.current?.getBoundingClientRect().width
496
+ : undefined,
497
+ );
498
+ }
499
+ }, [inputRef, isFocused]);
500
+
501
+ const contextValue = useMemo(
502
+ (): InputFieldContextValue => ({
503
+ labelPosition,
504
+ labelSize,
505
+ hasDropdown,
506
+ hasLabel,
507
+ size,
508
+ isFocused,
509
+ onFocusChange: handleFocusChange,
510
+ inputRef,
511
+ setInputRef,
512
+ }),
513
+ [
514
+ labelPosition,
515
+ labelSize,
516
+ hasDropdown,
517
+ hasLabel,
518
+ size,
519
+ isFocused,
520
+ handleFocusChange,
521
+ inputRef,
522
+ ],
523
+ );
524
+
525
+ const rootElement = (
526
+ <RootContainer id={id} width={width} flex={flex}>
527
+ {children}
528
+ </RootContainer>
529
+ );
530
+
531
+ return (
532
+ <InputFieldContext.Provider value={contextValue}>
533
+ {renderPopoverContent ? (
534
+ <Popover
535
+ open={true}
536
+ trigger={rootElement}
537
+ sideOffset={3}
538
+ showArrow={false}
539
+ onOpenAutoFocus={(event) => {
540
+ event.preventDefault();
541
+ event.stopPropagation();
542
+ }}
543
+ onCloseAutoFocus={(event) => {
544
+ event.preventDefault();
545
+ event.stopPropagation();
546
+ }}
547
+ >
548
+ {measuredWidth && (
549
+ <Stack.V width={measuredWidth} overflow="hidden">
550
+ {renderPopoverContent({ width: measuredWidth })}
551
+ </Stack.V>
552
+ )}
553
+ </Popover>
554
+ ) : (
555
+ rootElement
556
+ )}
557
+ </InputFieldContext.Provider>
558
+ );
559
+ }
560
+
561
+ export namespace InputField {
562
+ export const Root = memo(InputFieldRoot);
563
+ export const Input = memo(InputFieldInput);
564
+ export const NumberInput = memo(InputFieldNumberInput);
565
+ export const DropdownMenu = InputFieldDropdownMenu;
566
+ export const Button = InputFieldButton;
567
+ export const Label = InputFieldLabel;
568
+ }