@sdaia-ds/mcp 0.0.0-stage → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +291 -0
- package/dist/index.js.map +1 -0
- package/knowledge/actions/breadcrumb.md +50 -0
- package/knowledge/actions/button-menu.md +82 -0
- package/knowledge/actions/button-split.md +69 -0
- package/knowledge/actions/button.md +101 -0
- package/knowledge/actions/content-switcher.md +66 -0
- package/knowledge/actions/date-picker.md +115 -0
- package/knowledge/actions/floating-button.md +100 -0
- package/knowledge/actions/horizontal-tabs.md +52 -0
- package/knowledge/actions/link.md +76 -0
- package/knowledge/actions/modal.md +103 -0
- package/knowledge/actions/pagination.md +69 -0
- package/knowledge/actions/radio-button.md +88 -0
- package/knowledge/actions/switch.md +87 -0
- package/knowledge/actions/tag.md +69 -0
- package/knowledge/ai/agent-activity.md +65 -0
- package/knowledge/ai/agent-card.md +65 -0
- package/knowledge/ai/agent-handoff.md +65 -0
- package/knowledge/ai/ai-citation.md +78 -0
- package/knowledge/ai/ai-code-block.md +86 -0
- package/knowledge/ai/ai-disclaimer.md +84 -0
- package/knowledge/ai/ai-message-bubble.md +81 -0
- package/knowledge/ai/ai-message.md +118 -0
- package/knowledge/ai/ai-prompt-input.md +93 -0
- package/knowledge/ai/ai-states.md +107 -0
- package/knowledge/ai/ai-status-indicator.md +81 -0
- package/knowledge/ai/ai-suggested-prompts.md +62 -0
- package/knowledge/ai/ai-thinking-indicator.md +94 -0
- package/knowledge/ai/artifact-viewer.md +105 -0
- package/knowledge/ai/citation.md +61 -0
- package/knowledge/ai/context-manager.md +111 -0
- package/knowledge/ai/prompt-context.md +72 -0
- package/knowledge/ai/prompt-suggestion.md +68 -0
- package/knowledge/ai/prompt-template.md +71 -0
- package/knowledge/ai/prompt-variable.md +61 -0
- package/knowledge/ai/reasoning-trace.md +106 -0
- package/knowledge/ai/source-explorer.md +117 -0
- package/knowledge/ai/source-group.md +59 -0
- package/knowledge/ai/source-reference.md +70 -0
- package/knowledge/ai/thinking-panel.md +77 -0
- package/knowledge/ai/tool-activity-feed.md +67 -0
- package/knowledge/ai/tool-call-card.md +66 -0
- package/knowledge/ai/tool-status-row.md +72 -0
- package/knowledge/ai/tool-timeline-item.md +71 -0
- package/knowledge/ai/voice-session.md +93 -0
- package/knowledge/feedback/alert.md +106 -0
- package/knowledge/feedback/badge.md +86 -0
- package/knowledge/feedback/card.md +54 -0
- package/knowledge/feedback/feedback-overview.md +37 -0
- package/knowledge/feedback/feedback.md +46 -0
- package/knowledge/feedback/help-icon.md +57 -0
- package/knowledge/feedback/loading-indicator.md +76 -0
- package/knowledge/feedback/notification-banner.md +73 -0
- package/knowledge/feedback/notification-popup.md +87 -0
- package/knowledge/feedback/notifications.md +158 -0
- package/knowledge/feedback/progress-bar.md +69 -0
- package/knowledge/feedback/rating-overview.md +58 -0
- package/knowledge/feedback/rating.md +64 -0
- package/knowledge/feedback/skeleton-avatar.md +48 -0
- package/knowledge/feedback/skeleton.md +53 -0
- package/knowledge/feedback/toast.md +74 -0
- package/knowledge/feedback/tooltip.md +72 -0
- package/knowledge/form/autocomplete.md +100 -0
- package/knowledge/form/checkbox.md +95 -0
- package/knowledge/form/date-time-field.md +63 -0
- package/knowledge/form/error-summary.md +56 -0
- package/knowledge/form/field-group.md +57 -0
- package/knowledge/form/file-uploader.md +60 -0
- package/knowledge/form/form-section.md +58 -0
- package/knowledge/form/number-input.md +92 -0
- package/knowledge/form/otp-input.md +83 -0
- package/knowledge/form/password-input.md +49 -0
- package/knowledge/form/range-slider.md +71 -0
- package/knowledge/form/rich-text-editor.md +106 -0
- package/knowledge/form/select.md +113 -0
- package/knowledge/form/signature.md +83 -0
- package/knowledge/form/slider.md +66 -0
- package/knowledge/form/text-area.md +90 -0
- package/knowledge/form/text-input.md +132 -0
- package/knowledge/form/time-input.md +44 -0
- package/knowledge/form/time-picker.md +73 -0
- package/knowledge/foundations/accessibility.md +97 -0
- package/knowledge/foundations/colors.md +1117 -0
- package/knowledge/foundations/figma.md +30 -0
- package/knowledge/foundations/icon-usage.md +114 -0
- package/knowledge/foundations/icons.md +16 -0
- package/knowledge/foundations/motion.md +39 -0
- package/knowledge/foundations/radius.md +17 -0
- package/knowledge/foundations/responsive.md +64 -0
- package/knowledge/foundations/rtl.md +106 -0
- package/knowledge/foundations/spacing.md +27 -0
- package/knowledge/foundations/theme.md +115 -0
- package/knowledge/foundations/tokens.json +12124 -0
- package/knowledge/foundations/typography.md +45 -0
- package/knowledge/general/accordion.md +79 -0
- package/knowledge/general/activity.md +44 -0
- package/knowledge/general/app-shell.md +64 -0
- package/knowledge/general/area-chart.md +89 -0
- package/knowledge/general/audio-player.md +85 -0
- package/knowledge/general/avatar-group.md +50 -0
- package/knowledge/general/avatar.md +61 -0
- package/knowledge/general/carousel-image.md +103 -0
- package/knowledge/general/chart.md +25 -0
- package/knowledge/general/chip.md +90 -0
- package/knowledge/general/code-snippet.md +80 -0
- package/knowledge/general/column-chart.md +84 -0
- package/knowledge/general/context-menu.md +55 -0
- package/knowledge/general/digital-stamp.md +77 -0
- package/knowledge/general/divider.md +65 -0
- package/knowledge/general/donut-chart.md +75 -0
- package/knowledge/general/draggable-list.md +43 -0
- package/knowledge/general/dropdown.md +90 -0
- package/knowledge/general/empty-state.md +60 -0
- package/knowledge/general/filtration.md +85 -0
- package/knowledge/general/footer.md +59 -0
- package/knowledge/general/line-chart.md +95 -0
- package/knowledge/general/list.md +91 -0
- package/knowledge/general/media-gallery.md +85 -0
- package/knowledge/general/media-viewer.md +78 -0
- package/knowledge/general/menu.md +66 -0
- package/knowledge/general/metric.md +92 -0
- package/knowledge/general/nav-bar.md +62 -0
- package/knowledge/general/nav-header.md +125 -0
- package/knowledge/general/number.md +72 -0
- package/knowledge/general/page-template.md +80 -0
- package/knowledge/general/pdf-viewer.md +91 -0
- package/knowledge/general/pie-chart-panel.md +86 -0
- package/knowledge/general/popover.md +115 -0
- package/knowledge/general/progress-circle.md +63 -0
- package/knowledge/general/quote.md +64 -0
- package/knowledge/general/radial-stepper.md +72 -0
- package/knowledge/general/scatter-chart.md +62 -0
- package/knowledge/general/second-nav-header.md +55 -0
- package/knowledge/general/slideout-menu.md +92 -0
- package/knowledge/general/stepper.md +42 -0
- package/knowledge/general/structured-list.md +52 -0
- package/knowledge/general/table-bulk-actions-bar.md +66 -0
- package/knowledge/general/table-of-content.md +49 -0
- package/knowledge/general/table.md +113 -0
- package/knowledge/general/tree-view.md +55 -0
- package/knowledge/general/vertical-tabs.md +48 -0
- package/knowledge/general/video-player.md +88 -0
- package/knowledge/manifest.json +919 -0
- package/knowledge/patterns/buttons-with-sdaia-touch.md +34 -0
- package/knowledge/patterns/sdaia-logo-animation.md +35 -0
- package/knowledge/patterns/switch-with-sdaia-touch.md +29 -0
- package/knowledge/setup.md +125 -0
- package/package.json +45 -4
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Text Area
|
|
2
|
+
|
|
3
|
+
## Metadata
|
|
4
|
+
- Component: Text Area
|
|
5
|
+
- Slug: `text-area`
|
|
6
|
+
- Category: Form
|
|
7
|
+
- Install: `npx sdaia-ui@latest add text-area`
|
|
8
|
+
- Import: `import { TextArea } from '@/components/ui/TextArea'`
|
|
9
|
+
- Installed files: `TextArea.tsx`, `TextArea.types.ts`, `TextArea.variants.ts`, `index.ts`
|
|
10
|
+
- Docs: https://ds.nacew.com/components/textarea
|
|
11
|
+
|
|
12
|
+
> **Hard rule:** `sdaia-ui` is a CLI, not a runtime package — NEVER run `npm install sdaia-ui` and NEVER `import … from 'sdaia-ui'`. Run `npx sdaia-ui@latest init` once per project (Tailwind CSS v4, tokens, the IBM Plex Sans Arabic font, the `@/` alias on Vite, `cn`), then `npx sdaia-ui@latest add text-area`. It copies the source into your components folder (`components/ui/TextArea/`, under `src/` when the project has one); import it as `@/components/ui/TextArea`. The files are yours: prefer props and composition over editing them. `npx sdaia-ui@latest update` never overwrites a file you changed: it keeps it and says it has updates; `diff` shows them and `update --force` takes them.
|
|
13
|
+
|
|
14
|
+
## Description
|
|
15
|
+
Accessibility: the `<label>` is linked to the textarea via `htmlFor` / `id`
|
|
16
|
+
(the passed `id`, or an auto-generated one). Helper / error text is linked via
|
|
17
|
+
`aria-describedby`; any `aria-describedby` you pass (e.g. the id of a character
|
|
18
|
+
counter) is kept and merged in front of it.
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
| Prop | Type | Default | Description |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `dir?` | `'ltr' \| 'rtl'` | — | Layout direction — applied to the root wrapper. Unset inherits from the page. |
|
|
24
|
+
| `label?` | `ReactNode` | — | Label displayed above the textarea. When omitted, pass `aria-label` / `aria-labelledby`. |
|
|
25
|
+
| `labelHelp?` | `ReactNode` | — | Extra content rendered right after the label, e.g. a `<HelpIcon>`. It sits in the label row but OUTSIDE the `<label>` element, so its own accessible name (e.g. "Help") is not added to the field's name. |
|
|
26
|
+
| `validationBehavior?` | `'native' \| 'aria'` | 'native' | How `required` is applied to the native textarea. - `'native'`: the native `required` attribute (browser validation bubble on submit). - `'aria'`: `aria-required="true"` only — no browser bubble; validate in your own code. The visual `*` after the label shows in both modes. |
|
|
27
|
+
| `helperText?` | `string` | — | Helper text displayed below the textarea — linked via `aria-describedby` |
|
|
28
|
+
| `error?` | `string` | — | Error message — replaces helperText, switches to destructive style, sets `aria-invalid="true"` and is announced when it appears. |
|
|
29
|
+
| `destructive?` | `boolean` | false | Applies destructive (red) border and helper text styling; also sets `aria-invalid="true"` |
|
|
30
|
+
| `showButton?` | `boolean` | false | Shows a button below the textarea (rendered only when `buttonLabel` is set) |
|
|
31
|
+
| `buttonLabel?` | `string` | — | Label of the button shown by `showButton`. No default — pass your own (localised) text. |
|
|
32
|
+
| `onButtonClick?` | `() => void` | — | Callback when the button is clicked |
|
|
33
|
+
| `fullWidth?` | `boolean` | false | Makes the component take full width |
|
|
34
|
+
|
|
35
|
+
Also accepts standard `<textarea>` HTML attributes (`className`, `style`, `onClick`, `aria-*`, …) — except: `children`, `dir`.
|
|
36
|
+
|
|
37
|
+
## Options (allowed values)
|
|
38
|
+
- `dir`: `'ltr'` \| `'rtl'` — Layout direction — applied to the root wrapper. Unset inherits from the page.
|
|
39
|
+
- `validationBehavior`: `'native'` \| `'aria'` — Native `required` handling — see `TextAreaProps.validationBehavior`.
|
|
40
|
+
|
|
41
|
+
## Accessibility
|
|
42
|
+
Built in (SDAIA review item A2) — verified by `tests/a11y/keyboard/text-fields.spec.ts` in the design system's test suite:
|
|
43
|
+
- The textarea is named by its visible `label`.
|
|
44
|
+
- The destructive (error) state sets `aria-invalid` and keeps the helper text described.
|
|
45
|
+
|
|
46
|
+
You must:
|
|
47
|
+
- Always pass `label`.
|
|
48
|
+
|
|
49
|
+
- Don't remove the focus ring or replace interactive elements with `div`s; keep the control keyboard-operable.
|
|
50
|
+
- For contrast, keyboard patterns and RTL rules, call `get_foundations` (`accessibility`, `rtl`).
|
|
51
|
+
|
|
52
|
+
## Design tokens used
|
|
53
|
+
Keep these consistent (resolve values with `get_tokens`):
|
|
54
|
+
- `var(--ds-color-)`
|
|
55
|
+
- `var(--ds-color-bg-muted)`
|
|
56
|
+
- `var(--ds-color-border-brand)`
|
|
57
|
+
- `var(--ds-color-border-default)`
|
|
58
|
+
- `var(--ds-color-form-field-bg-default)`
|
|
59
|
+
- `var(--ds-color-form-field-border-danger)`
|
|
60
|
+
- `var(--ds-color-form-field-border-default)`
|
|
61
|
+
- `var(--ds-color-form-field-border-hovered)`
|
|
62
|
+
- `var(--ds-color-form-field-text-filled)`
|
|
63
|
+
- `var(--ds-color-form-field-text-helper)`
|
|
64
|
+
- `var(--ds-color-form-field-text-label)`
|
|
65
|
+
- `var(--ds-color-form-field-text-placeholder)`
|
|
66
|
+
- `var(--ds-color-icon-danger)`
|
|
67
|
+
- `var(--ds-color-icon-default-500)`
|
|
68
|
+
- `var(--ds-color-icon-default-disabled)`
|
|
69
|
+
- `var(--ds-color-primitive-neutral-400)`
|
|
70
|
+
- `var(--ds-color-text-danger)`
|
|
71
|
+
- `var(--ds-color-text-disabled)`
|
|
72
|
+
- `var(--ds-motion-feedback-duration)`
|
|
73
|
+
- `var(--ds-motion-feedback-easing)`
|
|
74
|
+
- `var(--ds-radius-m)`
|
|
75
|
+
- `var(--ds-spacing-lg)`
|
|
76
|
+
- `var(--ds-spacing-sm)`
|
|
77
|
+
- `var(--ds-spacing-xl)`
|
|
78
|
+
- `var(--ds-spacing-xs)`
|
|
79
|
+
- `var(--ds-spacing-xxs)`
|
|
80
|
+
- `var(--ds-text-family-text)`
|
|
81
|
+
- `var(--ds-text-leading-line-heights-text-md)`
|
|
82
|
+
- `var(--ds-text-leading-line-heights-text-sm)`
|
|
83
|
+
|
|
84
|
+
## AI usage guidance
|
|
85
|
+
When generating UI:
|
|
86
|
+
- Install with `npx sdaia-ui@latest add text-area` (after `npx sdaia-ui@latest init`), then import `{ TextArea }` from `@/components/ui/TextArea`.
|
|
87
|
+
- NEVER run `npm install sdaia-ui` and NEVER `import` from the `sdaia-ui` package — it is a source-copying CLI, not a component library.
|
|
88
|
+
- Use only the documented option values listed under "Options".
|
|
89
|
+
- Pass icons via `<DgaIcon data={…} className="size-icon-sm" />` from `@platformscode/icons` only — see `get_foundations` (`icon-usage`). Never emoji, Lucide, or random icons (e.g. `pizza01Stroke` for dark mode).
|
|
90
|
+
- Pick one theme per screen: dark is `.theme-dark` (or `.dark`) on `<html>`; style surrounding layout with DS tokens (`get_tokens`), never hardcoded colors.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Text Input
|
|
2
|
+
|
|
3
|
+
## Metadata
|
|
4
|
+
- Component: Text Input
|
|
5
|
+
- Slug: `text-input`
|
|
6
|
+
- Category: Form
|
|
7
|
+
- Install: `npx sdaia-ui@latest add text-input`
|
|
8
|
+
- Import: `import { TextInput } from '@/components/ui/TextInput'`
|
|
9
|
+
- Installed files: `TextInput.tsx`, `TextInput.types.ts`, `TextInput.variants.ts`, `TextInputTag.tsx`, `TextInputTag.types.ts`, `index.ts`, `resolveTextInputSize.ts`
|
|
10
|
+
- Docs: https://ds.nacew.com/components/text-input
|
|
11
|
+
|
|
12
|
+
> **Hard rule:** `sdaia-ui` is a CLI, not a runtime package — NEVER run `npm install sdaia-ui` and NEVER `import … from 'sdaia-ui'`. Run `npx sdaia-ui@latest init` once per project (Tailwind CSS v4, tokens, the IBM Plex Sans Arabic font, the `@/` alias on Vite, `cn`), then `npx sdaia-ui@latest add text-input`. It copies the source into your components folder (`components/ui/TextInput/`, under `src/` when the project has one); import it as `@/components/ui/TextInput`. The files are yours: prefer props and composition over editing them. `npx sdaia-ui@latest update` never overwrites a file you changed: it keeps it and says it has updates; `diff` shows them and `update --force` takes them.
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
| Prop | Type | Default | Description |
|
|
16
|
+
| --- | --- | --- | --- |
|
|
17
|
+
| `dir?` | `'ltr' \| 'rtl'` | — | Layout direction — applied to the root wrapper. Unset inherits from the page. |
|
|
18
|
+
| `label?` | `string` | — | Label text displayed above the input. Rendered as a `<label>` linked to the input via `htmlFor` / `id` (the passed `id`, or an auto-generated one). When omitted, pass `aria-label` or `aria-labelledby` so the field still has a name. |
|
|
19
|
+
| `labelHelp?` | `ReactNode` | — | Extra content rendered right after the label text, e.g. a `<HelpIcon>`. It sits in the label row but OUTSIDE the `<label>` element, so its own accessible name (e.g. "Help") is not added to the field's name. |
|
|
20
|
+
| `validationBehavior?` | `'native' \| 'aria'` | 'native' | How `required` is applied to the native input. - `'native'`: the native `required` attribute (browser validation bubble on submit). - `'aria'`: `aria-required="true"` only — no browser bubble; validate in your own code. The visual `*` after the label shows in both modes. |
|
|
21
|
+
| `helperText?` | `string` | — | Helper text displayed below the input — linked via `aria-describedby` |
|
|
22
|
+
| `error?` | `string` | — | Error message — replaces helperText, turns the input red, sets `aria-invalid="true"` and is linked via `aria-describedby`. |
|
|
23
|
+
| `invalid?` | `boolean` | false | Shows the error styling and sets `aria-invalid="true"` WITHOUT rendering a message. Use it when the message lives elsewhere, e.g. one shared error under a group of fields that each point to it with `aria-describedby`. `error` implies it. |
|
|
24
|
+
| `size?` | `'medium' \| 'large'` | — | Trigger size (Figma Size). Unset: responsive — medium below the system tablet breakpoint (768px), large from 768px. |
|
|
25
|
+
| `variant?` | `'default' \| 'search-box' \| 'leading-dropdown' \| 'trailing-dropdown' \| 'leading-text' \| 'trailing-button' \| 'input-button'` | 'default' | Structural variant of the input — determines layout and built-in adornments |
|
|
26
|
+
| `prefix?` | `ReactNode` | — | Content rendered before the input field (icon, text, dropdown) |
|
|
27
|
+
| `suffix?` | `ReactNode` | — | Content rendered after the input field (icon, button, text) |
|
|
28
|
+
| `prefixBordered?` | `boolean` | false | Whether the prefix has a visual separator border on its end edge |
|
|
29
|
+
| `suffixBordered?` | `boolean` | false | Whether the suffix has a visual separator border on its start edge |
|
|
30
|
+
| `clearable?` | `boolean` | false | Shows a clear button when the input has a value |
|
|
31
|
+
| `onClear?` | `() => void` | — | Callback fired when the clear button is clicked |
|
|
32
|
+
| `tags?` | `TagItem[]` | — | Tag chips rendered inside the input container (for multi-value variant) |
|
|
33
|
+
| `onTagRemove?` | `(id: string) => void` | — | Callback fired when a tag's remove button is clicked |
|
|
34
|
+
| `labels?` | `Partial<TextInputLabels>` | — | Localised built-in strings (clear button, tag remove buttons). |
|
|
35
|
+
| `fullWidth?` | `boolean` | false | Makes the input take the full width of its container |
|
|
36
|
+
| `leadingDropdownLabel?` | `string` | — | leading-dropdown: label text shown in the left dropdown panel |
|
|
37
|
+
| `onLeadingDropdownClick?` | `() => void` | — | leading-dropdown: callback when left dropdown panel is clicked |
|
|
38
|
+
| `leadingDropdownAriaLabel?` | `string` | — | leading-dropdown: accessible name for the dropdown panel button (e.g. "Country code, +966") |
|
|
39
|
+
| `trailingDropdownLabel?` | `string` | — | trailing-dropdown: label text shown in the right dropdown panel |
|
|
40
|
+
| `onTrailingDropdownClick?` | `() => void` | — | trailing-dropdown: callback when right dropdown panel is clicked |
|
|
41
|
+
| `trailingDropdownAriaLabel?` | `string` | — | trailing-dropdown: accessible name for the dropdown panel button (e.g. "Currency, SAR") |
|
|
42
|
+
| `leadingText?` | `string` | — | leading-text: static text shown in the left text panel (e.g. "http://") |
|
|
43
|
+
| `trailingButtonLabel?` | `string` | — | trailing-button: label for the attached right action button (e.g. "Copy") |
|
|
44
|
+
| `trailingButtonIcon?` | `ReactNode` | — | trailing-button: icon rendered inside the attached right action button |
|
|
45
|
+
| `onTrailingButtonClick?` | `() => void` | — | trailing-button: callback when the attached right action button is clicked |
|
|
46
|
+
| `trailingButtonAriaLabel?` | `string` | — | trailing-button: accessible name for the attached action button. Required when the button shows only `trailingButtonIcon` (no `trailingButtonLabel`). |
|
|
47
|
+
| `actionButtonLabel?` | `string` | — | input-button: label for the detached primary action button |
|
|
48
|
+
| `onActionButtonClick?` | `() => void` | — | input-button: callback when the detached primary action button is clicked |
|
|
49
|
+
|
|
50
|
+
Also accepts standard `<input>` HTML attributes (`className`, `style`, `onClick`, `aria-*`, …) — except: `size`, `prefix`, `dir`.
|
|
51
|
+
|
|
52
|
+
## Options (allowed values)
|
|
53
|
+
- `dir`: `'ltr'` \| `'rtl'` — Layout direction — applied to the root wrapper. Unset inherits from the page.
|
|
54
|
+
- `validationBehavior`: `'native'` \| `'aria'` — Native `required` handling — see `TextInputProps.validationBehavior`.
|
|
55
|
+
- `size`: `'medium'` \| `'large'` — Figma Size: Medium | Large only.
|
|
56
|
+
- `variant`: `'default'` \| `'search-box'` \| `'leading-dropdown'` \| `'trailing-dropdown'` \| `'leading-text'` \| `'trailing-button'` \| `'input-button'` — Structural variant of the input — maps to Figma component set "Type" property.
|
|
57
|
+
Named `variant` in code to avoid conflict with the native HTML `type` attribute.
|
|
58
|
+
- default: plain input with optional prefix/suffix slots
|
|
59
|
+
- search-box: leading search icon + trailing mic icon
|
|
60
|
+
- leading-dropdown: attached left panel with a selectable label + chevron
|
|
61
|
+
- trailing-dropdown: attached right panel with a selectable label + chevron
|
|
62
|
+
- leading-text: attached left static text panel (e.g. "http://")
|
|
63
|
+
- trailing-button: attached right action button (e.g. "Copy")
|
|
64
|
+
- input-button: standalone input + a separate detached primary action Button
|
|
65
|
+
|
|
66
|
+
## Deprecated props
|
|
67
|
+
Do not use in new code:
|
|
68
|
+
- `clearButtonLabel` — Accessible name for the icon-only clear button. Wins over `labels.clear`.
|
|
69
|
+
- `tagRemoveLabel` — Builds the accessible name of each tag's remove button. Wins over `labels.removeTag`.
|
|
70
|
+
|
|
71
|
+
## Accessibility
|
|
72
|
+
Built in (SDAIA review item A1) — verified by `tests/a11y/keyboard/text-fields.spec.ts` in the design system's test suite:
|
|
73
|
+
- The input is named by its visible `label` (`<label for>`).
|
|
74
|
+
- Error state sets `aria-invalid` and describes the field with the error text (`aria-describedby`).
|
|
75
|
+
- Helper text is linked with `aria-describedby`.
|
|
76
|
+
- Icon-only inline buttons (clear, show password) have accessible names.
|
|
77
|
+
|
|
78
|
+
You must:
|
|
79
|
+
- Always pass `label`.
|
|
80
|
+
|
|
81
|
+
- Built-in strings (button names, announcements) come from `labels`; pass translated strings for Arabic or other languages.
|
|
82
|
+
- Don't remove the focus ring or replace interactive elements with `div`s; keep the control keyboard-operable.
|
|
83
|
+
- For contrast, keyboard patterns and RTL rules, call `get_foundations` (`accessibility`, `rtl`).
|
|
84
|
+
|
|
85
|
+
## Design tokens used
|
|
86
|
+
Keep these consistent (resolve values with `get_tokens`):
|
|
87
|
+
- `var(--ds-color-)`
|
|
88
|
+
- `var(--ds-color-bg-muted)`
|
|
89
|
+
- `var(--ds-color-border-brand)`
|
|
90
|
+
- `var(--ds-color-border-default)`
|
|
91
|
+
- `var(--ds-color-border-disabled)`
|
|
92
|
+
- `var(--ds-color-border-muted)`
|
|
93
|
+
- `var(--ds-color-form-field-bg-default)`
|
|
94
|
+
- `var(--ds-color-form-field-border-danger)`
|
|
95
|
+
- `var(--ds-color-form-field-border-default)`
|
|
96
|
+
- `var(--ds-color-form-field-border-hovered)`
|
|
97
|
+
- `var(--ds-color-form-field-text-filled)`
|
|
98
|
+
- `var(--ds-color-form-field-text-helper)`
|
|
99
|
+
- `var(--ds-color-form-field-text-label)`
|
|
100
|
+
- `var(--ds-color-form-field-text-placeholder)`
|
|
101
|
+
- `var(--ds-color-icon-danger)`
|
|
102
|
+
- `var(--ds-color-icon-default)`
|
|
103
|
+
- `var(--ds-color-icon-default-500)`
|
|
104
|
+
- `var(--ds-color-icon-default-disabled)`
|
|
105
|
+
- `var(--ds-color-primitive-neutral-400)`
|
|
106
|
+
- `var(--ds-color-text-danger)`
|
|
107
|
+
- `var(--ds-color-text-default)`
|
|
108
|
+
- `var(--ds-color-text-disabled)`
|
|
109
|
+
- `var(--ds-color-text-paragraph-muted)`
|
|
110
|
+
- `var(--ds-motion-feedback-duration)`
|
|
111
|
+
- `var(--ds-motion-feedback-easing)`
|
|
112
|
+
- `var(--ds-radius-full)`
|
|
113
|
+
- `var(--ds-radius-m)`
|
|
114
|
+
- `var(--ds-radius-xs)`
|
|
115
|
+
- `var(--ds-radius-xxs)`
|
|
116
|
+
- `var(--ds-spacing-lg)`
|
|
117
|
+
- `var(--ds-spacing-md)`
|
|
118
|
+
- `var(--ds-spacing-sm)`
|
|
119
|
+
- `var(--ds-spacing-xl)`
|
|
120
|
+
- `var(--ds-spacing-xs)`
|
|
121
|
+
- `var(--ds-spacing-xxs)`
|
|
122
|
+
- `var(--ds-text-family-text)`
|
|
123
|
+
- `var(--ds-text-leading-line-heights-text-md)`
|
|
124
|
+
- `var(--ds-text-leading-line-heights-text-sm)`
|
|
125
|
+
|
|
126
|
+
## AI usage guidance
|
|
127
|
+
When generating UI:
|
|
128
|
+
- Install with `npx sdaia-ui@latest add text-input` (after `npx sdaia-ui@latest init`), then import `{ TextInput }` from `@/components/ui/TextInput`.
|
|
129
|
+
- NEVER run `npm install sdaia-ui` and NEVER `import` from the `sdaia-ui` package — it is a source-copying CLI, not a component library.
|
|
130
|
+
- Use only the documented option values listed under "Options".
|
|
131
|
+
- Pass icons via `<DgaIcon data={…} className="size-icon-sm" />` from `@platformscode/icons` only — see `get_foundations` (`icon-usage`). Never emoji, Lucide, or random icons (e.g. `pizza01Stroke` for dark mode).
|
|
132
|
+
- Pick one theme per screen: dark is `.theme-dark` (or `.dark`) on `<html>`; style surrounding layout with DS tokens (`get_tokens`), never hardcoded colors.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Time Input
|
|
2
|
+
|
|
3
|
+
## Metadata
|
|
4
|
+
- Component: Time Input
|
|
5
|
+
- Slug: `time-input`
|
|
6
|
+
- Category: Form
|
|
7
|
+
- Install: `npx sdaia-ui@latest add time-input`
|
|
8
|
+
- Import: `import { TimeInput } from '@/components/ui/TimeInput'`
|
|
9
|
+
- Installed files: `TimeInput.tsx`, `TimeInput.types.ts`, `TimeInput.variants.ts`, `index.ts`
|
|
10
|
+
- Docs: https://ds.nacew.com/components/time-input
|
|
11
|
+
|
|
12
|
+
> **Hard rule:** `sdaia-ui` is a CLI, not a runtime package — NEVER run `npm install sdaia-ui` and NEVER `import … from 'sdaia-ui'`. Run `npx sdaia-ui@latest init` once per project (Tailwind CSS v4, tokens, the IBM Plex Sans Arabic font, the `@/` alias on Vite, `cn`), then `npx sdaia-ui@latest add time-input`. It copies the source into your components folder (`components/ui/TimeInput/`, under `src/` when the project has one); import it as `@/components/ui/TimeInput`. The files are yours: prefer props and composition over editing them. `npx sdaia-ui@latest update` never overwrites a file you changed: it keeps it and says it has updates; `diff` shows them and `update --force` takes them.
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
| Prop | Type | Default | Description |
|
|
16
|
+
| --- | --- | --- | --- |
|
|
17
|
+
| `value?` | `TimeValue \| null` | — | Selected time (controlled). The field shows it formatted for `format` (`09:30 AM` / `14:30`). `null` = empty. While the user types, the text is kept as typed and `onChange` reports the parsed time. |
|
|
18
|
+
| `defaultValue?` | `TimeValue \| null` | null | Initial time (uncontrolled). |
|
|
19
|
+
| `defaultInputValue?` | `string` | — | Initial field text, used instead of `value` / `defaultValue` on the first render — e.g. to restore a draft the user typed (which may not be a valid time yet). |
|
|
20
|
+
| `onChange?` | `(time: TimeValue \| null, text: string) => void` | — | Fired when the user types or applies a time from the picker. `time` is the parsed value — `null` when the field is empty or the text is not a valid time (e.g. `25:00`), so you can show an error — and `text` is the field's text. |
|
|
21
|
+
| `format?` | `TimeFormat` | '12-hour' | Clock format of the field text and of the picker (Time Picker `Format`). |
|
|
22
|
+
| `minuteStep?` | `number` | 5 | Minutes between options in the picker's minute column. |
|
|
23
|
+
| `pickerTitle?` | `string` | — | Title in the picker header (Time Picker `Title`). Omit to hide it. |
|
|
24
|
+
| `pickerFooter?` | `boolean` | true | Show the picker's Cancel / Apply footer (Time Picker `Footer`). Without it, picking applies at once. |
|
|
25
|
+
| `open?` | `boolean` | — | Whether the picker is open (controlled). |
|
|
26
|
+
| `defaultOpen?` | `boolean` | false | Initial open state (uncontrolled). |
|
|
27
|
+
| `onOpenChange?` | `(open: boolean) => void` | — | Fired when the picker opens or closes. |
|
|
28
|
+
| `labels?` | `Partial<TimeInputLabels>` | — | Localised built-in strings (picker columns, AM / PM, buttons). |
|
|
29
|
+
|
|
30
|
+
## Accessibility
|
|
31
|
+
- Built-in strings (button names, announcements) come from `labels`; pass translated strings for Arabic or other languages.
|
|
32
|
+
- Don't remove the focus ring or replace interactive elements with `div`s; keep the control keyboard-operable.
|
|
33
|
+
- For contrast, keyboard patterns and RTL rules, call `get_foundations` (`accessibility`, `rtl`).
|
|
34
|
+
|
|
35
|
+
## Design tokens used
|
|
36
|
+
Keep these consistent (resolve values with `get_tokens`):
|
|
37
|
+
- `var(--ds-spacing-xl)`
|
|
38
|
+
- `var(--ds-spacing-xs)`
|
|
39
|
+
|
|
40
|
+
## AI usage guidance
|
|
41
|
+
When generating UI:
|
|
42
|
+
- Install with `npx sdaia-ui@latest add time-input` (after `npx sdaia-ui@latest init`), then import `{ TimeInput }` from `@/components/ui/TimeInput`.
|
|
43
|
+
- NEVER run `npm install sdaia-ui` and NEVER `import` from the `sdaia-ui` package — it is a source-copying CLI, not a component library.
|
|
44
|
+
- Pick one theme per screen: dark is `.theme-dark` (or `.dark`) on `<html>`; style surrounding layout with DS tokens (`get_tokens`), never hardcoded colors.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Time Picker
|
|
2
|
+
|
|
3
|
+
## Metadata
|
|
4
|
+
- Component: Time Picker
|
|
5
|
+
- Slug: `time-picker`
|
|
6
|
+
- Category: Form
|
|
7
|
+
- Install: `npx sdaia-ui@latest add time-picker`
|
|
8
|
+
- Import: `import { TimePicker } from '@/components/ui/TimePicker'`
|
|
9
|
+
- Installed files: `TimePicker.tsx`, `TimePicker.types.ts`, `TimePicker.variants.ts`, `index.ts`, `time.ts`
|
|
10
|
+
- Docs: https://ds.nacew.com/components/time-picker
|
|
11
|
+
|
|
12
|
+
> **Hard rule:** `sdaia-ui` is a CLI, not a runtime package — NEVER run `npm install sdaia-ui` and NEVER `import … from 'sdaia-ui'`. Run `npx sdaia-ui@latest init` once per project (Tailwind CSS v4, tokens, the IBM Plex Sans Arabic font, the `@/` alias on Vite, `cn`), then `npx sdaia-ui@latest add time-picker`. It copies the source into your components folder (`components/ui/TimePicker/`, under `src/` when the project has one); import it as `@/components/ui/TimePicker`. The files are yours: prefer props and composition over editing them. `npx sdaia-ui@latest update` never overwrites a file you changed: it keeps it and says it has updates; `diff` shows them and `update --force` takes them.
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
| Prop | Type | Default | Description |
|
|
16
|
+
| --- | --- | --- | --- |
|
|
17
|
+
| `dir?` | `'ltr' \| 'rtl'` | — | Layout direction — applied to the root. The columns mirror in RTL; digits stay Latin. Unset inherits. |
|
|
18
|
+
| `format?` | `'12-hour' \| '24-hour'` | '12-hour' | Clock format (Figma `Format`). |
|
|
19
|
+
| `value?` | `TimeValue \| null` | — | Selected time (controlled). `null` means nothing is selected yet. |
|
|
20
|
+
| `defaultValue?` | `TimeValue \| null` | null | Initial selected time (uncontrolled). |
|
|
21
|
+
| `onChange?` | `(value: TimeValue) => void` | — | Fired on every selection in a column, with the complete time. |
|
|
22
|
+
| `onApply?` | `(value: TimeValue) => void` | — | Fired by the Apply button and by Enter on an option, with the selected time. |
|
|
23
|
+
| `onCancel?` | `() => void` | — | Fired by the Cancel button and by Escape inside the picker. In a popup, close it here and move focus back to the field that opened it. |
|
|
24
|
+
| `title?` | `string` | — | Header title (Figma `Title` + `Title EN/AR`), e.g. "Select time". Omit to hide it in tight layouts; the selected time stays in the header. |
|
|
25
|
+
| `footer?` | `boolean` | true | Show the Cancel / Apply footer (Figma `Footer`). Without it, every selection applies at once through `onChange`. |
|
|
26
|
+
| `minuteStep?` | `number` | 5 | Minutes between options in the minute column. |
|
|
27
|
+
| `autoFocus?` | `boolean` | false | Move focus to the selected hour when the picker mounts (e.g. opened from the keyboard). |
|
|
28
|
+
| `labels?` | `Partial<TimePickerLabels>` | — | Localised built-in strings. |
|
|
29
|
+
|
|
30
|
+
Also accepts standard `<div>` HTML attributes (`className`, `style`, `onClick`, `aria-*`, …) — except: `onChange`, `defaultValue`, `title`, `dir`.
|
|
31
|
+
|
|
32
|
+
## Options (allowed values)
|
|
33
|
+
- `dir`: `'ltr'` \| `'rtl'` — Layout direction — applied to the root. The columns mirror in RTL; digits stay Latin. Unset inherits.
|
|
34
|
+
- `format`: `'12-hour'` \| `'24-hour'` — Clock format — Figma `Format`.
|
|
35
|
+
- `'12-hour'`: hour (01–12), minute and AM / PM columns.
|
|
36
|
+
- `'24-hour'`: hour (00–23) and minute columns. Use it on operational,
|
|
37
|
+
audit and reporting screens.
|
|
38
|
+
|
|
39
|
+
## Accessibility
|
|
40
|
+
- Built-in strings (button names, announcements) come from `labels`; pass translated strings for Arabic or other languages.
|
|
41
|
+
- Don't remove the focus ring or replace interactive elements with `div`s; keep the control keyboard-operable.
|
|
42
|
+
- For contrast, keyboard patterns and RTL rules, call `get_foundations` (`accessibility`, `rtl`).
|
|
43
|
+
|
|
44
|
+
## Design tokens used
|
|
45
|
+
Keep these consistent (resolve values with `get_tokens`):
|
|
46
|
+
- `var(--ds-color-)`
|
|
47
|
+
- `var(--ds-color-bg-brand)`
|
|
48
|
+
- `var(--ds-color-bg-raised)`
|
|
49
|
+
- `var(--ds-color-border-default)`
|
|
50
|
+
- `var(--ds-color-border-focus)`
|
|
51
|
+
- `var(--ds-color-border-muted)`
|
|
52
|
+
- `var(--ds-color-form-option-bg-hover)`
|
|
53
|
+
- `var(--ds-color-text-brand)`
|
|
54
|
+
- `var(--ds-color-text-default)`
|
|
55
|
+
- `var(--ds-color-text-on-color)`
|
|
56
|
+
- `var(--ds-motion-feedback-duration)`
|
|
57
|
+
- `var(--ds-motion-feedback-easing)`
|
|
58
|
+
- `var(--ds-radius-m)`
|
|
59
|
+
- `var(--ds-radius-xs)`
|
|
60
|
+
- `var(--ds-spacing-lg)`
|
|
61
|
+
- `var(--ds-spacing-md)`
|
|
62
|
+
- `var(--ds-spacing-xl)`
|
|
63
|
+
- `var(--ds-spacing-xs)`
|
|
64
|
+
- `var(--ds-text-family-text)`
|
|
65
|
+
- `var(--ds-text-leading-line-heights-text-md)`
|
|
66
|
+
- `var(--ds-text-leading-line-heights-text-sm)`
|
|
67
|
+
|
|
68
|
+
## AI usage guidance
|
|
69
|
+
When generating UI:
|
|
70
|
+
- Install with `npx sdaia-ui@latest add time-picker` (after `npx sdaia-ui@latest init`), then import `{ TimePicker }` from `@/components/ui/TimePicker`.
|
|
71
|
+
- NEVER run `npm install sdaia-ui` and NEVER `import` from the `sdaia-ui` package — it is a source-copying CLI, not a component library.
|
|
72
|
+
- Use only the documented option values listed under "Options".
|
|
73
|
+
- Pick one theme per screen: dark is `.theme-dark` (or `.dark`) on `<html>`; style surrounding layout with DS tokens (`get_tokens`), never hardcoded colors.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# SDAIA Accessibility Guide
|
|
2
|
+
|
|
3
|
+
Mirrors the docs site's Accessibility page (https://ds.nacew.com/foundations/accessibility). SDAIA UI targets **WCAG 2.1 level AA**. The components handle roles, keyboard support, focus and labels; a page is only accessible when its content and the way components are combined are accessible too.
|
|
4
|
+
|
|
5
|
+
Everything under "What the components do for you" is checked by the design system's own test suite: every component demo is scanned with axe in the light and dark themes and in right-to-left, and keyboard tests (`tests/a11y/keyboard/*.spec.ts`) cover Select, Modal, Date Picker, Switch and the text fields. `get_component_docs` shows the verified behaviour of each of these components and the spec that checks it.
|
|
6
|
+
|
|
7
|
+
## What the components do for you
|
|
8
|
+
|
|
9
|
+
| Component | Built-in behaviour |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Text Input, Text Area | The label is linked to the field. Helper and error text are linked with `aria-describedby`. Errors set `aria-invalid` and are announced. The required asterisk is hidden from screen readers; the field itself is marked required. |
|
|
12
|
+
| Select | WAI-ARIA select-only combobox with a listbox. Arrow keys, Home, End, Page Up and Page Down move through options; Enter and Space select; Escape closes without changing the value; typing jumps to a matching option. In multi-select, each chip has a named remove button. |
|
|
13
|
+
| Modal | `role="dialog"` with `aria-modal`, named by its `title`. Focus moves into the dialog, Tab and Shift+Tab stay inside it, Escape closes it (`closeOnEscape`, default `true`) and focus returns to the element that opened it. The page behind does not scroll. |
|
|
14
|
+
| Date Picker | The month is a grid (`grid` → `row` → `gridcell`) and a single Tab stop. Arrow keys move by day and week, Home and End go to the start and end of the week, Page Up and Page Down change the month (with Shift, the year). Today is marked with `aria-current`, and month changes are announced. Arabic locale gives Arabic month names and built-in strings. |
|
|
15
|
+
| Checkbox, Radio Button, Switch | Native inputs, so they work with the keyboard and with forms. Switch uses `role="switch"` and its off track meets 3:1 contrast. A click on the box, circle or track works even without a visible label. |
|
|
16
|
+
| Progress Bar, Progress Circle, File Uploader | `role="progressbar"` with the current value. File Uploader names each progress bar with the file name and status. |
|
|
17
|
+
| Chip, Filtration, Help Icon | No nested interactive controls. The help trigger has a name (default "Help") and its tooltip closes with Escape. |
|
|
18
|
+
| DgaIcon | Hidden from screen readers unless you give it a `title`. |
|
|
19
|
+
|
|
20
|
+
## What you still need to do
|
|
21
|
+
|
|
22
|
+
- Give every field a visible `label`. A placeholder is not a label.
|
|
23
|
+
- Give icon-only buttons an `aria-label`. Button does not add one for you.
|
|
24
|
+
- Give Progress Bar and Progress Circle a name with `aria-label` or `aria-labelledby` when there is no visible label next to them (Progress Bar's `label` prop only sets where the percentage is shown).
|
|
25
|
+
- Give every Modal a `title`, even a short one, so the dialog has a name.
|
|
26
|
+
- Use one `h1` per page and keep heading levels in order.
|
|
27
|
+
- Write meaningful link and button text, and alternative text for images.
|
|
28
|
+
- Pass `labels` to translate the built-in names of buttons and regions. Many components have a `labels` prop (for example Select, Date Picker, File Uploader, Table, the media players and the charts). Without it, those names are in English (Date Picker and Pagination switch to Arabic by themselves for an Arabic locale).
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<TextInput
|
|
32
|
+
label="National ID"
|
|
33
|
+
helperText="10 digits, starting with 1 or 2"
|
|
34
|
+
error={idError} // linked with aria-describedby, sets aria-invalid
|
|
35
|
+
required // native required by default
|
|
36
|
+
validationBehavior="aria" // or: announce required without blocking submit
|
|
37
|
+
/>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Colour contrast
|
|
41
|
+
|
|
42
|
+
| Content | Minimum contrast |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| Body text and labels | 4.5:1 |
|
|
45
|
+
| Large text (24px, or 18.66px bold, and up) | 3:1 |
|
|
46
|
+
| Icons, input borders, focus rings and other UI parts you need to see | 3:1 |
|
|
47
|
+
| Disabled controls and decorative elements | No minimum, but don't hide information in them |
|
|
48
|
+
|
|
49
|
+
- Use the semantic colour tokens (`text-*`, `bg-*`, `border-*`; `get_tokens`). They are tuned to meet these ratios in the light and dark themes and in every brand.
|
|
50
|
+
- Never hardcode hex colours; custom values bypass the tested pairings.
|
|
51
|
+
- Don't use colour alone to show a state. Errors also have an icon and a message; selected items also have a check or a weight change.
|
|
52
|
+
|
|
53
|
+
## Keyboard
|
|
54
|
+
|
|
55
|
+
- Everything you can do with a mouse must work with a keyboard: Tab and Shift+Tab to move, Enter or Space to activate, Escape to close.
|
|
56
|
+
- Keep the DOM order the same as the visual order, so Tab follows the reading order in both directions.
|
|
57
|
+
- Don't set a positive `tabIndex`. Use `tabIndex={0}` only on custom controls that need it.
|
|
58
|
+
- Inside composite widgets (Select, Date Picker, Tabs, Radio groups) arrow keys move within the widget and Tab leaves it.
|
|
59
|
+
- In right-to-left layouts, Left and Right arrows follow the reading direction.
|
|
60
|
+
|
|
61
|
+
## Focus
|
|
62
|
+
|
|
63
|
+
- Components show a 2px focus ring in the brand border colour, offset from the control, for keyboard focus only (`:focus-visible`). For custom controls use `--ds-color-border-focus`.
|
|
64
|
+
- Never remove the focus ring without a visible replacement.
|
|
65
|
+
- After an action, move focus somewhere sensible: into a dialog that opens, back to the trigger when it closes, to the errors after a failed submit (render Error Summary with `autoFocus`; each of its links moves focus to its field).
|
|
66
|
+
|
|
67
|
+
## Screen readers
|
|
68
|
+
|
|
69
|
+
- Use native elements first: `<button>` for actions, `<a href>` for navigation, `<input>` for data. Never a clickable `<div>`.
|
|
70
|
+
- Error messages are announced when they appear. Don't add another live region for the same message.
|
|
71
|
+
- Hide purely decorative images and icons; name everything else.
|
|
72
|
+
- Set the page language: `lang="ar"` for Arabic pages, `lang="en"` for English.
|
|
73
|
+
|
|
74
|
+
## Motion
|
|
75
|
+
|
|
76
|
+
Animated components respect `prefers-reduced-motion`. In your own code wrap animations in `motion-safe:` or remove them with `motion-reduce:`; don't auto-play movement longer than 5 seconds without a pause control; never flash more than three times a second.
|
|
77
|
+
|
|
78
|
+
## Themes and direction
|
|
79
|
+
|
|
80
|
+
Accessibility must hold in every combination. Switch them on `<html>`: `class="theme-dark"` for dark, `dir="rtl" lang="ar"` for Arabic (set both: `dir` mirrors the layout, `lang` gives screen readers the Arabic voice). See topics `theme` and `rtl`.
|
|
81
|
+
|
|
82
|
+
## Zoom and screen size
|
|
83
|
+
|
|
84
|
+
- Pages must work at 200% browser zoom and at a 320px-wide viewport (WCAG reflow) without losing content or scrolling in two directions.
|
|
85
|
+
- Touch targets at least 24 × 24px, and 44 × 44px for the main actions on phones.
|
|
86
|
+
- See topic `responsive` for the breakpoints.
|
|
87
|
+
|
|
88
|
+
## Testing checklist
|
|
89
|
+
|
|
90
|
+
- [ ] Tab through the page: every control is reachable, in order, with a visible focus ring.
|
|
91
|
+
- [ ] Every field, button and icon-only control has a name.
|
|
92
|
+
- [ ] Errors are announced and linked to their field.
|
|
93
|
+
- [ ] axe (or Lighthouse) shows no violations.
|
|
94
|
+
- [ ] Text and UI contrast pass in the light and dark themes.
|
|
95
|
+
- [ ] The page works in Arabic with `dir="rtl"` and `lang="ar"`.
|
|
96
|
+
- [ ] The page works at 200% zoom and with reduced motion on.
|
|
97
|
+
- [ ] Checked with a screen reader (VoiceOver, NVDA or TalkBack).
|