@godxjp/ui 31.30.1 → 31.31.1
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/agent/START-HERE.md +4 -4
- package/agent/components/RangeTimeline.json +11 -1
- package/agent/components.json +11 -1
- package/agent/index.json +4 -4
- package/agent/llms.txt +5 -5
- package/agent/tokens.json +66 -0
- package/dist/components/data-display/range-timeline.d.ts +79 -0
- package/dist/components/data-display/range-timeline.js +313 -93
- package/dist/components/data-entry/record-picker.js +6 -0
- package/dist/components/ui/segmented.js +4 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +11 -1
- package/dist/i18n/messages/ja.json +11 -1
- package/dist/i18n/messages/vi.json +11 -1
- package/dist/styles/data-display-layout.css +170 -0
- package/dist/styles/layers.json +1 -1
- package/dist/tokens/components/data-display.css +12 -0
- package/docs/data-display/timeline.tsx +98 -0
- package/docs/i18n/messages/en.json +12 -1
- package/docs/i18n/messages/ja.json +12 -1
- package/docs/i18n/messages/vi.json +12 -1
- package/package.json +2 -2
- package/scripts/visual-audit.mjs +22 -3
|
@@ -2221,6 +2221,176 @@
|
|
|
2221
2221
|
box-shadow: inset var(--range-timeline-bar-overdue-width) 0 0 hsl(var(--destructive));
|
|
2222
2222
|
}
|
|
2223
2223
|
|
|
2224
|
+
.ui-range-timeline-finish,
|
|
2225
|
+
.ui-range-timeline-plan-tick {
|
|
2226
|
+
position: absolute;
|
|
2227
|
+
inset-block-start: 50%;
|
|
2228
|
+
transform: translate(-50%, -50%);
|
|
2229
|
+
block-size: var(--range-timeline-bar-height);
|
|
2230
|
+
}
|
|
2231
|
+
[dir="rtl"] .ui-range-timeline-finish,
|
|
2232
|
+
[dir="rtl"] .ui-range-timeline-plan-tick {
|
|
2233
|
+
transform: translate(50%, -50%);
|
|
2234
|
+
}
|
|
2235
|
+
.ui-range-timeline-finish {
|
|
2236
|
+
inline-size: var(--range-timeline-finish-inline-size);
|
|
2237
|
+
border-radius: var(--range-timeline-finish-inline-size);
|
|
2238
|
+
background: var(--range-timeline-bar-color, hsl(var(--primary)));
|
|
2239
|
+
}
|
|
2240
|
+
.ui-range-timeline-plan-tick {
|
|
2241
|
+
inline-size: 0;
|
|
2242
|
+
border-inline-start: var(--range-timeline-plan-tick-inline-size) dashed
|
|
2243
|
+
hsl(var(--foreground) / 0.45);
|
|
2244
|
+
}
|
|
2245
|
+
.ui-range-timeline-bar[data-open-end="true"] {
|
|
2246
|
+
mask-image: linear-gradient(
|
|
2247
|
+
to right,
|
|
2248
|
+
black calc(100% - var(--range-timeline-open-end-fade-inline-size)),
|
|
2249
|
+
transparent
|
|
2250
|
+
);
|
|
2251
|
+
}
|
|
2252
|
+
[dir="rtl"] .ui-range-timeline-bar[data-open-end="true"] {
|
|
2253
|
+
mask-image: linear-gradient(
|
|
2254
|
+
to left,
|
|
2255
|
+
black calc(100% - var(--range-timeline-open-end-fade-inline-size)),
|
|
2256
|
+
transparent
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
.ui-range-timeline-bar[data-cancelled="true"],
|
|
2260
|
+
.ui-range-timeline-milestone[data-cancelled="true"]::before {
|
|
2261
|
+
background-image: repeating-linear-gradient(
|
|
2262
|
+
-45deg,
|
|
2263
|
+
transparent 0 var(--range-timeline-cancelled-hatch-gap),
|
|
2264
|
+
var(--range-timeline-cancelled-hatch-color, hsl(var(--foreground) / 0.45))
|
|
2265
|
+
var(--range-timeline-cancelled-hatch-gap)
|
|
2266
|
+
calc(
|
|
2267
|
+
var(--range-timeline-cancelled-hatch-gap) +
|
|
2268
|
+
var(--range-timeline-cancelled-hatch-line-width)
|
|
2269
|
+
)
|
|
2270
|
+
);
|
|
2271
|
+
}
|
|
2272
|
+
.ui-range-timeline-milestone,
|
|
2273
|
+
.ui-range-timeline-plan-diamond {
|
|
2274
|
+
position: absolute;
|
|
2275
|
+
inset-block-start: 50%;
|
|
2276
|
+
inline-size: var(--range-timeline-milestone-size);
|
|
2277
|
+
block-size: var(--range-timeline-milestone-size);
|
|
2278
|
+
transform: translate(-50%, -50%);
|
|
2279
|
+
}
|
|
2280
|
+
[dir="rtl"] .ui-range-timeline-milestone,
|
|
2281
|
+
[dir="rtl"] .ui-range-timeline-plan-diamond {
|
|
2282
|
+
transform: translate(50%, -50%);
|
|
2283
|
+
}
|
|
2284
|
+
.ui-range-timeline-milestone::before,
|
|
2285
|
+
.ui-range-timeline-plan-diamond::before {
|
|
2286
|
+
content: "";
|
|
2287
|
+
position: absolute;
|
|
2288
|
+
inset: calc(var(--range-timeline-milestone-size) * 0.15);
|
|
2289
|
+
rotate: 45deg;
|
|
2290
|
+
}
|
|
2291
|
+
.ui-range-timeline-milestone {
|
|
2292
|
+
color: var(--range-timeline-bar-ink, hsl(var(--primary-foreground)));
|
|
2293
|
+
}
|
|
2294
|
+
.ui-range-timeline-milestone::before {
|
|
2295
|
+
background-color: var(--range-timeline-bar-color, hsl(var(--primary)));
|
|
2296
|
+
}
|
|
2297
|
+
.ui-range-timeline-milestone[data-muted="true"] {
|
|
2298
|
+
opacity: var(--range-timeline-bar-muted-alpha);
|
|
2299
|
+
}
|
|
2300
|
+
.ui-range-timeline-milestone[data-overdue="true"]::before {
|
|
2301
|
+
box-shadow: 0 0 0 var(--range-timeline-bar-overdue-width) hsl(var(--destructive));
|
|
2302
|
+
}
|
|
2303
|
+
.ui-range-timeline-plan-diamond::before {
|
|
2304
|
+
border: var(--range-timeline-plan-border-width) dashed hsl(var(--foreground) / 0.45);
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
.ui-range-timeline-milestone > .ui-range-timeline-handle {
|
|
2308
|
+
inset-inline: 0;
|
|
2309
|
+
inline-size: 100%;
|
|
2310
|
+
}
|
|
2311
|
+
.ui-range-timeline-early-label {
|
|
2312
|
+
z-index: 1;
|
|
2313
|
+
position: absolute;
|
|
2314
|
+
inset-block-start: 50%;
|
|
2315
|
+
transform: translateY(-50%);
|
|
2316
|
+
pointer-events: none;
|
|
2317
|
+
padding-inline: var(--space-1);
|
|
2318
|
+
color: hsl(var(--text-success));
|
|
2319
|
+
font-size: var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)));
|
|
2320
|
+
font-weight: var(--font-weight-medium);
|
|
2321
|
+
white-space: nowrap;
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
.ui-range-timeline-links {
|
|
2325
|
+
position: absolute;
|
|
2326
|
+
inset: 0;
|
|
2327
|
+
z-index: 0;
|
|
2328
|
+
display: grid;
|
|
2329
|
+
grid-template-columns: var(--range-timeline-label-width) minmax(0, 1fr);
|
|
2330
|
+
pointer-events: none;
|
|
2331
|
+
}
|
|
2332
|
+
.ui-range-timeline-links-track {
|
|
2333
|
+
position: relative;
|
|
2334
|
+
min-inline-size: 0;
|
|
2335
|
+
}
|
|
2336
|
+
.ui-range-timeline-links-svg {
|
|
2337
|
+
position: absolute;
|
|
2338
|
+
inset: 0;
|
|
2339
|
+
inline-size: 100%;
|
|
2340
|
+
block-size: 100%;
|
|
2341
|
+
overflow: visible;
|
|
2342
|
+
}
|
|
2343
|
+
.ui-range-timeline-link line {
|
|
2344
|
+
fill: none;
|
|
2345
|
+
stroke: var(--range-timeline-link-color, hsl(var(--muted-foreground)));
|
|
2346
|
+
stroke-width: var(--range-timeline-link-width);
|
|
2347
|
+
}
|
|
2348
|
+
.ui-range-timeline-link[data-violated="true"] line {
|
|
2349
|
+
stroke: hsl(var(--mark-destructive, var(--text-error)));
|
|
2350
|
+
}
|
|
2351
|
+
.ui-range-timeline-link-head path {
|
|
2352
|
+
fill: var(--range-timeline-link-color, hsl(var(--muted-foreground)));
|
|
2353
|
+
}
|
|
2354
|
+
.ui-range-timeline-link-head[data-violated="true"] path {
|
|
2355
|
+
fill: hsl(var(--mark-destructive, var(--text-error)));
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
.ui-range-timeline-link-violation {
|
|
2359
|
+
position: absolute;
|
|
2360
|
+
inline-size: var(--range-timeline-link-violation-size);
|
|
2361
|
+
block-size: var(--range-timeline-link-violation-size);
|
|
2362
|
+
translate: -50% -50%;
|
|
2363
|
+
border-radius: var(--radius-full, 9999px);
|
|
2364
|
+
pointer-events: auto;
|
|
2365
|
+
}
|
|
2366
|
+
[dir="rtl"] .ui-range-timeline-link-violation {
|
|
2367
|
+
translate: 50% -50%;
|
|
2368
|
+
}
|
|
2369
|
+
.ui-range-timeline-link-violation::before {
|
|
2370
|
+
content: "";
|
|
2371
|
+
position: absolute;
|
|
2372
|
+
inset: calc(var(--range-timeline-link-violation-size) * 0.3);
|
|
2373
|
+
border-radius: inherit;
|
|
2374
|
+
background: hsl(var(--mark-destructive, var(--text-error)));
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
.ui-range-timeline-row[data-emphasis="warning"] > .ui-range-timeline-label {
|
|
2378
|
+
box-shadow: inset var(--range-timeline-emphasis-width) 0 0
|
|
2379
|
+
hsl(var(--mark-warning, var(--text-warning)));
|
|
2380
|
+
}
|
|
2381
|
+
.ui-range-timeline-row[data-emphasis="critical"] > .ui-range-timeline-label {
|
|
2382
|
+
box-shadow: inset var(--range-timeline-emphasis-width) 0 0
|
|
2383
|
+
hsl(var(--mark-destructive, var(--text-error)));
|
|
2384
|
+
}
|
|
2385
|
+
[dir="rtl"] .ui-range-timeline-row[data-emphasis="warning"] > .ui-range-timeline-label {
|
|
2386
|
+
box-shadow: inset calc(-1 * var(--range-timeline-emphasis-width)) 0 0
|
|
2387
|
+
hsl(var(--mark-warning, var(--text-warning)));
|
|
2388
|
+
}
|
|
2389
|
+
[dir="rtl"] .ui-range-timeline-row[data-emphasis="critical"] > .ui-range-timeline-label {
|
|
2390
|
+
box-shadow: inset calc(-1 * var(--range-timeline-emphasis-width)) 0 0
|
|
2391
|
+
hsl(var(--mark-destructive, var(--text-error)));
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2224
2394
|
.ui-range-timeline-bar-hit {
|
|
2225
2395
|
position: absolute;
|
|
2226
2396
|
inset: 0;
|
package/dist/styles/layers.json
CHANGED
|
@@ -270,6 +270,18 @@
|
|
|
270
270
|
--range-timeline-plan-border-width: var(--stroke-hairline);
|
|
271
271
|
--range-timeline-early-marker-inline-size: var(--stroke-md);
|
|
272
272
|
|
|
273
|
+
--range-timeline-milestone-size: var(--range-timeline-bar-height);
|
|
274
|
+
--range-timeline-finish-inline-size: calc(var(--stroke-md) * 2);
|
|
275
|
+
--range-timeline-plan-tick-inline-size: var(--stroke-md);
|
|
276
|
+
--range-timeline-open-end-fade-inline-size: var(--space-6);
|
|
277
|
+
--range-timeline-cancelled-hatch-gap: var(--space-1);
|
|
278
|
+
--range-timeline-cancelled-hatch-line-width: var(--stroke-md);
|
|
279
|
+
--range-timeline-cancelled-hatch-color: initial;
|
|
280
|
+
--range-timeline-link-color: initial;
|
|
281
|
+
--range-timeline-link-width: var(--stroke-hairline);
|
|
282
|
+
--range-timeline-link-violation-size: var(--space-6);
|
|
283
|
+
--range-timeline-emphasis-width: var(--stroke-md);
|
|
284
|
+
|
|
273
285
|
--range-timeline-border-color: var(--border);
|
|
274
286
|
|
|
275
287
|
--range-timeline-grid-color: initial;
|
|
@@ -354,6 +354,104 @@ export default function Demo() {
|
|
|
354
354
|
</CardContent>
|
|
355
355
|
</Card>
|
|
356
356
|
|
|
357
|
+
<Card>
|
|
358
|
+
<CardHeader>
|
|
359
|
+
<CardTitle level={2}>{t("rangeTimelineDocs.schedulesTitle")}</CardTitle>
|
|
360
|
+
<CardDescription>{t("rangeTimelineDocs.schedulesDescription")}</CardDescription>
|
|
361
|
+
</CardHeader>
|
|
362
|
+
<CardContent>
|
|
363
|
+
<RangeTimeline
|
|
364
|
+
label={t("rangeTimeline.schedule")}
|
|
365
|
+
planLabel={t("rangeTimelineDocs.baseline")}
|
|
366
|
+
columns={Array.from({ length: 14 }, (_, index) => ({
|
|
367
|
+
label: new Intl.NumberFormat(locale).format(index + 1),
|
|
368
|
+
units: 1,
|
|
369
|
+
}))}
|
|
370
|
+
rows={[
|
|
371
|
+
{
|
|
372
|
+
id: "phase",
|
|
373
|
+
label: t("rangeTimelineDocs.phase"),
|
|
374
|
+
start: null,
|
|
375
|
+
end: null,
|
|
376
|
+
startLabel: "",
|
|
377
|
+
endLabel: "",
|
|
378
|
+
emptyHint: false,
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
id: "design",
|
|
382
|
+
label: t("rangeTimelineDocs.design"),
|
|
383
|
+
start: 0,
|
|
384
|
+
end: 3,
|
|
385
|
+
startLabel: "",
|
|
386
|
+
endLabel: "",
|
|
387
|
+
color: "#16a34a",
|
|
388
|
+
plan: { start: 0, end: 4 },
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
id: "build",
|
|
392
|
+
label: t("rangeTimelineDocs.build"),
|
|
393
|
+
start: 4,
|
|
394
|
+
end: 9,
|
|
395
|
+
startLabel: "",
|
|
396
|
+
endLabel: "",
|
|
397
|
+
color: "#2563eb",
|
|
398
|
+
plan: { start: 4, end: 7 },
|
|
399
|
+
emphasis: "critical",
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
id: "release",
|
|
403
|
+
label: t("rangeTimelineDocs.release"),
|
|
404
|
+
start: null,
|
|
405
|
+
end: 10,
|
|
406
|
+
startLabel: "",
|
|
407
|
+
endLabel: "",
|
|
408
|
+
shape: "milestone",
|
|
409
|
+
color: "#7c3aed",
|
|
410
|
+
plan: { start: null, end: 8 },
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
id: "ops",
|
|
414
|
+
label: t("rangeTimelineDocs.ops"),
|
|
415
|
+
start: 6,
|
|
416
|
+
end: 12,
|
|
417
|
+
startLabel: "",
|
|
418
|
+
endLabel: "",
|
|
419
|
+
openEnd: true,
|
|
420
|
+
emphasis: "warning",
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
id: "legacy",
|
|
424
|
+
label: t("rangeTimelineDocs.legacy"),
|
|
425
|
+
start: 2,
|
|
426
|
+
end: 5,
|
|
427
|
+
startLabel: "",
|
|
428
|
+
endLabel: "",
|
|
429
|
+
cancelled: true,
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
id: "audit",
|
|
433
|
+
label: t("rangeTimelineDocs.audit"),
|
|
434
|
+
start: null,
|
|
435
|
+
end: 5,
|
|
436
|
+
startLabel: "",
|
|
437
|
+
endLabel: "",
|
|
438
|
+
},
|
|
439
|
+
]}
|
|
440
|
+
links={[
|
|
441
|
+
{ id: "design-build", from: "design", to: "build" },
|
|
442
|
+
{
|
|
443
|
+
id: "build-release",
|
|
444
|
+
from: "build",
|
|
445
|
+
to: "release",
|
|
446
|
+
type: "FF",
|
|
447
|
+
violated: true,
|
|
448
|
+
label: t("rangeTimelineDocs.violation"),
|
|
449
|
+
},
|
|
450
|
+
]}
|
|
451
|
+
/>
|
|
452
|
+
</CardContent>
|
|
453
|
+
</Card>
|
|
454
|
+
|
|
357
455
|
{/* sticky sits OUTSIDE a Card on purpose: Card clips (`overflow: hidden`), and a clipping
|
|
358
456
|
ancestor becomes the box the header sticks to — the same limit as antd Table sticky. */}
|
|
359
457
|
<Card>
|
|
@@ -1699,6 +1699,17 @@
|
|
|
1699
1699
|
"width": "Label column: {width}px",
|
|
1700
1700
|
"doneTask": "EXSELI-79 Release notes (done)",
|
|
1701
1701
|
"lateTask": "EXSELI-80 Data migration (overdue)",
|
|
1702
|
-
"plannedTask": "EXSELI-84 Payment API (plan 3–7, actual 3–10)"
|
|
1702
|
+
"plannedTask": "EXSELI-84 Payment API (plan 3–7, actual 3–10)",
|
|
1703
|
+
"schedulesTitle": "Schedules: milestones, dependencies, baselines",
|
|
1704
|
+
"schedulesDescription": "A phase heading row with no hint, bars against a baseline (overrun and early labels), a milestone diamond with its hollow baseline, an open-ended row with no end grip, a cancelled row, a finish recorded without a start, and dependency arrows: a violated one gets a focusable marker. Emphasis marks the critical path and an at-risk row.",
|
|
1705
|
+
"baseline": "the baseline",
|
|
1706
|
+
"phase": "Phase 1: Launch",
|
|
1707
|
+
"design": "Design",
|
|
1708
|
+
"build": "Build",
|
|
1709
|
+
"release": "Release",
|
|
1710
|
+
"ops": "Operations (in progress)",
|
|
1711
|
+
"legacy": "Legacy migration (cancelled)",
|
|
1712
|
+
"audit": "Security review (finish only)",
|
|
1713
|
+
"violation": "Release cannot finish before the build"
|
|
1703
1714
|
}
|
|
1704
1715
|
}
|
|
@@ -1692,6 +1692,17 @@
|
|
|
1692
1692
|
"width": "ラベル列: {width}px",
|
|
1693
1693
|
"doneTask": "EXSELI-79 リリースノート(完了)",
|
|
1694
1694
|
"lateTask": "EXSELI-80 データ移行(期限超過)",
|
|
1695
|
-
"plannedTask": "EXSELI-84 決済API(予定 3–7、実績 3–10)"
|
|
1695
|
+
"plannedTask": "EXSELI-84 決済API(予定 3–7、実績 3–10)",
|
|
1696
|
+
"schedulesTitle": "工程:マイルストーン・依存関係・ベースライン",
|
|
1697
|
+
"schedulesDescription": "見出しだけの行、ベースラインに対する遅れ・前倒しの表示、ベースライン(中抜きのひし形)付きのマイルストーン、完了未記録で終了グリップのない行、中止した行、開始日不明で完了だけ記録された行、依存関係の矢印(違反はフォーカスできるマーカー付き)。強調はクリティカルパスと要注意の行を示します。",
|
|
1698
|
+
"baseline": "ベースライン",
|
|
1699
|
+
"phase": "フェーズ1:リリース準備",
|
|
1700
|
+
"design": "設計",
|
|
1701
|
+
"build": "開発",
|
|
1702
|
+
"release": "リリース",
|
|
1703
|
+
"ops": "運用(進行中)",
|
|
1704
|
+
"legacy": "旧システム移行(中止)",
|
|
1705
|
+
"audit": "セキュリティ審査(完了のみ)",
|
|
1706
|
+
"violation": "開発の完了前にリリースは完了できません"
|
|
1696
1707
|
}
|
|
1697
1708
|
}
|
|
@@ -1692,6 +1692,17 @@
|
|
|
1692
1692
|
"width": "Cột nhãn: {width}px",
|
|
1693
1693
|
"doneTask": "EXSELI-79 Ghi chú phát hành (xong)",
|
|
1694
1694
|
"lateTask": "EXSELI-80 Chuyển dữ liệu (quá hạn)",
|
|
1695
|
-
"plannedTask": "EXSELI-84 API thanh toán (kế hoạch 3–7, thực tế 3–10)"
|
|
1695
|
+
"plannedTask": "EXSELI-84 API thanh toán (kế hoạch 3–7, thực tế 3–10)",
|
|
1696
|
+
"schedulesTitle": "Lịch trình: mốc, phụ thuộc, đường cơ sở",
|
|
1697
|
+
"schedulesDescription": "Một hàng tiêu đề không có gợi ý, các thanh so với đường cơ sở (nhãn trễ và sớm), một mốc hình thoi với đường cơ sở rỗng, một hàng chưa ghi nhận hoàn thành không có tay nắm cuối, một hàng đã hủy, một hàng chỉ có ngày hoàn thành, và các mũi tên phụ thuộc: mũi tên vi phạm có điểm đánh dấu có thể focus. Nhấn mạnh đánh dấu đường găng và hàng có rủi ro.",
|
|
1698
|
+
"baseline": "đường cơ sở",
|
|
1699
|
+
"phase": "Giai đoạn 1: Ra mắt",
|
|
1700
|
+
"design": "Thiết kế",
|
|
1701
|
+
"build": "Phát triển",
|
|
1702
|
+
"release": "Phát hành",
|
|
1703
|
+
"ops": "Vận hành (đang chạy)",
|
|
1704
|
+
"legacy": "Chuyển hệ thống cũ (đã hủy)",
|
|
1705
|
+
"audit": "Đánh giá bảo mật (chỉ ngày hoàn thành)",
|
|
1706
|
+
"violation": "Không thể phát hành trước khi phát triển xong"
|
|
1696
1707
|
}
|
|
1697
1708
|
}
|
package/package.json
CHANGED
package/scripts/visual-audit.mjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* godxjp-ui VISUAL audit — the runtime counterpart to the static ui-audit.mjs. Static audit
|
|
4
4
|
* (ui-audit.mjs) reads SOURCE with regexes — zero deps, fast, runs on every save.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { realpathSync } from "node:fs";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
7
8
|
import {
|
|
8
9
|
VISUAL_RULES,
|
|
9
10
|
isOversaturated,
|
|
@@ -84,7 +85,7 @@ export function exitCodeFor(result, { strict = false } = {}) {
|
|
|
84
85
|
|
|
85
86
|
/** Collect raw measurements from the rendered page; the PURE rules run back in node. */
|
|
86
87
|
/* c8 ignore start — runs inside the browser, exercised in the consumer/CI env. */
|
|
87
|
-
function collectInPage() {
|
|
88
|
+
export function collectInPage() {
|
|
88
89
|
const rgb = (s) => {
|
|
89
90
|
const m = s && s.match(/rgba?\(([^)]+)\)/);
|
|
90
91
|
if (!m) return null;
|
|
@@ -178,6 +179,9 @@ function collectInPage() {
|
|
|
178
179
|
"[role=alert], [role=status], [data-slot=alert], [class*=banner], [class*=notification]",
|
|
179
180
|
)) {
|
|
180
181
|
if (!visible(el)) continue;
|
|
182
|
+
// The kit's EmptyState is a polite status region, not a banner: it has no Alert anatomy to get
|
|
183
|
+
// wrong, so the banner checks do not apply to it (gh#1198).
|
|
184
|
+
if (el.closest("[data-slot=empty-state]")) continue;
|
|
181
185
|
const box = el.getBoundingClientRect();
|
|
182
186
|
const icons = el.querySelectorAll("svg, img").length;
|
|
183
187
|
const btns = [...el.querySelectorAll("button, [role=button], a[href]")];
|
|
@@ -558,9 +562,24 @@ async function main() {
|
|
|
558
562
|
}
|
|
559
563
|
/* c8 ignore stop */
|
|
560
564
|
|
|
565
|
+
/** True when `argvPath` (the script node was asked to run) is this module, symlinks resolved. */
|
|
566
|
+
export function isMainModule(argvPath, moduleUrl) {
|
|
567
|
+
const real = (p) => {
|
|
568
|
+
try {
|
|
569
|
+
return realpathSync(p);
|
|
570
|
+
} catch {
|
|
571
|
+
return p;
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
return real(argvPath) === real(fileURLToPath(moduleUrl));
|
|
575
|
+
}
|
|
576
|
+
|
|
561
577
|
// Run only as a CLI — importing this module (for unit tests) must NOT execute.
|
|
562
578
|
/* c8 ignore start */
|
|
563
|
-
|
|
579
|
+
// Compare REAL paths on both sides (gh#1198): through a symlinked node_modules, argv[1] is the
|
|
580
|
+
// link and import.meta.url the target, and a plain comparison skipped the audit and exited 0 — a
|
|
581
|
+
// silent no-op that reads exactly like a clean run.
|
|
582
|
+
if (process.argv[1] && isMainModule(process.argv[1], import.meta.url)) {
|
|
564
583
|
main().catch((e) => {
|
|
565
584
|
const asJson =
|
|
566
585
|
process.argv.indexOf("--format") !== -1 &&
|