@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,251 @@
|
|
|
1
|
+
# Accordion
|
|
2
|
+
|
|
3
|
+
Accordion presents related sections whose content can be expanded and collapsed.
|
|
4
|
+
Its rendering contract follows the WAI-ARIA Accordion pattern and targets WCAG
|
|
5
|
+
2.2 Level AA.
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
Use an accordion when research shows that users benefit from seeing an overview
|
|
10
|
+
of several related sections and selectively revealing their content. Do not use
|
|
11
|
+
it for content every user must read, for a sequence of form questions, or inside
|
|
12
|
+
another accordion. Prefer ordinary headings, links to page sections, separate
|
|
13
|
+
pages, or native `details` elements when those are simpler.
|
|
14
|
+
|
|
15
|
+
## Accordion props
|
|
16
|
+
|
|
17
|
+
| PropName | Type | Required | Default | Description |
|
|
18
|
+
|---|---|---:|---:|---|
|
|
19
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component and state classes. |
|
|
20
|
+
| `ariaLabel` | `string` | no | `"Accordion"` | Labels the accordion group. Provide a task-specific label when possible; pass an empty string to omit the group semantics. |
|
|
21
|
+
| `className` | `string` | no | `""` | Adds classes to the accordion wrapper. |
|
|
22
|
+
| `disabled` | `boolean` | no | - | Disables every panel trigger. Prefer removing unavailable sections or explaining their unavailable content. |
|
|
23
|
+
| `id` | `string` | no | - | Supplies the root ID. |
|
|
24
|
+
| `rtl` | `boolean` | no | - | Enables right-to-left layout. |
|
|
25
|
+
| `transitionDuration` | `number` | no | `500` | Default panel transition duration in milliseconds. |
|
|
26
|
+
|
|
27
|
+
## Accordion mediator state
|
|
28
|
+
|
|
29
|
+
| Property | Type | Description |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `ariaLabel` | `string \| undefined` | Normalized accessible name. An empty string is stored as `undefined` so the group role and label are omitted. |
|
|
32
|
+
| `isDisabled` | `true \| undefined` | Normalized disabled state. Renderers must use this value for the root `is-disabled` class, `aria-disabled`, and must never convert `false`. |
|
|
33
|
+
| `role` | `'group' \| undefined` | Group role present only when `ariaLabel` is a non-empty string. |
|
|
34
|
+
|
|
35
|
+
## Accordion mediator context
|
|
36
|
+
|
|
37
|
+
`accordionMediator.getContext()` exposes live getters consumed by each
|
|
38
|
+
`AccordionPanel`. Values that also exist on mediator state are read from that
|
|
39
|
+
normalized state rather than recomputed from raw props.
|
|
40
|
+
|
|
41
|
+
| Property | Type | Description |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `className` | `string` | Root classes inherited by every panel for coordinated styling. |
|
|
44
|
+
| `disabled` | `true \| undefined` | Normalized accordion disabled state. |
|
|
45
|
+
| `rtl` | `boolean` | Root text-direction preference combined with each panel's local `rtl` prop. |
|
|
46
|
+
| `transitionDuration` | `number` | Default panel transition duration in milliseconds. |
|
|
47
|
+
|
|
48
|
+
## Accordion slots
|
|
49
|
+
|
|
50
|
+
| SlotName | Description | Default content |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| default | Supplies the ordered `AccordionPanel` children rendered inside the accordion wrapper. | Empty. |
|
|
53
|
+
|
|
54
|
+
## CSS Variables
|
|
55
|
+
|
|
56
|
+
Accordion variables follow the
|
|
57
|
+
`--pw_<ComponentName>_<part>_<state>_<css-property>` token grammar. The
|
|
58
|
+
component name is PascalCase; part and state names are lowercase kebab case.
|
|
59
|
+
|
|
60
|
+
| Variable | Part | State | CSS property | Default | Description | Platforms |
|
|
61
|
+
|---|---|---|---|---|---|---|
|
|
62
|
+
| `--pw_Accordion_root_default_background-color` | `root` | `default` | `background-color` | `var(--pw_background-color)` | Panel background colour. | Web, Capacitor, NativeScript |
|
|
63
|
+
| `--pw_Accordion_root_default_color` | `root` | `default` | `color` | `var(--pw_text_color)` | Default accordion text colour. | Web, Capacitor, NativeScript |
|
|
64
|
+
| `--pw_Accordion_root_default_font-size` | `root` | `default` | `font-size` | `var(--pw_font-size)` | Base accordion font size. | Web, Capacitor, NativeScript |
|
|
65
|
+
| `--pw_Accordion_root_default_line-height` | `root` | `default` | `line-height` | `var(--pw_line-height)` | Base accordion line height. | Web, Capacitor, NativeScript |
|
|
66
|
+
| `--pw_Accordion_root_default_border-color` | `root` | `default` | `border-color` | `var(--pw_border-color)` | Border colour used by the wrapper and panel separators. | Web, Capacitor, NativeScript |
|
|
67
|
+
| `--pw_Accordion_root_default_border-width` | `root` | `default` | `border-width` | `var(--pw_border-width)` | Border width used by the wrapper and panel separators. | Web, Capacitor, NativeScript |
|
|
68
|
+
| `--pw_Accordion_root_default_border-style` | `root` | `default` | `border-style` | `var(--pw_border-style)` | Border style used by the wrapper and panel separators. | Web, Capacitor, NativeScript |
|
|
69
|
+
| `--pw_Accordion_root_default_border-radius` | `root` | `default` | `border-radius` | `var(--pw_border-radius)` | Outer accordion corner radius. | Web, Capacitor, NativeScript |
|
|
70
|
+
| `--pw_Accordion_root_default_border` | `root` | `default` | `border` | width, style and colour tokens | Composed border shorthand. | Web, Capacitor, NativeScript |
|
|
71
|
+
| `--pw_Accordion_root_default_transition-duration` | `root` | `default` | `transition-duration` | `0.5s` | Duration of panel open and close transitions. | Web, Capacitor; NativeScript adapter |
|
|
72
|
+
| `--pw_Accordion_root_disabled_opacity` | `root` | `disabled` | `opacity` | `var(--pw_disabled_opacity)` | Disabled accordion opacity. Descendant panels reset their own opacity to avoid compounding it. | Web, Capacitor, NativeScript |
|
|
73
|
+
| `--pw_Accordion_header_default_padding` | `header` | `default` | `padding` | `var(--pw_padding)` | Space inside the panel trigger. | Web, Capacitor, NativeScript |
|
|
74
|
+
| `--pw_Accordion_header_default_background-color` | `header` | `default` | `background-color` | `var(--pw_control_background-color)` | Default trigger background colour. | Web, Capacitor, NativeScript |
|
|
75
|
+
| `--pw_Accordion_header_default_color` | `header` | `default` | `color` | `var(--pw_text_strong_color)` | Trigger text and icon colour. | Web, Capacitor, NativeScript |
|
|
76
|
+
| `--pw_Accordion_header_default_font-size` | `header` | `default` | `font-size` | `1em` | Trigger font size. | Web, Capacitor, NativeScript |
|
|
77
|
+
| `--pw_Accordion_header_default_font-weight` | `header` | `default` | `font-weight` | `var(--bold_font-weight)` | Trigger font weight. | Web, Capacitor, NativeScript |
|
|
78
|
+
| `--pw_Accordion_header_default_line-height` | `header` | `default` | `line-height` | `var(--pw_line-height)` | Trigger line height. | Web, Capacitor, NativeScript |
|
|
79
|
+
| `--pw_Accordion_header_disabled_opacity` | `header` | `disabled` | `opacity` | `var(--pw_disabled_opacity)` | Opacity of an individually disabled panel. | Web, Capacitor, NativeScript |
|
|
80
|
+
| `--pw_Accordion_close-button_default_background-color` | `close-button` | `default` | `background-color` | header background token | Default expand/collapse icon background. | Web, Capacitor, NativeScript |
|
|
81
|
+
| `--pw_Accordion_close-button_hover_background-color` | `close-button` | `hover` | `background-color` | header colour token | Expand/collapse icon background while the web trigger is hovered. | Web, Capacitor |
|
|
82
|
+
| `--pw_Accordion_close-bar_default_background-color` | `close-bar` | `default` | `background-color` | header colour token | Default expand/collapse icon bar colour. | Web, Capacitor, NativeScript |
|
|
83
|
+
| `--pw_Accordion_close-bar_hover_background-color` | `close-bar` | `hover` | `background-color` | header background token | Expand/collapse icon bar colour while the web trigger is hovered. | Web, Capacitor |
|
|
84
|
+
| `--pw_Accordion_content_default_padding` | `content` | `default` | `padding` | header padding token | Space inside expanded panel content. | Web, Capacitor, NativeScript |
|
|
85
|
+
|
|
86
|
+
```xts
|
|
87
|
+
// Accordion
|
|
88
|
+
import { setContext, useBeforeUnmount, useMediator, withDefaultProps } from '@pastweb/x';
|
|
89
|
+
import { accordionMediator } from '@pastweb/components-core/Accordion';
|
|
90
|
+
import { DEFAULT_PROPS, ACCORDION_CONTEXT_KEY } from './constants';
|
|
91
|
+
|
|
92
|
+
export function Accordion(props: AccordionProps) {
|
|
93
|
+
const p = withDefaultProps<AccordionDefaultProps>(props, DEFAULT_PROPS);
|
|
94
|
+
const m = useMediator<AccordionMediator>(accordionMediator, p);
|
|
95
|
+
const s = m.state;
|
|
96
|
+
const c = m.getContext();
|
|
97
|
+
|
|
98
|
+
setContext(ACCORDION_CONTEXT_KEY, c);
|
|
99
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
id={m.id}
|
|
104
|
+
class={p.cls('Accordion', p.className, { 'is-disabled': s.isDisabled })}
|
|
105
|
+
role={s.role}
|
|
106
|
+
aria-label={s.ariaLabel}
|
|
107
|
+
aria-disabled={s.isDisabled}
|
|
108
|
+
>
|
|
109
|
+
<slot />
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## AccordionPanel props
|
|
116
|
+
|
|
117
|
+
| PropName | Type | Required | Default | Description |
|
|
118
|
+
|---|---|---:|---:|---|
|
|
119
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component and state classes. |
|
|
120
|
+
| `className` | `string` | no | `""` | Adds classes to the panel. |
|
|
121
|
+
| `disabled` | `boolean` | no | - | Disables the native trigger button. |
|
|
122
|
+
| `headingLevel` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | no | `2` | Web renderer property. Selects the heading level required by the surrounding document. |
|
|
123
|
+
| `id` | `string` | no | generated | Supplies the stable base ID used for trigger and panel relationships. |
|
|
124
|
+
| `isOpen` | `boolean` | no | - | Sets the panel's initial open state. |
|
|
125
|
+
| `landmark` | `boolean` | no | - | Gives the content `role="region"`. Enable selectively to avoid landmark proliferation. |
|
|
126
|
+
| `onOpenChange` | `(isOpen: boolean) => void` | no | - | Reports a user-requested state change. |
|
|
127
|
+
| `title` | `string \| number` | no | `""` | Provides the default accessible trigger content. |
|
|
128
|
+
| `rtl` | `boolean` | no | - | Enables right-to-left layout for this panel. |
|
|
129
|
+
| `transitionDuration` | `number` | no | `500` | Sets this panel's transition duration in milliseconds. |
|
|
130
|
+
|
|
131
|
+
## AccordionPanel mediator state
|
|
132
|
+
|
|
133
|
+
| Property | Type | Description |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `className` | `string` | Complete panel class name, including inherited Accordion classes and `is-disabled` / `is-open`. |
|
|
136
|
+
| `hideBorderBottom` | `boolean` | Indicates that the closed panel trigger should hide its bottom border after the close transition. |
|
|
137
|
+
| `isDisabled` | `true \| undefined` | Normalized disabled state from the panel or parent Accordion. Renderers must use this value for `disabled`, `aria-disabled`, and must never convert `false`. |
|
|
138
|
+
| `isOpen` | `boolean` | Current expanded state. |
|
|
139
|
+
| `isRtl` | `true \| undefined` | Normalized right-to-left layout from the panel or parent Accordion. |
|
|
140
|
+
| `role` | `'region' \| undefined` | Optional landmark role when `landmark` is enabled. |
|
|
141
|
+
| `transitionDuration` | `string` | CSS duration used by the open and close transition. |
|
|
142
|
+
|
|
143
|
+
## AccordionPanel slots
|
|
144
|
+
|
|
145
|
+
| SlotName | Description | Default content |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `header` | Replaces content inside the native trigger button. It does not replace the heading or button. | The title and decorative expand/collapse icon. |
|
|
148
|
+
| default | Supplies panel content. | Empty. |
|
|
149
|
+
|
|
150
|
+
Custom header content must provide a meaningful accessible name. Decorative
|
|
151
|
+
icons must use `aria-hidden="true"`.
|
|
152
|
+
|
|
153
|
+
```xts
|
|
154
|
+
// AccordionPanel
|
|
155
|
+
import {
|
|
156
|
+
useBeforeUnmount,
|
|
157
|
+
useMediator,
|
|
158
|
+
useMounted,
|
|
159
|
+
withDefaultProps,
|
|
160
|
+
} from '@pastweb/x';
|
|
161
|
+
import { accordionPanelMediator } from '@pastweb/components-core/Accordion';
|
|
162
|
+
import { DEFAULT_ACCORDION_PANEL_PROPS } from './constants';
|
|
163
|
+
|
|
164
|
+
export function AccordionPanel(props: AccordionPanelProps) {
|
|
165
|
+
const p = withDefaultProps<AccordionPanelDefaultProps>(props, DEFAULT_ACCORDION_PANEL_PROPS);
|
|
166
|
+
const m = useMediator<AccordionPanelMediator>(accordionPanelMediator, p);
|
|
167
|
+
const s = m.state;
|
|
168
|
+
const Heading = `h${p.headingLevel}`;
|
|
169
|
+
|
|
170
|
+
useMounted(trigger => {
|
|
171
|
+
m.useMounted({ focus: () => trigger.focus() });
|
|
172
|
+
});
|
|
173
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<section
|
|
177
|
+
id={m.id}
|
|
178
|
+
class={s.className}
|
|
179
|
+
dir={s.isRtl ? 'rtl' : undefined}
|
|
180
|
+
aria-disabled={s.isDisabled}
|
|
181
|
+
style={{
|
|
182
|
+
transitionDuration: s.transitionDuration,
|
|
183
|
+
'--pw_Accordion_root_default_transition-duration': s.transitionDuration,
|
|
184
|
+
}}
|
|
185
|
+
>
|
|
186
|
+
<Heading class={p.cls('heading')}>
|
|
187
|
+
<button
|
|
188
|
+
id={m.triggerId}
|
|
189
|
+
type="button"
|
|
190
|
+
class={p.cls('header', { rtl: s.isRtl, 'hide-border': s.hideBorderBottom })}
|
|
191
|
+
aria-expanded={s.isOpen}
|
|
192
|
+
aria-controls={m.panelId}
|
|
193
|
+
disabled={s.isDisabled}
|
|
194
|
+
@click={m.onToggle}
|
|
195
|
+
>
|
|
196
|
+
<slot name="header">
|
|
197
|
+
<span class={p.cls('title')}>
|
|
198
|
+
<render content={p.title} />
|
|
199
|
+
</span>
|
|
200
|
+
<span class={p.cls('closeButton', s.isOpen ? 'is-open' : '')} aria-hidden="true">
|
|
201
|
+
<span class={p.cls('closeBar')} />
|
|
202
|
+
<span class={p.cls('closeBar')} />
|
|
203
|
+
</span>
|
|
204
|
+
</slot>
|
|
205
|
+
</button>
|
|
206
|
+
</Heading>
|
|
207
|
+
|
|
208
|
+
<div
|
|
209
|
+
id={m.panelId}
|
|
210
|
+
class={p.cls('container', s.isOpen ? 'is-open' : '')}
|
|
211
|
+
role={s.role}
|
|
212
|
+
aria-labelledby={m.triggerId}
|
|
213
|
+
aria-hidden={!s.isOpen}
|
|
214
|
+
inert={!s.isOpen}
|
|
215
|
+
@transitionend={m.onTransitionEnd}
|
|
216
|
+
>
|
|
217
|
+
<div class={p.cls('contentWrapper')}>
|
|
218
|
+
<div class={p.cls('content')}>
|
|
219
|
+
<slot />
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
</section>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Keyboard interaction
|
|
229
|
+
|
|
230
|
+
- `Tab` and `Shift+Tab` move through panel triggers and focusable open content in normal document order.
|
|
231
|
+
- `Enter` or `Space` on a trigger toggles its panel through native button behavior.
|
|
232
|
+
- Collapsed panel content is removed from sequential focus navigation.
|
|
233
|
+
|
|
234
|
+
## Accessibility notes
|
|
235
|
+
|
|
236
|
+
- The trigger is a native button inside a native heading.
|
|
237
|
+
- `aria-expanded` communicates state, while `aria-controls` and
|
|
238
|
+
`aria-labelledby` establish the trigger/content relationship.
|
|
239
|
+
- Closing content becomes inert and hidden from the accessibility tree
|
|
240
|
+
immediately. Web renderers keep it mounted so the grid-row transition can
|
|
241
|
+
animate the real content height in both directions.
|
|
242
|
+
- `role="region"` is opt-in because repeated regions can create excessive
|
|
243
|
+
landmarks.
|
|
244
|
+
- Shared styles retain visible focus, support `forced-colors`, and disable
|
|
245
|
+
non-essential transitions under `prefers-reduced-motion`.
|
|
246
|
+
|
|
247
|
+
## Standards
|
|
248
|
+
|
|
249
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
250
|
+
- WAI-ARIA Accordion pattern: https://www.w3.org/WAI/ARIA/apg/patterns/accordion/
|
|
251
|
+
- GOV.UK Accordion guidance: https://design-system.service.gov.uk/components/accordion/
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Button
|
|
2
|
+
|
|
3
|
+
Button renders a native action control with independent disabled and loading
|
|
4
|
+
states. Its rendering contract follows the WAI-ARIA Button pattern and targets
|
|
5
|
+
WCAG 2.2 Level AA.
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
Use a button to perform an action on the current page. Use a link when activation
|
|
10
|
+
navigates to another location. Button labels should start with a clear verb and
|
|
11
|
+
describe the result of activation.
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
| PropName | Type | Required | Default | Description |
|
|
16
|
+
|---|---|---:|---:|---|
|
|
17
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component and state classes. |
|
|
18
|
+
| `className` | `string` | no | `""` | Adds classes to the native button. The legacy `is-loading` class continues to enable loading behavior. |
|
|
19
|
+
| `disabled` | `boolean` | no | - | Makes the action unavailable. |
|
|
20
|
+
| `id` | `string` | no | generated | Supplies the button ID. Generated IDs use the `button` prefix. |
|
|
21
|
+
| `loading` | `boolean` | no | - | Marks the action busy, suppresses its click handler, and displays the loading slot without disabling the native button. |
|
|
22
|
+
| `onClick` | `(event: unknown) => void` | no | noop | Handles an available button activation. Renderers may narrow the event type. |
|
|
23
|
+
| `tabIndex` | `number` | no | `0` | Controls sequential keyboard focus order. Prefer the default document order. |
|
|
24
|
+
| `type` | `'button' \| 'submit' \| 'reset'` | no | `'button'` | Selects native button behavior. |
|
|
25
|
+
|
|
26
|
+
## Mediator state
|
|
27
|
+
|
|
28
|
+
| Property | Type | Description |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `isDisabled` | `true \| undefined` | Is `true` when the button or its Buttons context is disabled; otherwise omitted. Renderers use this value directly for `.is-disabled`, `disabled`, and `aria-disabled`. |
|
|
31
|
+
| `isLoading` | `boolean` | Indicates loading independently from `isDisabled`. Loading suppresses the click handler without disabling the native button. |
|
|
32
|
+
|
|
33
|
+
## Mediator context
|
|
34
|
+
|
|
35
|
+
Button does not publish its own context. When rendered inside `Buttons`, its
|
|
36
|
+
mediator optionally consumes the parent `ButtonsContext` value below and
|
|
37
|
+
combines it with the local `disabled` prop.
|
|
38
|
+
|
|
39
|
+
| Context property | Type | Description |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `disabled` | `true \| undefined` | Normalized disabled state inherited from the containing Buttons component. |
|
|
42
|
+
|
|
43
|
+
## Slots
|
|
44
|
+
|
|
45
|
+
| SlotName | Description | Default content |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| default | Supplies the button's accessible label and optional icon content. | Empty. |
|
|
48
|
+
| `loading` | Supplies status content while `loading` is active. | `Loading...` |
|
|
49
|
+
|
|
50
|
+
## Utility classes
|
|
51
|
+
|
|
52
|
+
Apply these classes through `className`.
|
|
53
|
+
|
|
54
|
+
| Class | Description |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `is-rounded` | Uses the rounded button radius token. |
|
|
57
|
+
| `is-full-width` | Expands the button to the available width. |
|
|
58
|
+
|
|
59
|
+
## CSS Variables
|
|
60
|
+
|
|
61
|
+
| Variable | Part | State | CSS property | Default | Description | Platforms |
|
|
62
|
+
|---|---|---|---|---|---|---|
|
|
63
|
+
| `--pw_Button_root_default_background-color` | `root` | `default` | `background-color` | `var(--pw_control_background-color)` | Button background. | Web, Capacitor, NativeScript |
|
|
64
|
+
| `--pw_Button_root_default_color` | `root` | `default` | `color` | `var(--pw_text_strong_color)` | Button text colour. | Web, Capacitor, NativeScript |
|
|
65
|
+
| `--pw_Button_root_default_padding` | `root` | `default` | `padding` | `var(--pw_padding)` | Inner spacing. | Web, Capacitor, NativeScript |
|
|
66
|
+
| `--pw_Button_root_default_margin` | `root` | `default` | `margin` | `var(--pw_margin)` | Outer spacing. | Web, Capacitor, NativeScript |
|
|
67
|
+
| `--pw_Button_root_default_border-color` | `root` | `default` | `border-color` | `var(--pw_border-color)` | Default border colour. | Web, Capacitor, NativeScript |
|
|
68
|
+
| `--pw_Button_root_default_border-width` | `root` | `default` | `border-width` | `var(--pw_border-width)` | Border width. | Web, Capacitor, NativeScript |
|
|
69
|
+
| `--pw_Button_root_default_border-style` | `root` | `default` | `border-style` | `var(--pw_border-style)` | Border style. | Web, Capacitor, NativeScript |
|
|
70
|
+
| `--pw_Button_root_default_border-radius` | `root` | `default` | `border-radius` | `var(--pw_border-radius)` | Default corner radius. | Web, Capacitor, NativeScript |
|
|
71
|
+
| `--pw_Button_root_rounded_border-radius` | `root` | `rounded` | `border-radius` | `var(--pw_rounded_border-radius)` | Corner radius for `is-rounded`. | Web, Capacitor, NativeScript |
|
|
72
|
+
| `--pw_Button_root_default_transition-duration` | `root` | `default` | `transition-duration` | `var(--pw_transition-duration)` | Visual state transition duration. | Web, Capacitor; NativeScript adapter |
|
|
73
|
+
| `--pw_Button_color_default_box-shadow` | `color` | `default` | `box-shadow` | `var(--pw_color_box-shadow)` | Focus shadow colour. | Web, Capacitor |
|
|
74
|
+
| `--pw_Button_inset-color_default_box-shadow` | `inset-color` | `default` | `box-shadow` | `var(--pw_inset_color_box-shadow)` | Hover inset shadow colour. | Web, Capacitor |
|
|
75
|
+
| `--pw_Button_size_default_box-shadow` | `size` | `default` | `box-shadow` | `var(--pw_size_box-shadow)` | Shadow size. | Web, Capacitor |
|
|
76
|
+
| `--pw_Button_root_disabled_opacity` | `root` | `disabled` | `opacity` | `var(--pw_disabled_opacity)` | Disabled opacity. | Web, Capacitor, NativeScript |
|
|
77
|
+
| `--pw_Button_root_default_font-size` | `root` | `default` | `font-size` | `var(--pw_font-size)` | Label font size. | Web, Capacitor, NativeScript |
|
|
78
|
+
| `--pw_Button_root_default_font-weight` | `root` | `default` | `font-weight` | `var(--pw_semibold_font-weight)` | Label font weight. | Web, Capacitor, NativeScript |
|
|
79
|
+
| `--pw_Button_root_default_line-height` | `root` | `default` | `line-height` | `var(--pw_line-height)` | Label line height. | Web, Capacitor, NativeScript |
|
|
80
|
+
| `--pw_Button_item_default_gap` | `item` | `default` | `gap` | `var(--pw_horizontal_padding)` | Spacing between rendered items. | Web, Capacitor |
|
|
81
|
+
| `--pw_Button_icon_default_color` | `icon` | `default` | `color` | button colour | Icon colour. | Web, Capacitor, NativeScript |
|
|
82
|
+
| `--pw_Button_icon_default_stroke` | `icon` | `default` | `stroke` | icon colour | Icon stroke. | Web, Capacitor |
|
|
83
|
+
| `--pw_Button_icon_default_size` | `icon` | `default` | `size` | `var(--pw_icon_size)` | Font-icon size. | Web, Capacitor, NativeScript |
|
|
84
|
+
|
|
85
|
+
```xts
|
|
86
|
+
import { useBeforeUnmount, useMediator, withDefaultProps } from '@pastweb/x';
|
|
87
|
+
import { buttonMediator } from '@pastweb/components-core/Button';
|
|
88
|
+
import { DEFAULT_PROPS } from './constants';
|
|
89
|
+
|
|
90
|
+
export function Button(props: ButtonProps) {
|
|
91
|
+
const p = withDefaultProps<ButtonDefaultProps>(props, DEFAULT_PROPS);
|
|
92
|
+
const m = useMediator<ButtonMediator>(buttonMediator, p);
|
|
93
|
+
const s = m.state;
|
|
94
|
+
|
|
95
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<button
|
|
99
|
+
id={m.id}
|
|
100
|
+
type={p.type}
|
|
101
|
+
class={p.cls('Button', p.className, { 'is-disabled': s.isDisabled, 'is-loading': s.isLoading })}
|
|
102
|
+
@click={m.onClick}
|
|
103
|
+
disabled={s.isDisabled}
|
|
104
|
+
aria-disabled={s.isDisabled}
|
|
105
|
+
aria-busy={s.isLoading || undefined}
|
|
106
|
+
tabIndex={p.tabIndex}
|
|
107
|
+
>
|
|
108
|
+
<slot
|
|
109
|
+
map={(child, index) => (
|
|
110
|
+
<span key={index} class={p.cls('item')}>{child}</span>
|
|
111
|
+
)}
|
|
112
|
+
/>
|
|
113
|
+
<span #if={s.isLoading} class={p.cls('loading')} role="status" aria-live="polite">
|
|
114
|
+
<slot name="loading">Loading...</slot>
|
|
115
|
+
</span>
|
|
116
|
+
</button>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Accessibility notes
|
|
122
|
+
|
|
123
|
+
- The renderer must use a native button and preserve its keyboard activation.
|
|
124
|
+
- Disabled buttons use the native `disabled` property, `aria-disabled="true"`,
|
|
125
|
+
and the `is-disabled` class.
|
|
126
|
+
- Loading buttons remain independently enabled, expose `aria-busy="true"` and
|
|
127
|
+
the `is-loading` class, and suppress the component click handler. Status
|
|
128
|
+
content is announced politely.
|
|
129
|
+
- A button may be both disabled and loading when both states are set.
|
|
130
|
+
- The accessible name must remain meaningful without relying on a decorative icon.
|
|
131
|
+
- Shared web styles provide at least a 44 by 44 CSS-pixel target, visible focus,
|
|
132
|
+
forced-colours treatment, and reduced-motion behavior.
|
|
133
|
+
|
|
134
|
+
## Keyboard interaction
|
|
135
|
+
|
|
136
|
+
- `Tab` and `Shift+Tab` move focus to and from the native button in document order.
|
|
137
|
+
- `Enter` or `Space` activates the button through native button behavior.
|
|
138
|
+
|
|
139
|
+
## Standards
|
|
140
|
+
|
|
141
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
142
|
+
- WAI-ARIA Button pattern: https://www.w3.org/WAI/ARIA/apg/patterns/button/
|
|
143
|
+
- GOV.UK Button guidance: https://design-system.service.gov.uk/components/button/
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Buttons
|
|
2
|
+
|
|
3
|
+
Buttons groups related action controls and gives the collection a shared
|
|
4
|
+
accessible name. Its rendering contract follows the WAI-ARIA Button pattern
|
|
5
|
+
for the grouped native buttons and targets WCAG 2.2 Level AA.
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
Use Buttons when two or more actions belong to the same decision or workflow.
|
|
10
|
+
Keep the primary action first in the expected reading direction and avoid large
|
|
11
|
+
groups that make choices difficult to scan.
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
| PropName | Type | Required | Default | Description |
|
|
16
|
+
|---|---|---:|---:|---|
|
|
17
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves component and state classes. |
|
|
18
|
+
| `ariaLabel` | `string` | no | `"Button group"` | Supplies the group's accessible name. Applications should provide a task-specific label; pass an empty string to omit the group semantics. |
|
|
19
|
+
| `className` | `string` | no | `""` | Adds classes to the group wrapper. |
|
|
20
|
+
| `disabled` | `boolean` | no | - | Disables descendant Pastweb Button components and marks the group unavailable. |
|
|
21
|
+
| `id` | `string` | no | generated | Supplies the group ID. Generated IDs use the `buttons` prefix. |
|
|
22
|
+
|
|
23
|
+
## Mediator state
|
|
24
|
+
|
|
25
|
+
| Property | Type | Description |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `ariaLabel` | `string \| undefined` | Normalized accessible label for the group. Empty labels are omitted. |
|
|
28
|
+
| `isDisabled` | `true \| undefined` | Is `true` when the group is disabled; otherwise omitted. Renderers use this value directly for `.is-disabled` and `aria-disabled`, and the Buttons context shares it with descendant Button mediators. |
|
|
29
|
+
| `role` | `'group' \| undefined` | Is `group` when `ariaLabel` supplies an accessible group name; otherwise omitted. |
|
|
30
|
+
|
|
31
|
+
## Mediator context
|
|
32
|
+
|
|
33
|
+
`buttonsMediator.getContext()` exposes a live value consumed by descendant
|
|
34
|
+
Button mediators.
|
|
35
|
+
|
|
36
|
+
| Property | Type | Description |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `disabled` | `true \| undefined` | Normalized group disabled state combined with each Button's local `disabled` prop. |
|
|
39
|
+
|
|
40
|
+
## Slots
|
|
41
|
+
|
|
42
|
+
| SlotName | Description | Default content |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| default | Supplies the related Button controls in their intended reading and action order. | Empty. |
|
|
45
|
+
|
|
46
|
+
## Utility classes
|
|
47
|
+
|
|
48
|
+
Apply these classes through `className`.
|
|
49
|
+
|
|
50
|
+
| Class | Description |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `is-rounded` | Rounds the group's exposed first and last button corners. |
|
|
53
|
+
| `is-full-width` | Expands the group to the available width and distributes its buttons evenly. |
|
|
54
|
+
|
|
55
|
+
## CSS Variables
|
|
56
|
+
|
|
57
|
+
| Variable | Part | State | CSS property | Default | Description | Platforms |
|
|
58
|
+
|---|---|---|---|---|---|---|
|
|
59
|
+
| `--pw_Buttons_root_default_margin` | `root` | `default` | `margin` | `var(--pw_margin)` | Group outer spacing. | Web, Capacitor, NativeScript |
|
|
60
|
+
| `--pw_Buttons_root_default_border-radius` | `root` | `default` | `border-radius` | `var(--pw_border-radius)` | Outer button corner radius. | Web, Capacitor, NativeScript |
|
|
61
|
+
| `--pw_Buttons_root_rounded_border-radius` | `root` | `rounded` | `border-radius` | `var(--pw_rounded_border-radius)` | Outer radius for rounded groups. | Web, Capacitor, NativeScript |
|
|
62
|
+
| `--pw_Buttons_color_default_box-shadow` | `color` | `default` | `box-shadow` | `var(--pw_color_box-shadow)` | First-button focus shadow colour. | Web, Capacitor |
|
|
63
|
+
| `--pw_Buttons_inset-color_default_box-shadow` | `inset-color` | `default` | `box-shadow` | `var(--pw_inset_color_box-shadow)` | First-button hover inset shadow colour. | Web, Capacitor |
|
|
64
|
+
| `--pw_Buttons_size_default_box-shadow` | `size` | `default` | `box-shadow` | `var(--pw_size_box-shadow)` | First-button shadow size. | Web, Capacitor |
|
|
65
|
+
|
|
66
|
+
```xts
|
|
67
|
+
import { setContext, useBeforeUnmount, useMediator, withDefaultProps } from '@pastweb/x';
|
|
68
|
+
import { BUTTONS_CONTEXT_KEY, buttonsMediator } from '@pastweb/components-core/Buttons';
|
|
69
|
+
import { DEFAULT_PROPS } from './constants';
|
|
70
|
+
|
|
71
|
+
export function Buttons(props: ButtonsProps) {
|
|
72
|
+
const p = withDefaultProps<ButtonsDefaultProps>(props, DEFAULT_PROPS);
|
|
73
|
+
const m = useMediator<ButtonsMediator>(buttonsMediator, p);
|
|
74
|
+
const s = m.state;
|
|
75
|
+
const c = m.getContext();
|
|
76
|
+
setContext(BUTTONS_CONTEXT_KEY, c);
|
|
77
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div
|
|
81
|
+
id={m.id}
|
|
82
|
+
class={p.cls('Buttons', p.className, { 'is-disabled': s.isDisabled })}
|
|
83
|
+
role={s.role}
|
|
84
|
+
aria-label={s.ariaLabel}
|
|
85
|
+
aria-disabled={s.isDisabled}
|
|
86
|
+
>
|
|
87
|
+
<slot />
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Accessibility notes
|
|
94
|
+
|
|
95
|
+
- The wrapper uses `role="group"` only when `ariaLabel` provides a meaningful
|
|
96
|
+
accessible name. The default is `"Button group"`; both attributes are omitted
|
|
97
|
+
when an empty string is provided explicitly.
|
|
98
|
+
- Buttons retain their normal tab order and native keyboard behavior.
|
|
99
|
+
- Use a toolbar component with documented arrow-key behavior instead when the
|
|
100
|
+
collection represents a persistent application toolbar.
|
|
101
|
+
- Keep one primary call to action in a group. Additional default buttons make
|
|
102
|
+
the next step harder to identify.
|
|
103
|
+
|
|
104
|
+
## Standards
|
|
105
|
+
|
|
106
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
107
|
+
- WAI-ARIA Button pattern: https://www.w3.org/WAI/ARIA/apg/patterns/button/
|
|
108
|
+
- GOV.UK Button guidance: https://design-system.service.gov.uk/components/button/
|