@noya-app/noya-designsystem 0.1.30 → 0.1.32

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 (64) hide show
  1. package/.turbo/turbo-build.log +20 -12
  2. package/.turbo/turbo-lint.log +15 -1
  3. package/CHANGELOG.md +17 -0
  4. package/README.md +13 -1
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +238 -627
  7. package/dist/index.js +4259 -2862
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +4159 -2764
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +17 -7
  12. package/src/components/ActivityIndicator.tsx +4 -36
  13. package/src/components/Avatar.tsx +63 -62
  14. package/src/components/Button.tsx +53 -170
  15. package/src/components/Chip.tsx +117 -150
  16. package/src/components/ContextMenu.tsx +13 -35
  17. package/src/components/Dialog.tsx +66 -54
  18. package/src/components/Divider.tsx +31 -41
  19. package/src/components/DraggableMenuButton.tsx +29 -30
  20. package/src/components/DropdownMenu.tsx +30 -40
  21. package/src/components/FillInputField.tsx +16 -26
  22. package/src/components/FillPreviewBackground.tsx +18 -22
  23. package/src/components/FloatingWindow.tsx +4 -7
  24. package/src/components/GridView.tsx +70 -200
  25. package/src/components/IconButton.tsx +1 -5
  26. package/src/components/InputField.tsx +258 -234
  27. package/src/components/InputFieldWithCompletions.tsx +20 -27
  28. package/src/components/InspectorContainer.tsx +4 -9
  29. package/src/components/InspectorPrimitives.tsx +135 -109
  30. package/src/components/Label.tsx +5 -36
  31. package/src/components/LabeledElementView.tsx +5 -26
  32. package/src/components/ListView.tsx +239 -167
  33. package/src/components/Popover.tsx +15 -39
  34. package/src/components/Progress.tsx +21 -44
  35. package/src/components/RadioGroup.tsx +6 -71
  36. package/src/components/ScrollArea.tsx +11 -39
  37. package/src/components/SelectMenu.tsx +72 -32
  38. package/src/components/Slider.tsx +7 -43
  39. package/src/components/Spacer.tsx +6 -18
  40. package/src/components/Switch.tsx +4 -42
  41. package/src/components/Text.tsx +31 -66
  42. package/src/components/TextArea.tsx +5 -31
  43. package/src/components/Toast.tsx +15 -57
  44. package/src/components/Tooltip.tsx +4 -13
  45. package/src/components/WorkspaceLayout.tsx +27 -17
  46. package/src/components/internal/Menu.tsx +37 -83
  47. package/src/contexts/DesignSystemConfiguration.tsx +1 -47
  48. package/src/contexts/DialogContext.tsx +2 -10
  49. package/src/hooks/useDarkMode.ts +14 -0
  50. package/src/index.css +108 -0
  51. package/src/index.tsx +4 -5
  52. package/src/theme/index.ts +4 -16
  53. package/src/utils/tailwind.ts +17 -0
  54. package/tailwind.config.ts +223 -0
  55. package/tailwind.d.ts +11 -0
  56. package/tsconfig.json +4 -1
  57. package/tsup.config.ts +16 -0
  58. package/dist/index.d.mts +0 -1455
  59. package/src/components/Grid.tsx +0 -54
  60. package/src/components/Select.tsx +0 -183
  61. package/src/components/Stack.tsx +0 -155
  62. package/src/theme/dark.ts +0 -45
  63. package/src/theme/light.ts +0 -226
  64. package/src/utils/breakpoints.ts +0 -45
@@ -17,14 +17,12 @@ import React, {
17
17
  useRef,
18
18
  useState,
19
19
  } from "react";
20
- import styled from "styled-components";
21
20
  import handleNudge from "../utils/handleNudge";
22
21
  import { Button } from "./Button";
23
22
  import { DropdownMenu } from "./DropdownMenu";
24
23
  import { MenuItem } from "./internal/Menu";
25
24
  import TextInput, { TextInputProps } from "./internal/TextInput";
26
25
  import { Popover } from "./Popover";
27
- import { Stack } from "./Stack";
28
26
 
29
27
  type LabelPosition = "start" | "end";
30
28
 
@@ -32,8 +30,8 @@ export type InputFieldSize = "small" | "medium" | "large";
32
30
 
33
31
  type InputFieldContextValue = {
34
32
  labelPosition: LabelPosition;
35
- labelSize: number;
36
- hasLabel: boolean;
33
+ labelSize?: number;
34
+ buttonSize?: number;
37
35
  hasDropdown: boolean;
38
36
  /** @default medium */
39
37
  size: InputFieldSize;
@@ -42,12 +40,13 @@ type InputFieldContextValue = {
42
40
  inputRef?: ForwardedRef<HTMLInputElement>;
43
41
  setInputRef?: (ref: ForwardedRef<HTMLInputElement>) => void;
44
42
  setLabelWidth?: (width: number) => void;
43
+ setButtonWidth?: (width: number) => void;
45
44
  };
46
45
 
47
46
  const InputFieldContext = createContext<InputFieldContextValue>({
48
47
  labelPosition: "end",
49
- labelSize: 6,
50
- hasLabel: false,
48
+ labelSize: undefined,
49
+ buttonSize: undefined,
51
50
  hasDropdown: false,
52
51
  size: "medium",
53
52
  isFocused: false,
@@ -58,43 +57,63 @@ const InputFieldContext = createContext<InputFieldContextValue>({
58
57
  * Label
59
58
  * ------------------------------------------------------------------------- */
60
59
 
61
- const LabelContainer = styled.label<{
62
- pointerEvents: Property.PointerEvents;
63
- $labelPosition: LabelPosition;
64
- $hasDropdown: boolean;
65
- }>(({ theme, $labelPosition, $hasDropdown, pointerEvents }) => ({
66
- ...theme.textStyles.label,
67
- fontWeight: "bold",
68
- color: theme.colors.textDisabled,
69
- position: "absolute",
70
- top: 0,
71
- right: $labelPosition === "end" ? 0 : undefined,
72
- bottom: 0,
73
- left: $labelPosition === "start" ? 0 : undefined,
74
- display: "flex",
75
- alignItems: "center",
76
- pointerEvents,
77
- userSelect: "none",
78
- ...($labelPosition === "start"
79
- ? { justifyContent: "flex-start", paddingLeft: "6px" }
80
- : {
81
- justifyContent: "flex-end",
82
- paddingRight: $hasDropdown ? "16px" : "6px",
83
- }),
84
- }));
60
+ const LabelContainer = forwardRef<
61
+ HTMLLabelElement,
62
+ {
63
+ pointerEvents: Property.PointerEvents;
64
+ $labelPosition: LabelPosition;
65
+ $hasDropdown: boolean;
66
+ $size: InputFieldSize;
67
+ className?: string;
68
+ children?: React.ReactNode;
69
+ style?: React.CSSProperties;
70
+ }
71
+ >(
72
+ (
73
+ { pointerEvents, $labelPosition, $hasDropdown, $size, className, style, ...props },
74
+ ref
75
+ ) => {
76
+ const memoizedStyles = useMemo(() => ({
77
+ left: $labelPosition === "start" ? $size === "large" ? "6px" : $size === "medium" ? "2px" : "0px" : "",
78
+ right: $labelPosition === "end" ? $size === "large" ? "6px" : $size === "medium" ? "2px" : "0px" : "",
79
+ }), [$labelPosition, $size])
80
+
81
+ return (
82
+ <label
83
+ ref={ref}
84
+ className={`absolute top-0 bottom-0 flex items-center font-sans text-label font-bold uppercase text-text-disabled select-none ${
85
+ $labelPosition === "start"
86
+ ? `justify-start pl-[6px]`
87
+ : $labelPosition === "end"
88
+ ? `justify-end ${$hasDropdown ? "pr-[16px]" : "pr-[6px]"}`
89
+ : ""
90
+ } ${pointerEvents === "none" ? "pointer-events-none" : ""} ${className ?? ""}`}
91
+ style={{...memoizedStyles, ...style}}
92
+ {...props}
93
+ />
94
+ );
95
+ }
96
+ );
85
97
 
86
98
  interface InputFieldLabelProps {
87
99
  children?: ReactNode;
88
100
  pointerEvents?: Property.PointerEvents;
89
101
  style?: React.CSSProperties;
102
+ className?: string;
90
103
  }
91
104
 
105
+ /** Inserts a Label at the start or end of the input given a `labelPosition`on InputField.Root. Should not be used with an InputField.Button */
92
106
  const InputFieldLabel = memo(
93
107
  forwardRef(function InputFieldLabel(
94
- { children = false, pointerEvents = "none", style }: InputFieldLabelProps,
108
+ {
109
+ children = false,
110
+ pointerEvents = "none",
111
+ style,
112
+ className,
113
+ }: InputFieldLabelProps,
95
114
  forwardedRef: ForwardedRef<HTMLLabelElement>
96
115
  ) {
97
- const { labelPosition, hasDropdown, setLabelWidth } =
116
+ const { labelPosition, hasDropdown, setLabelWidth, size } =
98
117
  useContext(InputFieldContext);
99
118
 
100
119
  const ref = useRef<HTMLLabelElement | null>(null);
@@ -111,6 +130,7 @@ const InputFieldLabel = memo(
111
130
 
112
131
  return (
113
132
  <LabelContainer
133
+ $size={size}
114
134
  ref={(element) => {
115
135
  ref.current = element;
116
136
  assignRef(forwardedRef, element);
@@ -119,6 +139,7 @@ const InputFieldLabel = memo(
119
139
  $labelPosition={labelPosition}
120
140
  $hasDropdown={hasDropdown}
121
141
  style={style}
142
+ className={className}
122
143
  >
123
144
  {children}
124
145
  </LabelContainer>
@@ -130,14 +151,16 @@ const InputFieldLabel = memo(
130
151
  * Dropdown
131
152
  * ------------------------------------------------------------------------- */
132
153
 
133
- const DropdownContainer = styled.span(({ theme }) => ({
134
- position: "absolute",
135
- top: 0,
136
- right: 0,
137
- bottom: 0,
138
- display: "flex",
139
- flexDirection: "column",
140
- }));
154
+ const DropdownContainer = forwardRef<
155
+ HTMLSpanElement,
156
+ { className?: string; children?: React.ReactNode }
157
+ >(({ className, ...props }, ref) => (
158
+ <span
159
+ ref={ref}
160
+ className={`absolute inset-y-0 right-0 flex flex-col ${className ?? ""}`}
161
+ {...props}
162
+ />
163
+ ));
141
164
 
142
165
  interface InputFieldDropdownProps<T extends string> {
143
166
  id?: string;
@@ -163,7 +186,12 @@ const InputFieldDropdownMenu = memo(function InputFieldDropdownMenu<
163
186
  <DropdownContainer>
164
187
  <DropdownMenu<T> items={items} onSelect={onSelect}>
165
188
  {children || (
166
- <Button id={id} variant="thin" flex="1" contentStyle={contentStyle}>
189
+ <Button
190
+ id={id}
191
+ variant="thin"
192
+ className="flex flex-1"
193
+ contentStyle={contentStyle}
194
+ >
167
195
  <CaretDownIcon />
168
196
  </Button>
169
197
  )}
@@ -176,55 +204,82 @@ const InputFieldDropdownMenu = memo(function InputFieldDropdownMenu<
176
204
  * Button
177
205
  * ------------------------------------------------------------------------- */
178
206
 
179
- const ButtonContainer = styled.span<{ $size: InputFieldSize }>(
180
- ({ theme, $size }) => ({
181
- position: "absolute",
182
- right: $size === "large" ? "9px" : $size === "medium" ? "4px" : "2px",
183
- top: $size === "large" ? "8px" : $size === "medium" ? "4px" : "2px",
184
- })
185
- );
207
+ const ButtonContainer = forwardRef<
208
+ HTMLSpanElement,
209
+ { $size: InputFieldSize; className?: string; children?: React.ReactNode }
210
+ >(({ $size, className, ...props }, ref) => (
211
+ <span
212
+ ref={ref}
213
+ className={`absolute ${$size === "large" ? "right-[9px] top-[10px]" :
214
+ $size === "medium" ? "right-[4px] top-[4px]" :
215
+ $size === "small" ? "right-[2px] top-[2px]" : ""} ${className ?? ""}`}
216
+ {...props}
217
+ />
218
+ ));
219
+
220
+ /** Inserts a Button at the end of the input. Should not be used with an InputField.Label */
221
+ const InputFieldButton = memo(
222
+ forwardRef(function InputFieldButton(
223
+ props: React.ButtonHTMLAttributes<HTMLButtonElement>,
224
+ forwardedRef: ForwardedRef<HTMLButtonElement>
225
+ ) {
226
+ const { children, onClick, ...rest } = props;
227
+ const { size, inputRef, setButtonWidth } = useContext(InputFieldContext);
186
228
 
187
- const InputFieldButton = memo(function InputFieldButton({
188
- children,
189
- onClick,
190
- }: {
191
- children?: ReactNode;
192
- onClick?: () => void;
193
- }) {
194
- const { size, inputRef } = useContext(InputFieldContext);
195
-
196
- const defaultHandleClick = useCallback(
197
- (event: React.MouseEvent) => {
198
- if (inputRef && typeof inputRef !== "function") {
199
- inputRef.current?.focus();
200
- // Select all text
201
- inputRef.current?.setSelectionRange(0, inputRef.current.value.length);
202
- }
229
+ const ref = useRef<HTMLButtonElement | null>(null);
203
230
 
204
- event.preventDefault();
205
- event.stopPropagation();
206
- },
207
- [inputRef]
208
- );
231
+ useLayoutEffect(() => {
232
+ if (!setButtonWidth) return;
209
233
 
210
- const handlePointerDown = useCallback((event: React.PointerEvent) => {
211
- event.preventDefault();
212
- event.stopPropagation();
213
- }, []);
234
+ const width = ref.current?.getBoundingClientRect().width;
214
235
 
215
- return (
216
- <ButtonContainer $size={size}>
217
- <Button
218
- variant="floating"
219
- onClick={onClick ?? defaultHandleClick}
220
- onPointerDown={handlePointerDown}
221
- tabIndex={-1}
222
- >
223
- {children}
224
- </Button>
225
- </ButtonContainer>
226
- );
227
- });
236
+ if (!width) return;
237
+
238
+ setButtonWidth(width);
239
+ }, [setButtonWidth]);
240
+
241
+ const defaultHandleClick = useCallback(
242
+ (event: React.MouseEvent<HTMLButtonElement>) => {
243
+ if (inputRef && typeof inputRef !== "function") {
244
+ inputRef.current?.focus();
245
+ // Select all text
246
+ inputRef.current?.setSelectionRange(0, inputRef.current.value.length);
247
+ }
248
+
249
+ event.preventDefault();
250
+ event.stopPropagation();
251
+ },
252
+ [inputRef]
253
+ );
254
+
255
+ const handlePointerDown = useCallback(
256
+ (event: React.PointerEvent<HTMLButtonElement>) => {
257
+ event.preventDefault();
258
+ event.stopPropagation();
259
+ },
260
+ []
261
+ );
262
+
263
+ return (
264
+ <ButtonContainer $size={size}>
265
+ <Button
266
+ ref={(element) => {
267
+ ref.current = element;
268
+ assignRef(forwardedRef, element);
269
+ }}
270
+ variant="floating"
271
+ onClick={onClick ?? defaultHandleClick}
272
+ onPointerDown={handlePointerDown}
273
+ tabIndex={-1}
274
+ size={size === "medium" ? "normal" : size}
275
+ {...rest}
276
+ >
277
+ {children}
278
+ </Button>
279
+ </ButtonContainer>
280
+ );
281
+ })
282
+ );
228
283
 
229
284
  /* ----------------------------------------------------------------------------
230
285
  * Input
@@ -239,106 +294,91 @@ const InputFieldButton = memo(function InputFieldButton({
239
294
 
240
295
  type InputFieldVariant = "normal" | "bare";
241
296
 
242
- export const InputElement = styled(TextInput)<{
297
+ type InputElementProps = {
243
298
  disabled?: boolean;
244
299
  readOnly?: boolean;
245
300
  $labelPosition: LabelPosition;
246
- $labelSize: number;
247
- $hasLabel: boolean;
301
+ $labelSize?: number;
248
302
  $hasDropdown: boolean;
249
303
  $textAlign?: Property.TextAlign;
250
304
  $variant?: InputFieldVariant;
251
305
  $size: InputFieldSize;
252
- }>(({
253
- theme,
254
- $labelPosition,
255
- $labelSize,
256
- $hasDropdown,
257
- $textAlign,
258
- disabled,
259
- $hasLabel,
260
- readOnly,
261
- $variant = "normal",
262
- $size,
263
- }) => {
264
- return {
265
- // placeholder
266
- "&::placeholder": {
267
- color: theme.colors.textDisabled,
268
- },
269
- ...theme.textStyles.small,
270
- color: readOnly
271
- ? theme.colors.textMuted
272
- : disabled
273
- ? theme.colors.textDisabled
274
- : theme.colors.text,
275
- ...($size === "small" && {
276
- fontSize: "11px",
277
- }),
278
- width: "0px", // Reset intrinsic width
279
- flex: "1 1 0px",
280
- position: "relative",
281
- border: "0",
282
- outline: "none",
283
- minWidth: "0",
284
- textAlign: $textAlign ?? "left",
285
- alignSelf: "stretch",
286
- borderRadius: "4px",
287
- paddingTop: $size === "large" ? "10px" : $size === "medium" ? "4px" : "1px",
288
- paddingBottom:
289
- $size === "large" ? "10px" : $size === "medium" ? "4px" : "1px",
290
- paddingLeft:
291
- ($size === "large" ? 10 : $size === "medium" ? 6 : 4) +
292
- ($hasLabel && $labelPosition === "start" ? 6 + $labelSize : 0) +
293
- "px",
294
- paddingRight:
306
+ children?: React.ReactNode;
307
+ className?: string;
308
+ value?: string;
309
+ onSubmit?: (value: string) => void;
310
+ };
311
+
312
+ const InputElement = forwardRef(
313
+ (
314
+ {
315
+ disabled,
316
+ readOnly,
317
+ $labelPosition,
318
+ $labelSize,
319
+ $hasDropdown,
320
+ $textAlign,
321
+ $variant = "normal",
322
+ $size,
323
+ className,
324
+ children,
325
+ value,
326
+ onSubmit,
327
+ ...props
328
+ }: InputElementProps,
329
+ ref: ForwardedRef<any>
330
+ ) => {
331
+ const paddingLeft =
295
332
  ($size === "large" ? 10 : $size === "medium" ? 6 : 4) +
296
- ($hasLabel && $labelPosition === "end" ? 6 + $labelSize : 0) +
297
- ($hasDropdown ? 11 : 0) +
298
- "px",
299
- background: theme.colors.inputBackground,
300
- "&:focus": {
301
- boxShadow: `0 0 0 2px ${theme.colors.primary}`,
302
- },
303
- ...($variant === "bare" && {
304
- paddingTop: "4px",
305
- paddingRight: "4px",
306
- paddingBottom: "4px",
307
- paddingLeft: "4px",
308
- marginTop: "-4px",
309
- marginRight: "-4px",
310
- marginBottom: "-4px",
311
- marginLeft: "-4px",
312
- }),
333
+ ($labelSize && $labelPosition === "start" ? 6 + $labelSize : 0);
313
334
 
314
- // '&[type="search"]::-webkit-search-cancel-button': {
315
- // appearance: "none",
316
- // height: "15px",
317
- // width: "15px",
318
- // background: `url("data:image/svg+xml;utf8,${createCrossSVGString(
319
- // theme.colors.icon
320
- // )}") no-repeat`,
321
- // },
322
- };
323
- });
335
+ const paddingRight =
336
+ ($size === "large" ? 10 : $size === "medium" ? 6 : 1) +
337
+ ($labelSize && $labelPosition === "end" ? 6 + $labelSize : 0) +
338
+ ($hasDropdown ? 11 : 0);
324
339
 
340
+ const memoizedStyles = useMemo(() => ({
341
+ paddingLeft: `${paddingLeft}px`,
342
+ paddingRight: `${paddingRight}px`,
343
+ }), [paddingLeft, paddingRight])
344
+
345
+ return (
346
+ <TextInput
347
+ value={value ?? ""}
348
+ onSubmit={onSubmit ?? (() => {})}
349
+ ref={ref}
350
+ className={`flex w-0 flex-[1_1_0px] relative border-0 outline-none min-w-0 self-stretch rounded bg-input-background focus:ring-2 focus:ring-primary focus:z-10 placeholder:text-text-disabled ${readOnly ? "text-text-muted" : disabled ? "text-text-disabled" : "text-text"} font-sans font-normal ${$textAlign && `text-${$textAlign}`} ${
351
+ $size === "small"
352
+ ? "text-[11px] leading-[19px] py-[1px]"
353
+ : $size === "large"
354
+ ? "py-[10px] text-heading5"
355
+ : $size === "medium"
356
+ ? "py-1 text-heading5"
357
+ : $variant === "bare" && "p-1 -m-1"
358
+ } ${className ?? ""}`}
359
+ style={memoizedStyles}
360
+ {...props}
361
+ />
362
+ );
363
+ }
364
+ );
365
+
366
+ export type InputFieldInputProps = TextInputProps & {
367
+ textAlign?: Property.TextAlign;
368
+ variant?: "bare";
369
+ };
370
+
371
+ /** Should always be wrapped in InputField.Root */
325
372
  const InputFieldInput = forwardRef(function InputFieldInput(
326
373
  // onFocusChange should only be passed from the root, never directly
327
- {
328
- textAlign,
329
- variant,
330
- ...rest
331
- }: TextInputProps & {
332
- textAlign?: Property.TextAlign;
333
- variant?: "bare";
334
- },
374
+ { textAlign, variant, ...rest }: InputFieldInputProps,
335
375
  forwardedRef: ForwardedRef<HTMLInputElement>
336
376
  ) {
337
377
  const {
338
378
  labelPosition,
339
379
  labelSize,
340
380
  hasDropdown,
341
- hasLabel,
381
+ buttonSize,
342
382
  size,
343
383
  onFocusChange,
344
384
  setInputRef,
@@ -359,8 +399,7 @@ const InputFieldInput = forwardRef(function InputFieldInput(
359
399
  <InputElement
360
400
  ref={forwardedRef}
361
401
  $labelPosition={labelPosition}
362
- $labelSize={labelSize}
363
- $hasLabel={hasLabel}
402
+ $labelSize={labelSize || buttonSize}
364
403
  $hasDropdown={hasDropdown}
365
404
  $size={size}
366
405
  $variant={variant}
@@ -376,35 +415,22 @@ const InputFieldTypeahead = (props: { prefix: string; value: string }) => {
376
415
  labelPosition,
377
416
  labelSize,
378
417
  hasDropdown,
379
- hasLabel,
380
418
  size,
381
419
  // onFocusChange,
382
420
  } = useContext(InputFieldContext);
383
421
 
384
422
  return (
385
423
  <InputElement
386
- as="span"
387
424
  $labelPosition={labelPosition}
388
425
  $labelSize={labelSize}
389
- $hasLabel={hasLabel}
390
426
  $hasDropdown={hasDropdown}
391
427
  $size={size}
392
428
  // onFocusChange={onFocusChange}
393
429
  // readOnly
394
430
  // placeholder={props.value}
431
+ {...props}
395
432
  value=""
396
- style={{
397
- position: "absolute",
398
- top: 0,
399
- left: 0,
400
- right: 0,
401
- bottom: 0,
402
- width: "100%",
403
- height: "100%",
404
- pointerEvents: "none",
405
- background: "transparent",
406
- boxShadow: "none",
407
- }}
433
+ className="absolute inset-0 w-full h-full pointer-events-none bg-transparent shadow-none"
408
434
  >
409
435
  <span style={{ opacity: 0 }}>{props.prefix}</span>
410
436
  <span style={{ opacity: 0.5 }}>
@@ -529,15 +555,23 @@ function InputFieldNumberInput(props: InputFieldNumberInputProps) {
529
555
  * Root
530
556
  * ------------------------------------------------------------------------- */
531
557
 
532
- const RootContainer = styled.div<{ $width?: number; $flex?: string }>(
533
- ({ theme, $flex, $width }) => ({
534
- flex: $flex ?? "1",
535
- display: "flex",
536
- flexDirection: "row",
537
- position: "relative",
538
- maxWidth: typeof $width === "number" ? `${$width}px` : undefined,
539
- })
540
- );
558
+ const RootContainer = forwardRef<
559
+ HTMLDivElement,
560
+ {
561
+ $width?: number;
562
+ $flex?: string;
563
+ className?: string;
564
+ children?: React.ReactNode;
565
+ id?: string;
566
+ style?: React.CSSProperties;
567
+ }
568
+ >(({ $width, $flex, className, ...props }, ref) => (
569
+ <div
570
+ ref={ref}
571
+ className={`flex flex-row relative ${$flex ? `flex-[${$flex}]` : "flex-1"} ${$width || $width === 0 ? `max-w-[${$width}px]` : ""} ${className ?? ""}`}
572
+ {...props}
573
+ />
574
+ ));
541
575
 
542
576
  interface InputFieldRootProps {
543
577
  id?: string;
@@ -574,13 +608,11 @@ function InputFieldRoot({
574
608
  const hasDropdown = childrenArray.some(
575
609
  (child) => isValidElement(child) && child.type === InputFieldDropdownMenu
576
610
  );
577
- const hasLabel = childrenArray.some(
578
- (child) => isValidElement(child) && child.type === InputFieldLabel
579
- );
580
611
 
581
612
  const [isFocused, setIsFocused] = React.useState(false);
582
613
 
583
614
  const [measuredLabelSize, setMeasuredLabelSize] = React.useState<number>();
615
+ const [measuredButtonSize, setMeasuredButtonSize] = React.useState<number>();
584
616
  const [measuredWidth, setMeasuredWidth] = React.useState<number>();
585
617
 
586
618
  const handleFocusChange = useCallback(
@@ -606,22 +638,23 @@ function InputFieldRoot({
606
638
  const contextValue = useMemo(
607
639
  (): InputFieldContextValue => ({
608
640
  labelPosition,
609
- labelSize: measuredLabelSize ?? labelSize ?? 6,
641
+ labelSize: measuredLabelSize ?? labelSize,
642
+ buttonSize: measuredButtonSize,
610
643
  hasDropdown,
611
- hasLabel,
612
644
  size,
613
645
  isFocused,
614
646
  onFocusChange: handleFocusChange,
615
647
  inputRef,
616
648
  setInputRef,
617
649
  setLabelWidth: setMeasuredLabelSize,
650
+ setButtonWidth: setMeasuredButtonSize,
618
651
  }),
619
652
  [
620
653
  labelPosition,
621
654
  measuredLabelSize,
622
655
  labelSize,
656
+ measuredButtonSize,
623
657
  hasDropdown,
624
- hasLabel,
625
658
  size,
626
659
  isFocused,
627
660
  handleFocusChange,
@@ -659,9 +692,9 @@ function InputFieldRoot({
659
692
  }}
660
693
  >
661
694
  {measuredWidth && (
662
- <Stack.V width={measuredWidth} overflow="hidden">
695
+ <div className={`flex flex-col w-[${measuredWidth}] hidden`}>
663
696
  {renderPopoverContent({ width: measuredWidth })}
664
- </Stack.V>
697
+ </div>
665
698
  )}
666
699
  </Popover>
667
700
  ) : (
@@ -671,38 +704,29 @@ function InputFieldRoot({
671
704
  );
672
705
  }
673
706
 
674
- const PrimitiveInputField = styled.input(({ theme, readOnly, disabled }) => {
675
- return {
676
- // placeholder
677
- "&::placeholder": {
678
- color: theme.colors.textDisabled,
679
- },
680
- ...theme.textStyles.small,
681
- color: readOnly
682
- ? theme.colors.textMuted
683
- : disabled
684
- ? theme.colors.textDisabled
685
- : theme.colors.text,
686
- width: "0px", // Reset intrinsic width
687
- flex: "1 1 0px",
688
- position: "relative",
689
- border: "0",
690
- outline: "none",
691
- minWidth: "0",
692
- alignSelf: "stretch",
693
- borderRadius: "4px",
694
- paddingTop: "4px",
695
- paddingBottom: "4px",
696
- paddingLeft: "6px",
697
- paddingRight: "6px",
698
- background: theme.colors.inputBackground,
699
- "&:focus": {
700
- boxShadow: `0 0 0 2px ${theme.colors.primary}`,
701
- },
702
- userSelect: "all",
703
- pointerEvents: "all",
704
- };
705
- });
707
+ const PrimitiveInputField = ({
708
+ readOnly,
709
+ disabled,
710
+ className,
711
+ ...props
712
+ }: {
713
+ readOnly?: boolean;
714
+ disabled?: boolean;
715
+ } & React.DetailedHTMLProps<
716
+ React.InputHTMLAttributes<HTMLInputElement>,
717
+ HTMLInputElement
718
+ >) => (
719
+ <input
720
+ className={`flex w-0 flex-1 relative border-none outline-none min-w-0 self-stretch rounded py-1 px-1.5 bg-input-background select-all pointer-events-[all] focus:ring-2 focus:ring-primary focus:z-10 font-sans font-normal text-heading5 placeholder:text-text-disabled ${
721
+ readOnly
722
+ ? "text-text-muted"
723
+ : disabled
724
+ ? "text-text-disabled"
725
+ : "text-text"
726
+ } ${className ?? ""}`}
727
+ {...props}
728
+ />
729
+ );
706
730
 
707
731
  export namespace InputField {
708
732
  export const Root = memo(InputFieldRoot);