@plitzi/sdk-dev-tools 0.38.1 → 0.38.3
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 +141 -0
- package/dist/components/DevToolsPanel/tabs/ElementsViewer/components/ElementDetails/ElementDetails.mjs +8 -8
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaReplayButton.d.ts +6 -0
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaReplayButton.mjs +21 -0
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaToolbar.d.ts +4 -1
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaToolbar.mjs +29 -15
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaViewer.d.ts +4 -3
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaViewer.mjs +21 -12
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaXray.d.ts +3 -0
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaXray.mjs +16 -0
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaXrayRow.d.ts +7 -0
- package/dist/components/DevToolsPanel/tabs/QaViewer/QaXrayRow.mjs +40 -0
- package/dist/qa/QaContext.d.ts +4 -0
- package/dist/qa/QaContext.mjs +44 -38
- package/dist/qa/QaLayer.mjs +99 -47
- package/dist/qa/overlays/QaXrayTags.d.ts +10 -0
- package/dist/qa/overlays/QaXrayTags.mjs +58 -0
- package/dist/qa/qaCss.mjs +20 -18
- package/dist/qa/qaSettings.d.ts +8 -1
- package/dist/qa/qaSettings.mjs +4 -1
- package/dist/qa/xray.d.ts +20 -0
- package/dist/qa/xray.mjs +54 -0
- package/package.json +25 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,146 @@
|
|
|
1
1
|
# @plitzi/sdk-dev-tools
|
|
2
2
|
|
|
3
|
+
## 0.38.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e047e1d: ## `plitzi upgrade`: a project brought up to its CLI
|
|
8
|
+
|
|
9
|
+
A project written by an older CLI had no way up but `plitzi create` in a scratch folder and a file-by-file comparison:
|
|
10
|
+
`skills update` brought the skills and nothing else, so the `check` and `shot` scripts they teach did not exist.
|
|
11
|
+
`plitzi upgrade` (also `update`) shows what this CLI writes today for what is the CLI's in the project, and `--write`
|
|
12
|
+
makes it. One part or several: `plitzi upgrade skills`, `plitzi upgrade files packages`.
|
|
13
|
+
|
|
14
|
+
- **`files`:** the CLI's machinery — `author.ts`, `main.ts`, the Playwright, TypeScript and lint configs, AGENTS.md. One
|
|
15
|
+
nobody changed since the CLI wrote it is replaced, a missing one added; one the project made its own is shown as a
|
|
16
|
+
diff and left, until `--take <file>` (or `all`). `plitzi create` now records what it wrote, by digest, in
|
|
17
|
+
`.plitzi/scaffold.json`; a project made before that sees every file that differs as its own.
|
|
18
|
+
- **`packages`:** `package.json` merged, never replaced — the scripts and dependencies it lacks added, `@plitzi/*`
|
|
19
|
+
raised to this version, then the install (`--no-install` to leave it). A script of the project's own stays.
|
|
20
|
+
- **`skills`:** `.claude/skills/plitzi-*` from the packages installed, each replaced whole, and the ones a newer CLI
|
|
21
|
+
writes added. `plitzi skills update` is `plitzi upgrade skills --write`.
|
|
22
|
+
- **`renames`:** a name a version renamed with no alias, at its file and line — `canTemplate` → `canSnippet`,
|
|
23
|
+
`authorTemplate` → `authorSnippet` and its kin (renamed only where imported from `@plitzi/sdk-authoring`) — renamed
|
|
24
|
+
with `--write`.
|
|
25
|
+
|
|
26
|
+
`npm run author` says when the skills or the CLI's files are older than the SDK installed, and `plitzi --version`
|
|
27
|
+
prints the CLI's.
|
|
28
|
+
|
|
29
|
+
## Page checks that can be the definition of done
|
|
30
|
+
|
|
31
|
+
`inspectPage`, `plitzi check` and the scaffold's visual test failed pages that were whole, so an agent learnt to ignore
|
|
32
|
+
them:
|
|
33
|
+
|
|
34
|
+
- **A breakpoint hiding an element on purpose** — the desktop navigation on a phone, a bottom bar only a phone shows —
|
|
35
|
+
is no longer "not visible": an element whose `display` or `visibility` a breakpoint rule sets is checked at the width
|
|
36
|
+
it shows at.
|
|
37
|
+
- **A lazy image out of sight** waits whichever side it is out of: below the fold, as before, or beside the screen in a
|
|
38
|
+
carousel's track — cut off by any ancestor that clips, as the browser decides when to fetch it.
|
|
39
|
+
- **A plugin that draws nothing** says so: `drawsNothing: true` in its declaration (a clock that fires a flow), and its
|
|
40
|
+
handle is `boxless`, so no check waits for it on screen.
|
|
41
|
+
|
|
42
|
+
`plitzi check --json` and `PageReport` carry `issues` beside `problems`: each with its `code` (`element-hidden`,
|
|
43
|
+
`image-not-loaded`, `sideways-scroll`…), the `elementId` it is about and, in `check`, the `width`.
|
|
44
|
+
|
|
45
|
+
## Authoring
|
|
46
|
+
- **A link's `content` names it.** `control-without-name` read only a link's `label`, so applying the
|
|
47
|
+
`content-attribute` suggestion as written turned every link into a warning.
|
|
48
|
+
- **`plitzi fix` writes `content-attribute`** where it has one reading: a button's or link's children that are only
|
|
49
|
+
`text(…)` and `fontAwesome({ icon })` become its own `content` and `icon` — the words kept as written, an import left
|
|
50
|
+
unused taken out. A child with an id, options or a class of the space's own stays, and is said. `npm run author`'s
|
|
51
|
+
`[fix]` line counts these too.
|
|
52
|
+
- **The recipes, the skill's examples and the catalog template** hold to the suggestions as well as the warnings, and
|
|
53
|
+
their tests say so: six recipes and the template wrote a link's or a button's words as a child.
|
|
54
|
+
|
|
55
|
+
## Declared motion — in code, in the builder and over MCP
|
|
56
|
+
|
|
57
|
+
An element says how it arrives and whether it keeps moving with `motion`, and the SDK's stylesheet plays it — no
|
|
58
|
+
keyframes to write: `{ enter: 'fade-up', on: 'view' }` arrives as it scrolls into view, `{ enter: 'scale', stagger:
|
|
59
|
+
60 }` brings its children one by one (a grid, a list's rows), `{ loop: 'float' }` keeps it moving. Enters: `fade`,
|
|
60
|
+
`fade-up`, `fade-down`, `slide-left`, `slide-right`, `scale`; loops: `float`, `pulse`, `spin`, `sway`; `duration`,
|
|
61
|
+
`delay`, `stagger` in ms. Opacity and the transforms only — an arrival on `translate`/`scale`, so it composes with an
|
|
62
|
+
element's own `transform` — a loop held until the page is live (`data-hydrated`), and none of it for a visitor who asked
|
|
63
|
+
for less motion. `view` follows the scroll where the browser has scroll timelines and plays on load where not.
|
|
64
|
+
|
|
65
|
+
- **Authoring:** `motion` on any factory; refused where it cannot play (`motion-invalid`, `motion-no-tag`), and carried
|
|
66
|
+
by `specFromSpace` and `compareSpaces`.
|
|
67
|
+
- **Builder:** a **Motion** tab in an element's tools: the presets as chips, a stage that plays the one pointed at (a
|
|
68
|
+
loop shown stronger than the page plays it, and saying so), when and how long, children one by one, and the choices
|
|
69
|
+
read back as a sentence — laid out side by side once the sidebar is wide enough. The canvas holds motion still while
|
|
70
|
+
editing; **▶** in the header (or **Play on the canvas** in the tab) plays it from the start, restarting what already
|
|
71
|
+
played, and an arrival tied to the scroll plays by the clock there, where it is usually in view already.
|
|
72
|
+
- **MCP:** `motion` on `upsertElement` and `patchElement`, checked the same way; the guide names the presets.
|
|
73
|
+
- **Schema:** `definition.motion` (`ElementMotion`, `@plitzi/sdk-shared/schema/motion` — the presets, `motionProblems`,
|
|
74
|
+
`motionAttributes`, `isMotionAnimation`, and each preset's frames, which the stylesheet is tested against), in both
|
|
75
|
+
init queries. **The platform's GraphQL schema has to declare `SpaceElementMotion`
|
|
76
|
+
before this version's builder or SDK queries it.**
|
|
77
|
+
|
|
78
|
+
## Dev tools QA: x-ray and motion
|
|
79
|
+
|
|
80
|
+
The **QA** tab gains an **X-ray**: every element the document wires something to — bound to data, shown on a condition,
|
|
81
|
+
running a flow, moving, behind a flag — outlined in its colour and named on the page, read from the space's document by
|
|
82
|
+
the element's name; its legend counts each kind on the page and picks one to show alone. Beside **Pause**, **Slow**
|
|
83
|
+
plays every animation at a quarter of its speed and **Replay** plays the declared motion again from the start, without
|
|
84
|
+
reloading the page.
|
|
85
|
+
|
|
86
|
+
## Plugins that draw
|
|
87
|
+
|
|
88
|
+
`useCanvas2d`, `useWebGL`, `useWebGL2` and `useAnimationFrame` (`@plitzi/plitzi-sdk`): a canvas sized to the device (at
|
|
89
|
+
most 2×), followed as it resizes, animating only while somebody can see it move — a live page, no reduced motion, the
|
|
90
|
+
tab in front, the canvas on screen — and one still frame otherwise (the builder included). `createShaderProgram`
|
|
91
|
+
compiles and links, and a shader that fails throws a `ShaderError` with the driver's log, printed as
|
|
92
|
+
`[plugin <type> "<id>"] fragment shader failed: …` instead of an empty canvas; `error` and `ready` say where it is.
|
|
93
|
+
`useReducedMotion` for the rest.
|
|
94
|
+
|
|
95
|
+
## A space re-authored without a restart
|
|
96
|
+
|
|
97
|
+
A project's `npm run start:dev` restarts for its server code and its plugins only: a save to the space is re-authored
|
|
98
|
+
in a process of its own and every open page loads again (`server.reloadPages()` over an SSE endpoint, on with
|
|
99
|
+
`createServer({ devReload: true })` — never by `devMode` alone, since every open page holds a connection for it); an
|
|
100
|
+
edit authoring refuses is printed and the page keeps the last space that authored. A shutdown also ends WebSockets at
|
|
101
|
+
once (`1001`, going away) rather than waiting out the grace — the ten seconds a restart used to wait on an open page.
|
|
102
|
+
|
|
103
|
+
## Checks and authoring, from the stripe.com experiment
|
|
104
|
+
- **A component's instance** is found by its own name: its root carries `data-plitzi-instance`, and the instance's
|
|
105
|
+
handle selects it — `inspectPage` no longer reports every named instance as missing.
|
|
106
|
+
- **Hidden at this width on purpose** — the burger on a desktop, the desktop menu on a phone — is listed apart
|
|
107
|
+
(`hiddenAtWidth`, and a dim line under `plitzi check`'s ✓) rather than as a problem.
|
|
108
|
+
- **An element whose every child is conditional** — four flyouts in one list, each opening on the state that names
|
|
109
|
+
it — is conditional too: at rest it shows nothing, and that is it working.
|
|
110
|
+
- **A carousel that scrolls by itself** (`overflow-x: auto`) is not the page scrolling sideways; the page's own pane
|
|
111
|
+
still is.
|
|
112
|
+
- **Templates:** `{{ state.faq ?? -1 }}` — a sign on the right of `??` — reads.
|
|
113
|
+
- **A plugin attribute named as an element field** (`variant`, `class`, `id`…) is warned about
|
|
114
|
+
(`plugin-attribute-reserved`): a factory never hands it to the plugin. A `variant` no class or type style declares is
|
|
115
|
+
`unknown-variant`.
|
|
116
|
+
- **Lists:** a list with `items` renders as the `<ul>` (or `<ol>`) its `subType` says — it was a `<div>` — with no
|
|
117
|
+
markers and the same spacing, so a page looks as it did; the builder offers the list type for it too. Its rows are
|
|
118
|
+
`<li>`s: `list-row-not-li` warns of one that is not — a plain container is made one by `fixSpace`, a link or a button
|
|
119
|
+
is wrapped — and the recipes, the catalog template and the docs write rows as `listItem`.
|
|
120
|
+
- **CSS:** `mask-size`, `mask-position`, `mask-repeat`, `mask-composite`, `-webkit-mask-image`,
|
|
121
|
+
`-webkit-background-clip`, `box-decoration-break` and `-webkit-box-decoration-break`.
|
|
122
|
+
- **`plitzi shot`:** `--clip <element>`, `--scroll-to <element>` and `--viewport`; `--frames` takes the same framing.
|
|
123
|
+
- **SVG from files:** `svgFile` and `svgFiles` (`@plitzi/sdk-authoring/node`) read a logo or a folder of them,
|
|
124
|
+
compacted (`compactSvg`, also on the main entry), instead of strings in the space's source.
|
|
125
|
+
- The plugin scaffolds say that an inline `style` on `RootElement` outranks the element's classes.
|
|
126
|
+
|
|
127
|
+
- Updated dependencies [e047e1d]
|
|
128
|
+
- @plitzi/sdk-navigation@0.38.3
|
|
129
|
+
- @plitzi/sdk-schema@0.38.3
|
|
130
|
+
- @plitzi/sdk-shared@0.38.3
|
|
131
|
+
- @plitzi/sdk-style@0.38.3
|
|
132
|
+
|
|
133
|
+
## 0.38.2
|
|
134
|
+
|
|
135
|
+
### Patch Changes
|
|
136
|
+
|
|
137
|
+
- v0.38.2
|
|
138
|
+
- Updated dependencies
|
|
139
|
+
- @plitzi/sdk-navigation@0.38.2
|
|
140
|
+
- @plitzi/sdk-schema@0.38.2
|
|
141
|
+
- @plitzi/sdk-shared@0.38.2
|
|
142
|
+
- @plitzi/sdk-style@0.38.2
|
|
143
|
+
|
|
3
144
|
## 0.38.1
|
|
4
145
|
|
|
5
146
|
### Patch Changes
|
|
@@ -4,15 +4,15 @@ import n from "../DetailsRuntime/index.mjs";
|
|
|
4
4
|
import { useMemo as r } from "react";
|
|
5
5
|
import { useCommonStore as i } from "@plitzi/sdk-shared/store";
|
|
6
6
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
7
|
-
import s from "@plitzi/
|
|
8
|
-
import
|
|
7
|
+
import { treeOf as s } from "@plitzi/sdk-schema/helpers/components";
|
|
8
|
+
import c from "@plitzi/plitzi-ui/ContainerTabs";
|
|
9
9
|
//#region src/components/DevToolsPanel/tabs/ElementsViewer/components/ElementDetails/ElementDetails.tsx
|
|
10
10
|
var l = [
|
|
11
11
|
{ label: "Runtime" },
|
|
12
12
|
{ label: "Definition" },
|
|
13
13
|
{ label: "Attributes" }
|
|
14
14
|
], u = ({ id: u, onSelectElement: d }) => {
|
|
15
|
-
let [[f, p]] = i(["schema.flat", "schema.components"]), m = r(() =>
|
|
15
|
+
let [[f, p]] = i(["schema.flat", "schema.components"]), m = r(() => s({
|
|
16
16
|
flat: f,
|
|
17
17
|
components: p
|
|
18
18
|
}, u)?.flat[u], [
|
|
@@ -20,22 +20,22 @@ var l = [
|
|
|
20
20
|
p,
|
|
21
21
|
u
|
|
22
22
|
]);
|
|
23
|
-
return /* @__PURE__ */ o(
|
|
23
|
+
return /* @__PURE__ */ o(c, {
|
|
24
24
|
className: "w-full grow gap-4 overflow-hidden p-4",
|
|
25
25
|
children: [
|
|
26
|
-
/* @__PURE__ */ a(
|
|
27
|
-
/* @__PURE__ */ a(
|
|
26
|
+
/* @__PURE__ */ a(c.Tabs, { items: l }),
|
|
27
|
+
/* @__PURE__ */ a(c.TabContent, {
|
|
28
28
|
className: "flex-col overflow-y-auto",
|
|
29
29
|
children: /* @__PURE__ */ a(n, { id: u })
|
|
30
30
|
}),
|
|
31
|
-
/* @__PURE__ */ a(
|
|
31
|
+
/* @__PURE__ */ a(c.TabContent, {
|
|
32
32
|
className: "flex-col overflow-y-auto",
|
|
33
33
|
children: /* @__PURE__ */ a(t, {
|
|
34
34
|
definition: m?.definition,
|
|
35
35
|
onSelectElement: d
|
|
36
36
|
})
|
|
37
37
|
}),
|
|
38
|
-
/* @__PURE__ */ a(
|
|
38
|
+
/* @__PURE__ */ a(c.TabContent, {
|
|
39
39
|
className: "overflow-y-auto",
|
|
40
40
|
children: /* @__PURE__ */ a(e, { attributes: m?.attributes })
|
|
41
41
|
})
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plays the page's declared motion again from the start — its arrivals, its loops — without loading the page again,
|
|
3
|
+
* which would also lose whatever state the tester had brought it to.
|
|
4
|
+
*/
|
|
5
|
+
declare const QaReplayButton: () => import('react').JSX.Element;
|
|
6
|
+
export default QaReplayButton;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import e from "../../../../qa/QaContext.mjs";
|
|
2
|
+
import { use as t, useCallback as n } from "react";
|
|
3
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
4
|
+
import { isMotionAnimation as a } from "@plitzi/sdk-shared/schema/motion";
|
|
5
|
+
//#region src/components/DevToolsPanel/tabs/QaViewer/QaReplayButton.tsx
|
|
6
|
+
var o = () => {
|
|
7
|
+
let { pageRef: o } = t(e), s = n(() => {
|
|
8
|
+
o.current?.getAnimations({ subtree: !0 }).filter(a).forEach((e) => {
|
|
9
|
+
e.cancel(), e.play();
|
|
10
|
+
});
|
|
11
|
+
}, [o]);
|
|
12
|
+
return /* @__PURE__ */ i("button", {
|
|
13
|
+
type: "button",
|
|
14
|
+
title: "Play the page's arrivals and loops again from the start",
|
|
15
|
+
className: "flex h-6 shrink-0 cursor-pointer items-center gap-1.5 rounded-md border border-zinc-200 px-2 font-medium whitespace-nowrap text-zinc-600 transition-colors hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800",
|
|
16
|
+
onClick: s,
|
|
17
|
+
children: [/* @__PURE__ */ r("i", { className: "fa-solid fa-rotate-left text-[10px]" }), "Replay"]
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { o as default };
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Every tool that draws over the page, in one row that wraps: the inspector first, then layout and what the document
|
|
3
|
+
* wires, motion, and colour.
|
|
4
|
+
*/
|
|
2
5
|
declare const QaToolbar: () => import('react').JSX.Element;
|
|
3
6
|
export default QaToolbar;
|
|
@@ -1,58 +1,72 @@
|
|
|
1
1
|
import e from "./QaDivider.mjs";
|
|
2
|
-
import t from "./
|
|
3
|
-
import n from "./
|
|
4
|
-
import
|
|
2
|
+
import t from "./QaReplayButton.mjs";
|
|
3
|
+
import n from "./QaToolChip.mjs";
|
|
4
|
+
import r from "./QaVisionSelect.mjs";
|
|
5
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
6
|
//#region src/components/DevToolsPanel/tabs/QaViewer/QaToolbar.tsx
|
|
6
|
-
var
|
|
7
|
+
var o = () => /* @__PURE__ */ a("div", {
|
|
7
8
|
className: "flex shrink-0 flex-wrap items-center gap-1.5 border-b border-zinc-200 px-3 py-2 dark:border-zinc-700",
|
|
8
9
|
children: [
|
|
9
|
-
/* @__PURE__ */
|
|
10
|
+
/* @__PURE__ */ i(n, {
|
|
10
11
|
setting: "inspect",
|
|
11
12
|
label: "Inspect",
|
|
12
13
|
icon: "fa-solid fa-arrow-pointer",
|
|
13
14
|
title: "Point at an element for its box and style; click to keep it here; hold Alt over another to measure. Esc stops.",
|
|
14
15
|
primary: !0
|
|
15
16
|
}),
|
|
16
|
-
/* @__PURE__ */
|
|
17
|
-
/* @__PURE__ */
|
|
17
|
+
/* @__PURE__ */ i(e, {}),
|
|
18
|
+
/* @__PURE__ */ i(n, {
|
|
18
19
|
setting: "grid",
|
|
19
20
|
label: "Grid",
|
|
20
21
|
icon: "fa-solid fa-table-columns",
|
|
21
22
|
title: "The page's 12, 8 or 4 columns"
|
|
22
23
|
}),
|
|
23
|
-
/* @__PURE__ */
|
|
24
|
+
/* @__PURE__ */ i(n, {
|
|
24
25
|
setting: "outlines",
|
|
25
26
|
label: "Outlines",
|
|
26
27
|
icon: "fa-regular fa-square",
|
|
27
28
|
title: "Every element's box"
|
|
28
29
|
}),
|
|
29
|
-
/* @__PURE__ */
|
|
30
|
+
/* @__PURE__ */ i(n, {
|
|
31
|
+
setting: "xray",
|
|
32
|
+
label: "X-ray",
|
|
33
|
+
icon: "fa-solid fa-x-ray",
|
|
34
|
+
title: "What is bound to data, shown on a condition, runs a flow, moves or sits behind a flag — named on the page"
|
|
35
|
+
}),
|
|
36
|
+
/* @__PURE__ */ i(n, {
|
|
30
37
|
setting: "tabOrder",
|
|
31
38
|
label: "Tab order",
|
|
32
39
|
icon: "fa-solid fa-arrow-right-to-bracket",
|
|
33
40
|
title: "The order the Tab key walks the controls in"
|
|
34
41
|
}),
|
|
35
|
-
/* @__PURE__ */
|
|
42
|
+
/* @__PURE__ */ i(n, {
|
|
36
43
|
setting: "viewport",
|
|
37
44
|
label: "Viewport",
|
|
38
45
|
icon: "fa-solid fa-ruler-horizontal",
|
|
39
46
|
title: "The window's size and the breakpoint showing"
|
|
40
47
|
}),
|
|
41
|
-
/* @__PURE__ */
|
|
42
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ i(e, {}),
|
|
49
|
+
/* @__PURE__ */ i(n, {
|
|
43
50
|
setting: "paused",
|
|
44
51
|
label: "Pause",
|
|
45
52
|
icon: "fa-solid fa-pause",
|
|
46
53
|
title: "Hold every animation where it is"
|
|
47
54
|
}),
|
|
48
|
-
/* @__PURE__ */
|
|
55
|
+
/* @__PURE__ */ i(n, {
|
|
56
|
+
setting: "slowMotion",
|
|
57
|
+
label: "Slow",
|
|
58
|
+
icon: "fa-solid fa-gauge-simple",
|
|
59
|
+
title: "Every animation at a quarter of its speed"
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ i(t, {}),
|
|
62
|
+
/* @__PURE__ */ i(n, {
|
|
49
63
|
setting: "reducedMotion",
|
|
50
64
|
label: "Reduced motion",
|
|
51
65
|
icon: "fa-solid fa-person-walking",
|
|
52
66
|
title: "The page as a visitor who asked for less motion gets it"
|
|
53
67
|
}),
|
|
54
|
-
/* @__PURE__ */ r
|
|
68
|
+
/* @__PURE__ */ i(r, {})
|
|
55
69
|
]
|
|
56
70
|
});
|
|
57
71
|
//#endregion
|
|
58
|
-
export {
|
|
72
|
+
export { o as default };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tools for checking a build in the browser it will be used in — a pre-production deployment, say — rather than in the
|
|
3
|
-
* builder: an inspector for any element, what lines things up,
|
|
4
|
-
*
|
|
5
|
-
* All of it stays on while the panel is folded away, and
|
|
3
|
+
* builder: an inspector for any element, what lines things up, what the document wires to each element, motion and
|
|
4
|
+
* colour, and the checks a tester runs on every page. The bar on top; the x-ray's legend and the checks beside the
|
|
5
|
+
* inspector below, one over the other when the panel is narrow. All of it stays on while the panel is folded away, and
|
|
6
|
+
* in this browser only.
|
|
6
7
|
*/
|
|
7
8
|
declare const QaViewer: () => import('react').JSX.Element;
|
|
8
9
|
export default QaViewer;
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import e from "
|
|
2
|
-
import t from "./
|
|
3
|
-
import n from "./
|
|
4
|
-
import
|
|
1
|
+
import e from "../../../../qa/QaContext.mjs";
|
|
2
|
+
import t from "./QaChecks.mjs";
|
|
3
|
+
import n from "./QaInspectorPanel.mjs";
|
|
4
|
+
import r from "./QaToolbar.mjs";
|
|
5
|
+
import i from "./QaXray.mjs";
|
|
6
|
+
import { use as a } from "react";
|
|
7
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
5
8
|
//#region src/components/DevToolsPanel/tabs/QaViewer/QaViewer.tsx
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
className: "
|
|
10
|
-
children: [/* @__PURE__ */ r
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
var c = () => {
|
|
10
|
+
let { settings: c } = a(e);
|
|
11
|
+
return /* @__PURE__ */ s("div", {
|
|
12
|
+
className: "@container flex h-full min-h-0 w-full flex-col",
|
|
13
|
+
children: [/* @__PURE__ */ o(r, {}), /* @__PURE__ */ s("div", {
|
|
14
|
+
className: "grid min-h-0 grow grid-cols-1 content-start gap-3 overflow-y-auto p-3 @3xl:grid-cols-[minmax(0,0.85fr)_minmax(0,1.15fr)]",
|
|
15
|
+
children: [/* @__PURE__ */ s("div", {
|
|
16
|
+
className: "flex min-w-0 flex-col gap-3",
|
|
17
|
+
children: [c.xray && /* @__PURE__ */ o(i, {}), /* @__PURE__ */ o(t, {})]
|
|
18
|
+
}), /* @__PURE__ */ o(n, {})]
|
|
19
|
+
})]
|
|
20
|
+
});
|
|
21
|
+
};
|
|
13
22
|
//#endregion
|
|
14
|
-
export {
|
|
23
|
+
export { c as default };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { XRAY_MARKS as e } from "../../../../qa/xray.mjs";
|
|
2
|
+
import t from "./QaXrayRow.mjs";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/DevToolsPanel/tabs/QaViewer/QaXray.tsx
|
|
5
|
+
var i = () => /* @__PURE__ */ r("section", {
|
|
6
|
+
className: "flex min-w-0 flex-col gap-1.5",
|
|
7
|
+
children: [/* @__PURE__ */ r("div", {
|
|
8
|
+
className: "flex items-center gap-2 text-[10px] font-semibold tracking-wider text-zinc-400 uppercase dark:text-zinc-500",
|
|
9
|
+
children: [/* @__PURE__ */ n("i", { className: "fa-solid fa-x-ray" }), "X-ray"]
|
|
10
|
+
}), /* @__PURE__ */ n("div", {
|
|
11
|
+
className: "overflow-hidden rounded border border-zinc-200 dark:border-zinc-700",
|
|
12
|
+
children: e.map((e) => /* @__PURE__ */ n(t, { mark: e }, e))
|
|
13
|
+
})]
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { i as default };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { XrayMark } from '../../../../qa/xray';
|
|
2
|
+
export type QaXrayRowProps = {
|
|
3
|
+
mark: XrayMark;
|
|
4
|
+
};
|
|
5
|
+
/** One kind of wiring: how many elements of the page carry it — and, picked, the only one the x-ray shows. */
|
|
6
|
+
declare const QaXrayRow: ({ mark }: QaXrayRowProps) => import('react').JSX.Element;
|
|
7
|
+
export default QaXrayRow;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { XRAY as e } from "../../../../qa/xray.mjs";
|
|
2
|
+
import t from "../../../../qa/QaContext.mjs";
|
|
3
|
+
import n from "clsx";
|
|
4
|
+
import { use as r, useCallback as i } from "react";
|
|
5
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
6
|
+
//#region src/components/DevToolsPanel/tabs/QaViewer/QaXrayRow.tsx
|
|
7
|
+
var s = ({ mark: s }) => {
|
|
8
|
+
let { settings: c, setSetting: l, xrayCounts: u } = r(t), { label: d, description: f, colour: p } = e[s], m = c.xrayFilter === s, h = i(() => l("xrayFilter", m ? "all" : s), [
|
|
9
|
+
l,
|
|
10
|
+
m,
|
|
11
|
+
s
|
|
12
|
+
]);
|
|
13
|
+
return /* @__PURE__ */ o("button", {
|
|
14
|
+
type: "button",
|
|
15
|
+
"aria-pressed": m,
|
|
16
|
+
title: `${f}. Click to show only these; again for all.`,
|
|
17
|
+
className: n("flex w-full cursor-pointer items-center gap-2 border-b border-zinc-100 px-2.5 py-1.5 text-left last:border-b-0 dark:border-zinc-800", {
|
|
18
|
+
"bg-violet-500/10": m,
|
|
19
|
+
"hover:bg-zinc-50 dark:hover:bg-zinc-800/60": !m,
|
|
20
|
+
"opacity-50": c.xrayFilter !== "all" && !m
|
|
21
|
+
}),
|
|
22
|
+
onClick: h,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ a("span", {
|
|
25
|
+
className: "h-2.5 w-2.5 shrink-0 rounded-full",
|
|
26
|
+
style: { backgroundColor: p }
|
|
27
|
+
}),
|
|
28
|
+
/* @__PURE__ */ a("span", {
|
|
29
|
+
className: "min-w-0 truncate font-medium text-zinc-800 dark:text-zinc-200",
|
|
30
|
+
children: d
|
|
31
|
+
}),
|
|
32
|
+
/* @__PURE__ */ a("span", {
|
|
33
|
+
className: "ml-auto rounded-full bg-zinc-100 px-1.5 text-[10px] font-semibold text-zinc-600 tabular-nums dark:bg-zinc-800 dark:text-zinc-300",
|
|
34
|
+
children: u[s]
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { s as default };
|
package/dist/qa/QaContext.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { QaFindings } from './findings';
|
|
2
2
|
import { QaCheck, QaSettings } from './qaSettings';
|
|
3
|
+
import { XrayCounts } from './xray';
|
|
3
4
|
import { ReactNode, RefObject } from 'react';
|
|
4
5
|
export interface QaContextValue {
|
|
5
6
|
settings: QaSettings;
|
|
@@ -8,6 +9,9 @@ export interface QaContextValue {
|
|
|
8
9
|
/** What the checks that are on found, the last time they looked. */
|
|
9
10
|
findings: QaFindings;
|
|
10
11
|
setFindings: (findings: QaFindings) => void;
|
|
12
|
+
/** How many elements of the page the x-ray marked, by mark, the last time it looked. */
|
|
13
|
+
xrayCounts: XrayCounts;
|
|
14
|
+
setXrayCounts: (counts: XrayCounts) => void;
|
|
11
15
|
/** Bumped to make the checks look again. */
|
|
12
16
|
round: number;
|
|
13
17
|
rescan: () => void;
|
package/dist/qa/QaContext.mjs
CHANGED
|
@@ -1,73 +1,79 @@
|
|
|
1
1
|
import { NO_FINDINGS as e } from "./findings.mjs";
|
|
2
2
|
import { QA_DEFAULTS as t } from "./qaSettings.mjs";
|
|
3
|
-
import n from "
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import { NO_XRAY_COUNTS as n } from "./xray.mjs";
|
|
4
|
+
import r from "@plitzi/plitzi-ui/hooks/useStorage";
|
|
5
|
+
import { createContext as i, useCallback as a, useEffect as o, useMemo as s, useState as c } from "react";
|
|
6
|
+
import { jsx as l } from "react/jsx-runtime";
|
|
6
7
|
//#region src/qa/QaContext.tsx
|
|
7
|
-
var
|
|
8
|
+
var u = i({
|
|
8
9
|
settings: t,
|
|
9
10
|
setSetting: () => void 0,
|
|
10
11
|
setCheck: () => void 0,
|
|
11
12
|
findings: e,
|
|
12
13
|
setFindings: () => void 0,
|
|
14
|
+
xrayCounts: n,
|
|
15
|
+
setXrayCounts: () => void 0,
|
|
13
16
|
round: 0,
|
|
14
17
|
rescan: () => void 0,
|
|
15
18
|
pageRef: { current: null },
|
|
16
19
|
pinned: void 0,
|
|
17
20
|
setPinned: () => void 0
|
|
18
21
|
});
|
|
19
|
-
|
|
20
|
-
var
|
|
21
|
-
let [
|
|
22
|
+
u.displayName = "QaContext";
|
|
23
|
+
var d = ({ children: i, pageRef: d, collapsed: f }) => {
|
|
24
|
+
let [p, m] = r("plitzi-sdk-dev-tools-qa", t), [h, g] = c(e), [_, v] = c(n), [y, b] = c(0), [x, S] = c(), C = s(() => ({
|
|
22
25
|
...t,
|
|
23
|
-
...
|
|
26
|
+
...p,
|
|
24
27
|
checks: {
|
|
25
28
|
...t.checks,
|
|
26
|
-
...
|
|
29
|
+
...p.checks
|
|
27
30
|
}
|
|
28
|
-
}), [
|
|
31
|
+
}), [p]), w = a((e, t) => m((n) => ({
|
|
29
32
|
...n,
|
|
30
33
|
[e]: t
|
|
31
|
-
})), [
|
|
34
|
+
})), [m]), T = a((e, n) => m((r) => ({
|
|
32
35
|
...r,
|
|
33
36
|
checks: {
|
|
34
37
|
...t.checks,
|
|
35
38
|
...r.checks,
|
|
36
39
|
[e]: n
|
|
37
40
|
}
|
|
38
|
-
})), [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
})), [m]), E = a(() => b((e) => e + 1), []);
|
|
42
|
+
o(() => {
|
|
43
|
+
f && (m((e) => ({
|
|
41
44
|
...e,
|
|
42
45
|
inspect: !1,
|
|
43
46
|
checks: t.checks
|
|
44
|
-
})),
|
|
45
|
-
}, [
|
|
46
|
-
let
|
|
47
|
-
settings:
|
|
48
|
-
setSetting:
|
|
49
|
-
setCheck:
|
|
50
|
-
findings:
|
|
51
|
-
setFindings:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
})), S(void 0));
|
|
48
|
+
}, [f, m]);
|
|
49
|
+
let D = s(() => ({
|
|
50
|
+
settings: C,
|
|
51
|
+
setSetting: w,
|
|
52
|
+
setCheck: T,
|
|
53
|
+
findings: h,
|
|
54
|
+
setFindings: g,
|
|
55
|
+
xrayCounts: _,
|
|
56
|
+
setXrayCounts: v,
|
|
57
|
+
round: y,
|
|
58
|
+
rescan: E,
|
|
59
|
+
pageRef: d,
|
|
60
|
+
pinned: x,
|
|
61
|
+
setPinned: S
|
|
57
62
|
}), [
|
|
58
|
-
b,
|
|
59
|
-
x,
|
|
60
|
-
S,
|
|
61
|
-
m,
|
|
62
|
-
g,
|
|
63
63
|
C,
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
w,
|
|
65
|
+
T,
|
|
66
|
+
h,
|
|
67
|
+
_,
|
|
68
|
+
y,
|
|
69
|
+
E,
|
|
70
|
+
d,
|
|
71
|
+
x
|
|
66
72
|
]);
|
|
67
|
-
return /* @__PURE__ */
|
|
68
|
-
value:
|
|
69
|
-
children:
|
|
73
|
+
return /* @__PURE__ */ l(u, {
|
|
74
|
+
value: D,
|
|
75
|
+
children: i
|
|
70
76
|
});
|
|
71
77
|
};
|
|
72
78
|
//#endregion
|
|
73
|
-
export {
|
|
79
|
+
export { d as QaProvider, u as default };
|
package/dist/qa/QaLayer.mjs
CHANGED
|
@@ -1,69 +1,121 @@
|
|
|
1
1
|
import { NO_FINDINGS as e } from "./findings.mjs";
|
|
2
2
|
import { QA_CHECKS as t, QA_FINDING_ATTRIBUTE as n, QA_PAGE_ATTRIBUTE as r, REDUCED_MOTION_CLASS as i, isQaActive as a } from "./qaSettings.mjs";
|
|
3
|
-
import o from "./
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import h from "./
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
3
|
+
import { NO_XRAY_COUNTS as o, XRAY_ATTRIBUTE as s, xrayMarksOf as c } from "./xray.mjs";
|
|
4
|
+
import l from "./QaContext.mjs";
|
|
5
|
+
import { CHECKS as u } from "./checks/index.mjs";
|
|
6
|
+
import d from "./overlays/QaGrid.mjs";
|
|
7
|
+
import f from "./overlays/QaInspector.mjs";
|
|
8
|
+
import p from "./overlays/QaTabOrder.mjs";
|
|
9
|
+
import m from "./overlays/QaViewport.mjs";
|
|
10
|
+
import h from "./overlays/QaXrayTags.mjs";
|
|
11
|
+
import { VISION_MATRIX as g, qaCss as _, visionFilterId as v } from "./qaCss.mjs";
|
|
12
|
+
import y from "./usePageBox.mjs";
|
|
13
|
+
import { use as b, useEffect as x, useMemo as S } from "react";
|
|
14
|
+
import { useCommonStore as C } from "@plitzi/sdk-shared/store";
|
|
15
|
+
import { Fragment as w, jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
16
|
+
import { treeOf as D } from "@plitzi/sdk-schema/helpers/components";
|
|
14
17
|
//#region src/qa/QaLayer.tsx
|
|
15
|
-
var
|
|
16
|
-
let { settings:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
var O = "http://www.w3.org/2000/svg", k = 250, A = 1e3, j = 200, M = .25, N = () => {
|
|
19
|
+
let { settings: N, pageRef: P, round: F, setFindings: I, setXrayCounts: L } = b(l), [[R, z, B]] = C([
|
|
20
|
+
"navigation.currentPageId",
|
|
21
|
+
"schema.flat",
|
|
22
|
+
"schema.components"
|
|
23
|
+
]), V = y(P), H = a(N), U = S(() => _(N), [N]), W = S(() => t.filter((e) => N.checks[e]).join(" "), [N.checks]);
|
|
24
|
+
return x(() => {
|
|
25
|
+
let e = P.current;
|
|
26
|
+
if (e && H) return e.setAttribute(r, ""), () => e.removeAttribute(r);
|
|
27
|
+
}, [H, P]), x(() => {
|
|
28
|
+
if (!U) return;
|
|
22
29
|
let e = document.createElement("style");
|
|
23
|
-
return e.setAttribute("data-plitzi-qa", ""), e.textContent =
|
|
24
|
-
}, [
|
|
25
|
-
if (
|
|
26
|
-
}, [
|
|
27
|
-
let e =
|
|
30
|
+
return e.setAttribute("data-plitzi-qa", ""), e.textContent = U, document.head.append(e), () => e.remove();
|
|
31
|
+
}, [U]), x(() => {
|
|
32
|
+
if (N.reducedMotion) return document.documentElement.classList.add(i), () => document.documentElement.classList.remove(i);
|
|
33
|
+
}, [N.reducedMotion]), x(() => {
|
|
34
|
+
let e = N.vision;
|
|
28
35
|
if (e !== "protanopia" && e !== "deuteranopia" && e !== "tritanopia") return;
|
|
29
|
-
let t = document.createElementNS(
|
|
36
|
+
let t = document.createElementNS(O, "svg");
|
|
30
37
|
t.setAttribute("aria-hidden", "true"), t.setAttribute("style", "position: absolute; width: 0; height: 0");
|
|
31
|
-
let n = document.createElementNS(
|
|
32
|
-
n.setAttribute("id",
|
|
33
|
-
let r = document.createElementNS(
|
|
34
|
-
return r.setAttribute("type", "matrix"), r.setAttribute("values",
|
|
35
|
-
}, [
|
|
36
|
-
let
|
|
38
|
+
let n = document.createElementNS(O, "filter");
|
|
39
|
+
n.setAttribute("id", v(e));
|
|
40
|
+
let r = document.createElementNS(O, "feColorMatrix");
|
|
41
|
+
return r.setAttribute("type", "matrix"), r.setAttribute("values", g[e]), n.append(r), t.append(n), document.body.append(t), () => t.remove();
|
|
42
|
+
}, [N.vision]), x(() => {
|
|
43
|
+
let e = P.current;
|
|
44
|
+
if (!e || !N.xray) {
|
|
45
|
+
L(o);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let t, n = () => {
|
|
49
|
+
let t = { ...o };
|
|
50
|
+
e.querySelectorAll("[data-plitzi-el]").forEach((e) => {
|
|
51
|
+
let n = e.getAttribute("data-plitzi-el") ?? "", r = D({
|
|
52
|
+
flat: z,
|
|
53
|
+
components: B
|
|
54
|
+
}, n)?.flat[n]?.definition, i = r ? c(r) : [];
|
|
55
|
+
i.forEach((e) => {
|
|
56
|
+
t[e] += 1;
|
|
57
|
+
}), i.length === 0 ? e.removeAttribute(s) : e.getAttribute("data-plitzi-qa-xray") !== i.join(" ") && e.setAttribute(s, i.join(" "));
|
|
58
|
+
}), L(t);
|
|
59
|
+
}, r = () => {
|
|
60
|
+
clearTimeout(t), t = setTimeout(n, j);
|
|
61
|
+
};
|
|
62
|
+
n();
|
|
63
|
+
let i = new MutationObserver(r);
|
|
64
|
+
return i.observe(e, {
|
|
65
|
+
childList: !0,
|
|
66
|
+
subtree: !0
|
|
67
|
+
}), () => {
|
|
68
|
+
clearTimeout(t), i.disconnect(), e.querySelectorAll(`[${s}]`).forEach((e) => e.removeAttribute(s));
|
|
69
|
+
};
|
|
70
|
+
}, [
|
|
71
|
+
N.xray,
|
|
72
|
+
P,
|
|
73
|
+
z,
|
|
74
|
+
B,
|
|
75
|
+
R,
|
|
76
|
+
L
|
|
77
|
+
]), x(() => {
|
|
78
|
+
let e = P.current;
|
|
79
|
+
if (!e || !N.slowMotion) return;
|
|
80
|
+
let t = (t) => e.getAnimations({ subtree: !0 }).forEach((e) => {
|
|
81
|
+
e.playbackRate = t;
|
|
82
|
+
}), n = () => t(M);
|
|
83
|
+
return n(), e.addEventListener("animationstart", n), e.addEventListener("transitionrun", n), () => {
|
|
84
|
+
e.removeEventListener("animationstart", n), e.removeEventListener("transitionrun", n), t(1);
|
|
85
|
+
};
|
|
86
|
+
}, [N.slowMotion, P]), x(() => {
|
|
87
|
+
let r = P.current, i = t.filter((e) => W.split(" ").includes(e));
|
|
37
88
|
if (!r || i.length === 0) {
|
|
38
|
-
|
|
89
|
+
I(e);
|
|
39
90
|
return;
|
|
40
91
|
}
|
|
41
92
|
let a = [], o = () => {
|
|
42
93
|
a.forEach((e) => e.removeAttribute(n));
|
|
43
94
|
let t = { ...e };
|
|
44
|
-
for (let e of i) t[e] =
|
|
95
|
+
for (let e of i) t[e] = u[e].run(r);
|
|
45
96
|
let o = /* @__PURE__ */ new Map();
|
|
46
|
-
i.forEach((e) => t[e].forEach(({ element: t }) => o.set(t, [...o.get(t) ?? [], e]))), o.forEach((e, t) => t.setAttribute(n, e.join(" "))), a = [...o.keys()],
|
|
47
|
-
}, c, l
|
|
48
|
-
typeof requestIdleCallback == "function" ?
|
|
97
|
+
i.forEach((e) => t[e].forEach(({ element: t }) => o.set(t, [...o.get(t) ?? [], e]))), o.forEach((e, t) => t.setAttribute(n, e.join(" "))), a = [...o.keys()], I(t);
|
|
98
|
+
}, s, c, l = () => {
|
|
99
|
+
typeof requestIdleCallback == "function" ? c = requestIdleCallback(o, { timeout: A }) : o();
|
|
49
100
|
}, d = () => {
|
|
50
|
-
clearTimeout(
|
|
101
|
+
clearTimeout(s), c !== void 0 && typeof cancelIdleCallback == "function" && cancelIdleCallback(c), s = setTimeout(l, k);
|
|
51
102
|
};
|
|
52
103
|
return d(), window.addEventListener("resize", d), () => {
|
|
53
|
-
clearTimeout(
|
|
104
|
+
clearTimeout(s), c !== void 0 && typeof cancelIdleCallback == "function" && cancelIdleCallback(c), window.removeEventListener("resize", d), a.forEach((e) => e.removeAttribute(n));
|
|
54
105
|
};
|
|
55
106
|
}, [
|
|
107
|
+
W,
|
|
56
108
|
P,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
109
|
+
F,
|
|
110
|
+
R,
|
|
111
|
+
I
|
|
112
|
+
]), /* @__PURE__ */ E(w, { children: [
|
|
113
|
+
N.grid && /* @__PURE__ */ T(d, { box: V }),
|
|
114
|
+
N.xray && /* @__PURE__ */ T(h, { filter: N.xrayFilter }),
|
|
115
|
+
N.tabOrder && /* @__PURE__ */ T(p, {}),
|
|
116
|
+
N.inspect && /* @__PURE__ */ T(f, {}),
|
|
117
|
+
N.viewport && /* @__PURE__ */ T(m, { box: V })
|
|
66
118
|
] });
|
|
67
119
|
};
|
|
68
120
|
//#endregion
|
|
69
|
-
export {
|
|
121
|
+
export { N as default };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { XrayFilter } from '../xray';
|
|
2
|
+
export type QaXrayTagsProps = {
|
|
3
|
+
filter: XrayFilter;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Every element the x-ray marked, named on its corner with a dot for each thing wired to it — so the page says which of
|
|
7
|
+
* its parts are bound, conditional, interactive or moving without pointing at each one.
|
|
8
|
+
*/
|
|
9
|
+
declare const QaXrayTags: ({ filter }: QaXrayTagsProps) => import('react').JSX.Element;
|
|
10
|
+
export default QaXrayTags;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { XRAY as e, XRAY_ATTRIBUTE as t, XRAY_MARKS as n } from "../xray.mjs";
|
|
2
|
+
import r from "../QaContext.mjs";
|
|
3
|
+
import { use as i, useEffect as a, useState as o } from "react";
|
|
4
|
+
import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
5
|
+
//#region src/qa/overlays/QaXrayTags.tsx
|
|
6
|
+
var u = 150, d = 16, f = (e) => n.some((t) => t === e), p = (e, n) => {
|
|
7
|
+
let r = [], i = /* @__PURE__ */ new Set();
|
|
8
|
+
for (let a of e.querySelectorAll(`[${t}]`)) {
|
|
9
|
+
if (r.length >= u) break;
|
|
10
|
+
let e = (a.getAttribute("data-plitzi-qa-xray") ?? "").split(" ").filter(f);
|
|
11
|
+
if (n !== "all" && !e.includes(n)) continue;
|
|
12
|
+
let t = a.getBoundingClientRect();
|
|
13
|
+
if (t.width === 0 || t.bottom < 0 || t.top > window.innerHeight) continue;
|
|
14
|
+
let o = (e) => `${String(Math.round(t.left))}:${String(Math.round(e))}`, s = t.top >= d ? t.top - d + 1 : Math.max(t.top, 0);
|
|
15
|
+
for (let e = 0; e < 3 && i.has(o(s)); e += 1) s += d;
|
|
16
|
+
i.has(o(s)) || (i.add(o(s)), r.push({
|
|
17
|
+
id: a.getAttribute("data-plitzi-el") ?? "",
|
|
18
|
+
marks: e,
|
|
19
|
+
left: t.left,
|
|
20
|
+
top: s
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
return r;
|
|
24
|
+
}, m = ({ filter: n }) => {
|
|
25
|
+
let { pageRef: u } = i(r), [d, f] = o([]);
|
|
26
|
+
return a(() => {
|
|
27
|
+
let e = u.current;
|
|
28
|
+
if (!e) return;
|
|
29
|
+
let r = 0, i = () => {
|
|
30
|
+
cancelAnimationFrame(r), r = requestAnimationFrame(() => f(p(e, n)));
|
|
31
|
+
};
|
|
32
|
+
i();
|
|
33
|
+
let a = new MutationObserver(i);
|
|
34
|
+
return a.observe(e, {
|
|
35
|
+
subtree: !0,
|
|
36
|
+
attributes: !0,
|
|
37
|
+
attributeFilter: [t]
|
|
38
|
+
}), document.addEventListener("scroll", i, !0), window.addEventListener("resize", i), () => {
|
|
39
|
+
cancelAnimationFrame(r), a.disconnect(), document.removeEventListener("scroll", i, !0), window.removeEventListener("resize", i);
|
|
40
|
+
};
|
|
41
|
+
}, [u, n]), /* @__PURE__ */ c(s, { children: d.map(({ id: t, marks: n, left: r, top: i }) => /* @__PURE__ */ l("span", {
|
|
42
|
+
className: "pointer-events-none fixed z-[999998] flex h-[15px] max-w-56 items-center gap-1 rounded-sm bg-zinc-900/85 px-1 font-mono text-[10px] leading-none text-white shadow-sm",
|
|
43
|
+
style: {
|
|
44
|
+
left: r,
|
|
45
|
+
top: i
|
|
46
|
+
},
|
|
47
|
+
children: [n.map((t) => /* @__PURE__ */ c("span", {
|
|
48
|
+
title: e[t].label,
|
|
49
|
+
className: "h-1.5 w-1.5 shrink-0 rounded-full",
|
|
50
|
+
style: { backgroundColor: e[t].colour }
|
|
51
|
+
}, t)), /* @__PURE__ */ c("span", {
|
|
52
|
+
className: "truncate",
|
|
53
|
+
children: t
|
|
54
|
+
})]
|
|
55
|
+
}, `${t}-${String(r)}-${String(i)}`)) });
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { m as default };
|
package/dist/qa/qaCss.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { QA_CHECKS as e, QA_FINDING_ATTRIBUTE as t, QA_PAGE_ATTRIBUTE as n } from "./qaSettings.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { XRAY as r, XRAY_ATTRIBUTE as i, XRAY_MARKS as a } from "./xray.mjs";
|
|
3
|
+
import { CHECKS as o } from "./checks/index.mjs";
|
|
3
4
|
//#region src/qa/qaCss.ts
|
|
4
|
-
var
|
|
5
|
-
${
|
|
6
|
-
${
|
|
7
|
-
${
|
|
8
|
-
${
|
|
5
|
+
var s = `[${n}]`, c = ":is([data-type=\"heading\"], [data-type=\"text\"], [data-type=\"paragraph\"], [data-type=\"button\"], [data-type=\"link\"])", l = `
|
|
6
|
+
${s} [data-plitzi-el] { outline: 1px dashed rgba(124, 92, 255, 0.5); outline-offset: -1px; }
|
|
7
|
+
${s} [data-plitzi-el]:hover { outline: 1.5px solid #7c5cff; outline-offset: -1.5px; }
|
|
8
|
+
${s} ${c}[data-plitzi-el]:hover { position: relative; }
|
|
9
|
+
${s} ${c}[data-plitzi-el]:hover::after {
|
|
9
10
|
content: attr(data-type) ' · ' attr(data-plitzi-el);
|
|
10
11
|
position: absolute;
|
|
11
12
|
left: -1px;
|
|
@@ -20,26 +21,27 @@ ${i} ${a}[data-plitzi-el]:hover::after {
|
|
|
20
21
|
text-transform: none;
|
|
21
22
|
white-space: nowrap;
|
|
22
23
|
pointer-events: none;
|
|
23
|
-
}`,
|
|
24
|
+
}`, u = (e) => [`${s} [data-plitzi-el] { outline: 1px dashed rgba(127, 127, 127, 0.35); outline-offset: -1px; }`, ...a.filter((t) => e === "all" || e === t).reverse().map((e) => `${s} [${i}~="${e}"] { outline: 1.5px solid ${r[e].colour}; outline-offset: -1.5px; }`)].join("\n"), d = `${s}, ${s} * { cursor: crosshair !important; }`, f = `${s} *, ${s} ::before, ${s} ::after { animation-play-state: paused !important; }`, p = (e) => e.map((e) => `${s} [${t}~="${e}"] { outline: 2px solid ${o[e].colour} !important; outline-offset: 1px !important; box-shadow: 0 0 0 4px color-mix(in srgb, ${o[e].colour} 22%, transparent) !important; }`).join("\n"), m = (e) => `plitzi-qa-${e}`, h = {
|
|
24
25
|
none: "none",
|
|
25
26
|
grayscale: "grayscale(1)",
|
|
26
|
-
protanopia: `url(#${
|
|
27
|
-
deuteranopia: `url(#${
|
|
28
|
-
tritanopia: `url(#${
|
|
27
|
+
protanopia: `url(#${m("protanopia")})`,
|
|
28
|
+
deuteranopia: `url(#${m("deuteranopia")})`,
|
|
29
|
+
tritanopia: `url(#${m("tritanopia")})`,
|
|
29
30
|
blurred: "blur(2px)"
|
|
30
|
-
},
|
|
31
|
+
}, g = {
|
|
31
32
|
protanopia: "0.567 0.433 0 0 0 0.558 0.442 0 0 0 0 0.242 0.758 0 0 0 0 0 1 0",
|
|
32
33
|
deuteranopia: "0.625 0.375 0 0 0 0.7 0.3 0 0 0 0 0.3 0.7 0 0 0 0 0 1 0",
|
|
33
34
|
tritanopia: "0.95 0.05 0 0 0 0 0.433 0.567 0 0 0 0.475 0.525 0 0 0 0 0 1 0"
|
|
34
|
-
},
|
|
35
|
+
}, _ = (t) => {
|
|
35
36
|
let n = e.filter((e) => t.checks[e]);
|
|
36
37
|
return [
|
|
37
|
-
t.inspect ?
|
|
38
|
-
t.outlines ?
|
|
39
|
-
t.
|
|
40
|
-
t.
|
|
41
|
-
|
|
38
|
+
t.inspect ? d : "",
|
|
39
|
+
t.outlines ? l : "",
|
|
40
|
+
t.xray ? u(t.xrayFilter) : "",
|
|
41
|
+
t.paused ? f : "",
|
|
42
|
+
t.vision === "none" ? "" : `${s} { filter: ${h[t.vision]}; }`,
|
|
43
|
+
p(n)
|
|
42
44
|
].filter(Boolean).join("\n");
|
|
43
45
|
};
|
|
44
46
|
//#endregion
|
|
45
|
-
export {
|
|
47
|
+
export { h as VISION_FILTER, g as VISION_MATRIX, _ as qaCss, m as visionFilterId };
|
package/dist/qa/qaSettings.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { XrayFilter } from './xray';
|
|
1
2
|
/**
|
|
2
3
|
* What the QA tab can turn on over a running page — for whoever checks a build before it ships: a designer lining
|
|
3
4
|
* things up, a tester looking for what breaks. Kept in this browser, and only ever offered where the dev tools are,
|
|
@@ -14,12 +15,18 @@ export interface QaSettings {
|
|
|
14
15
|
grid: boolean;
|
|
15
16
|
/** Every element's box, and its type and id when pointed at. */
|
|
16
17
|
outlines: boolean;
|
|
18
|
+
/** What the document wires to each element — data, a condition, a flow, motion, a flag — marked and named on it. */
|
|
19
|
+
xray: boolean;
|
|
20
|
+
/** The one kind of wiring the x-ray shows, or all of them. */
|
|
21
|
+
xrayFilter: XrayFilter;
|
|
17
22
|
/** The order the Tab key walks the page's controls in, numbered on them. */
|
|
18
23
|
tabOrder: boolean;
|
|
19
24
|
/** The viewport's size and the breakpoint whose rules show. */
|
|
20
25
|
viewport: boolean;
|
|
21
26
|
/** Every animation held where it is, to look at a moment of it. */
|
|
22
27
|
paused: boolean;
|
|
28
|
+
/** Every animation at a quarter of its speed, to see how it moves rather than that it did. */
|
|
29
|
+
slowMotion: boolean;
|
|
23
30
|
/** The page as a visitor who asked for less motion gets it — the SDK's own rule, by class. */
|
|
24
31
|
reducedMotion: boolean;
|
|
25
32
|
vision: VisionMode;
|
|
@@ -27,7 +34,7 @@ export interface QaSettings {
|
|
|
27
34
|
}
|
|
28
35
|
export declare const QA_DEFAULTS: QaSettings;
|
|
29
36
|
/** The tools that are simply on or off. */
|
|
30
|
-
export type QaSwitch = 'inspect' | 'grid' | 'outlines' | 'tabOrder' | 'viewport' | 'paused' | 'reducedMotion';
|
|
37
|
+
export type QaSwitch = 'inspect' | 'grid' | 'outlines' | 'xray' | 'tabOrder' | 'viewport' | 'paused' | 'slowMotion' | 'reducedMotion';
|
|
31
38
|
/** Whether any of it is on: the page is marked only while something is. */
|
|
32
39
|
export declare const isQaActive: (settings: QaSettings) => boolean;
|
|
33
40
|
/** The class the SDK's stylesheet stills every animation under, as its `prefers-reduced-motion` rule does. */
|
package/dist/qa/qaSettings.mjs
CHANGED
|
@@ -10,9 +10,12 @@ var e = [
|
|
|
10
10
|
inspect: !1,
|
|
11
11
|
grid: !1,
|
|
12
12
|
outlines: !1,
|
|
13
|
+
xray: !1,
|
|
14
|
+
xrayFilter: "all",
|
|
13
15
|
tabOrder: !1,
|
|
14
16
|
viewport: !1,
|
|
15
17
|
paused: !1,
|
|
18
|
+
slowMotion: !1,
|
|
16
19
|
reducedMotion: !1,
|
|
17
20
|
vision: "none",
|
|
18
21
|
checks: {
|
|
@@ -23,6 +26,6 @@ var e = [
|
|
|
23
26
|
images: !1,
|
|
24
27
|
headings: !1
|
|
25
28
|
}
|
|
26
|
-
}, n = (e) => e.inspect || e.grid || e.outlines || e.tabOrder || e.viewport || e.paused || e.reducedMotion || e.vision !== "none" || Object.values(e.checks).some(Boolean), r = "plitzi-reduced-motion", i = "data-plitzi-qa-page", a = "data-plitzi-qa-finding";
|
|
29
|
+
}, n = (e) => e.inspect || e.grid || e.outlines || e.xray || e.tabOrder || e.viewport || e.paused || e.slowMotion || e.reducedMotion || e.vision !== "none" || Object.values(e.checks).some(Boolean), r = "plitzi-reduced-motion", i = "data-plitzi-qa-page", a = "data-plitzi-qa-finding";
|
|
27
30
|
//#endregion
|
|
28
31
|
export { e as QA_CHECKS, t as QA_DEFAULTS, a as QA_FINDING_ATTRIBUTE, i as QA_PAGE_ATTRIBUTE, r as REDUCED_MOTION_CLASS, n as isQaActive };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ElementDefinition } from '@plitzi/sdk-shared';
|
|
2
|
+
/**
|
|
3
|
+
* What the document wires to an element that its box does not show: where its values come from, what it does when
|
|
4
|
+
* used, whether it may be hidden, how it moves and the flag it exists under. The x-ray marks each on the page, which is
|
|
5
|
+
* what a tester needs to know before asking why something shows, moves or does what it does.
|
|
6
|
+
*/
|
|
7
|
+
export declare const XRAY_MARKS: readonly ["data", "visibility", "flows", "motion", "flag"];
|
|
8
|
+
export type XrayMark = (typeof XRAY_MARKS)[number];
|
|
9
|
+
export type XrayFilter = XrayMark | 'all';
|
|
10
|
+
/** The attribute the x-ray marks an element with, its value the marks it carries. */
|
|
11
|
+
export declare const XRAY_ATTRIBUTE = "data-plitzi-qa-xray";
|
|
12
|
+
export declare const XRAY: Record<XrayMark, {
|
|
13
|
+
label: string;
|
|
14
|
+
description: string;
|
|
15
|
+
colour: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type XrayCounts = Record<XrayMark, number>;
|
|
18
|
+
export declare const NO_XRAY_COUNTS: XrayCounts;
|
|
19
|
+
/** The marks an element's definition earns, in the order of {@link XRAY_MARKS}. */
|
|
20
|
+
export declare const xrayMarksOf: (definition: ElementDefinition) => XrayMark[];
|
package/dist/qa/xray.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//#region src/qa/xray.ts
|
|
2
|
+
var e = [
|
|
3
|
+
"data",
|
|
4
|
+
"visibility",
|
|
5
|
+
"flows",
|
|
6
|
+
"motion",
|
|
7
|
+
"flag"
|
|
8
|
+
], t = "data-plitzi-qa-xray", n = {
|
|
9
|
+
data: {
|
|
10
|
+
label: "Bound to data",
|
|
11
|
+
description: "A value of it — a text, a style, a state — is read from a binding",
|
|
12
|
+
colour: "#0ea5e9"
|
|
13
|
+
},
|
|
14
|
+
visibility: {
|
|
15
|
+
label: "Shown on a condition",
|
|
16
|
+
description: "Whether it shows is bound, or it starts hidden",
|
|
17
|
+
colour: "#f59e0b"
|
|
18
|
+
},
|
|
19
|
+
flows: {
|
|
20
|
+
label: "Runs a flow",
|
|
21
|
+
description: "Something done to it starts an interaction",
|
|
22
|
+
colour: "#ec4899"
|
|
23
|
+
},
|
|
24
|
+
motion: {
|
|
25
|
+
label: "Moves",
|
|
26
|
+
description: "It arrives, or keeps moving, by its declared motion",
|
|
27
|
+
colour: "#10b981"
|
|
28
|
+
},
|
|
29
|
+
flag: {
|
|
30
|
+
label: "Behind a flag",
|
|
31
|
+
description: "It exists only while a feature flag says so",
|
|
32
|
+
colour: "#8b5cf6"
|
|
33
|
+
}
|
|
34
|
+
}, r = {
|
|
35
|
+
data: 0,
|
|
36
|
+
visibility: 0,
|
|
37
|
+
flows: 0,
|
|
38
|
+
motion: 0,
|
|
39
|
+
flag: 0
|
|
40
|
+
}, i = (e) => e === "visibility", a = (t) => {
|
|
41
|
+
let n = Object.entries(t.bindings ?? {}).flatMap(([e, t]) => t.filter((e) => e.enabled !== !1).map((t) => ({
|
|
42
|
+
category: e,
|
|
43
|
+
to: t.to
|
|
44
|
+
}))), r = n.some(({ category: e, to: t }) => e === "initialState" && i(t)), a = {
|
|
45
|
+
data: n.some(({ category: e, to: t }) => !(e === "initialState" && i(t))),
|
|
46
|
+
visibility: r || t.initialState?.visibility === !1,
|
|
47
|
+
flows: Object.values(t.interactions ?? {}).some((e) => e.enabled),
|
|
48
|
+
motion: t.motion?.enter !== void 0 || t.motion?.loop !== void 0,
|
|
49
|
+
flag: t.flag !== void 0
|
|
50
|
+
};
|
|
51
|
+
return e.filter((e) => a[e]);
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { r as NO_XRAY_COUNTS, n as XRAY, t as XRAY_ATTRIBUTE, e as XRAY_MARKS, a as xrayMarksOf };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plitzi/sdk-dev-tools",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.3",
|
|
4
4
|
"license": "AGPL-3.0",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -674,6 +674,10 @@
|
|
|
674
674
|
"types": "./dist/components/DevToolsPanel/tabs/QaViewer/QaProperty.d.ts",
|
|
675
675
|
"import": "./dist/components/DevToolsPanel/tabs/QaViewer/QaProperty.mjs"
|
|
676
676
|
},
|
|
677
|
+
"./components/DevToolsPanel/tabs/QaViewer/QaReplayButton": {
|
|
678
|
+
"types": "./dist/components/DevToolsPanel/tabs/QaViewer/QaReplayButton.d.ts",
|
|
679
|
+
"import": "./dist/components/DevToolsPanel/tabs/QaViewer/QaReplayButton.mjs"
|
|
680
|
+
},
|
|
677
681
|
"./components/DevToolsPanel/tabs/QaViewer/QaRescanButton": {
|
|
678
682
|
"types": "./dist/components/DevToolsPanel/tabs/QaViewer/QaRescanButton.d.ts",
|
|
679
683
|
"import": "./dist/components/DevToolsPanel/tabs/QaViewer/QaRescanButton.mjs"
|
|
@@ -698,6 +702,14 @@
|
|
|
698
702
|
"types": "./dist/components/DevToolsPanel/tabs/QaViewer/QaVisionSelect.d.ts",
|
|
699
703
|
"import": "./dist/components/DevToolsPanel/tabs/QaViewer/QaVisionSelect.mjs"
|
|
700
704
|
},
|
|
705
|
+
"./components/DevToolsPanel/tabs/QaViewer/QaXray": {
|
|
706
|
+
"types": "./dist/components/DevToolsPanel/tabs/QaViewer/QaXray.d.ts",
|
|
707
|
+
"import": "./dist/components/DevToolsPanel/tabs/QaViewer/QaXray.mjs"
|
|
708
|
+
},
|
|
709
|
+
"./components/DevToolsPanel/tabs/QaViewer/QaXrayRow": {
|
|
710
|
+
"types": "./dist/components/DevToolsPanel/tabs/QaViewer/QaXrayRow.d.ts",
|
|
711
|
+
"import": "./dist/components/DevToolsPanel/tabs/QaViewer/QaXrayRow.mjs"
|
|
712
|
+
},
|
|
701
713
|
"./components/DevToolsPanel/tabs/QaViewer/index": {
|
|
702
714
|
"types": "./dist/components/DevToolsPanel/tabs/QaViewer/index.d.ts",
|
|
703
715
|
"import": "./dist/components/DevToolsPanel/tabs/QaViewer/index.mjs"
|
|
@@ -1110,6 +1122,10 @@
|
|
|
1110
1122
|
"types": "./dist/qa/overlays/QaViewport.d.ts",
|
|
1111
1123
|
"import": "./dist/qa/overlays/QaViewport.mjs"
|
|
1112
1124
|
},
|
|
1125
|
+
"./qa/overlays/QaXrayTags": {
|
|
1126
|
+
"types": "./dist/qa/overlays/QaXrayTags.d.ts",
|
|
1127
|
+
"import": "./dist/qa/overlays/QaXrayTags.mjs"
|
|
1128
|
+
},
|
|
1113
1129
|
"./qa/qaCss": {
|
|
1114
1130
|
"types": "./dist/qa/qaCss.d.ts",
|
|
1115
1131
|
"import": "./dist/qa/qaCss.mjs"
|
|
@@ -1126,6 +1142,10 @@
|
|
|
1126
1142
|
"types": "./dist/qa/usePageBox.d.ts",
|
|
1127
1143
|
"import": "./dist/qa/usePageBox.mjs"
|
|
1128
1144
|
},
|
|
1145
|
+
"./qa/xray": {
|
|
1146
|
+
"types": "./dist/qa/xray.d.ts",
|
|
1147
|
+
"import": "./dist/qa/xray.mjs"
|
|
1148
|
+
},
|
|
1129
1149
|
"./scope/helpers": {
|
|
1130
1150
|
"types": "./dist/scope/helpers.d.ts",
|
|
1131
1151
|
"import": "./dist/scope/helpers.mjs"
|
|
@@ -1187,10 +1207,10 @@
|
|
|
1187
1207
|
"dependencies": {
|
|
1188
1208
|
"@plitzi/nexus": "^1.4.0",
|
|
1189
1209
|
"@plitzi/plitzi-ui": "^1.6.29",
|
|
1190
|
-
"@plitzi/sdk-navigation": "0.38.
|
|
1191
|
-
"@plitzi/sdk-schema": "0.38.
|
|
1192
|
-
"@plitzi/sdk-shared": "0.38.
|
|
1193
|
-
"@plitzi/sdk-style": "0.38.
|
|
1210
|
+
"@plitzi/sdk-navigation": "0.38.3",
|
|
1211
|
+
"@plitzi/sdk-schema": "0.38.3",
|
|
1212
|
+
"@plitzi/sdk-shared": "0.38.3",
|
|
1213
|
+
"@plitzi/sdk-style": "0.38.3",
|
|
1194
1214
|
"@uiw/react-json-view": "^2.0.0-alpha.43",
|
|
1195
1215
|
"clsx": "^2.1.1"
|
|
1196
1216
|
}
|