@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,48 @@
1
+ import * as React from 'react';
2
+ import * as class_variance_authority_types from 'class-variance-authority/types';
3
+
4
+ interface ToastProps extends Omit<React.ComponentProps<"div">, "children"> {
5
+ /**
6
+ * Status. `success` → a polite `role="status"` region; `error` → an
7
+ * assertive `role="alert"` region. Also selects the leading icon + its color.
8
+ */
9
+ variation?: "success" | "error";
10
+ /** The message body (`body-03`). */
11
+ children: React.ReactNode;
12
+ /**
13
+ * Dismiss handler. When provided, the trailing close button is rendered and
14
+ * wired to it; omit it for a toast with no close affordance.
15
+ */
16
+ onClose?: () => void;
17
+ /** Ref forwarded to the root element. */
18
+ ref?: React.Ref<HTMLDivElement>;
19
+ }
20
+ /**
21
+ * Toast — the Figma `Toast` (node `5020:2203`). A presentational dark
22
+ * notification chip: a leading status icon, a message, and an optional close
23
+ * button. It is a live region (`role="status"` for success, `role="alert"` for
24
+ * error) so it announces when mounted; positioning, stacking, and auto-dismiss
25
+ * are the consumer's concern (there is no toast manager here).
26
+ */
27
+ declare function Toast({ variation, children, onClose, className, ref, ...props }: ToastProps): React.JSX.Element;
28
+
29
+ /**
30
+ * Toast styling — the Figma `Toast` (node `5020:2203`). Binds ONLY to the
31
+ * semantic token layer (never primitives); theme switching is automatic via
32
+ * `.dark`, so no `dark:` variants. The surface is the fixed dark "reversed"
33
+ * card, so the root is not variation-dependent — only the leading status
34
+ * icon's color changes with `variation`.
35
+ */
36
+ /** Root row — dark reversed surface; identical for both variations. */
37
+ declare const toastVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
38
+ /** Leading 20px status icon slot; color per variation. */
39
+ declare const toastIconVariants: (props?: ({
40
+ variation?: "error" | "success" | null | undefined;
41
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
42
+ /**
43
+ * Trailing close button — muted, brightens on hover; shared ADR-0010 focus
44
+ * ring (`rounded-xs` so the ring follows the small hit area).
45
+ */
46
+ declare const toastCloseVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
47
+
48
+ export { Toast, type ToastProps, toastCloseVariants, toastIconVariants, toastVariants };
package/dist/toast.js ADDED
@@ -0,0 +1,2 @@
1
+ export { Toast, toastCloseVariants, toastIconVariants, toastVariants } from './chunk-N4VAP2GB.js';
2
+ import './chunk-7EOSDFS3.js';
@@ -0,0 +1,415 @@
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/token-input/TokenInput.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 Token({
128
+ value,
129
+ invalid = false,
130
+ disabled = false,
131
+ onRemove
132
+ }) {
133
+ return /* @__PURE__ */ jsxRuntime.jsxs(
134
+ "span",
135
+ {
136
+ "data-slot": "token",
137
+ "data-invalid": invalid || void 0,
138
+ tabIndex: disabled ? void 0 : 0,
139
+ onKeyDown: disabled ? void 0 : (event) => {
140
+ if (event.key === "Delete" || event.key === "Backspace") {
141
+ event.preventDefault();
142
+ onRemove("keyboard");
143
+ }
144
+ },
145
+ className: cn(
146
+ // `group` so the ✕ can react to the badge's hover/focus (see below).
147
+ // Height is exactly 22px = 20px (`body-03` line) + 2px border, with NO
148
+ // vertical padding: this keeps the field a constant 40px tall
149
+ // (badge 22 + 8+8 field padding + 1+1 field border = 40, empty or filled).
150
+ // Adding `py-*` here would push the field past 40px once tokens appear.
151
+ "group inline-flex items-center gap-1 min-w-5 rounded-sm border px-1",
152
+ // Default: neutral card border + background. Invalid: destructive accent
153
+ // recolour (there is no `card-destructive` token — reuse `input-destructive-*`).
154
+ invalid ? "border-input-destructive-border bg-card-background" : "border-card-border bg-card-background",
155
+ // Interactive chrome (only when not disabled): hover/focus fill to
156
+ // `card-accent` (the DS's "stronger/hover" step up from `card-background`)
157
+ // and the STANDARD ADR-0010/0012 focus ring on the whole badge — the ✕
158
+ // itself carries no ring. `cursor-default` overrides the field's I-beam
159
+ // so a badge doesn't read as "type here".
160
+ !disabled && "cursor-default hover:bg-card-accent focus-visible:bg-card-accent outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-focus"
161
+ ),
162
+ children: [
163
+ /* @__PURE__ */ jsxRuntime.jsx(
164
+ "span",
165
+ {
166
+ "data-slot": "token-label",
167
+ className: cn(
168
+ "body-03",
169
+ // Disabled wins over invalid: the Figma disabled badge (561:12782) is
170
+ // fully muted — a disabled field is inert, so no destructive red.
171
+ disabled ? "text-card-foreground-muted" : invalid ? "text-input-destructive-foreground-accent" : "text-card-foreground"
172
+ ),
173
+ children: value
174
+ }
175
+ ),
176
+ /* @__PURE__ */ jsxRuntime.jsx(
177
+ "button",
178
+ {
179
+ type: "button",
180
+ "aria-label": `Remove ${value}`,
181
+ onClick: () => onRemove("pointer"),
182
+ disabled,
183
+ tabIndex: -1,
184
+ "data-slot": "token-remove",
185
+ className: cn(
186
+ // Reset native button chrome.
187
+ "inline-flex cursor-pointer items-center justify-center rounded-xs bg-transparent p-0",
188
+ // Icon colour follows the badge state. Disabled wins (fully muted, no
189
+ // hover strengthen — the badge is inert). Valid: muted at rest,
190
+ // strengthens to `card-foreground` on badge hover/focus (via `group-*`).
191
+ // Invalid: stays destructive (a strengthen would drop the flag).
192
+ disabled ? "text-card-foreground-muted" : invalid ? "text-input-destructive-foreground-accent" : "text-card-foreground-muted group-hover:text-card-foreground group-focus-visible:text-card-foreground",
193
+ "disabled:cursor-not-allowed"
194
+ ),
195
+ children: /* @__PURE__ */ jsxRuntime.jsx(react.XIcon, { weight: "regular", "aria-hidden": "true", className: "size-4" })
196
+ }
197
+ )
198
+ ]
199
+ }
200
+ );
201
+ }
202
+ function splitOnSeparators(raw, separators) {
203
+ if (separators.length === 0) return [raw];
204
+ const escaped = separators.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("");
205
+ return raw.split(new RegExp(`[${escaped}]`));
206
+ }
207
+ function TokenInput({
208
+ className,
209
+ fieldClassName,
210
+ wrapperClassName,
211
+ value,
212
+ defaultValue,
213
+ onChange,
214
+ separators = [","],
215
+ commitOnBlur = false,
216
+ validate,
217
+ label,
218
+ optional = false,
219
+ hint,
220
+ error = false,
221
+ disabled,
222
+ placeholder,
223
+ id: idProp,
224
+ onKeyDown,
225
+ onBlur,
226
+ onInput,
227
+ ref,
228
+ ...props
229
+ }) {
230
+ const isControlled = value !== void 0;
231
+ const [tokensState, setTokensState] = React__namespace.useState(
232
+ () => defaultValue ?? []
233
+ );
234
+ const tokens = isControlled ? value : tokensState;
235
+ const innerRef = React__namespace.useRef(null);
236
+ const setInputRef = React__namespace.useCallback(
237
+ (node) => {
238
+ innerRef.current = node;
239
+ if (typeof ref === "function") ref(node);
240
+ else if (ref)
241
+ ref.current = node;
242
+ },
243
+ [ref]
244
+ );
245
+ const generatedId = React__namespace.useId();
246
+ const id = idProp ?? generatedId;
247
+ const hintId = hint ? `${id}-hint` : void 0;
248
+ const commitTokens = (next) => {
249
+ if (!isControlled) setTokensState(next);
250
+ onChange?.(next);
251
+ };
252
+ const addTokens = (pieces) => {
253
+ const next = [...tokens];
254
+ const seen = new Set(next.map((t) => t.toLowerCase()));
255
+ let changed = false;
256
+ for (const piece of pieces) {
257
+ const trimmed = piece.trim();
258
+ if (trimmed === "") continue;
259
+ const key = trimmed.toLowerCase();
260
+ if (seen.has(key)) continue;
261
+ seen.add(key);
262
+ next.push(trimmed);
263
+ changed = true;
264
+ }
265
+ if (changed) commitTokens(next);
266
+ };
267
+ const removeTokenAt = (index, origin) => {
268
+ commitTokens(tokens.filter((_, i) => i !== index));
269
+ if (origin === "keyboard") innerRef.current?.focus();
270
+ };
271
+ const handleInput = (event) => {
272
+ onInput?.(event);
273
+ const input = event.currentTarget;
274
+ const raw = input.value;
275
+ if (separators.some((sep) => raw.includes(sep))) {
276
+ addTokens(splitOnSeparators(raw, separators));
277
+ input.value = "";
278
+ }
279
+ };
280
+ const handleKeyDown = (event) => {
281
+ onKeyDown?.(event);
282
+ if (event.key === "Backspace" && event.currentTarget.value === "" && tokens.length > 0) {
283
+ event.preventDefault();
284
+ removeTokenAt(tokens.length - 1);
285
+ }
286
+ };
287
+ const handleBlur = (event) => {
288
+ onBlur?.(event);
289
+ if (commitOnBlur) {
290
+ const input = event.currentTarget;
291
+ if (input.value.trim() !== "") {
292
+ addTokens([input.value]);
293
+ input.value = "";
294
+ }
295
+ }
296
+ };
297
+ const handleFieldMouseDown = (event) => {
298
+ const target = event.target;
299
+ if (target.closest("[data-slot=token]")) return;
300
+ if (target === innerRef.current) return;
301
+ event.preventDefault();
302
+ innerRef.current?.focus();
303
+ };
304
+ const iconStateClass = cn(
305
+ error ? "text-input-destructive-foreground-accent" : "text-input-foreground",
306
+ disabled && "text-input-foreground-muted"
307
+ );
308
+ const HintIcon = error ? react.WarningIcon : react.InfoIcon;
309
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1.5", wrapperClassName), children: [
310
+ label != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
311
+ /* @__PURE__ */ jsxRuntime.jsx(
312
+ "label",
313
+ {
314
+ htmlFor: id,
315
+ "data-slot": "input-label",
316
+ className: cn(
317
+ "caption-03-medium uppercase",
318
+ error ? "text-input-destructive-foreground-accent" : "text-input-foreground",
319
+ disabled && "text-input-foreground-muted"
320
+ ),
321
+ children: label
322
+ }
323
+ ),
324
+ optional && /* @__PURE__ */ jsxRuntime.jsx(
325
+ "span",
326
+ {
327
+ "data-slot": "input-optional",
328
+ className: "body-04 text-input-foreground-muted",
329
+ children: "Optional"
330
+ }
331
+ )
332
+ ] }),
333
+ /* @__PURE__ */ jsxRuntime.jsxs(
334
+ "div",
335
+ {
336
+ "data-slot": "token-input-field",
337
+ "data-error": error || void 0,
338
+ onMouseDown: handleFieldMouseDown,
339
+ className: cn(
340
+ // Reuse Input's field styling (bg/border/rounded/focus-within/error).
341
+ inputVariants({ variation: "field", size: "lg", error }),
342
+ // Layout overrides (tailwind-merge last-wins): grow with wrapped rows,
343
+ // keep single-row min height, allow badges + input to wrap, uniform
344
+ // spacing/2 inset (overrides field-lg's px-3 py-2).
345
+ "h-auto min-h-10 flex-wrap gap-1 p-2",
346
+ // Icon slots inherit the shared state colour.
347
+ iconStateClass,
348
+ fieldClassName
349
+ ),
350
+ children: [
351
+ tokens.map((token, index) => /* @__PURE__ */ jsxRuntime.jsx(
352
+ Token,
353
+ {
354
+ value: token,
355
+ invalid: validate ? !validate(token) : false,
356
+ disabled,
357
+ onRemove: (origin) => removeTokenAt(index, origin)
358
+ },
359
+ `${token}-${index}`
360
+ )),
361
+ /* @__PURE__ */ jsxRuntime.jsx(
362
+ "input",
363
+ {
364
+ id,
365
+ "data-slot": "token-input",
366
+ disabled,
367
+ placeholder: tokens.length === 0 ? placeholder : void 0,
368
+ "aria-invalid": error || void 0,
369
+ "aria-describedby": hintId,
370
+ className: cn(
371
+ // Typography + grow to fill remaining row width. `min-w-0` lets the
372
+ // input shrink; a small basis keeps it usable when tokens wrap.
373
+ "body-03 w-0 min-w-16 flex-1 bg-transparent outline-none",
374
+ "text-input-foreground-accent caret-input-foreground-accent",
375
+ "placeholder:text-input-foreground-muted",
376
+ "disabled:cursor-not-allowed disabled:text-input-foreground-muted",
377
+ className
378
+ ),
379
+ ref: setInputRef,
380
+ onInput: handleInput,
381
+ onKeyDown: handleKeyDown,
382
+ onBlur: handleBlur,
383
+ ...props
384
+ }
385
+ )
386
+ ]
387
+ }
388
+ ),
389
+ hint != null && /* @__PURE__ */ jsxRuntime.jsxs(
390
+ "p",
391
+ {
392
+ id: hintId,
393
+ "data-slot": "input-hint",
394
+ className: cn(
395
+ "body-04 flex items-center gap-1",
396
+ error ? "text-input-destructive-foreground-accent" : "text-input-foreground",
397
+ disabled && "text-input-foreground-muted"
398
+ ),
399
+ children: [
400
+ /* @__PURE__ */ jsxRuntime.jsx(
401
+ HintIcon,
402
+ {
403
+ "aria-hidden": "true",
404
+ weight: "regular",
405
+ className: "size-4 shrink-0"
406
+ }
407
+ ),
408
+ hint
409
+ ]
410
+ }
411
+ )
412
+ ] });
413
+ }
414
+
415
+ exports.TokenInput = TokenInput;
@@ -0,0 +1,90 @@
1
+ import * as React from 'react';
2
+
3
+ interface TokenInputProps extends Omit<React.ComponentProps<"input">, "size" | "value" | "defaultValue" | "onChange"> {
4
+ /**
5
+ * Committed tokens (controlled). Pair with `onChange`. When provided, the
6
+ * component does not hold its own token state — the parent owns the array.
7
+ */
8
+ value?: string[];
9
+ /**
10
+ * Initial committed tokens (uncontrolled). Seeds the internal token state;
11
+ * ignored once `value` is provided (controlled mode).
12
+ */
13
+ defaultValue?: string[];
14
+ /**
15
+ * Fires whenever a token is added or removed, with the full next tokens array.
16
+ * The in-progress draft text lives in the native `<input>` and is NOT reported
17
+ * here — the component's value is the committed tokens array.
18
+ */
19
+ onChange?: (tokens: string[]) => void;
20
+ /**
21
+ * Characters that commit the current draft into token(s). Default `[","]`.
22
+ * When the draft contains any of these chars it is split on all of them,
23
+ * trimmed, empties dropped, case-insensitive duplicates dropped, then pushed.
24
+ * No key other than a separator commits (Enter never commits).
25
+ */
26
+ separators?: string[];
27
+ /**
28
+ * Opt-in: commit a non-empty trailing draft as one token on blur. Default
29
+ * `false` (strict separator-only commit). Useful so a form never loses a
30
+ * half-typed trailing entry.
31
+ */
32
+ commitOnBlur?: boolean;
33
+ /**
34
+ * Optional per-token predicate. Default `undefined` = no validation, nothing
35
+ * is ever flagged (the generic component accepts anything). When provided,
36
+ * tokens failing it are KEPT but flagged destructive ("flag but allow") and
37
+ * expose `data-invalid`. The DS ships no domain-specific validator.
38
+ */
39
+ validate?: (token: string) => boolean;
40
+ /**
41
+ * Uppercase label shown above the field. When omitted the label row is not
42
+ * rendered. Paired with the `<input>` via generated `id`/`htmlFor` (or your
43
+ * own `id`) so the control is properly named for assistive tech.
44
+ */
45
+ label?: React.ReactNode;
46
+ /**
47
+ * Marks the field as not required — renders an "Optional" tag on the right of
48
+ * the label row (Figma). Has no effect without a `label`.
49
+ */
50
+ optional?: boolean;
51
+ /**
52
+ * Helper text shown below the field, with a leading 16px icon (info by
53
+ * default, warning when `error`). Linked to the input via `aria-describedby`.
54
+ */
55
+ hint?: React.ReactNode;
56
+ /**
57
+ * Field-level error state (distinct from per-token invalid flagging): sets
58
+ * `aria-invalid`, turns the label, border, icon and hint to the destructive
59
+ * accent, and swaps the hint icon to a warning — exactly as Input's `error`.
60
+ */
61
+ error?: boolean;
62
+ /** Class names for the outer wrapper (the vertical label/field/hint stack). */
63
+ wrapperClassName?: string;
64
+ /** Class names for the field row (border/background box), not the `<input>`. */
65
+ fieldClassName?: string;
66
+ }
67
+ /**
68
+ * TokenInput — a domain-agnostic token / tag input. As the user types, text
69
+ * commits into removable badges (tokens) on a configurable separator (default
70
+ * comma). The DS ships it knowing NOTHING about emails or any other domain:
71
+ * validation, copy and separators are all supplied at the call site (mirrors
72
+ * SearchBar-over-Input layering — ship the generic primitive, let the app
73
+ * specialize it).
74
+ *
75
+ * Composition — "reuse variants only": TokenInput does NOT render <Input> (its
76
+ * badges wrap inside the field and its leading slot is decorative-by-contract).
77
+ * It reuses `inputVariants({ variation: "field", size: "lg", error })` — the
78
+ * hard-to-duplicate token/focus/error handling — and overrides layout only via
79
+ * `cn` (tailwind-merge last-wins): `h-auto min-h-10 flex-wrap p-2`. The thin
80
+ * label + hint rows are replicated locally, matching Input's exact classes. The
81
+ * `field`/`lg` axes are fixed and NOT exposed as props (per the Figma scope).
82
+ *
83
+ * Value model: committed tokens are a `string[]` (controlled `value`+`onChange`
84
+ * or uncontrolled `defaultValue`); the draft lives in the native `<input>` (the
85
+ * source of truth for the in-progress text), read via a merged `ref`. `ref`
86
+ * forwards to the `<input>`.
87
+ */
88
+ declare function TokenInput({ className, fieldClassName, wrapperClassName, value, defaultValue, onChange, separators, commitOnBlur, validate, label, optional, hint, error, disabled, placeholder, id: idProp, onKeyDown, onBlur, onInput, ref, ...props }: TokenInputProps): React.JSX.Element;
89
+
90
+ export { TokenInput, type TokenInputProps };
@@ -0,0 +1,90 @@
1
+ import * as React from 'react';
2
+
3
+ interface TokenInputProps extends Omit<React.ComponentProps<"input">, "size" | "value" | "defaultValue" | "onChange"> {
4
+ /**
5
+ * Committed tokens (controlled). Pair with `onChange`. When provided, the
6
+ * component does not hold its own token state — the parent owns the array.
7
+ */
8
+ value?: string[];
9
+ /**
10
+ * Initial committed tokens (uncontrolled). Seeds the internal token state;
11
+ * ignored once `value` is provided (controlled mode).
12
+ */
13
+ defaultValue?: string[];
14
+ /**
15
+ * Fires whenever a token is added or removed, with the full next tokens array.
16
+ * The in-progress draft text lives in the native `<input>` and is NOT reported
17
+ * here — the component's value is the committed tokens array.
18
+ */
19
+ onChange?: (tokens: string[]) => void;
20
+ /**
21
+ * Characters that commit the current draft into token(s). Default `[","]`.
22
+ * When the draft contains any of these chars it is split on all of them,
23
+ * trimmed, empties dropped, case-insensitive duplicates dropped, then pushed.
24
+ * No key other than a separator commits (Enter never commits).
25
+ */
26
+ separators?: string[];
27
+ /**
28
+ * Opt-in: commit a non-empty trailing draft as one token on blur. Default
29
+ * `false` (strict separator-only commit). Useful so a form never loses a
30
+ * half-typed trailing entry.
31
+ */
32
+ commitOnBlur?: boolean;
33
+ /**
34
+ * Optional per-token predicate. Default `undefined` = no validation, nothing
35
+ * is ever flagged (the generic component accepts anything). When provided,
36
+ * tokens failing it are KEPT but flagged destructive ("flag but allow") and
37
+ * expose `data-invalid`. The DS ships no domain-specific validator.
38
+ */
39
+ validate?: (token: string) => boolean;
40
+ /**
41
+ * Uppercase label shown above the field. When omitted the label row is not
42
+ * rendered. Paired with the `<input>` via generated `id`/`htmlFor` (or your
43
+ * own `id`) so the control is properly named for assistive tech.
44
+ */
45
+ label?: React.ReactNode;
46
+ /**
47
+ * Marks the field as not required — renders an "Optional" tag on the right of
48
+ * the label row (Figma). Has no effect without a `label`.
49
+ */
50
+ optional?: boolean;
51
+ /**
52
+ * Helper text shown below the field, with a leading 16px icon (info by
53
+ * default, warning when `error`). Linked to the input via `aria-describedby`.
54
+ */
55
+ hint?: React.ReactNode;
56
+ /**
57
+ * Field-level error state (distinct from per-token invalid flagging): sets
58
+ * `aria-invalid`, turns the label, border, icon and hint to the destructive
59
+ * accent, and swaps the hint icon to a warning — exactly as Input's `error`.
60
+ */
61
+ error?: boolean;
62
+ /** Class names for the outer wrapper (the vertical label/field/hint stack). */
63
+ wrapperClassName?: string;
64
+ /** Class names for the field row (border/background box), not the `<input>`. */
65
+ fieldClassName?: string;
66
+ }
67
+ /**
68
+ * TokenInput — a domain-agnostic token / tag input. As the user types, text
69
+ * commits into removable badges (tokens) on a configurable separator (default
70
+ * comma). The DS ships it knowing NOTHING about emails or any other domain:
71
+ * validation, copy and separators are all supplied at the call site (mirrors
72
+ * SearchBar-over-Input layering — ship the generic primitive, let the app
73
+ * specialize it).
74
+ *
75
+ * Composition — "reuse variants only": TokenInput does NOT render <Input> (its
76
+ * badges wrap inside the field and its leading slot is decorative-by-contract).
77
+ * It reuses `inputVariants({ variation: "field", size: "lg", error })` — the
78
+ * hard-to-duplicate token/focus/error handling — and overrides layout only via
79
+ * `cn` (tailwind-merge last-wins): `h-auto min-h-10 flex-wrap p-2`. The thin
80
+ * label + hint rows are replicated locally, matching Input's exact classes. The
81
+ * `field`/`lg` axes are fixed and NOT exposed as props (per the Figma scope).
82
+ *
83
+ * Value model: committed tokens are a `string[]` (controlled `value`+`onChange`
84
+ * or uncontrolled `defaultValue`); the draft lives in the native `<input>` (the
85
+ * source of truth for the in-progress text), read via a merged `ref`. `ref`
86
+ * forwards to the `<input>`.
87
+ */
88
+ declare function TokenInput({ className, fieldClassName, wrapperClassName, value, defaultValue, onChange, separators, commitOnBlur, validate, label, optional, hint, error, disabled, placeholder, id: idProp, onKeyDown, onBlur, onInput, ref, ...props }: TokenInputProps): React.JSX.Element;
89
+
90
+ export { TokenInput, type TokenInputProps };
@@ -0,0 +1,3 @@
1
+ export { TokenInput } from './chunk-E6KPNTWW.js';
2
+ import './chunk-IEVN3J2F.js';
3
+ import './chunk-7EOSDFS3.js';