@carbonbits/sixr 1.4.0 → 1.5.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 (56) hide show
  1. package/README.md +139 -60
  2. package/dist/button.cjs +223 -0
  3. package/dist/button.cjs.map +1 -0
  4. package/dist/button.d.cts +34 -0
  5. package/dist/button.d.ts +34 -0
  6. package/dist/button.js +4 -0
  7. package/dist/button.js.map +1 -0
  8. package/dist/chunk-HDTW4FRT.js +111 -0
  9. package/dist/chunk-HDTW4FRT.js.map +1 -0
  10. package/dist/email-input.cjs +213 -170
  11. package/dist/email-input.cjs.map +1 -1
  12. package/dist/email-input.d.cts +4 -6
  13. package/dist/email-input.d.ts +4 -6
  14. package/dist/email-input.js +219 -170
  15. package/dist/email-input.js.map +1 -1
  16. package/dist/field.cjs +206 -0
  17. package/dist/field.cjs.map +1 -0
  18. package/dist/field.d.cts +80 -0
  19. package/dist/field.d.ts +80 -0
  20. package/dist/field.js +186 -0
  21. package/dist/field.js.map +1 -0
  22. package/dist/form.cjs +283 -42
  23. package/dist/form.cjs.map +1 -1
  24. package/dist/form.d.cts +79 -10
  25. package/dist/form.d.ts +79 -10
  26. package/dist/form.js +285 -45
  27. package/dist/form.js.map +1 -1
  28. package/dist/index-CdYkd6zz.d.cts +22 -0
  29. package/dist/index-CdYkd6zz.d.ts +22 -0
  30. package/dist/index.cjs +138 -34
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +116 -55
  33. package/dist/index.d.ts +116 -55
  34. package/dist/index.js +1 -0
  35. package/dist/password-input.cjs +217 -174
  36. package/dist/password-input.cjs.map +1 -1
  37. package/dist/password-input.d.cts +2 -3
  38. package/dist/password-input.d.ts +2 -3
  39. package/dist/password-input.js +222 -173
  40. package/dist/password-input.js.map +1 -1
  41. package/dist/phone-input.cjs +213 -170
  42. package/dist/phone-input.cjs.map +1 -1
  43. package/dist/phone-input.d.cts +5 -5
  44. package/dist/phone-input.d.ts +5 -5
  45. package/dist/phone-input.js +219 -170
  46. package/dist/phone-input.js.map +1 -1
  47. package/dist/styles.css +1 -1
  48. package/dist/text-input.cjs +213 -170
  49. package/dist/text-input.cjs.map +1 -1
  50. package/dist/text-input.d.cts +2 -3
  51. package/dist/text-input.d.ts +2 -3
  52. package/dist/text-input.js +219 -170
  53. package/dist/text-input.js.map +1 -1
  54. package/package.json +26 -2
  55. package/dist/index-DwjxC4l4.d.cts +0 -62
  56. package/dist/index-DwjxC4l4.d.ts +0 -62
@@ -25,85 +25,177 @@ __export(password_input_exports, {
25
25
  PasswordInput: () => PasswordInput
26
26
  });
27
27
  module.exports = __toCommonJS(password_input_exports);
28
- var import_react3 = require("react");
28
+ var import_react2 = require("react");
29
29
 
30
30
  // src/components/field/index.tsx
31
31
  var import_react_label = require("@radix-ui/react-label");
32
- var import_react2 = require("react");
33
-
34
- // src/components/field/use-field-behaviour.ts
32
+ var import_react_slot = require("@radix-ui/react-slot");
35
33
  var import_react = require("react");
36
- var FALLBACK_MESSAGE = "Invalid value";
37
- function runSchema(schema, value) {
38
- if (!schema) {
39
- return { valid: true };
40
- }
41
- const result = schema.safeParse(value);
42
- if (result.success) {
43
- return { valid: true };
34
+ var import_react_hook_form = require("react-hook-form");
35
+ var import_jsx_runtime = require("react/jsx-runtime");
36
+ var FieldContext = (0, import_react.createContext)(null);
37
+ function useFieldContext() {
38
+ const context = (0, import_react.useContext)(FieldContext);
39
+ if (!context) {
40
+ throw new Error("Field primitives must be rendered inside FieldRoot");
44
41
  }
42
+ return context;
43
+ }
44
+ function useFieldIds(id) {
45
+ const generated = (0, import_react.useId)();
46
+ const base = id ?? generated;
45
47
  return {
46
- valid: false,
47
- error: result.error.issues[0]?.message ?? FALLBACK_MESSAGE
48
+ id: base,
49
+ descriptionId: `${base}-description`,
50
+ messageId: `${base}-message`
48
51
  };
49
52
  }
50
- function useFieldBehaviour({
53
+ function FieldShell({
51
54
  value,
52
- defaultValue,
53
- error,
54
- onChange,
55
- onBlur,
56
- schema,
57
- validateOn = "blur",
58
- onValidationChange
55
+ asChild = false,
56
+ children,
57
+ ...rest
59
58
  }) {
60
- const [uncontrolledValue, setUncontrolledValue] = (0, import_react.useState)(
61
- defaultValue ?? ""
62
- );
63
- const [schemaError, setSchemaError] = (0, import_react.useState)(void 0);
64
- const isControlled = value !== void 0;
65
- const validate = (0, import_react.useCallback)(
66
- (next) => {
67
- const state = runSchema(schema, next);
68
- setSchemaError(state.error);
69
- onValidationChange?.(state);
70
- },
71
- [schema, onValidationChange]
59
+ const [hasDescription, setHasDescription] = (0, import_react.useState)(false);
60
+ const Component = asChild ? import_react_slot.Slot : "div";
61
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
62
+ FieldContext.Provider,
63
+ {
64
+ value: { ...value, hasDescription, setHasDescription },
65
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
66
+ Component,
67
+ {
68
+ ...rest,
69
+ "data-invalid": value.invalid ? "" : void 0,
70
+ "data-disabled": value.disabled ? "" : void 0,
71
+ children
72
+ }
73
+ )
74
+ }
72
75
  );
73
- const handleChange = (0, import_react.useCallback)(
74
- (event) => {
75
- const next = event.target.value;
76
- if (!isControlled) {
77
- setUncontrolledValue(next);
78
- }
79
- onChange?.(next);
80
- if (validateOn === "change" || validateOn === "blur" && schemaError) {
81
- validate(next);
76
+ }
77
+ function ConnectedFieldRoot({
78
+ name,
79
+ error,
80
+ required = false,
81
+ disabled = false,
82
+ id,
83
+ ...rest
84
+ }) {
85
+ const ids = useFieldIds(id);
86
+ const { field, fieldState } = (0, import_react_hook_form.useController)({ name, disabled });
87
+ const shownError = error ?? fieldState.error?.message;
88
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
89
+ FieldShell,
90
+ {
91
+ ...rest,
92
+ value: {
93
+ ...ids,
94
+ name,
95
+ error: shownError,
96
+ invalid: Boolean(shownError),
97
+ required,
98
+ disabled: Boolean(field.disabled ?? disabled),
99
+ bindings: {
100
+ name: field.name,
101
+ value: field.value ?? "",
102
+ onChange: field.onChange,
103
+ onBlur: field.onBlur,
104
+ ref: field.ref
105
+ }
82
106
  }
83
- },
84
- [isControlled, onChange, validateOn, schemaError, validate]
107
+ }
85
108
  );
86
- const handleBlur = (0, import_react.useCallback)(
87
- (event) => {
88
- if (validateOn === "blur") {
89
- validate(event.target.value);
109
+ }
110
+ function StandaloneFieldRoot({
111
+ name,
112
+ error,
113
+ required = false,
114
+ disabled = false,
115
+ id,
116
+ ...rest
117
+ }) {
118
+ const ids = useFieldIds(id);
119
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
120
+ FieldShell,
121
+ {
122
+ ...rest,
123
+ value: {
124
+ ...ids,
125
+ name,
126
+ error,
127
+ invalid: Boolean(error),
128
+ required,
129
+ disabled,
130
+ bindings: { name }
90
131
  }
91
- onBlur?.(event);
92
- },
93
- [validateOn, validate, onBlur]
132
+ }
94
133
  );
95
- return {
96
- currentValue: isControlled ? value : uncontrolledValue,
97
- // A caller-supplied error outranks the schema's verdict.
98
- shownError: error ?? schemaError,
99
- handleChange,
100
- handleBlur
134
+ }
135
+ function FieldRoot(props) {
136
+ const form = (0, import_react_hook_form.useFormContext)();
137
+ return form ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConnectedFieldRoot, { ...props }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StandaloneFieldRoot, { ...props });
138
+ }
139
+ function FieldLabel(props) {
140
+ const { id } = useFieldContext();
141
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_label.Label, { ...props, htmlFor: id });
142
+ }
143
+ function describedBy({
144
+ error,
145
+ messageId,
146
+ hasDescription,
147
+ descriptionId
148
+ }) {
149
+ if (error) {
150
+ return messageId;
151
+ }
152
+ return hasDescription ? descriptionId : void 0;
153
+ }
154
+ function FieldControl(props) {
155
+ const context = useFieldContext();
156
+ const { id, invalid, required, disabled, bindings } = context;
157
+ const controlProps = {
158
+ ...bindings,
159
+ id,
160
+ "aria-invalid": invalid || void 0,
161
+ "aria-required": required || void 0,
162
+ "aria-describedby": describedBy(context),
163
+ disabled: disabled || void 0
101
164
  };
165
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_slot.Slot, { ...props, ...controlProps });
166
+ }
167
+ function FieldDescription({
168
+ asChild = false,
169
+ ...props
170
+ }) {
171
+ const { descriptionId, error, setHasDescription } = useFieldContext();
172
+ (0, import_react.useEffect)(() => {
173
+ setHasDescription(true);
174
+ return () => setHasDescription(false);
175
+ }, [setHasDescription]);
176
+ if (error) {
177
+ return null;
178
+ }
179
+ const Component = asChild ? import_react_slot.Slot : "p";
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, id: descriptionId });
181
+ }
182
+ function FieldMessage({
183
+ asChild = false,
184
+ children,
185
+ ...props
186
+ }) {
187
+ const { messageId, error } = useFieldContext();
188
+ const content = error ?? children;
189
+ if (!content) {
190
+ return null;
191
+ }
192
+ const Component = asChild ? import_react_slot.Slot : "p";
193
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, id: messageId, role: "alert", children: content });
102
194
  }
103
195
 
104
196
  // src/components/typography/index.tsx
105
- var import_react_slot = require("@radix-ui/react-slot");
106
- var import_jsx_runtime = require("react/jsx-runtime");
197
+ var import_react_slot2 = require("@radix-ui/react-slot");
198
+ var import_jsx_runtime2 = require("react/jsx-runtime");
107
199
  var DEFAULT_ELEMENT = {
108
200
  display: "h1",
109
201
  heading: "h2",
@@ -190,14 +282,14 @@ function Typography({
190
282
  ...rest
191
283
  }) {
192
284
  const hasIcon = icon !== void 0 && icon !== null;
193
- const Component = asChild ? import_react_slot.Slot : as ?? DEFAULT_ELEMENT[variant];
194
- const iconNode = hasIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", className: ICON_CLASSES, children: icon }) : null;
195
- const content = hasIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
285
+ const Component = asChild ? import_react_slot2.Slot : as ?? DEFAULT_ELEMENT[variant];
286
+ const iconNode = hasIcon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", className: ICON_CLASSES, children: icon }) : null;
287
+ const content = hasIcon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
196
288
  iconPosition === "leading" ? iconNode : null,
197
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: truncate ? "min-w-0 truncate" : void 0, children }),
289
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: truncate ? "min-w-0 truncate" : void 0, children }),
198
290
  iconPosition === "trailing" ? iconNode : null
199
291
  ] }) : children;
200
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
292
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
201
293
  Component,
202
294
  {
203
295
  ...rest,
@@ -215,38 +307,26 @@ function Typography({
215
307
  );
216
308
  }
217
309
 
218
- // src/components/field/index.tsx
219
- var import_jsx_runtime2 = require("react/jsx-runtime");
220
- var FIELD_CLASSES = "h-10 w-full rounded-field border bg-surface px-3 font-[inherit] text-field text-fg outline-none placeholder:text-fg-subtle disabled:cursor-not-allowed disabled:opacity-45";
310
+ // src/components/input/index.tsx
311
+ var import_jsx_runtime3 = require("react/jsx-runtime");
312
+ var CONTROL_CLASSES = "h-10 w-full rounded-field border bg-surface px-3 font-[inherit] text-field text-fg outline-none placeholder:text-fg-subtle disabled:cursor-not-allowed disabled:opacity-45";
221
313
  var VALID_CLASSES = "border-line focus:border-accent focus:ring-3 focus:ring-accent-soft";
222
314
  var INVALID_CLASSES = "border-danger focus:border-danger focus:ring-3 focus:ring-danger-soft";
223
- function fieldClassName(invalid, hasTrailing, className) {
224
- return [
225
- FIELD_CLASSES,
226
- invalid ? INVALID_CLASSES : VALID_CLASSES,
227
- hasTrailing ? "pr-16" : "",
228
- className ?? ""
229
- ].filter(Boolean).join(" ");
230
- }
231
- function FieldLabel({
232
- htmlFor,
315
+ function InputLabel({
233
316
  label,
234
317
  optional,
235
318
  action
236
319
  }) {
237
- if (!label) {
238
- return null;
239
- }
240
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
320
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
241
321
  Typography,
242
322
  {
243
323
  variant: "label",
244
324
  tone: "muted",
245
325
  className: "mb-1.5 flex items-center",
246
326
  asChild: true,
247
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_label.Label, { htmlFor, children: [
327
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(FieldLabel, { children: [
248
328
  label,
249
- optional ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
329
+ optional ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
250
330
  Typography,
251
331
  {
252
332
  as: "span",
@@ -257,114 +337,77 @@ function FieldLabel({
257
337
  children: "Optional"
258
338
  }
259
339
  ) : null,
260
- action ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ml-auto", children: action }) : null
340
+ action ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ml-auto", children: action }) : null
261
341
  ] })
262
342
  }
263
343
  );
264
344
  }
265
- function FieldMessage({
266
- id,
267
- error,
268
- hint
345
+ function InputControl({
346
+ hasTrailing,
347
+ className,
348
+ ...rest
269
349
  }) {
350
+ const { invalid } = useFieldContext();
351
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FieldControl, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
352
+ "input",
353
+ {
354
+ ...rest,
355
+ className: [
356
+ CONTROL_CLASSES,
357
+ invalid ? INVALID_CLASSES : VALID_CLASSES,
358
+ hasTrailing ? "pr-16" : "",
359
+ className ?? ""
360
+ ].filter(Boolean).join(" ")
361
+ }
362
+ ) });
363
+ }
364
+ function InputMessages({ hint }) {
365
+ const { error } = useFieldContext();
270
366
  if (error) {
271
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
272
- Typography,
273
- {
274
- as: "p",
275
- variant: "hint",
276
- tone: "danger",
277
- id,
278
- role: "alert",
279
- className: "mt-1.5",
280
- children: error
281
- }
282
- );
367
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Typography, { as: "p", variant: "hint", tone: "danger", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FieldMessage, { className: "mt-1.5" }) });
283
368
  }
284
369
  if (hint) {
285
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
286
- Typography,
287
- {
288
- as: "p",
289
- variant: "hint",
290
- tone: "subtle",
291
- id,
292
- className: "mt-1.5",
293
- children: hint
294
- }
295
- );
370
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Typography, { as: "p", variant: "hint", tone: "subtle", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FieldDescription, { className: "mt-1.5", children: hint }) });
296
371
  }
297
372
  return null;
298
373
  }
299
- function Field({
374
+ function InputField({
375
+ name,
300
376
  label,
301
377
  hint,
302
378
  error,
303
379
  optional = false,
304
380
  action,
305
381
  trailing,
306
- type,
307
- value,
308
- defaultValue,
309
- onChange,
310
- schema,
311
- validateOn = "blur",
312
- onValidationChange,
313
382
  id,
314
- className,
315
- onBlur,
383
+ disabled,
384
+ required,
385
+ type,
316
386
  ...rest
317
387
  }) {
318
- const generatedId = (0, import_react2.useId)();
319
- const inputId = id ?? generatedId;
320
- const describedById = `${inputId}-description`;
321
- const { currentValue, shownError, handleChange, handleBlur } = useFieldBehaviour({
322
- value,
323
- defaultValue,
324
- error,
325
- onChange,
326
- onBlur,
327
- schema,
328
- validateOn,
329
- onValidationChange
330
- });
331
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col", children: [
332
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
333
- FieldLabel,
334
- {
335
- htmlFor: inputId,
336
- label,
337
- optional,
338
- action
339
- }
340
- ),
341
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: trailing ? "relative" : void 0, children: [
342
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
343
- "input",
344
- {
345
- ...rest,
346
- id: inputId,
347
- type,
348
- value: currentValue,
349
- "aria-invalid": shownError ? true : void 0,
350
- "aria-describedby": shownError || hint ? describedById : void 0,
351
- onChange: handleChange,
352
- onBlur: handleBlur,
353
- className: fieldClassName(
354
- Boolean(shownError),
355
- Boolean(trailing),
356
- className
357
- )
358
- }
359
- ),
360
- trailing ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "absolute top-1/2 right-[9px] flex -translate-y-1/2 items-center text-hint font-semibold text-fg-subtle", children: trailing }) : null
361
- ] }),
362
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FieldMessage, { id: describedById, error: shownError, hint })
363
- ] });
388
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
389
+ FieldRoot,
390
+ {
391
+ name,
392
+ id,
393
+ error,
394
+ disabled,
395
+ required,
396
+ className: "flex flex-col",
397
+ children: [
398
+ label ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InputLabel, { label, optional, action }) : null,
399
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: trailing ? "relative" : void 0, children: [
400
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InputControl, { ...rest, type, hasTrailing: Boolean(trailing) }),
401
+ trailing ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute top-1/2 right-[9px] flex -translate-y-1/2 items-center font-semibold text-fg-subtle text-hint", children: trailing }) : null
402
+ ] }),
403
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InputMessages, { hint })
404
+ ]
405
+ }
406
+ );
364
407
  }
365
408
 
366
409
  // src/components/password-input/index.tsx
367
- var import_jsx_runtime3 = require("react/jsx-runtime");
410
+ var import_jsx_runtime4 = require("react/jsx-runtime");
368
411
  var DEFAULT_REVEAL_LABELS = { show: "Show", hide: "Hide" };
369
412
  var TOGGLE_CLASSES = "cursor-pointer rounded-field font-[inherit] text-hint font-semibold text-fg-subtle outline-none hover:text-fg focus-visible:ring-3 focus-visible:ring-accent-soft disabled:cursor-not-allowed";
370
413
  function PasswordInput({
@@ -373,12 +416,12 @@ function PasswordInput({
373
416
  autoComplete = "current-password",
374
417
  ...rest
375
418
  }) {
376
- const [revealed, setRevealed] = (0, import_react3.useState)(false);
377
- const toggleRevealed = (0, import_react3.useCallback)(
419
+ const [revealed, setRevealed] = (0, import_react2.useState)(false);
420
+ const toggleRevealed = (0, import_react2.useCallback)(
378
421
  () => setRevealed((current) => !current),
379
422
  []
380
423
  );
381
- const toggle = revealable ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
424
+ const toggle = revealable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
382
425
  "button",
383
426
  {
384
427
  type: "button",
@@ -389,8 +432,8 @@ function PasswordInput({
389
432
  children: revealed ? revealLabels.hide : revealLabels.show
390
433
  }
391
434
  ) : void 0;
392
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
393
- Field,
435
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
436
+ InputField,
394
437
  {
395
438
  ...rest,
396
439
  type: revealed ? "text" : "password",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/password-input/index.tsx","../src/components/field/index.tsx","../src/components/field/use-field-behaviour.ts","../src/components/typography/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { Field, type FieldProps } from \"@/components/field\";\n\nexport type {\n FieldSchema,\n FieldValidation,\n} from \"@/components/field\";\n\n/**\n * A password. Fixes `type=\"password\"` and owns the design's in-field peek\n * affordance, so the trailing slot is not exposed here — the toggle is it.\n */\nexport type PasswordInputProps = Omit<FieldProps, \"trailing\"> & {\n /** Show the \"Show\"/\"Hide\" toggle. On by default, as the design has it. */\n revealable?: boolean;\n /** Labels for the toggle, for localisation. */\n revealLabels?: { show: string; hide: string };\n};\n\nconst DEFAULT_REVEAL_LABELS = { show: \"Show\", hide: \"Hide\" };\n\nconst TOGGLE_CLASSES =\n \"cursor-pointer rounded-field font-[inherit] text-hint font-semibold text-fg-subtle outline-none hover:text-fg focus-visible:ring-3 focus-visible:ring-accent-soft disabled:cursor-not-allowed\";\n\nexport function PasswordInput({\n revealable = true,\n revealLabels = DEFAULT_REVEAL_LABELS,\n autoComplete = \"current-password\",\n ...rest\n}: PasswordInputProps) {\n const [revealed, setRevealed] = useState(false);\n const toggleRevealed = useCallback(\n () => setRevealed((current) => !current),\n [],\n );\n\n const toggle = revealable ? (\n <button\n type=\"button\"\n aria-pressed={revealed}\n aria-label={revealed ? \"Hide password\" : \"Show password\"}\n className={TOGGLE_CLASSES}\n onClick={toggleRevealed}\n >\n {revealed ? revealLabels.hide : revealLabels.show}\n </button>\n ) : undefined;\n\n return (\n <Field\n {...rest}\n type={revealed ? \"text\" : \"password\"}\n autoComplete={autoComplete}\n trailing={toggle}\n />\n );\n}\n","\"use client\";\n\nimport { Label } from \"@radix-ui/react-label\";\nimport { type InputHTMLAttributes, type ReactNode, useId } from \"react\";\nimport {\n type FieldSchema,\n type FieldValidation,\n useFieldBehaviour,\n} from \"@/components/field/use-field-behaviour\";\nimport { Typography } from \"@/components/typography\";\n\nexport type {\n FieldSchema,\n FieldValidation,\n} from \"@/components/field/use-field-behaviour\";\n\n/**\n * The single-line input behind `TextInput`, `EmailInput`, `PasswordInput` and\n * `PhoneInput`. Each of those fixes the `type` (and the keyboard, autocomplete\n * and validation defaults that go with it) and hands everything else here.\n *\n * Internal: this module has no subpath of its own. Consumers reach it through\n * the specialised inputs, and its shared types through the barrel.\n */\n\nexport type FieldType = \"text\" | \"email\" | \"password\" | \"tel\";\n\n/** Props every specialised input shares. `type` is fixed by the wrapper. */\nexport type FieldProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"onChange\" | \"value\" | \"defaultValue\" | \"type\"\n> & {\n label?: string;\n /** Guidance under the field. Replaced by the error message while invalid. */\n hint?: ReactNode;\n /**\n * Error supplied by the caller — a server-side or cross-field failure. Takes\n * precedence over the schema, so a form can hold a field invalid regardless\n * of what `schema` makes of the value on its own.\n */\n error?: string;\n /** Renders the design's muted \"Optional\" marker at the end of the label. */\n optional?: boolean;\n /** Trailing label slot, for affordances like the design's \"Forgot?\" link. */\n action?: ReactNode;\n /** Trailing in-field slot, for affordances like the design's password peek. */\n trailing?: ReactNode;\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n /**\n * Any zod schema that accepts a string. Only `safeParse` is used, so a\n * refined, transformed or preprocessed schema works as well as a plain one.\n */\n schema?: FieldSchema;\n /**\n * When the schema runs. `blur` — the default — avoids scolding someone\n * mid-keystroke; once a field has gone invalid it revalidates on every\n * keystroke so the message clears as soon as it is fixed.\n */\n validateOn?: \"blur\" | \"change\" | \"never\";\n onValidationChange?: (state: FieldValidation) => void;\n};\n\nconst FIELD_CLASSES =\n \"h-10 w-full rounded-field border bg-surface px-3 font-[inherit] text-field text-fg outline-none placeholder:text-fg-subtle disabled:cursor-not-allowed disabled:opacity-45\";\nconst VALID_CLASSES =\n \"border-line focus:border-accent focus:ring-3 focus:ring-accent-soft\";\nconst INVALID_CLASSES =\n \"border-danger focus:border-danger focus:ring-3 focus:ring-danger-soft\";\nfunction fieldClassName(\n invalid: boolean,\n hasTrailing: boolean,\n className: string | undefined,\n): string {\n return [\n FIELD_CLASSES,\n invalid ? INVALID_CLASSES : VALID_CLASSES,\n hasTrailing ? \"pr-16\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction FieldLabel({\n htmlFor,\n label,\n optional,\n action,\n}: {\n htmlFor: string;\n label: string | undefined;\n optional: boolean;\n action: ReactNode;\n}) {\n if (!label) {\n return null;\n }\n\n return (\n <Typography\n variant=\"label\"\n tone=\"muted\"\n className=\"mb-1.5 flex items-center\"\n asChild\n >\n <Label htmlFor={htmlFor}>\n {label}\n {optional ? (\n <Typography\n as=\"span\"\n variant=\"hint\"\n tone=\"subtle\"\n weight=\"semibold\"\n className=\"ml-auto\"\n >\n Optional\n </Typography>\n ) : null}\n {action ? <span className=\"ml-auto\">{action}</span> : null}\n </Label>\n </Typography>\n );\n}\n\nfunction FieldMessage({\n id,\n error,\n hint,\n}: {\n id: string;\n error: string | undefined;\n hint: ReactNode;\n}) {\n if (error) {\n return (\n <Typography\n as=\"p\"\n variant=\"hint\"\n tone=\"danger\"\n id={id}\n role=\"alert\"\n className=\"mt-1.5\"\n >\n {error}\n </Typography>\n );\n }\n\n if (hint) {\n return (\n <Typography\n as=\"p\"\n variant=\"hint\"\n tone=\"subtle\"\n id={id}\n className=\"mt-1.5\"\n >\n {hint}\n </Typography>\n );\n }\n\n return null;\n}\n\nexport type FieldComponentProps = FieldProps & { type: FieldType };\n\nexport function Field({\n label,\n hint,\n error,\n optional = false,\n action,\n trailing,\n type,\n value,\n defaultValue,\n onChange,\n schema,\n validateOn = \"blur\",\n onValidationChange,\n id,\n className,\n onBlur,\n ...rest\n}: FieldComponentProps) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const describedById = `${inputId}-description`;\n\n const { currentValue, shownError, handleChange, handleBlur } =\n useFieldBehaviour({\n value,\n defaultValue,\n error,\n onChange,\n onBlur,\n schema,\n validateOn,\n onValidationChange,\n });\n\n return (\n <div className=\"flex flex-col\">\n <FieldLabel\n htmlFor={inputId}\n label={label}\n optional={optional}\n action={action}\n />\n\n <div className={trailing ? \"relative\" : undefined}>\n <input\n {...rest}\n id={inputId}\n type={type}\n value={currentValue}\n aria-invalid={shownError ? true : undefined}\n aria-describedby={shownError || hint ? describedById : undefined}\n onChange={handleChange}\n onBlur={handleBlur}\n className={fieldClassName(\n Boolean(shownError),\n Boolean(trailing),\n className,\n )}\n />\n {trailing ? (\n <span className=\"absolute top-1/2 right-[9px] flex -translate-y-1/2 items-center text-hint font-semibold text-fg-subtle\">\n {trailing}\n </span>\n ) : null}\n </div>\n\n <FieldMessage id={describedById} error={shownError} hint={hint} />\n </div>\n );\n}\n","import {\n type ChangeEvent,\n type FocusEvent,\n useCallback,\n useState,\n} from \"react\";\n\n/**\n * Structural shape of a zod schema — every zod schema satisfies it, and any\n * version of zod does. Declaring it this way rather than importing `ZodType`\n * keeps zod out of this module's public types, so consumers who only want an\n * input do not have to install zod to typecheck it.\n */\nexport type FieldSchema = {\n safeParse: (\n value: unknown,\n ) =>\n | { success: true }\n | { success: false; error: { issues: readonly { message: string }[] } };\n};\n\n/** Outcome of a single validation pass, handed to `onValidationChange`. */\nexport type FieldValidation = {\n valid: boolean;\n /** First issue reported by the schema, or `undefined` when valid. */\n error?: string;\n};\n\nexport type FieldBehaviour = {\n value?: string;\n defaultValue?: string;\n /** A caller-supplied error. Outranks the schema's verdict. */\n error?: string;\n onChange?: (value: string) => void;\n onBlur?: (event: FocusEvent<HTMLInputElement>) => void;\n schema?: FieldSchema;\n validateOn?: \"blur\" | \"change\" | \"never\";\n onValidationChange?: (state: FieldValidation) => void;\n};\n\nconst FALLBACK_MESSAGE = \"Invalid value\";\n\nfunction runSchema(\n schema: FieldSchema | undefined,\n value: string,\n): FieldValidation {\n if (!schema) {\n return { valid: true };\n }\n\n const result = schema.safeParse(value);\n if (result.success) {\n return { valid: true };\n }\n\n return {\n valid: false,\n error: result.error.issues[0]?.message ?? FALLBACK_MESSAGE,\n };\n}\n\n/**\n * Owns the value (controlled or not), the schema verdict, and when to re-run\n * it. Split out so the `Field` component itself stays markup.\n */\nexport function useFieldBehaviour({\n value,\n defaultValue,\n error,\n onChange,\n onBlur,\n schema,\n validateOn = \"blur\",\n onValidationChange,\n}: FieldBehaviour) {\n const [uncontrolledValue, setUncontrolledValue] = useState(\n defaultValue ?? \"\",\n );\n const [schemaError, setSchemaError] = useState<string | undefined>(undefined);\n\n const isControlled = value !== undefined;\n\n const validate = useCallback(\n (next: string) => {\n const state = runSchema(schema, next);\n setSchemaError(state.error);\n onValidationChange?.(state);\n },\n [schema, onValidationChange],\n );\n\n const handleChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n if (!isControlled) {\n setUncontrolledValue(next);\n }\n onChange?.(next);\n\n // Revalidate on every keystroke once the field is already invalid, so a\n // corrected value clears the message without waiting for another blur.\n if (validateOn === \"change\" || (validateOn === \"blur\" && schemaError)) {\n validate(next);\n }\n },\n [isControlled, onChange, validateOn, schemaError, validate],\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLInputElement>) => {\n if (validateOn === \"blur\") {\n validate(event.target.value);\n }\n onBlur?.(event);\n },\n [validateOn, validate, onBlur],\n );\n\n return {\n currentValue: isControlled ? value : uncontrolledValue,\n // A caller-supplied error outranks the schema's verdict.\n shownError: error ?? schemaError,\n handleChange,\n handleBlur,\n };\n}\n","import { Slot } from \"@radix-ui/react-slot\";\nimport type { ElementType, HTMLAttributes, ReactNode, Ref } from \"react\";\n\n/**\n * The library's type scale. Everything that renders text — field labels, hints,\n * form errors, headings — goes through here, so a size or colour lives in one\n * place and the tokens in `src/styles/index.css` stay the single source of\n * truth for what \"hint\" or \"muted\" means.\n *\n * Server-safe: no state, no handlers, no directive. It composes Radix `Slot`\n * for `asChild`, which is how a consumer puts these styles on their own\n * element (a `next/link`, a Radix `Label`) without an extra wrapper.\n */\n\nexport type TypographyVariant =\n | \"display\"\n | \"heading\"\n | \"subheading\"\n | \"body\"\n | \"label\"\n | \"hint\"\n | \"code\";\n\nexport type TypographyTone =\n | \"default\"\n | \"muted\"\n | \"subtle\"\n | \"accent\"\n | \"on-accent\"\n | \"success\"\n | \"warning\"\n | \"info\"\n | \"danger\";\n\nexport type TypographyWeight = \"regular\" | \"medium\" | \"semibold\" | \"bold\";\n\nexport type TypographyElement =\n | \"p\"\n | \"span\"\n | \"div\"\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\"\n | \"label\"\n | \"code\"\n | \"strong\"\n | \"em\"\n | \"small\";\n\nexport type TypographyProps = Omit<HTMLAttributes<HTMLElement>, \"color\"> & {\n /** Size and default element. `body` unless told otherwise. */\n variant?: TypographyVariant;\n /** Colour role, from the design tokens. */\n tone?: TypographyTone;\n /** Overrides the variant's default weight. */\n weight?: TypographyWeight;\n align?: \"start\" | \"center\" | \"end\";\n /** Clip to one line with an ellipsis. */\n truncate?: boolean;\n /**\n * An icon rendered beside the text, hidden from assistive tech. Sized to the\n * text with `1em`, so the same SVG fits every variant.\n */\n icon?: ReactNode;\n iconPosition?: \"leading\" | \"trailing\";\n /** The element to render. Defaults per variant (`h2` for a heading, and so on). */\n as?: TypographyElement;\n /**\n * Radix-style composition: render the child element itself, with these\n * styles merged onto it, instead of a wrapper. Takes precedence over `as`.\n */\n asChild?: boolean;\n ref?: Ref<HTMLElement>;\n children?: ReactNode;\n};\n\nconst DEFAULT_ELEMENT: Record<TypographyVariant, TypographyElement> = {\n display: \"h1\",\n heading: \"h2\",\n subheading: \"h3\",\n body: \"p\",\n label: \"span\",\n hint: \"p\",\n code: \"code\",\n};\n\nconst DEFAULT_WEIGHT: Record<TypographyVariant, TypographyWeight> = {\n display: \"semibold\",\n heading: \"semibold\",\n subheading: \"medium\",\n body: \"regular\",\n label: \"semibold\",\n hint: \"regular\",\n code: \"regular\",\n};\n\nconst VARIANT_CLASSES: Record<TypographyVariant, string> = {\n display: \"text-display leading-tight tracking-tight\",\n heading: \"text-heading leading-tight tracking-tight\",\n subheading: \"text-subheading leading-snug\",\n body: \"text-field leading-normal\",\n label: \"text-label leading-normal\",\n hint: \"text-hint leading-normal\",\n code: \"font-code text-field leading-normal\",\n};\n\nconst TONE_CLASSES: Record<TypographyTone, string> = {\n default: \"text-fg\",\n muted: \"text-fg-muted\",\n subtle: \"text-fg-subtle\",\n accent: \"text-accent\",\n \"on-accent\": \"text-on-accent\",\n success: \"text-success\",\n warning: \"text-warning\",\n info: \"text-info\",\n danger: \"text-danger\",\n};\n\nconst WEIGHT_CLASSES: Record<TypographyWeight, string> = {\n regular: \"font-normal\",\n medium: \"font-medium\",\n semibold: \"font-semibold\",\n bold: \"font-bold\",\n};\n\nconst ALIGN_CLASSES = {\n start: \"text-start\",\n center: \"text-center\",\n end: \"text-end\",\n} as const;\n\nconst ICON_CLASSES =\n \"inline-flex shrink-0 items-center [&>svg]:h-[1em] [&>svg]:w-[1em]\";\n\nfunction typographyClassName({\n variant,\n tone,\n weight,\n align,\n truncate,\n hasIcon,\n className,\n}: {\n variant: TypographyVariant;\n tone: TypographyTone;\n weight: TypographyWeight;\n align: \"start\" | \"center\" | \"end\" | undefined;\n truncate: boolean;\n hasIcon: boolean;\n className: string | undefined;\n}): string {\n return [\n VARIANT_CLASSES[variant],\n TONE_CLASSES[tone],\n WEIGHT_CLASSES[weight],\n align ? ALIGN_CLASSES[align] : \"\",\n hasIcon ? \"inline-flex items-center gap-1.5\" : \"\",\n // With an icon the root is a flex container, and text-overflow only\n // clips block text, so the text span carries the truncation instead.\n truncate && !hasIcon ? \"truncate\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nexport function Typography({\n variant = \"body\",\n tone = \"default\",\n weight,\n align,\n truncate = false,\n icon,\n iconPosition = \"leading\",\n as,\n asChild = false,\n className,\n children,\n ...rest\n}: TypographyProps) {\n const hasIcon = icon !== undefined && icon !== null;\n // Widened to `ElementType`: the union of intrinsic tags would otherwise\n // demand a `ref` typed to one specific element.\n const Component: ElementType = asChild\n ? Slot\n : (as ?? DEFAULT_ELEMENT[variant]);\n\n const iconNode = hasIcon ? (\n <span aria-hidden=\"true\" className={ICON_CLASSES}>\n {icon}\n </span>\n ) : null;\n\n const content = hasIcon ? (\n <>\n {iconPosition === \"leading\" ? iconNode : null}\n <span className={truncate ? \"min-w-0 truncate\" : undefined}>\n {children}\n </span>\n {iconPosition === \"trailing\" ? iconNode : null}\n </>\n ) : (\n children\n );\n\n return (\n <Component\n {...rest}\n className={typographyClassName({\n variant,\n tone,\n weight: weight ?? DEFAULT_WEIGHT[variant],\n align,\n truncate,\n hasIcon,\n className,\n })}\n >\n {content}\n </Component>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/components/password-input/index.tsx","../src/components/field/index.tsx","../src/components/typography/index.tsx","../src/components/input/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { InputField, type InputFieldProps } from \"@/components/input\";\n\n/**\n * A password. Fixes `type=\"password\"` and owns the design's in-field peek\n * affordance, so the trailing slot is not exposed here — the toggle is it.\n */\nexport type PasswordInputProps = Omit<InputFieldProps, \"trailing\"> & {\n /** Show the \"Show\"/\"Hide\" toggle. On by default, as the design has it. */\n revealable?: boolean;\n /** Labels for the toggle, for localisation. */\n revealLabels?: { show: string; hide: string };\n};\n\nconst DEFAULT_REVEAL_LABELS = { show: \"Show\", hide: \"Hide\" };\n\nconst TOGGLE_CLASSES =\n \"cursor-pointer rounded-field font-[inherit] text-hint font-semibold text-fg-subtle outline-none hover:text-fg focus-visible:ring-3 focus-visible:ring-accent-soft disabled:cursor-not-allowed\";\n\nexport function PasswordInput({\n revealable = true,\n revealLabels = DEFAULT_REVEAL_LABELS,\n autoComplete = \"current-password\",\n ...rest\n}: PasswordInputProps) {\n const [revealed, setRevealed] = useState(false);\n const toggleRevealed = useCallback(\n () => setRevealed((current) => !current),\n [],\n );\n\n const toggle = revealable ? (\n <button\n type=\"button\"\n aria-pressed={revealed}\n aria-label={revealed ? \"Hide password\" : \"Show password\"}\n className={TOGGLE_CLASSES}\n onClick={toggleRevealed}\n >\n {revealed ? revealLabels.hide : revealLabels.show}\n </button>\n ) : undefined;\n\n return (\n <InputField\n {...rest}\n type={revealed ? \"text\" : \"password\"}\n autoComplete={autoComplete}\n trailing={toggle}\n />\n );\n}\n","\"use client\";\n\nimport { Label } from \"@radix-ui/react-label\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport {\n type ComponentPropsWithoutRef,\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useId,\n useState,\n} from \"react\";\nimport {\n type FieldValues,\n type UseFormReturn,\n useController,\n useFormContext,\n} from \"react-hook-form\";\n\n/**\n * The structure behind every form field, with no styling of its own: an id\n * shared by label and control, the error and description ids the control is\n * described by, the field's validity, and — inside a `Form` — the\n * react-hook-form bindings (`value`, `onChange`, `onBlur`, `ref`) that keep\n * the control registered.\n *\n * Styled components compose these primitives with their own classes\n * (`TextInput` and friends do), and a screen that needs a control the\n * library does not ship — a select, a code entry, a toggle — composes them\n * the same way. Everything here is a plain element or a Radix `Slot`, so the\n * styling decisions stay with whoever renders the field.\n *\n * Outside a `Form` the primitives still wire label, control and messages\n * together; the control just isn't registered anywhere and the error comes\n * from the `error` prop alone.\n */\n\nexport type FieldBindings = {\n name: string;\n value?: unknown;\n onChange?: (event: unknown) => void;\n onBlur?: () => void;\n ref?: (instance: HTMLElement | null) => void;\n};\n\nexport type FieldContextValue = {\n id: string;\n name: string;\n descriptionId: string;\n messageId: string;\n error: string | undefined;\n invalid: boolean;\n required: boolean;\n disabled: boolean;\n hasDescription: boolean;\n setHasDescription: (present: boolean) => void;\n bindings: FieldBindings;\n};\n\nconst FieldContext = createContext<FieldContextValue | null>(null);\n\n// biome-ignore lint/style/useComponentExportOnlyModules: the hook is the primitives' public API for custom compositions and belongs on the same subpath.\nexport function useFieldContext(): FieldContextValue {\n const context = useContext(FieldContext);\n\n if (!context) {\n throw new Error(\"Field primitives must be rendered inside FieldRoot\");\n }\n\n return context;\n}\n\nexport type FieldRootProps = ComponentPropsWithoutRef<\"div\"> & {\n /** The form field this wires up — the key in the `Form`'s values. */\n name: string;\n /** A caller-supplied error. Outranks whatever the form's schema reports. */\n error?: string;\n required?: boolean;\n disabled?: boolean;\n /** Render the child element as the root instead of a `div`. */\n asChild?: boolean;\n children: ReactNode;\n};\n\ntype FieldShellProps = Omit<\n FieldRootProps,\n \"name\" | \"error\" | \"required\" | \"disabled\"\n> & {\n value: Omit<FieldContextValue, \"hasDescription\" | \"setHasDescription\">;\n};\n\nfunction useFieldIds(id: string | undefined) {\n const generated = useId();\n const base = id ?? generated;\n\n return {\n id: base,\n descriptionId: `${base}-description`,\n messageId: `${base}-message`,\n };\n}\n\nfunction FieldShell({\n value,\n asChild = false,\n children,\n ...rest\n}: FieldShellProps) {\n const [hasDescription, setHasDescription] = useState(false);\n const Component = asChild ? Slot : \"div\";\n\n return (\n <FieldContext.Provider\n value={{ ...value, hasDescription, setHasDescription }}\n >\n <Component\n {...rest}\n data-invalid={value.invalid ? \"\" : undefined}\n data-disabled={value.disabled ? \"\" : undefined}\n >\n {children}\n </Component>\n </FieldContext.Provider>\n );\n}\n\nfunction ConnectedFieldRoot({\n name,\n error,\n required = false,\n disabled = false,\n id,\n ...rest\n}: FieldRootProps) {\n const ids = useFieldIds(id);\n const { field, fieldState } = useController({ name, disabled });\n const shownError = error ?? fieldState.error?.message;\n\n return (\n <FieldShell\n {...rest}\n value={{\n ...ids,\n name,\n error: shownError,\n invalid: Boolean(shownError),\n required,\n disabled: Boolean(field.disabled ?? disabled),\n bindings: {\n name: field.name,\n value: field.value ?? \"\",\n onChange: field.onChange,\n onBlur: field.onBlur,\n ref: field.ref,\n },\n }}\n />\n );\n}\n\nfunction StandaloneFieldRoot({\n name,\n error,\n required = false,\n disabled = false,\n id,\n ...rest\n}: FieldRootProps) {\n const ids = useFieldIds(id);\n\n return (\n <FieldShell\n {...rest}\n value={{\n ...ids,\n name,\n error,\n invalid: Boolean(error),\n required,\n disabled,\n bindings: { name },\n }}\n />\n );\n}\n\nexport function FieldRoot(props: FieldRootProps) {\n const form = useFormContext() as UseFormReturn<FieldValues> | null;\n\n return form ? (\n <ConnectedFieldRoot {...props} />\n ) : (\n <StandaloneFieldRoot {...props} />\n );\n}\n\nexport type FieldLabelProps = ComponentPropsWithoutRef<typeof Label>;\n\nexport function FieldLabel(props: FieldLabelProps) {\n const { id } = useFieldContext();\n\n return <Label {...props} htmlFor={id} />;\n}\n\nexport type FieldControlProps = ComponentPropsWithoutRef<typeof Slot>;\n\nfunction describedBy({\n error,\n messageId,\n hasDescription,\n descriptionId,\n}: Pick<\n FieldContextValue,\n \"error\" | \"messageId\" | \"hasDescription\" | \"descriptionId\"\n>): string | undefined {\n if (error) {\n return messageId;\n }\n\n return hasDescription ? descriptionId : undefined;\n}\n\n/**\n * Wires the field's id, name, validity and bindings onto whatever element it\n * wraps — an `<input>`, a `<select>`, a `<textarea>`, a custom control.\n * Handlers on the child still run; the bindings run after them.\n */\nexport function FieldControl(props: FieldControlProps) {\n const context = useFieldContext();\n const { id, invalid, required, disabled, bindings } = context;\n\n // `disabled` is not on Slot's HTMLAttributes type, but it is what the\n // wrapped control needs, so the bindings are spread untyped on purpose.\n const controlProps: Record<string, unknown> = {\n ...bindings,\n id,\n \"aria-invalid\": invalid || undefined,\n \"aria-required\": required || undefined,\n \"aria-describedby\": describedBy(context),\n disabled: disabled || undefined,\n };\n\n return <Slot {...props} {...controlProps} />;\n}\n\nexport type FieldDescriptionProps = ComponentPropsWithoutRef<\"p\"> & {\n asChild?: boolean;\n};\n\n/** Guidance under the control. Hidden while the field has an error. */\nexport function FieldDescription({\n asChild = false,\n ...props\n}: FieldDescriptionProps) {\n const { descriptionId, error, setHasDescription } = useFieldContext();\n\n useEffect(() => {\n setHasDescription(true);\n\n return () => setHasDescription(false);\n }, [setHasDescription]);\n\n if (error) {\n return null;\n }\n\n const Component = asChild ? Slot : \"p\";\n\n return <Component {...props} id={descriptionId} />;\n}\n\nexport type FieldMessageProps = ComponentPropsWithoutRef<\"p\"> & {\n asChild?: boolean;\n};\n\n/**\n * The field's error, announced as an alert. Renders the error the field\n * currently holds; `children` is a fallback for a message the caller wants to\n * show in its place. Nothing renders while the field is valid.\n */\nexport function FieldMessage({\n asChild = false,\n children,\n ...props\n}: FieldMessageProps) {\n const { messageId, error } = useFieldContext();\n const content = error ?? children;\n\n if (!content) {\n return null;\n }\n\n const Component = asChild ? Slot : \"p\";\n\n return (\n <Component {...props} id={messageId} role=\"alert\">\n {content}\n </Component>\n );\n}\n","import { Slot } from \"@radix-ui/react-slot\";\nimport type { ElementType, HTMLAttributes, ReactNode, Ref } from \"react\";\n\n/**\n * The library's type scale. Everything that renders text — field labels, hints,\n * form errors, headings — goes through here, so a size or colour lives in one\n * place and the tokens in `src/styles/index.css` stay the single source of\n * truth for what \"hint\" or \"muted\" means.\n *\n * Server-safe: no state, no handlers, no directive. It composes Radix `Slot`\n * for `asChild`, which is how a consumer puts these styles on their own\n * element (a `next/link`, a Radix `Label`) without an extra wrapper.\n */\n\nexport type TypographyVariant =\n | \"display\"\n | \"heading\"\n | \"subheading\"\n | \"body\"\n | \"label\"\n | \"hint\"\n | \"code\";\n\nexport type TypographyTone =\n | \"default\"\n | \"muted\"\n | \"subtle\"\n | \"accent\"\n | \"on-accent\"\n | \"success\"\n | \"warning\"\n | \"info\"\n | \"danger\";\n\nexport type TypographyWeight = \"regular\" | \"medium\" | \"semibold\" | \"bold\";\n\nexport type TypographyElement =\n | \"p\"\n | \"span\"\n | \"div\"\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\"\n | \"label\"\n | \"code\"\n | \"strong\"\n | \"em\"\n | \"small\";\n\nexport type TypographyProps = Omit<HTMLAttributes<HTMLElement>, \"color\"> & {\n /** Size and default element. `body` unless told otherwise. */\n variant?: TypographyVariant;\n /** Colour role, from the design tokens. */\n tone?: TypographyTone;\n /** Overrides the variant's default weight. */\n weight?: TypographyWeight;\n align?: \"start\" | \"center\" | \"end\";\n /** Clip to one line with an ellipsis. */\n truncate?: boolean;\n /**\n * An icon rendered beside the text, hidden from assistive tech. Sized to the\n * text with `1em`, so the same SVG fits every variant.\n */\n icon?: ReactNode;\n iconPosition?: \"leading\" | \"trailing\";\n /** The element to render. Defaults per variant (`h2` for a heading, and so on). */\n as?: TypographyElement;\n /**\n * Radix-style composition: render the child element itself, with these\n * styles merged onto it, instead of a wrapper. Takes precedence over `as`.\n */\n asChild?: boolean;\n ref?: Ref<HTMLElement>;\n children?: ReactNode;\n};\n\nconst DEFAULT_ELEMENT: Record<TypographyVariant, TypographyElement> = {\n display: \"h1\",\n heading: \"h2\",\n subheading: \"h3\",\n body: \"p\",\n label: \"span\",\n hint: \"p\",\n code: \"code\",\n};\n\nconst DEFAULT_WEIGHT: Record<TypographyVariant, TypographyWeight> = {\n display: \"semibold\",\n heading: \"semibold\",\n subheading: \"medium\",\n body: \"regular\",\n label: \"semibold\",\n hint: \"regular\",\n code: \"regular\",\n};\n\nconst VARIANT_CLASSES: Record<TypographyVariant, string> = {\n display: \"text-display leading-tight tracking-tight\",\n heading: \"text-heading leading-tight tracking-tight\",\n subheading: \"text-subheading leading-snug\",\n body: \"text-field leading-normal\",\n label: \"text-label leading-normal\",\n hint: \"text-hint leading-normal\",\n code: \"font-code text-field leading-normal\",\n};\n\nconst TONE_CLASSES: Record<TypographyTone, string> = {\n default: \"text-fg\",\n muted: \"text-fg-muted\",\n subtle: \"text-fg-subtle\",\n accent: \"text-accent\",\n \"on-accent\": \"text-on-accent\",\n success: \"text-success\",\n warning: \"text-warning\",\n info: \"text-info\",\n danger: \"text-danger\",\n};\n\nconst WEIGHT_CLASSES: Record<TypographyWeight, string> = {\n regular: \"font-normal\",\n medium: \"font-medium\",\n semibold: \"font-semibold\",\n bold: \"font-bold\",\n};\n\nconst ALIGN_CLASSES = {\n start: \"text-start\",\n center: \"text-center\",\n end: \"text-end\",\n} as const;\n\nconst ICON_CLASSES =\n \"inline-flex shrink-0 items-center [&>svg]:h-[1em] [&>svg]:w-[1em]\";\n\nfunction typographyClassName({\n variant,\n tone,\n weight,\n align,\n truncate,\n hasIcon,\n className,\n}: {\n variant: TypographyVariant;\n tone: TypographyTone;\n weight: TypographyWeight;\n align: \"start\" | \"center\" | \"end\" | undefined;\n truncate: boolean;\n hasIcon: boolean;\n className: string | undefined;\n}): string {\n return [\n VARIANT_CLASSES[variant],\n TONE_CLASSES[tone],\n WEIGHT_CLASSES[weight],\n align ? ALIGN_CLASSES[align] : \"\",\n hasIcon ? \"inline-flex items-center gap-1.5\" : \"\",\n // With an icon the root is a flex container, and text-overflow only\n // clips block text, so the text span carries the truncation instead.\n truncate && !hasIcon ? \"truncate\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nexport function Typography({\n variant = \"body\",\n tone = \"default\",\n weight,\n align,\n truncate = false,\n icon,\n iconPosition = \"leading\",\n as,\n asChild = false,\n className,\n children,\n ...rest\n}: TypographyProps) {\n const hasIcon = icon !== undefined && icon !== null;\n // Widened to `ElementType`: the union of intrinsic tags would otherwise\n // demand a `ref` typed to one specific element.\n const Component: ElementType = asChild\n ? Slot\n : (as ?? DEFAULT_ELEMENT[variant]);\n\n const iconNode = hasIcon ? (\n <span aria-hidden=\"true\" className={ICON_CLASSES}>\n {icon}\n </span>\n ) : null;\n\n const content = hasIcon ? (\n <>\n {iconPosition === \"leading\" ? iconNode : null}\n <span className={truncate ? \"min-w-0 truncate\" : undefined}>\n {children}\n </span>\n {iconPosition === \"trailing\" ? iconNode : null}\n </>\n ) : (\n children\n );\n\n return (\n <Component\n {...rest}\n className={typographyClassName({\n variant,\n tone,\n weight: weight ?? DEFAULT_WEIGHT[variant],\n align,\n truncate,\n hasIcon,\n className,\n })}\n >\n {content}\n </Component>\n );\n}\n","\"use client\";\n\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\nimport {\n FieldControl,\n FieldDescription,\n FieldLabel,\n FieldMessage,\n FieldRoot,\n useFieldContext,\n} from \"@/components/field\";\nimport { Typography } from \"@/components/typography\";\n\n/**\n * The design's single-line input, composed from the headless `Field`\n * primitives: label with the optional marker and action slot, the control\n * with its trailing slot, and the hint or error beneath. `TextInput`,\n * `EmailInput`, `PasswordInput` and `PhoneInput` each fix the `type` and the\n * keyboard/autofill hints and hand everything else here.\n *\n * Internal: no subpath of its own. Consumers reach it through the\n * specialised inputs, or build their own composition from `Field`.\n */\n\nexport type InputType = \"text\" | \"email\" | \"password\" | \"tel\";\n\nexport type InputFieldProps = Omit<\n ComponentPropsWithoutRef<\"input\">,\n \"name\" | \"type\"\n> & {\n /** The form field this input edits — the key in the `Form`'s values. */\n name: string;\n label?: string;\n /** Guidance under the field. Replaced by the error message while invalid. */\n hint?: ReactNode;\n /**\n * Error supplied by the caller — a server-side or cross-field failure. Takes\n * precedence over what the form's schema reports for this field.\n */\n error?: string;\n /** Renders the design's muted \"Optional\" marker at the end of the label. */\n optional?: boolean;\n /** Trailing label slot, for affordances like the design's \"Forgot?\" link. */\n action?: ReactNode;\n /** Trailing in-field slot, for affordances like the design's password peek. */\n trailing?: ReactNode;\n};\n\ntype InputFieldComponentProps = InputFieldProps & { type: InputType };\n\nconst CONTROL_CLASSES =\n \"h-10 w-full rounded-field border bg-surface px-3 font-[inherit] text-field text-fg outline-none placeholder:text-fg-subtle disabled:cursor-not-allowed disabled:opacity-45\";\nconst VALID_CLASSES =\n \"border-line focus:border-accent focus:ring-3 focus:ring-accent-soft\";\nconst INVALID_CLASSES =\n \"border-danger focus:border-danger focus:ring-3 focus:ring-danger-soft\";\n\nfunction InputLabel({\n label,\n optional,\n action,\n}: {\n label: string;\n optional: boolean;\n action: ReactNode;\n}) {\n return (\n <Typography\n variant=\"label\"\n tone=\"muted\"\n className=\"mb-1.5 flex items-center\"\n asChild\n >\n <FieldLabel>\n {label}\n {optional ? (\n <Typography\n as=\"span\"\n variant=\"hint\"\n tone=\"subtle\"\n weight=\"semibold\"\n className=\"ml-auto\"\n >\n Optional\n </Typography>\n ) : null}\n {action ? <span className=\"ml-auto\">{action}</span> : null}\n </FieldLabel>\n </Typography>\n );\n}\n\nfunction InputControl({\n hasTrailing,\n className,\n ...rest\n}: Omit<ComponentPropsWithoutRef<\"input\">, \"name\"> & {\n hasTrailing: boolean;\n}) {\n const { invalid } = useFieldContext();\n\n return (\n <FieldControl>\n <input\n {...rest}\n className={[\n CONTROL_CLASSES,\n invalid ? INVALID_CLASSES : VALID_CLASSES,\n hasTrailing ? \"pr-16\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n />\n </FieldControl>\n );\n}\n\nfunction InputMessages({ hint }: { hint: ReactNode }) {\n const { error } = useFieldContext();\n\n if (error) {\n return (\n <Typography as=\"p\" variant=\"hint\" tone=\"danger\" asChild>\n <FieldMessage className=\"mt-1.5\" />\n </Typography>\n );\n }\n\n if (hint) {\n return (\n <Typography as=\"p\" variant=\"hint\" tone=\"subtle\" asChild>\n <FieldDescription className=\"mt-1.5\">{hint}</FieldDescription>\n </Typography>\n );\n }\n\n return null;\n}\n\nexport function InputField({\n name,\n label,\n hint,\n error,\n optional = false,\n action,\n trailing,\n id,\n disabled,\n required,\n type,\n ...rest\n}: InputFieldComponentProps) {\n return (\n <FieldRoot\n name={name}\n id={id}\n error={error}\n disabled={disabled}\n required={required}\n className=\"flex flex-col\"\n >\n {label ? (\n <InputLabel label={label} optional={optional} action={action} />\n ) : null}\n\n <div className={trailing ? \"relative\" : undefined}>\n <InputControl {...rest} type={type} hasTrailing={Boolean(trailing)} />\n {trailing ? (\n <span className=\"absolute top-1/2 right-[9px] flex -translate-y-1/2 items-center font-semibold text-fg-subtle text-hint\">\n {trailing}\n </span>\n ) : null}\n </div>\n\n <InputMessages hint={hint} />\n </FieldRoot>\n );\n}\n"],"mappings":"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","names":["import_react","import_react_slot","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
@@ -1,12 +1,11 @@
1
1
  import * as react from 'react';
2
- import { F as FieldProps } from './index-DwjxC4l4.cjs';
3
- export { a as FieldSchema, b as FieldValidation } from './index-DwjxC4l4.cjs';
2
+ import { I as InputFieldProps } from './index-CdYkd6zz.cjs';
4
3
 
5
4
  /**
6
5
  * A password. Fixes `type="password"` and owns the design's in-field peek
7
6
  * affordance, so the trailing slot is not exposed here — the toggle is it.
8
7
  */
9
- type PasswordInputProps = Omit<FieldProps, "trailing"> & {
8
+ type PasswordInputProps = Omit<InputFieldProps, "trailing"> & {
10
9
  /** Show the "Show"/"Hide" toggle. On by default, as the design has it. */
11
10
  revealable?: boolean;
12
11
  /** Labels for the toggle, for localisation. */
@@ -1,12 +1,11 @@
1
1
  import * as react from 'react';
2
- import { F as FieldProps } from './index-DwjxC4l4.js';
3
- export { a as FieldSchema, b as FieldValidation } from './index-DwjxC4l4.js';
2
+ import { I as InputFieldProps } from './index-CdYkd6zz.js';
4
3
 
5
4
  /**
6
5
  * A password. Fixes `type="password"` and owns the design's in-field peek
7
6
  * affordance, so the trailing slot is not exposed here — the toggle is it.
8
7
  */
9
- type PasswordInputProps = Omit<FieldProps, "trailing"> & {
8
+ type PasswordInputProps = Omit<InputFieldProps, "trailing"> & {
10
9
  /** Show the "Show"/"Hide" toggle. On by default, as the design has it. */
11
10
  revealable?: boolean;
12
11
  /** Labels for the toggle, for localisation. */