vireuikit 0.7.0 → 0.9.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/README.md +120 -5
- package/dist/chunk-7A3XUTXH.js +1314 -0
- package/dist/chunk-7A3XUTXH.js.map +1 -0
- package/dist/context-DQaAcRq-.d.cts +104 -0
- package/dist/context-DQaAcRq-.d.ts +104 -0
- package/dist/index.cjs +1155 -186
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +585 -127
- package/dist/index.d.ts +585 -127
- package/dist/index.js +146 -1
- package/dist/index.js.map +1 -1
- package/dist/web.cjs +2240 -130
- package/dist/web.cjs.map +1 -1
- package/dist/web.d.cts +37 -3
- package/dist/web.d.ts +37 -3
- package/dist/web.js +1460 -48
- package/dist/web.js.map +1 -1
- package/package.json +1 -1
- package/dist/a11y-D3SS74I3.d.cts +0 -25
- package/dist/a11y-D3SS74I3.d.ts +0 -25
- package/dist/chunk-AR2AM3BR.js +0 -557
- package/dist/chunk-AR2AM3BR.js.map +0 -1
package/README.md
CHANGED
|
@@ -51,10 +51,55 @@ import { MENU_CLOSED, menuPlacement, menuSurfaceFrame, stepMenu } from 'vireuiki
|
|
|
51
51
|
|
|
52
52
|
const step = stepMenu(MENU_CLOSED, { type: 'open', focus: 'first' }, items); // items: { label, disabled, focusable? }[]
|
|
53
53
|
// step.focus says where focus goes; a choice always closes the menu.
|
|
54
|
-
const { rect, anchor } = menuPlacement(triggerRect, menuSize,
|
|
54
|
+
const { rect, anchor } = menuPlacement(triggerRect, menuSize, segment); // the trigger's segment of the window, or the viewport
|
|
55
55
|
const surface = menuSurfaceFrame(triggerBox, { ...rect, radius }, anchor, growthPhase(state));
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
## Adaptive model
|
|
59
|
+
|
|
60
|
+
What every atom and pattern becomes across window classes, input and posture is one pure model, so every target
|
|
61
|
+
decides the same way. The context is the window in dp, the input in three layers (the primary pointer, any coarse
|
|
62
|
+
input, hover, a keyboard), the posture of a folding screen and reduced motion; the functions turn it into forms.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { adaptiveContext, halfOpen, INPUT_MIXED, navigationForm, paneLayout, presentationForm } from 'vireuikit';
|
|
66
|
+
|
|
67
|
+
const window = { width: 673, height: 841 };
|
|
68
|
+
const ctx = adaptiveContext({ window, input: INPUT_MIXED, posture: halfOpen('book', window) });
|
|
69
|
+
|
|
70
|
+
navigationForm(ctx, { primary: 4, secondary: 2, search: true }).form; // 'rail'
|
|
71
|
+
paneLayout(ctx, { selected: true, showing: 'detail' }).split; // { kind: 'fold', gap }: the panes split at the fold
|
|
72
|
+
presentationForm('sheet', ctx).form; // 'bottom-sheet'; a side sheet from 840 dp
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `classifyWindow` holds every threshold: widths 600, 840, 1200 and 1600 dp, heights 480 and 900.
|
|
76
|
+
- `navigationForm`: a bar on a compact width and in tabletop, a rail on medium, expanded and a compact height, a
|
|
77
|
+
sidebar from large; the same primary destinations on every form, at most five bar slots with search, no "More".
|
|
78
|
+
`bottomAccessory` places a strip above the bar, in its row or along the content.
|
|
79
|
+
- `presentationForm` for a menu, picker, popover, sheet, modal sheet, alert or dialog: a popover is a sheet grown from
|
|
80
|
+
its source below 600, a supplementary sheet is a bottom sheet below 840 and a side sheet from there, sheets fill
|
|
81
|
+
the window on a compact height, and every surface lives in one segment, never across the fold.
|
|
82
|
+
- `paneLayout` (list-detail: one pane below 840, a 360 or 412 dp list beside the detail, split at the fold in book
|
|
83
|
+
posture), `supportingPane` (beside the content from large, over it on expanded, remembered), `postureSplit`.
|
|
84
|
+
- `toolbarLayout` fits a toolbar into its container: neighbours merge, then the lowest priority goes into "…";
|
|
85
|
+
badged items and the main action stay. `toolbarPlacement` says where the window puts it.
|
|
86
|
+
- `sizeTier` follows the primary pointer and `hitTarget` any coarse input, so a laptop with a touch screen gets the
|
|
87
|
+
pointer tier with a 44 dp hit area.
|
|
88
|
+
- `formMorph`, `stepFormMorph` and `formMorphFrame` flow one body into its new form on the growth's springs; turned
|
|
89
|
+
back mid-way it runs back from where it is, and under reduced motion it lands in one frame.
|
|
90
|
+
|
|
91
|
+
On the web the elements collect their part of the context themselves. A shell that lays itself out from the model
|
|
92
|
+
watches its root:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { setInputOverride, setViewportOverride, watchAdaptiveContext } from 'vireuikit/web';
|
|
96
|
+
|
|
97
|
+
const stop = watchAdaptiveContext(shell, (ctx) => render(ctx)); // told now and on every change
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`setInputOverride` lets a host that knows its input better decide the layers, and `setViewportOverride` makes an
|
|
101
|
+
element the window, with its own segments; the lab's adaptive stage simulates devices with both.
|
|
102
|
+
|
|
58
103
|
## Web elements
|
|
59
104
|
|
|
60
105
|
`vireuikit/web` upgrades native controls with custom elements. The control inside works before the
|
|
@@ -78,9 +123,10 @@ setA11yOverride({ reduceTransparency: true });
|
|
|
78
123
|
- `<vire-icon-button>` lifts into the glass under the finger; the lens response is visible while the
|
|
79
124
|
press is held.
|
|
80
125
|
- Attributes: `glass` (empty or `present`: a lens at rest; `touch`: a lens only under the finger; absent: no
|
|
81
|
-
glass), `size` (`touch`, `small`, `medium`, `large`, `xlarge`; by default `touch`
|
|
82
|
-
`medium` otherwise), `disabled`.
|
|
83
|
-
-
|
|
126
|
+
glass), `size` (`touch`, `small`, `medium`, `large`, `xlarge`; by default `touch` when the primary pointer is
|
|
127
|
+
coarse and `medium` otherwise), `disabled`.
|
|
128
|
+
- Wherever a coarse input is present, a touch screen on a laptop too, every size keeps a hit area of at least 44 dp
|
|
129
|
+
without changing layout. Hover comes from the pointer that entered: a mouse on a tablet hovers, a finger never does.
|
|
84
130
|
- The lens reads the backdrop from declared colours and cannot see an image, a video or a canvas. A host that knows
|
|
85
131
|
what lies under the control sets the element's `sample` (a `BackdropSample` from `vireglass`), at any time; `null`
|
|
86
132
|
hands it back to the probe.
|
|
@@ -145,9 +191,78 @@ setA11yOverride({ reduceTransparency: true });
|
|
|
145
191
|
`<vire-icon-button>`), so there is never glass on glass.
|
|
146
192
|
- Attributes: `glass` (empty, `present` or `touch`: the surface is a lens; absent or anything else: an opaque surface), `size` (as for the buttons; rows are as tall
|
|
147
193
|
as the tier), `corner` (`top-left`, `top-right`, `bottom-left`, `bottom-right`: the trigger corner the menu pins to;
|
|
148
|
-
by default the one facing the nearest
|
|
194
|
+
by default the one facing the nearest corner of the trigger's segment of the window). On a folding screen the menu
|
|
195
|
+
stays in its trigger's half, every frame of its growth included, and scrolls if it is taller. `sample` works as on the buttons; without one, the backdrop
|
|
149
196
|
under the menu is read once as it opens and held while it is out.
|
|
150
197
|
|
|
198
|
+
### Navigation
|
|
199
|
+
|
|
200
|
+
`<vire-nav>` upgrades a `<nav>` of links into one glass body that is a bar, a rail or a sidebar by the window it covers,
|
|
201
|
+
and changes form through the selected destination.
|
|
202
|
+
|
|
203
|
+
```html
|
|
204
|
+
<vire-nav glass minimize="scroll" scroller="content">
|
|
205
|
+
<nav aria-label="Sections">
|
|
206
|
+
<ul>
|
|
207
|
+
<li><a href="/" aria-current="page"><svg>…</svg>Home</a></li>
|
|
208
|
+
<li><a href="/library"><svg>…</svg>Library</a></li>
|
|
209
|
+
</ul>
|
|
210
|
+
<ul data-secondary>
|
|
211
|
+
<li><a href="/feed"><svg>…</svg>Feed</a></li>
|
|
212
|
+
</ul>
|
|
213
|
+
<a href="/search" data-search><svg>…</svg>Search</a>
|
|
214
|
+
</nav>
|
|
215
|
+
<div data-accessory>…host content, such as a mini player…</div>
|
|
216
|
+
</vire-nav>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
- Before the upgrade it is a list of links. After it the element covers its containing block (give that a position): its
|
|
220
|
+
own box is the window it classifies, so it needs no breakpoints from the host. Only the body, the search, the toggle,
|
|
221
|
+
the scrim and the accessory take the pointer. Links stay links: no `tablist`, no arrow keys, Tab walks them, and
|
|
222
|
+
`aria-current` is the host's to set and move; the pill slides to it. Removing the element restores the markup.
|
|
223
|
+
- The form comes from `navigationForm`: a bar on a compact width, a rail on medium and expanded windows, a sidebar from
|
|
224
|
+
large. Destinations beyond the bar's slots move to the secondary list, which shows only in the sidebar; links not shown
|
|
225
|
+
in a form are `hidden`. The host carries `data-form` (`bar`, `rail`, `sidebar`), `data-search` (`button`, `item`,
|
|
226
|
+
`field`) and `data-minimized`.
|
|
227
|
+
- A change of form goes through the selection: it lifts into a lens, the old body contracts into it, the new body grows
|
|
228
|
+
out of it and the lens settles into the pill. The lens is glass only while it moves. Focus stays on the same link
|
|
229
|
+
while that link stays shown; a link the new form hides (minimising, a link moving to the secondary list) hands focus to
|
|
230
|
+
the selected link, or to the toggle. Reduced motion lands the new form in one frame. A press that starts on the bar's inset or between items and ends
|
|
231
|
+
without a drag settles the lens back on the selected item.
|
|
232
|
+
- On the bar a press lifts the selection into a lens under the finger; a drag moves it, and releasing activates the
|
|
233
|
+
nearest link once. A tap is a plain click on the link.
|
|
234
|
+
- Attributes: `form` (`bar`, `rail` or `sidebar`: fixes the form), `collapsed` (the sidebar held as a rail; the toggle
|
|
235
|
+
sets and clears it and the host remembers it), `panes` (panes the content shows; two on a medium window take the bar),
|
|
236
|
+
`minimize="scroll"` with `scroller` (the id of the scrolling element, resolved in the element's root; or set the
|
|
237
|
+
`scroller` property to an element), `search-key` (default `/`), `toggle-label` (the toggle's name, default "Sidebar";
|
|
238
|
+
it never changes, `aria-expanded` says whether the sidebar is shown), `glass` (empty or `present`: glass; otherwise a plain body).
|
|
239
|
+
- Minimising: the bar becomes a circle with the selected icon, and the search a second circle, after 24 dp scrolled
|
|
240
|
+
down in the scroller, and expands after 24 dp up, at the top, on a tap on it and when focus enters it. Giving the
|
|
241
|
+
bar another scroller expands it. The element looks the id up again on each change: a node that left the document, or
|
|
242
|
+
that the id no longer names, is let go and the bar expands. The document itself works as a scroller
|
|
243
|
+
(`document.documentElement`, `document.body` or `document.scrollingElement`, listened to on the window), and a
|
|
244
|
+
bounce past either end of the scroll range counts as the end. A step back of less than 4 dp does not break a run.
|
|
245
|
+
- `[data-accessory]` is the bottom accessory. It sits over the bar, in the minimised bar's row, or along the bottom of
|
|
246
|
+
the content beside a rail or sidebar, and says which in its `data-placement` (`above-bar`, `in-bar`,
|
|
247
|
+
`content-bottom`): show the transport only when `in-bar`.
|
|
248
|
+
- Insets: the element sets `--vire-nav-inset-bottom` and `--vire-nav-inset-start` (px) on its parent for the content to
|
|
249
|
+
clear, and fires `vire-nav-layout` with `{ form, minimized, insets, accessoryPlacement }` whenever any changes.
|
|
250
|
+
- Toggle: in the sidebar a button in its head collapses it into a rail (`collapsed`, and `vire-nav-collapse` with
|
|
251
|
+
`{ collapsed: true }`); an expandable rail beside the content clears it (`{ collapsed: false }`); on an expanded window
|
|
252
|
+
a rail opens the sidebar over the content behind a scrim (`aria-expanded` is true then too), closed by Escape, a press on the scrim or a link chosen;
|
|
253
|
+
Escape and the scrim return focus to the toggle if it was inside the navigation. The element stores nothing.
|
|
254
|
+
- Where the model gives a shortcut (a large window, or a keyboard in use), `search-key` pressed outside a field clicks
|
|
255
|
+
the search link, which carries `aria-keyshortcuts` while it is shown (the shortcut still works for a link the form hides).
|
|
256
|
+
- Every link keeps a 44 dp hit area wherever a coarse input is present, without changing the layout. A `[data-badge]`
|
|
257
|
+
inside a link is a count (or a dot, when empty) at the icon's corner, and only a picture: the element sets
|
|
258
|
+
`aria-hidden="true"` on it and restores the attribute on removal. To say it, put a `[data-badge-label]` in the link;
|
|
259
|
+
it is visually hidden but stays in the link's name:
|
|
260
|
+
`<a href="/messages"><svg>…</svg>Messages<span data-badge>3</span><span data-badge-label>3 new</span></a>`, read as "Messages 3 new". `sample` and `a11y` work as on the buttons. The bar clears the bottom safe area
|
|
261
|
+
(`env(safe-area-inset-bottom)`, read once per layout; 0 where unsupported).
|
|
262
|
+
- The element adds nodes inside `<vire-nav>`, so call `defineVireElements()` after a framework has hydrated the markup
|
|
263
|
+
(in an effect, say), not before. The lens's copy follows the selected link's content, and a link that leaves the markup
|
|
264
|
+
is left as the author wrote it.
|
|
265
|
+
|
|
151
266
|
Sizes, behaviour state machines and accessibility modes are exported from `vireuikit` and shared by every
|
|
152
267
|
target. How an atom is accepted:
|
|
153
268
|
[design](https://github.com/pruffit/vireuikit/blob/main/docs/design.md),
|