@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,187 @@
1
+ // src/core/registry/field-registry.ts
2
+
3
+ import type { Field } from "@/schema/field";
4
+ import { BinderRegistry } from "@/core/registry/binder-registry";
5
+
6
+ /**
7
+ * Runtime helper: check if a DOM node is currently attached.
8
+ *
9
+ * Guards against SSR or test environments where document may not exist.
10
+ */
11
+ export function isInDom(node: Element | null | undefined): boolean {
12
+ if (!node) return false;
13
+ if (typeof document === "undefined") return false;
14
+ return document.body.contains(node);
15
+ }
16
+
17
+ /**
18
+ * Central store for all fields registered with the core runtime.
19
+ *
20
+ * Responsibilities:
21
+ * - Keep a stable list of Field instances (no duplicates).
22
+ * - Only track fields that have at least one identifier:
23
+ * - name (non-empty, trimmed)
24
+ * - bindId
25
+ * - groupId
26
+ * - Provide convenient lookup methods:
27
+ * - all / getAllNamed / getAllBound / getAllGrouped
28
+ * - getByName / getAllByName
29
+ * - getByGroupId / getAllByGroupId
30
+ * - getByBind / getAllByBind (binder semantics, prefer mounted)
31
+ */
32
+ export class FieldRegistry {
33
+ private list: Field[] = [];
34
+ #binding: BinderRegistry | undefined;
35
+
36
+ /**
37
+ * Whether this field should be tracked at all.
38
+ *
39
+ * We require at least one of: name, bindId, groupId.
40
+ */
41
+ hasIdentifier(field: Field): boolean {
42
+ const anyField = field as any;
43
+ const name = (field.name ?? "").trim();
44
+ return !!(name || anyField.bindId || anyField.groupId);
45
+ }
46
+
47
+ /**
48
+ * Add a field to the registry if it has an identifier.
49
+ * Duplicate instances are ignored.
50
+ */
51
+ add(field: Field): void {
52
+ if (!this.hasIdentifier(field)) return;
53
+ if (this.list.includes(field)) return;
54
+ this.list.push(field);
55
+ }
56
+
57
+ /**
58
+ * Remove a field from the registry.
59
+ */
60
+ remove(field: Field): void {
61
+ const idx = this.list.indexOf(field);
62
+ if (idx === -1) return;
63
+ this.list.splice(idx, 1);
64
+ }
65
+
66
+ /**
67
+ * Clear all tracked fields.
68
+ */
69
+ clear(): void {
70
+ this.list = [];
71
+ }
72
+
73
+ /**
74
+ * All fields tracked by this registry.
75
+ */
76
+ all(): Field[] {
77
+ return this.list;
78
+ }
79
+
80
+ // ─────────────────────────────────────────────────────────
81
+ // “views” over the list
82
+ // ─────────────────────────────────────────────────────────
83
+
84
+ /** All fields that have a non-empty name. */
85
+ getAllNamed(): Field[] {
86
+ return this.list.filter((f) => !!(f.name && f.name.trim().length > 0));
87
+ }
88
+
89
+ /** All fields that have a bindId. */
90
+ getAllBound(): Field[] {
91
+ return this.list.filter((f) => (f as any).bindId);
92
+ }
93
+
94
+ /** All fields that have a groupId. */
95
+ getAllGrouped(): Field[] {
96
+ return this.list.filter((f) => (f as any).groupId);
97
+ }
98
+
99
+ // ─────────────────────────────────────────────────────────
100
+ // name-based lookups
101
+ // ─────────────────────────────────────────────────────────
102
+
103
+ /**
104
+ * First field with a given name (exact, trimmed match).
105
+ *
106
+ * Note: expects the raw name used by the field, e.g.:
107
+ * "email" or "tags[]"
108
+ */
109
+ getByName(name: string): Field | undefined {
110
+ if (!name) return undefined;
111
+ const target = name.trim();
112
+ if (!target) return undefined;
113
+
114
+ return this.list.find((f) => (f.name ?? "").trim() === target);
115
+ }
116
+
117
+ /**
118
+ * All fields with a given name (exact, trimmed match).
119
+ */
120
+ getAllByName(name: string): Field[] {
121
+ if (!name) return [];
122
+ const target = name.trim();
123
+ if (!target) return [];
124
+
125
+ return this.list.filter((f) => (f.name ?? "").trim() === target);
126
+ }
127
+
128
+ // ─────────────────────────────────────────────────────────
129
+ // groupId-based lookups
130
+ // ─────────────────────────────────────────────────────────
131
+
132
+ /** First field with the given groupId. */
133
+ getByGroupId(id: string): Field | undefined {
134
+ if (!id) return undefined;
135
+ return this.list.find((f) => (f as any).groupId === id);
136
+ }
137
+
138
+ /** All fields with the given groupId. */
139
+ getAllByGroupId(id: string): Field[] {
140
+ if (!id) return [];
141
+ return this.list.filter((f) => (f as any).groupId === id);
142
+ }
143
+
144
+ // ─────────────────────────────────────────────────────────
145
+ // bindId-based lookups (binder semantics)
146
+ // ─────────────────────────────────────────────────────────
147
+
148
+ /**
149
+ * All fields that share the given bindId.
150
+ */
151
+ getAllByBind(id: string): Field[] {
152
+ if (!id) return [];
153
+ return this.list.filter((f) => (f as any).bindId === id);
154
+ }
155
+
156
+ /**
157
+ * First field with the given bindId.
158
+ *
159
+ * Behaviour:
160
+ * - Prefer a field whose ref is currently in the DOM.
161
+ * - If none are mounted, fall back to the first matching field.
162
+ */
163
+ getByBind(id: string): Field | undefined {
164
+ if (!id) return undefined;
165
+
166
+ const candidates = this.getAllByBind(id);
167
+ if (!candidates.length) return undefined;
168
+
169
+ const mounted = candidates.find((f) => {
170
+ const anyField = f as any;
171
+ const el = anyField.ref?.current as Element | null | undefined;
172
+ return isInDom(el ?? null);
173
+ });
174
+
175
+ return mounted ?? candidates[0];
176
+ }
177
+
178
+ getBind(id: string): Field | undefined {
179
+ return this.getByBind(id);
180
+ }
181
+
182
+ get binding(): BinderRegistry {
183
+ if (!(this.#binding instanceof BinderRegistry))
184
+ this.#binding = new BinderRegistry(this);
185
+ return this.#binding;
186
+ }
187
+ }
@@ -0,0 +1,17 @@
1
+ import { InputField } from "@/index";
2
+ import { Form } from "@/index";
3
+
4
+ const Test = () => {
5
+ return (
6
+ <Form adapter="inertia">
7
+ <InputField
8
+ variant={"select"}
9
+ options={[{ label: 'name', value: 'string' }] as const}
10
+ optionValue='label'
11
+ onChange={e => {
12
+ e.detail.raw
13
+ }}
14
+ />
15
+ </Form>
16
+ )
17
+ }
@@ -0,0 +1,14 @@
1
+ import { PasswordDefinitionMap } from './presets/shadcn-variants/password';
2
+ // src/global.d.ts
3
+ import { PhoneCountry } from "./presets/shadcn-variants/phone";
4
+
5
+ declare global {
6
+ interface Window {
7
+ 'form-palette'?: {
8
+ countries: PhoneCountry[];
9
+ ruleDefinition: PasswordDefinitionMap;
10
+ };
11
+ }
12
+ }
13
+
14
+ export { };
package/src/index.ts ADDED
@@ -0,0 +1,68 @@
1
+ // src/index.ts
2
+
3
+ // ─────────────────────────────────────────────────────────────
4
+ // Schema exports (types only)
5
+ // ─────────────────────────────────────────────────────────────
6
+
7
+ // TS 5.x+ — keep these as type-only to avoid runtime cycles & noise.
8
+ export type * from "@/schema/core";
9
+ export type * from "@/schema/adapter";
10
+ export type * from "@/schema/field";
11
+ export type * from "@/schema/input-field";
12
+ export type * from "@/schema/variant";
13
+
14
+ // ─────────────────────────────────────────────────────────────
15
+ // Core runtime: provider + shell/root
16
+ // ─────────────────────────────────────────────────────────────
17
+
18
+ export { CoreProvider } from "@/core/core-provider";
19
+
20
+ // Export with aliases directly to keep type info intact
21
+ export { CoreShell, CoreShell as Form } from "@/core/core-shell";
22
+
23
+ export { CoreRoot, CoreRoot as FormRoot } from "@/core/core-root";
24
+
25
+ // ─────────────────────────────────────────────────────────────
26
+ // Core hooks
27
+ // ─────────────────────────────────────────────────────────────
28
+
29
+ export { useCore } from "@/core/hooks/use-core";
30
+ export { useCoreContext } from "@/core/hooks/use-core-context";
31
+ export { useField } from "@/core/hooks/use-field";
32
+ export { useOptionalField } from "@/core/hooks/use-optional-field";
33
+ export { useButton } from "@/core/hooks/use-button";
34
+
35
+ // ─────────────────────────────────────────────────────────────
36
+ // Errors / helpers
37
+ // ─────────────────────────────────────────────────────────────
38
+
39
+ export { ErrorStrip } from "@/core/errors/error-strip";
40
+ export { mapZodError } from "@/core/errors/map-zod";
41
+ export { mapErrorBag } from "@/core/errors/map-error-bag";
42
+
43
+ // ─────────────────────────────────────────────────────────────
44
+ // Input layer
45
+ // ─────────────────────────────────────────────────────────────
46
+
47
+ export { InputField } from "@/input/input-field";
48
+ export type { InputFieldProps, InputFieldBaseProps } from "@/input/input-props";
49
+
50
+ // ─────────────────────────────────────────────────────────────
51
+ // Variants & registry
52
+ // ─────────────────────────────────────────────────────────────
53
+
54
+ export { registerVariant, getVariant, listVariants } from "@/variants/registry";
55
+
56
+ export { registerCoreVariants } from "@/variants"; // if you have a convenience registrar there
57
+
58
+ export { Textarea } from "@/presets/ui/textarea";
59
+ export { Input } from '@/presets/ui/input';
60
+ // If you want to surface specific core variants:
61
+ export { textVariant } from "@/variants/core/text";
62
+ // (and similarly for others as you add them)
63
+
64
+ // ─────────────────────────────────────────────────────────────
65
+ // Adapters
66
+ // ─────────────────────────────────────────────────────────────
67
+
68
+ export * from "@/adapters";
@@ -0,0 +1,4 @@
1
+ // src/input/index.ts
2
+
3
+ export type { InputFieldProps, InputFieldBaseProps } from "@/input/input-props";
4
+ export { InputField } from "@/input/input-field";