@carbonbits/sixr 1.1.0 → 1.3.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.
package/dist/index.d.ts CHANGED
@@ -1,2 +1,64 @@
1
1
  export { Cart, CartProduct, CartProps } from './cart.js';
2
- import 'react';
2
+ import { InputHTMLAttributes, ReactNode } from 'react';
3
+
4
+ /**
5
+ * Structural shape of a zod schema — every zod schema satisfies it, and any
6
+ * version of zod does. Declaring it this way rather than importing `ZodType`
7
+ * keeps zod out of this module's public types, so consumers who only want an
8
+ * input do not have to install zod to typecheck it.
9
+ */
10
+ type TextInputSchema = {
11
+ safeParse: (value: unknown) => {
12
+ success: true;
13
+ } | {
14
+ success: false;
15
+ error: {
16
+ issues: readonly {
17
+ message: string;
18
+ }[];
19
+ };
20
+ };
21
+ };
22
+ /** Outcome of a single validation pass, handed to `onValidationChange`. */
23
+ type TextInputValidation = {
24
+ valid: boolean;
25
+ /** First issue reported by the schema, or `undefined` when valid. */
26
+ error?: string;
27
+ };
28
+ type TextInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "defaultValue" | "type"> & {
29
+ label?: string;
30
+ /** Guidance under the field. Replaced by the error message while invalid. */
31
+ hint?: ReactNode;
32
+ /**
33
+ * Error supplied by the caller — a server-side or cross-field failure. Takes
34
+ * precedence over the schema, so a form can hold a field invalid regardless
35
+ * of what `schema` makes of the value on its own.
36
+ */
37
+ error?: string;
38
+ /** Renders the design's muted "Optional" marker at the end of the label. */
39
+ optional?: boolean;
40
+ /** Trailing label slot, for affordances like the design's "Forgot?" link. */
41
+ action?: ReactNode;
42
+ /** Trailing in-field slot, for affordances like the design's password peek. */
43
+ trailing?: ReactNode;
44
+ /** Renders the value in the design's monospace face. */
45
+ mono?: boolean;
46
+ type?: "text" | "email" | "password" | "tel" | "url" | "search";
47
+ value?: string;
48
+ defaultValue?: string;
49
+ onChange?: (value: string) => void;
50
+ /**
51
+ * Any zod schema that accepts a string. Only `safeParse` is used, so a
52
+ * refined, transformed or preprocessed schema works as well as a plain one.
53
+ */
54
+ schema?: TextInputSchema;
55
+ /**
56
+ * When the schema runs. `blur` — the default — avoids scolding someone
57
+ * mid-keystroke; once a field has gone invalid it revalidates on every
58
+ * keystroke so the message clears as soon as it is fixed.
59
+ */
60
+ validateOn?: "blur" | "change" | "never";
61
+ onValidationChange?: (state: TextInputValidation) => void;
62
+ };
63
+
64
+ export type { TextInputProps, TextInputSchema, TextInputValidation };
package/dist/styles.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.contents{display:contents}.flex{display:flex}.w-full{width:100%}.max-w-md{max-width:var(--container-md)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-baseline{align-items:baseline}.justify-between{justify-content:space-between}.gap-4{gap:calc(var(--spacing) * 4)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-gray-200{border-color:var(--color-gray-200)}.bg-white{background-color:var(--color-white)}.p-4{padding:calc(var(--spacing) * 4)}.py-2{padding-block:calc(var(--spacing) * 2)}.pt-2{padding-top:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--radius-lg:.5rem;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.top-1\/2{top:50%}.right-\[9px\]{right:9px}.m-0{margin:0}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.ml-auto{margin-left:auto}.contents{display:contents}.flex{display:flex}.inline{display:inline}.table{display:table}.h-4{height:calc(var(--spacing) * 4)}.h-10{height:calc(var(--spacing) * 10)}.w-4{width:calc(var(--spacing) * 4)}.w-full{width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:0}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.flex-col{flex-direction:column}.items-baseline{align-items:baseline}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.rounded-field{border-radius:4px}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-danger{border-color:var(--sixr-danger)}.border-gray-200{border-color:var(--color-gray-200)}.border-line{border-color:var(--sixr-line)}.bg-accent{background-color:var(--sixr-accent)}.bg-surface{background-color:var(--sixr-surface)}.bg-white{background-color:var(--color-white)}.p-0{padding:0}.p-4{padding:calc(var(--spacing) * 4)}.px-3{padding-inline:calc(var(--spacing) * 3)}.py-2{padding-block:calc(var(--spacing) * 2)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pr-16{padding-right:calc(var(--spacing) * 16)}.font-\[inherit\]{font-family:inherit}.font-code{font-family:var(--sixr-font-code)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-field{font-size:13px}.text-hint{font-size:11px}.text-label{font-size:11.5px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-danger{color:var(--sixr-danger)}.text-fg{color:var(--sixr-fg)}.text-fg-muted{color:var(--sixr-fg-muted)}.text-fg-subtle{color:var(--sixr-fg-subtle)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-on-accent{color:var(--sixr-on-accent)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.placeholder\:text-fg-subtle::placeholder{color:var(--sixr-fg-subtle)}.focus\:border-accent:focus{border-color:var(--sixr-accent)}.focus\:border-danger:focus{border-color:var(--sixr-danger)}.focus\:ring-3:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-accent-soft:focus{--tw-ring-color:var(--sixr-accent-soft)}.focus\:ring-danger-soft:focus{--tw-ring-color:var(--sixr-danger-soft)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-45:disabled{opacity:.45}}:root{--sixr-bg:#f4f4f5;--sixr-surface:#fff;--sixr-surface-2:#f4f4f6;--sixr-surface-3:#eaeaec;--sixr-line:#e2e2e5;--sixr-line-strong:#cdcdd2;--sixr-fg:#0b0b0d;--sixr-fg-muted:#55555e;--sixr-fg-subtle:#8e8e99;--sixr-accent:#0b0b0d;--sixr-accent-2:#000;--sixr-accent-soft:#ededef;--sixr-on-accent:#fff;--sixr-success:#16a34a;--sixr-success-soft:#e9f5ec;--sixr-warning:#b45309;--sixr-info:#2563eb;--sixr-danger:#dc2626;--sixr-danger-soft:#fdecec;--sixr-font-code:"JetBrains Mono", ui-monospace, monospace}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--sixr-bg:#000;--sixr-surface:#0b0b0d;--sixr-surface-2:#121215;--sixr-surface-3:#1b1b1f;--sixr-line:#232328;--sixr-line-strong:#3a3a42;--sixr-fg:#fff;--sixr-fg-muted:#a3a3ad;--sixr-fg-subtle:#70707b;--sixr-accent:#fff;--sixr-accent-2:#e4e4e8;--sixr-accent-soft:#17171b;--sixr-on-accent:#000;--sixr-success:#34d399;--sixr-success-soft:#12301e;--sixr-warning:#fbbf24;--sixr-info:#60a5fa;--sixr-danger:#f87171;--sixr-danger-soft:#2a1416}}:root[data-theme=dark]{--sixr-bg:#000;--sixr-surface:#0b0b0d;--sixr-surface-2:#121215;--sixr-surface-3:#1b1b1f;--sixr-line:#232328;--sixr-line-strong:#3a3a42;--sixr-fg:#fff;--sixr-fg-muted:#a3a3ad;--sixr-fg-subtle:#70707b;--sixr-accent:#fff;--sixr-accent-2:#e4e4e8;--sixr-accent-soft:#17171b;--sixr-on-accent:#000;--sixr-success:#34d399;--sixr-success-soft:#12301e;--sixr-warning:#fbbf24;--sixr-info:#60a5fa;--sixr-danger:#f87171;--sixr-danger-soft:#2a1416}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
@@ -0,0 +1,216 @@
1
+ "use client";
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/components/text-input/index.tsx
23
+ var text_input_exports = {};
24
+ __export(text_input_exports, {
25
+ TextInput: () => TextInput
26
+ });
27
+ module.exports = __toCommonJS(text_input_exports);
28
+ var import_react = require("react");
29
+ var import_jsx_runtime = require("react/jsx-runtime");
30
+ 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";
31
+ var VALID_CLASSES = "border-line focus:border-accent focus:ring-3 focus:ring-accent-soft";
32
+ var INVALID_CLASSES = "border-danger focus:border-danger focus:ring-3 focus:ring-danger-soft";
33
+ var FALLBACK_MESSAGE = "Invalid value";
34
+ function runSchema(schema, value) {
35
+ if (!schema) {
36
+ return { valid: true };
37
+ }
38
+ const result = schema.safeParse(value);
39
+ if (result.success) {
40
+ return { valid: true };
41
+ }
42
+ return {
43
+ valid: false,
44
+ error: result.error.issues[0]?.message ?? FALLBACK_MESSAGE
45
+ };
46
+ }
47
+ function fieldClassName(invalid, mono, hasTrailing, className) {
48
+ return [
49
+ FIELD_CLASSES,
50
+ invalid ? INVALID_CLASSES : VALID_CLASSES,
51
+ mono ? "font-code" : "",
52
+ hasTrailing ? "pr-16" : "",
53
+ className ?? ""
54
+ ].filter(Boolean).join(" ");
55
+ }
56
+ function FieldLabel({
57
+ htmlFor,
58
+ label,
59
+ optional,
60
+ action
61
+ }) {
62
+ if (!label) {
63
+ return null;
64
+ }
65
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
66
+ "label",
67
+ {
68
+ htmlFor,
69
+ className: "mb-1.5 flex items-center text-label font-semibold text-fg-muted",
70
+ children: [
71
+ label,
72
+ optional ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto text-hint font-semibold text-fg-subtle", children: "Optional" }) : null,
73
+ action ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto", children: action }) : null
74
+ ]
75
+ }
76
+ );
77
+ }
78
+ function FieldMessage({
79
+ id,
80
+ error,
81
+ hint
82
+ }) {
83
+ if (error) {
84
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { id, role: "alert", className: "mt-1.5 text-hint text-danger", children: error });
85
+ }
86
+ if (hint) {
87
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { id, className: "mt-1.5 text-hint text-fg-subtle", children: hint });
88
+ }
89
+ return null;
90
+ }
91
+ function useFieldBehaviour({
92
+ value,
93
+ defaultValue,
94
+ error,
95
+ onChange,
96
+ onBlur,
97
+ schema,
98
+ validateOn = "blur",
99
+ onValidationChange
100
+ }) {
101
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react.useState)(
102
+ defaultValue ?? ""
103
+ );
104
+ const [schemaError, setSchemaError] = (0, import_react.useState)(void 0);
105
+ const isControlled = value !== void 0;
106
+ const validate = (0, import_react.useCallback)(
107
+ (next) => {
108
+ const state = runSchema(schema, next);
109
+ setSchemaError(state.error);
110
+ onValidationChange?.(state);
111
+ },
112
+ [schema, onValidationChange]
113
+ );
114
+ const handleChange = (0, import_react.useCallback)(
115
+ (event) => {
116
+ const next = event.target.value;
117
+ if (!isControlled) {
118
+ setUncontrolledValue(next);
119
+ }
120
+ onChange?.(next);
121
+ if (validateOn === "change" || validateOn === "blur" && schemaError) {
122
+ validate(next);
123
+ }
124
+ },
125
+ [isControlled, onChange, validateOn, schemaError, validate]
126
+ );
127
+ const handleBlur = (0, import_react.useCallback)(
128
+ (event) => {
129
+ if (validateOn === "blur") {
130
+ validate(event.target.value);
131
+ }
132
+ onBlur?.(event);
133
+ },
134
+ [validateOn, validate, onBlur]
135
+ );
136
+ return {
137
+ currentValue: isControlled ? value : uncontrolledValue,
138
+ // A caller-supplied error outranks the schema's verdict.
139
+ shownError: error ?? schemaError,
140
+ handleChange,
141
+ handleBlur
142
+ };
143
+ }
144
+ function TextInput({
145
+ label,
146
+ hint,
147
+ error,
148
+ optional = false,
149
+ action,
150
+ trailing,
151
+ mono = false,
152
+ type = "text",
153
+ value,
154
+ defaultValue,
155
+ onChange,
156
+ schema,
157
+ validateOn = "blur",
158
+ onValidationChange,
159
+ id,
160
+ className,
161
+ onBlur,
162
+ ...rest
163
+ }) {
164
+ const generatedId = (0, import_react.useId)();
165
+ const inputId = id ?? generatedId;
166
+ const describedById = `${inputId}-description`;
167
+ const { currentValue, shownError, handleChange, handleBlur } = useFieldBehaviour({
168
+ value,
169
+ defaultValue,
170
+ error,
171
+ onChange,
172
+ onBlur,
173
+ schema,
174
+ validateOn,
175
+ onValidationChange
176
+ });
177
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
178
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
179
+ FieldLabel,
180
+ {
181
+ htmlFor: inputId,
182
+ label,
183
+ optional,
184
+ action
185
+ }
186
+ ),
187
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: trailing ? "relative" : void 0, children: [
188
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
189
+ "input",
190
+ {
191
+ ...rest,
192
+ id: inputId,
193
+ type,
194
+ value: currentValue,
195
+ "aria-invalid": shownError ? true : void 0,
196
+ "aria-describedby": shownError || hint ? describedById : void 0,
197
+ onChange: handleChange,
198
+ onBlur: handleBlur,
199
+ className: fieldClassName(
200
+ Boolean(shownError),
201
+ mono,
202
+ Boolean(trailing),
203
+ className
204
+ )
205
+ }
206
+ ),
207
+ trailing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute top-1/2 right-[9px] -translate-y-1/2 text-hint font-semibold text-fg-subtle", children: trailing }) : null
208
+ ] }),
209
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldMessage, { id: describedById, error: shownError, hint })
210
+ ] });
211
+ }
212
+ // Annotate the CommonJS export names for ESM import in node:
213
+ 0 && (module.exports = {
214
+ TextInput
215
+ });
216
+ //# sourceMappingURL=text-input.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/text-input/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ChangeEvent,\n type FocusEvent,\n type InputHTMLAttributes,\n type ReactNode,\n useCallback,\n useId,\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 TextInputSchema = {\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 TextInputValidation = {\n valid: boolean;\n /** First issue reported by the schema, or `undefined` when valid. */\n error?: string;\n};\n\nexport type TextInputProps = 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 /** Renders the value in the design's monospace face. */\n mono?: boolean;\n type?: \"text\" | \"email\" | \"password\" | \"tel\" | \"url\" | \"search\";\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?: TextInputSchema;\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: TextInputValidation) => 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\";\nconst FALLBACK_MESSAGE = \"Invalid value\";\n\nfunction runSchema(\n schema: TextInputSchema | undefined,\n value: string,\n): TextInputValidation {\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\nfunction fieldClassName(\n invalid: boolean,\n mono: boolean,\n hasTrailing: boolean,\n className: string | undefined,\n): string {\n return [\n FIELD_CLASSES,\n invalid ? INVALID_CLASSES : VALID_CLASSES,\n mono ? \"font-code\" : \"\",\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 <label\n htmlFor={htmlFor}\n className=\"mb-1.5 flex items-center text-label font-semibold text-fg-muted\"\n >\n {label}\n {optional ? (\n <span className=\"ml-auto text-hint font-semibold text-fg-subtle\">\n Optional\n </span>\n ) : null}\n {action ? <span className=\"ml-auto\">{action}</span> : null}\n </label>\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 <p id={id} role=\"alert\" className=\"mt-1.5 text-hint text-danger\">\n {error}\n </p>\n );\n }\n\n if (hint) {\n return (\n <p id={id} className=\"mt-1.5 text-hint text-fg-subtle\">\n {hint}\n </p>\n );\n }\n\n return null;\n}\n\ntype FieldBehaviour = Pick<\n TextInputProps,\n | \"value\"\n | \"defaultValue\"\n | \"error\"\n | \"onChange\"\n | \"onBlur\"\n | \"schema\"\n | \"validateOn\"\n | \"onValidationChange\"\n>;\n\n/**\n * Owns the value (controlled or not), the schema verdict, and when to re-run\n * it. Split out so the component itself stays markup.\n */\nfunction 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\nexport function TextInput({\n label,\n hint,\n error,\n optional = false,\n action,\n trailing,\n mono = false,\n type = \"text\",\n value,\n defaultValue,\n onChange,\n schema,\n validateOn = \"blur\",\n onValidationChange,\n id,\n className,\n onBlur,\n ...rest\n}: TextInputProps) {\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 mono,\n Boolean(trailing),\n className,\n )}\n />\n {trailing ? (\n <span className=\"absolute top-1/2 right-[9px] -translate-y-1/2 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"],"mappings":"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","names":[]}
@@ -0,0 +1,65 @@
1
+ import * as react from 'react';
2
+ import { InputHTMLAttributes, ReactNode } from 'react';
3
+
4
+ /**
5
+ * Structural shape of a zod schema — every zod schema satisfies it, and any
6
+ * version of zod does. Declaring it this way rather than importing `ZodType`
7
+ * keeps zod out of this module's public types, so consumers who only want an
8
+ * input do not have to install zod to typecheck it.
9
+ */
10
+ type TextInputSchema = {
11
+ safeParse: (value: unknown) => {
12
+ success: true;
13
+ } | {
14
+ success: false;
15
+ error: {
16
+ issues: readonly {
17
+ message: string;
18
+ }[];
19
+ };
20
+ };
21
+ };
22
+ /** Outcome of a single validation pass, handed to `onValidationChange`. */
23
+ type TextInputValidation = {
24
+ valid: boolean;
25
+ /** First issue reported by the schema, or `undefined` when valid. */
26
+ error?: string;
27
+ };
28
+ type TextInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "defaultValue" | "type"> & {
29
+ label?: string;
30
+ /** Guidance under the field. Replaced by the error message while invalid. */
31
+ hint?: ReactNode;
32
+ /**
33
+ * Error supplied by the caller — a server-side or cross-field failure. Takes
34
+ * precedence over the schema, so a form can hold a field invalid regardless
35
+ * of what `schema` makes of the value on its own.
36
+ */
37
+ error?: string;
38
+ /** Renders the design's muted "Optional" marker at the end of the label. */
39
+ optional?: boolean;
40
+ /** Trailing label slot, for affordances like the design's "Forgot?" link. */
41
+ action?: ReactNode;
42
+ /** Trailing in-field slot, for affordances like the design's password peek. */
43
+ trailing?: ReactNode;
44
+ /** Renders the value in the design's monospace face. */
45
+ mono?: boolean;
46
+ type?: "text" | "email" | "password" | "tel" | "url" | "search";
47
+ value?: string;
48
+ defaultValue?: string;
49
+ onChange?: (value: string) => void;
50
+ /**
51
+ * Any zod schema that accepts a string. Only `safeParse` is used, so a
52
+ * refined, transformed or preprocessed schema works as well as a plain one.
53
+ */
54
+ schema?: TextInputSchema;
55
+ /**
56
+ * When the schema runs. `blur` — the default — avoids scolding someone
57
+ * mid-keystroke; once a field has gone invalid it revalidates on every
58
+ * keystroke so the message clears as soon as it is fixed.
59
+ */
60
+ validateOn?: "blur" | "change" | "never";
61
+ onValidationChange?: (state: TextInputValidation) => void;
62
+ };
63
+ declare function TextInput({ label, hint, error, optional, action, trailing, mono, type, value, defaultValue, onChange, schema, validateOn, onValidationChange, id, className, onBlur, ...rest }: TextInputProps): react.JSX.Element;
64
+
65
+ export { TextInput, type TextInputProps, type TextInputSchema, type TextInputValidation };
@@ -0,0 +1,65 @@
1
+ import * as react from 'react';
2
+ import { InputHTMLAttributes, ReactNode } from 'react';
3
+
4
+ /**
5
+ * Structural shape of a zod schema — every zod schema satisfies it, and any
6
+ * version of zod does. Declaring it this way rather than importing `ZodType`
7
+ * keeps zod out of this module's public types, so consumers who only want an
8
+ * input do not have to install zod to typecheck it.
9
+ */
10
+ type TextInputSchema = {
11
+ safeParse: (value: unknown) => {
12
+ success: true;
13
+ } | {
14
+ success: false;
15
+ error: {
16
+ issues: readonly {
17
+ message: string;
18
+ }[];
19
+ };
20
+ };
21
+ };
22
+ /** Outcome of a single validation pass, handed to `onValidationChange`. */
23
+ type TextInputValidation = {
24
+ valid: boolean;
25
+ /** First issue reported by the schema, or `undefined` when valid. */
26
+ error?: string;
27
+ };
28
+ type TextInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "defaultValue" | "type"> & {
29
+ label?: string;
30
+ /** Guidance under the field. Replaced by the error message while invalid. */
31
+ hint?: ReactNode;
32
+ /**
33
+ * Error supplied by the caller — a server-side or cross-field failure. Takes
34
+ * precedence over the schema, so a form can hold a field invalid regardless
35
+ * of what `schema` makes of the value on its own.
36
+ */
37
+ error?: string;
38
+ /** Renders the design's muted "Optional" marker at the end of the label. */
39
+ optional?: boolean;
40
+ /** Trailing label slot, for affordances like the design's "Forgot?" link. */
41
+ action?: ReactNode;
42
+ /** Trailing in-field slot, for affordances like the design's password peek. */
43
+ trailing?: ReactNode;
44
+ /** Renders the value in the design's monospace face. */
45
+ mono?: boolean;
46
+ type?: "text" | "email" | "password" | "tel" | "url" | "search";
47
+ value?: string;
48
+ defaultValue?: string;
49
+ onChange?: (value: string) => void;
50
+ /**
51
+ * Any zod schema that accepts a string. Only `safeParse` is used, so a
52
+ * refined, transformed or preprocessed schema works as well as a plain one.
53
+ */
54
+ schema?: TextInputSchema;
55
+ /**
56
+ * When the schema runs. `blur` — the default — avoids scolding someone
57
+ * mid-keystroke; once a field has gone invalid it revalidates on every
58
+ * keystroke so the message clears as soon as it is fixed.
59
+ */
60
+ validateOn?: "blur" | "change" | "never";
61
+ onValidationChange?: (state: TextInputValidation) => void;
62
+ };
63
+ declare function TextInput({ label, hint, error, optional, action, trailing, mono, type, value, defaultValue, onChange, schema, validateOn, onValidationChange, id, className, onBlur, ...rest }: TextInputProps): react.JSX.Element;
64
+
65
+ export { TextInput, type TextInputProps, type TextInputSchema, type TextInputValidation };