@nice2dev/ui-buildings 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,438 @@
1
1
  # @nice2dev/ui-buildings
2
2
 
3
+ ## 1.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @nice2dev/spatial-core@1.3.1
8
+
9
+ ## 1.3.0
10
+
11
+ ### Patch Changes
12
+
13
+ - ada5a2d: Keyboard, gamepad and remote input for every Nice control (TODO_1.3.0, ADR-005).
14
+
15
+ - `@nice2dev/ui-core` gets the input layer, also as its own entry `@nice2dev/ui-core/input`:
16
+ one engine per page that turns keys, pad buttons and remote keys into intents (`navigate`,
17
+ `activate`, `back`, `secondary`, `tertiary`, `menu`, `view`, `sectionPrev` / `sectionNext`,
18
+ `pagePrev` / `pageNext`, `first` / `last`, `scroll`, `toggleHints`). No animation frame without a
19
+ pad; changes only, no re-render per frame; repeat with acceleration, stick hysteresis, several
20
+ pads, Xbox / PlayStation / Nintendo / Steam / generic families (Nintendo confirms with the right
21
+ button). Pads also emulate the matching key on the focused element, so controls with a keyboard
22
+ pattern work with a pad as they are.
23
+ - Focus without registration: spatial moves between tabbable elements, focus scopes
24
+ (`useFocusScope`, `<NiceFocusScope>`) with memory, wrapping, traps and escalation at an edge,
25
+ regions for F6 / Select, focus recovery when the focused element disappears. Value controls are
26
+ engaged first on a pad (`useEngage`): the d-pad passes them by until A.
27
+ - `useRovingFocus` (APG keys, 1-D and 2-D, typeahead, RTL), `useOverlayFocus` (initial focus,
28
+ trap, Escape / B, overlay stack, return to the opener), `useIntent`, `useInputMethod`,
29
+ `useGamepadFamily`, `useInputPreferences`, `NiceInputProvider` (preferences persisted in
30
+ `NiceUserPreferences` as `global.input`; `useUserPreferencesOptional` added).
31
+ - `@nice2dev/testing`: `mockGamepad()` with a controlled frame clock, `pressKey()`,
32
+ `pressIntent()`, `describeInputContract()` / `runInputContract()`, `stubLayout()` /
33
+ `stubGridLayout()` for jsdom.
34
+ - Focus visibility: in pad and remote modes the ring shows on plain `:focus` (the browsers'
35
+ `:focus-visible` heuristics miss focus moved by a pad); an engaged control wears
36
+ `--nice-focus-ring-engaged`; `scroll-padding` on the root from `--nice-scroll-padding-top` /
37
+ `-bottom`. `NiceDisplayValue` drew no ring: its outline used the box-shadow token as a colour.
38
+ - The old APIs are layers over the engine and `@deprecated` (removal only in a breaking release):
39
+ `useGamepad` reads the engine's frames — no animation loop of its own and no render per frame;
40
+ `NiceSpatialNavProvider` takes intents instead of a `window` keydown listener, so it no longer
41
+ steals the arrow keys of text fields; `useRovingTabIndex` runs on `useRovingFocus` (2-D in
42
+ `grid`); `createNavigationActions` fires once per stick push instead of every frame.
43
+ - Button prompts (B1–B4, B6, B7): 41 glyphs of pad buttons (Xbox, PlayStation, Nintendo, generic
44
+ positions), bumpers, triggers, d-pad, sticks, remote keys and the macOS key symbols — outline
45
+ built-ins of `NiceIcon` and filled, coloured `Ntd*` icons of `@nice2dev/icons` under the same
46
+ names (`pad-xbox-a` → `NtdPadXboxA`); `NiceKeyCap` (words translated, arrows and ⌘ ⌥ ⇧ as
47
+ glyphs); `NiceButtonPrompt` (the button or key of an intent for the device in use, the pad
48
+ family and the user's bindings); `NiceInputHintBar` + `useInputHints` (the actions of the focus
49
+ path); `useNiceAction` (application actions with a key, a pad intent, a scope, `when`,
50
+ `aria-keyshortcuts`, conflict warnings) and `useNiceActions` / `triggerNiceAction` for command
51
+ palettes. `NiceKeyboardHint` is reachable with Tab, draws an icon instead of "?", keycaps, and
52
+ the pad button of shortcuts that carry an `intent` (`COMMON_SHORTCUTS` do); `NiceSkipLink`
53
+ translates its default text. 64 dictionary keys in six languages.
54
+ - `NiceDeviceManager`, the karaoke pad player, the note particles (ui-audio) and the model viewer
55
+ (ui-3d) read pads through the engine (`getInputEngine().gamepadSnapshot`,
56
+ `useConnectedGamepads`). `@nice2dev/ui` re-exports the app-facing part of the input layer.
57
+ - `NiceInputSettings` (new): the input preferences and the rebinding of every intent to keys or a
58
+ pad button, captured from the next press. `NiceCommandPalette` opens on the `menu` intent
59
+ (Ctrl+K, Start, the remote's menu key), keeps focus inside, moves with the d-pad, runs with A
60
+ and lists the `useNiceAction` actions (`includeActions`, default on).
61
+ - Shells are focus scopes (D1, D2): `NiceNavShell`, `NiceAppShell` and the shells of
62
+ `NiceShells` move with the arrows and the d-pad, have F6 / Select regions, switch sections with
63
+ LB / RB and show the hint bar in pad mode (`hintBar`: `bottom` by default, `top`, `none`).
64
+ `NiceNavShell` gets an APG tab strip with a tab menu and moving tabs without dragging
65
+ (Ctrl+Shift+← →), moves focus into the new page after navigating (`focusContentOnNavigate`),
66
+ remembers focus per route and announces the page; `contentArrows: 'native'` gives the arrows
67
+ back to the page.
68
+ - Tabs (C6): every tab list moves with ← → Home End and the d-pad (`useRovingFocus`, also new
69
+ `activateOnMove`). `NiceTabs` links each tab to its panel (`aria-controls` /
70
+ `aria-labelledby`), sets `aria-orientation`, switches with LB / RB in its scope and shows those
71
+ prompts with `showHints`. `NiceCarousel` moves between its dots; ← → on the carousel go on to
72
+ the page at an end without wrapping. The sheet buttons of `NiceSpreadsheet` and the tabs of
73
+ `NiceMobileTabs` are now `role="tab"` with `aria-selected` (they were buttons with
74
+ `aria-pressed` — tests that look them up as buttons must look up tabs); stepping onto "More"
75
+ does not open its sheet.
76
+ - Overlays (C12): every modal, drawer, sheet, popover, lightbox, picker popup and confirmation
77
+ runs on `useOverlayFocus`. Escape / B close only the top overlay — they listened on the
78
+ document before, so one Escape closed every open overlay at once — and focus returns to the
79
+ element that opened it. `useFocusTrap` runs on `useOverlayFocus` (it took its element list
80
+ once, so elements added later broke the trap); a modal no longer pulls focus back from a popup
81
+ opened above it (a select's list portalled after it). An overlay that can be closed shows
82
+ "B Close" in the hint bar (`closeHint`); `useInputHints` takes several publishers per element
83
+ (`fallback` hints give way). Consent dialogs (`NiceCookieConsent`, `NiceGDPRConsent`) keep focus
84
+ until answered. `NiceLightbox`, the mobile `NiceImageGallery`, both print previews and
85
+ `NiceTutorial` take LB / RB (and LT / RT for zoom) on a pad; their keys listen on the overlay
86
+ instead of the window. The context menus (`NiceOverlayContextMenu`, `NiceTouchMenuPopover`)
87
+ open from the menu key, Shift+F10 and X, move with the arrows and letters, and a submenu
88
+ closes on ← / Escape alone. `NiceWindowManager` / `NiceWindow`: windows are F6 / View regions,
89
+ raised when focus enters them, and the taskbar moves with the arrows. `NiceCommandBar` gets
90
+ `aria-activedescendant` and unique ids. The raw glyphs used as icons in `NiceTutorial`, the
91
+ print preview of `@nice2dev/ui-printing` and `NiceGlobalSearch` are `NiceIcon` / `NiceKeyCap`.
92
+ - Menus (C7): `useMenuButton` (new) — ↓ / ↑ on the trigger open the menu on its first / last
93
+ item, the arrows, Home End and letters move, Enter / Space activate items that are not buttons,
94
+ Escape / B, focus leaving and a press outside close it, and a pad's d-pad moves past the trigger
95
+ (A opens). It runs `NiceDropDownButton`, `NiceSpeedDialAction`, `NiceUserMenu`, the extra-action
96
+ menus of `NiceTopNav`, `NiceHamburgerMenu`, the desktop Start menu and the "Open" menu of
97
+ `NiceThemeBuilder`. `NiceUserMenu` and the `NiceTopNav` action menus closed 200 / 180 ms after
98
+ their button lost focus, so focus could never move into them. `NiceTopMenu` is an APG menubar;
99
+ `NiceNavMenu` moves focus into an opened panel (it never did), adds Home / End, moves in two
100
+ dimensions in a mega panel and opens / closes its flyouts from the keyboard; panels opened by
101
+ hovering leave focus where it is. The closed panel of `NiceHamburgerMenu` is inert (Tab reached
102
+ its hidden items). The quick settings of `NiceDeviceTile` are a `dialog`, not a `menu`.
103
+ - Select lists (C3): with the default `searchable`, `NiceSelect` moved focus into a search
104
+ field that had no keys — the list could not be used from the keyboard at all. The field and the
105
+ trigger now share the keys (↑ ↓ PageUp PageDown, Home / End on the trigger, Enter, Escape), the
106
+ list opens on the selected option, names the highlighted one (`aria-activedescendant`), keeps
107
+ it in view and gives focus back to the trigger after a pick; a pad moves and picks in the field.
108
+ The same for `NiceLookup`, `NiceCountryPicker`, `NiceLanguagePicker` and `NiceThemePicker`
109
+ (after a pick from their search field focus was lost to the page), `NiceAutocomplete`,
110
+ `NiceMention` and `NiceSearchInput`. A select open inside a modal now closes alone on Escape.
111
+ `useOverlayFocus` takes `initialFocus: 'none'` and returns focus to the element focused before
112
+ an `autoFocus` child took it.
113
+ - Lists (C8): every list of items is an APG listbox with one tab stop — the arrows, Home End,
114
+ PageUp PageDown and letters move, Enter / Space (A on a pad) pick: `NiceList` (one listbox with
115
+ groups too), both columns of `NicePickList`, `NiceRevisionHistory`, `NiceTaskInbox` and both
116
+ panels of `NiceReconciliationView` (Space picks a row, Enter opens its details as a double
117
+ click does; its rows were `role="row"`, each a tab stop, and `focusStatements()` /
118
+ `focusEntries()` focused nothing). The fields with a list of suggestions drive it from the field
119
+ (`aria-activedescendant`) and with a pad: `NiceTagBox` (a list opened by focus alone has no
120
+ highlight, so Enter still submits a form), `NiceTagInput` (a combobox only with `suggestions`),
121
+ `NiceAccountPicker`, `NiceContactPicker`, `NiceCommandBar` and `NiceGlobalSearch` (Enter and the
122
+ pad took the result from before the filter). The dropdowns of `NiceModeSelector` and
123
+ `NiceDisplayStylePicker` are select-only comboboxes that open on the current item. These fields
124
+ and triggers are `role="combobox"` now — tests that look them up as textboxes or buttons must
125
+ look up comboboxes. Each column of `NiceCascadeSelect` is a listbox: → / Enter go into an
126
+ option's children, ← back; it opens on the selected path and Escape returns focus to the
127
+ trigger. The panel of `NiceIconPicker` is a dialog on the overlay stack (it listened for Escape
128
+ on the document) with a two-dimensional icon grid. The time columns of the `NiceDateTimePicker`
129
+ popup are spinbuttons (Home / End, PageUp / PageDown); the wheel beside them is for the pointer.
130
+ The palette of `NiceWorkflowDesigner` inserts an element on Enter / Space.
131
+ - Trees (C9): `useTreeFocus` (new, also exported from `@nice2dev/ui`) — the APG tree view on
132
+ nested or flat (`aria-level`) trees: one tab stop, ↑ ↓ Home End and letters move, → opens an
133
+ item or enters it, ← closes it or goes to its parent, `*` opens the siblings; Enter / Space and
134
+ a pad's A click the item's row and a pad's X / Shift+F10 open its context menu, so the
135
+ components keep their click handlers. `NiceTreeView` (the items had only the pointer; F2 edits
136
+ and focus comes back after the edit; its context menu is a real menu with focus in it and
137
+ Escape back to the item), `NiceTreeSelect` (↓ / ↑ / Enter on the field open the tree with
138
+ focus in it, ↓ from the search box goes to the tree, a pick returns focus to the field),
139
+ the page tree of `NiceWiki`, the resource tree of `NiceAccessManager` and the mobile tree of
140
+ `NiceTopNav` (each node was two tab stops — its toggle and its link — and the mobile tree had
141
+ `role="tree"` with no items in it).
142
+ - Data grids (C10): `useGridFocus` (new, also exported from `@nice2dev/ui`) — the APG data grid:
143
+ one tab stop, the arrows move by row and column, Home / End along a row, Ctrl+Home / Ctrl+End
144
+ to the corners, PageUp / PageDown by rows; Enter / Space / a pad's A click the cell, and a cell
145
+ holding one control (a header's "toggle all", a row checkbox, a link) is reached on that
146
+ control. `NicePermissionMatrix` (the grants had only the pointer), `NiceModuleGrid` (its cells
147
+ are `gridcell`s now and `role="grid"` sits on the table, no longer on the whole control with
148
+ its toolbar and pagination — tests that look the grid up still find it, by its label too; a
149
+ cell's Enter selects its row, a header's sorts; the mobile cards are a listbox of options, not
150
+ rows), `NiceWarehouseView` (ui-erp; every bin was a tab stop, and a focused bin shows its
151
+ details as a hovered one does). `NiceSpreadsheet` adds Home / End, Ctrl+Home / Ctrl+End and
152
+ PageUp / PageDown.
153
+ - One of several (C4): `NiceSegmentedControl` is a radio group — one tab stop, the arrows (a
154
+ pad's d-pad) move and select; its options were toggle buttons with `aria-pressed`, one tab stop
155
+ each (tests that look them up as pressed buttons must look up checked radios). So are the
156
+ true / false, NPS and star scales of the assessment widgets (`NiceSurvey`, `NiceQuiz`,
157
+ `NicePollLive`). `NiceRadioGroup` and the payment method selector were native radio groups
158
+ already.
159
+ - Sliders (C5): `NiceRangeSlider`'s thumbs had no keys at all — the arrows step, PageUp /
160
+ PageDown take a tenth of the range, Home / End go as far as the thumb may, and they are named
161
+ "Minimum" / "Maximum" with the formatted value as `aria-valuetext`. `NiceKnob`, `NiceTempDial`
162
+ and `NiceRating` add PageUp / PageDown and Home / End; `NiceTempDial` consumes its keys (the
163
+ arrows also scrolled the page, and an engaged pad's d-pad moved focus away instead of stepping).
164
+ - Toolbars (C13): the toolbars of `NiceDocumentEditor`, `NiceImageEditor`, `NicePDFViewer`, the
165
+ file manager, the component playground's canvas and `NiceDock` are one tab stop with the arrows
166
+ along the bar and Home / End between their buttons (their fields and selects keep their own
167
+ keys); they are named, a side dock is a vertical toolbar and a focused dock item magnifies as a
168
+ hovered one does. The file manager's panels name the item under their cursor
169
+ (`aria-activedescendant`) — its rows were no options, so ↑ ↓ moved a cursor no screen reader
170
+ could follow.
171
+ - Dates (C11): `NiceCalendar` is an APG date grid — its days had no keys at all though the hint
172
+ listed them: focus sits on a day (one tab stop), ← → a day, ↑ ↓ a week, Home / End the week,
173
+ PageUp / PageDown a month, Shift+PageUp / PageDown a year, crossing into the next month as
174
+ needed; Enter / Space pick; a pad's LB / RB change the month and LT / RT the year; the month
175
+ and year pickers move in two dimensions and a pick keeps focus in the calendar. The
176
+ `NiceDateTimePicker` field opens its picker with Alt+↓, the context-menu key, Shift+F10 or a
177
+ pad's X (its button is no tab stop), focus on the day; the clock's hour and minute are
178
+ spinbuttons. The single-field `NiceDateRangeBox` opens with Enter / Space / ↓, its popup is on
179
+ the overlay stack (it closed on any Escape on the page) and a picked range returns focus to
180
+ the field. In the engine a read-only text field is not engaged: a pad's A acts as its Enter.
181
+ - Number fields (C2): WAI-ARIA spinbutton keys — ↑ ↓ a step, PageUp / PageDown ten, Home / End
182
+ the minimum / maximum (without a bound they stay the caret's). `NiceNumericInput` had no keys
183
+ at all; `NiceNumberInput` adds the big step and the bounds, a stepped value replaces the typed
184
+ text (it stayed on screen) and a read-only field no longer steps. With `showSteppers`
185
+ `NiceMoneyInput`'s amount is a `spinbutton` with the same keys — its stepper buttons are out of
186
+ the tab order, so the steps were pointer-only (the buttons show `NiceIcon`s instead of "−" /
187
+ "+"); without steppers it stays a text field. On a pad B on an engaged number field cancels:
188
+ the engine puts a native `<input type="number">`'s value from before back, and the new
189
+ `useEngage` option `restoreOnCancel` does it for a custom control (put the value back in
190
+ `onRelease(true)`). LT / RT on an engaged native field (minimum / maximum) went past React's
191
+ value tracker unseen — a controlled input never heard of it. The hint bar names what the
192
+ buttons do on an engaged control — "Adjust", "A Done, B Cancel" on number fields, "Start
193
+ Confirm, B Done" on a text field, "A Select, B Close" with a list open — and follows engaging
194
+ and opening a list (it only changed when focus moved).
195
+ - Composites (C14, part 1): `NiceAccordion` headers move with ↑ ↓ Home / End (each stays a Tab
196
+ stop; `type="button"` — in a form a header submitted it; `aria-controls` only while the panel
197
+ exists). `NiceCollapse`'s panel is named by its trigger; a header-toggled
198
+ `NiceCollapsibleCard` no longer takes Enter / Space from the controls in it. `NiceFAQ`'s
199
+ folded answers are `inert` (their buttons stayed in the Tab order while hidden) and a
200
+ foldable group has a button. `NiceStepper` steps are buttons with `allowStepClick` (pointer
201
+ only before) and the active one is `aria-current="step"`. `NiceWizard` and
202
+ `NiceSetupWizard` step back and on with LB / RB (Ctrl+PageUp / Ctrl+PageDown) — validated as
203
+ the buttons are, with hints; the wizard's progress is a `progressbar`, its step content a
204
+ named `group` (a `tabpanel` without tabs) and its validation error an `alert`; the setup
205
+ wizard's vertical layout moves through the steps with ↑ ↓. `NiceCarousel` waits while the
206
+ pointer is over it or focus is in it, has a button that stops / starts the rotation
207
+ (WCAG 2.2.2 — it never stopped), takes slides out of view out of the Tab order (`inert`),
208
+ announces a slide the user changed and changes slides on LB / RB. `NiceGallery`'s
209
+ thumbnails are one Tab stop (← → Home End move and show), `aria-pressed` on the shown one;
210
+ its autoplay waits the same way; LB / RB change the image. `NicePagination` buttons are
211
+ `type="button"` (in a form, Enter in a field "clicked" First / Previous), pages are named
212
+ ("Page 3"), the ellipsis is hidden, the jump field is labelled, the page change is announced
213
+ and LT / RT (PageUp / PageDown) turn the page, the prev / next buttons showing the triggers
214
+ next to them (B5). In a paged `NiceDataGrid` a pad's LT / RT turn the page from anywhere in
215
+ the grid — the keyboard's PageUp / PageDown stay the cell's. A breadcrumb with only `onClick`
216
+ is a button (an `<a>` without `href` had no Tab stop), separators are hidden. A clickable
217
+ `NiceTag` takes Enter / Space and, when removable, Delete / Backspace; `aria-pressed` with
218
+ `selected`; its remove button names the tag ("Remove: React").
219
+ - Composites (C14, part 2): `NiceColorPicker`'s saturation / brightness box is a slider — it
220
+ took only the pointer (← → saturation, ↑ ↓ brightness, Shift by ten, PageUp / PageDown,
221
+ Home / End); its presets are one Tab stop moved in two dimensions (as its shortcut hint
222
+ already promised), `aria-pressed` on the current one; every channel field is named and a
223
+ disabled picker is no Tab stop. `NiceGradientPicker`'s stops are sliders (← → move,
224
+ Delete removes; focus selects as a click does), its toggle groups show `aria-pressed`, every
225
+ field is named. `NiceColorPalette`'s hue wheel is a slider of the base hue (pointer only
226
+ before); its tints and shades took focus but no keys — one Tab stop now, Enter / Space
227
+ apply; focus into a colour row selects it. `NiceUpload`: an icon-only drop zone is named,
228
+ progress is a `progressbar`, a file's actions name the file and status changes are
229
+ announced. `NiceTutorial` is named by its step and described by its text, says the title of
230
+ a new step (focus stays on the Next button) and goes to the first / last step with Home /
231
+ End. In `useRovingFocus` the pressed button of a toggle group is the initial stop.
232
+ - TV / 10-foot mode (D4): `data-nice-tv` on any element applies the 10-foot variant of the
233
+ theme below it — type of 24–28 px on a 1080p picture, targets of 48–64 px, spacing × 1.5, a
234
+ stronger focus ring (`styles/tv.css`, part of the `@nice2dev/ui` stylesheet); the input engine
235
+ sets it on `<html>` in a TV browser (webOS, Tizen, Android TV …; `engine.isTv`), and
236
+ `NiceKioskShell` / `NiceNavShell` take `tv`, which also keeps a 5 % safe area for overscan.
237
+ Remote keys were already the engine's (A1).
238
+ - `NiceMdiWorkspace` (D1): the tab menu (right click, X on a pad, Shift+F10) is a menu that
239
+ takes focus, moves with ↑ ↓ and closes on Escape / B with focus back on its tab — it was a
240
+ plain box the keyboard never reached; it moves a tab left or right (the way without
241
+ dragging); Delete closes the focused tab; the unsaved-changes question is a modal dialog with
242
+ focus on Cancel; LB / RB (Ctrl+PageUp / Ctrl+PageDown) switch tabs from anywhere in the
243
+ workspace.
244
+ - Hover has a focus counterpart (C15): `NiceRate` previews the focused star; an auto-hidden
245
+ `NiceDockMenu` shows while focus is in it (a Tab reached its buttons while they stayed
246
+ hidden) and its icon or letter items are named by their text; a hover `NicePopover` opens on
247
+ focus of its trigger too and Escape there hides it first; `NiceTimeline` events took only the
248
+ pointer — they are one Tab stop moved by the arrows, Enter / Space open one and focus shows
249
+ its details; `NiceScheduler` events are Tab stops with Enter / Space and their details on
250
+ focus; the comment button of `NiceGitDiffViewer` shows on focus as on hover.
251
+ - Typing with a pad (H1, H2): `NiceOnScreenKeyboard` (new, `@nice2dev/ui`) — the d-pad moves
252
+ over the keys and A types; X deletes, Y types a space, LT / RT move the cursor, LB / RB change
253
+ the layout (letters with the accents of the interface language, symbols, more languages),
254
+ Start confirms and B closes; the buttons show next to their keys in pad mode; a physical
255
+ keyboard and touch type too; `modal={false}` makes it a standing keyboard of a page.
256
+ `NiceOnScreenKeyboardHost` (new) opens it for the text field a pad or remote engages (A on the
257
+ field) — every key goes into the field as typing would (a controlled field hears it in
258
+ `onChange`), Start submits as Enter (a form submits), B leaves the text as it is; number
259
+ fields get digits, a text area new lines; the `onScreenKeyboard` preference turns it off or
260
+ also opens it on touch (kiosks). The application shells render the host. Its layouts are the
261
+ keyboard core now in `@nice2dev/ui-core` (`NICE_KEYBOARD_LAYOUTS`, `buildKeyboardRows`,
262
+ `insertAtCaret` …), which `NiceTouchKeyboard` (ui-mobile) uses too — its exported type names
263
+ are unchanged. New built-in glyphs `key-backspace`, `key-space`, `key-caps` (and
264
+ `NtdKeyBackspace`, `NtdKeySpace`, `NtdKeyCaps` in `@nice2dev/icons`); `setFieldText` writes a
265
+ field's text past React's value tracker.
266
+ - Toasts (D3): `NiceToastContainer` is a region named "Notifications", so F6 or a pad's View
267
+ reaches the toasts while they never take focus; Escape / B dismisses the toast with focus,
268
+ which goes on to the next toast or back where it came from (it was lost with the toast). The
269
+ countdown waits while the pointer is over a toast or focus is in it (WCAG 2.2.1). A toast can
270
+ carry an `action` (`{ label, onClick }`, also in `useNiceToast`'s options, `NiceToastOptions`)
271
+ — it runs and dismisses the toast.
272
+ - `NiceScientificChart` (ui-science): the export buttons had no handler — CSV and JSON of the
273
+ visible data and SVG / PNG of the plot download now, and the new `onExport` takes every format
274
+ over (PDF is offered only with it); the tooltip sits beside the hovered point instead of the
275
+ plot's corner. The VLAN panel of `@nice2dev/ui-buildings` labels its connections with a key of
276
+ their own (in Polish it read "połączeń", the counted form).
277
+ - `NiceCodeEditor`: an inline `lsp={{ … }}` object re-created the Monaco editor on every render,
278
+ dropping its undo history and cursor — it is re-created only when the LSP config's content
279
+ changes. The audio editor's project hooks (`useProjectCRUD`, `useAutoSave`) word their status
280
+ messages and questions through the translator (some were Polish without diacritics).
281
+ - Prompts next to controls (B5): `NiceControlHint`, and `hint` / `showHint` on `NiceButton` — the
282
+ button or keys of its action, shown while hints are visible; keys also become
283
+ `aria-keyshortcuts`. `NiceButton` also passes `role`, `aria-selected`, `aria-pressed`,
284
+ `aria-expanded`, `aria-controls`, `aria-haspopup`, `tabIndex` and `onKeyDown`.
285
+ - Found by the showcase crawler (I4, `scripts/audit-input-crawl.mjs`): **no `NiceButton` showed a
286
+ focus ring** — the display styles write `box-shadow` inline (`none` for the default `flat`) and
287
+ that beat the `:focus-visible` rule; the ring is `!important` now, also for the `underlined` and
288
+ `neumorphic` fields. `NiceCodeEditor`, `NiceCodeDiffEditor`, `NiceSimpleCodeEditor` and
289
+ `NiceMarkdownEditor` were keyboard traps (Tab indents and Shift+Tab outdents, nothing left the
290
+ field): Escape, then Tab moves focus on (WCAG 2.1.2), said in the field's description, and a
291
+ read-only editor lets Tab through (it indented its text); `createTabEscape()` (new, ui-core
292
+ and ui) gives a control of your own the same. These editors, `NiceHtmlEditor`,
293
+ `NiceTerminalUI` and the search of `NicePickList` drew no focus at all — their frame shows the
294
+ ring now. The diagram buttons of `NiceGamepad` were pointer-only, so arming a button for an
295
+ assignment took a mouse: with a handler or an action tree they are buttons (one Tab stop, the
296
+ arrows move by geometry, Enter / Space / A press, `aria-pressed` while armed); an SVG element
297
+ has no `click()`, so a pad's A dispatches a click to one (`clickElement`, new). A sortable
298
+ `NiceDataGrid` header sorted only on a click: it is a Tab stop and sorts on
299
+ Enter / Space / A. `NicePasswordInput`'s show / hide button is a Tab stop (showing the password
300
+ took a pointer). The `NiceDateTimePicker` field says how its picker opens (`aria-haspopup`,
301
+ `aria-keyshortcuts="Alt+ArrowDown"`).
302
+ - More from the crawler (I4). `NiceDataGrid` took keys from anything inside it: with a focused
303
+ cell Tab never left the grid (a trap, also from a header) and the search field's arrows did
304
+ not move its caret — the cell cursor follows only the grid's own focus, and Tab at the edge of
305
+ a row leaves. `NiceSpreadsheet`'s formula bar kept Tab without an edit. `NiceModelEditor`
306
+ (ui-3d) listened on the whole page: Tab cycled its mode anywhere (focus moved nowhere on a page
307
+ with the editor), Space pressed no button and Ctrl+Z took the undo of every text field — its
308
+ shortcuts work inside the editor only, Tab and Space on its controls are theirs, Escape then
309
+ Tab leaves the viewport. `NiceDocumentEditor` indents a block on Tab and lets the keyboard out
310
+ as the code editors do (Escape, then Tab; its shortcut list says so). `NicePlaylistDualPane` (ui-audio)
311
+ switches panes on Tab, and Escape then Tab moves on. `NiceSeatingChart` / `NiceSeatPicker`
312
+ (events) take focus to the cursor seat — it stayed on the chart, out of a screen reader's
313
+ reach. Rings where there were none: the cursor row of `NiceKaraokeSongBrowser` (it looked the
314
+ same focused as not), `NiceFileManager`'s panels, `NiceTagInput`, the name field of
315
+ `NiceWorkflowDesigner`, `NiceDocumentEditor`, the chat and search fields of ui-communication
316
+ (`outline: none` inline), the search of `NiceGlobalSearch` and `NiceAccessLog`
317
+ (ui-enterprise), the fields of `NiceTaskManager` and `NiceTorrentUI` (templates) and of the
318
+ automation and scene editors (ui-buildings), the viewport of `NiceModelViewer` (ui-3d).
319
+ - `useOverlayFocus` gave focus back to the opener whenever an overlay closed with focus on the
320
+ page body — also for the moment of a Tab, when the opener's blur closed a popup it showed on
321
+ focus: a `NiceDataGrid` header with column stats took focus back on every Tab, a trap. Focus
322
+ goes back now only when it was in the overlay. The keyboard shortcuts of `GenericPlayer`
323
+ (ui-audio) and `NicePresentationPlayer` (ui-presentations) listened on the whole page — the
324
+ arrows of every list and a pad's d-pad (they move focus with them) did nothing on a page with a
325
+ player, Space pressed no button, and with a presentation Backspace deleted nothing and Enter
326
+ submitted nothing in any field; they work in the player or with focus on the page body, and
327
+ Space / Enter on the player's own buttons press them. A pad has no Tab: on a control of a
328
+ player its d-pad moves focus (as seek, volume or the next slide it kept focus in the player for
329
+ good); on the player itself or the page body a remote's arrows still turn the slides.
330
+ - Lint (I2): the whole jsx-a11y recommended set is on, with the input program's own rules against
331
+ page-wide key listeners and inline `outline: 'none'`. Found on the way: the reply box of
332
+ `NiceHelpdesk` and the search of `NiceCommandBar` took the outline away and showed nothing
333
+ instead — they show focus now.
334
+ - `NicePopover` (the one anchored to a `targetRef`) had no keyboard at all — it closed only on a
335
+ click outside it. It is a `dialog` named by its `title`, takes focus when it opens, closes on
336
+ Escape / B and gives focus back to its target (tests that count the page's dialogs see it now).
337
+ A pick in a `NiceSelect` inside it closed it and was lost (the select's list is portalled out
338
+ of the popover): such a click keeps it open.
339
+ - Rows, cards, tiles and list entries that answered a pointer only (C1) are buttons for the
340
+ keyboard and the pad: `role="button"`, a Tab stop, Enter / Space / A press them — a selection
341
+ toggle says `aria-pressed`, a folder or summary row `aria-expanded`, a check box drawn with a
342
+ `div` is a `checkbox` with its item's name. `clickOnActivationKey` (new, ui-core and ui) is the
343
+ `onKeyDown` for such an element: Enter and Space click it, once per press and with the
344
+ modifiers, so Ctrl+Enter selects as Ctrl+click does; keys of a control inside it stay that
345
+ control's. Dialog backdrops and click stoppers are `role="presentation"` (Escape / B close the
346
+ dialogs). Done so far in events (attraction picker and voting, round list), game-engine (the
347
+ Godot, Unity and Unreal project browsers, the asset store, the editor's hierarchy), licensing
348
+ (portal, transfer, the license table), templates (health, life dashboard, personal finance,
349
+ task manager, torrent UI) and `OmniWerkLogo`, whose `role="button"` took no key; ui-3d (model
350
+ editor outliner with expand / show-hide buttons, Add menu, context menu, timeline, particle
351
+ editor), ui-ai (dataset, experiment, model and labeling cards), ui-api (endpoints, schemas,
352
+ history), ui-audio (sample browser, bar-fill swatches, DMX cues and tracks, the "activate
353
+ audio" overlay, playlist grid / overview / sidebar / search / tags / track list),
354
+ ui-bi (ETL palette and nodes), ui-buildings (automations, zone card, scenes, network paths,
355
+ object library), ui-diagrams, ui-enterprise (access log, contract sections), ui-erp (capacity
356
+ planner — its time cells are named buttons, the only way to add an allocation — and inventory
357
+ cards), ui-forms, and in ui-core `NiceIcon` and `NiceTouchTarget` with an `onClick` and the
358
+ profiler's header — `NiceTouchTarget` also draws a focus ring now; ui-graphics (font glyphs, 2D game asset lists and state nodes, photo
359
+ overlays and colour swatches, pixel layers with show / lock buttons, palette and frames,
360
+ texture and UI designer layers, vector gradients and layers), ui-iot cards, ui-math templates,
361
+ ui-monitoring (saved queries, expandable log rows), ui-presentations (slide thumbnails and the
362
+ overview), ui-printing (template cards, schema fields, layers), ui-science (citations,
363
+ notebooks) and ui-video (live sources, timeline tracks and clips). A clickable `NiceIcon` is a
364
+ button now. `ImportPreviewDialog` (ui-buildings) carried `role="dialog"` on its backdrop — it
365
+ is on the dialog box now. The wheel of `NiceMobilePicker` still has no keys (it gets a
366
+ spinbutton column with E). Tests that count the buttons of these components find more.
367
+ - C1 in `@nice2dev/ui`: the rows, cards and items of the devops, data-branching, media, no-code,
368
+ tools, backup and chart components are buttons (selection toggles `aria-pressed`, folding rows
369
+ `aria-expanded`); a `NiceKanbanBoard` card that opens on a click and a `NiceTileView` tile with
370
+ `onTileClick` are buttons; `NiceTreeList` rows fold from the keyboard (the toggle is a named
371
+ button with `aria-expanded`); `NiceDataGrid`'s virtual group rows and detail toggles take
372
+ Enter / Space. A built-in `NiceIcon` with `onClick` is a button — it was `aria-hidden` and took
373
+ no key. `NiceSelect`, `NiceCountryPicker`, `NiceLanguagePicker` and `NiceThemePicker` clear with
374
+ Delete / Backspace on the trigger (`aria-keyshortcuts="Delete"`): the × in the trigger was
375
+ pointer-only (in `NiceSelect` a `role="button"` inside the trigger button) and is
376
+ `role="presentation"` now. `NiceModal`, `NiceConfirmDialog`, `NiceCommandPalette` and
377
+ `NiceGlobalSearch` stop clicks at the backdrop instead of the dialog — a click on the backdrop
378
+ itself closes, and no click inside or on it reaches a component around the overlay.
379
+ `NiceHtmlEditor`'s template list is a menu with keys, its emoji are buttons; `NiceGitManager`
380
+ opens a file's diff from its path, a button (a click elsewhere on the row did it before);
381
+ `NiceResourceAllocation`'s days are named buttons with `onSlotClick`. Options of comboboxes and
382
+ items of menus, trees and grids keep their click with a line disable naming the keys that
383
+ drive them. The empty cells of `NiceScheduler`'s grids get their keys with E.
384
+
385
+ - 2972a9a: Showcase feedback: charts, the theme and workflow designers, the vector editor and the spatial
386
+ editor.
387
+
388
+ - `NiceChart`: bars are centred on their category label. The slots counted line series too, so in
389
+ a bar + line chart every bar sat left of its label.
390
+ - `NicePieChart`: the slice labels get a white fill with a dark halo (`.nice-piechart__label`,
391
+ tokens `--nice-piechart-label-color` / `--nice-piechart-label-halo`) and read on light slices.
392
+ In a donut the label sits in the middle of the ring, not at 0.7 of the radius, where it fell
393
+ into a wide hole. `innerRadius` stays 0 by default: a full pie.
394
+ - `NiceBarGauge`: the title gets a band of its own and the drawn arc, not the whole circle, is
395
+ fitted into the box. The outer ring no longer runs into the title, and the rings of the default
396
+ 270° gauge are larger. Visual change only; the props are the same.
397
+ - `NiceThemeDesigner` / `NiceThemeBuilder`:
398
+ - Apply Theme and `livePreview` apply the theme through the enclosing `NiceThemeProvider`
399
+ (`setTheme`), and to the document root only outside one. The provider's scope shadows
400
+ `:root`, so inside a provider neither had a visible effect.
401
+ - Export JSON downloads `<theme name>.json` when no `onExport` is given; it did nothing before.
402
+ - A click on the next preview element clears the previous field's dashed highlight.
403
+ - `NiceWorkflowDesigner` (state machine):
404
+ - A drag on the empty canvas pans the view; the canvas now fills the height and scrolls. A
405
+ press on the canvas without a drag clears the selection, and the properties panel has a close
406
+ button (new key `workflowDesigner.closeProps` × 6 languages).
407
+ - No properties panel opens while simulating: a simulation step no longer selects the state it
408
+ leaves. The current state of a simulation scrolls into view.
409
+ - `NiceVectorEditor`:
410
+ - A dragged rectangle, ellipse, line or arrow stays on the canvas; it was deleted on release as
411
+ "tiny".
412
+ - The pointer maps through the viewBox fit of the artboard, so shapes land where they are
413
+ drawn, also when the artboard is shown smaller than its size.
414
+ - `NiceSpatialEditor`:
415
+ - A plan given as `initialDocument` gets its active floor; objects added to it were dropped.
416
+ - The canvas draws walls, devices, furniture, network and infrastructure gear, besides the
417
+ zones and cables it drew before.
418
+ - Finishing a drawing (double-click or Enter) creates a zone or wall segments in
419
+ spatial-core's shapes. Before, the drawing vanished.
420
+ - A pick in the object library is placed by a click on the plan, or dragged onto it; the
421
+ toolbar's place tools put their kind of object down.
422
+ - The select tool moves objects by dragging. `MOVE_OBJECTS` moves all of an object's geometry
423
+ (box, outline, wall ends), and attached cable ends follow. The X / Y fields of the properties
424
+ panel move the object.
425
+ - `onDocumentChange` and `onSelectionChange` are called on every change; they never were.
426
+ - An added object goes into the first layer of its name, else of its type, else a new layer.
427
+ - `NiceSpatialViewer`:
428
+ - Reads zones in any of the shapes in use: `boundary`, `metadata.points` or `polygon`.
429
+ - Draws walls and cables as lines, and objects without `position` at their box instead of
430
+ (0, 0).
431
+ - Shows a real minimap; the minimap was an empty box.
432
+ - `Minimap`: reads zones in any of those shapes; it read `polygon` only.
433
+
434
+ - @nice2dev/spatial-core@1.3.0
435
+
3
436
  ## 1.2.2
4
437
 
5
438
  ### Patch Changes