@godxjp/ui 23.4.7 → 23.4.9
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/dist/components/feedback/dialog.d.ts +2 -1
- package/dist/components/feedback/dialog.js +9 -6
- package/dist/contracts/measurement.json +57 -0
- package/dist/styles/control.css +4 -0
- package/dist/styles/dialog-layout.css +22 -1
- package/dist/styles/layout.css +5 -5
- package/dist/tokens/components/feedback.css +3 -0
- package/docs/MEASUREMENT-CONTRACT.md +109 -0
- package/docs/SPACING.md +5 -0
- package/docs/feedback/danger-confirm.tsx +6 -3
- package/package.json +6 -3
|
@@ -142,7 +142,8 @@ declare const AlertDialogAction: typeof DialogAction;
|
|
|
142
142
|
declare const AlertDialogCancel: typeof DialogCancel;
|
|
143
143
|
/**
|
|
144
144
|
* Preset: confirm / destructive / typed-challenge / step-up without compound markup. Both flows
|
|
145
|
-
* force the destructive
|
|
145
|
+
* force the destructive shape: the confirm button plus antd's leading status glyph. The header
|
|
146
|
+
* surface stays untinted — see the note on `showDangerIcon` below.
|
|
146
147
|
*/
|
|
147
148
|
declare function AlertDialog({ open, onOpenChange, title, description, confirmLabel, cancelLabel, variant, confirmPhrase, challenge, onConfirm, stepUp, keepOpenOnConfirm, pending, }: AlertDialogProp): React.JSX.Element;
|
|
148
149
|
export declare const Dialog: typeof DialogRoot & {
|
|
@@ -4,7 +4,7 @@ import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
|
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { chain, mergeRefs } from "@react-aria/utils";
|
|
6
6
|
import { Dialog as RacDialog, Modal, ModalOverlay } from "react-aria-components";
|
|
7
|
-
import { X } from "lucide-react";
|
|
7
|
+
import { AlertCircle, X } from "lucide-react";
|
|
8
8
|
import { cn } from "../../lib/utils.js";
|
|
9
9
|
import { Slot } from "../../lib/slot.js";
|
|
10
10
|
import { overlayHeaderToneClass } from "./overlay-header-tone.js";
|
|
@@ -392,7 +392,7 @@ function AlertDialog({
|
|
|
392
392
|
const needsPhrase = phrase != null && phrase.length > 0;
|
|
393
393
|
const phraseMatches = !needsPhrase || typed === phrase;
|
|
394
394
|
const effectiveVariant = needsPhrase ? "destructive" : variant;
|
|
395
|
-
const
|
|
395
|
+
const showDangerIcon = effectiveVariant === "destructive";
|
|
396
396
|
const resolvedConfirm = confirmLabel ?? (needsPhrase ? t("common.delete") : t("common.continue"));
|
|
397
397
|
const resolvedCancel = cancelLabel ?? t("common.cancel");
|
|
398
398
|
const busy = pending || verifying;
|
|
@@ -429,10 +429,13 @@ function AlertDialog({
|
|
|
429
429
|
})();
|
|
430
430
|
};
|
|
431
431
|
return /* @__PURE__ */ jsx(AlertDialogRoot, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
/* @__PURE__ */ jsx(
|
|
434
|
-
|
|
435
|
-
|
|
432
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsxs("div", { className: "ui-dialog-confirm-body", children: [
|
|
433
|
+
showDangerIcon && /* @__PURE__ */ jsx(AlertCircle, { className: "ui-dialog-confirm-icon", "aria-hidden": true }),
|
|
434
|
+
/* @__PURE__ */ jsxs("div", { className: "ui-dialog-confirm-text", children: [
|
|
435
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: title }),
|
|
436
|
+
description ? /* @__PURE__ */ jsx(AlertDialogDescription, { children: description }) : null
|
|
437
|
+
] })
|
|
438
|
+
] }) }),
|
|
436
439
|
needsPhrase && /* @__PURE__ */ jsx(FormField, { id: inputId, label: t("common.typeToConfirm", { phrase }), children: /* @__PURE__ */ jsx(
|
|
437
440
|
Input,
|
|
438
441
|
{
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
+
"version": "23.4.9",
|
|
4
|
+
"targetSize": {
|
|
5
|
+
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
|
+
"min": 24,
|
|
7
|
+
"measures": "target",
|
|
8
|
+
"note": "The TARGET is the region that accepts the pointer action, which is not always the painted box. getBoundingClientRect() returns the border box and cannot see a pseudo-element, so it UNDER-REPORTS every selector listed under `expanders`. Measure with elementFromPoint — see `method` — or treat a listed selector as conforming at `targetMin`.",
|
|
9
|
+
"method": "docs/MEASUREMENT-CONTRACT.md#measuring-a-target",
|
|
10
|
+
"expanders": [
|
|
11
|
+
{
|
|
12
|
+
"selector": ".ui-control-inline-affix-action",
|
|
13
|
+
"via": "::after",
|
|
14
|
+
"source": "src/styles/control.css",
|
|
15
|
+
"targetMin": 24,
|
|
16
|
+
"components": [
|
|
17
|
+
"badge",
|
|
18
|
+
"date-picker",
|
|
19
|
+
"input",
|
|
20
|
+
"tag-input",
|
|
21
|
+
"textarea",
|
|
22
|
+
"time-picker"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"selector": ".ui-data-table-sort-button",
|
|
27
|
+
"via": "::after",
|
|
28
|
+
"source": "src/styles/table-layout.css",
|
|
29
|
+
"targetMin": 24,
|
|
30
|
+
"components": [
|
|
31
|
+
"data-table"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"selector": ".ui-number-input-step",
|
|
36
|
+
"via": "::after",
|
|
37
|
+
"source": "src/styles/control.css",
|
|
38
|
+
"targetMin": 24,
|
|
39
|
+
"components": [
|
|
40
|
+
"number-input"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"spacing": {
|
|
46
|
+
"scale": "--space-* measures the distance BETWEEN things: page sections, siblings, a Card and its content.",
|
|
47
|
+
"doesNotApplyTo": "The INTERIOR of a control. That geometry is derived from the control band, not from --space-*, so a control's own label sits closer to its edge than --space-2 and is not a finding.",
|
|
48
|
+
"derivation": "interior height = --control-height − (interior padding × 2)",
|
|
49
|
+
"predicate": "An element is a control when its painted block-size equals the resolved --control-height for its size. Segmented's track, Button, Input and Select all satisfy it — a gate that applies a --space-* floor inside a control flags all four, not just Segmented.",
|
|
50
|
+
"reference": "docs/SPACING.md#control-interiors-are-not-on-this-scale"
|
|
51
|
+
},
|
|
52
|
+
"issues": {
|
|
53
|
+
"503": "Segmented track padding read against a --space-2 floor that does not govern control interiors.",
|
|
54
|
+
"506": "NumberInput steppers read as 24×13 (paint); the target is 24×26.",
|
|
55
|
+
"507": "DatePicker calendar button read as 20×20 (paint); the target is 24×24."
|
|
56
|
+
}
|
|
57
|
+
}
|
package/dist/styles/control.css
CHANGED
|
@@ -470,6 +470,10 @@
|
|
|
470
470
|
fill: currentColor;
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
+
.ui-radio[data-state="unchecked"] .ui-radio-icon {
|
|
474
|
+
visibility: hidden;
|
|
475
|
+
}
|
|
476
|
+
|
|
473
477
|
.ui-switch:has(input[aria-invalid="true"]) {
|
|
474
478
|
--tw-ring-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--destructive));
|
|
475
479
|
box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--destructive));
|
|
@@ -123,7 +123,8 @@
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
[data-slot="dialog-content"]:has([data-slot="dialog-body"]) [data-slot="dialog-header"]
|
|
126
|
+
[data-slot="dialog-content"]:has([data-slot="dialog-body"]) [data-slot="dialog-header"],
|
|
127
|
+
[data-slot="dialog-header"]:not([data-tone="default"]) {
|
|
127
128
|
margin-inline: calc(-1 * var(--dialog-space-x));
|
|
128
129
|
margin-block-start: calc(-1 * var(--dialog-space-y));
|
|
129
130
|
padding: var(--dialog-space-y) var(--dialog-space-x);
|
|
@@ -222,6 +223,26 @@
|
|
|
222
223
|
[data-slot="dialog-header"]:not([data-tone="default"]) [data-slot="dialog-description"] {
|
|
223
224
|
color: hsl(var(--foreground));
|
|
224
225
|
}
|
|
226
|
+
|
|
227
|
+
.ui-dialog-confirm-body {
|
|
228
|
+
display: flex;
|
|
229
|
+
align-items: flex-start;
|
|
230
|
+
gap: var(--dialog-confirm-space-gap);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.ui-dialog-confirm-icon {
|
|
234
|
+
flex: none;
|
|
235
|
+
inline-size: var(--dialog-confirm-icon-size);
|
|
236
|
+
block-size: var(--dialog-confirm-icon-size);
|
|
237
|
+
color: hsl(var(--text-error));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.ui-dialog-confirm-text {
|
|
241
|
+
display: flex;
|
|
242
|
+
min-inline-size: 0;
|
|
243
|
+
flex-direction: column;
|
|
244
|
+
gap: var(--dialog-title-block-space-gap);
|
|
245
|
+
}
|
|
225
246
|
}
|
|
226
247
|
|
|
227
248
|
@media (prefers-reduced-motion: reduce) {
|
package/dist/styles/layout.css
CHANGED
|
@@ -716,6 +716,11 @@
|
|
|
716
716
|
width: 100%;
|
|
717
717
|
}
|
|
718
718
|
|
|
719
|
+
.ui-page-header-extra > .ui-flex[data-direction="row"] {
|
|
720
|
+
flex-wrap: wrap;
|
|
721
|
+
max-inline-size: 100%;
|
|
722
|
+
}
|
|
723
|
+
|
|
719
724
|
.ui-page-header-title-row {
|
|
720
725
|
display: flex;
|
|
721
726
|
flex-wrap: wrap;
|
|
@@ -762,11 +767,6 @@
|
|
|
762
767
|
.ui-page-header .ui-page-subtitle {
|
|
763
768
|
font-size: var(--page-subtitle-font-size-compact);
|
|
764
769
|
}
|
|
765
|
-
|
|
766
|
-
.ui-page-header-extra > .ui-flex[data-direction="row"] {
|
|
767
|
-
flex-wrap: wrap;
|
|
768
|
-
max-width: 100%;
|
|
769
|
-
}
|
|
770
770
|
}
|
|
771
771
|
|
|
772
772
|
@media (max-width: 639.98px) {
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
--dialog-title-block-space-gap: var(--space-1);
|
|
37
37
|
--dialog-extra-space-gap: var(--space-2);
|
|
38
38
|
|
|
39
|
+
--dialog-confirm-icon-size: var(--icon-size-xl);
|
|
40
|
+
--dialog-confirm-space-gap: var(--space-3);
|
|
41
|
+
|
|
39
42
|
--dialog-header-close-space-inline-end: var(--space-8);
|
|
40
43
|
|
|
41
44
|
--dialog-close-rest-alpha: 0.7;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Measurement contract
|
|
2
|
+
|
|
3
|
+
**What box this library means when it says a target is 24×24, and where the `--space-*` scale stops
|
|
4
|
+
applying.** The facts below also ship as data at
|
|
5
|
+
`node_modules/@godxjp/ui/dist/contracts/measurement.json`, so a gate can read them without reading
|
|
6
|
+
this page.
|
|
7
|
+
|
|
8
|
+
## Why this page exists
|
|
9
|
+
|
|
10
|
+
Three issues — [#503], [#506], [#507] — were each closed and reopened four times between 23.0.0 and
|
|
11
|
+
23.4.5. Every reopening carried a correct measurement. Every closing carried a correct fix. The two
|
|
12
|
+
sides were measuring different boxes:
|
|
13
|
+
|
|
14
|
+
| issue | the consumer's gate read | what the library ships |
|
|
15
|
+
| ----- | ------------------------ | ---------------------------- |
|
|
16
|
+
| #507 | `20×20` | a **24×24** target |
|
|
17
|
+
| #506 | `24×13` | a **24×26** target |
|
|
18
|
+
| #503 | text `5.1px` from edge | 5.1px **derived** from the band |
|
|
19
|
+
|
|
20
|
+
`getBoundingClientRect()` returns an element's **border box**, and a border box does not include an
|
|
21
|
+
absolutely-positioned pseudo-element. So a gate built on it reports the same number forever no
|
|
22
|
+
matter what the library ships — which means it cannot tell *fixed* from *ignored*, and reopening the
|
|
23
|
+
issue is the correct thing for it to do. Prose could not close that gap either: `docs/SPACING.md`
|
|
24
|
+
carried the #503 derivation from 23.4.0 onward and the issue was reopened twice afterwards, because
|
|
25
|
+
a gate cannot read prose.
|
|
26
|
+
|
|
27
|
+
## Target size
|
|
28
|
+
|
|
29
|
+
**WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px.** The criterion measures the
|
|
30
|
+
**target**: the region that accepts the pointer action. That is not always the painted box, and
|
|
31
|
+
carrying the target on a pseudo-element is the technique [Understanding 2.5.8] names.
|
|
32
|
+
|
|
33
|
+
This library does that in three places, because in each one growing the **paint** would move
|
|
34
|
+
geometry that belongs to something else:
|
|
35
|
+
|
|
36
|
+
| selector | paint stays | why the paint cannot grow |
|
|
37
|
+
| ------------------------------- | ----------- | --------------------------------------------------------------------------- |
|
|
38
|
+
| `.ui-control-inline-affix-action` | 20×20 | it is an affix inside a 32px field; growing it moves the field's own geometry |
|
|
39
|
+
| `.ui-number-input-step` | 24×13 | two steppers stacked in a 32px band — 24×2 = 48 does not fit |
|
|
40
|
+
| `.ui-data-table-sort-button` | header size | a header cell's height is the table's row rhythm |
|
|
41
|
+
|
|
42
|
+
The authoritative list is `targetSize.expanders` in `dist/contracts/measurement.json`; it is
|
|
43
|
+
generated from the CSS, and `scripts/check-measurement-contract.mjs` proves every entry in a real
|
|
44
|
+
browser before release, so it cannot claim a target the library does not ship.
|
|
45
|
+
|
|
46
|
+
### Measuring a target
|
|
47
|
+
|
|
48
|
+
Scan outward from the centre with `elementFromPoint` until the point stops belonging to the element.
|
|
49
|
+
This reads the real target, and it also catches the case `getBoundingClientRect` misses in the other
|
|
50
|
+
direction — a 44×44 button half-covered by something else still reports 44×44 from its rect.
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
function hitRegion(el) {
|
|
54
|
+
const r = el.getBoundingClientRect();
|
|
55
|
+
const cx = r.left + r.width / 2;
|
|
56
|
+
const cy = r.top + r.height / 2;
|
|
57
|
+
const edge = (dx, dy) => {
|
|
58
|
+
let reach = 0;
|
|
59
|
+
for (let i = 0; i <= 40; i += 0.25) {
|
|
60
|
+
const hit = document.elementFromPoint(cx + dx * i, cy + dy * i);
|
|
61
|
+
if (hit === el || el.contains(hit)) reach = i;
|
|
62
|
+
else break;
|
|
63
|
+
}
|
|
64
|
+
return reach;
|
|
65
|
+
};
|
|
66
|
+
return { width: edge(-1, 0) + edge(1, 0), height: edge(0, -1) + edge(0, 1) };
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
If your gate cannot run a hit-test, read the contract and treat a listed selector as conforming at
|
|
71
|
+
its `targetMin` instead:
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
const contract = require("@godxjp/ui/contracts/measurement.json");
|
|
75
|
+
const expanded = contract.targetSize.expanders.map((e) => e.selector);
|
|
76
|
+
|
|
77
|
+
// inside the gate, per candidate element:
|
|
78
|
+
if (expanded.some((sel) => el.matches(sel) || el.closest(sel))) return; // target is on a ::after
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Spacing
|
|
82
|
+
|
|
83
|
+
`--space-*` measures the distance **between** things: page sections, siblings in a stack, a card's
|
|
84
|
+
shell against its content. It is **not** a floor for the **interior** of a control — that geometry
|
|
85
|
+
derives from the control band (`--control-height`, `--control-padding-x`).
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
interior height = --control-height − (interior padding × 2)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A gate can tell the two apart at runtime without a selector list:
|
|
92
|
+
|
|
93
|
+
> An element is a control when its painted block-size equals the resolved `--control-height` for its
|
|
94
|
+
> size.
|
|
95
|
+
|
|
96
|
+
`Segmented`'s track satisfies it, and so do `Button`, `Input` and `Select` — which is the useful part
|
|
97
|
+
of the test: a `--space-2` floor applied inside a control flags all four, not just the one that got
|
|
98
|
+
reported. `docs/SPACING.md` § *Control interiors are NOT on this scale* carries the full derivation
|
|
99
|
+
and the `--segmented-track-padding` knob for a service that wants a roomier control.
|
|
100
|
+
|
|
101
|
+
## MCP
|
|
102
|
+
|
|
103
|
+
`get_rule` · `list_audit_rules` · `get_tokens` — and `draft_bug_report` if a measurement taken this
|
|
104
|
+
way still disagrees with what the library claims. Bring the number; that is what this page is for.
|
|
105
|
+
|
|
106
|
+
[#503]: https://github.com/godx-jp/godxjp-ui/issues/503
|
|
107
|
+
[#506]: https://github.com/godx-jp/godxjp-ui/issues/506
|
|
108
|
+
[#507]: https://github.com/godx-jp/godxjp-ui/issues/507
|
|
109
|
+
[understanding 2.5.8]: https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html
|
package/docs/SPACING.md
CHANGED
|
@@ -89,6 +89,11 @@ this library holds — or the track grows to 44px (28 + 8 × 2) and stops lining
|
|
|
89
89
|
control. The same derivation is why a `Button`'s own label sits ~5px inside its border. A control
|
|
90
90
|
is sized by its band; the band is what a dense enterprise UI is for.
|
|
91
91
|
|
|
92
|
+
**For a gate, not a reader.** This derivation also ships as data at
|
|
93
|
+
`dist/contracts/measurement.json` (`spacing`), because gh#503 was reopened twice *after* this
|
|
94
|
+
section was written — prose cannot be read by the browser test that files the bug. See
|
|
95
|
+
`docs/MEASUREMENT-CONTRACT.md`.
|
|
96
|
+
|
|
92
97
|
**The knob, if a service wants a roomier control.** `--segmented-track-padding` is a published
|
|
93
98
|
component token (`src/tokens/components/segmented.css`); raising it re-derives the item height from
|
|
94
99
|
the same formula, so the track stays exactly one control tall. Do not reach for a Tailwind `p-*` on
|
|
@@ -7,7 +7,8 @@ import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
|
7
7
|
/**
|
|
8
8
|
* DangerConfirm recipe (godxui#193) — high-stakes deletion built on the AlertDialog preset.
|
|
9
9
|
* No new component: `challenge` gates the confirm button behind an exact typed slug, and `stepUp`
|
|
10
|
-
* runs an async passkey / 2FA re-auth before onConfirm fires. Both force the destructive
|
|
10
|
+
* runs an async passkey / 2FA re-auth before onConfirm fires. Both force the destructive shape
|
|
11
|
+
* (button + leading status glyph, untinted surface — antd `Modal.confirm` parity).
|
|
11
12
|
* Mirrors DXS SCR-203 (org delete by slug) and SCR-209 (refund with step-up).
|
|
12
13
|
*/
|
|
13
14
|
export default function Demo() {
|
|
@@ -25,8 +26,10 @@ export default function Demo() {
|
|
|
25
26
|
<CardTitle level={2}>Organization delete · typed slug challenge</CardTitle>
|
|
26
27
|
<CardDescription>
|
|
27
28
|
The confirm button stays disabled until the operator types the exact organization slug
|
|
28
|
-
(<code>acme-inc</code>). A typed challenge always forces the destructive
|
|
29
|
-
|
|
29
|
+
(<code>acme-inc</code>). A typed challenge always forces the destructive shape: the
|
|
30
|
+
destructive confirm button and antd’s leading status glyph. The header surface
|
|
31
|
+
stays untinted — the glyph is the signal, exactly as <code>Modal.confirm</code> does
|
|
32
|
+
it.
|
|
30
33
|
</CardDescription>
|
|
31
34
|
</CardHeader>
|
|
32
35
|
<CardContent>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui",
|
|
3
|
-
"version": "23.4.
|
|
4
|
-
"godxUiMcp": "23.4.
|
|
3
|
+
"version": "23.4.9",
|
|
4
|
+
"godxUiMcp": "23.4.9",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"./styles/*": "./dist/styles/*.css",
|
|
53
53
|
"./theme/*": "./dist/theme/*",
|
|
54
54
|
"./tokens": "./dist/tokens/base.css",
|
|
55
|
+
"./contracts/measurement.json": "./dist/contracts/measurement.json",
|
|
55
56
|
"./admin": {
|
|
56
57
|
"types": "./dist/components/admin/index.d.ts",
|
|
57
58
|
"import": "./dist/components/admin/index.js"
|
|
@@ -335,7 +336,7 @@
|
|
|
335
336
|
"verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:radix-surface && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:disclosure-duplication && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:frame-coverage && pnpm test",
|
|
336
337
|
"verify:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:token-scale-bypass && pnpm check:radix-surface && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:disclosure-duplication && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm check:visual-audit && pnpm test",
|
|
337
338
|
"verify:ci": "pnpm verify:ci:static && pnpm check:frame-contracts && pnpm test",
|
|
338
|
-
"verify:ci:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:registry && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:no-antd-runtime && pnpm check:radix-surface && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:disclosure-duplication && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-token-sync && pnpm check:email-token-sync && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-catalog-completeness && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:gate-coverage && pnpm check:mcp-prop-sync && pnpm check:catalog-contradictions && pnpm check:catalog-snippets",
|
|
339
|
+
"verify:ci:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:registry && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:no-antd-runtime && pnpm check:radix-surface && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:disclosure-duplication && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:measurement-contract && pnpm check:mcp-token-sync && pnpm check:email-token-sync && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-catalog-completeness && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:gate-coverage && pnpm check:mcp-prop-sync && pnpm check:catalog-contradictions && pnpm check:catalog-snippets",
|
|
339
340
|
"verify:browser": "pnpm check:contrast && pnpm check:text-ink-clip && pnpm check:font-fallback-metrics && pnpm check:visual-audit",
|
|
340
341
|
"verify:release": "pnpm verify:static && pnpm check:frame-contracts && pnpm check:frame-coverage",
|
|
341
342
|
"verify:publish-tree": "pnpm build && pnpm check:packed-public-contract && pnpm check:use-client && pnpm check:dist-tokens-resolve",
|
|
@@ -399,6 +400,8 @@
|
|
|
399
400
|
"check:data-entry-frame-runtime": "node scripts/check-data-entry-frame-runtime.mjs",
|
|
400
401
|
"check:data-table-empty-inset": "node scripts/check-data-table-empty-inset.mjs",
|
|
401
402
|
"check:number-input-step-target": "node scripts/check-number-input-step-target.mjs",
|
|
403
|
+
"check:measurement-contract": "node scripts/gen-measurement-contract.mjs --check",
|
|
404
|
+
"check:measurement-contract-browser": "node scripts/check-measurement-contract.mjs",
|
|
402
405
|
"check:mcp-token-sync": "node scripts/gen-component-tokens.mjs --check",
|
|
403
406
|
"check:email-token-sync": "node scripts/gen-email-tokens.mjs --check",
|
|
404
407
|
"check:focus-ring-paint": "node scripts/check-focus-ring-paint.mjs",
|