@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,188 @@
|
|
|
1
|
+
# Walktour
|
|
2
|
+
|
|
3
|
+
Walktour guides a user through an ordered set of targets. The core package owns
|
|
4
|
+
the browser-portable state machine: navigation, controlled or uncontrolled
|
|
5
|
+
visibility, target measurement, event handling, step options, geometry
|
|
6
|
+
calculation, and interaction decisions. A framework renderer renders
|
|
7
|
+
`WalktourState`.
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
Use Walktour for optional, short orientation flows that help people discover a
|
|
12
|
+
feature or a changed workflow. Keep each step focused on one action. Do not use
|
|
13
|
+
it for essential instructions, errors, or information a user must be able to
|
|
14
|
+
refer back to later; show that content in the interface instead.
|
|
15
|
+
|
|
16
|
+
## Props
|
|
17
|
+
|
|
18
|
+
| PropName | Type | Required | Default | Description |
|
|
19
|
+
|---|---|---:|---:|---|
|
|
20
|
+
| `cls` | `(...args: ClassValue[]) => string` | yes | - | Resolves root and part classes in a renderer. |
|
|
21
|
+
| `steps` | `WalktourStep[]` | yes | - | Ordered guide steps. An empty list renders nothing. |
|
|
22
|
+
| `open` | `boolean` | no | `false` | Controlled visibility. Omit for mediator-managed visibility. |
|
|
23
|
+
| `initialStepIndex` | `number` | no | `0` | Initial zero-based step for `open()`. Out-of-range values are clamped. |
|
|
24
|
+
| `className` | `string` | no | `''` | Additional root classes. |
|
|
25
|
+
| `zIndex` | `number` | no | `1000` | Overlay stacking level used by web renderers. |
|
|
26
|
+
| `maskPadding` | `number` | no | `8` | Space around a target highlight in pixels. |
|
|
27
|
+
| `maskRadius` | `number` | no | `6` | Highlight corner radius in pixels. |
|
|
28
|
+
| `offset` | `number` | no | `12` | Gap between a target and the tour card in pixels. |
|
|
29
|
+
| `placement` | `WalktourPlacement` | no | `'bottom'` | Default card placement. |
|
|
30
|
+
| `disableMask` | `boolean` | no | - | Hides the dimmed mask and spotlight. |
|
|
31
|
+
| `disableMaskInteraction` | `boolean` | no | - | Prevents interaction with the highlighted target. |
|
|
32
|
+
| `closeOnMaskClick` | `boolean` | no | - | Lets an eligible mask activation close the tour. |
|
|
33
|
+
| `closeOnEscape` | `boolean` | no | `true` | Lets Escape close an eligible tour step. |
|
|
34
|
+
| `scrollIntoView` | `boolean` | no | `true` | Asks web renderers to scroll the current target into view. |
|
|
35
|
+
| `nextLabel` | `string` | no | `'Next'` | Default next control label. The last step uses `Finish`. |
|
|
36
|
+
| `previousLabel` | `string` | no | `'Back'` | Default previous control label. |
|
|
37
|
+
| `closeLabel` | `string` | no | `'Skip'` | Default close control label. |
|
|
38
|
+
| `onOpenChange` | `(open: boolean) => void` | no | - | Reports requested visibility changes. |
|
|
39
|
+
| `onStepChange` | `(index, step) => void` | no | - | Reports a completed step change. |
|
|
40
|
+
| `onComplete` | `() => void` | no | - | Runs before the final step closes. |
|
|
41
|
+
| `onClose` | `() => void` | no | - | Runs whenever the mediator requests closure. |
|
|
42
|
+
|
|
43
|
+
`WalktourPlacement` is `'top' | 'right' | 'bottom' | 'left' | 'center'`.
|
|
44
|
+
When a target cannot be resolved, the card uses the centred placement.
|
|
45
|
+
|
|
46
|
+
## Core usage
|
|
47
|
+
|
|
48
|
+
Pass a framework-neutral element reference for every step that should highlight
|
|
49
|
+
an element. The reference must expose its current element through `value`.
|
|
50
|
+
Steps without `ref` intentionally render as centred, targetless steps.
|
|
51
|
+
|
|
52
|
+
```xts
|
|
53
|
+
const saveButton = ref<HTMLElement | null>(null);
|
|
54
|
+
|
|
55
|
+
const steps: WalktourStep[] = [
|
|
56
|
+
{
|
|
57
|
+
ref: saveButton,
|
|
58
|
+
title: 'Save changes',
|
|
59
|
+
description: 'Select Save when you are ready to publish your updates.',
|
|
60
|
+
placement: 'top',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
title: 'You are ready',
|
|
64
|
+
description: 'Your changes can now be reviewed.',
|
|
65
|
+
placement: 'center',
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The core component is renderer-neutral. A framework package maps its own ref
|
|
71
|
+
type to this contract and is responsible only for rendering `WalktourState`.
|
|
72
|
+
|
|
73
|
+
## Step options
|
|
74
|
+
|
|
75
|
+
| Property | Type | Description |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `ref` | `{ value: HTMLElement \| null }` | Framework-neutral element reference. Omit it for a centred, targetless step. React adapters accept `RefObject<HTMLElement \| null>`. |
|
|
78
|
+
| `title` / `description` | renderer content | Content rendered by the framework adapter. `description` is required. |
|
|
79
|
+
| `placement`, `maskPadding`, `maskRadius`, `offset` | step override | Override the matching component default for this step. |
|
|
80
|
+
| `nextLabel`, `previousLabel`, `closeLabel` | `string` | Override a control label for this step. |
|
|
81
|
+
| `disableNext`, `disablePrevious`, `disableClose` | `boolean` | Removes the matching navigation action. |
|
|
82
|
+
| `nextOnTargetClick` | `boolean` | Advances through the mediator when the renderer reports a target activation. |
|
|
83
|
+
|
|
84
|
+
## Renderer implementation
|
|
85
|
+
|
|
86
|
+
`walktourMediator` composes reactive state and effects. Stateless helpers in
|
|
87
|
+
`utils/` perform navigation, state updates, geometry calculation, target
|
|
88
|
+
resolution, and listener setup with explicit props, state, and mutable vars.
|
|
89
|
+
This keeps those helpers reusable and avoids creating internal action factories
|
|
90
|
+
for every Walktour instance.
|
|
91
|
+
|
|
92
|
+
The mediator resolves the active target reference, measures the target element,
|
|
93
|
+
subscribes to resize, scroll, keyboard, and target-click events, and cleans
|
|
94
|
+
them up when unmounted. A browser framework renderer creates the mediator,
|
|
95
|
+
connects its lifecycle methods, and renders the mediator state:
|
|
96
|
+
|
|
97
|
+
```xts
|
|
98
|
+
import { Render, useBeforeUnmount, useMediator, useMounted, withDefaultProps } from '@pastweb/x';
|
|
99
|
+
import { DEFAULT_PROPS, walktourMediator } from '@pastweb/components-core/Walktour';
|
|
100
|
+
|
|
101
|
+
export function Walktour(props: WalktourProps) {
|
|
102
|
+
const p = withDefaultProps<WalktourDefaultProps>(props, DEFAULT_PROPS);
|
|
103
|
+
const m = useMediator<WalktourMediator>(walktourMediator, p);
|
|
104
|
+
const s = m.state;
|
|
105
|
+
|
|
106
|
+
useMounted(m.useMounted);
|
|
107
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
108
|
+
|
|
109
|
+
if (!s.isOpen || !s.step) return null;
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div class={p.cls('Walktour', p.className)} #style={{ zIndex: p.zIndex }} aria-live="polite">
|
|
113
|
+
<fragment #if={s.isMaskVisible && s.hole}>
|
|
114
|
+
<button class={p.cls('maskPiece')} type="button" tabindex={-1} aria-hidden="true"
|
|
115
|
+
#style={{ top: 0, left: 0, right: 0, height: s.hole.top }} @click={m.onMaskClick} />
|
|
116
|
+
<button class={p.cls('maskPiece')} type="button" tabindex={-1} aria-hidden="true"
|
|
117
|
+
#style={{ top: s.hole.bottom, left: 0, right: 0, bottom: 0 }} @click={m.onMaskClick} />
|
|
118
|
+
<button class={p.cls('maskPiece')} type="button" tabindex={-1} aria-hidden="true"
|
|
119
|
+
#style={{ top: s.hole.top, left: 0, width: s.hole.left, height: s.hole.bottom - s.hole.top }} @click={m.onMaskClick} />
|
|
120
|
+
<button class={p.cls('maskPiece')} type="button" tabindex={-1} aria-hidden="true"
|
|
121
|
+
#style={{ top: s.hole.top, left: s.hole.right, right: 0, height: s.hole.bottom - s.hole.top }} @click={m.onMaskClick} />
|
|
122
|
+
<div class={p.cls('spotlight')} #style={{
|
|
123
|
+
top: s.hole.top, left: s.hole.left, width: s.hole.right - s.hole.left,
|
|
124
|
+
height: s.hole.bottom - s.hole.top, borderRadius: s.maskRadius,
|
|
125
|
+
pointerEvents: s.isTargetInteractionDisabled ? 'auto' : 'none',
|
|
126
|
+
}} @click={s.isTargetInteractionDisabled ? m.onMaskClick : undefined} />
|
|
127
|
+
</fragment>
|
|
128
|
+
<button #if={s.isMaskVisible && !s.hole} class={p.cls('maskPiece')}
|
|
129
|
+
type="button" tabindex={-1} aria-hidden="true" #style={{ inset: 0 }} @click={m.onMaskClick} />
|
|
130
|
+
<section class={p.cls('card')} #style={s.cardPosition} role="dialog" aria-modal="true"
|
|
131
|
+
aria-label={typeof s.step.title === 'string' ? s.step.title : 'Guided tour'}>
|
|
132
|
+
<h2 #if={s.step.title} class={p.cls('title')}><Render content={s.step.title} /></h2>
|
|
133
|
+
<div class={p.cls('description')}><Render content={s.step.description} /></div>
|
|
134
|
+
<footer class={p.cls('footer')}>
|
|
135
|
+
<span class={p.cls('progress')}>{s.stepIndex + 1} / {p.steps.length}</span>
|
|
136
|
+
<button #if={s.canClose} class={p.cls('button')} type="button" @click={m.close}>{s.closeLabel}</button>
|
|
137
|
+
<button #if={s.canPrevious} class={p.cls('button')} type="button" @click={m.previous}>{s.previousLabel}</button>
|
|
138
|
+
<button #if={s.canNext} class={p.cls('button')} type="button" @click={m.next}>{s.nextLabel}</button>
|
|
139
|
+
</footer>
|
|
140
|
+
</section>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The mediator exposes `open`, `close`, `next`, and `previous`, plus lifecycle
|
|
147
|
+
methods. It performs all clamping, callback invocation, per-step option
|
|
148
|
+
precedence, target measurement, scrolling, and close eligibility checks.
|
|
149
|
+
|
|
150
|
+
## Mediator state
|
|
151
|
+
|
|
152
|
+
| Property | Description |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `isOpen`, `stepIndex`, `step` | Visibility and current resolved step. |
|
|
155
|
+
| `targetRect`, `hole` | Target and viewport-clipped mask geometry. |
|
|
156
|
+
| `cardPosition` | Renderer-ready `top`, `left`, and `transform` card position. |
|
|
157
|
+
| `maskPadding`, `maskRadius` | Resolved visual values for the active step. |
|
|
158
|
+
| `isMaskVisible`, `isTargetInteractionDisabled` | Resolved mask interaction state. |
|
|
159
|
+
| `canClose`, `canPrevious`, `canNext` | Renderer-ready control availability. |
|
|
160
|
+
| `closeLabel`, `previousLabel`, `nextLabel` | Renderer-ready active-step labels. |
|
|
161
|
+
|
|
162
|
+
## CSS Variables
|
|
163
|
+
|
|
164
|
+
| Variable | Part | Default | Description |
|
|
165
|
+
|---|---|---|---|
|
|
166
|
+
| `--pw_Walktour_mask_default_background-color` | mask | `rgba(0, 0, 0, 0.5)` | Dimmed overlay colour. |
|
|
167
|
+
| `--pw_Walktour_card_default_background-color` | card | `var(--pw_background-color)` | Card background. |
|
|
168
|
+
| `--pw_Walktour_card_default_color` | card | `var(--pw_text_color)` | Card text colour. |
|
|
169
|
+
| `--pw_Walktour_card_default_border-radius` | card | `var(--pw_border-radius)` | Card corner radius. |
|
|
170
|
+
| `--pw_Walktour_card_default_box-shadow` | card | elevation shadow | Card elevation. |
|
|
171
|
+
| `--pw_Walktour_step_default_transition-duration` | mask, spotlight, card | `320ms` | Geometry transition duration between steps. |
|
|
172
|
+
|
|
173
|
+
Web styles honour `prefers-reduced-motion` by disabling the step transition.
|
|
174
|
+
|
|
175
|
+
Portal integration is application-specific and belongs in a framework or app
|
|
176
|
+
wrapper, not in this core renderer contract.
|
|
177
|
+
|
|
178
|
+
## Accessibility notes
|
|
179
|
+
|
|
180
|
+
- Web renderers expose the card as a labelled modal dialog and announce changes
|
|
181
|
+
through a polite live region.
|
|
182
|
+
- Escape is handled through `onKeyDown` only when `closeOnEscape` and
|
|
183
|
+
`canClose` are both true.
|
|
184
|
+
- Renderers should make mask controls non-focusable or otherwise ensure they do
|
|
185
|
+
not add unnecessary tab stops.
|
|
186
|
+
- A step without a target remains usable because the card is centred.
|
|
187
|
+
- Native renderers should provide an equivalent mediator implementation for
|
|
188
|
+
their native target, viewport, scrolling, and accessibility APIs.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# WindowController
|
|
2
|
+
|
|
3
|
+
WindowController presents either a modal dialog or a movable floating work
|
|
4
|
+
surface. Its rendering contract follows the WAI-ARIA Dialog pattern and targets
|
|
5
|
+
WCAG 2.2 Level AA.
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
Use a modal window when the user must complete or dismiss a task before
|
|
10
|
+
continuing. Use a floating window for a parallel work surface that does not
|
|
11
|
+
block the rest of the page.
|
|
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 | `"Window"` | Accessible dialog name. |
|
|
19
|
+
| `portal` | `Portal` | no | - | Portal configuration. |
|
|
20
|
+
| `portalElement` | `HTMLElement` | no | - | Portal container. |
|
|
21
|
+
| `entryId` | `string` | no | - | Portal entry ID. |
|
|
22
|
+
| `manager` | `WindowManager` | no | - | Application manager for shared state, visibility, focus, bounds, and taskbar behavior. |
|
|
23
|
+
| `getTaskBarButtonBounds` | `(id) => WindowBounds \| undefined` | no | - | Supplies the matching taskbar button bounds for minimize and restore animation. |
|
|
24
|
+
| `mode` | `'modal' \| 'floating'` | no | `'modal'` | Dialog modality and movement behavior. |
|
|
25
|
+
| `moveCursor` | `boolean` | no | `true` | Enables the move cursor in floating mode. |
|
|
26
|
+
| `resizable` | `boolean` | no | - | Enables resize handles and `is-resizable`. |
|
|
27
|
+
| `resizeCursor` | `boolean` | no | `true` | Enables resize cursors. |
|
|
28
|
+
| `width` | `number` | no | - | Initial width in pixels. |
|
|
29
|
+
| `height` | `number` | no | - | Initial height in pixels. |
|
|
30
|
+
| `animation` | `Animation` | no | `zoom` | Entry and exit animation. |
|
|
31
|
+
| `closeOnBackdropClick` | `boolean` | no | `true` | Dismisses a modal from the backdrop. |
|
|
32
|
+
| `closeOnEscape` | `boolean` | no | `true` | Dismisses on `Escape` unless the consumer prevents the event. |
|
|
33
|
+
| `onClose` | `() => void` | no | noop | Reports completed close. |
|
|
34
|
+
| `onKeyDown` | `(event) => void` | no | noop | Observes keyboard input. |
|
|
35
|
+
|
|
36
|
+
## Window context
|
|
37
|
+
|
|
38
|
+
Projected window content can read `WindowContext` to control its own window.
|
|
39
|
+
`manager` in this context is the current `ManagedWindowState`, not the manager
|
|
40
|
+
instance. The application-owned `WindowManager` remains available to the
|
|
41
|
+
portal/controller through the `manager` prop.
|
|
42
|
+
|
|
43
|
+
| Member | Description |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `close(options?)` | Requests closure through the portal lifecycle. |
|
|
46
|
+
| `bringToFront(activate?)` | Reveals and brings the window forward. Pass `false` while dragging or resizing to preserve its active position. |
|
|
47
|
+
| `hide()` / `show()` | Hides or reveals the window. Managed windows update the manager's reactive `isHidden` state; unmanaged windows use local controller state. |
|
|
48
|
+
| `minimize()` | Reveals and minimizes the managed window. Returns `false` without a manager. |
|
|
49
|
+
| `maximize()` | Toggles a managed window between the portal workspace bounds and its previous bounds. Returns `false` without a manager or workspace. |
|
|
50
|
+
| `isActive` | Indicates whether this window is active in its manager. |
|
|
51
|
+
| `manager` | Current immutable `ManagedWindowState`, including `status`, `bounds`, and `isHidden`. |
|
|
52
|
+
|
|
53
|
+
The manager is optional. Existing modal and floating windows continue to work
|
|
54
|
+
without one; manager-specific commands then return `false`.
|
|
55
|
+
|
|
56
|
+
Managed floating windows apply the current `manager.bounds` to their rendered
|
|
57
|
+
position and size. The portal host should therefore cover the intended
|
|
58
|
+
workspace (for example, an absolutely positioned full-layout anchor); a
|
|
59
|
+
zero-sized host causes windows to be measured from the top-left corner.
|
|
60
|
+
|
|
61
|
+
Modal renderers must contain focus, restore prior focus, expose `aria-modal`,
|
|
62
|
+
and include an obvious close control in the projected content. Floating
|
|
63
|
+
renderers must not begin a drag from interactive descendants; use
|
|
64
|
+
`data-window-no-drag` for custom interactive regions.
|
|
65
|
+
|
|
66
|
+
## XTS rendering contract
|
|
67
|
+
|
|
68
|
+
```xts
|
|
69
|
+
import {
|
|
70
|
+
setContext,
|
|
71
|
+
useBeforeUnmount,
|
|
72
|
+
useMediator,
|
|
73
|
+
useMounted,
|
|
74
|
+
useRef,
|
|
75
|
+
withDefaultProps,
|
|
76
|
+
} from '@pastweb/x';
|
|
77
|
+
import {
|
|
78
|
+
MODE,
|
|
79
|
+
WINDOW_CONTEXT_KEY,
|
|
80
|
+
windowControllerMediator,
|
|
81
|
+
} from '@pastweb/components-core/WindowController';
|
|
82
|
+
import { DEFAULT_PROPS } from './constants';
|
|
83
|
+
|
|
84
|
+
export function WindowController(props: WindowControllerProps) {
|
|
85
|
+
const p = withDefaultProps<WindowControllerDefaultProps>(props, DEFAULT_PROPS);
|
|
86
|
+
const m = useMediator<WindowControllerMediator>(windowControllerMediator, p);
|
|
87
|
+
const s = m.state;
|
|
88
|
+
const c = m.getContext();
|
|
89
|
+
const windowReference = useRef(null);
|
|
90
|
+
|
|
91
|
+
setContext(WINDOW_CONTEXT_KEY, c);
|
|
92
|
+
useMounted(() => {
|
|
93
|
+
if (windowReference.value) m.onMounted(windowReference.value);
|
|
94
|
+
});
|
|
95
|
+
useBeforeUnmount(m.useBeforeUnmount);
|
|
96
|
+
|
|
97
|
+
const className = p.cls(
|
|
98
|
+
p.mode === MODE.floating ? 'window' : 'modal',
|
|
99
|
+
{
|
|
100
|
+
[`${p.animation.name}-in`]: s.isOpen && !s.manager,
|
|
101
|
+
[`${p.animation.name}-out`]: !s.isOpen,
|
|
102
|
+
'is-managed': !!s.manager,
|
|
103
|
+
'is-hide': s.isHidden || s.manager?.isHidden,
|
|
104
|
+
'is-maximised': s.manager?.status === 'maximized',
|
|
105
|
+
'is-minimised': s.manager?.status === 'minimized',
|
|
106
|
+
'is-resizable': p.resizable,
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return p.mode === MODE.floating ? (
|
|
111
|
+
<div
|
|
112
|
+
#ref={windowReference}
|
|
113
|
+
class={className}
|
|
114
|
+
style={m.getAnimationStyle()}
|
|
115
|
+
role='dialog'
|
|
116
|
+
aria-label={p.ariaLabel}
|
|
117
|
+
tabIndex={-1}
|
|
118
|
+
@mousedown={() => c.bringToFront()}
|
|
119
|
+
@keydown={m.onKeyDown}
|
|
120
|
+
>
|
|
121
|
+
<slot />
|
|
122
|
+
</div>
|
|
123
|
+
) : (
|
|
124
|
+
<div class={p.cls('WindowController', { 'is-hide': s.isHidden || s.manager?.isHidden })}>
|
|
125
|
+
<button
|
|
126
|
+
type='button'
|
|
127
|
+
class={p.cls('backdrop')}
|
|
128
|
+
tabIndex={-1}
|
|
129
|
+
aria-hidden='true'
|
|
130
|
+
@click={m.onBackdropClick}
|
|
131
|
+
/>
|
|
132
|
+
<div
|
|
133
|
+
#ref={windowReference}
|
|
134
|
+
class={className}
|
|
135
|
+
style={m.getAnimationStyle()}
|
|
136
|
+
role='dialog'
|
|
137
|
+
aria-modal='true'
|
|
138
|
+
aria-label={p.ariaLabel}
|
|
139
|
+
tabIndex={-1}
|
|
140
|
+
@mousedown={() => c.bringToFront()}
|
|
141
|
+
@keydown={m.onKeyDown}
|
|
142
|
+
>
|
|
143
|
+
<slot />
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The controller publishes `WindowContext` before projected content renders, so a
|
|
151
|
+
Panel or custom child can call `close`, `hide`, `show`, `minimize`, `maximize`,
|
|
152
|
+
or `bringToFront` through the framework context hook.
|
|
153
|
+
|
|
154
|
+
## Keyboard interaction
|
|
155
|
+
|
|
156
|
+
- Focus moves to the dialog when mounted.
|
|
157
|
+
- `Escape` closes when `closeOnEscape` is enabled.
|
|
158
|
+
- Modal windows keep `Tab` and `Shift+Tab` inside their focusable content.
|
|
159
|
+
- Focus returns to the previously focused element when unmounting.
|
|
160
|
+
|
|
161
|
+
## Accessibility notes
|
|
162
|
+
|
|
163
|
+
- The web renderer exposes a named `dialog`. `aria-modal` is set only in modal
|
|
164
|
+
mode.
|
|
165
|
+
- The backdrop is a native `button` excluded from the tab order and
|
|
166
|
+
accessibility tree.
|
|
167
|
+
- Dragging ignores buttons, links, form controls, and `[data-window-no-drag]`.
|
|
168
|
+
- Shared web styles keep a visible `:focus-visible` indicator and disable
|
|
169
|
+
non-essential motion under `prefers-reduced-motion`.
|
|
170
|
+
|
|
171
|
+
## Known limitations
|
|
172
|
+
|
|
173
|
+
- Nested windows require distinct labels so dialog announcements remain
|
|
174
|
+
understandable.
|
|
175
|
+
- A modal window still depends on its content to provide a visible close
|
|
176
|
+
control.
|
|
177
|
+
- Automated accessibility checks do not by themselves establish WCAG
|
|
178
|
+
conformance.
|
|
179
|
+
|
|
180
|
+
## Native renderer mapping
|
|
181
|
+
|
|
182
|
+
NativeScript maps the window to an accessible modal or floating native
|
|
183
|
+
container, uses native focus containment and restoration, and maps back-button
|
|
184
|
+
dismissal to the same close intent.
|
|
185
|
+
|
|
186
|
+
## Standards
|
|
187
|
+
|
|
188
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
189
|
+
- WAI-ARIA Dialog (Modal) pattern: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
|
|
190
|
+
- GOV.UK components: https://design-system.service.gov.uk/components/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pastweb/components-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A components tools package.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
"author": "Domenico Pasto",
|
|
16
16
|
"funding": "https://github.com/sponsors/pastweb",
|
|
17
17
|
"files": [
|
|
18
|
-
"./dist"
|
|
18
|
+
"./dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
19
21
|
],
|
|
20
22
|
"main": "./dist/index.cjs",
|
|
21
23
|
"module": "./dist/index.mjs",
|
|
@@ -1824,6 +1826,7 @@
|
|
|
1824
1826
|
"require": "./dist/WindowController/windowController.mediator.cjs"
|
|
1825
1827
|
},
|
|
1826
1828
|
"./package.json": "./package.json",
|
|
1829
|
+
"./*/README.md": "./dist/*/README.md",
|
|
1827
1830
|
"./*.scss": {
|
|
1828
1831
|
"import": "./dist/*.scss",
|
|
1829
1832
|
"require": "./dist/*.scss",
|