@pastweb/components-core 2.0.0 → 2.2.0
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/dist/Accordion/README.md +251 -0
- package/dist/Button/README.md +143 -0
- package/dist/Buttons/README.md +108 -0
- package/dist/Carousel/README.md +204 -0
- package/dist/Checkbox/README.md +140 -0
- package/dist/DateTimePicker/README.md +125 -0
- package/dist/DropDown/README.md +237 -0
- package/dist/FileUploader/README.md +224 -0
- package/dist/Icon/README.md +103 -0
- package/dist/Input/README.md +212 -0
- package/dist/Link/README.md +108 -0
- package/dist/Notification/README.md +141 -0
- package/dist/Pagination/README.md +147 -0
- package/dist/Panel/README.md +158 -0
- package/dist/Placeholder/README.md +124 -0
- package/dist/ProgressBar/README.md +137 -0
- package/dist/Radio/README.md +144 -0
- package/dist/RangeSlider/README.md +120 -0
- package/dist/ScrollArea/README.md +105 -0
- package/dist/Select/README.md +243 -0
- package/dist/SheetController/README.md +143 -0
- package/dist/Spinner/README.md +80 -0
- package/dist/SplitLayout/README.md +132 -0
- package/dist/Stepper/README.md +146 -0
- package/dist/Table/README.md +76 -0
- package/dist/Tabs/README.md +352 -0
- package/dist/Tabs/utils/index.d.cts +2 -1
- package/dist/Tag/README.md +90 -0
- package/dist/TaskBar/README.md +105 -0
- package/dist/TextArea/README.md +141 -0
- package/dist/ToastController/README.md +119 -0
- package/dist/Toggle/README.md +109 -0
- package/dist/Tooltip/README.md +128 -0
- package/dist/Walktour/README.md +188 -0
- package/dist/WindowController/README.md +190 -0
- package/package.json +5 -2
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Panel
|
|
2
|
+
|
|
3
|
+
Panel groups related content in a bordered, optionally rounded article with a
|
|
4
|
+
semantic heading, close action, and footer. Its rendering contract targets
|
|
5
|
+
WCAG 2.2 Level AA. It is a content grouping container, not a confirmation or
|
|
6
|
+
interruption panel.
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
Use Panel to visually group a self-contained section of page content. Keep
|
|
11
|
+
heading levels consistent with the surrounding document. Do not use it as a
|
|
12
|
+
modal dialog without adding the separate dialog focus and interaction contract.
|
|
13
|
+
Do not use it as a GOV.UK confirmation or interruption panel.
|
|
14
|
+
|
|
15
|
+
## Props
|
|
16
|
+
|
|
17
|
+
| PropName | Type | Required | Default | Description |
|
|
18
|
+
|---|---|---:|---:|---|
|
|
19
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component, part, and state classes. |
|
|
20
|
+
| `ariaLabel` | `string` | no | `""` | Names the article when no title is supplied. Pass an empty string to omit the name. |
|
|
21
|
+
| `border` | `boolean` | no | `true` | Applies the `has-border` class. The public prop name remains `border`. |
|
|
22
|
+
| `borderRadius` | `boolean` | no | `true` | Applies the `has-border-radius` class. The public prop name remains `borderRadius`. |
|
|
23
|
+
| `className` | `string` | no | `""` | Adds classes to the root article. |
|
|
24
|
+
| `closeButton` | `boolean` | no | `true` | Displays the native close button. |
|
|
25
|
+
| `closeLabel` | `string` | no | `"Close panel"` | Names the close button. |
|
|
26
|
+
| `headingLevel` | `2 \| 3 \| 4 \| 5 \| 6` | no | `2` | Selects the native title heading level. |
|
|
27
|
+
| `id` | `string` | no | generated | Supplies the stable panel ID and title-ID base. Generated IDs use the `panel` prefix. Explicit IDs are stored as `_${id}`. |
|
|
28
|
+
| `title` | `string` | no | `""` | Supplies the default heading content. |
|
|
29
|
+
| `contentPadding` | `number \| string` | no | `0` | Sets inline padding on the content area. |
|
|
30
|
+
| `onClose` | `() => void` | no | noop | Reports close intent. |
|
|
31
|
+
| `rtl` | `boolean` | no | - | Reverses header content order. |
|
|
32
|
+
|
|
33
|
+
## Mediator state
|
|
34
|
+
|
|
35
|
+
| Property | Type | Description |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `ariaLabel` | `string \| undefined` | Normalized accessible name when no title is present. Empty labels are omitted. |
|
|
38
|
+
| `heading` | `PanelHeading` | Native title tag from `headingLevel`, such as `h2`. |
|
|
39
|
+
| `id` | `string` | Article ID from an explicit `id` or a generated `panel` prefix. |
|
|
40
|
+
| `titleId` | `string \| undefined` | Title relationship ID `title${id}` when heading content is present; otherwise omitted. |
|
|
41
|
+
|
|
42
|
+
## Slots
|
|
43
|
+
|
|
44
|
+
| SlotName | Description | Default content |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| default | Supplies panel body content. | Empty. |
|
|
47
|
+
| `header` | Replaces title and close content inside the semantic header. | Heading and optional close button. |
|
|
48
|
+
| `footer` | Supplies content wrapped in the semantic footer. | Empty. |
|
|
49
|
+
|
|
50
|
+
## CSS classes
|
|
51
|
+
|
|
52
|
+
| Class | Applied when | Notes |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `Panel` | Always | Root component class. |
|
|
55
|
+
| `has-border` | `border` is `true` | Optional article border. |
|
|
56
|
+
| `has-border-radius` | `borderRadius` is `true` | Optional article corner radius. |
|
|
57
|
+
|
|
58
|
+
## CSS Variables
|
|
59
|
+
|
|
60
|
+
| Variable | Part | State | CSS property | Default | Description | Platforms |
|
|
61
|
+
|---|---|---|---|---|---|---|
|
|
62
|
+
| `--pw_Panel_root_default_background-color` | `root` | `default` | `background-color` | `var(--pw_background-color)` | Panel background. | Web, Capacitor, NativeScript |
|
|
63
|
+
| `--pw_Panel_root_default_color` | `root` | `default` | `color` | `var(--pw_text_color)` | Panel foreground. | Web, Capacitor, NativeScript |
|
|
64
|
+
| `--pw_Panel_root_default_font-size` | `root` | `default` | `font-size` | `var(--pw_font-size)` | Body text size. | Web, Capacitor, NativeScript |
|
|
65
|
+
| `--pw_Panel_root_default_font-weight` | `root` | `default` | `font-weight` | `var(--pw_font-weight)` | Body text weight. | Web, Capacitor, NativeScript |
|
|
66
|
+
| `--pw_Panel_root_default_line-height` | `root` | `default` | `line-height` | `var(--pw_line-height)` | Body line height. | Web, Capacitor, NativeScript |
|
|
67
|
+
| `--pw_Panel_root_default_border-color` | `root` | `default` | `border-color` | `var(--pw_border-color)` | Optional border colour. | Web, Capacitor, NativeScript |
|
|
68
|
+
| `--pw_Panel_root_default_border-width` | `root` | `default` | `border-width` | `var(--pw_border-width)` | Optional border width. | Web, Capacitor, NativeScript |
|
|
69
|
+
| `--pw_Panel_root_default_border-style` | `root` | `default` | `border-style` | `var(--pw_border-style)` | Optional border style. | Web, Capacitor, NativeScript |
|
|
70
|
+
| `--pw_Panel_root_default_border-radius` | `root` | `default` | `border-radius` | `var(--pw_border-radius)` | Optional corner radius. | Web, Capacitor, NativeScript |
|
|
71
|
+
| `--pw_Panel_header_default_padding` | `header` | `default` | `padding` | `var(--pw_padding)` | Header spacing. | Web, Capacitor, NativeScript |
|
|
72
|
+
| `--pw_Panel_header_default_background-color` | `header` | `default` | `background-color` | `var(--pw_control_background-color)` | Header background. | Web, Capacitor, NativeScript |
|
|
73
|
+
| `--pw_Panel_header_default_border-bottom` | `header` | `default` | `border-bottom` | shared border | Header separator. | Web, Capacitor, NativeScript |
|
|
74
|
+
| `--pw_Panel_header_default_color` | `header` | `default` | `color` | `var(--pw_text_strong_color)` | Header foreground. | Web, Capacitor, NativeScript |
|
|
75
|
+
| `--pw_Panel_header_default_font-size` | `header` | `default` | `font-size` | `1em` | Heading text size. | Web, Capacitor, NativeScript |
|
|
76
|
+
| `--pw_Panel_header_default_font-weight` | `header` | `default` | `font-weight` | `var(--pw_bold_font-weight)` | Heading weight. | Web, Capacitor, NativeScript |
|
|
77
|
+
| `--pw_Panel_header_default_line-height` | `header` | `default` | `line-height` | `var(--pw_line-height)` | Heading line height. | Web, Capacitor, NativeScript |
|
|
78
|
+
| `--pw_Panel_close-button_default_background-color` | `close-button` | `default` | `background-color` | header background | Close-button background. | Web, Capacitor, NativeScript |
|
|
79
|
+
| `--pw_Panel_close-button_hover_background-color` | `close-button` | `hover` | `background-color` | header colour | Hover background. | Web, Capacitor |
|
|
80
|
+
| `--pw_Panel_close-button_default_min-width` | `close-button` | `default` | `min-width` | `1.563em` | Close-button width, matching Notification. | Web, Capacitor, NativeScript |
|
|
81
|
+
| `--pw_Panel_close-button_default_height` | `close-button` | `default` | `height` | `1.563em` | Close-button height, matching Notification. | Web, Capacitor, NativeScript |
|
|
82
|
+
| `--pw_Panel_close-button_default_transition-duration` | `close-button` | `default` | `transition-duration` | `0.5s` | Visual transition duration. | Web, Capacitor; NativeScript adapter |
|
|
83
|
+
| `--pw_Panel_close-bar_default_background-color` | `close-bar` | `default` | `background-color` | header colour | Close glyph colour. | Web, Capacitor, NativeScript |
|
|
84
|
+
| `--pw_Panel_close-bar_hover_background-color` | `close-bar` | `hover` | `background-color` | close-button background | Hover glyph colour. | Web, Capacitor |
|
|
85
|
+
| `--pw_Panel_footer_default_padding` | `footer` | `default` | `padding` | header padding | Footer spacing. | Web, Capacitor, NativeScript |
|
|
86
|
+
| `--pw_Panel_footer_default_background-color` | `footer` | `default` | `background-color` | header background | Footer background. | Web, Capacitor, NativeScript |
|
|
87
|
+
| `--pw_Panel_footer_default_border-top` | `footer` | `default` | `border-top` | header separator | Footer separator. | Web, Capacitor, NativeScript |
|
|
88
|
+
|
|
89
|
+
```xts
|
|
90
|
+
import { useBeforeUnmount, useMediator, withDefaultProps } from '@pastweb/x';
|
|
91
|
+
import { panelMediator } from '@pastweb/components-core/Panel';
|
|
92
|
+
import { DEFAULT_PROPS } from './constants';
|
|
93
|
+
|
|
94
|
+
export function Panel(props: PanelProps) {
|
|
95
|
+
const p = withDefaultProps<PanelDefaultProps>(props, DEFAULT_PROPS);
|
|
96
|
+
const m = useMediator<PanelMediator>(panelMediator, p);
|
|
97
|
+
const s = m.state;
|
|
98
|
+
const Heading = s.heading;
|
|
99
|
+
|
|
100
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<article
|
|
104
|
+
id={s.id}
|
|
105
|
+
class={p.cls('Panel', {
|
|
106
|
+
'has-border': p.border,
|
|
107
|
+
'has-border-radius': p.borderRadius,
|
|
108
|
+
}, p.className)}
|
|
109
|
+
aria-label={s.ariaLabel}
|
|
110
|
+
aria-labelledby={s.titleId}
|
|
111
|
+
>
|
|
112
|
+
<header class={p.cls('header', { rtl: p.rtl })}>
|
|
113
|
+
<slot name="header">
|
|
114
|
+
<Heading #if={p.title} id={s.titleId} class={p.cls('title')}>{p.title}</Heading>
|
|
115
|
+
<button #if={p.closeButton} type="button" class={p.cls('closeButton')} @click={m.onClose} aria-label={p.closeLabel}>
|
|
116
|
+
<span class={p.cls('closeBar')} aria-hidden="true" />
|
|
117
|
+
<span class={p.cls('closeBar')} aria-hidden="true" />
|
|
118
|
+
</button>
|
|
119
|
+
</slot>
|
|
120
|
+
</header>
|
|
121
|
+
<div class={p.cls('content')} #style={p.contentPadding ? { padding: p.contentPadding } : {}}>
|
|
122
|
+
<slot />
|
|
123
|
+
</div>
|
|
124
|
+
<slot name="footer" map={content => <footer class={p.cls('footer')}>{content}</footer>} />
|
|
125
|
+
</article>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Keyboard interaction
|
|
131
|
+
|
|
132
|
+
- The close action is a native button and is operable with `Enter` or `Space`.
|
|
133
|
+
- Body content is not interactive unless projected content supplies its own
|
|
134
|
+
controls.
|
|
135
|
+
|
|
136
|
+
## Accessibility notes
|
|
137
|
+
|
|
138
|
+
- The default title is a native heading connected to the article through
|
|
139
|
+
`aria-labelledby` and the `title${id}` relationship ID.
|
|
140
|
+
- Without a title, `ariaLabel` can provide the article's accessible name. The
|
|
141
|
+
default is an empty string, which omits the name.
|
|
142
|
+
- The close action is a native button with a configurable name. Decorative close
|
|
143
|
+
bars are excluded from the accessibility tree.
|
|
144
|
+
- A custom header must preserve an appropriate heading and close-action name.
|
|
145
|
+
- Shared web styles match the Notification close control size, with visible
|
|
146
|
+
keyboard focus, forced-colours treatment, and reduced-motion behavior.
|
|
147
|
+
|
|
148
|
+
## Known limitations
|
|
149
|
+
|
|
150
|
+
- Automated accessibility checks do not by themselves establish WCAG
|
|
151
|
+
conformance.
|
|
152
|
+
|
|
153
|
+
## Standards
|
|
154
|
+
|
|
155
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
156
|
+
- WAI-ARIA landmark regions: https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/
|
|
157
|
+
- GOV.UK Panel guidance: https://design-system.service.gov.uk/components/panel/
|
|
158
|
+
- GOV.UK headings guidance: https://design-system.service.gov.uk/styles/headings/
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Placeholder
|
|
2
|
+
|
|
3
|
+
Placeholder renders a non-interactive shape that stands in for content that has
|
|
4
|
+
not loaded yet. Its rendering contract targets WCAG 2.2 Level AA.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
Use Placeholder to reserve layout while content loads. Keep placeholders
|
|
9
|
+
decorative when several shapes compose one skeleton, and announce loading once
|
|
10
|
+
on a parent region or with a single non-decorative Placeholder. Do not rely on
|
|
11
|
+
the pulse animation as the only loading signal. Use Spinner for a compact
|
|
12
|
+
indeterminate status, and ProgressBar when completion can be calculated.
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
|
|
16
|
+
| PropName | Type | Required | Default | Description |
|
|
17
|
+
|---|---|---:|---:|---|
|
|
18
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component and state classes. |
|
|
19
|
+
| `ariaLabel` | `string` | no | `"Loading"` | Names the status when the placeholder is not decorative. Pass an empty string to omit the name. |
|
|
20
|
+
| `className` | `string` | no | `""` | Adds classes to the root, including shape utilities. |
|
|
21
|
+
| `decorative` | `boolean` | no | `true` | Removes status semantics, hides the shape from the accessibility tree, and applies `is-decorative`. |
|
|
22
|
+
|
|
23
|
+
## Mediator state
|
|
24
|
+
|
|
25
|
+
| Property | Type | Description |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `ariaHidden` | `true \| undefined` | Is `true` when the placeholder is decorative; otherwise omitted. Renderers use this value directly for `aria-hidden`. |
|
|
28
|
+
| `ariaLabel` | `string \| undefined` | Normalized status name. Decorative and empty labels are omitted. |
|
|
29
|
+
| `ariaLive` | `'polite' \| undefined` | Is `polite` unless decorative. |
|
|
30
|
+
| `role` | `'status' \| undefined` | Is `status` unless decorative. |
|
|
31
|
+
|
|
32
|
+
## Utility classes
|
|
33
|
+
|
|
34
|
+
Apply these classes through `className`. The default shape is a full-width bar
|
|
35
|
+
at Button height using the same `--pw_border-radius` token as Button.
|
|
36
|
+
`is-circle`, `is-square`, and `is-block` replace that size. `is-rounded` and
|
|
37
|
+
`is-pill` change the corner radius and can combine with the default, square, or
|
|
38
|
+
block shapes. A circle keeps a 50% radius.
|
|
39
|
+
|
|
40
|
+
| Class | Description |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `is-circle` | Equal sides and a circular radius, for avatars and round media. |
|
|
43
|
+
| `is-square` | Equal sides with the default corner radius. |
|
|
44
|
+
| `is-block` | A taller full-width rectangle, for images and cards. |
|
|
45
|
+
| `is-rounded` | Uses the rounded corner-radius token. |
|
|
46
|
+
| `is-pill` | Uses a fully rounded capsule radius. |
|
|
47
|
+
|
|
48
|
+
## CSS Variables
|
|
49
|
+
|
|
50
|
+
| Variable | Part | State | CSS property | Default | Description | Platforms |
|
|
51
|
+
|---|---|---|---|---|---|---|
|
|
52
|
+
| `--pw_Placeholder_root_default_color` | `root` | `default` | `color` | `var(--pw_text_color)` | Colour used by the `currentcolor` fill. | Web, Capacitor, NativeScript |
|
|
53
|
+
| `--pw_Placeholder_root_default_background-color` | `root` | `default` | `background-color` | `currentcolor` | Placeholder fill. | Web, Capacitor, NativeScript |
|
|
54
|
+
| `--pw_Placeholder_root_default_opacity` | `root` | `default` | `opacity` | `0.5` | Resting fill opacity. | Web, Capacitor, NativeScript |
|
|
55
|
+
| `--pw_Placeholder_root_pulse_opacity` | `root` | `pulse` | `opacity` | `0.2` | Glow opacity at the midpoint of the pulse. | Web, Capacitor; NativeScript adapter |
|
|
56
|
+
| `--pw_Placeholder_root_default_width` | `root` | `default` | `width` | `100%` | Default width. | Web, Capacitor, NativeScript |
|
|
57
|
+
| `--pw_Placeholder_root_default_height` | `root` | `default` | `height` | `2.75em` | Default height, matching Button. | Web, Capacitor, NativeScript |
|
|
58
|
+
| `--pw_Placeholder_root_default_border-radius` | `root` | `default` | `border-radius` | `var(--pw_border-radius)` | Default corner radius, matching Button. | Web, Capacitor, NativeScript |
|
|
59
|
+
| `--pw_Placeholder_root_rounded_border-radius` | `root` | `rounded` | `border-radius` | `var(--pw_rounded_border-radius)` | Corner radius for `is-rounded`. | Web, Capacitor, NativeScript |
|
|
60
|
+
| `--pw_Placeholder_root_pill_border-radius` | `root` | `pill` | `border-radius` | `999px` | Corner radius for `is-pill`. | Web, Capacitor, NativeScript |
|
|
61
|
+
| `--pw_Placeholder_root_circle_width` | `root` | `circle` | `width` | `3em` | Width for `is-circle`. | Web, Capacitor, NativeScript |
|
|
62
|
+
| `--pw_Placeholder_root_circle_height` | `root` | `circle` | `height` | `3em` | Height for `is-circle`. | Web, Capacitor, NativeScript |
|
|
63
|
+
| `--pw_Placeholder_root_square_width` | `root` | `square` | `width` | `3em` | Width for `is-square`. | Web, Capacitor, NativeScript |
|
|
64
|
+
| `--pw_Placeholder_root_square_height` | `root` | `square` | `height` | `3em` | Height for `is-square`. | Web, Capacitor, NativeScript |
|
|
65
|
+
| `--pw_Placeholder_root_block_width` | `root` | `block` | `width` | `100%` | Width for `is-block`. | Web, Capacitor, NativeScript |
|
|
66
|
+
| `--pw_Placeholder_root_block_height` | `root` | `block` | `height` | `8em` | Height for `is-block`. | Web, Capacitor, NativeScript |
|
|
67
|
+
| `--pw_Placeholder_root_default_animation-duration` | `root` | `default` | `animation-duration` | `2s` | Pulse duration. | Web, Capacitor; NativeScript adapter |
|
|
68
|
+
|
|
69
|
+
```xts
|
|
70
|
+
import { useMediator, withDefaultProps } from '@pastweb/x';
|
|
71
|
+
import { placeholderMediator } from '@pastweb/components-core/Placeholder';
|
|
72
|
+
import { DEFAULT_PROPS } from './constants';
|
|
73
|
+
|
|
74
|
+
export function Placeholder(props: PlaceholderProps) {
|
|
75
|
+
const p = withDefaultProps<PlaceholderDefaultProps>(props, DEFAULT_PROPS);
|
|
76
|
+
const m = useMediator<PlaceholderMediator>(placeholderMediator, p);
|
|
77
|
+
const s = m.state;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div
|
|
81
|
+
class={p.cls('Placeholder', { 'is-decorative': p.decorative }, p.className)}
|
|
82
|
+
role={s.role}
|
|
83
|
+
aria-label={s.ariaLabel}
|
|
84
|
+
aria-live={s.ariaLive}
|
|
85
|
+
aria-hidden={s.ariaHidden}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Keyboard interaction
|
|
92
|
+
|
|
93
|
+
- Placeholder is not interactive. It does not enter the tab order.
|
|
94
|
+
|
|
95
|
+
## Accessibility notes
|
|
96
|
+
|
|
97
|
+
- Placeholders are decorative by default and are removed from the accessibility
|
|
98
|
+
tree with `aria-hidden`.
|
|
99
|
+
- A non-decorative Placeholder exposes `role="status"`, a polite live region,
|
|
100
|
+
and `ariaLabel`. Use that mode only for a single loading signal.
|
|
101
|
+
- When several placeholders compose a skeleton, keep them decorative and
|
|
102
|
+
announce loading once on a parent region.
|
|
103
|
+
- The pulse animation is suppressed when the user prefers reduced motion.
|
|
104
|
+
- Do not use Placeholder as an unlabeled interactive control.
|
|
105
|
+
|
|
106
|
+
## Native renderer mapping
|
|
107
|
+
|
|
108
|
+
NativeScript renderers map the shape to a native view with the configured size
|
|
109
|
+
and corner radius. Decorative placeholders disable native accessibility
|
|
110
|
+
exposure; a non-decorative placeholder maps `ariaLabel` intent to
|
|
111
|
+
`accessibilityLabel` and status semantics. Do not copy ARIA attributes into
|
|
112
|
+
native markup.
|
|
113
|
+
|
|
114
|
+
## Known limitations
|
|
115
|
+
|
|
116
|
+
- Automated accessibility checks do not by themselves establish WCAG
|
|
117
|
+
conformance.
|
|
118
|
+
- The fill colour must remain distinguishable from the page background.
|
|
119
|
+
|
|
120
|
+
## Standards
|
|
121
|
+
|
|
122
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
123
|
+
- WAI-ARIA status guidance: https://www.w3.org/WAI/ARIA/apg/patterns/
|
|
124
|
+
- GOV.UK components guidance: https://design-system.service.gov.uk/components/
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# ProgressBar
|
|
2
|
+
|
|
3
|
+
ProgressBar communicates the completion of a determinate task in linear or
|
|
4
|
+
circular form. Its rendering contract targets WCAG 2.2 Level AA.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
Use it when a numeric completion value is known, such as an upload or processing
|
|
9
|
+
task. Use a separate indeterminate status indicator when completion cannot be
|
|
10
|
+
calculated. Keep important status text available as accessible value text, not
|
|
11
|
+
only as a visual bar.
|
|
12
|
+
|
|
13
|
+
Do not use it as a multi-step form progress indicator. GOV.UK guidance is to
|
|
14
|
+
avoid step trackers that show every question at once.
|
|
15
|
+
|
|
16
|
+
## Props
|
|
17
|
+
|
|
18
|
+
| PropName | Type | Required | Default | Description |
|
|
19
|
+
|---|---|---:|---:|---|
|
|
20
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component and part classes. |
|
|
21
|
+
| `ariaLabel` | `string` | no | `"Progress"` | Accessible name for the progressbar. Pass an empty string to omit the name. |
|
|
22
|
+
| `total` | `number` | conditional | - | Total used with `current`. |
|
|
23
|
+
| `current` | `number` | conditional | - | Current value used with `total`. |
|
|
24
|
+
| `percentage` | `number` | conditional | - | Direct percentage; clamped from 0 to 100. |
|
|
25
|
+
| `label` | `string \| (values) => string` | no | `"%"` | Visible and accessible value text; use an empty string to hide it. |
|
|
26
|
+
| `type` | `'linear' \| 'circular'` | no | `'linear'` | Visual presentation. |
|
|
27
|
+
| `size` | `number` | no | `100` | Circular SVG coordinate size. |
|
|
28
|
+
| `className` | `string` | no | `""` | Additional root classes. |
|
|
29
|
+
|
|
30
|
+
Provide either `percentage` or both `total` and `current`.
|
|
31
|
+
|
|
32
|
+
## Utility classes
|
|
33
|
+
|
|
34
|
+
Apply these classes through `className`.
|
|
35
|
+
|
|
36
|
+
| Class | Description |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `is-rounded` | Uses the rounded progress-bar radius token. |
|
|
39
|
+
| `is-outlined` | Uses the page background for the unfilled track so the bar reads as outlined. |
|
|
40
|
+
| `is-full-width` | Expands the progress bar to the available width. |
|
|
41
|
+
|
|
42
|
+
## Mediator state
|
|
43
|
+
|
|
44
|
+
| Property | Type | Description |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `ariaLabel` | `string \| undefined` | Normalized accessible name. Empty labels are omitted. |
|
|
47
|
+
| `circumference` | `number` | Circular stroke length. |
|
|
48
|
+
| `labelContent` | `string \| null` | Visible value label, or `null` when `label` is empty. |
|
|
49
|
+
| `offset` | `number` | Circular stroke offset for the remaining portion. |
|
|
50
|
+
| `percentage` | `number` | Completion from 0 to 100. Renderers use this for `aria-valuenow`. |
|
|
51
|
+
| `radius` | `number` | Circular track radius from `size`. |
|
|
52
|
+
| `valueText` | `string` | Accessible value text. Falls back to `percentage%` when the label is hidden. |
|
|
53
|
+
| `width` | `string` | Linear filler width as a percentage string. |
|
|
54
|
+
|
|
55
|
+
## CSS Variables
|
|
56
|
+
|
|
57
|
+
| Variable | Part | State | CSS property | Default | Description | Platforms |
|
|
58
|
+
|---|---|---|---|---|---|---|
|
|
59
|
+
| `--pw_ProgressBar_root_default_background-color` | `root` | `default` | `background-color` | `var(--pw_control_background-color)` | Unfilled track colour. | Web, Capacitor, NativeScript |
|
|
60
|
+
| `--pw_ProgressBar_root_default_border-color` | `root` | `default` | `border-color` | `var(--pw_border-color)` | Linear border colour. | Web, Capacitor, NativeScript |
|
|
61
|
+
| `--pw_ProgressBar_root_default_border-radius` | `root` | `default` | `border-radius` | `var(--pw_border-radius)` | Linear corner radius. | Web, Capacitor, NativeScript |
|
|
62
|
+
| `--pw_ProgressBar_root_rounded_border-radius` | `root` | `rounded` | `border-radius` | `var(--pw_rounded_border-radius)` | Corner radius for `is-rounded`. | Web, Capacitor, NativeScript |
|
|
63
|
+
| `--pw_ProgressBar_root_default_border-style` | `root` | `default` | `border-style` | `var(--pw_border-style)` | Linear border style. | Web, Capacitor, NativeScript |
|
|
64
|
+
| `--pw_ProgressBar_root_default_border-width` | `root` | `default` | `border-width` | `var(--pw_border-width)` | Linear border width. | Web, Capacitor, NativeScript |
|
|
65
|
+
| `--pw_ProgressBar_label_default_color` | `label` | `default` | `color` | `inherit` | Value-label colour. | Web, Capacitor, NativeScript |
|
|
66
|
+
| `--pw_ProgressBar_fill_default_background-color` | `fill` | `default` | `background-color` | border colour | Linear completion colour. | Web, Capacitor, NativeScript |
|
|
67
|
+
| `--pw_ProgressBar_fill_default_stroke` | `fill` | `default` | `stroke` | border colour | Circular completion stroke. | Web, Capacitor |
|
|
68
|
+
| `--pw_ProgressBar_linear_default_height` | `linear` | `default` | `height` | `2em` | Linear bar height. | Web, Capacitor, NativeScript |
|
|
69
|
+
| `--pw_ProgressBar_circular_default_width` | `circular` | `default` | `width` | `5em` | Circular width. | Web, Capacitor, NativeScript |
|
|
70
|
+
| `--pw_ProgressBar_circular_default_height` | `circular` | `default` | `height` | `5em` | Circular height. | Web, Capacitor, NativeScript |
|
|
71
|
+
| `--pw_ProgressBar_circle_default_stroke-width` | `circle` | `default` | `stroke-width` | `0.5em` | Circular stroke width. | Web, Capacitor |
|
|
72
|
+
| `--pw_ProgressBar_circle_default_stroke-linecap` | `circle` | `default` | `stroke-linecap` | `round` | Circular stroke cap. | Web, Capacitor |
|
|
73
|
+
|
|
74
|
+
```xts
|
|
75
|
+
import { useMediator, withDefaultProps } from '@pastweb/x';
|
|
76
|
+
import { progressbarMediator } from '@pastweb/components-core/ProgressBar';
|
|
77
|
+
import { DEFAULT_PROPS } from './constants';
|
|
78
|
+
|
|
79
|
+
export function ProgressBar(props: ProgressBarProps) {
|
|
80
|
+
const p = withDefaultProps<ProgressBarDefaultProps>(props, DEFAULT_PROPS);
|
|
81
|
+
const m = useMediator<ProgressBarMediator>(progressbarMediator, p);
|
|
82
|
+
const s = m.state;
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
class={p.cls('ProgressBar', `type-${p.type}`, p.className)}
|
|
87
|
+
role="progressbar"
|
|
88
|
+
aria-label={s.ariaLabel}
|
|
89
|
+
aria-valuemin={0}
|
|
90
|
+
aria-valuemax={100}
|
|
91
|
+
aria-valuenow={s.percentage}
|
|
92
|
+
aria-valuetext={s.valueText}
|
|
93
|
+
>
|
|
94
|
+
<div #if={p.type === 'linear'} class={p.cls('linear')}>
|
|
95
|
+
<div class={p.cls('filler')} #style={{ width: s.width }}>
|
|
96
|
+
<div #if={s.labelContent} class={p.cls('label')}>{s.labelContent}</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div #if={p.type === 'circular'} class={p.cls('circular')}>
|
|
100
|
+
<svg class={p.cls('svg')} viewBox={`0 0 ${p.size} ${p.size}`} aria-hidden="true">
|
|
101
|
+
<circle class={p.cls('track')} cx={p.size / 2} cy={p.size / 2} r={s.radius} />
|
|
102
|
+
<circle class={p.cls('fill')} cx={p.size / 2} cy={p.size / 2} r={s.radius}
|
|
103
|
+
stroke-dasharray={s.circumference} stroke-dashoffset={s.offset} />
|
|
104
|
+
</svg>
|
|
105
|
+
<div #if={s.labelContent} class={p.cls('label')}>{s.labelContent}</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Keyboard interaction
|
|
113
|
+
|
|
114
|
+
- ProgressBar is not interactive. It does not enter the tab order.
|
|
115
|
+
|
|
116
|
+
## Accessibility notes
|
|
117
|
+
|
|
118
|
+
- The web renderer exposes the `progressbar` role, a name, and values from 0 to
|
|
119
|
+
100. The SVG is decorative.
|
|
120
|
+
- The default accessible name is `Progress`. An explicit empty string omits the
|
|
121
|
+
name.
|
|
122
|
+
- Visible `label` content is also used as `aria-valuetext`. Hiding the label
|
|
123
|
+
still exposes a numeric value text.
|
|
124
|
+
- Shared web styles support `forced-colors` and disable non-essential
|
|
125
|
+
transitions under `prefers-reduced-motion`.
|
|
126
|
+
|
|
127
|
+
## Known limitations
|
|
128
|
+
|
|
129
|
+
- ProgressBar is determinate only. It does not represent unknown remaining time.
|
|
130
|
+
- Automated accessibility checks do not by themselves establish WCAG
|
|
131
|
+
conformance.
|
|
132
|
+
|
|
133
|
+
## Standards
|
|
134
|
+
|
|
135
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
136
|
+
- WAI-ARIA Meter pattern: https://www.w3.org/WAI/ARIA/apg/patterns/meter/
|
|
137
|
+
- GOV.UK components: https://design-system.service.gov.uk/components/
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Radio
|
|
2
|
+
|
|
3
|
+
Radio presents a labelled group in which exactly one enabled option can be
|
|
4
|
+
selected. Its rendering contract follows the WAI-ARIA Radio Group pattern and
|
|
5
|
+
targets WCAG 2.2 Level AA.
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
Use radios when choices are mutually exclusive and should remain visible. Use
|
|
10
|
+
Select for a long option list. Provide a concise group label and clear option
|
|
11
|
+
labels. Do not pre-select an option unless a default is required.
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
| PropName | Type | Required | Default | Description |
|
|
16
|
+
|---|---|---:|---:|---|
|
|
17
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component, part, and state classes. |
|
|
18
|
+
| `ariaLabel` | `string` | no | `"Radio options"` | Names the group when `label` is absent. Pass an empty string to omit the name. |
|
|
19
|
+
| `id` | `string` | no | generated | Stable group and relationship ID base. Generated IDs use the `radio` prefix. Explicit IDs are stored as `_${id}`. |
|
|
20
|
+
| `label` | `string` | no | `""` | Visible group label. |
|
|
21
|
+
| `labelPlacement` | `Placement` | no | `'top-start'` | Group-label placement. |
|
|
22
|
+
| `name` | `string` | no | generated group ID | Shared native form name. |
|
|
23
|
+
| `options` | `RadioOption[]` | yes | - | Options to render. |
|
|
24
|
+
| `orientation` | `'horizontal' \| 'vertical' \| string` | no | `'horizontal'` | Option layout. |
|
|
25
|
+
| `disabled` | `boolean` | no | - | Disables every option and applies `is-disabled`. |
|
|
26
|
+
| `value` | `string` | no | `""` | Selected value. |
|
|
27
|
+
| `onChange` | `(value, event) => void` | no | noop | Reports selection. |
|
|
28
|
+
| `className` | `string` | no | `""` | Additional root classes. |
|
|
29
|
+
|
|
30
|
+
`RadioOption` accepts `label`, `value`, optional `id`, `name`, `disabled`,
|
|
31
|
+
`tabIndex`, and `labelPosition`. The option default is `labelPosition: 'right'`.
|
|
32
|
+
Do not set `tabIndex` on every option; native radios
|
|
33
|
+
keep only the selected or first available option in sequential tab order.
|
|
34
|
+
|
|
35
|
+
## Mediator state
|
|
36
|
+
|
|
37
|
+
| Property | Type | Description |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `ariaLabel` | `string \| undefined` | Normalized group name when no visible `label` is present. Empty labels are omitted. |
|
|
40
|
+
| `groupId` | `string` | Group ID from an explicit `id` or a generated `radio` prefix. |
|
|
41
|
+
| `groupLabelId` | `string \| undefined` | Label relationship ID `label${groupId}` when visible label text is present; otherwise omitted. |
|
|
42
|
+
| `isDisabled` | `true \| undefined` | Is `true` when the group is disabled; otherwise omitted. Renderers use this value directly for `.is-disabled`, `aria-disabled`, and native `disabled`. |
|
|
43
|
+
| `value` | `string` | Selected option value. |
|
|
44
|
+
|
|
45
|
+
Option IDs are `option${groupId}${index}` unless an option supplies an explicit
|
|
46
|
+
`id`.
|
|
47
|
+
|
|
48
|
+
## CSS Variables
|
|
49
|
+
|
|
50
|
+
| Variable | Part | State | CSS property | Default | Description | Platforms |
|
|
51
|
+
|---|---|---|---|---|---|---|
|
|
52
|
+
| `--pw_Radio_root_default_margin` | `root` | `default` | `margin` | shared margins | Group spacing. | Web, Capacitor, NativeScript |
|
|
53
|
+
| `--pw_Radio_root_default_font-size` | `root` | `default` | `font-size` | `var(--pw_font-size)` | Group text size. | Web, Capacitor, NativeScript |
|
|
54
|
+
| `--pw_Radio_root_default_font-weight` | `root` | `default` | `font-weight` | `var(--pw_semibold_font-weight)` | Group text weight. | Web, Capacitor, NativeScript |
|
|
55
|
+
| `--pw_Radio_root_default_line-height` | `root` | `default` | `line-height` | `var(--pw_line-height)` | Group line height. | Web, Capacitor, NativeScript |
|
|
56
|
+
| `--pw_Radio_root_disabled_opacity` | `root` | `disabled` | `opacity` | `var(--pw_disabled_opacity)` | Disabled appearance. | Web, Capacitor, NativeScript |
|
|
57
|
+
| `--pw_Radio_option_default_margin` | `option` | `default` | `margin` | shared margins | Horizontal option spacing. | Web, Capacitor, NativeScript |
|
|
58
|
+
| `--pw_Radio_option_vertical_margin` | `option` | `vertical` | `margin` | `1em 0.5em` | Vertical option spacing. | Web, Capacitor, NativeScript |
|
|
59
|
+
| `--pw_Radio_control_default_width` | `control` | `default` | `width` | `2.375em` | Control width. | Web, Capacitor, NativeScript |
|
|
60
|
+
| `--pw_Radio_control_default_height` | `control` | `default` | `height` | `2.375em` | Control height. | Web, Capacitor, NativeScript |
|
|
61
|
+
| `--pw_Radio_control_default_background-color` | `control` | `default` | `background-color` | `var(--pw_control_background-color)` | Control background. | Web, Capacitor, NativeScript |
|
|
62
|
+
| `--pw_Radio_control_default_border-color` | `control` | `default` | `border-color` | `var(--pw_border-color)` | Control border colour. | Web, Capacitor, NativeScript |
|
|
63
|
+
| `--pw_Radio_control_default_border-radius` | `control` | `default` | `border-radius` | `var(--pw_rounded_border-radius)` | Control shape. | Web, Capacitor, NativeScript |
|
|
64
|
+
| `--pw_Radio_control_default_border-style` | `control` | `default` | `border-style` | `var(--pw_border-style)` | Control border style. | Web, Capacitor, NativeScript |
|
|
65
|
+
| `--pw_Radio_control_default_border-width` | `control` | `default` | `border-width` | `var(--pw_border-width)` | Control border width. | Web, Capacitor, NativeScript |
|
|
66
|
+
| `--pw_Radio_control_default_transition-duration` | `control` | `default` | `transition-duration` | `var(--pw_transition-duration)` | Indicator transition duration. | Web, Capacitor; NativeScript adapter |
|
|
67
|
+
| `--pw_Radio_control_hover_box-shadow` | `control` | `hover` | `box-shadow` | shared inset shadow | Hover treatment. | Web, Capacitor |
|
|
68
|
+
| `--pw_Radio_control_focus_box-shadow` | `control` | `focus` | `box-shadow` | shared focus shadow | Keyboard focus treatment. | Web, Capacitor |
|
|
69
|
+
| `--pw_Radio_indicator_default_width` | `indicator` | `default` | `width` | `1em` | Indicator width. | Web, Capacitor, NativeScript |
|
|
70
|
+
| `--pw_Radio_indicator_default_height` | `indicator` | `default` | `height` | `1em` | Indicator height. | Web, Capacitor, NativeScript |
|
|
71
|
+
| `--pw_Radio_indicator_default_background-color` | `indicator` | `default` | `background-color` | `var(--pw_text_strong_color)` | Selected indicator colour. | Web, Capacitor, NativeScript |
|
|
72
|
+
| `--pw_Radio_label_default_color` | `label` | `default` | `color` | `var(--pw_label_text_color)` | Label colour. | Web, Capacitor, NativeScript |
|
|
73
|
+
|
|
74
|
+
```xts
|
|
75
|
+
import { useBeforeUnmount, useMediator, withDefaultProps } from '@pastweb/x';
|
|
76
|
+
import { radioMediator } from '@pastweb/components-core/Radio';
|
|
77
|
+
import { DEFAULT_PROPS } from './constants';
|
|
78
|
+
|
|
79
|
+
export function Radio(props: RadioProps) {
|
|
80
|
+
const p = withDefaultProps<RadioDefaultProps>(props, DEFAULT_PROPS);
|
|
81
|
+
const m = useMediator<RadioMediator>(radioMediator, p);
|
|
82
|
+
const s = m.state;
|
|
83
|
+
|
|
84
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div
|
|
88
|
+
id={s.groupId}
|
|
89
|
+
class={p.cls('Radio', `label-${p.labelPlacement}`, { 'is-disabled': s.isDisabled }, p.className)}
|
|
90
|
+
role="radiogroup"
|
|
91
|
+
aria-labelledby={s.groupLabelId}
|
|
92
|
+
aria-label={s.ariaLabel}
|
|
93
|
+
aria-disabled={s.isDisabled}
|
|
94
|
+
>
|
|
95
|
+
<div class={p.cls('buttons', { vertical: p.orientation === 'vertical' })}>
|
|
96
|
+
{p.options.map((option, index) => (
|
|
97
|
+
<label class={p.cls('group', `label-${option.labelPosition || 'right'}`, {
|
|
98
|
+
'is-checked': s.value === `${option.value}`,
|
|
99
|
+
'is-disabled': s.isDisabled || option.disabled,
|
|
100
|
+
})}>
|
|
101
|
+
<input type="radio" class={p.cls('input')} id={m.getOptionId(index, option.id)}
|
|
102
|
+
name={option.name || p.name || s.groupId} value={option.value}
|
|
103
|
+
checked={s.value === `${option.value}`} disabled={s.isDisabled || option.disabled}
|
|
104
|
+
@change={event => m.onChange(event.target.value, event)} />
|
|
105
|
+
<span class={p.cls('box')} aria-hidden="true"><span class={p.cls('indicator')} /></span>
|
|
106
|
+
<span class={p.cls('buttonLabel')}>{option.label}</span>
|
|
107
|
+
</label>
|
|
108
|
+
))}
|
|
109
|
+
</div>
|
|
110
|
+
<span #if={p.label} id={s.groupLabelId} class={p.cls('label', p.labelPlacement)}>{p.label}</span>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Keyboard interaction
|
|
117
|
+
|
|
118
|
+
- Native radio inputs provide arrow-key selection within the group.
|
|
119
|
+
- `Tab` and `Shift+Tab` move sequential focus to the selected or first available
|
|
120
|
+
option.
|
|
121
|
+
- Disabled options and a disabled group are not operable.
|
|
122
|
+
|
|
123
|
+
## Accessibility notes
|
|
124
|
+
|
|
125
|
+
- Native radio inputs provide group semantics, checked state, and form behavior.
|
|
126
|
+
The visual control is decorative; the native input remains in the
|
|
127
|
+
accessibility tree and tab order.
|
|
128
|
+
- The visible group label is connected through `aria-labelledby`. When it is
|
|
129
|
+
absent, `ariaLabel` names the group. The default name is `Radio options`.
|
|
130
|
+
- Disabled state is reflected through `.is-disabled`, native `disabled`, and
|
|
131
|
+
`aria-disabled`.
|
|
132
|
+
- Shared web styles provide visible keyboard focus, forced-colours treatment,
|
|
133
|
+
and reduced-motion behavior.
|
|
134
|
+
|
|
135
|
+
## Known limitations
|
|
136
|
+
|
|
137
|
+
- Automated accessibility checks do not by themselves establish WCAG
|
|
138
|
+
conformance.
|
|
139
|
+
|
|
140
|
+
## Standards
|
|
141
|
+
|
|
142
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
143
|
+
- WAI-ARIA Radio Group pattern: https://www.w3.org/WAI/ARIA/apg/patterns/radio/
|
|
144
|
+
- GOV.UK radios: https://design-system.service.gov.uk/components/radios/
|