@financedistrict/apps-ui 0.1.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 (136) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +119 -0
  3. package/dist/Radio-BYWz1n7p.d.cts +32 -0
  4. package/dist/Radio-BYWz1n7p.d.ts +32 -0
  5. package/dist/SelectTrigger-By0iPBI3.d.cts +78 -0
  6. package/dist/SelectTrigger-By0iPBI3.d.ts +78 -0
  7. package/dist/accordion.cjs +322 -0
  8. package/dist/accordion.d.cts +156 -0
  9. package/dist/accordion.d.ts +156 -0
  10. package/dist/accordion.js +2 -0
  11. package/dist/apps-ui.umd.js +1 -0
  12. package/dist/button.cjs +366 -0
  13. package/dist/button.d.cts +52 -0
  14. package/dist/button.d.ts +52 -0
  15. package/dist/button.js +3 -0
  16. package/dist/checkbox.cjs +74 -0
  17. package/dist/checkbox.d.cts +63 -0
  18. package/dist/checkbox.d.ts +63 -0
  19. package/dist/checkbox.js +2 -0
  20. package/dist/chunk-3RU7JMFE.js +27 -0
  21. package/dist/chunk-5TWRK4NW.js +783 -0
  22. package/dist/chunk-7EOSDFS3.js +9 -0
  23. package/dist/chunk-AIQ4UOGK.js +142 -0
  24. package/dist/chunk-B3MMGTPV.js +200 -0
  25. package/dist/chunk-DAHQYLUI.js +146 -0
  26. package/dist/chunk-DGBXADSS.js +1 -0
  27. package/dist/chunk-E6KPNTWW.js +295 -0
  28. package/dist/chunk-EOAB6G2D.js +149 -0
  29. package/dist/chunk-FAOVKDVM.js +32 -0
  30. package/dist/chunk-FV76Z4Z2.js +78 -0
  31. package/dist/chunk-GLTLBUZ7.js +285 -0
  32. package/dist/chunk-GTZFV43T.js +154 -0
  33. package/dist/chunk-HRGZNL4A.js +88 -0
  34. package/dist/chunk-IEVN3J2F.js +98 -0
  35. package/dist/chunk-IRS3T6LF.js +352 -0
  36. package/dist/chunk-IYYHCQXG.js +146 -0
  37. package/dist/chunk-JIXW3455.js +89 -0
  38. package/dist/chunk-N4VAP2GB.js +77 -0
  39. package/dist/chunk-SJ2ZRYVV.js +167 -0
  40. package/dist/chunk-SNU4YXOR.js +66 -0
  41. package/dist/chunk-TT6JQATV.js +99 -0
  42. package/dist/chunk-UPQ3ZPCO.js +66 -0
  43. package/dist/chunk-UVUSVFOH.js +264 -0
  44. package/dist/chunk-WJFPGGJB.js +255 -0
  45. package/dist/chunk-WXEBQA7A.js +371 -0
  46. package/dist/chunk-Y2O4YYZQ.js +184 -0
  47. package/dist/cut-corner.cjs +111 -0
  48. package/dist/cut-corner.d.cts +49 -0
  49. package/dist/cut-corner.d.ts +49 -0
  50. package/dist/cut-corner.js +1 -0
  51. package/dist/dialog.cjs +441 -0
  52. package/dist/dialog.d.cts +240 -0
  53. package/dist/dialog.d.ts +240 -0
  54. package/dist/dialog.js +3 -0
  55. package/dist/feature-card.cjs +182 -0
  56. package/dist/feature-card.d.cts +54 -0
  57. package/dist/feature-card.d.ts +54 -0
  58. package/dist/feature-card.js +2 -0
  59. package/dist/filter.cjs +873 -0
  60. package/dist/filter.d.cts +129 -0
  61. package/dist/filter.d.ts +129 -0
  62. package/dist/filter.js +6 -0
  63. package/dist/index.cjs +4583 -0
  64. package/dist/index.d.cts +29 -0
  65. package/dist/index.d.ts +29 -0
  66. package/dist/index.js +27 -0
  67. package/dist/inline-select.cjs +856 -0
  68. package/dist/inline-select.d.cts +92 -0
  69. package/dist/inline-select.d.ts +92 -0
  70. package/dist/inline-select.js +6 -0
  71. package/dist/input.cjs +263 -0
  72. package/dist/input.d.cts +157 -0
  73. package/dist/input.d.ts +157 -0
  74. package/dist/input.js +4 -0
  75. package/dist/panel.cjs +185 -0
  76. package/dist/panel.d.cts +103 -0
  77. package/dist/panel.d.ts +103 -0
  78. package/dist/panel.js +2 -0
  79. package/dist/property-grid.cjs +110 -0
  80. package/dist/property-grid.d.cts +56 -0
  81. package/dist/property-grid.d.ts +56 -0
  82. package/dist/property-grid.js +2 -0
  83. package/dist/radio.cjs +74 -0
  84. package/dist/radio.d.cts +39 -0
  85. package/dist/radio.d.ts +39 -0
  86. package/dist/radio.js +2 -0
  87. package/dist/scrollbar.cjs +34 -0
  88. package/dist/scrollbar.d.cts +35 -0
  89. package/dist/scrollbar.d.ts +35 -0
  90. package/dist/scrollbar.js +1 -0
  91. package/dist/search-bar.cjs +408 -0
  92. package/dist/search-bar.d.cts +42 -0
  93. package/dist/search-bar.d.ts +42 -0
  94. package/dist/search-bar.js +4 -0
  95. package/dist/select.cjs +998 -0
  96. package/dist/select.d.cts +357 -0
  97. package/dist/select.d.ts +357 -0
  98. package/dist/select.js +5 -0
  99. package/dist/selectable-feature-card.cjs +159 -0
  100. package/dist/selectable-feature-card.d.cts +74 -0
  101. package/dist/selectable-feature-card.d.ts +74 -0
  102. package/dist/selectable-feature-card.js +3 -0
  103. package/dist/sidebar-item.cjs +175 -0
  104. package/dist/sidebar-item.d.cts +75 -0
  105. package/dist/sidebar-item.d.ts +75 -0
  106. package/dist/sidebar-item.js +2 -0
  107. package/dist/switch.cjs +86 -0
  108. package/dist/switch.d.cts +72 -0
  109. package/dist/switch.d.ts +72 -0
  110. package/dist/switch.js +2 -0
  111. package/dist/table-cell.cjs +196 -0
  112. package/dist/table-cell.d.cts +76 -0
  113. package/dist/table-cell.d.ts +76 -0
  114. package/dist/table-cell.js +2 -0
  115. package/dist/table-title.cjs +34 -0
  116. package/dist/table-title.d.cts +16 -0
  117. package/dist/table-title.d.ts +16 -0
  118. package/dist/table-title.js +2 -0
  119. package/dist/tabs.cjs +299 -0
  120. package/dist/tabs.d.cts +116 -0
  121. package/dist/tabs.d.ts +116 -0
  122. package/dist/tabs.js +2 -0
  123. package/dist/toast.cjs +87 -0
  124. package/dist/toast.d.cts +48 -0
  125. package/dist/toast.d.ts +48 -0
  126. package/dist/toast.js +2 -0
  127. package/dist/token-input.cjs +415 -0
  128. package/dist/token-input.d.cts +90 -0
  129. package/dist/token-input.d.ts +90 -0
  130. package/dist/token-input.js +3 -0
  131. package/dist/tooltip.cjs +384 -0
  132. package/dist/tooltip.d.cts +142 -0
  133. package/dist/tooltip.d.ts +142 -0
  134. package/dist/tooltip.js +2 -0
  135. package/package.json +200 -0
  136. package/src/fonts.css +33 -0
@@ -0,0 +1,92 @@
1
+ import * as React from 'react';
2
+ import { S as SelectOption } from './SelectTrigger-By0iPBI3.cjs';
3
+ import * as class_variance_authority_types from 'class-variance-authority/types';
4
+ import { VariantProps } from 'class-variance-authority';
5
+
6
+ /**
7
+ * InlineSelect trigger styling — the inline-text select (Figma node 4926:5462).
8
+ * Unlike `Select`, there is NO field box: the trigger is a run of inline text
9
+ * (the value label) plus a small filled caret. Binds ONLY to the semantic
10
+ * `--color-*` token layer (never primitives, never arbitrary values); theme
11
+ * switching is automatic via the `.dark` class.
12
+ *
13
+ * Two `variation`s map to the two card-foreground families:
14
+ * - `primary` → neutral card foreground (`card-primary-foreground`), muted
15
+ * caret/placeholder (`card-primary-foreground-muted`).
16
+ * - `secondary` → brand card foreground (`card-brand-secondary-foreground`),
17
+ * muted caret/placeholder (`card-brand-secondary-foreground-muted`).
18
+ *
19
+ * FOCUS is the ADR-0010 system ring — a momentary control (not a text field, so
20
+ * NOT the border-recolor treatment `Select`/`Input` use): 2px `--focus` stroke,
21
+ * 2px offset, on `:focus-visible` only, with a 2px (`radius/xs`) corner to match
22
+ * the Figma focus ring. Suppressed when disabled. The placeholder / value / caret
23
+ * colours are applied by `InlineSelectTrigger` (they depend on runtime state:
24
+ * whether a value is selected, and whether the caret follows the muted or full
25
+ * foreground), so this file owns the shared layout + focus + disabled shell.
26
+ */
27
+ declare const inlineSelectVariants: (props?: ({
28
+ variation?: "primary" | "secondary" | null | undefined;
29
+ disabled?: boolean | null | undefined;
30
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
31
+ type InlineSelectVariantsProps = VariantProps<typeof inlineSelectVariants>;
32
+
33
+ interface InlineSelectProps extends Omit<React.ComponentProps<"button">, "value" | "defaultValue" | "onChange"> {
34
+ /** The options to choose from (array-of-data API). */
35
+ options: SelectOption[];
36
+ /** Controlled selection (single). */
37
+ value?: string;
38
+ /** Uncontrolled initial selection (single). */
39
+ defaultValue?: string;
40
+ /** Fires with the next selected value. */
41
+ onValueChange?: (value: string) => void;
42
+ /** `primary` (neutral foreground, default) | `secondary` (brand foreground). */
43
+ variation?: NonNullable<InlineSelectVariantsProps["variation"]>;
44
+ /** Shown when nothing is selected. */
45
+ placeholder?: string;
46
+ /** Leading adornment before the label (decorative, 16px). */
47
+ leadingSlot?: React.ReactNode;
48
+ /** Disabled — the trigger won't open. */
49
+ disabled?: boolean;
50
+ /** Form field name (mirrors the value into a hidden input for form submission). */
51
+ name?: string;
52
+ }
53
+ /**
54
+ * InlineSelect — a single-select styled as inline text (NO field box), for use
55
+ * inline in a sentence, a card header, or a toolbar (Figma node 4926:5462). The
56
+ * trigger is the value label + a small filled caret; choosing opens a portaled
57
+ * dropdown reusing `Select`'s `SelectListbox`.
58
+ *
59
+ * Single-select only (no multi): `value` / `defaultValue` are `string`s and
60
+ * `onValueChange` emits a `string`. Uncontrolled by default (`defaultValue`)
61
+ * with a controlled escape hatch (`value` + `onValueChange`). Behaviour (open,
62
+ * keyboard model, type-ahead, active-descendant, reposition, outside-click) is
63
+ * shared with `Select` via the `useSelectListbox` hook. `ref` is a normal React
64
+ * 19 prop, forwarded to the trigger button.
65
+ */
66
+ declare function InlineSelect({ options, value: valueProp, defaultValue, onValueChange, variation, placeholder, leadingSlot, disabled, name, id: idProp, className, ref, ...props }: InlineSelectProps): React.JSX.Element;
67
+
68
+ interface InlineSelectTriggerProps extends Omit<React.ComponentProps<"button">, "value">, Omit<InlineSelectVariantsProps, "disabled"> {
69
+ /** Resolved display text (from the hook's `selectTriggerLabel`). */
70
+ displayText: string;
71
+ /** Whether `displayText` is the placeholder (muted) vs a real value. */
72
+ isPlaceholder: boolean;
73
+ /** Whether the listbox is open (flips the caret). */
74
+ open?: boolean;
75
+ /** Leading adornment (decorative — kept out of the a11y tree via `aria-hidden`). */
76
+ leadingSlot?: React.ReactNode;
77
+ }
78
+ /**
79
+ * The InlineSelect trigger — a `<button type="button">` styled as inline text
80
+ * (NO field box): an optional 16px leading slot, the value label (`body-03`),
81
+ * and a 12px filled caret that flips (`rotate-180`) when `open`. The value uses
82
+ * the variation foreground colour; the placeholder + caret use the muted
83
+ * variation colour (Figma node 4926:5462).
84
+ *
85
+ * Presentational leaf: all open/selection/keyboard orchestration and the ARIA
86
+ * popup wiring (`aria-haspopup`/`aria-expanded`/`aria-controls`/
87
+ * `aria-activedescendant`) live in `InlineSelect`, which spreads them through
88
+ * `...props`. `ref` is a normal React 19 prop, forwarded to the button.
89
+ */
90
+ declare function InlineSelectTrigger({ variation, disabled, displayText, isPlaceholder, open, leadingSlot, className, ref, ...props }: InlineSelectTriggerProps): React.JSX.Element;
91
+
92
+ export { InlineSelect, type InlineSelectProps, InlineSelectTrigger, type InlineSelectTriggerProps, type InlineSelectVariantsProps, inlineSelectVariants };
@@ -0,0 +1,92 @@
1
+ import * as React from 'react';
2
+ import { S as SelectOption } from './SelectTrigger-By0iPBI3.js';
3
+ import * as class_variance_authority_types from 'class-variance-authority/types';
4
+ import { VariantProps } from 'class-variance-authority';
5
+
6
+ /**
7
+ * InlineSelect trigger styling — the inline-text select (Figma node 4926:5462).
8
+ * Unlike `Select`, there is NO field box: the trigger is a run of inline text
9
+ * (the value label) plus a small filled caret. Binds ONLY to the semantic
10
+ * `--color-*` token layer (never primitives, never arbitrary values); theme
11
+ * switching is automatic via the `.dark` class.
12
+ *
13
+ * Two `variation`s map to the two card-foreground families:
14
+ * - `primary` → neutral card foreground (`card-primary-foreground`), muted
15
+ * caret/placeholder (`card-primary-foreground-muted`).
16
+ * - `secondary` → brand card foreground (`card-brand-secondary-foreground`),
17
+ * muted caret/placeholder (`card-brand-secondary-foreground-muted`).
18
+ *
19
+ * FOCUS is the ADR-0010 system ring — a momentary control (not a text field, so
20
+ * NOT the border-recolor treatment `Select`/`Input` use): 2px `--focus` stroke,
21
+ * 2px offset, on `:focus-visible` only, with a 2px (`radius/xs`) corner to match
22
+ * the Figma focus ring. Suppressed when disabled. The placeholder / value / caret
23
+ * colours are applied by `InlineSelectTrigger` (they depend on runtime state:
24
+ * whether a value is selected, and whether the caret follows the muted or full
25
+ * foreground), so this file owns the shared layout + focus + disabled shell.
26
+ */
27
+ declare const inlineSelectVariants: (props?: ({
28
+ variation?: "primary" | "secondary" | null | undefined;
29
+ disabled?: boolean | null | undefined;
30
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
31
+ type InlineSelectVariantsProps = VariantProps<typeof inlineSelectVariants>;
32
+
33
+ interface InlineSelectProps extends Omit<React.ComponentProps<"button">, "value" | "defaultValue" | "onChange"> {
34
+ /** The options to choose from (array-of-data API). */
35
+ options: SelectOption[];
36
+ /** Controlled selection (single). */
37
+ value?: string;
38
+ /** Uncontrolled initial selection (single). */
39
+ defaultValue?: string;
40
+ /** Fires with the next selected value. */
41
+ onValueChange?: (value: string) => void;
42
+ /** `primary` (neutral foreground, default) | `secondary` (brand foreground). */
43
+ variation?: NonNullable<InlineSelectVariantsProps["variation"]>;
44
+ /** Shown when nothing is selected. */
45
+ placeholder?: string;
46
+ /** Leading adornment before the label (decorative, 16px). */
47
+ leadingSlot?: React.ReactNode;
48
+ /** Disabled — the trigger won't open. */
49
+ disabled?: boolean;
50
+ /** Form field name (mirrors the value into a hidden input for form submission). */
51
+ name?: string;
52
+ }
53
+ /**
54
+ * InlineSelect — a single-select styled as inline text (NO field box), for use
55
+ * inline in a sentence, a card header, or a toolbar (Figma node 4926:5462). The
56
+ * trigger is the value label + a small filled caret; choosing opens a portaled
57
+ * dropdown reusing `Select`'s `SelectListbox`.
58
+ *
59
+ * Single-select only (no multi): `value` / `defaultValue` are `string`s and
60
+ * `onValueChange` emits a `string`. Uncontrolled by default (`defaultValue`)
61
+ * with a controlled escape hatch (`value` + `onValueChange`). Behaviour (open,
62
+ * keyboard model, type-ahead, active-descendant, reposition, outside-click) is
63
+ * shared with `Select` via the `useSelectListbox` hook. `ref` is a normal React
64
+ * 19 prop, forwarded to the trigger button.
65
+ */
66
+ declare function InlineSelect({ options, value: valueProp, defaultValue, onValueChange, variation, placeholder, leadingSlot, disabled, name, id: idProp, className, ref, ...props }: InlineSelectProps): React.JSX.Element;
67
+
68
+ interface InlineSelectTriggerProps extends Omit<React.ComponentProps<"button">, "value">, Omit<InlineSelectVariantsProps, "disabled"> {
69
+ /** Resolved display text (from the hook's `selectTriggerLabel`). */
70
+ displayText: string;
71
+ /** Whether `displayText` is the placeholder (muted) vs a real value. */
72
+ isPlaceholder: boolean;
73
+ /** Whether the listbox is open (flips the caret). */
74
+ open?: boolean;
75
+ /** Leading adornment (decorative — kept out of the a11y tree via `aria-hidden`). */
76
+ leadingSlot?: React.ReactNode;
77
+ }
78
+ /**
79
+ * The InlineSelect trigger — a `<button type="button">` styled as inline text
80
+ * (NO field box): an optional 16px leading slot, the value label (`body-03`),
81
+ * and a 12px filled caret that flips (`rotate-180`) when `open`. The value uses
82
+ * the variation foreground colour; the placeholder + caret use the muted
83
+ * variation colour (Figma node 4926:5462).
84
+ *
85
+ * Presentational leaf: all open/selection/keyboard orchestration and the ARIA
86
+ * popup wiring (`aria-haspopup`/`aria-expanded`/`aria-controls`/
87
+ * `aria-activedescendant`) live in `InlineSelect`, which spreads them through
88
+ * `...props`. `ref` is a normal React 19 prop, forwarded to the button.
89
+ */
90
+ declare function InlineSelectTrigger({ variation, disabled, displayText, isPlaceholder, open, leadingSlot, className, ref, ...props }: InlineSelectTriggerProps): React.JSX.Element;
91
+
92
+ export { InlineSelect, type InlineSelectProps, InlineSelectTrigger, type InlineSelectTriggerProps, type InlineSelectVariantsProps, inlineSelectVariants };
@@ -0,0 +1,6 @@
1
+ export { InlineSelect, InlineSelectTrigger, inlineSelectVariants } from './chunk-Y2O4YYZQ.js';
2
+ import './chunk-5TWRK4NW.js';
3
+ import './chunk-IEVN3J2F.js';
4
+ import './chunk-SNU4YXOR.js';
5
+ import './chunk-FAOVKDVM.js';
6
+ import './chunk-7EOSDFS3.js';
package/dist/input.cjs ADDED
@@ -0,0 +1,263 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var react = require('@phosphor-icons/react');
5
+ var clsx = require('clsx');
6
+ var tailwindMerge = require('tailwind-merge');
7
+ var classVarianceAuthority = require('class-variance-authority');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+
10
+ function _interopNamespace(e) {
11
+ if (e && e.__esModule) return e;
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
22
+ });
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
27
+
28
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
29
+
30
+ // src/input/Input.tsx
31
+ function cn(...inputs) {
32
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
33
+ }
34
+ var inputVariants = classVarianceAuthority.cva(
35
+ [
36
+ // Field row layout — icons + input on one line, vertically centred.
37
+ "flex w-full items-center",
38
+ // Colour transitions for the focus border change.
39
+ "transition-colors",
40
+ // I-beam text cursor over the WHOLE field row (not just the inner input),
41
+ // so clicking anywhere in the padding/icon area reads as "type here". This
42
+ // is the only hover affordance — hover intentionally does NOT recolour the
43
+ // border (user-authorized deviation from the Figma). `cursor-text` sits in
44
+ // the base; `has-[:disabled]:cursor-not-allowed` below is declared AFTER it
45
+ // so it wins on a disabled field (same-specificity utilities, later class
46
+ // takes precedence — confirmed by tailwind-merge ordering).
47
+ "cursor-text",
48
+ // Disabled: not-allowed cursor + block pointer interaction on the whole
49
+ // field (the native `disabled` on the input already stops typing; icons are
50
+ // dimmed separately by the `disabled`-derived `iconStateClass` in <Input>).
51
+ // Declared after `cursor-text` so it overrides the I-beam when disabled.
52
+ "has-[:disabled]:cursor-not-allowed"
53
+ ],
54
+ {
55
+ variants: {
56
+ variation: {
57
+ field: [
58
+ "bg-input-background border border-input-border rounded-sm",
59
+ // Focus (mouse or keyboard) strengthens the whole border to the
60
+ // accent. Hover does NOT change colour (cursor-only affordance).
61
+ "focus-within:border-input-border-accent"
62
+ ],
63
+ line: [
64
+ "border-b border-input-border",
65
+ // Focus (mouse or keyboard) strengthens the bottom line to the
66
+ // accent. Hover does NOT change colour (cursor-only affordance).
67
+ "focus-within:border-input-border-accent"
68
+ ]
69
+ },
70
+ size: {
71
+ // sm/lg heights reuse the Button scale; gap follows Figma per size.
72
+ sm: "h-8 gap-1",
73
+ lg: "h-10 gap-2"
74
+ },
75
+ error: {
76
+ // Error out-ranks focus: declare the destructive border for the resting
77
+ // state AND its `focus-within:` form so an errored field never recolours
78
+ // to the accent when focused (a bare `border-…` alone would lose to the
79
+ // variation's `focus-within:` accent utility above). No `hover:` form is
80
+ // needed — hover no longer changes colour on any variation. The `error`
81
+ // variant's classes are emitted after the variation's, so at equal
82
+ // specificity the destructive `focus-within:` wins by order.
83
+ true: "border-input-destructive-foreground-accent focus-within:border-input-destructive-foreground-accent",
84
+ false: ""
85
+ },
86
+ // Bottom-line visibility toggle. LINE ONLY — the hide effect is applied
87
+ // via a compound variant below (scoped to `variation:line`), so `field`
88
+ // is unaffected. Boolean → `true`/`false`; `true` (default) keeps today's
89
+ // behaviour. No classes here: `true` is the resting `border-input-border`
90
+ // from the variation, and `false`'s hide is the compound variant.
91
+ showBottomLine: {
92
+ true: "",
93
+ false: ""
94
+ }
95
+ },
96
+ compoundVariants: [
97
+ // field padding — Figma field-lg = px-3 (12px) / py-2 (8px).
98
+ { variation: "field", size: "lg", className: "px-3 py-2" },
99
+ // field-sm: DERIVED. px-2 (8px = spacing/2) steps down from field-lg's
100
+ // px-3 (12px) and equals py-2 for a uniform spacing/2 inset all around.
101
+ { variation: "field", size: "sm", className: "px-2 py-2" },
102
+ // line — no horizontal padding (Figma px-0); vertical padding per size.
103
+ { variation: "line", size: "lg", className: "py-2" },
104
+ { variation: "line", size: "sm", className: "py-2.5" },
105
+ // Hide the resting bottom line (LINE ONLY): recolour to transparent while
106
+ // keeping `border-b` for a stable 1px width (no layout shift). Gated on
107
+ // `error:false` so an errored field keeps its destructive rest border
108
+ // (transparent would otherwise last-win over it). Focus still wins:
109
+ // `focus-within:border-input-border-accent` out-ranks `border-transparent`
110
+ // (later in class order), so the line reappears on focus. `field` is
111
+ // untouched — this compound only matches `variation:line`.
112
+ {
113
+ variation: "line",
114
+ showBottomLine: false,
115
+ error: false,
116
+ className: "border-transparent"
117
+ }
118
+ ],
119
+ defaultVariants: {
120
+ variation: "field",
121
+ size: "lg",
122
+ error: false,
123
+ showBottomLine: true
124
+ }
125
+ }
126
+ );
127
+ function Input({
128
+ className,
129
+ fieldClassName,
130
+ wrapperClassName,
131
+ variation = "field",
132
+ size = "lg",
133
+ error = false,
134
+ // LINE-only bottom-line toggle. Destructured OUT of `props` so it never
135
+ // spreads onto the native <input> (invalid DOM attribute → React warning).
136
+ showBottomLine = true,
137
+ label,
138
+ optional = false,
139
+ hint,
140
+ leftSlot,
141
+ rightSlot,
142
+ disabled,
143
+ id: idProp,
144
+ ref,
145
+ ...props
146
+ }) {
147
+ const generatedId = React__namespace.useId();
148
+ const id = idProp ?? generatedId;
149
+ const hintId = hint ? `${id}-hint` : void 0;
150
+ const iconStateClass = cn(
151
+ error ? "text-input-destructive-foreground-accent" : "text-input-foreground",
152
+ disabled && "text-input-foreground-muted"
153
+ );
154
+ const HintIcon = error ? react.WarningIcon : react.InfoIcon;
155
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1.5", wrapperClassName), children: [
156
+ label != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
157
+ /* @__PURE__ */ jsxRuntime.jsx(
158
+ "label",
159
+ {
160
+ htmlFor: id,
161
+ "data-slot": "input-label",
162
+ className: cn(
163
+ "caption-03-medium uppercase",
164
+ error ? "text-input-destructive-foreground-accent" : "text-input-foreground",
165
+ disabled && "text-input-foreground-muted"
166
+ ),
167
+ children: label
168
+ }
169
+ ),
170
+ optional && /* @__PURE__ */ jsxRuntime.jsx(
171
+ "span",
172
+ {
173
+ "data-slot": "input-optional",
174
+ className: "body-04 text-input-foreground-muted",
175
+ children: "Optional"
176
+ }
177
+ )
178
+ ] }),
179
+ /* @__PURE__ */ jsxRuntime.jsxs(
180
+ "div",
181
+ {
182
+ "data-slot": "input-field",
183
+ "data-variation": variation,
184
+ "data-error": error || void 0,
185
+ className: cn(
186
+ inputVariants({ variation, size, error, showBottomLine }),
187
+ // Icon slots inherit the shared state colour; 16px default size.
188
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
189
+ iconStateClass,
190
+ fieldClassName
191
+ ),
192
+ children: [
193
+ leftSlot != null && /* @__PURE__ */ jsxRuntime.jsx(
194
+ "span",
195
+ {
196
+ "data-slot": "input-leading",
197
+ "aria-hidden": "true",
198
+ className: "flex items-center",
199
+ children: leftSlot
200
+ }
201
+ ),
202
+ /* @__PURE__ */ jsxRuntime.jsx(
203
+ "input",
204
+ {
205
+ id,
206
+ "data-slot": "input",
207
+ disabled,
208
+ "aria-invalid": error || void 0,
209
+ "aria-describedby": hintId,
210
+ className: cn(
211
+ // Typography (Figma `body-03`) + fill the row. `min-w-0` lets the
212
+ // input shrink inside the flex row instead of overflowing.
213
+ "body-03 w-full min-w-0 bg-transparent outline-none",
214
+ // Typed text + caret colour (Figma `input-foreground-accent`).
215
+ "text-input-foreground-accent caret-input-foreground-accent",
216
+ // Placeholder colour (Figma `input-foreground-muted`).
217
+ "placeholder:text-input-foreground-muted",
218
+ // Disabled text goes muted; keep the not-allowed cursor.
219
+ "disabled:cursor-not-allowed disabled:text-input-foreground-muted",
220
+ className
221
+ ),
222
+ ref,
223
+ ...props
224
+ }
225
+ ),
226
+ rightSlot != null && // NOT aria-hidden: the trailing slot may host an interactive control
227
+ // (e.g. SearchBar's clear button) that must stay reachable by AT +
228
+ // keyboard, and a focusable element inside aria-hidden is an ARIA
229
+ // violation. Decorative bare-<svg> icons are silent to AT on their own
230
+ // (no role / no accessible name), so dropping aria-hidden here does not
231
+ // make them announced. The leading slot stays decorative (aria-hidden).
232
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-slot": "input-trailing", className: "flex items-center", children: rightSlot })
233
+ ]
234
+ }
235
+ ),
236
+ hint != null && /* @__PURE__ */ jsxRuntime.jsxs(
237
+ "p",
238
+ {
239
+ id: hintId,
240
+ "data-slot": "input-hint",
241
+ className: cn(
242
+ "body-04 flex items-center gap-1",
243
+ error ? "text-input-destructive-foreground-accent" : "text-input-foreground",
244
+ disabled && "text-input-foreground-muted"
245
+ ),
246
+ children: [
247
+ /* @__PURE__ */ jsxRuntime.jsx(
248
+ HintIcon,
249
+ {
250
+ "aria-hidden": "true",
251
+ weight: "regular",
252
+ className: "size-4 shrink-0"
253
+ }
254
+ ),
255
+ hint
256
+ ]
257
+ }
258
+ )
259
+ ] });
260
+ }
261
+
262
+ exports.Input = Input;
263
+ exports.inputVariants = inputVariants;
@@ -0,0 +1,157 @@
1
+ import * as React from 'react';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+ import { VariantProps } from 'class-variance-authority';
4
+
5
+ /**
6
+ * Input styling — mirrors the Figma `BaseInput` component (node 4973:6816) and
7
+ * binds ONLY to the semantic `--input-*` token layer (never primitives, never
8
+ * arbitrary values). Theme switching is automatic via the `.dark` class, so no
9
+ * `dark:` variants are needed.
10
+ *
11
+ * This cva styles the FIELD wrapper (the row that holds the leading icon, the
12
+ * real `<input>`, and the trailing icon) — NOT the bare `<input>`, whose own
13
+ * classes live in <Input> so the token that colours typed text
14
+ * (`text-input-foreground-accent`) and the placeholder
15
+ * (`text-input-foreground-muted`) can sit on the element itself.
16
+ *
17
+ * The 7 Figma "states" (default / hover / focused&active / active&filled /
18
+ * filled …) are runtime DOM states of a real `<input>`, NOT a prop:
19
+ * - hover → a text (I-beam) cursor affordance ONLY (`cursor-text` in the
20
+ * base). Hover does NOT recolour the border/underline. This is a
21
+ * deliberate, user-authorized deviation from the Figma (which draws
22
+ * the accent border on hover): the team decided hover is a pointer
23
+ * affordance, not a colour change.
24
+ * - focus → `focus-within:` on the field wrapper recolours the border (field)
25
+ * / bottom line (line) to `input-border-accent`. The input is the
26
+ * focusable descendant; the visible treatment lives on its wrapper.
27
+ * There is NO system outline ring on this control (see below).
28
+ * - filled → whether the input holds a value (no styling delta in this token
29
+ * set beyond the typed-text colour, applied on the input directly).
30
+ * Only `disabled` and `error` are real props (handled below + in <Input>).
31
+ *
32
+ * Focus model — user-authorized exception to ADR-0010 #4 / ADR-0011:
33
+ * text inputs do NOT use the system `:focus-visible` outline ring. A keyboard
34
+ * user never triggers `:hover`, and (since hover no longer changes colour) the
35
+ * gray→accent border recolour on ANY focus is itself a clear, unambiguous
36
+ * WCAG 2.1 AA (2.4.7) focus indicator. Text inputs also hold focus while the
37
+ * user types, so `focus-within` (any focus, not just `:focus-visible`) is the
38
+ * correct trigger. The ring is intentionally omitted here; do NOT re-add it.
39
+ *
40
+ * Variant × size axes (both independent, 4 combinations):
41
+ * - variation `field`: bordered rounded box (`bg-input-background`, `border`,
42
+ * `rounded-sm`, horizontal padding). Focus strengthens the border to
43
+ * `input-border-accent` (hover does not change colour).
44
+ * - variation `line`: no box/background — a single bottom border only
45
+ * (`border-b`), no horizontal padding. Focus strengthens the bottom line
46
+ * (hover does not change colour).
47
+ *
48
+ * Sizes reuse the sibling sm/lg scale (Button = `h-8` / `h-10`):
49
+ * - lg: `h-10`, `gap-2`, `py-2`; field adds `px-3` (Figma field-lg = 12px).
50
+ * - sm: `h-8`, `gap-1`; line uses `py-2.5` (Figma line-sm = 10px), field uses
51
+ * `py-2` (matches lg vertical rhythm inside the shorter box).
52
+ *
53
+ * field-sm horizontal padding is DERIVED (Figma only draws field-lg): we use
54
+ * `px-2` (8px = `spacing/2`), stepping down from field-lg's `px-3` (12px) and
55
+ * matching field-sm's own `py-2` (8px) for a uniform `spacing/2` inset on all
56
+ * sides. (This is a deliberate token-aligned choice; it does NOT match
57
+ * Button's sm `px-2.5`.)
58
+ *
59
+ * Error is a prop, not an interaction state: it recolours the border/bottom
60
+ * line to the destructive accent and out-ranks focus (an errored field stays
61
+ * red when focused — it never flips to the purple accent), so its border
62
+ * utilities are declared with matching-but-later specificity via the `error`
63
+ * variant below (a plain destructive border for the resting state plus a
64
+ * `focus-within:` destructive form that out-ranks the variation's
65
+ * `focus-within:` accent by class order).
66
+ *
67
+ * `showBottomLine` (LINE ONLY) toggles the resting visibility of the bottom
68
+ * line without any layout shift. The `border-b` (1px width) is ALWAYS present;
69
+ * only the border COLOUR changes. When `false`, a compound variant recolours
70
+ * the resting bottom line to `border-transparent` (invisible), while focus
71
+ * (`focus-within:border-input-border-accent`) and error still win — so the
72
+ * line reappears on focus and on error. The compound is gated on `error:false`
73
+ * so an errored field's destructive rest border is NOT overridden by
74
+ * transparent (tailwind-merge last-wins would otherwise drop it). On the
75
+ * `field` variation `showBottomLine` has NO effect: the compound is scoped to
76
+ * `variation:line`, so `field`'s box border is untouched.
77
+ */
78
+ declare const inputVariants: (props?: ({
79
+ variation?: "line" | "field" | null | undefined;
80
+ size?: "sm" | "lg" | null | undefined;
81
+ error?: boolean | null | undefined;
82
+ showBottomLine?: boolean | null | undefined;
83
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
84
+ type InputVariantsProps = VariantProps<typeof inputVariants>;
85
+
86
+ interface InputProps extends Omit<React.ComponentProps<"input">, "size">, Omit<InputVariantsProps, "error"> {
87
+ /**
88
+ * Uppercase label shown above the field. When omitted the label row is not
89
+ * rendered. Always paired with the `<input>` via generated `id`/`htmlFor`
90
+ * (or your own `id`), so the control is properly named for assistive tech.
91
+ */
92
+ label?: React.ReactNode;
93
+ /**
94
+ * Marks the field as not required — renders an "Optional" tag on the right of
95
+ * the label row (Figma). Has no effect without a `label`.
96
+ */
97
+ optional?: boolean;
98
+ /**
99
+ * Helper text shown below the field, with a leading 16px icon (info by
100
+ * default, warning when `error`). Linked to the input via `aria-describedby`.
101
+ */
102
+ hint?: React.ReactNode;
103
+ /**
104
+ * Error state (a prop, not an interaction state): sets `aria-invalid`, turns
105
+ * the label, border/bottom-line, icons and hint to the destructive accent,
106
+ * and swaps the hint icon to a warning.
107
+ */
108
+ error?: boolean;
109
+ /** Leading adornment (usually a 16px Phosphor icon). Decorative — kept out of the a11y tree via `aria-hidden`. */
110
+ leftSlot?: React.ReactNode;
111
+ /**
112
+ * Trailing adornment. Usually a 16px Phosphor icon (decorative), but MAY be an
113
+ * interactive control (e.g. SearchBar's clear `<button>`). The wrapper is NOT
114
+ * `aria-hidden` (that would hide a focusable child from assistive tech — an
115
+ * ARIA violation); decorative bare `<svg>` icons are silent to AT on their own
116
+ * (no role, no accessible name), so they stay unannounced without it. An
117
+ * interactive control placed here must carry its own accessible name.
118
+ */
119
+ rightSlot?: React.ReactNode;
120
+ /** Class names for the outer wrapper (the vertical label/field/hint stack). */
121
+ wrapperClassName?: string;
122
+ /** Class names for the field row (border/background box), not the `<input>`. */
123
+ fieldClassName?: string;
124
+ /**
125
+ * Toggles the resting visibility of the bottom line on the **`line`**
126
+ * variation only. Default `true` (line visible at rest). When `false`, the
127
+ * bottom line is hidden at rest (recoloured to transparent) but still appears
128
+ * on focus (accent) and on error (destructive); the 1px `border-b` is kept in
129
+ * all cases so there is no layout shift — only the border colour changes.
130
+ *
131
+ * Has NO effect on the `field` variation (its box border is out of scope).
132
+ */
133
+ showBottomLine?: boolean;
134
+ }
135
+ /**
136
+ * Text input — the Figma `BaseInput` component (node 4973:6816), rendered as a
137
+ * real `<input>` wrapped in a field row with optional `leftSlot`/`rightSlot`
138
+ * icon slots, an optional uppercase label row, and an optional hint message.
139
+ *
140
+ * Follows the ADR-0010 form-control conventions: the native `<input>` is the
141
+ * single source of truth (uncontrolled `defaultValue` or controlled
142
+ * `value` + `onChange`); the component holds no React state. `ref` is a normal
143
+ * prop (React 19). Not `asChild` — the root must stay a void, platform-behaviour
144
+ * -bearing `<input>` (ADR-0010).
145
+ *
146
+ * Two independent axes (4 combinations): `variation` (`field` bordered box /
147
+ * `line` bottom-border-only) × `size` (`sm` / `lg`, reusing the sibling scale).
148
+ * The Figma "states" (hover/focus/filled) are runtime DOM states: hover is an
149
+ * I-beam cursor affordance only (no colour change), focus recolours the border
150
+ * via `focus-within:` (no system outline ring — a user-authorized exception to
151
+ * ADR-0010 #4 / ADR-0011, see `inputVariants.ts`), and filled shows the typed-
152
+ * text colour. Only `disabled` (native attribute) and `error` (prop) are real
153
+ * props.
154
+ */
155
+ declare function Input({ className, fieldClassName, wrapperClassName, variation, size, error, showBottomLine, label, optional, hint, leftSlot, rightSlot, disabled, id: idProp, ref, ...props }: InputProps): React.JSX.Element;
156
+
157
+ export { Input, type InputProps, type InputVariantsProps, inputVariants };