cleanplate 0.2.7 → 0.2.8

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 (34) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/components/form-controls/Date.d.ts +27 -7
  3. package/dist/components/form-controls/Date.d.ts.map +1 -1
  4. package/dist/components/form-controls/date/DatePickerFooter.d.ts +8 -0
  5. package/dist/components/form-controls/date/DatePickerFooter.d.ts.map +1 -0
  6. package/dist/components/form-controls/date/DatePickerGrid.d.ts +18 -0
  7. package/dist/components/form-controls/date/DatePickerGrid.d.ts.map +1 -0
  8. package/dist/components/form-controls/date/DatePickerHeader.d.ts +21 -0
  9. package/dist/components/form-controls/date/DatePickerHeader.d.ts.map +1 -0
  10. package/dist/components/form-controls/date/DatePickerPanel.d.ts +15 -0
  11. package/dist/components/form-controls/date/DatePickerPanel.d.ts.map +1 -0
  12. package/dist/components/form-controls/date/ScrollPicker.d.ts +16 -0
  13. package/dist/components/form-controls/date/ScrollPicker.d.ts.map +1 -0
  14. package/dist/components/form-controls/date/calendar-matrix.d.ts +6 -0
  15. package/dist/components/form-controls/date/calendar-matrix.d.ts.map +1 -0
  16. package/dist/components/form-controls/date/date-constraints.d.ts +7 -0
  17. package/dist/components/form-controls/date/date-constraints.d.ts.map +1 -0
  18. package/dist/components/form-controls/date/date-types.d.ts +8 -0
  19. package/dist/components/form-controls/date/date-types.d.ts.map +1 -0
  20. package/dist/components/form-controls/date/normalize-date.d.ts +13 -0
  21. package/dist/components/form-controls/date/normalize-date.d.ts.map +1 -0
  22. package/dist/components/form-controls/date/use-date-picker-state.d.ts +27 -0
  23. package/dist/components/form-controls/date/use-date-picker-state.d.ts.map +1 -0
  24. package/dist/components/form-controls/date/use-media-query.d.ts +2 -0
  25. package/dist/components/form-controls/date/use-media-query.d.ts.map +1 -0
  26. package/dist/index.css +1 -1
  27. package/dist/index.es.css +1 -1
  28. package/dist/index.es.js +4 -4
  29. package/dist/index.js +4 -4
  30. package/docs/FormControls.md +19 -4
  31. package/docs/superpowers/plans/2026-05-10-date-picker.md +955 -0
  32. package/docs/superpowers/specs/2026-05-10-date-picker-design.md +196 -0
  33. package/llms.txt +2 -2
  34. package/package.json +21 -8
@@ -9,7 +9,7 @@ FormControls is a set of form primitives exported as a namespace: `FormControls.
9
9
  | Input | Single-line text | placeholder, value, onChange(e), type |
10
10
  | TextArea | Multi-line text | placeholder, value, onChange(e) |
11
11
  | Select | Floating UI combobox: desktop portalled list; **≤768px** bottom sheet; sync or async options, search, groups, multi chips + cap | `mode` / `isMulti`, `options`, `onSearch`, `groups`, `maxSelect`, `triggerMaxItems`, `name`, `placeholder`, `error` |
12
- | Date | Day/month/year picker (DD-MMM-YYYY) | defaultValue, onChange(dateValue: string) |
12
+ | Date | Calendar date picker (`date-fns` + Floating UI); **Cancel** / **OK** staging; desktop **popover** (~**400px** max width, viewport-capped); **≤768px** **bottom sheet** + backdrop; **month** / **year** subviews with back + titled headers; trigger **`calendar_month`** icon | `value`/`defaultValue` (`Date \| null`), `onChange`, `minDate`/`maxDate`/`disabledDates`/`disabledDaysOfWeek`, `locale`, `weekStartsOn`, `dateFormat`, `clearable`, `readOnly`, `name` (hidden **yyyy-MM-dd**), `popoverPlacement`, `onOpen`/`onClose` |
13
13
  | Checkbox | Checkbox group (array-based, multi-select) | name, label, options, value (CheckboxValue[]), defaultValue, onChange(values, e), orientation, variant |
14
14
  | Radio | Radio group (array-based) | name, label, options, value, defaultValue, onChange(value, e), orientation, variant |
15
15
  | File | File picker with `button` / `card` variants, drag-and-drop, and a removable file list | name, label, variant, multiple, accept, value (File[]), onChange(files, e), buttonLabel, dropZoneText |
@@ -136,7 +136,7 @@ interface InputProps {
136
136
  - **ToggleProps**: checked, defaultChecked, onChange(checked: boolean), label, isDisabled, isRequired, isFluid, className, error, dataTestId.
137
137
  - **CheckboxProps**: `options` (non-empty `CheckboxOption[]`), `name`, `label` (group `<legend>`), optional `id`, `value` (`CheckboxValue[]`), `defaultValue` (`CheckboxValue[]`), `onChange(values, e)`, `orientation` (`"vertical" | "horizontal"`), `variant` (`"default" | "card"`), `isDisabled`, `isRequired`, `isFluid`, `className`, `error`, `dataTestId`.
138
138
  - **CheckboxOption**: `{ label, value, isDisabled?, description?, icon?, dataTestId?, id? }`. `description` is rendered under the option label as muted secondary text and linked via `aria-describedby`. `icon` accepts any `ReactNode` (e.g. `<Icon />`, `<img />`, custom SVG) and renders to the left of the label/description. `CheckboxValue = string | number`.
139
- - **DateProps**: optional `id`, `label`, `defaultValue` (`"dd-mm-yyyy"`), `onChange(dateValue: string)`, plus `isDisabled`, `isRequired`, `isFluid`, `className`, `error`, `dataTestId`.
139
+ - **DateProps**: `value` / `defaultValue` (`Date | null`), `onChange(date: Date | null)`, `placeholder`, **`dateFormat`** (display string via `date-fns` + `locale`, default `MMM dd, yyyy`), **`name`** (renders a hidden `<input>` that submits **`yyyy-MM-dd`** for the committed calendar date), **`minDate`** / **`maxDate`** (inclusive navigation + selection bounds), **`disabledDates`** / **`disabledDaysOfWeek`** (greyed cells), **`locale`** (`date-fns` `Locale` — grid, subview copy, and field text), **`weekStartsOn`** (`0`–`6`, default `0` = Sunday), **`clearable`** (default `true`; shows clear control when a value exists), **`readOnly`** (no picker; value fixed), **`popoverPlacement`** (Floating UI placement for desktop; default `bottom-start`), **`onOpen`** / **`onClose`**, plus shared `label`, `isDisabled`, `isRequired`, `isFluid`, `className`, `error`, `dataTestId`.
140
140
  - **FormControlsStepperProps**: label, placeholder, value/defaultValue, onChange(e), type, isDisabled, isRequired, isFluid, className, error, dataTestId.
141
141
 
142
142
  ## Usage Examples
@@ -203,8 +203,23 @@ const [tags, setTags] = useState([{ label: "A", value: "a" }]);
203
203
  ### TextArea and Date
204
204
 
205
205
  ```jsx
206
+ import { de } from "date-fns/locale/de";
207
+
206
208
  <FormControls.TextArea label="Message" placeholder="Hello" />
207
- <FormControls.Date label="DOB" defaultValue="31-05-1992" onChange={(v) => {}} />
209
+ <FormControls.Date label="DOB" defaultValue={new Date(1992, 4, 31)} onChange={(d) => {}} />
210
+ <FormControls.Date
211
+ label="Ship date"
212
+ minDate={new Date(2026, 0, 1)}
213
+ maxDate={new Date(2026, 11, 31)}
214
+ disabledDaysOfWeek={[0, 6]}
215
+ weekStartsOn={1}
216
+ />
217
+ <FormControls.Date
218
+ label="Start (DE)"
219
+ locale={de}
220
+ dateFormat="dd.MM.yyyy"
221
+ defaultValue={new Date(2026, 3, 20)}
222
+ />
208
223
  ```
209
224
 
210
225
  ### Checkbox group
@@ -357,7 +372,7 @@ Pagination uses `FormControls.Select` for rows-per-page. Pills uses `FormControl
357
372
  - **Input (validation / constraints):** `maxLength` is passed straight to the native attribute (works for any `type`). `min` / `max` are passed to the native attribute (HTML5 form-validation hints) and, for `type="number"` only, also clamped on `blur` — the user can finish typing freely and the value snaps to the bound when they leave the field.
358
373
  - **Input (`autoComplete` / `onBlur`):** `autoComplete` maps to the native attribute (`"email"`, `"current-password"`, `"off"`, …). `onBlur` runs after any internal numeric clamp so consumers see the final value.
359
374
  - **Select:** Built on **Floating UI** — desktop uses a **portalled** panel with flip/shift to stay in the viewport; **≤768px** uses a **bottom sheet** (`role="dialog"`, `aria-modal`, `aria-labelledby` to the field label when the label exists). **Option** shape supports `group`, `icon`, `avatar`, `meta`, `disabled`. **`mode`** (`'single' | 'multi'`) replaces **`isMulti`** (still supported, deprecated). Single mode: **`onChange(Option | null)`** — `null` when cleared. Multi mode: **`onChange(Option[])`** — use **`[]`** for clear. **`name` + hidden `<input>`:** native form submit posts the selected **`value`**(s); **multi** joins with **commas** — avoid comma characters inside `value` if you rely on `FormData`, or parse manually. **`options={null}` + `onSearch`:** async loading; show loading/empty/error states in the panel. **`groups`:** sticky headings for shared `Option.group`. **`maxSelect`:** multi only; **`triggerMaxItems`:** chip overflow **`+N`**. **`aria-controls`** on the combobox trigger and panel search point at the listbox **only while open**. **`aria-invalid`** reflects **`error`** on trigger, search field, and listbox. Validation message uses **`role="alert"`** (via shared field error pattern).
360
- - **Date:** Returns string "dd-mm-yyyy" to onChange; uses internal day/month/year Selects.
375
+ - **Date:** **`Date | null`** with **`onChange`**. Opens a **`role="dialog"`** calendar: **staging** applies on day tap; **Cancel** reverts to the last committed value; **OK** commits (and clears staging). **Desktop:** portalled Floating UI panel with flip/shift, fixed **max width ~400px** (capped by viewport). **≤768px:** bottom sheet fixed to the lower viewport + dimmed backdrop, `aria-modal`, body scroll lock while open (same breakpoint idea as Select). **Header:** month cluster + year cluster (44px arrow hits); tapping month/year opens **scrollable subviews** with **back (`arrow_back`)** and headings **“Select a month of {yyyy}”** / **“Select a year for {MMMM}”** (locale-aware via `locale`). **Trigger:** **`calendar_month`** trailing icon (not Select chevrons); optional **clear** when `clearable`. **`readOnly`** and **`isDisabled`** block interaction. Constraints: **`minDate`/`maxDate`** (inclusive), **`disabledDates`**, **`disabledDaysOfWeek`**. **`dateFormat`** + **`locale`** control the field string; grid labels follow **`locale`** and **`weekStartsOn`**. **`name`:** hidden input posts **`yyyy-MM-dd`** for the **committed** value only. **`onOpen`/`onClose`** fire when the panel opens/closes. **`popoverPlacement`** adjusts desktop anchor (default `bottom-start`). **`error`** / **`isRequired`** use the shared field error pattern (`aria-invalid`, message under the field).
361
376
  - **Radio:** Group-first API — pass `options: RadioOption[]`. Renders `<fieldset>` + `<legend>` with a single `value` and `onChange(value, e)`. `isRequired` puts `*` on the legend and adds `required`/`aria-required` to the first enabled option (HTML5 only requires one input in the group to carry it). Custom ring/dot follows the native `:checked` state so uncontrolled groups stay visually correct. Pass `variant="card"` for tile-style options (ring in top-right, optional `icon` on the left, primary-brand border + tint when selected).
362
377
  - **Checkbox:** Group-first API — pass `options: CheckboxOption[]`. Renders `<fieldset>` + `<legend>` with a `value: CheckboxValue[]` and `onChange(values, e)`. `isRequired` puts `*` on the legend and sets `aria-required` on the group; native HTML5 doesn't enforce "at least one" for checkbox groups, so add custom validation at the form layer. Custom box/tick follows the native `:checked` state. Pass `variant="card"` for tile-style options (box in top-right, optional `icon` on the left, primary-brand border + tint when checked). For a single checkbox, pass a one-element `options` array — `value=[]` is unchecked, `value=[opt.value]` is checked.
363
378
  - **File:** Native `<input type="file">` is visually hidden but stays in the a11y tree. Manages a `File[]` selection internally; `onChange(files, e)` fires for picker selections, drops, and removals (the underlying event is `undefined` for non-picker triggers). With `multiple`, subsequent picks/drops append; without, the new selection replaces the old. The card variant supports drag-and-drop and tints primary-brand on hover. Removing a file resets the native input so re-selecting the same file still emits a change. `defaultValue` seeds the visual list only — browsers don't allow programmatic pre-population of file inputs.