@uxelle/skills 0.2.0-beta.2
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/LICENSE +674 -0
- package/README.md +58 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +586 -0
- package/index.json +573 -0
- package/package.json +57 -0
- package/skills/uxelle-components/Accordion.md +51 -0
- package/skills/uxelle-components/AccordionGroup.md +39 -0
- package/skills/uxelle-components/Banner.md +73 -0
- package/skills/uxelle-components/BannerAnnouncement.md +63 -0
- package/skills/uxelle-components/Breadcrumb.md +38 -0
- package/skills/uxelle-components/Breadcrumbs.md +32 -0
- package/skills/uxelle-components/Bubble.md +34 -0
- package/skills/uxelle-components/Button.md +54 -0
- package/skills/uxelle-components/ButtonGroup.md +43 -0
- package/skills/uxelle-components/Card.md +35 -0
- package/skills/uxelle-components/Checkbox.md +57 -0
- package/skills/uxelle-components/CheckboxGroup.md +47 -0
- package/skills/uxelle-components/ChoiceChip.md +44 -0
- package/skills/uxelle-components/ChoiceChipGroup.md +50 -0
- package/skills/uxelle-components/DatePicker.md +59 -0
- package/skills/uxelle-components/DatePickerRange.md +73 -0
- package/skills/uxelle-components/Dialog.md +83 -0
- package/skills/uxelle-components/Divider.md +37 -0
- package/skills/uxelle-components/DynamicAngleLine.md +36 -0
- package/skills/uxelle-components/DynamicAngleLineCombo.md +30 -0
- package/skills/uxelle-components/DynamicAngleShape.md +32 -0
- package/skills/uxelle-components/DynamicAngleShapeSurface.md +35 -0
- package/skills/uxelle-components/DynamicAngleTexture.md +29 -0
- package/skills/uxelle-components/DynamicAngleTextureText.md +35 -0
- package/skills/uxelle-components/FieldMessage.md +31 -0
- package/skills/uxelle-components/FileUpload.md +53 -0
- package/skills/uxelle-components/FilterChip.md +35 -0
- package/skills/uxelle-components/FilterChipGroup.md +42 -0
- package/skills/uxelle-components/Footer.md +34 -0
- package/skills/uxelle-components/Hero.md +61 -0
- package/skills/uxelle-components/Icon.md +43 -0
- package/skills/uxelle-components/IconButton.md +44 -0
- package/skills/uxelle-components/Image.md +40 -0
- package/skills/uxelle-components/Label.md +35 -0
- package/skills/uxelle-components/LabelBadge.md +58 -0
- package/skills/uxelle-components/LanguageSelector.md +38 -0
- package/skills/uxelle-components/LanguageSelectorButton.md +34 -0
- package/skills/uxelle-components/Layout.md +81 -0
- package/skills/uxelle-components/LinearProgress.md +53 -0
- package/skills/uxelle-components/Link.md +52 -0
- package/skills/uxelle-components/List.md +35 -0
- package/skills/uxelle-components/ListControls.md +100 -0
- package/skills/uxelle-components/ListItem.md +69 -0
- package/skills/uxelle-components/Lockup.md +50 -0
- package/skills/uxelle-components/Logo.md +39 -0
- package/skills/uxelle-components/Menu.md +48 -0
- package/skills/uxelle-components/MultiSelect.md +54 -0
- package/skills/uxelle-components/NavLink.md +44 -0
- package/skills/uxelle-components/Navigation.md +61 -0
- package/skills/uxelle-components/NavigationSide.md +51 -0
- package/skills/uxelle-components/NavigationSideGroup.md +36 -0
- package/skills/uxelle-components/NavigationSideItem.md +56 -0
- package/skills/uxelle-components/NavigationSideSubItem.md +39 -0
- package/skills/uxelle-components/NotificationBadge.md +62 -0
- package/skills/uxelle-components/Pagination.md +49 -0
- package/skills/uxelle-components/PaginationComplex.md +51 -0
- package/skills/uxelle-components/PaginationSimple.md +44 -0
- package/skills/uxelle-components/ProductCard.md +46 -0
- package/skills/uxelle-components/Quantity.md +45 -0
- package/skills/uxelle-components/Radio.md +55 -0
- package/skills/uxelle-components/RadioGroup.md +49 -0
- package/skills/uxelle-components/SKILL.md +242 -0
- package/skills/uxelle-components/Scrim.md +28 -0
- package/skills/uxelle-components/SegmentedControl.md +118 -0
- package/skills/uxelle-components/Select.md +55 -0
- package/skills/uxelle-components/Sheet.md +31 -0
- package/skills/uxelle-components/Skeleton.md +35 -0
- package/skills/uxelle-components/Spinner.md +33 -0
- package/skills/uxelle-components/StatTile.md +150 -0
- package/skills/uxelle-components/Stepper.md +73 -0
- package/skills/uxelle-components/Switch.md +41 -0
- package/skills/uxelle-components/Tab.md +41 -0
- package/skills/uxelle-components/Table.md +55 -0
- package/skills/uxelle-components/TabsCompact.md +37 -0
- package/skills/uxelle-components/TabsStretch.md +35 -0
- package/skills/uxelle-components/Text.md +56 -0
- package/skills/uxelle-components/Textarea.md +77 -0
- package/skills/uxelle-components/Textfield.md +62 -0
- package/skills/uxelle-components/Tooltip.md +33 -0
- package/skills/uxelle-design-harness/SKILL.md +149 -0
- package/skills/uxelle-design-harness/a2ui.md +73 -0
- package/skills/uxelle-design-harness/how-to-accessibility.md +31 -0
- package/skills/uxelle-design-harness/how-to-color.md +82 -0
- package/skills/uxelle-design-harness/how-to-host.md +108 -0
- package/skills/uxelle-design-harness/how-to-page-layout.md +203 -0
- package/skills/uxelle-design-harness/principles.md +72 -0
- package/skills/uxelle-design-harness/recipe-app-chrome.md +168 -0
- package/skills/uxelle-design-harness/recipe-card-grid.md +104 -0
- package/skills/uxelle-design-harness/recipe-cta-band.md +91 -0
- package/skills/uxelle-design-harness/recipe-dashboard-overview.md +118 -0
- package/skills/uxelle-design-harness/recipe-data-table-page.md +323 -0
- package/skills/uxelle-design-harness/recipe-feature-section.md +96 -0
- package/skills/uxelle-design-harness/recipe-footer.md +156 -0
- package/skills/uxelle-design-harness/recipe-form-section.md +163 -0
- package/skills/uxelle-design-harness/recipe-hero.md +89 -0
- package/skills/uxelle-design-harness/recipe-landing-page.md +94 -0
- package/skills/uxelle-design-harness/recipe-logo-wall.md +80 -0
- package/skills/uxelle-design-harness/recipe-multi-step-flow.md +108 -0
- package/skills/uxelle-design-harness/recipe-page-header.md +102 -0
- package/skills/uxelle-design-harness/recipe-page-shell.md +82 -0
- package/skills/uxelle-design-harness/recipe-pricing.md +83 -0
- package/skills/uxelle-design-harness/recipe-query-bar.md +108 -0
- package/skills/uxelle-design-harness/recipe-record-detail.md +96 -0
- package/skills/uxelle-design-harness/recipe-settings-page.md +170 -0
- package/skills/uxelle-design-harness/recipe-stat-callouts.md +111 -0
- package/skills/uxelle-design-harness/recipe-states.md +119 -0
- package/skills/uxelle-design-harness/recipe-summary-list.md +88 -0
- package/skills/uxelle-design-harness/recipe-template.md +62 -0
- package/skills/uxelle-design-harness/recipe-testimonial.md +73 -0
- package/skills/uxelle-design-harness/spacing-steps.md +57 -0
- package/skills/uxelle-design-harness/tokens.md +101 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# ChoiceChipGroup
|
|
2
|
+
|
|
3
|
+
Import: `import { ChoiceChipGroup } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Groups choice toggles under an optional legend, wrapping to new rows as needed.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| children | `ReactNode` | `—` | **ChoiceChip** elements only. They render in a wrapping row inside the fieldset, above `fieldMessage`. |
|
|
14
|
+
| label | `boolean` | `true` | Renders a `legend` naming the group when `true` and `labelText` is non-empty. When `false`, name the group with `aria-label` or `aria-labelledby` instead. |
|
|
15
|
+
| labelText | `string` | `"Options"` | Text shown in the `legend` while `label` is `true`. It is trimmed first, so a blank string suppresses the legend and the group then needs `aria-label`. |
|
|
16
|
+
| fieldMessage | `ReactNode` | `—` | Validation or helper content rendered below the chips. A string or number is wrapped in **FieldMessage** using `fieldMessageType`; any other node renders as-is. When `invalid` is true, a Danger field message is shown (this value when provided, otherwise a default error string). |
|
|
17
|
+
| fieldMessageType | `"Info" \| "Danger" \| "Warning" \| "Success"` | `CHOICE_CHIP_GROUP_DEFAULTS.fieldMessageType` | Tone of the wrapped **FieldMessage** — `Info`, `Danger`, `Warning`, or `Success`. Forced to `Danger` while `invalid` is true. `Danger` wires the message as `aria-errormessage` and announces it politely; other tones link through `aria-describedby`. |
|
|
18
|
+
| required | `boolean` | `false` | Sets `aria-required` on the fieldset and shows the **Label** asterisk while a legend is visible. No native validation is enforced — the app owns that. |
|
|
19
|
+
| invalid | `boolean` | `false` | Sets `aria-invalid="true"` and shows a Danger field message (uses `fieldMessage` when set, otherwise a default error string). Also wires `aria-errormessage` and announces the message politely. `aria-invalid={true}` does the same; `false` is treated as omitted so this prop can still apply. |
|
|
20
|
+
| role | `string` | `"group"` | ARIA role on the fieldset. Keep `group` for independent toggles; switch to `radiogroup` only when the app enforces exclusive selection and the chips carry matching roles. |
|
|
21
|
+
| "aria-label" | `string` | `""` | Accessible name for the fieldset, used only when no legend is showing. Prefer a visible legend via `label` and `labelText`; this value is dropped while one renders. |
|
|
22
|
+
| "aria-labelledby" | `string` | `""` | IDs of elements that name the fieldset when no legend renders, space-separated. Dropped while a legend is showing, since the legend already names the group. |
|
|
23
|
+
| "aria-describedby" | `string` | `""` | IDs of elements describing the group, space-separated. Merged with the field-message region id for non-`Danger` messages rather than replacing it. |
|
|
24
|
+
| "aria-errormessage" | `string` | `""` | ID of the element holding the error text. Defaults to the field-message region once the resolved message type is Danger, and is only announced while the group is also invalid. An empty string is treated as omitted so that default still applies. |
|
|
25
|
+
| "aria-invalid" | `boolean` | `false` | Explicit `aria-invalid` on the fieldset. `true` marks the group invalid and triggers the Danger field message; `false` is treated as omitted so `invalid` can still apply. A `Danger` field message alone does not mark the group invalid. |
|
|
26
|
+
| "aria-required" | `boolean` | `false` | Explicit `aria-required` on the fieldset. `true` marks a selection mandatory; `false` is treated as omitted so `required` can still apply. |
|
|
27
|
+
|
|
28
|
+
<!-- prettier-ignore-end -->
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
<ChoiceChipGroup label labelText="Sort by">
|
|
34
|
+
<ChoiceChip label="Relevance" onChange={() => {}} />
|
|
35
|
+
<ChoiceChip label="Newest" checked onChange={() => {}} />
|
|
36
|
+
</ChoiceChipGroup>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// Exclusive single-select (app-owned)
|
|
41
|
+
<ChoiceChipGroup label labelText="Sort by" role="radiogroup">
|
|
42
|
+
<ChoiceChip label="Relevance" checked onChange={() => {}} />
|
|
43
|
+
<ChoiceChip label="Newest" onChange={() => {}} />
|
|
44
|
+
</ChoiceChipGroup>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Notes
|
|
49
|
+
|
|
50
|
+
- Pass **ChoiceChip** children. Root is a **`fieldset`** with default **`role="group"`**; name it with the legend (`label` + `labelText`) or `aria-label` / `aria-labelledby`. Selection policy (single vs multi) is app-owned — this group does not enforce exclusivity. Keep **`role="group"`** for independent toggles. For exclusive single-select, keep one checked value in app state and set **`role="radiogroup"`** on the group. Form parity: **`fieldMessage`**, **`required`**, **`invalid`**, and merged **`aria-describedby`** / **`aria-errormessage`**. For dismissible applied filters, use **FilterChipGroup**. There is no InputChip — compose entry (e.g. Textfield) with FilterChips for removable values.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# DatePicker
|
|
2
|
+
|
|
3
|
+
Import: `import { DatePicker } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Form control for choosing a single calendar date by typing or from a month grid.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| label | `boolean` | `true` | Renders the label row above the field. Set it false for a bare field, and then pass `aria-label` so the combobox still has an accessible name. |
|
|
14
|
+
| labelText | `string` | `"Select a date"` | Visible label rendered as `Text` (Body Medium Alt) inside `Label`, and the element that names the combobox. An empty string drops the label row entirely. |
|
|
15
|
+
| labelSlot | `ReactNode` | `—` | Custom label content replacing the default `Text`, while `Label` keeps `htmlFor` and the `required` asterisk. Use it for links or badges beside the label copy. |
|
|
16
|
+
| fieldDescription | `string` | `""` | Supporting copy below the label (Condensed text), wired to the combobox through `aria-describedby`. Rendered only while the label row is visible. |
|
|
17
|
+
| fieldMessage | `boolean` | `false` | Shows the message row below the field so helper copy is always visible. The row also appears on its own whenever `validation` is `error`. |
|
|
18
|
+
| fieldMessageContent | `string` | `""` | Message text for the row. Falls back to `Enter a valid date.` when `validation` is `error`, or to generic helper copy otherwise; a rejected typed date overrides it with a locale format hint. |
|
|
19
|
+
| validation | `"none" \| "error"` | `"none"` | Validation state of the field. `error` turns the message row into a Danger `FieldMessage` and sets `aria-invalid` / `aria-errormessage`; only `none` and `error` are supported. |
|
|
20
|
+
| placeholder | `string` | `""` | Hint text shown in the field while no date is selected. |
|
|
21
|
+
| value | `string` | `""` | Selected date as `YYYY-MM-DD`, controlled whenever the prop is present. Use `null` or `""` for empty; strings that are not valid ISO dates read as empty. |
|
|
22
|
+
| defaultValue | `string \| null` | `—` | Starting date as `YYYY-MM-DD` while `value` is omitted, after which the component owns the selection. |
|
|
23
|
+
| onChange | `(value: string \| null) => void` | `—` | Called with the committed date as `YYYY-MM-DD`, or `null` when the field is cleared or the picked date fails the availability rules. |
|
|
24
|
+
| open | `boolean` | `—` | Controlled open state of the calendar. Pass with `onOpenChange`; omit to let the component manage its own. |
|
|
25
|
+
| defaultOpen | `boolean` | `false` | Whether the calendar starts open while `open` is omitted. |
|
|
26
|
+
| onOpenChange | `(open: boolean) => void` | `—` | Called with the next open state whenever the calendar opens or closes. |
|
|
27
|
+
| readOnly | `boolean` | `false` | Keeps the formatted date visible but blocks editing: the calendar cannot open and the chevron is not rendered. Use `disabled` instead when the field is inactive. |
|
|
28
|
+
| required | `boolean` | `false` | Marks the field as required — asterisk on `Label`, plus `required` and `aria-required` on the combobox. It does not block submission on its own. |
|
|
29
|
+
| minDate | `string` | `""` | Earliest selectable date (`YYYY-MM-DD`). Earlier days are disabled, month navigation stops there, and an earlier typed date is rejected as invalid. |
|
|
30
|
+
| maxDate | `string` | `""` | Latest selectable date (`YYYY-MM-DD`). Later days are disabled, month navigation stops there, and a later typed date is rejected as invalid. |
|
|
31
|
+
| unavailableDates | `readonly string[] \| null` | `—` | ISO dates (`YYYY-MM-DD`) that cannot be selected. Combined with `isDateUnavailable` and `minDate` / `maxDate`. |
|
|
32
|
+
| isDateUnavailable | `(iso: string) => boolean` | `—` | Return true to disable that calendar day. Receives an ISO date-only string. Combined with `unavailableDates` and `minDate` / `maxDate`. |
|
|
33
|
+
| locale | `string` | `"en-US"` | BCP 47 tag driving the displayed date format, the field order accepted when typing, weekday labels, and which day starts the week. ISO input is always accepted regardless. |
|
|
34
|
+
| today | `string \| null` | `—` | Overrides the date marked as today and the month opened when nothing is selected (`YYYY-MM-DD`). Pin it for deterministic tests and snapshots. |
|
|
35
|
+
| datePickerSlot | `ReactNode` | `—` | Replaces the whole built-in calendar panel, month navigation included, so `previousMonthAriaLabel` / `nextMonthAriaLabel` no longer apply. Omit it to use the month grid. |
|
|
36
|
+
| previousMonthAriaLabel | `string` | `"Previous month"` | Accessible name for the previous-month button. Defaults to English, so pass a translated string in localized apps. |
|
|
37
|
+
| nextMonthAriaLabel | `string` | `"Next month"` | Accessible name for the next-month button. Defaults to English, so pass a translated string in localized apps. |
|
|
38
|
+
| name | `string` | `—` | Form field name for a hidden input carrying the ISO date. The input is omitted while nothing is selected or a typed draft is still invalid. |
|
|
39
|
+
| disabled | `boolean` | `false` | Blocks all interaction and applies disabled styling: the field cannot be typed in and the calendar cannot open. |
|
|
40
|
+
|
|
41
|
+
<!-- prettier-ignore-end -->
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
<DatePicker labelText="Start date" value={date} onChange={setDate} locale="en-US" />
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## Notes
|
|
51
|
+
|
|
52
|
+
- **Value** — `onChange` receives an ISO date-only string (`YYYY-MM-DD`) or `null`. Display and typed input follow `locale` (week start included). Paste also accepts ISO. Month names and other non-numeric text are not parsed: the typed value stays, the field is marked invalid, and a locale format hint is shown (for example `Enter a date as MM/DD/YYYY.`). Hidden form values are omitted while the draft is invalid.
|
|
53
|
+
- **Calendar** — Opens from the field; **Escape** or clicking outside closes it. Choosing a date commits and closes. Days outside the current month are shown but not selectable.
|
|
54
|
+
- **Accessibility**: Visible label uses `<Label htmlFor>`; the combobox name uses `aria-labelledby` on the label text. `required` shows the Label asterisk and sets `aria-required` on the combobox. `FieldMessage` uses `aria-describedby` (info) or `aria-errormessage` (error). Pass `id` for stable ids; use `aria-label` when `label={false}`. `autoComplete` defaults to `off` so browser date autofill does not fight the calendar; pass `bday` (or another HTML token) when the field collects a known personal date.
|
|
55
|
+
- **Keyboard**: **Tab** focuses the text field so a locale-formatted date can be typed (**Enter** commits). Dates in the calendar are not separate tab stops. **ArrowDown** opens the calendar and moves focus into the month grid; arrows move by day/week; **Home** / **End** move to the start/end of the week; **PageUp** / **PageDown** move the focused date by one month (same day, clamped); **Shift+PageUp** / **Shift+PageDown** move by one year. **Escape** (from the field or the grid) closes and returns focus to the field.
|
|
56
|
+
- **Trigger**: The visible chevron is presentational (`aria-hidden`, `tabIndex={-1}`); the combobox owns `aria-haspopup`.
|
|
57
|
+
- **Limits**: Selectable dates are gated with `minDate` / `maxDate`, `unavailableDates`, and `isDateUnavailable`. Those rules disable `DatePickerDate` cells. `validation` supports `none` and `error` only.
|
|
58
|
+
- **Copy**: `previousMonthAriaLabel` / `nextMonthAriaLabel` default to English so the host app can pass translated strings. Month titles, weekdays, and typed values follow `locale`.
|
|
59
|
+
- **Forms**: With `name`, a hidden input posts the ISO date; it is omitted when empty or the typed draft is invalid.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# DatePickerRange
|
|
2
|
+
|
|
3
|
+
Import: `import { DatePickerRange } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Form control for choosing a start and end calendar date by typing or from a month grid.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| label | `boolean` | `true` | Renders the label row above the field. Set it false for a bare field, and then pass `aria-label` so the combobox still has an accessible name. |
|
|
14
|
+
| labelText | `string` | `"Select your date range"` | Visible label rendered as `Text` (Body Medium Alt) inside `Label`, and the element that names the combobox. An empty string drops the label row entirely. |
|
|
15
|
+
| labelSlot | `ReactNode` | `—` | Custom label content replacing the default `Text`, while `Label` keeps `htmlFor` and the `required` asterisk. Use it for links or badges beside the label copy. |
|
|
16
|
+
| fieldDescription | `string` | `""` | Supporting copy below the label (Condensed text), wired to the combobox through `aria-describedby`. Rendered only while the label row is visible. |
|
|
17
|
+
| fieldMessage | `boolean` | `false` | Shows the message row below the field so helper copy is always visible. The row also appears on its own whenever `validation` is `error`. |
|
|
18
|
+
| fieldMessageContent | `string` | `""` | Message text for the row. Falls back to `Enter a valid date range.` when `validation` is `error`, or to generic helper copy otherwise; a rejected typed range overrides it with a locale format hint. |
|
|
19
|
+
| validation | `"none" \| "error"` | `"none"` | Validation state of the field. `error` turns the message row into a Danger `FieldMessage` and sets `aria-invalid` / `aria-errormessage`; only `none` and `error` are supported. |
|
|
20
|
+
| placeholder | `string` | `""` | Hint text shown in the field while no range is selected. |
|
|
21
|
+
| start | `string` | `""` | Range start as `YYYY-MM-DD`, controlled whenever the prop is present and independent of `end`. Use `null` or `""` for empty; strings that are not valid ISO dates read as empty. |
|
|
22
|
+
| end | `string` | `""` | Range end as `YYYY-MM-DD`, controlled whenever the prop is present and independent of `start`. Use `null` or `""` for empty; strings that are not valid ISO dates read as empty. |
|
|
23
|
+
| defaultStart | `string \| null` | `—` | Starting range start while `start` is omitted, after which the component owns it. |
|
|
24
|
+
| defaultEnd | `string \| null` | `—` | Starting range end while `end` is omitted, after which the component owns it. |
|
|
25
|
+
| onChange | `(value: DatePickerRangeValue) => void` | `—` | Called with both sides of the range on every commit — `{ start, end }` as ISO dates or `null`. Picking a first date reports an end of `null` until the range is closed. |
|
|
26
|
+
| open | `boolean` | `—` | Controlled open state of the calendar. Pass with `onOpenChange`; omit to let the component manage its own. |
|
|
27
|
+
| defaultOpen | `boolean` | `false` | Whether the calendar starts open while `open` is omitted. |
|
|
28
|
+
| onOpenChange | `(open: boolean) => void` | `—` | Called with the next open state whenever the calendar opens or closes. |
|
|
29
|
+
| readOnly | `boolean` | `false` | Keeps the formatted range visible but blocks editing: the calendar cannot open and the chevron is not rendered. Use `disabled` instead when the field is inactive. |
|
|
30
|
+
| required | `boolean` | `false` | Marks the field as required — asterisk on `Label`, plus `required` and `aria-required` on the combobox. It does not block submission on its own. |
|
|
31
|
+
| minDate | `string` | `""` | Earliest selectable date (`YYYY-MM-DD`) for both ends of the range. Earlier days are disabled, month navigation stops there, and an earlier typed date is rejected. |
|
|
32
|
+
| maxDate | `string` | `""` | Latest selectable date (`YYYY-MM-DD`) for both ends of the range. Later days are disabled, month navigation stops there, and a later typed date is rejected. |
|
|
33
|
+
| unavailableDates | `readonly string[] \| null` | `—` | ISO dates (`YYYY-MM-DD`) that cannot be selected. Combined with `isDateUnavailable` and `minDate` / `maxDate`. Dates between the ends are not checked, so a range can span an unavailable day. |
|
|
34
|
+
| isDateUnavailable | `(iso: string) => boolean` | `—` | Return true to disable that calendar day. Receives an ISO date-only string. Combined with `unavailableDates` and `minDate` / `maxDate`, and applied to the chosen ends rather than the days between them. |
|
|
35
|
+
| locale | `string` | `"en-US"` | BCP 47 tag driving the displayed range format, the field order accepted when typing, weekday labels, and which day starts the week. ISO input is always accepted regardless. |
|
|
36
|
+
| today | `string \| null` | `—` | Overrides the date marked as today and the month opened when nothing is selected (`YYYY-MM-DD`). Pin it for deterministic tests and snapshots. |
|
|
37
|
+
| datePickerSlot | `ReactNode` | `—` | Replaces the whole built-in calendar panel, month navigation and range status included, so `previousMonthAriaLabel`, `nextMonthAriaLabel`, and `rangeSelectionStatus` no longer apply. Omit it to use the month grid. |
|
|
38
|
+
| previousMonthAriaLabel | `string` | `"Previous month"` | Accessible name for the previous-month button. Defaults to English, so pass a translated string in localized apps. |
|
|
39
|
+
| nextMonthAriaLabel | `string` | `"Next month"` | Accessible name for the next-month button. Defaults to English, so pass a translated string in localized apps. |
|
|
40
|
+
| rangeSelectionStatus | `string` | `"Start date selected. Choose an end date."` | Polite live-region copy announced while a start date is chosen and an end date is still needed. Defaults to English, so pass a translated string in localized apps. |
|
|
41
|
+
| startName | `string` | `—` | Form field name for a hidden input carrying the ISO start date; falls back to `name` when omitted. The input is omitted while no start is set or a typed draft is invalid. |
|
|
42
|
+
| endName | `string` | `—` | Form field name for a hidden input carrying the ISO end date. The input is omitted while no end is set or a typed draft is invalid. |
|
|
43
|
+
| disabled | `boolean` | `false` | Blocks all interaction and applies disabled styling: the field cannot be typed in and the calendar cannot open. |
|
|
44
|
+
|
|
45
|
+
<!-- prettier-ignore-end -->
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<DatePickerRange
|
|
51
|
+
labelText="Travel dates"
|
|
52
|
+
start={start}
|
|
53
|
+
end={end}
|
|
54
|
+
onChange={({ start, end }) => {
|
|
55
|
+
setStart(start);
|
|
56
|
+
setEnd(end);
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Notes
|
|
63
|
+
|
|
64
|
+
- **Value** — `start` / `end` are ISO date-only strings (`YYYY-MM-DD`) or `null`. `onChange` receives both. Display and typed input follow `locale` as `start - end`.
|
|
65
|
+
- **Selection** — The first click sets start; the second sets end and closes the calendar. A later click starts a new range. Days outside the current month are shown but not selectable. v1 uses a single field and one month grid.
|
|
66
|
+
- **Accessibility**: Same labeling pattern as DatePicker (`Label htmlFor`, `aria-describedby`, `aria-errormessage`). `required` shows the Label asterisk and sets `aria-required` on the combobox. Use `aria-label` when `label={false}`. After the start date is chosen, a live region announces `rangeSelectionStatus`. `autoComplete` defaults to `off`; pass an HTML token when the host needs browser autofill.
|
|
67
|
+
- **Keyboard**: **Tab** focuses the text field so a locale-formatted range can be typed (**Enter** commits). Dates in the calendar are not separate tab stops. **ArrowDown** opens the calendar and moves focus into the grid; arrows move by day/week; **Home** / **End** move to the start/end of the week; **PageUp** / **PageDown** move the focused date by one month; **Shift+PageUp** / **Shift+PageDown** move by one year. **Escape** closes and returns focus to the field.
|
|
68
|
+
- **Typing**: Display uses `start - end`. Range parsing splits on a spaced hyphen or an en/em dash so ISO dates and hyphen locales (e.g. `sv-SE`) are not shattered. Month names and other non-numeric text are not parsed: the typed value stays, the field is marked invalid, and a locale format hint is shown. Hidden form values are omitted while the draft is invalid.
|
|
69
|
+
- **Controlled value**: `start` and `end` are controlled independently. Pass both (use `null` for an empty side) when the host owns the range. Passing only one leaves the other uncontrolled.
|
|
70
|
+
- **Trigger**: The visible chevron is presentational (`aria-hidden`, `tabIndex={-1}`); the combobox owns `aria-haspopup`.
|
|
71
|
+
- **Limits**: Selectable dates are gated with `minDate` / `maxDate`, `unavailableDates`, and `isDateUnavailable`. Those rules disable `DatePickerDate` cells. `validation` supports `none` and `error` only.
|
|
72
|
+
- **Copy**: Chrome strings (`previousMonthAriaLabel`, `nextMonthAriaLabel`, `rangeSelectionStatus`) default to English so the host app can pass translated copy. Month titles, weekdays, and typed values follow `locale`.
|
|
73
|
+
- **Forms**: `startName` / `endName` render hidden inputs with ISO dates when set; they are omitted while the typed draft is invalid.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Dialog
|
|
2
|
+
|
|
3
|
+
Import: `import { Dialog } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Centered modal for focused tasks such as confirmations and forms.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| fullScreen | `boolean` | `false` | Fills the viewport with edge-to-edge panel chrome and drops the scrim, so `size` and `closeOnScrimClick` no longer apply. |
|
|
14
|
+
| size | `"Small" \| "Medium" \| "Large"` | `"Medium"` | Panel width preset — Small for confirmations, Medium for short forms, Large for denser content. Ignored while `fullScreen` is true. |
|
|
15
|
+
| open | `boolean` | `—` | Controlled visibility. Pass it with `onOpenChange` and update it yourself; omit it to let the dialog track its own state from `defaultOpen`. |
|
|
16
|
+
| defaultOpen | `boolean` | `false` | Whether the dialog starts open on first render. Ignored afterwards, and whenever `open` is passed. |
|
|
17
|
+
| onOpenChange | `(open: boolean) => void` | `—` | Called with the requested visibility when the trigger is clicked, Escape is pressed, or the scrim is dismissed. Required when `open` is controlled. |
|
|
18
|
+
| trigger | `ReactElement` | `—` | Optional single element used to toggle visibility. Must accept and forward `onClick`, `aria-expanded`, `aria-haspopup`, and `aria-controls` (native button or a component that spreads props to its hit target). Fragments and wrappers that drop props are not supported — control `open` yourself instead. |
|
|
19
|
+
| topSlotContent | `ReactNode` | `—` | Header region — the visible title, an optional subtitle, and a close control (`Text` plus `IconButton`). With no `aria-label` / `aria-labelledby`, the first non-kicker `Text` here becomes the dialog's accessible name. |
|
|
20
|
+
| centerSlotContent | `ReactNode` | `—` | Body region holding the task content; it scrolls on its own once the panel overflows. Point `aria-describedby` at it when the body should be announced. |
|
|
21
|
+
| bottomSlotContent | `ReactNode` | `—` | Footer region for the confirm and cancel actions, usually a `ButtonGroup` of `Button`s. Put a Cancel action here so the dialog is dismissible without relying on Escape or the scrim. |
|
|
22
|
+
| initialFocusRef | `RefObject<HTMLElement \| null>` | `—` | Ref to the element that should take focus when the dialog opens — typically the first input, or the safe action for destructive flows. Omit it to focus the panel itself; a target outside the panel or one that refuses focus also falls back to the panel. Focus returns to the trigger on close either way. |
|
|
23
|
+
| closeOnEscape | `boolean` | `true` | When true, Escape closes the dialog — only the topmost of stacked dialogs responds. Set false for critical flows the user must finish or cancel from in-panel actions. |
|
|
24
|
+
| closeOnScrimClick | `boolean` | `true` | When true, pressing outside the panel closes the dialog. Has no effect while `fullScreen` is true, since there is no scrim to press. |
|
|
25
|
+
|
|
26
|
+
<!-- prettier-ignore-end -->
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<Dialog
|
|
32
|
+
size="Large"
|
|
33
|
+
aria-labelledby="dialog-title"
|
|
34
|
+
topSlotContent={
|
|
35
|
+
<>
|
|
36
|
+
<div className="uxl-internal-dialog__title-block">
|
|
37
|
+
<Text id="dialog-title" type="Component Medium" width={false}>
|
|
38
|
+
Confirm your changes
|
|
39
|
+
</Text>
|
|
40
|
+
<Text type="Body Small" width={false}>
|
|
41
|
+
Step 2 of 3
|
|
42
|
+
</Text>
|
|
43
|
+
</div>
|
|
44
|
+
<IconButton
|
|
45
|
+
emphasis="low"
|
|
46
|
+
size="small"
|
|
47
|
+
iconName="close"
|
|
48
|
+
iconVariant="sharpFilled"
|
|
49
|
+
aria-label="Close"
|
|
50
|
+
onClick={() => setOpen(false)}
|
|
51
|
+
/>
|
|
52
|
+
</>
|
|
53
|
+
}
|
|
54
|
+
centerSlotContent={
|
|
55
|
+
<Text type="Body Medium" width={false}>
|
|
56
|
+
Review the details below before continuing.
|
|
57
|
+
</Text>
|
|
58
|
+
}
|
|
59
|
+
bottomSlotContent={
|
|
60
|
+
<ButtonGroup direction="row" aria-label="Dialog actions">
|
|
61
|
+
<Button emphasis="low" size="medium" onClick={() => setOpen(false)}>
|
|
62
|
+
Cancel
|
|
63
|
+
</Button>
|
|
64
|
+
<Button emphasis="high" size="medium" onClick={() => setOpen(false)}>
|
|
65
|
+
Confirm
|
|
66
|
+
</Button>
|
|
67
|
+
</ButtonGroup>
|
|
68
|
+
}
|
|
69
|
+
trigger={<Button emphasis="high">Open</Button>}
|
|
70
|
+
/>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Notes
|
|
75
|
+
|
|
76
|
+
- **Composition**: Renders `InternalDialog` for the panel chrome. Prefer this host over using `InternalDialog` alone so scrim, focus trap, Escape, and open/close stay consistent.
|
|
77
|
+
- **Slots**: Compose header, body, and actions into `topSlotContent`, `centerSlotContent`, and `bottomSlotContent` (Text, IconButton, Button, ButtonGroup, etc.). Empty slots are omitted from the panel DOM.
|
|
78
|
+
- **Dismiss affordance**: Always provide a visible Close control and/or Cancel action in the slots. Do not rely on Escape or scrim alone — especially for full screen, where there is no scrim.
|
|
79
|
+
- **Critical flows**: Set `closeOnEscape={false}` and/or `closeOnScrimClick={false}` when the user must complete or cancel via in-panel actions.
|
|
80
|
+
- **Full screen**: When `fullScreen` is true, the panel fills the viewport edge-to-edge and the scrim is omitted. Use `size` only for Small / Medium / Large widths.
|
|
81
|
+
- **Trigger**: `trigger` must be a single element that forwards click and ARIA props to its hit target. Use controlled `open` / `onOpenChange` when the opener cannot accept those props.
|
|
82
|
+
- **Text width**: `Text` in `topSlotContent` and `centerSlotContent` uses `width={false}` (100% of the slot). `width` / `width={true}` shrinks to the string and leaves a narrow column. Button labels stay `width` (fit content).
|
|
83
|
+
- **Accessibility**: `role="dialog"`, `aria-modal="true"`. Prefer `aria-labelledby` pointing at the visible title in `topSlotContent`, or `aria-label`. When those are omitted, the first heading or non-kicker `Text` in `topSlotContent` is associated automatically. Kicker/caption `Text` variants (`Overline`, `Overline Alt`, `Body Small`, `Body Small Alt`) and close buttons are never bound; if only kicker text is present, set `aria-label`/`aria-labelledby` explicitly. Optionally describe the body with `aria-describedby`. Focus moves into the panel on open and returns to the trigger on close.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Divider
|
|
2
|
+
|
|
3
|
+
Import: `import { Divider } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Thin rule that separates content, either horizontally or vertically.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| orientation | `"horizontal" \| "vertical"` | `"horizontal"` | Direction the rule runs: `horizontal` spans the parent's width, `vertical` its height. Only `horizontal` supports the `text` label layout. |
|
|
14
|
+
| emphasis | `"low" \| "high"` | `"low"` | Line weight and contrast: `low` is a hairline for separating items inside a list or card, `high` a darker, thicker rule for major section breaks. |
|
|
15
|
+
| text | `boolean` | `undefined` | Forces the label layout, splitting the rule around centered `children` (`horizontal` only). Omit it to pick the layout automatically from whether `children` are present. |
|
|
16
|
+
| children | `ReactNode` | `—` | Label rendered between the two line segments, wrapped in `Text` (`Condensed`). Passing children turns the label layout on unless `text` is explicitly false. |
|
|
17
|
+
| decorative | `boolean` | `undefined` | Semantics of the rule: true hides it with `aria-hidden`, false exposes it as `role='separator'` with `aria-orientation` (plus `aria-label` when set). Resolves to hidden for a plain rule and exposed once the label layout is shown. |
|
|
18
|
+
| "aria-label" | `string` | `""` | Accessible name for the separator, e.g. the section it introduces. Applied only when `decorative` resolves to false. |
|
|
19
|
+
|
|
20
|
+
<!-- prettier-ignore-end -->
|
|
21
|
+
|
|
22
|
+
Extends `HTMLAttributes` — supports standard HTML attributes.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
<Divider />
|
|
28
|
+
<Divider orientation="vertical" />
|
|
29
|
+
<Divider emphasis="high" text>Section</Divider>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- **WCAG AA compliant**: Uses theme tokens that meet contrast requirements
|
|
36
|
+
- **Semantic**: role="separator" with aria-orientation when not decorative
|
|
37
|
+
- **Decorative by default**: aria-hidden="true" when not showing text; use decorative={false} for semantic dividers
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# DynamicAngleLine
|
|
2
|
+
|
|
3
|
+
Import: `import { DynamicAngleLine } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Single diagonal brand accent line for decorative layouts and texture strips.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| dataColorSwitcher | `string` | `DYNAMIC_ANGLE_DEFAULT_DATA_COLOR_SWITCHER` | Palette name applied as `data-color-switcher` on the graphic, retinting its accent strokes or brand fill (for example `brand-1` or `brand-2`). On **DynamicAngleTextureText** it scopes the texture strip only, so the label keeps the surrounding page palette. |
|
|
14
|
+
| "data-color-switcher" | `string` | `—` | Attribute-style alias for `dataColorSwitcher`, useful when spreading raw DOM props. It wins when both are set; a blank value is treated as unset. |
|
|
15
|
+
| rotation | `"80" \| "75" \| "72" \| "65" \| "55" \| "50" \| "40"` | `"80"` | Stroke inclination in degrees: `80` is nearly upright and `40` the most reclined. Lower values also widen the cross-axis footprint, from 50px at `80` to 249px at `40` before `height` scaling. |
|
|
16
|
+
| direction | `"Vertical" \| "Horizontal"` | `"Vertical"` | Orientation of the 160px long axis. `Vertical` makes it the height for a tall, narrow accent; `Horizontal` makes it the width and tilts the stroke the opposite way. |
|
|
17
|
+
| height | `number` | `DYNAMIC_ANGLE_LINE_BASE_HEIGHT` | Long-axis length in px, scaled from the 160px base. The cross-axis grows in proportion while stroke thickness stays fixed; negative or non-finite values collapse to 0. |
|
|
18
|
+
|
|
19
|
+
<!-- prettier-ignore-end -->
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
// Decorative accent beside a hero band
|
|
25
|
+
<DynamicAngleLine
|
|
26
|
+
rotation="80"
|
|
27
|
+
direction="Vertical"
|
|
28
|
+
height={160}
|
|
29
|
+
dataColorSwitcher="brand-1"
|
|
30
|
+
/>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Notes
|
|
35
|
+
|
|
36
|
+
- Non-interactive graphic element. Stroke color follows `dataColorSwitcher` on this root (`--uxl-component-dynamic-angle-line-color`). Defaults to `aria-hidden={true}` for decorative hero and section accents; set `aria-hidden={false}` only when the graphic must be announced. `height` scales the footprint uniformly from its 160px long axis. Stroke thickness stays fixed via `--uxl-component-dynamic-angle-line-weight`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# DynamicAngleLineCombo
|
|
2
|
+
|
|
3
|
+
Import: `import { DynamicAngleLineCombo } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Paired diagonal accent lines arranged for brand expression layouts.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| dataColorSwitcher | `string` | `DYNAMIC_ANGLE_DEFAULT_DATA_COLOR_SWITCHER` | Palette name applied as `data-color-switcher` on the graphic, retinting its accent strokes or brand fill (for example `brand-1` or `brand-2`). On **DynamicAngleTextureText** it scopes the texture strip only, so the label keeps the surrounding page palette. |
|
|
14
|
+
| "data-color-switcher" | `string` | `—` | Attribute-style alias for `dataColorSwitcher`, useful when spreading raw DOM props. It wins when both are set; a blank value is treated as unset. |
|
|
15
|
+
| comboType | `"1" \| "2" \| "3"` | `"1"` | Which of the three built-in stroke pairings fills the 222×160 frame: `1` diverges from the bottom-left at 40° and 55°, `2` pairs a steep 75° with a reclined 50°, and `3` pairs 55° with 72°. |
|
|
16
|
+
| height | `number` | `DYNAMIC_ANGLE_LINE_COMBO_DEFAULTS.height` | Rendered height in px, scaled from the 160px base frame. Width follows at the 222:160 aspect and stroke thickness does not scale; omit for 160, and negative or non-finite values collapse to 0. |
|
|
17
|
+
|
|
18
|
+
<!-- prettier-ignore-end -->
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
// Decorative pair in a hero layout
|
|
24
|
+
<DynamicAngleLineCombo comboType="1" height={160} dataColorSwitcher="brand-1" />
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Notes
|
|
29
|
+
|
|
30
|
+
- Non-interactive decorative graphic. Draws two design-accurate accent strokes for the selected combo type. Accent color is scoped via `dataColorSwitcher` on this root. Defaults to `aria-hidden={true}` for decorative hero and section accents. `height` uniformly scales the design frame; stroke thickness stays fixed via `--uxl-component-dynamic-angle-line-weight`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# DynamicAngleShape
|
|
2
|
+
|
|
3
|
+
Import: `import { DynamicAngleShape } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Angled gradient shard for brand hero bands and section accents.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| dataColorSwitcher | `string` | `DYNAMIC_ANGLE_DEFAULT_DATA_COLOR_SWITCHER` | Palette name applied as `data-color-switcher` on the graphic, retinting its accent strokes or brand fill (for example `brand-1` or `brand-2`). On **DynamicAngleTextureText** it scopes the texture strip only, so the label keeps the surrounding page palette. |
|
|
14
|
+
| "data-color-switcher" | `string` | `—` | Attribute-style alias for `dataColorSwitcher`, useful when spreading raw DOM props. It wins when both are set; a blank value is treated as unset. |
|
|
15
|
+
| angleDirection | `"Right" \| "Left" \| "Bottom"` | `"Right"` | Edge the diagonal cuts from. `Right` and `Left` render a tall right triangle (mirrored from each other); `Bottom` renders a short wedge rising left to right and forces `angle` to `12`. |
|
|
16
|
+
| angle | `"80" \| "75" \| "72" \| "12"` | `"80"` | Steepness of the diagonal in degrees: `80` is the narrowest wedge, `75` and `72` are progressively wider at the same height, and `12` is the shallow `Bottom` cut. Ignored when `angleDirection` is `Bottom`, which always renders at `12`. |
|
|
17
|
+
| height | `number` | `DYNAMIC_ANGLE_SHAPE_BASE_HEIGHT` | Rendered height in px; width scales with it so the diagonal keeps its angle. Omit for the base height of the active direction (315.3 for `Right` and `Left`, 67 for `Bottom`); negative or non-finite values collapse to 0. |
|
|
18
|
+
| colorSwitcherBrand | `boolean` | `false` | Swaps the fill from the default blue theme gradient to the flat brand color of the active `dataColorSwitcher` palette. Use it when the shard sits on a section that already carries a palette. |
|
|
19
|
+
|
|
20
|
+
<!-- prettier-ignore-end -->
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
// Decorative shard in a hero band
|
|
26
|
+
<DynamicAngleShape angleDirection="Right" angle="80" colorSwitcherBrand />
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Notes
|
|
31
|
+
|
|
32
|
+
- Non-interactive decorative fill. By default uses the theme blue gradient; set `colorSwitcherBrand` to fill with `--uxl-component-dynamic-angle-shape-color` instead. `dataColorSwitcher` scopes the palette on this root. Defaults to `aria-hidden={true}` for decorative hero placement. `height` scales the footprint from the design base for the active direction (width included).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# DynamicAngleShapeSurface
|
|
2
|
+
|
|
3
|
+
Import: `import { DynamicAngleShapeSurface } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Large angled surface for section backgrounds and hero bands.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| dataColorSwitcher | `string` | `DYNAMIC_ANGLE_DEFAULT_DATA_COLOR_SWITCHER` | Palette name applied as `data-color-switcher` on the graphic, retinting its accent strokes or brand fill (for example `brand-1` or `brand-2`). On **DynamicAngleTextureText** it scopes the texture strip only, so the label keeps the surrounding page palette. |
|
|
14
|
+
| "data-color-switcher" | `string` | `—` | Attribute-style alias for `dataColorSwitcher`, useful when spreading raw DOM props. It wins when both are set; a blank value is treated as unset. |
|
|
15
|
+
| angleDirection | `"Right" \| "Left" \| "Top"` | `"Right"` | Corner or edge the diagonal cut runs along: `Right` slopes the bottom-right corner inward, `Left` slopes the top-left corner, and `Top` shaves a shallow rise across the top edge. It also selects the base frame — 742×618 for `Right` and `Left`, 742×487 for `Top`. |
|
|
16
|
+
| height | `number` | `DYNAMIC_ANGLE_SHAPE_SURFACE_BASE_HEIGHT` | Rendered height in px; width scales with it so the cut keeps its angle. Omit for the base height of the active direction (618 for `Right` and `Left`, 487 for `Top`); negative or non-finite values collapse to 0. |
|
|
17
|
+
| colorSwitcherBrand | `boolean` | `false` | Swaps the fill from the default blue theme gradient to the flat brand color of the active `dataColorSwitcher` palette. Use it when the surface sits on a section that already carries a palette. |
|
|
18
|
+
|
|
19
|
+
<!-- prettier-ignore-end -->
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
// Decorative surface in a hero band
|
|
25
|
+
<DynamicAngleShapeSurface
|
|
26
|
+
angleDirection="Right"
|
|
27
|
+
height={618}
|
|
28
|
+
colorSwitcherBrand
|
|
29
|
+
/>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- Non-interactive decorative background. By default uses the theme blue gradient; set `colorSwitcherBrand` to fill with `--uxl-component-dynamic-angle-shape-color` instead. `dataColorSwitcher` scopes the palette on this root. Defaults to `aria-hidden={true}` for decorative hero placement. `height` uniformly scales the design frame so the angle cut does not warp.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# DynamicAngleTexture
|
|
2
|
+
|
|
3
|
+
Import: `import { DynamicAngleTexture } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Repeating diagonal line strip for inline brand texture accents.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| dataColorSwitcher | `string` | `DYNAMIC_ANGLE_DEFAULT_DATA_COLOR_SWITCHER` | Palette name applied as `data-color-switcher` on the graphic, retinting its accent strokes or brand fill (for example `brand-1` or `brand-2`). On **DynamicAngleTextureText** it scopes the texture strip only, so the label keeps the surrounding page palette. |
|
|
14
|
+
| "data-color-switcher" | `string` | `—` | Attribute-style alias for `dataColorSwitcher`, useful when spreading raw DOM props. It wins when both are set; a blank value is treated as unset. |
|
|
15
|
+
| lineCount | `number` | `DYNAMIC_ANGLE_TEXTURE_LINE_COUNT` | Number of repeated diagonal strokes; each adds about 3.6px of width, so the default 52 spans roughly 192px. Height is fixed at about 20.5px, and the value is floored and clamped to 0–500. |
|
|
16
|
+
|
|
17
|
+
<!-- prettier-ignore-end -->
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
// Decorative texture strip in a hero layout
|
|
23
|
+
<DynamicAngleTexture lineCount={52} dataColorSwitcher="brand-1" />
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Notes
|
|
28
|
+
|
|
29
|
+
- Non-interactive decorative graphic with compact stroke geometry (not a scaled **DynamicAngleLine**). Strokes are drawn in one SVG on an exact pitch grid so spacing stays even (avoids sub-pixel flex rounding). The strip uses a fixed height and clips stroke tips at the top and bottom edges. Defaults to `aria-hidden={true}`. `lineCount` is capped at **DYNAMIC_ANGLE_TEXTURE_LINE_COUNT_MAX**.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# DynamicAngleTextureText
|
|
2
|
+
|
|
3
|
+
Import: `import { DynamicAngleTextureText } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Inline label paired with a repeating diagonal texture strip.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| dataColorSwitcher | `string` | `DYNAMIC_ANGLE_DEFAULT_DATA_COLOR_SWITCHER` | Palette name applied as `data-color-switcher` on the graphic, retinting its accent strokes or brand fill (for example `brand-1` or `brand-2`). On **DynamicAngleTextureText** it scopes the texture strip only, so the label keeps the surrounding page palette. |
|
|
14
|
+
| "data-color-switcher" | `string` | `—` | Attribute-style alias for `dataColorSwitcher`, useful when spreading raw DOM props. It wins when both are set; a blank value is treated as unset. |
|
|
15
|
+
| textDirection | `"Right" \| "Left"` | `"Right"` | Side the label sits on. `Right` renders the texture strip first with the label after it; `Left` puts the label first and the strip after. |
|
|
16
|
+
| text | `string` | `"Health for all, Hunger for none"` | Tagline copy rendered as Body Medium **Text** beside the strip. Unlike the texture it keeps the surrounding page palette, so it stays readable whatever `dataColorSwitcher` is set to. |
|
|
17
|
+
| lineCount | `number` | `DYNAMIC_ANGLE_TEXTURE_LINE_COUNT` | Number of repeated diagonal strokes; each adds about 3.6px of width, so the default 52 spans roughly 192px. Height is fixed at about 20.5px, and the value is floored and clamped to 0–500. |
|
|
18
|
+
|
|
19
|
+
<!-- prettier-ignore-end -->
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
// Tagline row in a hero band
|
|
25
|
+
<DynamicAngleTextureText
|
|
26
|
+
textDirection="Right"
|
|
27
|
+
text="Health for all, Hunger for none"
|
|
28
|
+
dataColorSwitcher="brand-1"
|
|
29
|
+
/>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- Decorative brand expression row for taglines and manifesto copy in hero and section layouts. `dataColorSwitcher` applies to the texture strip only so label text keeps the page palette. The texture is hidden from assistive technologies; the label uses **Text** Body Medium styling and remains readable.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# FieldMessage
|
|
2
|
+
|
|
3
|
+
Import: `import { FieldMessage } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Contextual helper, error, or success message shown below a form field or input.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| messageType | `"Info" \| "Danger" \| "Warning" \| "Success"` | `"Info"` | Status the message conveys, which picks the default icon (`help`, `error`, `warning`, `check_circle`) and the status color. When you compose your own children the color still applies, but you supply the icon. |
|
|
14
|
+
| children (required) | `ReactNode` | `—` | Message content. Pass a plain string to get the `messageType` icon plus `Condensed` `Text` automatically; pass elements — your own `Icon` and `Text` — to render them verbatim instead. |
|
|
15
|
+
|
|
16
|
+
<!-- prettier-ignore-end -->
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
<FieldMessage>
|
|
22
|
+
{/* React.ReactNode */}
|
|
23
|
+
</FieldMessage>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Notes
|
|
27
|
+
|
|
28
|
+
- Message types: Info, Danger, Warning, Success.
|
|
29
|
+
- **Simple usage** — pass a string; default Icon and Text are rendered: <FieldMessage messageType="Danger">You must choose at least 1 option</FieldMessage>
|
|
30
|
+
- **Composable usage** — pass Icon and Text as children for full control: <FieldMessage messageType="Danger"> <Icon iconName="error" variant="sharpFilled" size={16} aria-hidden /> <Text type="Condensed" inline>You must choose at least 1 option</Text> </FieldMessage>
|
|
31
|
+
- **Accessibility**: Use for validation hints, character counts, or supplemental guidance.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# FileUpload
|
|
2
|
+
|
|
3
|
+
Import: `import { FileUpload } from "@uxelle/components";`
|
|
4
|
+
|
|
5
|
+
Form control for choosing files with optional drag-and-drop, file list, and validation.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
<!-- prettier-ignore-start -->
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
|------|------|---------|-------------|
|
|
13
|
+
| label | `boolean` | `true` | When false, the label row is not rendered — pass `aria-label` (or `aria-labelledby`) for the accessible name. `fieldDescription` is dropped with it, so move helper copy to `aria-describedby`. |
|
|
14
|
+
| labelText | `string` | `"Upload documents"` | Visible label text, rendered as Body Medium Alt inside `Label`; ignored when `labelSlot` is set, and an empty string hides the label row. |
|
|
15
|
+
| fieldDescription | `string` | `"Max file size is 10MB."` | Helper copy under the label, linked to the file input with `aria-describedby`; keep it aligned with the active size limit. |
|
|
16
|
+
| labelSlot | `ReactNode` | `—` | Replaces `labelText` with custom content inside `Label`, which keeps `htmlFor` and the required asterisk. |
|
|
17
|
+
| fieldMessage | `boolean` | `false` | Renders a `FieldMessage` row below the control; `validation` set to `success` or `error` shows the row as well, so use this flag for neutral helper copy. |
|
|
18
|
+
| fieldMessageContent | `string` | `""` | Content for the `FieldMessage` row; when set it also replaces the built-in oversize-file error. |
|
|
19
|
+
| validation | `"none" \| "success" \| "error"` | `"none"` | Validation state: `success` and `error` restyle the field message and force the row. Any value other than `none` also suppresses the built-in oversize-file error, leaving the message to the app. |
|
|
20
|
+
| dragFiles | `boolean` | `false` | When true, the trigger is a dashed drop zone that accepts dropped files; when false, it is an upload `Button` that opens the file picker. |
|
|
21
|
+
| fullWidth | `boolean` | `false` | When true, the root fills its container; when false, it stays at the compact 243px width. |
|
|
22
|
+
| height | `number` | `150` | Height in pixels of the dashed drop zone. Only applies when `dragFiles` is true; the button trigger keeps the button’s intrinsic height. |
|
|
23
|
+
| buttonText | `string` | `"Upload Files"` | Label on the upload `Button`, or the centered copy inside the drop zone when `dragFiles` is true. |
|
|
24
|
+
| fileItems | `FileUploadFileItem[]` | `—` | Controlled list of rows shown under the trigger. Pair it with `onFileItemsChange` (or update it from `onFilesSelected`) — the component never mutates it. |
|
|
25
|
+
| onFileItemsChange | `(items: FileUploadFileItem[]) => void` | `—` | Called with the next row array whenever files are added or removed, in both controlled and uncontrolled mode. |
|
|
26
|
+
| defaultFileItems | `FileUploadFileItem[]` | `—` | Starting rows for uncontrolled usage; ignored once `fileItems` is set. |
|
|
27
|
+
| listSlot | `ReactNode` | `—` | Custom node rendered in place of the built-in file list. While it is set, selections no longer update the row state, so own the list from `onFilesSelected`. |
|
|
28
|
+
| onFilesSelected | `(files: FileList) => void` | `—` | Called with the accepted files as a `FileList` after a pick or drop; oversized files are already filtered out. Fires alongside the native `onChange`. |
|
|
29
|
+
| onRemoveFile | `(id: string) => void` | `—` | Called with the removed row's `id` after a built-in remove control is used. |
|
|
30
|
+
| removeFileAriaLabel | `string` | `"Remove {name}"` | `aria-label` template for each row's remove control; `{name}` is replaced with the file name. |
|
|
31
|
+
| maxFileSizeBytes | `number \| null` | `10 * 1024 * 1024` | Size limit in bytes: oversized files are dropped before `onFilesSelected` and the file list, and a danger `FieldMessage` appears while `validation` is `none`. Takes precedence over `maxFileSizeMB`; pass `null` to turn the check off. |
|
|
32
|
+
| maxFileSizeMB | `number` | `10` | Size limit in mebibytes (1024×1024 bytes) — the friendlier alias for `maxFileSizeBytes`. Ignored when `maxFileSizeBytes` is set; pass `null` to turn the check off. |
|
|
33
|
+
| maxFileSizeMessage | `string` | `"File exceeds the {limit}MB limit."` | Copy for the built-in oversize-file error, where `{limit}` is replaced with the limit in MB. Ignored when `fieldMessageContent` is set. |
|
|
34
|
+
| onMaxFileSizeExceeded | `(files: File[]) => void` | `—` | Called with the rejected `File` objects whenever files exceed the size limit. Fires even when the app owns `validation`, so it can raise its own message. |
|
|
35
|
+
| multiple | `boolean` | `true` | Allows picking or dropping several files at once; when false, each new selection replaces the current row instead of appending. |
|
|
36
|
+
| accept | `string` | `""` | Comma-separated file types forwarded to the native input `accept` (e.g. `image/*,.pdf`); it filters the file picker, not dropped files. |
|
|
37
|
+
|
|
38
|
+
<!-- prettier-ignore-end -->
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<FileUpload name="documents" accept="image/*,.pdf" onFilesSelected={upload} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## Notes
|
|
48
|
+
|
|
49
|
+
- **Uncontrolled list** — omit `fileItems`; selected files appear in the list automatically.
|
|
50
|
+
- **Controlled list** — pass `fileItems` and `onFileItemsChange` (or update `fileItems` from `onFilesSelected`).
|
|
51
|
+
- **File size** — `maxFileSizeMB` (default 10) or `maxFileSizeBytes` (bytes win if both are set; `null` disables) rejects oversized files and shows a FieldMessage when `validation` is `"none"`. Customize copy with `maxFileSizeMessage` (`{limit}` = MB) or own the message via `validation` / `fieldMessageContent` / `onMaxFileSizeExceeded`. Keep `fieldDescription` aligned with the limit.
|
|
52
|
+
- Root width defaults to 243px; set `fullWidth` to stretch to the container. Drop-zone height defaults to 150px via `height` (only when `dragFiles`). Remaining HTML attributes forward to the native file input; `className` applies to the root wrapper.
|
|
53
|
+
- **Accessibility**: Built-in `label` / `fieldDescription` wire `aria-labelledby` and `aria-describedby` on the file input. When `label={false}`, pass `aria-label` (or `aria-labelledby`). Upload rows use determinate `LinearProgress` while in progress.
|