@vinyasa/form 1.0.22
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/README.md +188 -0
- package/dist/cjs/autocomplete.cjs +344 -0
- package/dist/cjs/autocomplete.css +308 -0
- package/dist/cjs/checkbox.cjs +299 -0
- package/dist/cjs/checkbox.css +175 -0
- package/dist/cjs/color-picker.cjs +363 -0
- package/dist/cjs/color-picker.css +248 -0
- package/dist/cjs/combobox.cjs +394 -0
- package/dist/cjs/combobox.css +308 -0
- package/dist/cjs/date-picker.cjs +357 -0
- package/dist/cjs/date-picker.css +295 -0
- package/dist/cjs/dropzone.cjs +438 -0
- package/dist/cjs/dropzone.css +293 -0
- package/dist/cjs/file-upload.cjs +428 -0
- package/dist/cjs/file-upload.css +250 -0
- package/dist/cjs/icon-button.cjs +183 -0
- package/dist/cjs/index.cjs +3780 -0
- package/dist/cjs/index.css +1229 -0
- package/dist/cjs/input.cjs +340 -0
- package/dist/cjs/input.css +139 -0
- package/dist/cjs/multi-select.cjs +436 -0
- package/dist/cjs/multi-select.css +308 -0
- package/dist/cjs/number-input.cjs +458 -0
- package/dist/cjs/number-input.css +250 -0
- package/dist/cjs/otp-input.cjs +355 -0
- package/dist/cjs/otp-input.css +194 -0
- package/dist/cjs/password-input.cjs +368 -0
- package/dist/cjs/password-input.css +139 -0
- package/dist/cjs/radio-group.cjs +301 -0
- package/dist/cjs/radio-group.css +181 -0
- package/dist/cjs/range-slider.cjs +276 -0
- package/dist/cjs/range-slider.css +46 -0
- package/dist/cjs/rich-text-editor.cjs +570 -0
- package/dist/cjs/rich-text-editor.css +213 -0
- package/dist/cjs/search-input.cjs +380 -0
- package/dist/cjs/search-input.css +139 -0
- package/dist/cjs/select.cjs +407 -0
- package/dist/cjs/select.css +213 -0
- package/dist/cjs/slider.cjs +188 -0
- package/dist/cjs/slider.css +46 -0
- package/dist/cjs/switch.cjs +294 -0
- package/dist/cjs/switch.css +183 -0
- package/dist/cjs/tags-input.cjs +348 -0
- package/dist/cjs/tags-input.css +328 -0
- package/dist/cjs/textarea.cjs +361 -0
- package/dist/cjs/textarea.css +139 -0
- package/dist/cjs/time-picker.cjs +408 -0
- package/dist/cjs/time-picker.css +308 -0
- package/dist/cjs/toggle-button.cjs +172 -0
- package/dist/esm/27.css +46 -0
- package/dist/esm/27.js +38 -0
- package/dist/esm/2942.css +111 -0
- package/dist/esm/2942.js +13 -0
- package/dist/esm/2995.css +135 -0
- package/dist/esm/2995.js +117 -0
- package/dist/esm/3876.js +27 -0
- package/dist/esm/4557.js +39 -0
- package/dist/esm/6720.css +164 -0
- package/dist/esm/6720.js +19 -0
- package/dist/esm/autocomplete.d.ts +2 -0
- package/dist/esm/autocomplete.js +95 -0
- package/dist/esm/checkbox.css +36 -0
- package/dist/esm/checkbox.d.ts +2 -0
- package/dist/esm/checkbox.js +38 -0
- package/dist/esm/color-picker.css +109 -0
- package/dist/esm/color-picker.d.ts +2 -0
- package/dist/esm/color-picker.js +130 -0
- package/dist/esm/combobox.d.ts +2 -0
- package/dist/esm/combobox.js +126 -0
- package/dist/esm/components/autocomplete/Autocomplete.d.ts +21 -0
- package/dist/esm/components/autocomplete/index.d.ts +3 -0
- package/dist/esm/components/checkbox/Checkbox.css.d.ts +2 -0
- package/dist/esm/components/checkbox/Checkbox.d.ts +7 -0
- package/dist/esm/components/checkbox/index.d.ts +3 -0
- package/dist/esm/components/color-picker/ColorPicker.css.d.ts +11 -0
- package/dist/esm/components/color-picker/ColorPicker.d.ts +28 -0
- package/dist/esm/components/color-picker/index.d.ts +3 -0
- package/dist/esm/components/combobox/Combobox.d.ts +34 -0
- package/dist/esm/components/combobox/index.d.ts +3 -0
- package/dist/esm/components/date-picker/DatePicker.css.d.ts +18 -0
- package/dist/esm/components/date-picker/DatePicker.d.ts +29 -0
- package/dist/esm/components/date-picker/index.d.ts +3 -0
- package/dist/esm/components/dropzone/Dropzone.css.d.ts +4 -0
- package/dist/esm/components/dropzone/Dropzone.d.ts +20 -0
- package/dist/esm/components/dropzone/index.d.ts +3 -0
- package/dist/esm/components/file-upload/FileUpload.css.d.ts +11 -0
- package/dist/esm/components/file-upload/FileUpload.d.ts +20 -0
- package/dist/esm/components/file-upload/index.d.ts +3 -0
- package/dist/esm/components/icon-button/IconButton.d.ts +8 -0
- package/dist/esm/components/icon-button/index.d.ts +3 -0
- package/dist/esm/components/input/Input.d.ts +11 -0
- package/dist/esm/components/input/index.d.ts +3 -0
- package/dist/esm/components/multi-select/MultiSelect.d.ts +35 -0
- package/dist/esm/components/multi-select/index.d.ts +3 -0
- package/dist/esm/components/number-input/NumberInput.css.d.ts +51 -0
- package/dist/esm/components/number-input/NumberInput.d.ts +13 -0
- package/dist/esm/components/number-input/index.d.ts +3 -0
- package/dist/esm/components/otp-input/OtpInput.css.d.ts +6 -0
- package/dist/esm/components/otp-input/OtpInput.d.ts +16 -0
- package/dist/esm/components/otp-input/index.d.ts +3 -0
- package/dist/esm/components/password-input/PasswordInput.d.ts +11 -0
- package/dist/esm/components/password-input/index.d.ts +3 -0
- package/dist/esm/components/radio-group/RadioGroup.css.d.ts +3 -0
- package/dist/esm/components/radio-group/RadioGroup.d.ts +12 -0
- package/dist/esm/components/radio-group/index.d.ts +3 -0
- package/dist/esm/components/range-slider/RangeSlider.d.ts +11 -0
- package/dist/esm/components/range-slider/index.d.ts +3 -0
- package/dist/esm/components/rich-text-editor/RichTextEditor.css.d.ts +5 -0
- package/dist/esm/components/rich-text-editor/RichTextEditor.d.ts +18 -0
- package/dist/esm/components/rich-text-editor/index.d.ts +3 -0
- package/dist/esm/components/search-input/SearchInput.d.ts +13 -0
- package/dist/esm/components/search-input/index.d.ts +3 -0
- package/dist/esm/components/select/Select.css.d.ts +8 -0
- package/dist/esm/components/select/Select.d.ts +29 -0
- package/dist/esm/components/select/index.d.ts +3 -0
- package/dist/esm/components/slider/Slider.css.d.ts +4 -0
- package/dist/esm/components/slider/Slider.d.ts +12 -0
- package/dist/esm/components/slider/index.d.ts +3 -0
- package/dist/esm/components/switch/Switch.css.d.ts +2 -0
- package/dist/esm/components/switch/Switch.d.ts +7 -0
- package/dist/esm/components/switch/index.d.ts +3 -0
- package/dist/esm/components/tags-input/TagsInput.css.d.ts +1 -0
- package/dist/esm/components/tags-input/TagsInput.d.ts +18 -0
- package/dist/esm/components/tags-input/index.d.ts +3 -0
- package/dist/esm/components/textarea/Textarea.d.ts +13 -0
- package/dist/esm/components/textarea/index.d.ts +3 -0
- package/dist/esm/components/time-picker/TimePicker.d.ts +32 -0
- package/dist/esm/components/time-picker/index.d.ts +3 -0
- package/dist/esm/components/toggle-button/ToggleButton.d.ts +12 -0
- package/dist/esm/components/toggle-button/index.d.ts +3 -0
- package/dist/esm/date-picker.css +153 -0
- package/dist/esm/date-picker.d.ts +2 -0
- package/dist/esm/date-picker.js +118 -0
- package/dist/esm/dropzone.css +43 -0
- package/dist/esm/dropzone.d.ts +2 -0
- package/dist/esm/dropzone.js +137 -0
- package/dist/esm/field.css.d.ts +33 -0
- package/dist/esm/field.d.ts +24 -0
- package/dist/esm/file-upload.d.ts +2 -0
- package/dist/esm/file-upload.js +123 -0
- package/dist/esm/icon-button.d.ts +2 -0
- package/dist/esm/icon-button.js +29 -0
- package/dist/esm/index.d.ts +24 -0
- package/dist/esm/index.js +24 -0
- package/dist/esm/input.d.ts +2 -0
- package/dist/esm/input.js +39 -0
- package/dist/esm/multi-select.d.ts +2 -0
- package/dist/esm/multi-select.js +164 -0
- package/dist/esm/number-input.css +107 -0
- package/dist/esm/number-input.d.ts +2 -0
- package/dist/esm/number-input.js +153 -0
- package/dist/esm/otp-input.css +55 -0
- package/dist/esm/otp-input.d.ts +2 -0
- package/dist/esm/otp-input.js +56 -0
- package/dist/esm/password-input.d.ts +2 -0
- package/dist/esm/password-input.js +56 -0
- package/dist/esm/radio-group.css +42 -0
- package/dist/esm/radio-group.d.ts +2 -0
- package/dist/esm/radio-group.js +44 -0
- package/dist/esm/range-slider.d.ts +2 -0
- package/dist/esm/range-slider.js +22 -0
- package/dist/esm/rich-text-editor.css +74 -0
- package/dist/esm/rich-text-editor.d.ts +2 -0
- package/dist/esm/rich-text-editor.js +212 -0
- package/dist/esm/search-input.d.ts +2 -0
- package/dist/esm/search-input.js +62 -0
- package/dist/esm/select.css +73 -0
- package/dist/esm/select.d.ts +2 -0
- package/dist/esm/select.js +87 -0
- package/dist/esm/selectPopover.css.d.ts +17 -0
- package/dist/esm/slider.d.ts +2 -0
- package/dist/esm/slider.js +4 -0
- package/dist/esm/switch.css +44 -0
- package/dist/esm/switch.d.ts +2 -0
- package/dist/esm/switch.js +36 -0
- package/dist/esm/tags-input.css +16 -0
- package/dist/esm/tags-input.d.ts +2 -0
- package/dist/esm/tags-input.js +100 -0
- package/dist/esm/textarea.d.ts +2 -0
- package/dist/esm/textarea.js +58 -0
- package/dist/esm/time-picker.d.ts +2 -0
- package/dist/esm/time-picker.js +137 -0
- package/dist/esm/toggle-button.d.ts +2 -0
- package/dist/esm/toggle-button.js +4 -0
- package/package.json +255 -0
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# @vinyasa/form
|
|
2
|
+
|
|
3
|
+
All 25 form controls in the "Form Components" category, delivered in three staged phases:
|
|
4
|
+
|
|
5
|
+
- **Phase 1**: Icon Button, Toggle Button, Input, Search Input, Password Input, Number Input, Textarea, Checkbox, Radio Group, Switch.
|
|
6
|
+
- **Phase 2**: Slider, Range Slider, OTP Input, Select, Combobox, Autocomplete, Multi Select, Tags Input.
|
|
7
|
+
- **Phase 3** (this round): Date Picker, Time Picker, Color Picker, File Upload, Dropzone, Rich Text Editor.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @vinyasa/form @vinyasa/layout @vinyasa/icons @vinyasa/button @vinyasa/tokens react react-dom
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`@vinyasa/button`'s `Button` is composed directly by Icon Button and Toggle Button rather than reimplemented. Every interactive control wraps an established library rather than hand-rolling keyboard/ARIA/drag behavior — all regular dependencies of this package, not something consumers install themselves:
|
|
16
|
+
|
|
17
|
+
| Component(s) | Library |
|
|
18
|
+
| -------------------------------------------- | ------------------------------------------------------------------- |
|
|
19
|
+
| Checkbox, Radio Group, Switch, Toggle Button | `@radix-ui/react-checkbox` / `-radio-group` / `-switch` / `-toggle` |
|
|
20
|
+
| Slider, Range Slider | `@radix-ui/react-slider` |
|
|
21
|
+
| Select | `@radix-ui/react-select` |
|
|
22
|
+
| Combobox, Autocomplete, Multi Select | `@radix-ui/react-popover` + `cmdk` |
|
|
23
|
+
| OTP Input | `input-otp` |
|
|
24
|
+
| Date Picker | `react-day-picker` + `@radix-ui/react-popover` + `date-fns` |
|
|
25
|
+
| Color Picker | `react-colorful` + `@radix-ui/react-popover` |
|
|
26
|
+
| File Upload, Dropzone | `react-dropzone` |
|
|
27
|
+
| Rich Text Editor | `@tiptap/react` + `@tiptap/starter-kit` |
|
|
28
|
+
|
|
29
|
+
Tags Input has no dropdown, so it needs neither Popover nor cmdk — it's a plain chip-token text field. Time Picker wraps a native `<input type="time">` rather than a library — the browser already provides an accessible, localized time-entry UI for free.
|
|
30
|
+
|
|
31
|
+
## New tokens this package introduces
|
|
32
|
+
|
|
33
|
+
None across all three phases. Every control's chrome (border, focus ring, invalid/disabled state, floating-content elevation) reuses existing tokens.
|
|
34
|
+
|
|
35
|
+
## New icons this package needed
|
|
36
|
+
|
|
37
|
+
Added to `@vinyasa/icons` across the three phases: `CalendarIcon`, `ClockIcon`, `PaletteIcon`, `PaperclipIcon`, `UploadIcon` (Phase 1, used by Phase 3's pickers/uploaders) and `BoldIcon`, `ItalicIcon`, `ListIcon`, `ListOrderedIcon`, `QuoteIcon`, `RedoIcon`, `StrikethroughIcon`, `UndoIcon` (Phase 3, for Rich Text Editor's toolbar).
|
|
38
|
+
|
|
39
|
+
## Shared internal chrome
|
|
40
|
+
|
|
41
|
+
- `src/field.tsx` / `src/field.css.ts` — label/description/error/required/focus-ring/invalid/disabled layout shared by every text-like control. Not a public component — the same "shared internal system" pattern `@vinyasa/feedback`'s `status.ts` used.
|
|
42
|
+
- `src/selectPopover.css.ts` — floating-listbox chrome (content/list/item/chip styles) shared by Combobox, Autocomplete, and Multi Select, the three "type to filter a list" patterns built on Popover + cmdk. Select, Date Picker, and Color Picker each have their own `<Component>.css.ts` popover-content styling instead, since their underlying libraries (`@radix-ui/react-select`, `react-day-picker`, `react-colorful`) have different part structures — Date Picker's content, in particular, deliberately isn't width-constrained to its trigger the way selectPopover's is, since a calendar has its own natural size.
|
|
43
|
+
|
|
44
|
+
**A load-bearing fix, not just a style choice**: every popover-based component (Select, Combobox, Autocomplete, Multi Select, Date Picker, Color Picker) deliberately renders its floating content **without** `Portal`. `VinyasaProvider` injects theme CSS custom properties as an inline style on its own wrapper element, not `:root` — anything rendered via `createPortal` to `document.body` (which is what those Portal components do by default) falls outside that subtree, and every `var(--vinyasa-*)` token resolves to nothing (the exact bug `@vinyasa/feedback`'s `Toaster` hit and fixed the same way). Radix's own floating-position calculation still works correctly without the portal; only the DOM location changes. Verified in a real browser for each of these six components — the popover content genuinely renders with real, non-transparent styling, not just "doesn't crash."
|
|
45
|
+
|
|
46
|
+
**A cmdk gotcha worth knowing if you touch Combobox/Autocomplete**: `Command.Input` always overwrites any `id` prop you pass with its own internally-generated one, and gets its accessible name from `<Command label="...">` (wired via `aria-labelledby` to a hidden label cmdk renders itself) — not from `FieldChrome`'s own visible `<label htmlFor>`. `FieldChrome` has a `disableLabelFor` escape hatch for exactly this (omits the now-dangling `htmlFor`, which would otherwise silently fail to focus anything when a real user clicks the visible label). The same underlying issue — a trigger's accessible name coming from its `<label>`, not its own visible text content — is why Date Picker's, Color Picker's, and File Upload's own trigger buttons show their current value/state as plain rendered content rather than as part of the button's accessible name; tests and consumers alike should query these by their `label` text, not by the formatted date/hex/filename shown inside.
|
|
47
|
+
|
|
48
|
+
**react-day-picker is styled entirely through its own `classNames` prop** (keyed by its `UI`/`DayFlag`/`SelectionState` enums) rather than its default stylesheet — the same "headless, theme it yourself" contract already used for Select/Combobox's underlying libraries. `DatePicker` also passes `defaultMonth={currentValue}` so reopening the popover on an already-selected date shows that date's month, not always today's — react-day-picker's own default otherwise anchors to today's month regardless of the current selection.
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
### Icon Button
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<IconButton aria-label="Delete" icon={<TrashIcon />} variant="ghost" />
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`aria-label` is a required prop — an icon-only button has no other accessible name.
|
|
59
|
+
|
|
60
|
+
### Toggle Button
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
<ToggleButton pressed={bold} onPressedChange={setBold}>
|
|
64
|
+
<BoldIcon />
|
|
65
|
+
</ToggleButton>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Wraps Radix's `Toggle` with `asChild`, passing `Button` as the child — Radix owns press/keyboard/`aria-pressed`, Button owns the visual chrome. `pressedVariant`/`unpressedVariant` (default `'primary'`/`'outline'`) pick which Button `variant` renders for each state.
|
|
69
|
+
|
|
70
|
+
### Input, Search Input, Password Input, Number Input, Textarea
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<Input label="Email" error="Enter a valid email address." />
|
|
74
|
+
<SearchInput label="Search" value={query} onChange={handleChange} onClear={() => setQuery('')} />
|
|
75
|
+
<PasswordInput label="Password" />
|
|
76
|
+
<NumberInput label="Quantity" min={0} max={10} />
|
|
77
|
+
<Textarea label="Bio" autoResize />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Checkbox, Switch, Radio Group
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<Checkbox label="Accept terms" checked={accepted} onCheckedChange={setAccepted} />
|
|
84
|
+
<Switch label="Enable notifications" defaultChecked />
|
|
85
|
+
<RadioGroup
|
|
86
|
+
options={[
|
|
87
|
+
{ value: 'sm', label: 'Small' },
|
|
88
|
+
{ value: 'md', label: 'Medium' },
|
|
89
|
+
]}
|
|
90
|
+
value={size}
|
|
91
|
+
onValueChange={setSize}
|
|
92
|
+
/>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Slider, Range Slider
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
<Slider label="Volume" value={[volume]} onValueChange={([v]) => setVolume(v)} />
|
|
99
|
+
<RangeSlider value={range} onValueChange={setRange} minLabel="Low" maxLabel="High" />
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`RangeSlider` is a convenience wrapper around `Slider`, not a separate implementation — Radix's Slider already supports any number of thumbs via a `value` array; `RangeSlider` just fixes it at two with distinct min/max accessible labels.
|
|
103
|
+
|
|
104
|
+
### OTP Input
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<OtpInput label="Verification code" length={6} onComplete={handleSubmit} />
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Select
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<Select
|
|
114
|
+
label="Size"
|
|
115
|
+
options={[{ value: 'md', label: 'Medium' }]}
|
|
116
|
+
placeholder="Choose a size"
|
|
117
|
+
value={size}
|
|
118
|
+
onValueChange={setSize}
|
|
119
|
+
/>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Combobox, Autocomplete
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<Combobox label="Framework" options={frameworkOptions} value={framework} onValueChange={setFramework} />
|
|
126
|
+
<Autocomplete label="State" suggestions={states} value={state} onValueChange={setState} />
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The entire difference between the two: Combobox only ever commits one of its own `options`; Autocomplete commits whatever text is in the field, with `suggestions` as a shortcut for filling it in rather than a constraint on it.
|
|
130
|
+
|
|
131
|
+
### Multi Select
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
<MultiSelect
|
|
135
|
+
label="Favorite colors"
|
|
136
|
+
options={colorOptions}
|
|
137
|
+
value={colors}
|
|
138
|
+
onValueChange={setColors}
|
|
139
|
+
/>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Selected values render as removable chips in the trigger; picking an item in the popover toggles membership without closing (unlike Combobox, which closes on selection).
|
|
143
|
+
|
|
144
|
+
### Tags Input
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
<TagsInput label="Skills" value={skills} onValueChange={setSkills} max={10} />
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Free-text tokens — press Enter or comma to commit the current draft as a tag, Backspace on an empty draft removes the last one.
|
|
151
|
+
|
|
152
|
+
### Date Picker, Time Picker
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
<DatePicker label="Date of birth" value={date} onValueChange={setDate} />
|
|
156
|
+
<TimePicker label="Meeting time" value={time} onChange={handleChange} />
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`dateFormat` (a `date-fns` format string, default `'PPP'`) controls how the selected date renders on the trigger.
|
|
160
|
+
|
|
161
|
+
### Color Picker
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<ColorPicker label="Brand color" value={color} onValueChange={setColor} />
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
A hex-only picker (`react-colorful`'s `HexColorPicker` + `HexColorInput`) — the trigger shows a swatch plus the current hex value, and the popover's text input keeps typed hex codes in sync with the visual picker.
|
|
168
|
+
|
|
169
|
+
### File Upload, Dropzone
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<FileUpload label="Attachments" value={files} onValueChange={setFiles} accept={{ 'application/pdf': ['.pdf'] }} />
|
|
173
|
+
<Dropzone label="Attachments" value={files} onValueChange={setFiles} maxSize={5 * 1024 * 1024} />
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Both wrap the same `useDropzone` hook and share their file-list styling (`file-upload/FileUpload.css.ts`) — File Upload is a compact button trigger, Dropzone a full drag-and-drop area; pick whichever chrome fits the layout.
|
|
177
|
+
|
|
178
|
+
### Rich Text Editor
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
<RichTextEditor label="Description" value={html} onValueChange={setHtml} />
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Wraps Tiptap (`StarterKit`) with a toolbar built from this package's own Toggle Button (bold/italic/strikethrough/lists/blockquote/undo/redo). `value`/`onValueChange` are HTML strings; an externally-set `value` is pushed into the editor via `setContent` only when it actually differs from the editor's current content, so it doesn't fight the user's own typing.
|
|
185
|
+
|
|
186
|
+
## Subpath imports
|
|
187
|
+
|
|
188
|
+
Every component has its own subpath export (e.g. `@vinyasa/form/date-picker`) alongside the root `@vinyasa/form` entry, for consumers who want to import a single component without pulling in the rest.
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_modules__ = {
|
|
3
|
+
400 (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4
|
+
function toPrimitive(t, r) {
|
|
5
|
+
if ("object" != typeof t || !t) return t;
|
|
6
|
+
var e = t[Symbol.toPrimitive];
|
|
7
|
+
if (void 0 !== e) {
|
|
8
|
+
var i = e.call(t, r || "default");
|
|
9
|
+
if ("object" != typeof i) return i;
|
|
10
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
11
|
+
}
|
|
12
|
+
return ("string" === r ? String : Number)(t);
|
|
13
|
+
}
|
|
14
|
+
function toPropertyKey(t) {
|
|
15
|
+
var i = toPrimitive(t, "string");
|
|
16
|
+
return "symbol" == typeof i ? i : String(i);
|
|
17
|
+
}
|
|
18
|
+
function _defineProperty(obj, key, value) {
|
|
19
|
+
key = toPropertyKey(key);
|
|
20
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
21
|
+
value: value,
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true
|
|
25
|
+
});
|
|
26
|
+
else obj[key] = value;
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
function ownKeys(e, r) {
|
|
30
|
+
var t = Object.keys(e);
|
|
31
|
+
if (Object.getOwnPropertySymbols) {
|
|
32
|
+
var o = Object.getOwnPropertySymbols(e);
|
|
33
|
+
r && (o = o.filter(function(r) {
|
|
34
|
+
return Object.getOwnPropertyDescriptor(e, r).enumerable;
|
|
35
|
+
})), t.push.apply(t, o);
|
|
36
|
+
}
|
|
37
|
+
return t;
|
|
38
|
+
}
|
|
39
|
+
function _objectSpread2(e) {
|
|
40
|
+
for(var r = 1; r < arguments.length; r++){
|
|
41
|
+
var t = null != arguments[r] ? arguments[r] : {};
|
|
42
|
+
r % 2 ? ownKeys(Object(t), !0).forEach(function(r) {
|
|
43
|
+
_defineProperty(e, r, t[r]);
|
|
44
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r) {
|
|
45
|
+
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return e;
|
|
49
|
+
}
|
|
50
|
+
function mapValues(input, fn) {
|
|
51
|
+
var result = {};
|
|
52
|
+
for(var _key in input)result[_key] = fn(input[_key], _key);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
var shouldApplyCompound = (compoundCheck, selections, defaultVariants)=>{
|
|
56
|
+
for (var key of Object.keys(compoundCheck)){
|
|
57
|
+
var _selections$key;
|
|
58
|
+
if (compoundCheck[key] !== (null != (_selections$key = selections[key]) ? _selections$key : defaultVariants[key])) return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
};
|
|
62
|
+
var createRuntimeFn = (config)=>{
|
|
63
|
+
var runtimeFn = (options)=>{
|
|
64
|
+
var className = config.defaultClassName;
|
|
65
|
+
var selections = _objectSpread2(_objectSpread2({}, config.defaultVariants), options);
|
|
66
|
+
for(var variantName in selections){
|
|
67
|
+
var _selections$variantNa;
|
|
68
|
+
var variantSelection = null != (_selections$variantNa = selections[variantName]) ? _selections$variantNa : config.defaultVariants[variantName];
|
|
69
|
+
if (null != variantSelection) {
|
|
70
|
+
var selection = variantSelection;
|
|
71
|
+
if ('boolean' == typeof selection) selection = true === selection ? 'true' : 'false';
|
|
72
|
+
var selectionClassName = config.variantClassNames[variantName][selection];
|
|
73
|
+
if (selectionClassName) className += ' ' + selectionClassName;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (var [compoundCheck, compoundClassName] of config.compoundVariants)if (shouldApplyCompound(compoundCheck, selections, config.defaultVariants)) className += ' ' + compoundClassName;
|
|
77
|
+
return className;
|
|
78
|
+
};
|
|
79
|
+
runtimeFn.variants = ()=>Object.keys(config.variantClassNames);
|
|
80
|
+
runtimeFn.classNames = {
|
|
81
|
+
get base () {
|
|
82
|
+
return config.defaultClassName.split(' ')[0];
|
|
83
|
+
},
|
|
84
|
+
get variants () {
|
|
85
|
+
return mapValues(config.variantClassNames, (classNames)=>mapValues(classNames, (className)=>className.split(' ')[0]));
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
return runtimeFn;
|
|
89
|
+
};
|
|
90
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
91
|
+
c: ()=>createRuntimeFn
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
891 (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
95
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
96
|
+
ij: ()=>descriptionText,
|
|
97
|
+
kc: ()=>errorText,
|
|
98
|
+
Ij: ()=>fieldControl,
|
|
99
|
+
Pf: ()=>label,
|
|
100
|
+
Zy: ()=>requiredMark
|
|
101
|
+
});
|
|
102
|
+
var createRuntimeFn_62c9670f_esm = __webpack_require__(400);
|
|
103
|
+
var descriptionText = 'sbqkrxd';
|
|
104
|
+
var errorText = 'sbqkrxe';
|
|
105
|
+
var fieldControl = (0, createRuntimeFn_62c9670f_esm.c)({
|
|
106
|
+
defaultClassName: 'sbqkrx0',
|
|
107
|
+
variantClassNames: {
|
|
108
|
+
size: {
|
|
109
|
+
sm: 'sbqkrx1',
|
|
110
|
+
md: 'sbqkrx2',
|
|
111
|
+
lg: 'sbqkrx3'
|
|
112
|
+
},
|
|
113
|
+
invalid: {
|
|
114
|
+
true: 'sbqkrx4'
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
defaultVariants: {
|
|
118
|
+
size: 'md'
|
|
119
|
+
},
|
|
120
|
+
compoundVariants: []
|
|
121
|
+
});
|
|
122
|
+
var label = 'sbqkrxb';
|
|
123
|
+
var requiredMark = 'sbqkrxc';
|
|
124
|
+
},
|
|
125
|
+
629 (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
126
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
127
|
+
Qs: ()=>content,
|
|
128
|
+
Ie: ()=>empty,
|
|
129
|
+
AS: ()=>item,
|
|
130
|
+
p_: ()=>list
|
|
131
|
+
});
|
|
132
|
+
var content = '_1u69cbs0';
|
|
133
|
+
var empty = '_1u69cbs4';
|
|
134
|
+
var item = '_1u69cbs2';
|
|
135
|
+
var list = '_1u69cbs1';
|
|
136
|
+
},
|
|
137
|
+
140 (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
138
|
+
var react_jsx_runtime__rspack_import_0 = __webpack_require__(732);
|
|
139
|
+
var _field_css__rspack_import_1 = __webpack_require__(891);
|
|
140
|
+
const describedByIds = (id, { description, error })=>{
|
|
141
|
+
const ids = [];
|
|
142
|
+
if (description) ids.push(`${id}-description`);
|
|
143
|
+
if (error) ids.push(`${id}-error`);
|
|
144
|
+
return ids.length > 0 ? ids.join(' ') : void 0;
|
|
145
|
+
};
|
|
146
|
+
const FieldChrome = ({ id, label, description, error, required, children, disableLabelFor = false })=>/*#__PURE__*/ (0, react_jsx_runtime__rspack_import_0.jsxs)("div", {
|
|
147
|
+
children: [
|
|
148
|
+
label ? /*#__PURE__*/ (0, react_jsx_runtime__rspack_import_0.jsxs)("label", {
|
|
149
|
+
htmlFor: disableLabelFor ? void 0 : id,
|
|
150
|
+
id: `${id}-label`,
|
|
151
|
+
className: _field_css__rspack_import_1.Pf,
|
|
152
|
+
children: [
|
|
153
|
+
label,
|
|
154
|
+
required ? /*#__PURE__*/ (0, react_jsx_runtime__rspack_import_0.jsx)("span", {
|
|
155
|
+
className: _field_css__rspack_import_1.Zy,
|
|
156
|
+
"aria-hidden": "true",
|
|
157
|
+
children: "*"
|
|
158
|
+
}) : null
|
|
159
|
+
]
|
|
160
|
+
}) : null,
|
|
161
|
+
children,
|
|
162
|
+
description ? /*#__PURE__*/ (0, react_jsx_runtime__rspack_import_0.jsx)("p", {
|
|
163
|
+
id: `${id}-description`,
|
|
164
|
+
className: _field_css__rspack_import_1.ij,
|
|
165
|
+
children: description
|
|
166
|
+
}) : null,
|
|
167
|
+
error ? /*#__PURE__*/ (0, react_jsx_runtime__rspack_import_0.jsx)("p", {
|
|
168
|
+
id: `${id}-error`,
|
|
169
|
+
className: _field_css__rspack_import_1.kc,
|
|
170
|
+
role: "alert",
|
|
171
|
+
children: error
|
|
172
|
+
}) : null
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
const __rspack_default_export = FieldChrome;
|
|
176
|
+
__webpack_require__.d(__webpack_exports__, {}, {
|
|
177
|
+
A: __rspack_default_export,
|
|
178
|
+
z: describedByIds
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
283 (module) {
|
|
182
|
+
module.exports = require("@radix-ui/react-popover");
|
|
183
|
+
},
|
|
184
|
+
817 (module) {
|
|
185
|
+
module.exports = require("cmdk");
|
|
186
|
+
},
|
|
187
|
+
15 (module) {
|
|
188
|
+
module.exports = require("react");
|
|
189
|
+
},
|
|
190
|
+
732 (module) {
|
|
191
|
+
module.exports = require("react/jsx-runtime");
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
var __webpack_module_cache__ = {};
|
|
195
|
+
function __webpack_require__(moduleId) {
|
|
196
|
+
var cachedModule = __webpack_module_cache__[moduleId];
|
|
197
|
+
if (void 0 !== cachedModule) return cachedModule.exports;
|
|
198
|
+
var module = __webpack_module_cache__[moduleId] = {
|
|
199
|
+
exports: {}
|
|
200
|
+
};
|
|
201
|
+
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
202
|
+
return module.exports;
|
|
203
|
+
}
|
|
204
|
+
(()=>{
|
|
205
|
+
__webpack_require__.n = (module)=>{
|
|
206
|
+
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
207
|
+
__webpack_require__.d(getter, {
|
|
208
|
+
a: getter
|
|
209
|
+
});
|
|
210
|
+
return getter;
|
|
211
|
+
};
|
|
212
|
+
})();
|
|
213
|
+
(()=>{
|
|
214
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
215
|
+
var define = (defs, kind)=>{
|
|
216
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
217
|
+
enumerable: true,
|
|
218
|
+
[kind]: defs[key]
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
define(getters, "get");
|
|
222
|
+
define(values, "value");
|
|
223
|
+
};
|
|
224
|
+
})();
|
|
225
|
+
(()=>{
|
|
226
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
227
|
+
})();
|
|
228
|
+
(()=>{
|
|
229
|
+
__webpack_require__.r = (exports1)=>{
|
|
230
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
231
|
+
value: 'Module'
|
|
232
|
+
});
|
|
233
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
234
|
+
value: true
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
})();
|
|
238
|
+
var __webpack_exports__ = {};
|
|
239
|
+
(()=>{
|
|
240
|
+
__webpack_require__.r(__webpack_exports__);
|
|
241
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
242
|
+
default: ()=>autocomplete
|
|
243
|
+
});
|
|
244
|
+
var jsx_runtime_ = __webpack_require__(732);
|
|
245
|
+
var react_popover_ = __webpack_require__(283);
|
|
246
|
+
var external_cmdk_ = __webpack_require__(817);
|
|
247
|
+
var external_react_ = __webpack_require__(15);
|
|
248
|
+
var field = __webpack_require__(140);
|
|
249
|
+
var field_css = __webpack_require__(891);
|
|
250
|
+
var selectPopover_css = __webpack_require__(629);
|
|
251
|
+
const Autocomplete = ({ suggestions, value, defaultValue = '', onValueChange, placeholder, label, description, error, required, size, emptyMessage = 'No suggestions.', id: idProp })=>{
|
|
252
|
+
const [internalValue, setInternalValue] = (0, external_react_.useState)(defaultValue);
|
|
253
|
+
const isControlled = void 0 !== value;
|
|
254
|
+
const currentValue = isControlled ? value : internalValue;
|
|
255
|
+
const [open, setOpen] = (0, external_react_.useState)(false);
|
|
256
|
+
const generatedId = (0, external_react_.useId)();
|
|
257
|
+
const id = null != idProp ? idProp : generatedId;
|
|
258
|
+
const setValue = (next)=>{
|
|
259
|
+
if (!isControlled) setInternalValue(next);
|
|
260
|
+
null == onValueChange || onValueChange(next);
|
|
261
|
+
};
|
|
262
|
+
return /*#__PURE__*/ (0, jsx_runtime_.jsx)(field.A, {
|
|
263
|
+
id: id,
|
|
264
|
+
label: label,
|
|
265
|
+
description: description,
|
|
266
|
+
error: error,
|
|
267
|
+
required: required,
|
|
268
|
+
disableLabelFor: true,
|
|
269
|
+
children: /*#__PURE__*/ (0, jsx_runtime_.jsx)(external_cmdk_.Command, {
|
|
270
|
+
loop: true,
|
|
271
|
+
shouldFilter: true,
|
|
272
|
+
label: 'string' == typeof label ? label : void 0,
|
|
273
|
+
children: /*#__PURE__*/ (0, jsx_runtime_.jsxs)(react_popover_.Root, {
|
|
274
|
+
open: open,
|
|
275
|
+
onOpenChange: setOpen,
|
|
276
|
+
children: [
|
|
277
|
+
/*#__PURE__*/ (0, jsx_runtime_.jsx)(react_popover_.Trigger, {
|
|
278
|
+
asChild: true,
|
|
279
|
+
children: /*#__PURE__*/ (0, jsx_runtime_.jsx)(external_cmdk_.Command.Input, {
|
|
280
|
+
id: id,
|
|
281
|
+
value: currentValue,
|
|
282
|
+
onClick: (event)=>{
|
|
283
|
+
event.preventDefault();
|
|
284
|
+
},
|
|
285
|
+
onValueChange: (next)=>{
|
|
286
|
+
setValue(next);
|
|
287
|
+
setOpen(true);
|
|
288
|
+
},
|
|
289
|
+
onFocus: ()=>{
|
|
290
|
+
setOpen(true);
|
|
291
|
+
},
|
|
292
|
+
placeholder: placeholder,
|
|
293
|
+
className: (0, field_css.Ij)({
|
|
294
|
+
size,
|
|
295
|
+
invalid: Boolean(error)
|
|
296
|
+
}),
|
|
297
|
+
"aria-describedby": (0, field.z)(id, {
|
|
298
|
+
description,
|
|
299
|
+
error
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
}),
|
|
303
|
+
/*#__PURE__*/ (0, jsx_runtime_.jsx)(react_popover_.Content, {
|
|
304
|
+
className: selectPopover_css.Qs,
|
|
305
|
+
align: "start",
|
|
306
|
+
sideOffset: 4,
|
|
307
|
+
onOpenAutoFocus: (event)=>{
|
|
308
|
+
event.preventDefault();
|
|
309
|
+
},
|
|
310
|
+
children: /*#__PURE__*/ (0, jsx_runtime_.jsxs)(external_cmdk_.Command.List, {
|
|
311
|
+
className: selectPopover_css.p_,
|
|
312
|
+
children: [
|
|
313
|
+
/*#__PURE__*/ (0, jsx_runtime_.jsx)(external_cmdk_.Command.Empty, {
|
|
314
|
+
className: selectPopover_css.Ie,
|
|
315
|
+
children: emptyMessage
|
|
316
|
+
}),
|
|
317
|
+
suggestions.map((suggestion)=>/*#__PURE__*/ (0, jsx_runtime_.jsx)(external_cmdk_.Command.Item, {
|
|
318
|
+
value: suggestion,
|
|
319
|
+
onSelect: ()=>{
|
|
320
|
+
setValue(suggestion);
|
|
321
|
+
setOpen(false);
|
|
322
|
+
},
|
|
323
|
+
className: selectPopover_css.AS,
|
|
324
|
+
children: suggestion
|
|
325
|
+
}, suggestion))
|
|
326
|
+
]
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
]
|
|
330
|
+
})
|
|
331
|
+
})
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
Autocomplete.displayName = 'Autocomplete';
|
|
335
|
+
const autocomplete_Autocomplete = Autocomplete;
|
|
336
|
+
const autocomplete = autocomplete_Autocomplete;
|
|
337
|
+
})();
|
|
338
|
+
exports["default"] = __webpack_exports__["default"];
|
|
339
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
340
|
+
"default"
|
|
341
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
342
|
+
Object.defineProperty(exports, '__esModule', {
|
|
343
|
+
value: true
|
|
344
|
+
});
|