@timeax/form-palette 0.0.1

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 (109) hide show
  1. package/.scaffold-cache.json +537 -0
  2. package/package.json +42 -0
  3. package/src/.scaffold-cache.json +544 -0
  4. package/src/adapters/axios.ts +117 -0
  5. package/src/adapters/index.ts +91 -0
  6. package/src/adapters/inertia.ts +187 -0
  7. package/src/core/adapter-registry.ts +87 -0
  8. package/src/core/bound/bind-host.ts +14 -0
  9. package/src/core/bound/observe-bound-field.ts +172 -0
  10. package/src/core/bound/wait-for-bound-field.ts +57 -0
  11. package/src/core/context.ts +23 -0
  12. package/src/core/core-provider.tsx +818 -0
  13. package/src/core/core-root.tsx +72 -0
  14. package/src/core/core-shell.tsx +44 -0
  15. package/src/core/errors/error-strip.tsx +71 -0
  16. package/src/core/errors/index.ts +2 -0
  17. package/src/core/errors/map-error-bag.ts +51 -0
  18. package/src/core/errors/map-zod.ts +39 -0
  19. package/src/core/hooks/use-button.ts +220 -0
  20. package/src/core/hooks/use-core-context.ts +20 -0
  21. package/src/core/hooks/use-core-utility.ts +0 -0
  22. package/src/core/hooks/use-core.ts +13 -0
  23. package/src/core/hooks/use-field.ts +497 -0
  24. package/src/core/hooks/use-optional-field.ts +28 -0
  25. package/src/core/index.ts +0 -0
  26. package/src/core/registry/binder-registry.ts +82 -0
  27. package/src/core/registry/field-registry.ts +187 -0
  28. package/src/core/test.tsx +17 -0
  29. package/src/global.d.ts +14 -0
  30. package/src/index.ts +68 -0
  31. package/src/input/index.ts +4 -0
  32. package/src/input/input-field.tsx +854 -0
  33. package/src/input/input-layout-graph.ts +230 -0
  34. package/src/input/input-props.ts +190 -0
  35. package/src/lib/get-global-countries.ts +87 -0
  36. package/src/lib/utils.ts +6 -0
  37. package/src/presets/index.ts +0 -0
  38. package/src/presets/shadcn-preset.ts +0 -0
  39. package/src/presets/shadcn-variants/checkbox.tsx +849 -0
  40. package/src/presets/shadcn-variants/chips.tsx +756 -0
  41. package/src/presets/shadcn-variants/color.tsx +284 -0
  42. package/src/presets/shadcn-variants/custom.tsx +227 -0
  43. package/src/presets/shadcn-variants/date.tsx +796 -0
  44. package/src/presets/shadcn-variants/file.tsx +764 -0
  45. package/src/presets/shadcn-variants/keyvalue.tsx +556 -0
  46. package/src/presets/shadcn-variants/multiselect.tsx +1132 -0
  47. package/src/presets/shadcn-variants/number.tsx +176 -0
  48. package/src/presets/shadcn-variants/password.tsx +737 -0
  49. package/src/presets/shadcn-variants/phone.tsx +628 -0
  50. package/src/presets/shadcn-variants/radio.tsx +578 -0
  51. package/src/presets/shadcn-variants/select.tsx +956 -0
  52. package/src/presets/shadcn-variants/slider.tsx +622 -0
  53. package/src/presets/shadcn-variants/text.tsx +343 -0
  54. package/src/presets/shadcn-variants/textarea.tsx +66 -0
  55. package/src/presets/shadcn-variants/toggle.tsx +218 -0
  56. package/src/presets/shadcn-variants/treeselect.tsx +784 -0
  57. package/src/presets/ui/badge.tsx +46 -0
  58. package/src/presets/ui/button.tsx +60 -0
  59. package/src/presets/ui/calendar.tsx +214 -0
  60. package/src/presets/ui/checkbox.tsx +115 -0
  61. package/src/presets/ui/custom.tsx +0 -0
  62. package/src/presets/ui/dialog.tsx +141 -0
  63. package/src/presets/ui/field.tsx +246 -0
  64. package/src/presets/ui/input-mask.tsx +739 -0
  65. package/src/presets/ui/input-otp.tsx +77 -0
  66. package/src/presets/ui/input.tsx +1011 -0
  67. package/src/presets/ui/label.tsx +22 -0
  68. package/src/presets/ui/number.tsx +1370 -0
  69. package/src/presets/ui/popover.tsx +46 -0
  70. package/src/presets/ui/radio-group.tsx +43 -0
  71. package/src/presets/ui/scroll-area.tsx +56 -0
  72. package/src/presets/ui/select.tsx +190 -0
  73. package/src/presets/ui/separator.tsx +28 -0
  74. package/src/presets/ui/slider.tsx +61 -0
  75. package/src/presets/ui/switch.tsx +32 -0
  76. package/src/presets/ui/textarea.tsx +634 -0
  77. package/src/presets/ui/time-dropdowns.tsx +350 -0
  78. package/src/schema/adapter.ts +217 -0
  79. package/src/schema/core.ts +429 -0
  80. package/src/schema/field-map.ts +0 -0
  81. package/src/schema/field.ts +224 -0
  82. package/src/schema/index.ts +0 -0
  83. package/src/schema/input-field.ts +260 -0
  84. package/src/schema/presets.ts +0 -0
  85. package/src/schema/variant.ts +216 -0
  86. package/src/variants/core/checkbox.tsx +54 -0
  87. package/src/variants/core/chips.tsx +22 -0
  88. package/src/variants/core/color.tsx +16 -0
  89. package/src/variants/core/custom.tsx +18 -0
  90. package/src/variants/core/date.tsx +25 -0
  91. package/src/variants/core/file.tsx +9 -0
  92. package/src/variants/core/keyvalue.tsx +12 -0
  93. package/src/variants/core/multiselect.tsx +28 -0
  94. package/src/variants/core/number.tsx +115 -0
  95. package/src/variants/core/password.tsx +35 -0
  96. package/src/variants/core/phone.tsx +16 -0
  97. package/src/variants/core/radio.tsx +38 -0
  98. package/src/variants/core/select.tsx +15 -0
  99. package/src/variants/core/slider.tsx +55 -0
  100. package/src/variants/core/text.tsx +114 -0
  101. package/src/variants/core/textarea.tsx +22 -0
  102. package/src/variants/core/toggle.tsx +50 -0
  103. package/src/variants/core/treeselect.tsx +11 -0
  104. package/src/variants/helpers/selection-summary.tsx +236 -0
  105. package/src/variants/index.ts +75 -0
  106. package/src/variants/registry.ts +38 -0
  107. package/src/variants/select-shared.ts +0 -0
  108. package/src/variants/shared.ts +126 -0
  109. package/tsconfig.json +14 -0
@@ -0,0 +1,115 @@
1
+ // src/variants/core/text.tsx
2
+
3
+ import * as React from "react";
4
+
5
+ import type { Dict } from "@/schema/core";
6
+ import type { VariantModule } from "@/schema/variant";
7
+ import type { ValidateResult } from "@/schema/input-field";
8
+ import { ShadcnTextVariant } from "@/presets/shadcn-variants/text";
9
+ import type { ShadcnTextUiProps } from "@/presets/shadcn-variants/text";
10
+ import { ShadcnNumberVariant, ShadcnNumberVariantProps } from "@/presets/shadcn-variants/number";
11
+
12
+ /**
13
+ * Text variant props (core layer).
14
+ *
15
+ * - Extends Dict so it can cleanly participate in the Variants registry.
16
+ * - Extends the Shadcn UI props so the core variant can pass everything
17
+ * straight through to the underlying visual component.
18
+ *
19
+ * This is where we hang *semantic* flags that drive validation.
20
+ */
21
+ export interface TextVariantProps extends Dict, ShadcnTextUiProps {
22
+ /**
23
+ * If true, the value will be trimmed before validation.
24
+ * (Visual value is still whatever the user types; this is just for
25
+ * validation semantics.)
26
+ */
27
+ trim?: boolean;
28
+
29
+ /**
30
+ * Minimum allowed string length (after optional trimming).
31
+ */
32
+ minLength?: number;
33
+
34
+ /**
35
+ * Maximum allowed string length (after optional trimming).
36
+ */
37
+ maxLength?: number;
38
+ }
39
+
40
+ /**
41
+ * Simple validation helper for the text variant.
42
+ */
43
+ function validateText(
44
+ value: number | undefined,
45
+ ctx: {
46
+ required?: boolean;
47
+ props: ShadcnNumberVariantProps;
48
+ }
49
+ ): ValidateResult {
50
+ const { required, props } = ctx;
51
+ const { minLength, maxLength } = props;
52
+
53
+ const raw = (value ?? "") + "";
54
+ const v = raw.trim();
55
+
56
+ // required
57
+ if (required && v.length === 0) {
58
+ return "This field is required.";
59
+ }
60
+
61
+ // minLength
62
+ if (typeof minLength === "number" && v.length > 0 && v.length < minLength) {
63
+ return `Please enter at least ${minLength} characters.`;
64
+ }
65
+
66
+ // maxLength
67
+ if (typeof maxLength === "number" && v.length > maxLength) {
68
+ return `Please enter no more than ${maxLength} characters.`;
69
+ }
70
+
71
+ return true;
72
+ }
73
+
74
+ /**
75
+ * Core text variant module.
76
+ *
77
+ * - Uses ShadcnTextVariant as the visual component.
78
+ * - Adds simple length-based validation.
79
+ * - Provides layout defaults for InputField to use.
80
+ */
81
+ export const numberVariant: VariantModule<"number"> = {
82
+ variant: "number",
83
+
84
+ // Visual component: Shadcn-based text input
85
+ Variant: ShadcnNumberVariant as any,
86
+
87
+ // Validation logic (runs before/alongside per-field onValidate)
88
+ validate(value, { required, props, field, form }) {
89
+ // field + form are available if you need them later.
90
+ return validateText(value, { required, props });
91
+ },
92
+
93
+ // Layout defaults for this variant
94
+ defaults: {
95
+ layout: {
96
+ labelPlacement: "top",
97
+ sublabelPlacement: "right",
98
+ descriptionPlacement: "below",
99
+ helpTextPlacement: "below",
100
+ errorTextPlacement: "below",
101
+ inline: false,
102
+ fullWidth: true,
103
+ defaultSize: "md",
104
+ defaultDensity: "comfortable",
105
+ },
106
+ },
107
+
108
+ meta: {
109
+ label: "Number",
110
+ description: "Single-line number input",
111
+ tags: ["number", "input", "integer", "float"],
112
+ },
113
+ };
114
+
115
+ export default numberVariant;
@@ -0,0 +1,35 @@
1
+ // src/variants/core/password.tsx
2
+
3
+ import type { VariantModuleFor } from "@/schema/variant";
4
+ import { ShadcnPasswordVariant } from "@/presets/shadcn-variants/password";
5
+
6
+ /**
7
+ * Core module for the "password" variant.
8
+ *
9
+ * - Uses the ShadcnPasswordVariant UI (Input + reveal toggle + strength meter).
10
+ * - Value type is string | undefined (from Variants["password"].value).
11
+ * - Props are ShadcnPasswordVariantProps (from Variants["password"].props).
12
+ */
13
+ export const passwordVariant: VariantModuleFor<"password"> = {
14
+ variant: "password",
15
+ Variant: ShadcnPasswordVariant,
16
+
17
+ // Optional layout defaults – tweak as you like
18
+ defaults: {
19
+ layout: {
20
+ fullWidth: true,
21
+ // You can set defaultSize/defaultDensity here if you want:
22
+ // defaultSize: "md",
23
+ // defaultDensity: "normal",
24
+ },
25
+ },
26
+
27
+ meta: {
28
+ label: "Password",
29
+ description:
30
+ "Password input with reveal toggle and optional strength meter.",
31
+ tags: ["auth", "security", "password"],
32
+ },
33
+ };
34
+
35
+ export default passwordVariant;
@@ -0,0 +1,16 @@
1
+ // ———————————————————————————————
2
+ // VariantModule wiring
3
+
4
+ import { ShadcnPhoneVariant } from "@/presets/shadcn-variants/phone";
5
+ import { VariantModule } from "@/schema/variant";
6
+
7
+ // ———————————————————————————————
8
+ export const PhoneVariantModule: VariantModule<"phone"> = {
9
+ variant: "phone",
10
+ Variant: ShadcnPhoneVariant,
11
+ meta: {
12
+ label: "Phone",
13
+ description: "Phone number input with country code and masking.",
14
+ tags: ["phone", "tel", "contact"],
15
+ },
16
+ };
@@ -0,0 +1,38 @@
1
+ // src/variants/core/radio.ts
2
+
3
+ import type { VariantModuleFor } from "@/schema/variant";
4
+ import { ShadcnRadioVariant } from "@/presets/shadcn-variants/radio";
5
+
6
+ /**
7
+ * Built-in "radio" variant module.
8
+ *
9
+ * Uses the Shadcn-based implementation in presets/shadcn-variants/radio.tsx
10
+ */
11
+ export const radioVariantModule: VariantModuleFor<"radio"> = {
12
+ variant: "radio",
13
+ // Note: registry-level typing uses unknown, but the component itself is generic.
14
+ Variant: ShadcnRadioVariant as any,
15
+ defaults: {
16
+ layout: {
17
+ // Standard stacked field layout; the smart renderer still
18
+ // handles ordering/relative roots for helpers.
19
+ labelPlacement: "top",
20
+ sublabelPlacement: "right",
21
+ descriptionPlacement: "below",
22
+ helpTextPlacement: "below",
23
+ errorTextPlacement: "below",
24
+ inline: false,
25
+ fullWidth: true,
26
+
27
+ // Explicit layout hints
28
+ defaultSize: "md",
29
+ defaultDensity: "comfortable", // ← uses your FieldDensity union
30
+ },
31
+ },
32
+ meta: {
33
+ label: "Radio group",
34
+ description:
35
+ "Choose one option from a list of mutually exclusive choices.",
36
+ tags: ["choice", "select", "exclusive", "radio"],
37
+ },
38
+ };
@@ -0,0 +1,15 @@
1
+ import ShadcnSelectVariant, { ShadcnSelectVariantProps } from "@/presets/shadcn-variants/select";
2
+ import { VariantModuleFor } from "@/schema/variant";
3
+
4
+ export type SelectVariantProps = ShadcnSelectVariantProps;
5
+
6
+ export const selectModule: VariantModuleFor<"select"> = {
7
+ variant: "select",
8
+ Variant: ShadcnSelectVariant,
9
+
10
+ meta: {
11
+ label: "Select",
12
+ description: "Single-value dropdown based on Shadcn Select.",
13
+ tags: ["select", "dropdown", "single-value"],
14
+ },
15
+ };
@@ -0,0 +1,55 @@
1
+ // src/variants/core/slider.ts
2
+
3
+ import type { ValidateResult } from "@/schema/input-field";
4
+ import type { ShadcnSliderVariantProps } from "@/presets/shadcn-variants/slider";
5
+ import { ShadcnSliderVariant } from "@/presets/shadcn-variants/slider";
6
+ import { VariantModule } from "@/schema/variant";
7
+
8
+ /**
9
+ * Slider value type:
10
+ * - `number | undefined` for now (single-value slider).
11
+ * If/when you add range support, this can be widened to [number, number].
12
+ */
13
+ export type SliderValue = number | undefined;
14
+
15
+
16
+ /**
17
+ * Basic validation:
18
+ * - if required → must have a numeric value
19
+ * - otherwise always OK
20
+ */
21
+ function validateSlider(
22
+ value: SliderValue,
23
+ ctx: { required?: boolean }
24
+ ): ValidateResult {
25
+ if (ctx.required) {
26
+ if (value === undefined || value === null) {
27
+ return "Required.";
28
+ }
29
+ if (typeof value !== "number" || Number.isNaN(value)) {
30
+ return "Invalid number.";
31
+ }
32
+ }
33
+
34
+ // You could optionally enforce min/max here using ctx.props
35
+ return true;
36
+ }
37
+
38
+ /**
39
+ * Register the slider variant with the global registry.
40
+ *
41
+ * No layout defaults are provided here:
42
+ * - layout (inline vs stacked, label placement, etc.) is controlled by
43
+ * the host via FieldLayoutConfig / InputField overrides instead.
44
+ */
45
+ export default {
46
+ variant: "slider",
47
+ Variant: ShadcnSliderVariant,
48
+ validate(value, ctx): ValidateResult {
49
+ return validateSlider(value as SliderValue, {
50
+ required: ctx.required,
51
+ });
52
+ },
53
+ } as VariantModule<'slider'>;
54
+
55
+ export type SliderVariantProps = ShadcnSliderVariantProps;
@@ -0,0 +1,114 @@
1
+ // src/variants/core/text.tsx
2
+
3
+ import * as React from "react";
4
+
5
+ import type { Dict } from "@/schema/core";
6
+ import type { VariantModule } from "@/schema/variant";
7
+ import type { ValidateResult } from "@/schema/input-field";
8
+ import { ShadcnTextVariant } from "@/presets/shadcn-variants/text";
9
+ import type { ShadcnTextUiProps, ShadcnTextVariantProps } from "@/presets/shadcn-variants/text";
10
+
11
+ /**
12
+ * Text variant props (core layer).
13
+ *
14
+ * - Extends Dict so it can cleanly participate in the Variants registry.
15
+ * - Extends the Shadcn UI props so the core variant can pass everything
16
+ * straight through to the underlying visual component.
17
+ *
18
+ * This is where we hang *semantic* flags that drive validation.
19
+ */
20
+ export interface TextVariantProps extends Dict, ShadcnTextUiProps {
21
+ /**
22
+ * If true, the value will be trimmed before validation.
23
+ * (Visual value is still whatever the user types; this is just for
24
+ * validation semantics.)
25
+ */
26
+ trim?: boolean;
27
+
28
+ /**
29
+ * Minimum allowed string length (after optional trimming).
30
+ */
31
+ minLength?: number;
32
+
33
+ /**
34
+ * Maximum allowed string length (after optional trimming).
35
+ */
36
+ maxLength?: number;
37
+ }
38
+
39
+ /**
40
+ * Simple validation helper for the text variant.
41
+ */
42
+ function validateText(
43
+ value: string | undefined,
44
+ ctx: {
45
+ required?: boolean;
46
+ props: ShadcnTextVariantProps & TextVariantProps;
47
+ }
48
+ ): ValidateResult {
49
+ const { required, props } = ctx;
50
+ const { trim, minLength, maxLength } = props;
51
+
52
+ const raw = value ?? "";
53
+ const v = trim ? raw.trim() : raw;
54
+
55
+ // required
56
+ if (required && v.length === 0) {
57
+ return "This field is required.";
58
+ }
59
+
60
+ // minLength
61
+ if (typeof minLength === "number" && v.length > 0 && v.length < minLength) {
62
+ return `Please enter at least ${minLength} characters.`;
63
+ }
64
+
65
+ // maxLength
66
+ if (typeof maxLength === "number" && v.length > maxLength) {
67
+ return `Please enter no more than ${maxLength} characters.`;
68
+ }
69
+
70
+ return true;
71
+ }
72
+
73
+ /**
74
+ * Core text variant module.
75
+ *
76
+ * - Uses ShadcnTextVariant as the visual component.
77
+ * - Adds simple length-based validation.
78
+ * - Provides layout defaults for InputField to use.
79
+ */
80
+ export const textVariant: VariantModule<"text"> = {
81
+ variant: "text",
82
+
83
+ // Visual component: Shadcn-based text input
84
+ Variant: ShadcnTextVariant,
85
+
86
+ // Validation logic (runs before/alongside per-field onValidate)
87
+ validate(value, { required, props, field, form }) {
88
+ //@ts-ignore field + form are available if you need them later.
89
+ return validateText(value, { required, props });
90
+ },
91
+
92
+ // Layout defaults for this variant
93
+ defaults: {
94
+ layout: {
95
+ labelPlacement: "top",
96
+ sublabelPlacement: "right",
97
+ descriptionPlacement: "below",
98
+ helpTextPlacement: "below",
99
+ errorTextPlacement: "below",
100
+ inline: false,
101
+ fullWidth: true,
102
+ defaultSize: "md",
103
+ defaultDensity: "comfortable",
104
+ },
105
+ },
106
+
107
+ meta: {
108
+ label: "Text",
109
+ description: "Single-line text input",
110
+ tags: ["text", "input", "string"],
111
+ },
112
+ };
113
+
114
+ export default textVariant;
@@ -0,0 +1,22 @@
1
+ import ShadcnTextareaVariant from "@/presets/shadcn-variants/textarea";
2
+ import { VariantModuleFor } from "@/schema/variant";
3
+
4
+
5
+ export const textareaVariant: VariantModuleFor<"textarea"> = {
6
+ variant: "textarea",
7
+ Variant: ShadcnTextareaVariant as any,
8
+ // Optional layout defaults – tweak as you like
9
+ defaults: {
10
+ layout: {
11
+ fullWidth: true,
12
+ // You can set defaultSize/defaultDensity here if you want:
13
+ // defaultSize: "md",
14
+ // defaultDensity: "normal",
15
+ },
16
+ },
17
+ meta: {
18
+ label: "Textarea",
19
+ description: "Multi-line text input area.",
20
+ tags: ["text", "multiline", "comments", "notes"],
21
+ },
22
+ }
@@ -0,0 +1,50 @@
1
+ // src/variants/core/toggle.ts
2
+
3
+ import type { VariantModuleFor } from "@/schema/variant";
4
+ import type { FieldLayoutConfig } from "@/schema/input-field";
5
+ import ShadcnToggleVariant from "@/presets/shadcn-variants/toggle";
6
+
7
+ export const toggleLayoutDefaults: FieldLayoutConfig = {
8
+ // Render label + control in a single row
9
+ inline: true,
10
+
11
+ // Semantically: label is to the "right" of the control for this variant.
12
+ // (Your InputField can use this to decide macro-level positioning.)
13
+ labelPlacement: "right",
14
+
15
+ // Attach all helpers to the label root by default.
16
+ // Sublabel will still use its own placement (default: "right"),
17
+ // but it's logically anchored to the label block.
18
+ relativeRoots: {
19
+ sublabel: "label",
20
+ description: "label",
21
+ helpText: "label",
22
+ errorText: "label",
23
+ },
24
+
25
+ fullWidth: false,
26
+
27
+ // Within the label root, show error first, then description, then help,
28
+ // then sublabel (all still respecting their individual placements).
29
+ ordering: {
30
+ label: ["errorText", "description", "helpText", "sublabel"],
31
+ // For this variant we don't really use input-root helpers,
32
+ // but we keep the key for completeness.
33
+ input: [],
34
+ },
35
+ };
36
+
37
+ export const ToggleVariantModule: VariantModuleFor<"toggle"> = {
38
+ variant: "toggle",
39
+ Variant: ShadcnToggleVariant as any,
40
+ defaults: {
41
+ layout: toggleLayoutDefaults,
42
+ },
43
+ meta: {
44
+ label: "Toggle",
45
+ description: "Boolean on/off switch",
46
+ tags: ["boolean", "toggle", "switch"],
47
+ },
48
+ };
49
+
50
+ export default ToggleVariantModule;
@@ -0,0 +1,11 @@
1
+ import ShadcnTreeSelectVariant from "@/presets/shadcn-variants/treeselect";
2
+ import { VariantModule } from "@/schema/variant";
3
+
4
+
5
+
6
+ const treeselectModule: VariantModule<'treeselect'> = {
7
+ variant: 'treeselect',
8
+ Variant: ShadcnTreeSelectVariant as any
9
+ }
10
+
11
+ export default treeselectModule