@takazudo/zdtp 0.4.5 → 0.4.7
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 +34 -0
- package/README.md +46 -0
- package/dist/astro/host-adapter.js +69 -56
- package/dist/astro/index.js +1 -1
- package/dist/{autoload-state-DF7TsTgY.js → autoload-state-D26ML6sW.js} +1 -1
- package/dist/bin/server.js +1 -1
- package/dist/config/panel-config.d.ts +32 -0
- package/dist/controls/actions-menu-popover.d.ts +26 -0
- package/dist/controls/help-icon.d.ts +43 -0
- package/dist/controls/tooltip.d.ts +20 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3283 -2932
- package/dist/{load-routing-LJ72261l.js → load-routing-D4H2VOl5.js} +166 -161
- package/dist/{panel-config-CipeKMTz.js → panel-config-Bw7D-25C.js} +242 -184
- package/dist/server/index.js +1 -1
- package/dist/tabs/notes-tab.d.ts +25 -0
- package/dist/testing.js +4 -4
- package/dist/tokens/manifest.d.ts +8 -0
- package/dist/tokens/tier-model.d.ts +24 -0
- package/dist/{tweak-state-xt-tSQ_t.js → tweak-state-CD1y56zR.js} +59 -59
- package/dist/utils/sanitize-html.d.ts +27 -0
- package/dist/utils/unit-cycle.d.ts +61 -0
- package/dist/zdtp.css +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.7
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- fix(server): coalesce same-file token groups in createApplyHandler ([#527](https://github.com/Takazudo/zudo-design-token-panel/pull/527)) (1d84c94)
|
|
8
|
+
|
|
9
|
+
### Other Changes
|
|
10
|
+
|
|
11
|
+
- chore(deps): resolve 19 pnpm audit security advisories ([#525](https://github.com/Takazudo/zudo-design-token-panel/pull/525)) (80c9a0e)
|
|
12
|
+
|
|
13
|
+
## 0.4.6
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- Notes tab — host-configurable token notes as the panel's top page ([#515](https://github.com/Takazudo/zudo-design-token-panel/issues/515)) (4169a05)
|
|
18
|
+
- Palette tab: groups collapsed by default with boxed toggle headers ([#517](https://github.com/Takazudo/zudo-design-token-panel/issues/517)) (2ff5a1e)
|
|
19
|
+
- Container-query responsive header & tabs at narrow panel widths, plus "zdtp" panel title + square corners ([#518](https://github.com/Takazudo/zudo-design-token-panel/issues/518)) (25dff1a)
|
|
20
|
+
- Click-to-cycle unit suffix on value inputs ([#519](https://github.com/Takazudo/zudo-design-token-panel/issues/519)) (b05581d)
|
|
21
|
+
- "?" help tooltips for Literal and Per-mode rows in the Color tab ([#520](https://github.com/Takazudo/zudo-design-token-panel/issues/520)) (c85fd69)
|
|
22
|
+
- `zdtp.show()` — fixed-name global open API ([#523](https://github.com/Takazudo/zudo-design-token-panel/issues/523)) (9b3c636)
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Tooltip repositions correctly after panel resize (ResizeObserver initial-delivery fix) ([#516](https://github.com/Takazudo/zudo-design-token-panel/issues/516)) (d10fe16)
|
|
27
|
+
- Closed a C0-control URL-scheme bypass in the notes-tab HTML sanitizer ([#515](https://github.com/Takazudo/zudo-design-token-panel/issues/515)) (19f7147)
|
|
28
|
+
- Corrected kebab-close dead zone + title truncation in the responsive header ([#518](https://github.com/Takazudo/zudo-design-token-panel/issues/518)) (bfc4b81)
|
|
29
|
+
- `window.zdtp` guards against a null instance and clarifies multi-instance behavior ([#523](https://github.com/Takazudo/zudo-design-token-panel/issues/523)) (bcc71aa)
|
|
30
|
+
|
|
31
|
+
### Other Changes
|
|
32
|
+
|
|
33
|
+
- docs: notes-tab demo in doc-site manifest; help-icon resize-pin trade-off + sanitizer intent documented (82cf7d8, fe1b477)
|
|
34
|
+
- test: VRT baselines re-recorded for zdtp title + square corners; broad coverage added for notes tab, help icons, unit cycling
|
|
35
|
+
- chore: removed consumed `_temp-resource/` prototype scaffold (ccbd18a)
|
|
36
|
+
|
|
3
37
|
## 0.4.5
|
|
4
38
|
|
|
5
39
|
### Features
|
package/README.md
CHANGED
|
@@ -53,6 +53,8 @@ The package builds against Preact (declared as a `peerDependency`) and ships its
|
|
|
53
53
|
|
|
54
54
|
> Visual: a screenshot or short capture would go here. Skipped in the v1 README — a placeholder is worse than nothing. See the external example repos linked in §15 for live demos.
|
|
55
55
|
|
|
56
|
+
**Browser floor:** the panel's own header/tabbar chrome adapts to the panel's *width* (not the viewport) via CSS container queries, which are Baseline 2023 (Safari 16+). The panel is a developer tool used on evergreen browsers, so older browsers simply keep the wide-layout chrome with no JS fallback.
|
|
57
|
+
|
|
56
58
|
---
|
|
57
59
|
|
|
58
60
|
## 2. Install
|
|
@@ -326,6 +328,22 @@ That is the entire integration. `<DesignTokenPanelHost>` emits a JSON `<script>`
|
|
|
326
328
|
window.myapp.toggleDesignPanel();
|
|
327
329
|
```
|
|
328
330
|
|
|
331
|
+
Or use the fixed-name `zdtp` global — no need to remember your own
|
|
332
|
+
`consoleNamespace`:
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
// In the browser devtools console — works regardless of consoleNamespace
|
|
336
|
+
zdtp.show();
|
|
337
|
+
zdtp.hide();
|
|
338
|
+
zdtp.toggle();
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
`zdtp.show()` / `hide()` / `toggle()` are console sugar for the exact same
|
|
342
|
+
open/close verbs `window.myapp.*` exposes (see §10 for the full contract) —
|
|
343
|
+
`window.myapp.*` keeps working unchanged. On an Astro page, `zdtp.*` is
|
|
344
|
+
available as soon as the host-adapter script has run, even before the panel
|
|
345
|
+
bundle itself has loaded.
|
|
346
|
+
|
|
329
347
|
Or wire a hidden keyboard shortcut / dev-only button to call the same helper.
|
|
330
348
|
|
|
331
349
|
### 4.1.4 Stylesheet (self-injected — no consumer import required)
|
|
@@ -472,6 +490,13 @@ export interface PanelInstanceHandle {
|
|
|
472
490
|
}
|
|
473
491
|
```
|
|
474
492
|
|
|
493
|
+
`open()` / `close()` / `toggle()` are the same primitives both
|
|
494
|
+
`window.myapp.*` (§10) and the fixed-name `window.zdtp.*` global (§10) wrap
|
|
495
|
+
for the **default** (most-recently-configured) instance. On a page with more
|
|
496
|
+
than one instance, call `handle.open()` / `.close()` / `.toggle()` directly
|
|
497
|
+
on the specific instance's handle — `window.zdtp.*` always targets the
|
|
498
|
+
default instance only.
|
|
499
|
+
|
|
475
500
|
### 5.3 Field summary
|
|
476
501
|
|
|
477
502
|
| Field | Type | Purpose |
|
|
@@ -1000,6 +1025,27 @@ window.myapp.disableAutoload(); // disarm owner-mode; unmounts the panel
|
|
|
1000
1025
|
|
|
1001
1026
|
All helpers are **async** — the first call lazy-imports the panel module. Subsequent calls share the memoised module promise and resolve synchronously after the first import completes.
|
|
1002
1027
|
|
|
1028
|
+
### Fixed-name global: `window.zdtp`
|
|
1029
|
+
|
|
1030
|
+
`consoleNamespace` is a **required** field on `PanelConfig` — every consumer picks its own value, so `window[consoleNamespace].*` needs the host's chosen namespace before you can open the panel from the console. `window.zdtp` is an additive, fixed-name alias that needs none:
|
|
1031
|
+
|
|
1032
|
+
```ts
|
|
1033
|
+
zdtp.show(); // open the panel (lazy-loads the bundle on first call, same as showDesignPanel())
|
|
1034
|
+
zdtp.hide(); // close the panel
|
|
1035
|
+
zdtp.toggle(); // toggle open/closed
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
- **`show` / `hide` / `toggle` only.** There is no `zdtp.enableAutoload()` — owner-autoload (§10.1) stays on `window[consoleNamespace].*` and the package-root `enableAutoload()` / `disableAutoload()` exports.
|
|
1039
|
+
- **`window[consoleNamespace].*` is unchanged** — `window.zdtp` is sugar layered on top of it, not a replacement. Both stay available side by side.
|
|
1040
|
+
- **Targets the default instance**, exactly like the package-root `showDesignTokenPanel()` / `hideDesignTokenPanel()` / `toggleDesignPanel()` exports and `window[consoleNamespace].*` itself. On an Astro host specifically, the alias binds to whichever instance's adapter script installs it first, rather than re-resolving "the current default" on every call — see `PORTABLE-CONTRACT.md` §6.5 for the exact per-install-site rule. For a page with more than one panel instance, use `configurePanel(cfg)`'s returned handle (§5.2) instead — it is unambiguous regardless of install order.
|
|
1041
|
+
- **Available on both integration paths:**
|
|
1042
|
+
- Non-Astro hosts get it as soon as `@takazudo/zdtp`'s package-root module has loaded (it installs the alias at module init).
|
|
1043
|
+
- Astro hosts get it as soon as the host-adapter `<script>` has run — **before** the panel bundle itself has loaded. The first `zdtp.*` call lazy-imports the bundle, exactly like `window[consoleNamespace].*`.
|
|
1044
|
+
- **Never clobbers a host-defined `window.zdtp`.** If your page already has its own `window.zdtp` for something unrelated, the package leaves it alone and logs a `console.warn` instead of overwriting it — including the edge case of choosing `consoleNamespace: 'zdtp'` yourself.
|
|
1045
|
+
- **Auto-remember applies too** — `zdtp.show()` arms the `:autoload` flag exactly like `showDesignPanel()` (§10.1's Auto-remember footgun note applies here as well).
|
|
1046
|
+
|
|
1047
|
+
See `PORTABLE-CONTRACT.md` §6.5 for the full install-site and no-clobber/no-double-install contract.
|
|
1048
|
+
|
|
1003
1049
|
### Backward-compatible: the on-demand flow is unchanged
|
|
1004
1050
|
|
|
1005
1051
|
The pre-existing on-demand usage — calling `window.<consoleNamespace>.showDesignPanel()` / `hideDesignPanel()` / `toggleDesignPanel()` to lazy-import and initialize the panel — is **unchanged and fully supported**. Owner-autoload (§10.1) is an opt-in layered on top, not a replacement. If you never call `enableAutoload()`, the panel behaves exactly as it always did: nothing loads for any visitor until the first console call.
|
|
@@ -1,102 +1,115 @@
|
|
|
1
|
-
import { c as
|
|
2
|
-
import { g as
|
|
3
|
-
import { s as
|
|
4
|
-
const
|
|
5
|
-
function
|
|
1
|
+
import { c as h, g as u, a as g, b as y, d as P, e as b, f as _, i as A } from "../panel-config-Bw7D-25C.js";
|
|
2
|
+
import { g as c, Z as k } from "../tweak-state-CD1y56zR.js";
|
|
3
|
+
import { s as I, l as E, a as d, c as C, b as S } from "../autoload-state-D26ML6sW.js";
|
|
4
|
+
const r = "tokenpanel-config";
|
|
5
|
+
function T() {
|
|
6
6
|
if (typeof document > "u")
|
|
7
7
|
throw new Error(
|
|
8
8
|
"[design-token-panel] host-adapter loaded without a document; expected to run in a browser context."
|
|
9
9
|
);
|
|
10
|
-
const
|
|
11
|
-
if (!
|
|
10
|
+
const e = document.getElementById(r);
|
|
11
|
+
if (!e)
|
|
12
12
|
throw new Error(
|
|
13
|
-
`[design-token-panel] Inline config script #${
|
|
13
|
+
`[design-token-panel] Inline config script #${r} not found. Ensure <DesignTokenPanelHost config={...} /> is rendered on this page before the host script runs.`
|
|
14
14
|
);
|
|
15
|
-
const
|
|
16
|
-
let
|
|
15
|
+
const t = e.textContent ?? "";
|
|
16
|
+
let n;
|
|
17
17
|
try {
|
|
18
|
-
|
|
18
|
+
n = JSON.parse(t);
|
|
19
19
|
} catch (o) {
|
|
20
20
|
throw new Error(
|
|
21
|
-
`[design-token-panel] Failed to parse inline config from #${
|
|
21
|
+
`[design-token-panel] Failed to parse inline config from #${r}: ${o.message}`
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
|
-
return _(
|
|
24
|
+
return _(n), n;
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
return
|
|
26
|
+
function V(e) {
|
|
27
|
+
return e.__zudoDesignTokenPanelAdapter || (e.__zudoDesignTokenPanelAdapter = {}), e.__zudoDesignTokenPanelAdapter;
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
const
|
|
31
|
-
let o =
|
|
32
|
-
return o || (o = { bound: !1, modulePromise: null },
|
|
29
|
+
function v(e, t) {
|
|
30
|
+
const n = V(e);
|
|
31
|
+
let o = n[t];
|
|
32
|
+
return o || (o = { bound: !1, modulePromise: null }, n[t] = o), o;
|
|
33
33
|
}
|
|
34
|
-
function
|
|
34
|
+
function D(e) {
|
|
35
35
|
try {
|
|
36
|
-
return window.localStorage.getItem(
|
|
36
|
+
return window.localStorage.getItem(e) === "1";
|
|
37
37
|
} catch {
|
|
38
38
|
return !1;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
function
|
|
41
|
+
function K(e, t, n) {
|
|
42
42
|
try {
|
|
43
43
|
const o = window.localStorage;
|
|
44
|
-
return o.getItem(
|
|
44
|
+
return o.getItem(n) !== null || o.getItem(t) !== null || o.getItem(e) !== null;
|
|
45
45
|
} catch {
|
|
46
46
|
return !1;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
async function
|
|
50
|
-
return
|
|
49
|
+
async function i(e) {
|
|
50
|
+
return e.modulePromise === null && (e.modulePromise = import("@takazudo/zdtp").then((t) => {
|
|
51
51
|
try {
|
|
52
|
-
const
|
|
53
|
-
|
|
52
|
+
const n = u(), o = t.__panelConfigForTest();
|
|
53
|
+
n !== o && console.warn(
|
|
54
54
|
"[design-token-panel] Singleton-sharing check failed: the host adapter and the panel module observed different PanelConfig singletons. This indicates the package's `config/panel-config` module is no longer code-split into a single shared chunk. The panel may behave correctly today, but storage keys / namespaces / branding could diverge between the two surfaces in future bundles."
|
|
55
55
|
);
|
|
56
|
-
} catch (
|
|
56
|
+
} catch (n) {
|
|
57
57
|
console.warn(
|
|
58
|
-
"[design-token-panel] Singleton-sharing check could not run (likely an older dist without the __panelConfigForTest accessor): " +
|
|
58
|
+
"[design-token-panel] Singleton-sharing check could not run (likely an older dist without the __panelConfigForTest accessor): " + n.message
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
|
-
return
|
|
62
|
-
})),
|
|
61
|
+
return t;
|
|
62
|
+
})), e.modulePromise;
|
|
63
63
|
}
|
|
64
|
-
function
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
},
|
|
69
|
-
await
|
|
70
|
-
},
|
|
71
|
-
await
|
|
72
|
-
let
|
|
64
|
+
function M(e, t, n, o, a) {
|
|
65
|
+
const l = e[t] ?? {};
|
|
66
|
+
l.showDesignPanel = async () => {
|
|
67
|
+
d(a, !0), await i(n), o.open();
|
|
68
|
+
}, l.hideDesignPanel = async () => {
|
|
69
|
+
await i(n), o.close();
|
|
70
|
+
}, l.toggleDesignPanel = async () => {
|
|
71
|
+
await i(n), o.toggle();
|
|
72
|
+
let s = !1;
|
|
73
73
|
try {
|
|
74
|
-
|
|
74
|
+
s = window.localStorage.getItem(c(a)) === "1";
|
|
75
75
|
} catch {
|
|
76
76
|
}
|
|
77
|
-
|
|
78
|
-
},
|
|
79
|
-
(await
|
|
80
|
-
},
|
|
81
|
-
if (
|
|
82
|
-
(await
|
|
77
|
+
s && d(a, !0);
|
|
78
|
+
}, l.enableAutoload = async () => {
|
|
79
|
+
(await i(n)).enableAutoload(a);
|
|
80
|
+
}, l.disableAutoload = async () => {
|
|
81
|
+
if (n.modulePromise !== null) {
|
|
82
|
+
(await i(n)).disableAutoload(a);
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
C(a), S(!1, a);
|
|
86
86
|
try {
|
|
87
|
-
window.localStorage.setItem(g(
|
|
87
|
+
window.localStorage.setItem(g(a), "0");
|
|
88
88
|
} catch {
|
|
89
89
|
}
|
|
90
90
|
try {
|
|
91
|
-
window.localStorage.removeItem(
|
|
91
|
+
window.localStorage.removeItem(c(a));
|
|
92
92
|
} catch {
|
|
93
93
|
}
|
|
94
|
-
},
|
|
94
|
+
}, e[t] = l;
|
|
95
|
+
}
|
|
96
|
+
function O(e, t) {
|
|
97
|
+
A({
|
|
98
|
+
show: async () => {
|
|
99
|
+
await i(e), t.open();
|
|
100
|
+
},
|
|
101
|
+
hide: async () => {
|
|
102
|
+
await i(e), t.close();
|
|
103
|
+
},
|
|
104
|
+
toggle: async () => {
|
|
105
|
+
await i(e), t.toggle();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
95
108
|
}
|
|
96
109
|
(function() {
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
(
|
|
110
|
+
const t = T(), n = t.legacyIdRenameMap ? t : { ...t, legacyIdRenameMap: { ...k } }, o = h(n), a = u(), l = window, s = v(l, a.storagePrefix);
|
|
111
|
+
if (M(l, a.consoleNamespace, s, o, a), O(s, o), s.bound) return;
|
|
112
|
+
s.bound = !0;
|
|
113
|
+
const p = g(a), f = y(a), m = P(a), w = b(a);
|
|
114
|
+
(D(p) || K(f, m, w) || I(a) || E(a)) && i(s);
|
|
102
115
|
})();
|
package/dist/astro/index.js
CHANGED
package/dist/bin/server.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { realpathSync as E } from "node:fs";
|
|
3
3
|
import { createServer as H } from "node:http";
|
|
4
4
|
import { resolve as p } from "node:path";
|
|
5
|
-
import { l as $, c as x } from "../load-routing-
|
|
5
|
+
import { l as $, c as x } from "../load-routing-D4H2VOl5.js";
|
|
6
6
|
function g(o, t) {
|
|
7
7
|
return typeof o != "string" || o.length === 0 || t.length === 0 ? !1 : t.includes(o);
|
|
8
8
|
}
|
|
@@ -490,6 +490,38 @@ export declare function openStateChangedEventName(cfg: PanelConfig): string;
|
|
|
490
490
|
export declare function modalClass(cfg: PanelConfig, suffix: string): string;
|
|
491
491
|
/** Default download filename for export. */
|
|
492
492
|
export declare function exportFilename(cfg: PanelConfig): string;
|
|
493
|
+
/** Shape of the fixed-name global alias installed at `window.zdtp`. */
|
|
494
|
+
export interface ZdtpGlobalApi {
|
|
495
|
+
show: () => void | Promise<void>;
|
|
496
|
+
hide: () => void | Promise<void>;
|
|
497
|
+
toggle: () => void | Promise<void>;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Install `window.zdtp = { show, hide, toggle }`, the fixed-name console
|
|
501
|
+
* sugar for the common single-panel case (issue #523).
|
|
502
|
+
*
|
|
503
|
+
* Guard rules:
|
|
504
|
+
* - A pre-existing `window.zdtp` WITHOUT this package's marker is assumed to
|
|
505
|
+
* be host-defined — never overwritten. Logs a `console.warn` so the host
|
|
506
|
+
* can see why `zdtp.show()` did not appear.
|
|
507
|
+
* - A pre-existing `window.zdtp` WITH the marker means this package already
|
|
508
|
+
* installed the alias (from the other call site, or an earlier run of this
|
|
509
|
+
* same one). First install wins — the call is a silent no-op. In the Astro
|
|
510
|
+
* flow this manifests as "the adapter wins": its bootstrap script always
|
|
511
|
+
* runs (and installs the alias) before the panel module's lazy dynamic
|
|
512
|
+
* import can resolve and reach the package-root install site.
|
|
513
|
+
*
|
|
514
|
+
* `show` / `hide` / `toggle` are caller-supplied closures, so which instance
|
|
515
|
+
* they target is up to the caller — the package-root install site (below,
|
|
516
|
+
* `index.tsx`) wraps `showDesignTokenPanel()` etc., which re-resolve
|
|
517
|
+
* `getPanelConfig()` (the CURRENT default instance) on every call; the Astro
|
|
518
|
+
* host-adapter install site instead binds to the specific `PanelInstanceHandle`
|
|
519
|
+
* captured at its own install time, which does NOT track a later change of
|
|
520
|
+
* default (see PORTABLE-CONTRACT.md §6.5 for the full nuance). Either way,
|
|
521
|
+
* for a multi-instance page use `configurePanel(cfg).open()` etc. on the
|
|
522
|
+
* specific instance's own handle instead of relying on this alias.
|
|
523
|
+
*/
|
|
524
|
+
export declare function installZdtpGlobalAlias(api: ZdtpGlobalApi): void;
|
|
493
525
|
/**
|
|
494
526
|
* Runtime validation at the host-adapter trust boundary. The Astro inline
|
|
495
527
|
* `<script type="application/json">` payload is untrusted-by-the-types:
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ActionsMenuPopover — narrow-panel replacement for the header action links
|
|
3
|
+
* (Export / Load from JSON… / Apply / Reset), collapsed behind the kebab
|
|
4
|
+
* trigger below the panel's <480px container-query breakpoint (#518).
|
|
5
|
+
*
|
|
6
|
+
* A PLAIN popover of ordinary action RoleButtons, NOT an ARIA menu:
|
|
7
|
+
* role="menu"/menuitem demands arrow-key navigation and focus management,
|
|
8
|
+
* and RoleButton hardcodes role="button" — so this follows the existing
|
|
9
|
+
* gear-settings popover's dialog + outside-click/Escape wiring instead
|
|
10
|
+
* (usePopoverClose, shared with highlight/highlight-settings-popover.tsx).
|
|
11
|
+
*/
|
|
12
|
+
import type { JSX } from 'preact';
|
|
13
|
+
export interface ActionsMenuAction {
|
|
14
|
+
label: string;
|
|
15
|
+
onSelect: () => void;
|
|
16
|
+
}
|
|
17
|
+
interface ActionsMenuPopoverProps {
|
|
18
|
+
/** The kebab trigger element — excluded from the outside-click close so its
|
|
19
|
+
* own click-to-toggle isn't raced by the popover's pointerdown listener
|
|
20
|
+
* (mirrors the gear button / HighlightSettingsPopover pairing). */
|
|
21
|
+
anchorRef: React.RefObject<HTMLElement | null>;
|
|
22
|
+
actions: readonly ActionsMenuAction[];
|
|
23
|
+
onClose: () => void;
|
|
24
|
+
}
|
|
25
|
+
export declare function ActionsMenuPopover({ anchorRef, actions, onClose, }: ActionsMenuPopoverProps): JSX.Element;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelpIcon — small round "?" badge that explains a nearby control via the
|
|
3
|
+
* shared `.tokenpanel-tooltip--help` variant (issue #520).
|
|
4
|
+
*
|
|
5
|
+
* Chrome-button policy (CLAUDE.md): implemented as
|
|
6
|
+
* `<div role="button" tabIndex={0}>` with explicit Enter/Space handling —
|
|
7
|
+
* never a native `<button>`.
|
|
8
|
+
*
|
|
9
|
+
* Behavior:
|
|
10
|
+
* - Hover / focus shows the help tooltip transiently, same as any other
|
|
11
|
+
* `useTooltip` trigger.
|
|
12
|
+
* - Click (or Enter/Space) PINS the tooltip open — touch devices have no
|
|
13
|
+
* hover, so a tap must be able to reveal and hold the tip. A second
|
|
14
|
+
* activation, or pressing Escape anywhere on the page, unpins it.
|
|
15
|
+
*
|
|
16
|
+
* Callers place this as a SIBLING of the control it explains (e.g. after a
|
|
17
|
+
* `<select>`, or after a `<label>` wrapping a checkbox) — never nested
|
|
18
|
+
* inside a `<label>`, where a click would also toggle the label's own
|
|
19
|
+
* control.
|
|
20
|
+
*
|
|
21
|
+
* Known trade-off: `tooltip.tsx` renders a single shared tooltip DOM node,
|
|
22
|
+
* so pinning icon A then hovering/pinning icon B silently replaces A's
|
|
23
|
+
* visible content with B's — A's `pinned`/`is-pinned` state persists until
|
|
24
|
+
* A is next clicked or Escape is pressed, even though its tooltip is no
|
|
25
|
+
* longer the one on screen. Acceptable for this panel's single-tooltip
|
|
26
|
+
* architecture; not worth a cross-instance pin registry for a "?" hint.
|
|
27
|
+
* The same applies to a panel/window resize: `tooltip.tsx` hides the shared
|
|
28
|
+
* tooltip on resize (its ResizeObserver + window-resize handlers), but this
|
|
29
|
+
* component's local `pinned` state only clears on click/Escape — so after a
|
|
30
|
+
* resize the icon may briefly keep `is-pinned`/`aria-pressed` with no tooltip
|
|
31
|
+
* visible until the next activation. Same accepted single-tooltip trade-off.
|
|
32
|
+
*/
|
|
33
|
+
import type { JSX } from 'preact';
|
|
34
|
+
export declare const LITERAL_HELP_TEXT = "Literal sets a fixed color just for this token \u2014 it won't update if you edit a palette/ramp swatch later. Pick a ramp option to keep it linked live.";
|
|
35
|
+
export declare const PER_MODE_HELP_TEXT = "Per-mode gives this token two colors \u2014 one for light mode, one for dark. The browser picks the right one automatically via CSS light-dark().";
|
|
36
|
+
export interface HelpIconProps {
|
|
37
|
+
/** The help text shown in the tooltip (wrapped, multi-line). */
|
|
38
|
+
text: string;
|
|
39
|
+
/** Accessible name for the icon itself (e.g. "Literal help", "Surface per-mode help"). */
|
|
40
|
+
ariaLabel: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function HelpIcon({ text, ariaLabel }: HelpIconProps): JSX.Element;
|
|
43
|
+
export default HelpIcon;
|
|
@@ -16,6 +16,13 @@
|
|
|
16
16
|
* <div {...tooltipProps}>...</div>
|
|
17
17
|
*/
|
|
18
18
|
import type { ComponentChildren, JSX } from 'preact';
|
|
19
|
+
/**
|
|
20
|
+
* Opt-in tooltip presentation variant. `'help'` applies the wrapped,
|
|
21
|
+
* bounded-width `.tokenpanel-tooltip--help` class (see panel.css) instead of
|
|
22
|
+
* the default single-line `nowrap` tooltip — used by `controls/help-icon.tsx`
|
|
23
|
+
* for the multi-sentence Literal / Per-mode explainer tips.
|
|
24
|
+
*/
|
|
25
|
+
export type TooltipVariant = 'help';
|
|
19
26
|
interface TooltipProviderProps {
|
|
20
27
|
children: ComponentChildren;
|
|
21
28
|
}
|
|
@@ -27,17 +34,28 @@ interface TooltipProviderProps {
|
|
|
27
34
|
* tooltip globally.
|
|
28
35
|
*/
|
|
29
36
|
export declare function TooltipProvider({ children }: TooltipProviderProps): JSX.Element;
|
|
37
|
+
export interface UseTooltipOptions {
|
|
38
|
+
/** Opt into a presentation variant — see `TooltipVariant` above. Omit for
|
|
39
|
+
* the default single-line `nowrap` tooltip. */
|
|
40
|
+
variant?: TooltipVariant;
|
|
41
|
+
}
|
|
30
42
|
/**
|
|
31
43
|
* Returns event handler props to spread onto the tooltip trigger element.
|
|
32
44
|
*
|
|
33
45
|
* @param text - The full text to show in the tooltip.
|
|
46
|
+
* @param opts - Optional presentation variant (see `UseTooltipOptions`).
|
|
34
47
|
* @returns An object of `onMouseEnter`, `onMouseLeave`, `onFocusIn`, `onFocusOut`
|
|
35
|
-
* handlers to spread onto the trigger element
|
|
48
|
+
* handlers to spread onto the trigger element, plus imperative
|
|
49
|
+
* `show`/`hide` escape hatches for callers that need to
|
|
50
|
+
* show/keep-open the tooltip outside of a raw hover/focus event
|
|
51
|
+
* (e.g. `controls/help-icon.tsx`'s click-to-pin behavior).
|
|
36
52
|
*/
|
|
37
|
-
export declare function useTooltip(text: string): {
|
|
53
|
+
export declare function useTooltip(text: string, opts?: UseTooltipOptions): {
|
|
38
54
|
onMouseEnter: JSX.MouseEventHandler<HTMLElement>;
|
|
39
55
|
onMouseLeave: JSX.MouseEventHandler<HTMLElement>;
|
|
40
56
|
onFocusIn: JSX.FocusEventHandler<HTMLElement>;
|
|
41
57
|
onFocusOut: JSX.FocusEventHandler<HTMLElement>;
|
|
58
|
+
show: (el: HTMLElement) => void;
|
|
59
|
+
hide: (el: HTMLElement) => void;
|
|
42
60
|
};
|
|
43
61
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export type { ColorClusterConfig } from './state/tweak-state';
|
|
|
56
56
|
export { ZDTP_LEGACY_TYPOGRAPHY_RENAME_MAP } from './state/tweak-state';
|
|
57
57
|
export type { ColorScheme, ColorRef } from './config/color-schemes';
|
|
58
58
|
export type { TokenManifest, TokenDef } from './tokens/manifest';
|
|
59
|
-
export type { TierValueKind, PillSpec, TierItem, TierConfig, TabConfig, ColorClusterExtras, } from './tokens/tier-model';
|
|
59
|
+
export type { TierValueKind, PillSpec, TierItem, TierConfig, TabConfig, ColorClusterExtras, NotesExtras, } from './tokens/tier-model';
|
|
60
60
|
export { isLengthKind, isNumberKind, isSelectKind, isTextKind, isColorKind, isCursorKind, isContentKind, isMaskImageKind, } from './tokens/tier-model';
|
|
61
61
|
export type { TweakState } from './state/tweak-state';
|
|
62
62
|
export { emptyOverrides } from './state/tweak-state';
|