@carbonbits/sixr 1.3.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 (62) hide show
  1. package/README.md +204 -66
  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/chunk-NZHHNVXZ.js +118 -0
  11. package/dist/chunk-NZHHNVXZ.js.map +1 -0
  12. package/dist/email-input.cjs +433 -0
  13. package/dist/email-input.cjs.map +1 -0
  14. package/dist/email-input.d.cts +12 -0
  15. package/dist/email-input.d.ts +12 -0
  16. package/dist/email-input.js +416 -0
  17. package/dist/email-input.js.map +1 -0
  18. package/dist/field.cjs +206 -0
  19. package/dist/field.cjs.map +1 -0
  20. package/dist/field.d.cts +80 -0
  21. package/dist/field.d.ts +80 -0
  22. package/dist/field.js +186 -0
  23. package/dist/field.js.map +1 -0
  24. package/dist/form.cjs +283 -42
  25. package/dist/form.cjs.map +1 -1
  26. package/dist/form.d.cts +79 -10
  27. package/dist/form.d.ts +79 -10
  28. package/dist/form.js +285 -45
  29. package/dist/form.js.map +1 -1
  30. package/dist/index-CdYkd6zz.d.cts +22 -0
  31. package/dist/index-CdYkd6zz.d.ts +22 -0
  32. package/dist/index.cjs +217 -1
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +146 -46
  35. package/dist/index.d.ts +146 -46
  36. package/dist/index.js +2 -0
  37. package/dist/password-input.cjs +449 -0
  38. package/dist/password-input.cjs.map +1 -0
  39. package/dist/password-input.d.cts +19 -0
  40. package/dist/password-input.d.ts +19 -0
  41. package/dist/password-input.js +434 -0
  42. package/dist/password-input.js.map +1 -0
  43. package/dist/phone-input.cjs +429 -0
  44. package/dist/phone-input.cjs.map +1 -0
  45. package/dist/phone-input.d.cts +12 -0
  46. package/dist/phone-input.d.ts +12 -0
  47. package/dist/phone-input.js +412 -0
  48. package/dist/phone-input.js.map +1 -0
  49. package/dist/styles.css +1 -1
  50. package/dist/text-input.cjs +359 -147
  51. package/dist/text-input.cjs.map +1 -1
  52. package/dist/text-input.d.cts +9 -58
  53. package/dist/text-input.d.ts +9 -58
  54. package/dist/text-input.js +365 -150
  55. package/dist/text-input.js.map +1 -1
  56. package/dist/typography.cjs +120 -0
  57. package/dist/typography.cjs.map +1 -0
  58. package/dist/typography.d.cts +46 -0
  59. package/dist/typography.d.ts +46 -0
  60. package/dist/typography.js +3 -0
  61. package/dist/typography.js.map +1 -0
  62. package/package.json +69 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/field/index.tsx"],"sourcesContent":["\"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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,yBAAsB;AACtB,wBAAqB;AACrB,mBAQO;AACP,6BAKO;AAkGD;AAxDN,IAAM,mBAAe,4BAAwC,IAAI;AAG1D,SAAS,kBAAqC;AACnD,QAAM,cAAU,yBAAW,YAAY;AAEvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AAEA,SAAO;AACT;AAqBA,SAAS,YAAY,IAAwB;AAC3C,QAAM,gBAAY,oBAAM;AACxB,QAAM,OAAO,MAAM;AAEnB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,eAAe,GAAG,IAAI;AAAA,IACtB,WAAW,GAAG,IAAI;AAAA,EACpB;AACF;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,GAAG;AACL,GAAoB;AAClB,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAS,KAAK;AAC1D,QAAM,YAAY,UAAU,yBAAO;AAEnC,SACE;AAAA,IAAC,aAAa;AAAA,IAAb;AAAA,MACC,OAAO,EAAE,GAAG,OAAO,gBAAgB,kBAAkB;AAAA,MAErD;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ,gBAAc,MAAM,UAAU,KAAK;AAAA,UACnC,iBAAe,MAAM,WAAW,KAAK;AAAA,UAEpC;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA,GAAG;AACL,GAAmB;AACjB,QAAM,MAAM,YAAY,EAAE;AAC1B,QAAM,EAAE,OAAO,WAAW,QAAI,sCAAc,EAAE,MAAM,SAAS,CAAC;AAC9D,QAAM,aAAa,SAAS,WAAW,OAAO;AAE9C,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,OAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA,OAAO;AAAA,QACP,SAAS,QAAQ,UAAU;AAAA,QAC3B;AAAA,QACA,UAAU,QAAQ,MAAM,YAAY,QAAQ;AAAA,QAC5C,UAAU;AAAA,UACR,MAAM,MAAM;AAAA,UACZ,OAAO,MAAM,SAAS;AAAA,UACtB,UAAU,MAAM;AAAA,UAChB,QAAQ,MAAM;AAAA,UACd,KAAK,MAAM;AAAA,QACb;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,oBAAoB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA,GAAG;AACL,GAAmB;AACjB,QAAM,MAAM,YAAY,EAAE;AAE1B,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,OAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA;AAAA,QACA,SAAS,QAAQ,KAAK;AAAA,QACtB;AAAA,QACA;AAAA,QACA,UAAU,EAAE,KAAK;AAAA,MACnB;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,UAAU,OAAuB;AAC/C,QAAM,WAAO,uCAAe;AAE5B,SAAO,OACL,4CAAC,sBAAoB,GAAG,OAAO,IAE/B,4CAAC,uBAAqB,GAAG,OAAO;AAEpC;AAIO,SAAS,WAAW,OAAwB;AACjD,QAAM,EAAE,GAAG,IAAI,gBAAgB;AAE/B,SAAO,4CAAC,4BAAO,GAAG,OAAO,SAAS,IAAI;AACxC;AAIA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAGuB;AACrB,MAAI,OAAO;AACT,WAAO;AAAA,EACT;AAEA,SAAO,iBAAiB,gBAAgB;AAC1C;AAOO,SAAS,aAAa,OAA0B;AACrD,QAAM,UAAU,gBAAgB;AAChC,QAAM,EAAE,IAAI,SAAS,UAAU,UAAU,SAAS,IAAI;AAItD,QAAM,eAAwC;AAAA,IAC5C,GAAG;AAAA,IACH;AAAA,IACA,gBAAgB,WAAW;AAAA,IAC3B,iBAAiB,YAAY;AAAA,IAC7B,oBAAoB,YAAY,OAAO;AAAA,IACvC,UAAU,YAAY;AAAA,EACxB;AAEA,SAAO,4CAAC,0BAAM,GAAG,OAAQ,GAAG,cAAc;AAC5C;AAOO,SAAS,iBAAiB;AAAA,EAC/B,UAAU;AAAA,EACV,GAAG;AACL,GAA0B;AACxB,QAAM,EAAE,eAAe,OAAO,kBAAkB,IAAI,gBAAgB;AAEpE,8BAAU,MAAM;AACd,sBAAkB,IAAI;AAEtB,WAAO,MAAM,kBAAkB,KAAK;AAAA,EACtC,GAAG,CAAC,iBAAiB,CAAC;AAEtB,MAAI,OAAO;AACT,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,UAAU,yBAAO;AAEnC,SAAO,4CAAC,aAAW,GAAG,OAAO,IAAI,eAAe;AAClD;AAWO,SAAS,aAAa;AAAA,EAC3B,UAAU;AAAA,EACV;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,EAAE,WAAW,MAAM,IAAI,gBAAgB;AAC7C,QAAM,UAAU,SAAS;AAEzB,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,UAAU,yBAAO;AAEnC,SACE,4CAAC,aAAW,GAAG,OAAO,IAAI,WAAW,MAAK,SACvC,mBACH;AAEJ;","names":[]}
@@ -0,0 +1,80 @@
1
+ import * as react from 'react';
2
+ import { ComponentPropsWithoutRef, ReactNode } from 'react';
3
+ import { Label } from '@radix-ui/react-label';
4
+ import { Slot } from '@radix-ui/react-slot';
5
+
6
+ /**
7
+ * The structure behind every form field, with no styling of its own: an id
8
+ * shared by label and control, the error and description ids the control is
9
+ * described by, the field's validity, and — inside a `Form` — the
10
+ * react-hook-form bindings (`value`, `onChange`, `onBlur`, `ref`) that keep
11
+ * the control registered.
12
+ *
13
+ * Styled components compose these primitives with their own classes
14
+ * (`TextInput` and friends do), and a screen that needs a control the
15
+ * library does not ship — a select, a code entry, a toggle — composes them
16
+ * the same way. Everything here is a plain element or a Radix `Slot`, so the
17
+ * styling decisions stay with whoever renders the field.
18
+ *
19
+ * Outside a `Form` the primitives still wire label, control and messages
20
+ * together; the control just isn't registered anywhere and the error comes
21
+ * from the `error` prop alone.
22
+ */
23
+ type FieldBindings = {
24
+ name: string;
25
+ value?: unknown;
26
+ onChange?: (event: unknown) => void;
27
+ onBlur?: () => void;
28
+ ref?: (instance: HTMLElement | null) => void;
29
+ };
30
+ type FieldContextValue = {
31
+ id: string;
32
+ name: string;
33
+ descriptionId: string;
34
+ messageId: string;
35
+ error: string | undefined;
36
+ invalid: boolean;
37
+ required: boolean;
38
+ disabled: boolean;
39
+ hasDescription: boolean;
40
+ setHasDescription: (present: boolean) => void;
41
+ bindings: FieldBindings;
42
+ };
43
+ declare function useFieldContext(): FieldContextValue;
44
+ type FieldRootProps = ComponentPropsWithoutRef<"div"> & {
45
+ /** The form field this wires up — the key in the `Form`'s values. */
46
+ name: string;
47
+ /** A caller-supplied error. Outranks whatever the form's schema reports. */
48
+ error?: string;
49
+ required?: boolean;
50
+ disabled?: boolean;
51
+ /** Render the child element as the root instead of a `div`. */
52
+ asChild?: boolean;
53
+ children: ReactNode;
54
+ };
55
+ declare function FieldRoot(props: FieldRootProps): react.JSX.Element;
56
+ type FieldLabelProps = ComponentPropsWithoutRef<typeof Label>;
57
+ declare function FieldLabel(props: FieldLabelProps): react.JSX.Element;
58
+ type FieldControlProps = ComponentPropsWithoutRef<typeof Slot>;
59
+ /**
60
+ * Wires the field's id, name, validity and bindings onto whatever element it
61
+ * wraps — an `<input>`, a `<select>`, a `<textarea>`, a custom control.
62
+ * Handlers on the child still run; the bindings run after them.
63
+ */
64
+ declare function FieldControl(props: FieldControlProps): react.JSX.Element;
65
+ type FieldDescriptionProps = ComponentPropsWithoutRef<"p"> & {
66
+ asChild?: boolean;
67
+ };
68
+ /** Guidance under the control. Hidden while the field has an error. */
69
+ declare function FieldDescription({ asChild, ...props }: FieldDescriptionProps): react.JSX.Element | null;
70
+ type FieldMessageProps = ComponentPropsWithoutRef<"p"> & {
71
+ asChild?: boolean;
72
+ };
73
+ /**
74
+ * The field's error, announced as an alert. Renders the error the field
75
+ * currently holds; `children` is a fallback for a message the caller wants to
76
+ * show in its place. Nothing renders while the field is valid.
77
+ */
78
+ declare function FieldMessage({ asChild, children, ...props }: FieldMessageProps): react.JSX.Element | null;
79
+
80
+ export { type FieldBindings, type FieldContextValue, FieldControl, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldLabel, type FieldLabelProps, FieldMessage, type FieldMessageProps, FieldRoot, type FieldRootProps, useFieldContext };
@@ -0,0 +1,80 @@
1
+ import * as react from 'react';
2
+ import { ComponentPropsWithoutRef, ReactNode } from 'react';
3
+ import { Label } from '@radix-ui/react-label';
4
+ import { Slot } from '@radix-ui/react-slot';
5
+
6
+ /**
7
+ * The structure behind every form field, with no styling of its own: an id
8
+ * shared by label and control, the error and description ids the control is
9
+ * described by, the field's validity, and — inside a `Form` — the
10
+ * react-hook-form bindings (`value`, `onChange`, `onBlur`, `ref`) that keep
11
+ * the control registered.
12
+ *
13
+ * Styled components compose these primitives with their own classes
14
+ * (`TextInput` and friends do), and a screen that needs a control the
15
+ * library does not ship — a select, a code entry, a toggle — composes them
16
+ * the same way. Everything here is a plain element or a Radix `Slot`, so the
17
+ * styling decisions stay with whoever renders the field.
18
+ *
19
+ * Outside a `Form` the primitives still wire label, control and messages
20
+ * together; the control just isn't registered anywhere and the error comes
21
+ * from the `error` prop alone.
22
+ */
23
+ type FieldBindings = {
24
+ name: string;
25
+ value?: unknown;
26
+ onChange?: (event: unknown) => void;
27
+ onBlur?: () => void;
28
+ ref?: (instance: HTMLElement | null) => void;
29
+ };
30
+ type FieldContextValue = {
31
+ id: string;
32
+ name: string;
33
+ descriptionId: string;
34
+ messageId: string;
35
+ error: string | undefined;
36
+ invalid: boolean;
37
+ required: boolean;
38
+ disabled: boolean;
39
+ hasDescription: boolean;
40
+ setHasDescription: (present: boolean) => void;
41
+ bindings: FieldBindings;
42
+ };
43
+ declare function useFieldContext(): FieldContextValue;
44
+ type FieldRootProps = ComponentPropsWithoutRef<"div"> & {
45
+ /** The form field this wires up — the key in the `Form`'s values. */
46
+ name: string;
47
+ /** A caller-supplied error. Outranks whatever the form's schema reports. */
48
+ error?: string;
49
+ required?: boolean;
50
+ disabled?: boolean;
51
+ /** Render the child element as the root instead of a `div`. */
52
+ asChild?: boolean;
53
+ children: ReactNode;
54
+ };
55
+ declare function FieldRoot(props: FieldRootProps): react.JSX.Element;
56
+ type FieldLabelProps = ComponentPropsWithoutRef<typeof Label>;
57
+ declare function FieldLabel(props: FieldLabelProps): react.JSX.Element;
58
+ type FieldControlProps = ComponentPropsWithoutRef<typeof Slot>;
59
+ /**
60
+ * Wires the field's id, name, validity and bindings onto whatever element it
61
+ * wraps — an `<input>`, a `<select>`, a `<textarea>`, a custom control.
62
+ * Handlers on the child still run; the bindings run after them.
63
+ */
64
+ declare function FieldControl(props: FieldControlProps): react.JSX.Element;
65
+ type FieldDescriptionProps = ComponentPropsWithoutRef<"p"> & {
66
+ asChild?: boolean;
67
+ };
68
+ /** Guidance under the control. Hidden while the field has an error. */
69
+ declare function FieldDescription({ asChild, ...props }: FieldDescriptionProps): react.JSX.Element | null;
70
+ type FieldMessageProps = ComponentPropsWithoutRef<"p"> & {
71
+ asChild?: boolean;
72
+ };
73
+ /**
74
+ * The field's error, announced as an alert. Renders the error the field
75
+ * currently holds; `children` is a fallback for a message the caller wants to
76
+ * show in its place. Nothing renders while the field is valid.
77
+ */
78
+ declare function FieldMessage({ asChild, children, ...props }: FieldMessageProps): react.JSX.Element | null;
79
+
80
+ export { type FieldBindings, type FieldContextValue, FieldControl, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldLabel, type FieldLabelProps, FieldMessage, type FieldMessageProps, FieldRoot, type FieldRootProps, useFieldContext };
package/dist/field.js ADDED
@@ -0,0 +1,186 @@
1
+ "use client";
2
+ "use client";
3
+
4
+ // src/components/field/index.tsx
5
+ import { Label } from "@radix-ui/react-label";
6
+ import { Slot } from "@radix-ui/react-slot";
7
+ import {
8
+ createContext,
9
+ useContext,
10
+ useEffect,
11
+ useId,
12
+ useState
13
+ } from "react";
14
+ import {
15
+ useController,
16
+ useFormContext
17
+ } from "react-hook-form";
18
+ import { jsx } from "react/jsx-runtime";
19
+ var FieldContext = createContext(null);
20
+ function useFieldContext() {
21
+ const context = useContext(FieldContext);
22
+ if (!context) {
23
+ throw new Error("Field primitives must be rendered inside FieldRoot");
24
+ }
25
+ return context;
26
+ }
27
+ function useFieldIds(id) {
28
+ const generated = useId();
29
+ const base = id ?? generated;
30
+ return {
31
+ id: base,
32
+ descriptionId: `${base}-description`,
33
+ messageId: `${base}-message`
34
+ };
35
+ }
36
+ function FieldShell({
37
+ value,
38
+ asChild = false,
39
+ children,
40
+ ...rest
41
+ }) {
42
+ const [hasDescription, setHasDescription] = useState(false);
43
+ const Component = asChild ? Slot : "div";
44
+ return /* @__PURE__ */ jsx(
45
+ FieldContext.Provider,
46
+ {
47
+ value: { ...value, hasDescription, setHasDescription },
48
+ children: /* @__PURE__ */ jsx(
49
+ Component,
50
+ {
51
+ ...rest,
52
+ "data-invalid": value.invalid ? "" : void 0,
53
+ "data-disabled": value.disabled ? "" : void 0,
54
+ children
55
+ }
56
+ )
57
+ }
58
+ );
59
+ }
60
+ function ConnectedFieldRoot({
61
+ name,
62
+ error,
63
+ required = false,
64
+ disabled = false,
65
+ id,
66
+ ...rest
67
+ }) {
68
+ const ids = useFieldIds(id);
69
+ const { field, fieldState } = useController({ name, disabled });
70
+ const shownError = error ?? fieldState.error?.message;
71
+ return /* @__PURE__ */ jsx(
72
+ FieldShell,
73
+ {
74
+ ...rest,
75
+ value: {
76
+ ...ids,
77
+ name,
78
+ error: shownError,
79
+ invalid: Boolean(shownError),
80
+ required,
81
+ disabled: Boolean(field.disabled ?? disabled),
82
+ bindings: {
83
+ name: field.name,
84
+ value: field.value ?? "",
85
+ onChange: field.onChange,
86
+ onBlur: field.onBlur,
87
+ ref: field.ref
88
+ }
89
+ }
90
+ }
91
+ );
92
+ }
93
+ function StandaloneFieldRoot({
94
+ name,
95
+ error,
96
+ required = false,
97
+ disabled = false,
98
+ id,
99
+ ...rest
100
+ }) {
101
+ const ids = useFieldIds(id);
102
+ return /* @__PURE__ */ jsx(
103
+ FieldShell,
104
+ {
105
+ ...rest,
106
+ value: {
107
+ ...ids,
108
+ name,
109
+ error,
110
+ invalid: Boolean(error),
111
+ required,
112
+ disabled,
113
+ bindings: { name }
114
+ }
115
+ }
116
+ );
117
+ }
118
+ function FieldRoot(props) {
119
+ const form = useFormContext();
120
+ return form ? /* @__PURE__ */ jsx(ConnectedFieldRoot, { ...props }) : /* @__PURE__ */ jsx(StandaloneFieldRoot, { ...props });
121
+ }
122
+ function FieldLabel(props) {
123
+ const { id } = useFieldContext();
124
+ return /* @__PURE__ */ jsx(Label, { ...props, htmlFor: id });
125
+ }
126
+ function describedBy({
127
+ error,
128
+ messageId,
129
+ hasDescription,
130
+ descriptionId
131
+ }) {
132
+ if (error) {
133
+ return messageId;
134
+ }
135
+ return hasDescription ? descriptionId : void 0;
136
+ }
137
+ function FieldControl(props) {
138
+ const context = useFieldContext();
139
+ const { id, invalid, required, disabled, bindings } = context;
140
+ const controlProps = {
141
+ ...bindings,
142
+ id,
143
+ "aria-invalid": invalid || void 0,
144
+ "aria-required": required || void 0,
145
+ "aria-describedby": describedBy(context),
146
+ disabled: disabled || void 0
147
+ };
148
+ return /* @__PURE__ */ jsx(Slot, { ...props, ...controlProps });
149
+ }
150
+ function FieldDescription({
151
+ asChild = false,
152
+ ...props
153
+ }) {
154
+ const { descriptionId, error, setHasDescription } = useFieldContext();
155
+ useEffect(() => {
156
+ setHasDescription(true);
157
+ return () => setHasDescription(false);
158
+ }, [setHasDescription]);
159
+ if (error) {
160
+ return null;
161
+ }
162
+ const Component = asChild ? Slot : "p";
163
+ return /* @__PURE__ */ jsx(Component, { ...props, id: descriptionId });
164
+ }
165
+ function FieldMessage({
166
+ asChild = false,
167
+ children,
168
+ ...props
169
+ }) {
170
+ const { messageId, error } = useFieldContext();
171
+ const content = error ?? children;
172
+ if (!content) {
173
+ return null;
174
+ }
175
+ const Component = asChild ? Slot : "p";
176
+ return /* @__PURE__ */ jsx(Component, { ...props, id: messageId, role: "alert", children: content });
177
+ }
178
+ export {
179
+ FieldControl,
180
+ FieldDescription,
181
+ FieldLabel,
182
+ FieldMessage,
183
+ FieldRoot,
184
+ useFieldContext
185
+ };
186
+ //# sourceMappingURL=field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/field/index.tsx"],"sourcesContent":["\"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"],"mappings":"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","names":[]}