@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.
- package/.scaffold-cache.json +537 -0
- package/package.json +42 -0
- package/src/.scaffold-cache.json +544 -0
- package/src/adapters/axios.ts +117 -0
- package/src/adapters/index.ts +91 -0
- package/src/adapters/inertia.ts +187 -0
- package/src/core/adapter-registry.ts +87 -0
- package/src/core/bound/bind-host.ts +14 -0
- package/src/core/bound/observe-bound-field.ts +172 -0
- package/src/core/bound/wait-for-bound-field.ts +57 -0
- package/src/core/context.ts +23 -0
- package/src/core/core-provider.tsx +818 -0
- package/src/core/core-root.tsx +72 -0
- package/src/core/core-shell.tsx +44 -0
- package/src/core/errors/error-strip.tsx +71 -0
- package/src/core/errors/index.ts +2 -0
- package/src/core/errors/map-error-bag.ts +51 -0
- package/src/core/errors/map-zod.ts +39 -0
- package/src/core/hooks/use-button.ts +220 -0
- package/src/core/hooks/use-core-context.ts +20 -0
- package/src/core/hooks/use-core-utility.ts +0 -0
- package/src/core/hooks/use-core.ts +13 -0
- package/src/core/hooks/use-field.ts +497 -0
- package/src/core/hooks/use-optional-field.ts +28 -0
- package/src/core/index.ts +0 -0
- package/src/core/registry/binder-registry.ts +82 -0
- package/src/core/registry/field-registry.ts +187 -0
- package/src/core/test.tsx +17 -0
- package/src/global.d.ts +14 -0
- package/src/index.ts +68 -0
- package/src/input/index.ts +4 -0
- package/src/input/input-field.tsx +854 -0
- package/src/input/input-layout-graph.ts +230 -0
- package/src/input/input-props.ts +190 -0
- package/src/lib/get-global-countries.ts +87 -0
- package/src/lib/utils.ts +6 -0
- package/src/presets/index.ts +0 -0
- package/src/presets/shadcn-preset.ts +0 -0
- package/src/presets/shadcn-variants/checkbox.tsx +849 -0
- package/src/presets/shadcn-variants/chips.tsx +756 -0
- package/src/presets/shadcn-variants/color.tsx +284 -0
- package/src/presets/shadcn-variants/custom.tsx +227 -0
- package/src/presets/shadcn-variants/date.tsx +796 -0
- package/src/presets/shadcn-variants/file.tsx +764 -0
- package/src/presets/shadcn-variants/keyvalue.tsx +556 -0
- package/src/presets/shadcn-variants/multiselect.tsx +1132 -0
- package/src/presets/shadcn-variants/number.tsx +176 -0
- package/src/presets/shadcn-variants/password.tsx +737 -0
- package/src/presets/shadcn-variants/phone.tsx +628 -0
- package/src/presets/shadcn-variants/radio.tsx +578 -0
- package/src/presets/shadcn-variants/select.tsx +956 -0
- package/src/presets/shadcn-variants/slider.tsx +622 -0
- package/src/presets/shadcn-variants/text.tsx +343 -0
- package/src/presets/shadcn-variants/textarea.tsx +66 -0
- package/src/presets/shadcn-variants/toggle.tsx +218 -0
- package/src/presets/shadcn-variants/treeselect.tsx +784 -0
- package/src/presets/ui/badge.tsx +46 -0
- package/src/presets/ui/button.tsx +60 -0
- package/src/presets/ui/calendar.tsx +214 -0
- package/src/presets/ui/checkbox.tsx +115 -0
- package/src/presets/ui/custom.tsx +0 -0
- package/src/presets/ui/dialog.tsx +141 -0
- package/src/presets/ui/field.tsx +246 -0
- package/src/presets/ui/input-mask.tsx +739 -0
- package/src/presets/ui/input-otp.tsx +77 -0
- package/src/presets/ui/input.tsx +1011 -0
- package/src/presets/ui/label.tsx +22 -0
- package/src/presets/ui/number.tsx +1370 -0
- package/src/presets/ui/popover.tsx +46 -0
- package/src/presets/ui/radio-group.tsx +43 -0
- package/src/presets/ui/scroll-area.tsx +56 -0
- package/src/presets/ui/select.tsx +190 -0
- package/src/presets/ui/separator.tsx +28 -0
- package/src/presets/ui/slider.tsx +61 -0
- package/src/presets/ui/switch.tsx +32 -0
- package/src/presets/ui/textarea.tsx +634 -0
- package/src/presets/ui/time-dropdowns.tsx +350 -0
- package/src/schema/adapter.ts +217 -0
- package/src/schema/core.ts +429 -0
- package/src/schema/field-map.ts +0 -0
- package/src/schema/field.ts +224 -0
- package/src/schema/index.ts +0 -0
- package/src/schema/input-field.ts +260 -0
- package/src/schema/presets.ts +0 -0
- package/src/schema/variant.ts +216 -0
- package/src/variants/core/checkbox.tsx +54 -0
- package/src/variants/core/chips.tsx +22 -0
- package/src/variants/core/color.tsx +16 -0
- package/src/variants/core/custom.tsx +18 -0
- package/src/variants/core/date.tsx +25 -0
- package/src/variants/core/file.tsx +9 -0
- package/src/variants/core/keyvalue.tsx +12 -0
- package/src/variants/core/multiselect.tsx +28 -0
- package/src/variants/core/number.tsx +115 -0
- package/src/variants/core/password.tsx +35 -0
- package/src/variants/core/phone.tsx +16 -0
- package/src/variants/core/radio.tsx +38 -0
- package/src/variants/core/select.tsx +15 -0
- package/src/variants/core/slider.tsx +55 -0
- package/src/variants/core/text.tsx +114 -0
- package/src/variants/core/textarea.tsx +22 -0
- package/src/variants/core/toggle.tsx +50 -0
- package/src/variants/core/treeselect.tsx +11 -0
- package/src/variants/helpers/selection-summary.tsx +236 -0
- package/src/variants/index.ts +75 -0
- package/src/variants/registry.ts +38 -0
- package/src/variants/select-shared.ts +0 -0
- package/src/variants/shared.ts +126 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { InputNumber, InputNumberProps, InputNumberValueChangeEvent } from "../ui/number";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
import { ChevronUp, ChevronDown, Plus, Minus } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
// Wrapper-level props for the variant
|
|
7
|
+
export type ShadcnNumberVariantProps =
|
|
8
|
+
// All the usual number stuff (mode, locale, prefix, suffix, etc.)
|
|
9
|
+
Omit<InputNumberProps,
|
|
10
|
+
| "onValueChange"
|
|
11
|
+
| "onChange"
|
|
12
|
+
| "leadingControl"
|
|
13
|
+
| "trailingControl"
|
|
14
|
+
>
|
|
15
|
+
& {
|
|
16
|
+
/**
|
|
17
|
+
* Show +/- buttons around the numeric field.
|
|
18
|
+
* Defaults to false.
|
|
19
|
+
*/
|
|
20
|
+
showButtons?: boolean;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* How the step buttons are laid out when showButtons is true.
|
|
24
|
+
*
|
|
25
|
+
* - 'inline': "-" on the left, "+" on the right
|
|
26
|
+
* - 'stacked': vertical +/- stack on the right
|
|
27
|
+
*/
|
|
28
|
+
buttonLayout?: "inline" | "stacked";
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
export const ShadcnNumberVariant = React.forwardRef<
|
|
33
|
+
HTMLInputElement,
|
|
34
|
+
ShadcnNumberVariantProps
|
|
35
|
+
>(function ShadcnNumberVariant(props, forwardedRef) {
|
|
36
|
+
const {
|
|
37
|
+
showButtons,
|
|
38
|
+
buttonLayout = "stacked",
|
|
39
|
+
disabled, // Extract disabled to style buttons
|
|
40
|
+
...rest
|
|
41
|
+
} = props;
|
|
42
|
+
|
|
43
|
+
// we still want access to these for stepping logic
|
|
44
|
+
const {
|
|
45
|
+
step = 1,
|
|
46
|
+
min,
|
|
47
|
+
value,
|
|
48
|
+
max,
|
|
49
|
+
onValue: onValueChange,
|
|
50
|
+
name,
|
|
51
|
+
id,
|
|
52
|
+
inputId,
|
|
53
|
+
} = rest as ShadcnNumberVariantProps;
|
|
54
|
+
|
|
55
|
+
const handleChange = React.useCallback(
|
|
56
|
+
(e: InputNumberValueChangeEvent) => {
|
|
57
|
+
if (onValueChange) {
|
|
58
|
+
onValueChange(e.value as any, {
|
|
59
|
+
source: "user",
|
|
60
|
+
nativeEvent: e.originalEvent as any,
|
|
61
|
+
raw: e.value,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
[onValueChange]
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const handleStep = React.useCallback(
|
|
69
|
+
(direction: 1 | -1, originalEvent: React.SyntheticEvent<any>) => {
|
|
70
|
+
if (disabled) return;
|
|
71
|
+
|
|
72
|
+
const current = value ?? 0;
|
|
73
|
+
let next = current + direction * step;
|
|
74
|
+
|
|
75
|
+
if (typeof min === "number") next = Math.max(next, min);
|
|
76
|
+
if (typeof max === "number") next = Math.min(next, max);
|
|
77
|
+
|
|
78
|
+
// Prime-style event
|
|
79
|
+
const e: InputNumberValueChangeEvent = {
|
|
80
|
+
originalEvent,
|
|
81
|
+
value: next,
|
|
82
|
+
stopPropagation: () => originalEvent.stopPropagation(),
|
|
83
|
+
preventDefault: () => originalEvent.preventDefault(),
|
|
84
|
+
target: {
|
|
85
|
+
name,
|
|
86
|
+
id: id ?? inputId ?? null,
|
|
87
|
+
value: next,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
handleChange(e)
|
|
92
|
+
},
|
|
93
|
+
[value, step, min, max, onValueChange, name, id, inputId, disabled, handleChange]
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// --- Styles ---
|
|
97
|
+
// Common styles for the interactive buttons
|
|
98
|
+
const btnBase = "flex h-full items-center justify-center bg-transparent text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:cursor-not-allowed";
|
|
99
|
+
|
|
100
|
+
// Build controls based on layout
|
|
101
|
+
let leadingControl: React.ReactNode | undefined;
|
|
102
|
+
let trailingControl: React.ReactNode | undefined;
|
|
103
|
+
|
|
104
|
+
if (showButtons) {
|
|
105
|
+
if (buttonLayout === "inline") {
|
|
106
|
+
// INLINE: "-" on the left, "+" on the right
|
|
107
|
+
leadingControl = (
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
tabIndex={-1} // Prevent tabbing to buttons
|
|
111
|
+
disabled={disabled}
|
|
112
|
+
onClick={(e) => handleStep(-1, e)}
|
|
113
|
+
className={cn(btnBase, "border-r border-input px-3")}
|
|
114
|
+
aria-label="Decrease value"
|
|
115
|
+
>
|
|
116
|
+
<Minus className="h-4 w-4" />
|
|
117
|
+
</button>
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
trailingControl = (
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
tabIndex={-1}
|
|
124
|
+
disabled={disabled}
|
|
125
|
+
onClick={(e) => handleStep(1, e)}
|
|
126
|
+
className={cn(btnBase, "border-l border-input px-3")}
|
|
127
|
+
aria-label="Increase value"
|
|
128
|
+
>
|
|
129
|
+
<Plus className="h-4 w-4" />
|
|
130
|
+
</button>
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
// STACKED: vertical +/- on the right
|
|
134
|
+
trailingControl = (
|
|
135
|
+
<div className="flex h-full flex-col border-l border-input">
|
|
136
|
+
<button
|
|
137
|
+
type="button"
|
|
138
|
+
tabIndex={-1}
|
|
139
|
+
disabled={disabled}
|
|
140
|
+
onClick={(e) => handleStep(1, e)}
|
|
141
|
+
className={cn(btnBase, "h-1/2 px-2 border-b border-input")}
|
|
142
|
+
aria-label="Increase value"
|
|
143
|
+
>
|
|
144
|
+
<ChevronUp className="h-3 w-3" />
|
|
145
|
+
</button>
|
|
146
|
+
<button
|
|
147
|
+
type="button"
|
|
148
|
+
tabIndex={-1}
|
|
149
|
+
disabled={disabled}
|
|
150
|
+
onClick={(e) => handleStep(-1, e)}
|
|
151
|
+
className={cn(btnBase, "h-1/2 px-2")}
|
|
152
|
+
aria-label="Decrease value"
|
|
153
|
+
>
|
|
154
|
+
<ChevronDown className="h-3 w-3" />
|
|
155
|
+
</button>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<InputNumber
|
|
163
|
+
ref={forwardedRef}
|
|
164
|
+
value={value}
|
|
165
|
+
disabled={disabled}
|
|
166
|
+
{...rest}
|
|
167
|
+
onValueChange={handleChange}
|
|
168
|
+
leadingControl={leadingControl}
|
|
169
|
+
trailingControl={trailingControl}
|
|
170
|
+
extendBoxToControls
|
|
171
|
+
// Ensure the controls sit flush inside the container
|
|
172
|
+
leadingControlClassName={cn("flex h-full", rest.leadingControlClassName)}
|
|
173
|
+
trailingControlClassName={cn("flex h-full", rest.trailingControlClassName)}
|
|
174
|
+
/>
|
|
175
|
+
);
|
|
176
|
+
});
|