@apostel/bedrock 0.1.0 → 0.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/README.md +60 -169
- package/dist/capabilities.d.ts +4 -3
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +4 -3
- package/dist/capabilities.js.map +1 -1
- package/dist/collapsible/root.d.ts +2 -2
- package/dist/collapsible/root.js +2 -2
- package/dist/interest.d.ts +14 -7
- package/dist/interest.d.ts.map +1 -1
- package/dist/interest.js +199 -28
- package/dist/interest.js.map +1 -1
- package/dist/menu/parts.d.ts.map +1 -1
- package/dist/menu/parts.js +16 -6
- package/dist/menu/parts.js.map +1 -1
- package/dist/open-state.d.ts.map +1 -1
- package/dist/open-state.js +21 -3
- package/dist/open-state.js.map +1 -1
- package/dist/tooltip/parts.d.ts +7 -0
- package/dist/tooltip/parts.d.ts.map +1 -1
- package/dist/tooltip/parts.js +12 -1
- package/dist/tooltip/parts.js.map +1 -1
- package/package.json +21 -10
package/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
# bedrock
|
|
2
2
|
|
|
3
|
-
Headless React primitives
|
|
3
|
+
Headless React primitives that let the browser do the layering, positioning and
|
|
4
|
+
dismissal.
|
|
4
5
|
|
|
5
|
-
Radix-shaped anatomy
|
|
6
|
-
already type.
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
Radix-shaped anatomy: compound components, `asChild`, the part names you
|
|
7
|
+
already type. Underneath, the top layer, invoker commands and anchor positioning
|
|
8
|
+
do the work that `Portal`, `Presence`, `DismissableLayer` and Floating UI used to
|
|
9
|
+
do.
|
|
9
10
|
|
|
10
11
|
```bash
|
|
11
12
|
npm i @apostel/bedrock
|
|
12
13
|
```
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
**<https://bedrock.sams.land>**
|
|
15
|
+
<!-- demo: dialog -->
|
|
16
16
|
|
|
17
17
|
## The shape
|
|
18
18
|
|
|
@@ -30,187 +30,78 @@ import { Dialog } from '@apostel/bedrock'
|
|
|
30
30
|
</Dialog.Root>
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
renders roughly this:
|
|
34
34
|
|
|
35
35
|
```html
|
|
36
36
|
<button commandfor="d1" command="show-modal">Delete project</button>
|
|
37
37
|
<dialog id="d1">…</dialog>
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
No effect opens it. No state hook holds it. No portal moves it. The
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
No effect opens it. No state hook holds it. No portal moves it. The parser wires
|
|
41
|
+
the button to the dialog, so it works before hydration and keeps working if your
|
|
42
|
+
bundle never arrives.
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## What it saves
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
default — and it costs nothing.
|
|
46
|
+
Measured with esbuild, minified and gzipped, React external:
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
read-only `onOpenChange`, which is a `toggle` listener and nothing more. This
|
|
51
|
-
covers the common case that gets miscategorised as "controlled": *I need to know
|
|
52
|
-
when it closed so I can reset the form.*
|
|
53
|
-
|
|
54
|
-
**`Dialog.Root` from `@apostel/bedrock/controlled`** — React gets a veto. Your
|
|
55
|
-
`open` prop decides whether an open is allowed to proceed.
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
import { Dialog } from '@apostel/bedrock/controlled'
|
|
59
|
-
|
|
60
|
-
<Dialog.Root open={open} onOpenChange={setOpen}>
|
|
61
|
-
{/* identical children */}
|
|
62
|
-
</Dialog.Root>
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Same component names, same parts, same props on every part. Swapping is a
|
|
66
|
-
one-line import change, and a codemod if you're doing it across a repo.
|
|
67
|
-
|
|
68
|
-
The two entry points are separate module graphs, so if nothing in your app
|
|
69
|
-
imports `/controlled`, none of the reconciliation code reaches your bundle. This
|
|
70
|
-
is a real guarantee from the `exports` map, not a tree-shaking hope.
|
|
71
|
-
|
|
72
|
-
### How the veto works
|
|
73
|
-
|
|
74
|
-
Controlled mode is **DOM leads, React vetoes**, not React-owns-state:
|
|
75
|
-
|
|
76
|
-
1. User clicks. The browser fires `beforetoggle`, which is cancelable for
|
|
77
|
-
popovers. If your `open` prop disagrees, we `preventDefault()` and nothing
|
|
78
|
-
moved.
|
|
79
|
-
2. `onOpenChange` fires either way, so you can decide.
|
|
80
|
-
3. If your prop changes without user interaction, a reconciliation effect moves
|
|
81
|
-
the DOM to match.
|
|
82
|
-
|
|
83
|
-
Where the platform gives no cancelable hook, step 1 is skipped and step 3 puts
|
|
84
|
-
things back — one frame of visible movement in the refuse case only. Modal
|
|
85
|
-
dialogs get an extra veto on close via `request-close` and the `cancel` event.
|
|
86
|
-
|
|
87
|
-
## `asChild` and the button rule
|
|
88
|
-
|
|
89
|
-
Invoker commands work on `<button>` only. Interest invokers also work on `<a>`.
|
|
90
|
-
So this is fine:
|
|
91
|
-
|
|
92
|
-
```tsx
|
|
93
|
-
<Tooltip.Trigger asChild><a href="/pricing">Pricing</a></Tooltip.Trigger>
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
and this is not:
|
|
97
|
-
|
|
98
|
-
```tsx
|
|
99
|
-
<Dialog.Trigger asChild><div onClick={…}>Open</div></Dialog.Trigger>
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
A trigger that isn't a button gets no `commandfor` wiring, which means no
|
|
103
|
-
keyboard activation and no implicit `aria-expanded`. That's an accessibility
|
|
104
|
-
regression, and it's silent, so we make noise about it: **development throws**
|
|
105
|
-
at mount, with the tag it found and the tags that part accepts. Production logs
|
|
106
|
-
an error at the same check point.
|
|
107
|
-
|
|
108
|
-
There is no fallback click handler. Attaching one would ship the exact
|
|
109
|
-
imperative trigger machinery this library exists to delete, to every consumer,
|
|
110
|
-
forever — and nobody removes a fallback that works.
|
|
111
|
-
|
|
112
|
-
If you're wrapping a third-party component that renders a div and can't change
|
|
113
|
-
it, take the props and own the consequences:
|
|
114
|
-
|
|
115
|
-
```tsx
|
|
116
|
-
const props = useDialogTrigger(id)
|
|
117
|
-
<ThirdPartyThing {...props} />
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
The same check catches `<button>` inside a `<form>` without `type="button"`.
|
|
121
|
-
Submit buttons can't invoke popovers — submitting and opening are conflicting
|
|
122
|
-
behaviours — and that one bites people more often than the div case.
|
|
123
|
-
|
|
124
|
-
## What's native and what still ships JS
|
|
125
|
-
|
|
126
|
-
Be clear-eyed about this. The platform deleted positioning and layering. It did
|
|
127
|
-
not delete focus management.
|
|
128
|
-
|
|
129
|
-
**Almost entirely native** — AspectRatio, Separator, Label, VisuallyHidden,
|
|
130
|
-
Progress, Slider, ScrollArea, Collapsible, Accordion, Checkbox, Switch,
|
|
131
|
-
RadioGroup, Select, Dialog, AlertDialog, Popover.
|
|
132
|
-
|
|
133
|
-
Several of those are one element and no state at all: `Progress` is
|
|
134
|
-
`<progress>`, `Slider` is `<input type="range">`, `Select` is a `<select>` under
|
|
135
|
-
`appearance: base-select`, and `Accordion` gets single-open exclusivity from
|
|
136
|
-
`<details name>` rather than from an effect that closes its siblings.
|
|
137
|
-
|
|
138
|
-
**Native layering, small JS state layer** — Tooltip, HoverCard, Avatar, Toggle,
|
|
139
|
-
Toast.
|
|
140
|
-
|
|
141
|
-
**Still substantially JS** — DropdownMenu, ContextMenu, Menubar,
|
|
142
|
-
NavigationMenu, Tabs, Toolbar, ToggleGroup.
|
|
143
|
-
|
|
144
|
-
The reason is short: there is no native roving tabindex, no native typeahead, no
|
|
145
|
-
focus trap for non-modal layers, and no way to anchor to a pointer coordinate.
|
|
146
|
-
Every menu-shaped primitive needs all four, and they all share one `roving.ts` —
|
|
147
|
-
which ships from either entry point, so the two-root split saves them almost
|
|
148
|
-
nothing. The docs say that rather than implying otherwise.
|
|
149
|
-
|
|
150
|
-
Measured, not estimated — esbuild, minified, gzipped, React external:
|
|
48
|
+
<!-- sizes-figure -->
|
|
151
49
|
|
|
152
50
|
| primitive | bedrock | Radix | |
|
|
153
51
|
| --- | --- | --- | --- |
|
|
154
|
-
| Checkbox | **0.70 kB** | 5.9 kB | 8.
|
|
155
|
-
| Slider | **0.74 kB** | 9.8 kB | 13× |
|
|
156
|
-
| Select | **0.84 kB** | 31.5 kB | 37× |
|
|
52
|
+
| Checkbox | **0.70 kB** | 5.9 kB | 8.4× |
|
|
53
|
+
| Slider | **0.74 kB** | 9.8 kB | 13.2× |
|
|
54
|
+
| Select | **0.84 kB** | 31.5 kB | 37.5× |
|
|
157
55
|
| Accordion | **1.61 kB** | 8.8 kB | 5.5× |
|
|
158
|
-
| Dialog | **1.95 kB** | 13.7 kB | 7× |
|
|
159
|
-
| Popover | **2.11 kB** | 24.2 kB | 11× |
|
|
56
|
+
| Dialog | **1.95 kB** | 13.7 kB | 7.0× |
|
|
57
|
+
| Popover | **2.11 kB** | 24.2 kB | 11.5× |
|
|
160
58
|
| Tooltip | **2.55 kB** | 19.3 kB | 7.6× |
|
|
161
59
|
| DropdownMenu | **3.55 kB** | 31.6 kB | 8.9× |
|
|
162
60
|
|
|
163
|
-
The ratio
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
61
|
+
The ratio is largest where the platform hands over a whole element and smallest
|
|
62
|
+
where it hands over nothing but the layering. Menus are the case to budget from:
|
|
63
|
+
they save more kilobytes than anything but Select, and they still leave the
|
|
64
|
+
largest bedrock bundle in the library, because roving focus and typeahead have
|
|
65
|
+
no native equivalent and ship either way.
|
|
66
|
+
[Should you switch?](./docs/should-you-switch.md#3-the-saving-is-uneven)
|
|
67
|
+
breaks that down by group. The larger win is behavioural anyway: no z-index
|
|
68
|
+
fights, no portal clipping, no repositioning on every scroll frame.
|
|
167
69
|
|
|
168
|
-
##
|
|
70
|
+
## What it costs
|
|
169
71
|
|
|
170
|
-
|
|
72
|
+
bedrock targets current browsers on purpose, and the price is a hard floor.
|
|
73
|
+
Triggers are invoker commands with no JavaScript standing behind them, so:
|
|
171
74
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
[
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
[`docs/compat.html`](./docs/compat.html) — live at
|
|
198
|
-
<https://bedrock.sams.land/compat.html> — tests every platform feature bedrock
|
|
199
|
-
uses in whatever browser you open it in, and says what each missing one does to
|
|
200
|
-
your UI. Chrome 141 scores 20 of 21.
|
|
201
|
-
|
|
202
|
-
Migrating with an agent: [`skills/migrate-to-bedrock`](./skills/migrate-to-bedrock/SKILL.md),
|
|
203
|
-
a Claude Code skill that does the mechanical work and brings you the four
|
|
204
|
-
decisions it cannot make for you.
|
|
205
|
-
|
|
206
|
-
Contributing is [`CONTRIBUTING.md`](./CONTRIBUTING.md); releasing is
|
|
207
|
-
[`RELEASING.md`](./RELEASING.md).
|
|
208
|
-
|
|
209
|
-
[`docs/gaps.md`](./docs/gaps.md) is the case against adopting this. Read it
|
|
210
|
-
first if you are evaluating.
|
|
75
|
+
| | Chrome | Firefox | Safari |
|
|
76
|
+
| --- | --- | --- | --- |
|
|
77
|
+
| Minimum | **135** | **144** | **26.2** |
|
|
78
|
+
|
|
79
|
+
Above that line, missing features degrade: placement falls back to the centre of
|
|
80
|
+
the viewport, transitions are skipped, a `<select>` renders as the OS dropdown.
|
|
81
|
+
The component still opens, closes, traps focus and is announced correctly. Below
|
|
82
|
+
it, nothing opens at all.
|
|
83
|
+
|
|
84
|
+
[Browser support](./docs/compat.md) has every feature, its minimum version in
|
|
85
|
+
each engine, and what its absence does to your UI, measured in the browser you
|
|
86
|
+
open it in.
|
|
87
|
+
|
|
88
|
+
## Where to start
|
|
89
|
+
|
|
90
|
+
- **[Getting started](./docs/getting-started.md)**: install, a first component,
|
|
91
|
+
and the one rule that applies to every trigger.
|
|
92
|
+
- **[Should you switch?](./docs/should-you-switch.md)**: the case against
|
|
93
|
+
adopting this. Read it first if you are evaluating.
|
|
94
|
+
- **[Migrating from Radix](./docs/migration-from-radix.md)**: what changes,
|
|
95
|
+
what breaks, and what to do about it.
|
|
96
|
+
- **[shadcn registry](./docs/shadcn-registry.md)**: shadcn's own components with
|
|
97
|
+
Radix swapped for bedrock, installable with `npx shadcn add`.
|
|
98
|
+
- **[Agent skill](./skills/migrate-to-bedrock/SKILL.md)**: does the mechanical
|
|
99
|
+
migration and brings you the four decisions it cannot make for you.
|
|
211
100
|
|
|
212
101
|
## Status
|
|
213
102
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
103
|
+
`0.1.1` on npm. All 29 primitives, 200 Playwright tests against real Chrome.
|
|
104
|
+
What is missing is soak time and other engines, not components.
|
|
105
|
+
|
|
106
|
+
[Contributing](./CONTRIBUTING.md) · [Releasing](./RELEASING.md) ·
|
|
107
|
+
[Changelog](./CHANGELOG.md)
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* All of them are safe to call while server-rendering.
|
|
6
6
|
*/
|
|
7
7
|
/**
|
|
8
|
-
* `interestfor` — hover and focus intent without timers.
|
|
9
|
-
*
|
|
10
|
-
* JavaScript path as their normal one rather
|
|
8
|
+
* `interestfor` — hover and focus intent without timers. In Chrome since 142
|
|
9
|
+
* and in no other engine, and still not on a standards track, which is why
|
|
10
|
+
* Tooltip and HoverCard ship the JavaScript path as their normal one rather
|
|
11
|
+
* than as a contingency.
|
|
11
12
|
*/
|
|
12
13
|
export declare function supportsInterestInvokers(): boolean;
|
|
13
14
|
/** Anchor positioning. Without it, overlays land where the UA puts them. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED,4EAA4E;AAC5E,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,OAAO,CAM9C;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD"}
|
package/dist/capabilities.js
CHANGED
|
@@ -8,9 +8,10 @@ import { useSyncExternalStore } from 'react';
|
|
|
8
8
|
const hasDom = typeof window !== 'undefined';
|
|
9
9
|
const noopSubscribe = () => () => { };
|
|
10
10
|
/**
|
|
11
|
-
* `interestfor` — hover and focus intent without timers.
|
|
12
|
-
*
|
|
13
|
-
* JavaScript path as their normal one rather
|
|
11
|
+
* `interestfor` — hover and focus intent without timers. In Chrome since 142
|
|
12
|
+
* and in no other engine, and still not on a standards track, which is why
|
|
13
|
+
* Tooltip and HoverCard ship the JavaScript path as their normal one rather
|
|
14
|
+
* than as a contingency.
|
|
14
15
|
*/
|
|
15
16
|
export function supportsInterestInvokers() {
|
|
16
17
|
return hasDom && 'interestForElement' in HTMLButtonElement.prototype;
|
package/dist/capabilities.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAE5C,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,WAAW,CAAA;AAC5C,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;AAEpC
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAE5C,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,WAAW,CAAA;AAC5C,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;AAEpC;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,MAAM,IAAI,oBAAoB,IAAI,iBAAiB,CAAC,SAAS,CAAA;AACtE,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,yBAAyB;IACvC,OAAO,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;AACrD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,oBAAoB;IAClC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAEzB,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC7C,OAAO,CAAC,OAAO,GAAG,MAAM,CAAA;IACxB,OAAO,OAAO,CAAC,OAAO,KAAK,MAAM,CAAA;AACnC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,oBAAoB,CAAC,aAAa,EAAE,wBAAwB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;AACnF,CAAC"}
|
|
@@ -6,8 +6,8 @@ export interface CollapsibleRootProps extends ComponentPropsWithRef<'details'>,
|
|
|
6
6
|
onOpenChange?(open: boolean): void;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* `<summary>` only works as a child of `<details>`, so the parts are bound by
|
|
10
|
+
* nesting: nothing to wire by id, no invoker involved.
|
|
11
11
|
*
|
|
12
12
|
* Which means `defaultOpen` is a plain attribute rather than an imperative call
|
|
13
13
|
* on mount — the disclosure is open in the HTML before any script runs.
|
package/dist/collapsible/root.js
CHANGED
|
@@ -5,8 +5,8 @@ import { useOpenState } from '../open-state.js';
|
|
|
5
5
|
import { Slot } from '../slot.js';
|
|
6
6
|
import { CollapsibleContext } from './shared.js';
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* `<summary>` only works as a child of `<details>`, so the parts are bound by
|
|
9
|
+
* nesting: nothing to wire by id, no invoker involved.
|
|
10
10
|
*
|
|
11
11
|
* Which means `defaultOpen` is a plain attribute rather than an imperative call
|
|
12
12
|
* on mount — the disclosure is open in the HTML before any script runs.
|
package/dist/interest.d.ts
CHANGED
|
@@ -5,17 +5,24 @@ export interface InterestOptions {
|
|
|
5
5
|
hoverableContent: boolean;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Hover and
|
|
9
|
-
* something we can rely on.
|
|
8
|
+
* Hover, focus and press intent, in JavaScript, for as long as `interestfor` is
|
|
9
|
+
* not something we can rely on.
|
|
10
10
|
*
|
|
11
|
-
* This is the fallback the compat table calls "replaceable":
|
|
12
|
-
*
|
|
11
|
+
* This is the fallback the compat table calls "replaceable": where the attribute
|
|
12
|
+
* is supported, `useInterest` stops opening anything and the same props become
|
|
13
13
|
* declarative. Nothing above it changes — which is the entire reason
|
|
14
14
|
* `delayDuration` is not called `interest-show-delay`.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* One thing stays attached either way. A long press ends in a click, and a
|
|
17
|
+
* browser answering the press itself still lets that click through, so the
|
|
18
|
+
* gesture previews the link *and* follows it. Tracking the press costs four
|
|
19
|
+
* listeners and an early return; leaving it to the platform costs a navigation
|
|
20
|
+
* nobody asked for.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately not a general hover library: it does the gestures the pattern
|
|
23
|
+
* needs — pointer in, pointer out, focus, blur, and the long press that stands
|
|
24
|
+
* in for all four on a touch screen — and leaves dismissal to the popover,
|
|
25
|
+
* which already handles Escape and light dismiss.
|
|
19
26
|
*
|
|
20
27
|
* Listeners are attached when a node registers, not from an effect that runs
|
|
21
28
|
* each render. That distinction is load-bearing: opening the card is itself a
|
package/dist/interest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interest.d.ts","sourceRoot":"","sources":["../src/interest.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,gBAAgB,EAAE,OAAO,CAAA;CAC1B;
|
|
1
|
+
{"version":3,"file":"interest.d.ts","sourceRoot":"","sources":["../src/interest.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AA6CD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,EAAE,eAAe;4BAoO5E,WAAW,GAAG,IAAI;oCAWlB,WAAW,GAAG,IAAI;EAwB5B"}
|
package/dist/interest.js
CHANGED
|
@@ -1,17 +1,63 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from 'react';
|
|
2
2
|
import { supportsInterestInvokers } from './capabilities.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* A press long enough to be a deliberate gesture rather than a tap. iOS and
|
|
5
|
+
* Android both use half a second for their own long-press, so it is the number
|
|
6
|
+
* a thumb already knows — and it is deliberately not `showDelay`, because a
|
|
7
|
+
* press is a different gesture from a pointer coming to rest, and a consumer
|
|
8
|
+
* tuning one has said nothing about the other.
|
|
9
|
+
*/
|
|
10
|
+
const PRESS_DURATION = 500;
|
|
11
|
+
/** How far a finger may drift and still be pressing rather than scrolling. */
|
|
12
|
+
const PRESS_SLOP = 10;
|
|
13
|
+
/** Long enough to catch the click a lift produces, short enough to catch only that one. */
|
|
14
|
+
const CLICK_GRACE = 400;
|
|
15
|
+
/**
|
|
16
|
+
* Whether the focus is one a tooltip should answer.
|
|
17
|
+
*
|
|
18
|
+
* Tapping a control focuses it on Android, and a tooltip that appears on tap is
|
|
19
|
+
* a popover with extra steps. `:focus-visible` is the platform's own answer to
|
|
20
|
+
* "did this focus come from a pointer", so we ask it rather than tracking the
|
|
21
|
+
* last input type ourselves.
|
|
22
|
+
*/
|
|
23
|
+
function focusIsVisible(node) {
|
|
24
|
+
try {
|
|
25
|
+
return node.matches(':focus-visible');
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// An engine that does not know the selector throws. Showing on every focus
|
|
29
|
+
// is the older behaviour and the safer one: an unwanted tooltip beats a
|
|
30
|
+
// keyboard user who can never see one.
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A touch pointer reports enter on touchdown and leave on lift, so the hover
|
|
36
|
+
* path would make every tap a half-open tooltip. Touch has its own gesture; the
|
|
37
|
+
* hover handlers are for the pointers that actually hover.
|
|
38
|
+
*/
|
|
39
|
+
function hovering(event) {
|
|
40
|
+
return event.pointerType !== 'touch';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Hover, focus and press intent, in JavaScript, for as long as `interestfor` is
|
|
44
|
+
* not something we can rely on.
|
|
6
45
|
*
|
|
7
|
-
* This is the fallback the compat table calls "replaceable":
|
|
8
|
-
*
|
|
46
|
+
* This is the fallback the compat table calls "replaceable": where the attribute
|
|
47
|
+
* is supported, `useInterest` stops opening anything and the same props become
|
|
9
48
|
* declarative. Nothing above it changes — which is the entire reason
|
|
10
49
|
* `delayDuration` is not called `interest-show-delay`.
|
|
11
50
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
51
|
+
* One thing stays attached either way. A long press ends in a click, and a
|
|
52
|
+
* browser answering the press itself still lets that click through, so the
|
|
53
|
+
* gesture previews the link *and* follows it. Tracking the press costs four
|
|
54
|
+
* listeners and an early return; leaving it to the platform costs a navigation
|
|
55
|
+
* nobody asked for.
|
|
56
|
+
*
|
|
57
|
+
* Deliberately not a general hover library: it does the gestures the pattern
|
|
58
|
+
* needs — pointer in, pointer out, focus, blur, and the long press that stands
|
|
59
|
+
* in for all four on a touch screen — and leaves dismissal to the popover,
|
|
60
|
+
* which already handles Escape and light dismiss.
|
|
15
61
|
*
|
|
16
62
|
* Listeners are attached when a node registers, not from an effect that runs
|
|
17
63
|
* each render. That distinction is load-bearing: opening the card is itself a
|
|
@@ -23,18 +69,27 @@ export function useInterest({ showDelay, hideDelay, hoverableContent }) {
|
|
|
23
69
|
const triggerRef = useRef(null);
|
|
24
70
|
const contentRef = useRef(null);
|
|
25
71
|
const timer = useRef(0);
|
|
72
|
+
const pressTimer = useRef(0);
|
|
73
|
+
const clickTimer = useRef(0);
|
|
74
|
+
// Null between gestures. `held` flips once our own press has lasted long
|
|
75
|
+
// enough to have opened something, which is what separates a press from a
|
|
76
|
+
// tap; `openAtDown` is what tells a press that opened the panel from a tap on
|
|
77
|
+
// a trigger whose panel was already showing.
|
|
78
|
+
const press = useRef(null);
|
|
26
79
|
// Read at call time, so changing a delay never means rebinding anything.
|
|
27
80
|
const options = useRef({ showDelay, hideDelay, hoverableContent });
|
|
28
81
|
options.current = { showDelay, hideDelay, hoverableContent };
|
|
29
82
|
const clear = useCallback(() => window.clearTimeout(timer.current), []);
|
|
83
|
+
const isOpen = useCallback(() => contentRef.current?.matches(':popover-open') === true, []);
|
|
84
|
+
const reveal = useCallback(() => {
|
|
85
|
+
const content = contentRef.current;
|
|
86
|
+
if (content && !isOpen())
|
|
87
|
+
content.showPopover();
|
|
88
|
+
}, [isOpen]);
|
|
30
89
|
const show = useCallback(() => {
|
|
31
90
|
clear();
|
|
32
|
-
timer.current = window.setTimeout(
|
|
33
|
-
|
|
34
|
-
if (content && !content.matches(':popover-open'))
|
|
35
|
-
content.showPopover();
|
|
36
|
-
}, options.current.showDelay);
|
|
37
|
-
}, [clear]);
|
|
91
|
+
timer.current = window.setTimeout(reveal, options.current.showDelay);
|
|
92
|
+
}, [clear, reveal]);
|
|
38
93
|
const hide = useCallback(() => {
|
|
39
94
|
clear();
|
|
40
95
|
timer.current = window.setTimeout(() => {
|
|
@@ -43,32 +98,144 @@ export function useInterest({ showDelay, hideDelay, hoverableContent }) {
|
|
|
43
98
|
content.hidePopover();
|
|
44
99
|
}, options.current.hideDelay);
|
|
45
100
|
}, [clear]);
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
101
|
+
const enter = useCallback((event) => {
|
|
102
|
+
if (hovering(event))
|
|
103
|
+
show();
|
|
104
|
+
}, [show]);
|
|
105
|
+
const leave = useCallback((event) => {
|
|
106
|
+
if (hovering(event))
|
|
107
|
+
hide();
|
|
108
|
+
}, [hide]);
|
|
109
|
+
const focus = useCallback((event) => {
|
|
110
|
+
if (focusIsVisible(event.currentTarget))
|
|
111
|
+
show();
|
|
112
|
+
}, [show]);
|
|
113
|
+
const keepOpen = useCallback((event) => {
|
|
114
|
+
if (hovering(event) && options.current.hoverableContent)
|
|
48
115
|
clear();
|
|
49
116
|
}, [clear]);
|
|
50
|
-
const leaveContent = useCallback(() => {
|
|
51
|
-
if (options.current.hoverableContent)
|
|
117
|
+
const leaveContent = useCallback((event) => {
|
|
118
|
+
if (hovering(event) && options.current.hoverableContent)
|
|
52
119
|
hide();
|
|
53
120
|
}, [hide]);
|
|
121
|
+
const suppressClick = useCallback((event) => {
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
event.stopPropagation();
|
|
124
|
+
}, []);
|
|
125
|
+
/**
|
|
126
|
+
* The lift of a press produces a click, and on an `<a>` that click is a
|
|
127
|
+
* navigation. A press asked to see more about the control, not to activate
|
|
128
|
+
* it, so exactly one click is swallowed — with a deadline, so a press that
|
|
129
|
+
* ends without one does not leave a trap for the next real click.
|
|
130
|
+
*/
|
|
131
|
+
const swallowClick = useCallback((node) => {
|
|
132
|
+
node.addEventListener('click', suppressClick, { capture: true, once: true });
|
|
133
|
+
window.clearTimeout(clickTimer.current);
|
|
134
|
+
clickTimer.current = window.setTimeout(() => node.removeEventListener('click', suppressClick, true), CLICK_GRACE);
|
|
135
|
+
}, [suppressClick]);
|
|
136
|
+
/**
|
|
137
|
+
* A long press is how a touch screen asks to see something without
|
|
138
|
+
* activating it — the gesture iOS uses for its own link previews, and the one
|
|
139
|
+
* `interestfor` answers where the platform runs intent itself. The press is
|
|
140
|
+
* tracked either way; only the opening is ours.
|
|
141
|
+
*
|
|
142
|
+
* While ours runs, selection is off. Otherwise the press is a text selection
|
|
143
|
+
* on Android and a selection magnifier on iOS before it is ever ours. It is
|
|
144
|
+
* turned off for the gesture rather than for the life of the trigger, because
|
|
145
|
+
* a hover card trigger is usually a link in a paragraph and permanently
|
|
146
|
+
* unselectable text drops out of the selection around it.
|
|
147
|
+
*/
|
|
148
|
+
const startPress = useCallback((event) => {
|
|
149
|
+
const pointer = event;
|
|
150
|
+
if (pointer.pointerType !== 'touch')
|
|
151
|
+
return;
|
|
152
|
+
const node = event.currentTarget;
|
|
153
|
+
window.clearTimeout(pressTimer.current);
|
|
154
|
+
press.current = { x: pointer.clientX, y: pointer.clientY, held: false, openAtDown: isOpen() };
|
|
155
|
+
if (supportsInterestInvokers())
|
|
156
|
+
return;
|
|
157
|
+
node.style.setProperty('user-select', 'none');
|
|
158
|
+
node.style.setProperty('-webkit-user-select', 'none');
|
|
159
|
+
pressTimer.current = window.setTimeout(() => {
|
|
160
|
+
if (!press.current)
|
|
161
|
+
return;
|
|
162
|
+
press.current.held = true;
|
|
163
|
+
reveal();
|
|
164
|
+
}, PRESS_DURATION);
|
|
165
|
+
}, [isOpen, reveal]);
|
|
166
|
+
const endPress = useCallback((node) => {
|
|
167
|
+
window.clearTimeout(pressTimer.current);
|
|
168
|
+
press.current = null;
|
|
169
|
+
node.style.removeProperty('user-select');
|
|
170
|
+
node.style.removeProperty('-webkit-user-select');
|
|
171
|
+
}, []);
|
|
172
|
+
const movePress = useCallback((event) => {
|
|
173
|
+
const state = press.current;
|
|
174
|
+
if (!state || state.held)
|
|
175
|
+
return;
|
|
176
|
+
const pointer = event;
|
|
177
|
+
const drifted = Math.abs(pointer.clientX - state.x) > PRESS_SLOP ||
|
|
178
|
+
Math.abs(pointer.clientY - state.y) > PRESS_SLOP;
|
|
179
|
+
// A finger that has moved that far is scrolling, and a page that opens
|
|
180
|
+
// tooltips while you scroll past them is unusable.
|
|
181
|
+
if (drifted)
|
|
182
|
+
endPress(event.currentTarget);
|
|
183
|
+
}, [endPress]);
|
|
184
|
+
const liftPress = useCallback((event) => {
|
|
185
|
+
const state = press.current;
|
|
186
|
+
const node = event.currentTarget;
|
|
187
|
+
if (!state)
|
|
188
|
+
return;
|
|
189
|
+
endPress(node);
|
|
190
|
+
// The lift is a pointerup outside every open popover, and the popover the
|
|
191
|
+
// press opened did not exist when the finger went down — so as far as
|
|
192
|
+
// light dismiss is concerned it was never part of this gesture, and it
|
|
193
|
+
// closes. Re-assert it in the same task the dismissal ran in: nothing is
|
|
194
|
+
// painted between the two, so the card the press opened simply stays.
|
|
195
|
+
if (state.held)
|
|
196
|
+
reveal();
|
|
197
|
+
// Whoever opened it, the lift still produces a click, and on an `<a>` that
|
|
198
|
+
// click is a navigation. A browser answering the hold itself lets it
|
|
199
|
+
// through, so a long press there previews *and* follows the link; only
|
|
200
|
+
// that second half is ours to stop. A panel that was already showing when
|
|
201
|
+
// the finger went down is not this gesture's, and the tap under it stands.
|
|
202
|
+
if (state.held || (!state.openAtDown && isOpen()))
|
|
203
|
+
swallowClick(node);
|
|
204
|
+
}, [endPress, isOpen, reveal, swallowClick]);
|
|
205
|
+
const cancelPress = useCallback((event) => endPress(event.currentTarget), [endPress]);
|
|
206
|
+
// Android offers its own long-press menu on the same gesture, and whichever
|
|
207
|
+
// of the two the user gets should not be a race. iOS is asked in CSS instead,
|
|
208
|
+
// by the `-webkit-touch-callout` the trigger carries.
|
|
209
|
+
const suppressCallout = useCallback((event) => {
|
|
210
|
+
if (press.current)
|
|
211
|
+
event.preventDefault();
|
|
212
|
+
}, []);
|
|
54
213
|
const bindTrigger = useCallback((node, add) => {
|
|
55
214
|
const method = add ? 'addEventListener' : 'removeEventListener';
|
|
56
|
-
|
|
57
|
-
|
|
215
|
+
// Touch captures its pointer implicitly, so every one of these lands on
|
|
216
|
+
// the trigger for the whole gesture, wherever the finger has gone. They
|
|
217
|
+
// are bound even where the platform runs intent itself, because the click
|
|
218
|
+
// a press ends in is left to us there — see `liftPress`.
|
|
219
|
+
node[method]('pointerdown', startPress);
|
|
220
|
+
node[method]('pointermove', movePress);
|
|
221
|
+
node[method]('pointerup', liftPress);
|
|
222
|
+
node[method]('pointercancel', cancelPress);
|
|
223
|
+
if (supportsInterestInvokers())
|
|
224
|
+
return;
|
|
225
|
+
node[method]('pointerenter', enter);
|
|
226
|
+
node[method]('pointerleave', leave);
|
|
58
227
|
// Focus, not focusin: the trigger itself is the control, and a tooltip
|
|
59
228
|
// should not appear because something inside it was focused.
|
|
60
|
-
node[method]('focus',
|
|
229
|
+
node[method]('focus', focus);
|
|
61
230
|
node[method]('blur', hide);
|
|
62
|
-
|
|
231
|
+
node[method]('contextmenu', suppressCallout);
|
|
232
|
+
}, [startPress, movePress, liftPress, cancelPress, enter, leave, focus, hide, suppressCallout]);
|
|
63
233
|
const bindContent = useCallback((node, add) => {
|
|
64
234
|
const method = add ? 'addEventListener' : 'removeEventListener';
|
|
65
235
|
node[method]('pointerenter', keepOpen);
|
|
66
236
|
node[method]('pointerleave', leaveContent);
|
|
67
237
|
}, [keepOpen, leaveContent]);
|
|
68
238
|
const registerTrigger = useCallback((node) => {
|
|
69
|
-
// When the platform does the work, nothing is attached and no timer runs.
|
|
70
|
-
if (supportsInterestInvokers())
|
|
71
|
-
return;
|
|
72
239
|
const previous = triggerRef.current;
|
|
73
240
|
if (previous)
|
|
74
241
|
bindTrigger(previous, false);
|
|
@@ -77,18 +244,22 @@ export function useInterest({ showDelay, hideDelay, hoverableContent }) {
|
|
|
77
244
|
bindTrigger(node, true);
|
|
78
245
|
}, [bindTrigger]);
|
|
79
246
|
const registerInterestContent = useCallback((node) => {
|
|
80
|
-
if (supportsInterestInvokers())
|
|
81
|
-
return;
|
|
82
247
|
const previous = contentRef.current;
|
|
83
248
|
if (previous)
|
|
84
249
|
bindContent(previous, false);
|
|
250
|
+
// Held either way: where the platform runs intent, the lift still has to
|
|
251
|
+
// ask whether this press is the reason the panel is showing.
|
|
85
252
|
contentRef.current = node;
|
|
86
|
-
if (node)
|
|
253
|
+
if (node && !supportsInterestInvokers())
|
|
87
254
|
bindContent(node, true);
|
|
88
255
|
}, [bindContent]);
|
|
89
256
|
// Only unmount. A pending timer outliving the component would call
|
|
90
257
|
// showPopover() on a detached node.
|
|
91
|
-
useEffect(() =>
|
|
258
|
+
useEffect(() => () => {
|
|
259
|
+
window.clearTimeout(timer.current);
|
|
260
|
+
window.clearTimeout(pressTimer.current);
|
|
261
|
+
window.clearTimeout(clickTimer.current);
|
|
262
|
+
}, []);
|
|
92
263
|
return { registerTrigger, registerInterestContent };
|
|
93
264
|
}
|
|
94
265
|
//# sourceMappingURL=interest.js.map
|
package/dist/interest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interest.js","sourceRoot":"","sources":["../src/interest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AASzD
|
|
1
|
+
{"version":3,"file":"interest.js","sourceRoot":"","sources":["../src/interest.ts"],"names":[],"mappings":"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"}
|
package/dist/menu/parts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parts.d.ts","sourceRoot":"","sources":["../../src/menu/parts.tsx"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,qBAAqB,EAI3B,MAAM,OAAO,CAAA;AACd,OAAO,EAA+B,KAAK,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAA;AAK9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAI5C,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB,CAAC,QAAQ,CAAC,EAAE,YAAY;CAAG;AAE1F,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,+BAkB9E;AAED,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB,CAAC,KAAK,CAAC,EAAE,YAAY;IAClF,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,IAAe,EACf,KAAe,EACf,UAAc,EACd,eAAsB,EACtB,IAAW,EACX,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,gBAAgB,+
|
|
1
|
+
{"version":3,"file":"parts.d.ts","sourceRoot":"","sources":["../../src/menu/parts.tsx"],"names":[],"mappings":"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"}
|
package/dist/menu/parts.js
CHANGED
|
@@ -29,14 +29,24 @@ export function MenuContent({ asChild, children, side = 'bottom', align = 'start
|
|
|
29
29
|
useEffect(() => {
|
|
30
30
|
if (!open)
|
|
31
31
|
return;
|
|
32
|
-
// The popover opens synchronously on the invoker's click; this effect runs
|
|
33
|
-
// a frame or two later. Anything the user did in between — a key that
|
|
34
|
-
// already moved focus into the menu — wins, because re-focusing the first
|
|
35
|
-
// item here would silently undo it.
|
|
36
32
|
const menu = nodeRef.current;
|
|
37
|
-
if (!menu
|
|
33
|
+
if (!menu)
|
|
38
34
|
return;
|
|
39
|
-
|
|
35
|
+
// A frame, because `open` is set on `beforetoggle` — which fires while the
|
|
36
|
+
// popover is still `display: none`, and `focus()` on a hidden element does
|
|
37
|
+
// nothing at all. By the next frame `toggle` has fired and it is painted.
|
|
38
|
+
//
|
|
39
|
+
// This used to work by accident: the open state was briefly cleared and
|
|
40
|
+
// re-set, so the effect ran a second time, late enough to land. Fixing that
|
|
41
|
+
// churn is what exposed this.
|
|
42
|
+
const frame = requestAnimationFrame(() => {
|
|
43
|
+
// Anything the user did in between wins — a key that already moved focus
|
|
44
|
+
// into the menu must not be silently undone.
|
|
45
|
+
if (menu.contains(document.activeElement))
|
|
46
|
+
return;
|
|
47
|
+
menu.querySelector('[data-bedrock-roving-item]')?.focus();
|
|
48
|
+
});
|
|
49
|
+
return () => cancelAnimationFrame(frame);
|
|
40
50
|
}, [open]);
|
|
41
51
|
return (_jsx(Part, { ...props, id: id, popover: "auto", role: "menu", style: { ...placementStyles(anchor, { side, align, sideOffset, avoidCollisions }), ...style }, "data-side": side, "data-align": align, ref: useComposedRefs(ref, registerContent, registerContainer, (node) => {
|
|
42
52
|
nodeRef.current = node;
|
package/dist/menu/parts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parts.js","sourceRoot":"","sources":["../../src/menu/parts.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,KAAK,EACL,OAAO,EACP,MAAM,EACN,QAAQ,GAKT,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,UAAU,EAAE,eAAe,EAAyB,MAAM,WAAW,CAAA;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAItD,MAAM,UAAU,WAAW,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,EAAoB;IAC7E,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,cAAc,CAAC,CAAA;IACrD,MAAM,IAAI,GAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAA;IAEnD,OAAO,CACL,KAAC,IAAI,OACC,KAAK,EACT,IAAI,EAAC,QAAQ,EACb,UAAU,EAAE,EAAE,EACd,OAAO,EAAC,gBAAgB,mBACV,MAAM,EACpB,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,EAAkB,EACvD,GAAG,EAAE,eAAe,CAAc,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAC9C,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CACjD,+BACyB,EAAE,GAC5B,CACH,CAAA;AACH,CAAC;AAUD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,KAAK,GAAG,OAAO,EACf,UAAU,GAAG,CAAC,EACd,eAAe,GAAG,IAAI,EACtB,IAAI,GAAG,IAAI,EACX,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACS;IACjB,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,cAAc,CAAC,cAAc,CAAC,CAAA;IAC5E,MAAM,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3F,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAA;IAClC,MAAM,OAAO,GAAG,MAAM,CAAqB,IAAI,CAAC,CAAA;IAChD,MAAM,IAAI,GAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAA;IAEhD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAM;QAEjB,2EAA2E;QAC3E,
|
|
1
|
+
{"version":3,"file":"parts.js","sourceRoot":"","sources":["../../src/menu/parts.tsx"],"names":[],"mappings":"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"}
|
package/dist/open-state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-state.d.ts","sourceRoot":"","sources":["../src/open-state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"open-state.d.ts","sourceRoot":"","sources":["../src/open-state.ts"],"names":[],"mappings":"AA8BA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,EAAE,WAAW,UAAQ;;oBA2DzE,WAAW,GAAG,IAAI;;EA+B5B"}
|
package/dist/open-state.js
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import { useCallback, useRef, useState } from 'react';
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Separate calls, not `:open, :popover-open`. An unknown selector invalidates a
|
|
4
|
+
* whole selector list and makes `matches()` throw, so combining them would mean
|
|
5
|
+
* an engine missing either one reports every element as closed.
|
|
6
|
+
*/
|
|
7
|
+
function matchesSelector(node, selector) {
|
|
4
8
|
try {
|
|
5
|
-
return node.matches(
|
|
9
|
+
return node.matches(selector);
|
|
6
10
|
}
|
|
7
11
|
catch {
|
|
8
12
|
return false;
|
|
9
13
|
}
|
|
10
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether the element is open, by the DOM's own reckoning.
|
|
17
|
+
*
|
|
18
|
+
* `:open` covers `<dialog>`, `<details>` and `<select>`. It does **not** match
|
|
19
|
+
* an open popover in Chrome today — measured, not assumed — which is why
|
|
20
|
+
* `:popover-open` is asked separately rather than trusted to be covered.
|
|
21
|
+
*
|
|
22
|
+
* Getting this wrong is not subtle: `settle()` reads it a frame after opening,
|
|
23
|
+
* concludes a perfectly open popover is closed, and unmounts the children. The
|
|
24
|
+
* popover stays open and empty, collapsing to the width of nothing.
|
|
25
|
+
*/
|
|
26
|
+
function isOpen(node) {
|
|
27
|
+
return matchesSelector(node, ':popover-open') || matchesSelector(node, ':open');
|
|
28
|
+
}
|
|
11
29
|
/**
|
|
12
30
|
* Tracks what the DOM is actually doing, so parts can render children only
|
|
13
31
|
* while there is something to see.
|
package/dist/open-state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-state.js","sourceRoot":"","sources":["../src/open-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAErD
|
|
1
|
+
{"version":3,"file":"open-state.js","sourceRoot":"","sources":["../src/open-state.ts"],"names":[],"mappings":"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"}
|
package/dist/tooltip/parts.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ export interface TooltipTriggerProps extends ComponentPropsWithRef<'button'>, As
|
|
|
11
11
|
* The `interestfor` attribute is emitted only when the platform can act on it.
|
|
12
12
|
* Otherwise the same node is handed to the JavaScript fallback, and nothing
|
|
13
13
|
* about the markup a consumer writes changes either way.
|
|
14
|
+
*
|
|
15
|
+
* The callout suppression goes with the fallback rather than with the trigger:
|
|
16
|
+
* a long press is how a touch screen asks to see more, and on iOS the callout
|
|
17
|
+
* menu — the share sheet on a link, the copy bar on text — takes that gesture
|
|
18
|
+
* first. Where the platform runs intent itself it also owns that conflict, so
|
|
19
|
+
* we leave it alone. Selection is only turned off for the length of a press,
|
|
20
|
+
* in `interest.ts`, so a link in a paragraph still comes with the paragraph.
|
|
14
21
|
*/
|
|
15
22
|
export declare function TooltipTrigger({ asChild, ref, style, ...props }: TooltipTriggerProps): import("react").JSX.Element;
|
|
16
23
|
export interface TooltipContentProps extends ComponentPropsWithRef<'div'>, AsChildProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parts.d.ts","sourceRoot":"","sources":["../../src/tooltip/parts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAe,MAAM,OAAO,CAAA;AAC/D,OAAO,EAAmB,KAAK,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAA;AAIlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAI5C,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB,CAAC,QAAQ,CAAC,EAAE,YAAY;CAAG;AAE7F
|
|
1
|
+
{"version":3,"file":"parts.d.ts","sourceRoot":"","sources":["../../src/tooltip/parts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAe,MAAM,OAAO,CAAA;AAC/D,OAAO,EAAmB,KAAK,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAA;AAIlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAI5C,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB,CAAC,QAAQ,CAAC,EAAE,YAAY;CAAG;AAE7F;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,mBAAmB,+BAuBpF;AAED,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB,CAAC,KAAK,CAAC,EAAE,YAAY;IACrF,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,QAAQ,EACR,IAAY,EACZ,KAAgB,EAChB,UAAc,EACd,eAAsB,EACtB,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,mBAAmB,+BAoBrB"}
|
package/dist/tooltip/parts.js
CHANGED
|
@@ -13,11 +13,22 @@ import { useTooltipContext } from './shared.js';
|
|
|
13
13
|
* The `interestfor` attribute is emitted only when the platform can act on it.
|
|
14
14
|
* Otherwise the same node is handed to the JavaScript fallback, and nothing
|
|
15
15
|
* about the markup a consumer writes changes either way.
|
|
16
|
+
*
|
|
17
|
+
* The callout suppression goes with the fallback rather than with the trigger:
|
|
18
|
+
* a long press is how a touch screen asks to see more, and on iOS the callout
|
|
19
|
+
* menu — the share sheet on a link, the copy bar on text — takes that gesture
|
|
20
|
+
* first. Where the platform runs intent itself it also owns that conflict, so
|
|
21
|
+
* we leave it alone. Selection is only turned off for the length of a press,
|
|
22
|
+
* in `interest.ts`, so a link in a paragraph still comes with the paragraph.
|
|
16
23
|
*/
|
|
17
24
|
export function TooltipTrigger({ asChild, ref, style, ...props }) {
|
|
18
25
|
const { id, anchor, native, registerTrigger } = useTooltipContext('Tooltip.Trigger');
|
|
19
26
|
const Part = asChild ? Slot : 'button';
|
|
20
|
-
return (_jsx(Part, { ...props, ...(native ? { interestfor: id } : {}), "aria-describedby": id, style: {
|
|
27
|
+
return (_jsx(Part, { ...props, ...(native ? { interestfor: id } : {}), "aria-describedby": id, style: {
|
|
28
|
+
anchorName: anchor,
|
|
29
|
+
...(native ? null : { WebkitTouchCallout: 'none' }),
|
|
30
|
+
...style,
|
|
31
|
+
}, ref: useComposedRefs(ref, registerTrigger, (node) => validateTrigger(node, 'interest', 'Tooltip.Trigger')), "data-bedrock-tooltip-trigger": "" }));
|
|
21
32
|
}
|
|
22
33
|
export function TooltipContent({ asChild, children, side = 'top', align = 'center', sideOffset = 6, avoidCollisions = true, style, ref, ...props }) {
|
|
23
34
|
const { id, open, anchor, kind, role, registerContent } = useTooltipContext('Tooltip.Content');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parts.js","sourceRoot":"","sources":["../../src/tooltip/parts.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAyB,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAI5C
|
|
1
|
+
{"version":3,"file":"parts.js","sourceRoot":"","sources":["../../src/tooltip/parts.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAyB,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAI5C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,EAAuB;IACnF,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;IACpF,MAAM,IAAI,GAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAA;IAEnD,OAAO,CACL,KAAC,IAAI,OACC,KAAK,KACL,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,sBAErB,EAAE,EACpB,KAAK,EACH;YACE,UAAU,EAAE,MAAM;YAClB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAAC;YACnD,GAAG,KAAK;SACO,EAEnB,GAAG,EAAE,eAAe,CAAc,GAAG,EAAE,eAAe,EAAE,CAAC,IAAI,EAAE,EAAE,CAC/D,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,iBAAiB,CAAC,CACrD,kCAC4B,EAAE,GAC/B,CACH,CAAA;AACH,CAAC;AASD,MAAM,UAAU,cAAc,CAAC,EAC7B,OAAO,EACP,QAAQ,EACR,IAAI,GAAG,KAAK,EACZ,KAAK,GAAG,QAAQ,EAChB,UAAU,GAAG,CAAC,EACd,eAAe,GAAG,IAAI,EACtB,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACY;IACpB,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;IAC9F,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAA;IAClC,MAAM,IAAI,GAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAA;IAEhD,OAAO,CACL,KAAC,IAAI,OACC,KAAK,EACT,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,IAAI,EACb,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,EAAE,GAAG,eAAe,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,eAClF,IAAI,gBACH,KAAK,EACjB,GAAG,EAAE,eAAe,CAAc,GAAG,EAAE,eAAe,CAAC,0BAClC,EAAE,YAEtB,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAC/B,CACR,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apostel/bedrock",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Headless React primitives built on native platform features",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -43,33 +43,44 @@
|
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsc -p tsconfig.build.json && node scripts/postbuild.mjs",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
46
|
+
"changeset": "changeset",
|
|
47
|
+
"compat:build": "node scripts/build-compat.mjs",
|
|
48
|
+
"demos:build": "vite build --config vite.demos.config.ts",
|
|
49
|
+
"docs:baseline": "node scripts/build-baseline.mjs",
|
|
50
|
+
"docs:build": "node scripts/build-docs.mjs && npm run demos:build",
|
|
49
51
|
"format": "oxfmt",
|
|
50
52
|
"format:check": "oxfmt --check",
|
|
53
|
+
"lint": "oxlint",
|
|
54
|
+
"lint:graph": "depcruise src --config .dependency-cruiser.cjs",
|
|
55
|
+
"prepublishOnly": "npm run verify",
|
|
51
56
|
"registry:build": "node scripts/build-registry.mjs",
|
|
57
|
+
"release": "changeset publish",
|
|
52
58
|
"test": "playwright test",
|
|
53
59
|
"test:install": "playwright install chromium",
|
|
60
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
54
61
|
"verify": "npm run format:check && npm run lint && npm run typecheck && npm run lint:graph && npm run build && npm run test",
|
|
55
|
-
"
|
|
56
|
-
"docs:build": "node scripts/build-docs.mjs",
|
|
57
|
-
"changeset": "changeset",
|
|
58
|
-
"version": "changeset version",
|
|
59
|
-
"release": "changeset publish"
|
|
62
|
+
"version": "changeset version"
|
|
60
63
|
},
|
|
61
64
|
"devDependencies": {
|
|
62
65
|
"@axe-core/playwright": "^4.12.1",
|
|
63
66
|
"@changesets/cli": "^3.0.1",
|
|
67
|
+
"@mdn/browser-compat-data": "^8.0.13",
|
|
64
68
|
"@playwright/test": "^1.62.1",
|
|
69
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
65
70
|
"@types/react": "^19.0.0",
|
|
71
|
+
"@types/react-dom": "^19.2.5",
|
|
66
72
|
"@vitejs/plugin-react": "^6.0.5",
|
|
73
|
+
"clsx": "^2.1.1",
|
|
67
74
|
"dependency-cruiser": "^16.0.0",
|
|
75
|
+
"lucide-react": "^1.39.0",
|
|
68
76
|
"marked": "^15.0.12",
|
|
69
77
|
"oxfmt": "^0.61.0",
|
|
70
78
|
"oxlint": "^1.76.0",
|
|
79
|
+
"tailwind-merge": "^3.6.0",
|
|
80
|
+
"tailwindcss": "^4.3.3",
|
|
71
81
|
"typescript": "^5.6.0",
|
|
72
|
-
"vite": "^8.2.0"
|
|
82
|
+
"vite": "^8.2.0",
|
|
83
|
+
"web-features": "^3.36.0"
|
|
73
84
|
},
|
|
74
85
|
"peerDependencies": {
|
|
75
86
|
"react": ">=19",
|