@beyondwork/docx-react-component 1.0.51 → 1.0.53
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/package.json +3 -1
- package/src/api/public-types.ts +41 -0
- package/src/io/chart-preview-resolver.ts +41 -0
- package/src/io/docx-session.ts +187 -17
- package/src/runtime/collab/runtime-collab-sync.ts +87 -6
- package/src/runtime/document-runtime.ts +159 -0
- package/src/runtime/layout/layout-engine-version.ts +40 -2
- package/src/runtime/layout/public-facet.ts +43 -1
- package/src/runtime/prerender/cache-envelope.ts +30 -0
- package/src/runtime/prerender/customxml-cache.ts +17 -3
- package/src/runtime/prerender/prerender-document.ts +17 -1
- package/src/runtime/render/render-kernel.ts +67 -19
- package/src/runtime/surface-projection.ts +28 -0
- package/src/runtime/table-schema.ts +27 -0
- package/src/runtime/table-style-resolver.ts +51 -0
- package/src/ui/WordReviewEditor.tsx +3 -0
- package/src/ui/editor-runtime-boundary.ts +39 -2
- package/src/ui-tailwind/editor-surface/perf-probe.ts +1 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +54 -0
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +107 -3
- package/src/ui-tailwind/page-stack/tw-footnote-area.tsx +2 -2
- package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +224 -0
- package/src/ui-tailwind/page-stack/tw-page-footer-band.tsx +2 -2
- package/src/ui-tailwind/page-stack/tw-page-header-band.tsx +2 -2
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +11 -147
- package/src/ui-tailwind/theme/chart-palette-adapter.ts +57 -0
- package/src/ui-tailwind/theme/editor-theme.css +26 -24
- package/src/ui-tailwind/theme/tokens.css +345 -0
- package/src/ui-tailwind/theme/tokens.ts +313 -0
- package/src/ui-tailwind/theme/use-density.ts +60 -0
|
@@ -32,7 +32,7 @@ export interface TwPageHeaderBandProps {
|
|
|
32
32
|
"data-testid"?: string;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export const TwPageHeaderBand: React.FC<TwPageHeaderBandProps> = ({
|
|
35
|
+
export const TwPageHeaderBand: React.FC<TwPageHeaderBandProps> = React.memo(({
|
|
36
36
|
pageIndex,
|
|
37
37
|
blocks,
|
|
38
38
|
bandHeightPx,
|
|
@@ -69,6 +69,6 @@ export const TwPageHeaderBand: React.FC<TwPageHeaderBandProps> = ({
|
|
|
69
69
|
)}
|
|
70
70
|
</div>
|
|
71
71
|
);
|
|
72
|
-
};
|
|
72
|
+
});
|
|
73
73
|
|
|
74
74
|
export default TwPageHeaderBand;
|
|
@@ -77,11 +77,8 @@ import {
|
|
|
77
77
|
resolvePageOverlayRects,
|
|
78
78
|
type PageOverlayRect,
|
|
79
79
|
} from "../chrome-overlay/tw-page-stack-overlay-layer.tsx";
|
|
80
|
-
import { TwPageHeaderBand } from "./tw-page-header-band.tsx";
|
|
81
|
-
import { TwPageFooterBand } from "./tw-page-footer-band.tsx";
|
|
82
|
-
import { TwFootnoteArea } from "./tw-footnote-area.tsx";
|
|
83
80
|
import { TwEndnoteArea } from "./tw-endnote-area.tsx";
|
|
84
|
-
import {
|
|
81
|
+
import { TwPageChromeEntry } from "./tw-page-chrome-entry.tsx";
|
|
85
82
|
|
|
86
83
|
/**
|
|
87
84
|
* Minimal structural type for the PM `EditorView` handle consumed by
|
|
@@ -369,115 +366,18 @@ export const TwPageStackChromeLayer: React.FC<TwPageStackChromeLayerProps> = ({
|
|
|
369
366
|
{rects.map((rect, pageIndex) => {
|
|
370
367
|
const page = facet.getPage(pageIndex);
|
|
371
368
|
if (!page) return null;
|
|
372
|
-
|
|
373
|
-
// L7 Phase 2.8 — viewport cull. Pages outside the visible range
|
|
374
|
-
// (plus overscan) render an empty frame wrapper: the
|
|
375
|
-
// `data-page-chrome-frame` + `data-page-index` attributes stay
|
|
376
|
-
// put so downstream DOM queries (portal-slot, test hooks) keep
|
|
377
|
-
// working, but the four heavy React subtrees below do not mount.
|
|
378
|
-
const frameHeightPxForCull = rect.bottomPx - rect.topPx;
|
|
379
|
-
if (
|
|
380
|
-
visiblePageIndexRange &&
|
|
381
|
-
(pageIndex < visiblePageIndexRange.start ||
|
|
382
|
-
pageIndex >= visiblePageIndexRange.end)
|
|
383
|
-
) {
|
|
384
|
-
return (
|
|
385
|
-
<div
|
|
386
|
-
key={`page-chrome-${rect.pageId}`}
|
|
387
|
-
data-page-chrome-frame=""
|
|
388
|
-
data-page-index={pageIndex}
|
|
389
|
-
data-page-chrome-culled=""
|
|
390
|
-
style={{
|
|
391
|
-
position: "absolute",
|
|
392
|
-
top: `${rect.topPx}px`,
|
|
393
|
-
left: 0,
|
|
394
|
-
width: "100%",
|
|
395
|
-
height: `${frameHeightPxForCull}px`,
|
|
396
|
-
pointerEvents: "none",
|
|
397
|
-
}}
|
|
398
|
-
/>
|
|
399
|
-
);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
const layout = page.layout;
|
|
403
|
-
const headerStory = page.stories.header;
|
|
404
|
-
const footerStory = page.stories.footer;
|
|
405
|
-
const headerRegion = page.regions.header;
|
|
406
|
-
const footerRegion = page.regions.footer;
|
|
407
|
-
const footnoteRegion = page.regions.footnotes?.[0];
|
|
408
|
-
|
|
409
|
-
const headerBlocks = headerStory
|
|
410
|
-
? facet
|
|
411
|
-
.getStoryBlocksForRegion(pageIndex, "header")
|
|
412
|
-
.map((b) => b.blockSnapshot)
|
|
413
|
-
: [];
|
|
414
|
-
const footerBlocks = footerStory
|
|
415
|
-
? facet
|
|
416
|
-
.getStoryBlocksForRegion(pageIndex, "footer")
|
|
417
|
-
.map((b) => b.blockSnapshot)
|
|
418
|
-
: [];
|
|
419
|
-
const footnoteBlocks = footnoteRegion
|
|
420
|
-
? facet
|
|
421
|
-
.getStoryBlocksForRegion(pageIndex, "footnote-area")
|
|
422
|
-
.map((b) => b.blockSnapshot)
|
|
423
|
-
: [];
|
|
424
|
-
|
|
425
|
-
const px = (twips: number): number => twips * FRAME_PX_PER_TWIP_AT_96DPI;
|
|
426
|
-
const bandWidthPx = px(
|
|
427
|
-
layout.pageWidth - layout.marginLeft - layout.marginRight,
|
|
428
|
-
);
|
|
429
|
-
const bandLeftPx = px(layout.marginLeft);
|
|
430
|
-
const frameHeightPx = rect.bottomPx - rect.topPx;
|
|
431
|
-
|
|
432
369
|
return (
|
|
433
|
-
<
|
|
370
|
+
<TwPageChromeEntry
|
|
434
371
|
key={`page-chrome-${rect.pageId}`}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}}
|
|
445
|
-
>
|
|
446
|
-
{headerRegion && headerStory ? (
|
|
447
|
-
<TwPageHeaderBand
|
|
448
|
-
pageIndex={pageIndex}
|
|
449
|
-
blocks={headerBlocks}
|
|
450
|
-
topPx={px(layout.headerMargin ?? 720)}
|
|
451
|
-
leftPx={bandLeftPx}
|
|
452
|
-
widthPx={bandWidthPx}
|
|
453
|
-
bandHeightPx={px(headerRegion.heightTwips)}
|
|
454
|
-
isActiveSlot={isActiveStoryMatch(activeStory, headerStory)}
|
|
455
|
-
onClick={() => onOpenStory?.(headerStory)}
|
|
456
|
-
/>
|
|
457
|
-
) : null}
|
|
458
|
-
{footerRegion && footerStory ? (
|
|
459
|
-
<TwPageFooterBand
|
|
460
|
-
pageIndex={pageIndex}
|
|
461
|
-
blocks={footerBlocks}
|
|
462
|
-
bottomPx={px(layout.footerMargin ?? 720)}
|
|
463
|
-
leftPx={bandLeftPx}
|
|
464
|
-
widthPx={bandWidthPx}
|
|
465
|
-
bandHeightPx={px(footerRegion.heightTwips)}
|
|
466
|
-
isActiveSlot={isActiveStoryMatch(activeStory, footerStory)}
|
|
467
|
-
onClick={() => onOpenStory?.(footerStory)}
|
|
468
|
-
/>
|
|
469
|
-
) : null}
|
|
470
|
-
{footnoteRegion ? (
|
|
471
|
-
<TwFootnoteArea
|
|
472
|
-
pageIndex={pageIndex}
|
|
473
|
-
blocks={footnoteBlocks}
|
|
474
|
-
topPx={px(footnoteRegion.originTwips - layout.marginTop)}
|
|
475
|
-
leftPx={bandLeftPx}
|
|
476
|
-
widthPx={px(footnoteRegion.widthTwips)}
|
|
477
|
-
heightPx={px(footnoteRegion.heightTwips)}
|
|
478
|
-
/>
|
|
479
|
-
) : null}
|
|
480
|
-
</div>
|
|
372
|
+
rect={rect}
|
|
373
|
+
pageIndex={pageIndex}
|
|
374
|
+
page={page}
|
|
375
|
+
facet={facet}
|
|
376
|
+
activeStory={activeStory}
|
|
377
|
+
onOpenStory={onOpenStory}
|
|
378
|
+
visiblePageIndexRange={visiblePageIndexRange}
|
|
379
|
+
renderFrameRevision={renderFrameRevision}
|
|
380
|
+
/>
|
|
481
381
|
);
|
|
482
382
|
})}
|
|
483
383
|
<TwEndnoteArea blocks={endnoteBlocks} />
|
|
@@ -485,40 +385,4 @@ export const TwPageStackChromeLayer: React.FC<TwPageStackChromeLayerProps> = ({
|
|
|
485
385
|
);
|
|
486
386
|
};
|
|
487
387
|
|
|
488
|
-
/**
|
|
489
|
-
* Strict equality for two `EditorStoryTarget` values — used to decide
|
|
490
|
-
* whether a given band should render in active-slot mode.
|
|
491
|
-
*
|
|
492
|
-
* For `"main"` the kinds must match; for header/footer the triple
|
|
493
|
-
* `(relationshipId, variant, sectionIndex)` must match; for footnote /
|
|
494
|
-
* endnote the `noteId` must match. Any mismatch returns false.
|
|
495
|
-
*/
|
|
496
|
-
function isActiveStoryMatch(
|
|
497
|
-
active: EditorStoryTarget,
|
|
498
|
-
candidate: EditorStoryTarget,
|
|
499
|
-
): boolean {
|
|
500
|
-
if (active.kind !== candidate.kind) return false;
|
|
501
|
-
if (active.kind === "main" || candidate.kind === "main") {
|
|
502
|
-
return active.kind === candidate.kind;
|
|
503
|
-
}
|
|
504
|
-
if (active.kind === "footnote" && candidate.kind === "footnote") {
|
|
505
|
-
return active.noteId === candidate.noteId;
|
|
506
|
-
}
|
|
507
|
-
if (active.kind === "endnote" && candidate.kind === "endnote") {
|
|
508
|
-
return active.noteId === candidate.noteId;
|
|
509
|
-
}
|
|
510
|
-
// header / footer — triple match.
|
|
511
|
-
if (
|
|
512
|
-
(active.kind === "header" && candidate.kind === "header") ||
|
|
513
|
-
(active.kind === "footer" && candidate.kind === "footer")
|
|
514
|
-
) {
|
|
515
|
-
return (
|
|
516
|
-
active.relationshipId === candidate.relationshipId &&
|
|
517
|
-
active.variant === candidate.variant &&
|
|
518
|
-
active.sectionIndex === candidate.sectionIndex
|
|
519
|
-
);
|
|
520
|
-
}
|
|
521
|
-
return false;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
388
|
export default TwPageStackChromeLayer;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime chart-palette adapter.
|
|
3
|
+
*
|
|
4
|
+
* Reads live CSS variable values from the document root so that the palette
|
|
5
|
+
* automatically tracks light/dark mode and any host accent overrides applied
|
|
6
|
+
* at the `:root` level. No React dependency — pure module.
|
|
7
|
+
*
|
|
8
|
+
* See `docs/wiki/design-tokens.md` → "Chart palette" section.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const CATEGORICAL_COUNT = 8;
|
|
12
|
+
const SEQUENTIAL_COUNT = 6;
|
|
13
|
+
|
|
14
|
+
function cssVar(name: string): string {
|
|
15
|
+
return getComputedStyle(document.documentElement)
|
|
16
|
+
.getPropertyValue(name)
|
|
17
|
+
.trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Returns the CSS value for the categorical series slot at `index`.
|
|
22
|
+
* Wraps around after 8 slots (0-indexed).
|
|
23
|
+
*/
|
|
24
|
+
export function getCategoricalAt(index: number): string {
|
|
25
|
+
const slot = (((index % CATEGORICAL_COUNT) + CATEGORICAL_COUNT) % CATEGORICAL_COUNT) + 1;
|
|
26
|
+
return cssVar(`--color-chart-categorical-${slot}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns all 6 sequential ramp values in order (lightest → darkest in light
|
|
31
|
+
* mode; darkest → lightest in dark mode — always index 1..6).
|
|
32
|
+
*/
|
|
33
|
+
export function getSequentialRamp(): string[] {
|
|
34
|
+
return Array.from({ length: SEQUENTIAL_COUNT }, (_, i) =>
|
|
35
|
+
cssVar(`--color-chart-sequential-${i + 1}`),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns the five diverging scale stops. Keys match the token names so
|
|
41
|
+
* consumers can reference them by semantic intent.
|
|
42
|
+
*/
|
|
43
|
+
export function getDivergingScale(): {
|
|
44
|
+
negStrong: string;
|
|
45
|
+
neg: string;
|
|
46
|
+
neutral: string;
|
|
47
|
+
pos: string;
|
|
48
|
+
posStrong: string;
|
|
49
|
+
} {
|
|
50
|
+
return {
|
|
51
|
+
negStrong: cssVar("--color-chart-diverging-neg-strong"),
|
|
52
|
+
neg: cssVar("--color-chart-diverging-neg"),
|
|
53
|
+
neutral: cssVar("--color-chart-diverging-neutral"),
|
|
54
|
+
pos: cssVar("--color-chart-diverging-pos"),
|
|
55
|
+
posStrong: cssVar("--color-chart-diverging-pos-strong"),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
@import "tailwindcss";
|
|
17
|
+
@import "./tokens.css";
|
|
17
18
|
|
|
18
19
|
@theme {
|
|
19
20
|
/* Backgrounds */
|
|
@@ -32,9 +33,8 @@
|
|
|
32
33
|
--color-secondary: #6b6b6b;
|
|
33
34
|
--color-tertiary: #616161;
|
|
34
35
|
|
|
35
|
-
/* Accent */
|
|
36
|
-
--color-accent:
|
|
37
|
-
--color-accent-soft: rgba(24, 179, 148, 0.1);
|
|
36
|
+
/* Accent — 6a.S1 forest-green flip. Values resolve through tokens.css. */
|
|
37
|
+
--color-accent: var(--color-accent-primary);
|
|
38
38
|
--color-workflow: #7557d8;
|
|
39
39
|
--color-workflow-soft: rgba(117, 87, 216, 0.12);
|
|
40
40
|
|
|
@@ -123,8 +123,7 @@
|
|
|
123
123
|
* the .dark block below so the transform lives in one place.
|
|
124
124
|
*/
|
|
125
125
|
--shadow-hairline: 0 0 0 1px var(--color-border);
|
|
126
|
-
--shadow-soft
|
|
127
|
-
--shadow-float: 0 12px 28px -20px rgba(16, 24, 40, 0.18);
|
|
126
|
+
/* --shadow-soft / --shadow-float / --shadow-focus owned by tokens.css (§3.3/§3.4). */
|
|
128
127
|
|
|
129
128
|
/*
|
|
130
129
|
* Tailwind shadow-sm / shadow-md / shadow-lg / shadow-xl follow the runtime
|
|
@@ -170,26 +169,10 @@
|
|
|
170
169
|
--color-secondary: #A5B7AC;
|
|
171
170
|
--color-tertiary: #7F9187;
|
|
172
171
|
|
|
173
|
-
|
|
174
|
-
--color-accent-soft: rgba(83, 180, 135, 0.16);
|
|
172
|
+
/* Accent / semantic / change / comment dark values owned by tokens.css. */
|
|
175
173
|
--color-workflow: #c7b6ff;
|
|
176
174
|
--color-workflow-soft: rgba(199, 182, 255, 0.16);
|
|
177
175
|
|
|
178
|
-
--color-comment: #c7b6ff;
|
|
179
|
-
--color-comment-soft: rgba(199, 182, 255, 0.18);
|
|
180
|
-
--color-comment-strong: rgba(199, 182, 255, 0.24);
|
|
181
|
-
--color-insert: #8fd2a9;
|
|
182
|
-
--color-insert-soft: rgba(143, 210, 169, 0.18);
|
|
183
|
-
--color-delete: #d78d84;
|
|
184
|
-
--color-delete-soft: rgba(215, 141, 132, 0.14);
|
|
185
|
-
|
|
186
|
-
--color-warning: #c7b6ff;
|
|
187
|
-
--color-warning-soft: rgba(199, 182, 255, 0.16);
|
|
188
|
-
--color-danger: #d78d84;
|
|
189
|
-
--color-danger-soft: rgba(215, 141, 132, 0.16);
|
|
190
|
-
--color-success: #8fd2a9;
|
|
191
|
-
--color-success-soft: rgba(143, 210, 169, 0.18);
|
|
192
|
-
|
|
193
176
|
--color-border: rgba(255, 255, 255, 0.09);
|
|
194
177
|
--color-border-strong: rgba(255, 255, 255, 0.16);
|
|
195
178
|
|
|
@@ -202,8 +185,7 @@
|
|
|
202
185
|
--color-page-ruler: color-mix(in srgb, var(--color-border) 70%, transparent);
|
|
203
186
|
--color-workspace-canvas: #111827;
|
|
204
187
|
|
|
205
|
-
--shadow-soft
|
|
206
|
-
--shadow-float: 0 18px 40px -22px rgba(0, 0, 0, 0.7);
|
|
188
|
+
/* --shadow-soft / --shadow-float / --shadow-focus owned by tokens.css. */
|
|
207
189
|
}
|
|
208
190
|
|
|
209
191
|
/*
|
|
@@ -509,6 +491,26 @@
|
|
|
509
491
|
background: color-mix(in srgb, var(--color-danger) 14%, transparent);
|
|
510
492
|
}
|
|
511
493
|
|
|
494
|
+
/* §3.7 canonical scope families */
|
|
495
|
+
.wre-scope-rail-tint-blocked {
|
|
496
|
+
background: var(--color-scope-tint-blocked);
|
|
497
|
+
}
|
|
498
|
+
.wre-scope-rail-tint-in-scope {
|
|
499
|
+
background: var(--color-scope-tint-in-scope);
|
|
500
|
+
}
|
|
501
|
+
.wre-scope-rail-tint-suggest {
|
|
502
|
+
background: var(--color-scope-tint-suggest);
|
|
503
|
+
}
|
|
504
|
+
.wre-scope-rail-tint-comment {
|
|
505
|
+
background: var(--color-scope-tint-comment);
|
|
506
|
+
}
|
|
507
|
+
.wre-scope-rail-tint-scheduled {
|
|
508
|
+
background: var(--color-scope-tint-scheduled);
|
|
509
|
+
}
|
|
510
|
+
.wre-scope-rail-tint-proposed {
|
|
511
|
+
background: var(--color-scope-tint-proposed);
|
|
512
|
+
}
|
|
513
|
+
|
|
512
514
|
.wre-scope-rail-tint-active {
|
|
513
515
|
outline: 1px solid color-mix(in srgb, var(--color-accent) 40%, transparent);
|
|
514
516
|
outline-offset: -1px;
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @beyondwork/docx-react-component — canonical design tokens
|
|
3
|
+
*
|
|
4
|
+
* Source of truth for every color, shadow, radius, space, and motion value
|
|
5
|
+
* consumed by the chrome and document surface. Values are copied verbatim
|
|
6
|
+
* from `docs/reference/designsystem.md` §10 (starter CSS). Any hex change
|
|
7
|
+
* happens HERE and in `tokens.ts` — never in a component file.
|
|
8
|
+
*
|
|
9
|
+
* Two-layer model:
|
|
10
|
+
* 1. Product names (TypeScript) — `BRAND_TOKENS.color.accent.primary`
|
|
11
|
+
* 2. CSS variables (this file) — `var(--color-accent-primary)`
|
|
12
|
+
*
|
|
13
|
+
* See `docs/wiki/design-tokens.md` for narrative + eviction policy.
|
|
14
|
+
*
|
|
15
|
+
* Host overrides:
|
|
16
|
+
* Allowed — accent family, `--color-bg-app`, `--radius-*`, `--motion-*`
|
|
17
|
+
* Locked — semantic, change, comment, canvas, focus-ring
|
|
18
|
+
* See `docs/reference/designsystem.md` §8.5 + §9.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
:root {
|
|
22
|
+
/* Backgrounds */
|
|
23
|
+
--color-bg-app: #F4F7F5;
|
|
24
|
+
--color-bg-chrome: #FAFCFA;
|
|
25
|
+
--color-bg-sidebar: #F1F6F2;
|
|
26
|
+
--color-bg-canvas: #FFFFFF;
|
|
27
|
+
--color-bg-elevated: #FFFFFF;
|
|
28
|
+
--color-bg-hover: #EAF6EF;
|
|
29
|
+
--color-bg-selected: #E2F2E8;
|
|
30
|
+
--color-bg-muted: #F7FAF8;
|
|
31
|
+
--color-bg-overlay: rgba(21, 26, 23, 0.08);
|
|
32
|
+
|
|
33
|
+
/* Borders */
|
|
34
|
+
--color-border-subtle: #E2EAE4;
|
|
35
|
+
--color-border-default: #D3DED6;
|
|
36
|
+
--color-border-strong: #BECDBF;
|
|
37
|
+
--color-border-accent: #8FC9AD;
|
|
38
|
+
|
|
39
|
+
/* Text */
|
|
40
|
+
--color-text-primary: #151A17;
|
|
41
|
+
--color-text-secondary: #5E6D63;
|
|
42
|
+
--color-text-tertiary: #8A978F;
|
|
43
|
+
--color-text-quiet: #A4AEA8;
|
|
44
|
+
--color-text-inverse: #F7FAF8;
|
|
45
|
+
--color-text-on-accent: #F7FAF8;
|
|
46
|
+
--color-text-on-soft-accent: #18563F;
|
|
47
|
+
|
|
48
|
+
/* Accent (host-overridable) */
|
|
49
|
+
--color-accent-primary: #1F6B4F;
|
|
50
|
+
--color-accent-primary-hover: #18563F;
|
|
51
|
+
--color-accent-primary-active: #124432;
|
|
52
|
+
--color-accent-secondary: #72D6AE;
|
|
53
|
+
--color-accent-secondary-hover: #5FC79C;
|
|
54
|
+
--color-accent-secondary-active: #49B785;
|
|
55
|
+
--color-accent-soft: #DDF1E4;
|
|
56
|
+
--color-accent-soft-hover: #CEEAD8;
|
|
57
|
+
|
|
58
|
+
/* Semantic (locked) */
|
|
59
|
+
--color-semantic-success: #1F8A5B;
|
|
60
|
+
--color-semantic-success-soft: #DDF3E8;
|
|
61
|
+
--color-semantic-warning: #D58B1E;
|
|
62
|
+
--color-semantic-warning-soft: #FBEFD8;
|
|
63
|
+
--color-semantic-error: #D95C67;
|
|
64
|
+
--color-semantic-error-soft: #FBE3E6;
|
|
65
|
+
--color-semantic-info: #2F8FCE;
|
|
66
|
+
--color-semantic-info-soft: #DCEFFC;
|
|
67
|
+
|
|
68
|
+
/* Field */
|
|
69
|
+
--color-field-fill: #F6FAF7;
|
|
70
|
+
--color-field-editable: #EEF8F0;
|
|
71
|
+
--color-field-focus: #DDF1E4;
|
|
72
|
+
--color-field-invalid: #FBE3E6;
|
|
73
|
+
--color-field-warning: #FBEFD8;
|
|
74
|
+
|
|
75
|
+
/* Status */
|
|
76
|
+
--color-status-ready: #1F8A5B;
|
|
77
|
+
--color-status-in-progress: #2F8FCE;
|
|
78
|
+
--color-status-paused: #8A978F;
|
|
79
|
+
--color-status-blocked: #D95C67;
|
|
80
|
+
--color-status-review: #1F6B4F;
|
|
81
|
+
--color-status-draft: #72907E;
|
|
82
|
+
|
|
83
|
+
/* Comment (locked) */
|
|
84
|
+
--color-comment-marker: #1F6B4F;
|
|
85
|
+
--color-comment-marker-hover: #18563F;
|
|
86
|
+
--color-comment-thread-bg: #F3FAF6;
|
|
87
|
+
|
|
88
|
+
/* Change (locked) */
|
|
89
|
+
--color-change-insertion: #DDF3E8;
|
|
90
|
+
--color-change-deletion: #FBE3E6;
|
|
91
|
+
--color-change-comment: #E8F4EC;
|
|
92
|
+
--color-change-selection: #DDF1E4;
|
|
93
|
+
|
|
94
|
+
/* Chart — categorical */
|
|
95
|
+
--color-chart-categorical-1: #1F6B4F;
|
|
96
|
+
--color-chart-categorical-2: #72D6AE;
|
|
97
|
+
--color-chart-categorical-3: #2F8FCE;
|
|
98
|
+
--color-chart-categorical-4: #D58B1E;
|
|
99
|
+
--color-chart-categorical-5: #7A6AF0;
|
|
100
|
+
--color-chart-categorical-6: #D95C67;
|
|
101
|
+
--color-chart-categorical-7: #5E8E7A;
|
|
102
|
+
--color-chart-categorical-8: #A7D9C1;
|
|
103
|
+
|
|
104
|
+
/* Chart — sequential */
|
|
105
|
+
--color-chart-sequential-1: #EAF6EF;
|
|
106
|
+
--color-chart-sequential-2: #D4EEDD;
|
|
107
|
+
--color-chart-sequential-3: #B4DFC8;
|
|
108
|
+
--color-chart-sequential-4: #8FC9AD;
|
|
109
|
+
--color-chart-sequential-5: #5FA985;
|
|
110
|
+
--color-chart-sequential-6: #1F6B4F;
|
|
111
|
+
|
|
112
|
+
/* Chart — diverging */
|
|
113
|
+
--color-chart-diverging-neg-strong: #C94B57;
|
|
114
|
+
--color-chart-diverging-neg: #E9979F;
|
|
115
|
+
--color-chart-diverging-neutral: #E9EFEA;
|
|
116
|
+
--color-chart-diverging-pos: #97D1B3;
|
|
117
|
+
--color-chart-diverging-pos-strong: #1F6B4F;
|
|
118
|
+
|
|
119
|
+
/* Scope tints (§3.7.1) */
|
|
120
|
+
--color-scope-tint-blocked: #FBE3E6;
|
|
121
|
+
--color-scope-tint-in-scope: #E2F2E8;
|
|
122
|
+
--color-scope-tint-suggest: #FBEFD8;
|
|
123
|
+
--color-scope-tint-comment: #F3FAF6;
|
|
124
|
+
--color-scope-tint-scheduled: #DCEFFC;
|
|
125
|
+
--color-scope-tint-proposed: #EAF6EF;
|
|
126
|
+
|
|
127
|
+
/* Shadows */
|
|
128
|
+
--shadow-soft: 0 6px 20px rgba(21, 26, 23, 0.06);
|
|
129
|
+
--shadow-float: 0 12px 32px rgba(21, 26, 23, 0.12);
|
|
130
|
+
--shadow-focus: 0 0 0 3px rgba(114, 214, 174, 0.28);
|
|
131
|
+
|
|
132
|
+
/* Radius (§4.3) */
|
|
133
|
+
--radius-sm: 10px;
|
|
134
|
+
--radius-md: 12px;
|
|
135
|
+
--radius-lg: 14px;
|
|
136
|
+
--radius-xl: 16px;
|
|
137
|
+
--radius-pill: 9999px;
|
|
138
|
+
|
|
139
|
+
/* Spacing (4px base) */
|
|
140
|
+
--space-1: 4px;
|
|
141
|
+
--space-2: 8px;
|
|
142
|
+
--space-3: 12px;
|
|
143
|
+
--space-4: 16px;
|
|
144
|
+
--space-5: 20px;
|
|
145
|
+
--space-6: 24px;
|
|
146
|
+
--space-8: 32px;
|
|
147
|
+
--space-10: 40px;
|
|
148
|
+
--space-12: 48px;
|
|
149
|
+
--space-16: 64px;
|
|
150
|
+
|
|
151
|
+
/* Motion (host-overridable) */
|
|
152
|
+
--motion-fast: 120ms;
|
|
153
|
+
--motion-default: 160ms;
|
|
154
|
+
--motion-slow: 220ms;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/*
|
|
158
|
+
* Dark palette (designsystem §3.4).
|
|
159
|
+
*
|
|
160
|
+
* Canonical selector is `[data-theme="dark"]`; `.dark` class is retained
|
|
161
|
+
* as a compat selector for one release cycle (existing harness markup
|
|
162
|
+
* uses it alongside the attribute). Remove `.dark` after an explicit
|
|
163
|
+
* consumer audit.
|
|
164
|
+
*/
|
|
165
|
+
[data-theme="dark"],
|
|
166
|
+
.dark {
|
|
167
|
+
/* Backgrounds */
|
|
168
|
+
--color-bg-app: #0E1411;
|
|
169
|
+
--color-bg-chrome: #131B17;
|
|
170
|
+
--color-bg-sidebar: #16211B;
|
|
171
|
+
--color-bg-canvas: #1B2620;
|
|
172
|
+
--color-bg-elevated: #202E27;
|
|
173
|
+
--color-bg-hover: #21342A;
|
|
174
|
+
--color-bg-selected: #274234;
|
|
175
|
+
--color-bg-muted: #17211C;
|
|
176
|
+
--color-bg-overlay: rgba(0, 0, 0, 0.32);
|
|
177
|
+
|
|
178
|
+
/* Borders */
|
|
179
|
+
--color-border-subtle: #26352C;
|
|
180
|
+
--color-border-default: #32463A;
|
|
181
|
+
--color-border-strong: #405847;
|
|
182
|
+
--color-border-accent: #4F8E70;
|
|
183
|
+
|
|
184
|
+
/* Text */
|
|
185
|
+
--color-text-primary: #EFF7F2;
|
|
186
|
+
--color-text-secondary: #A5B7AC;
|
|
187
|
+
--color-text-tertiary: #7F9187;
|
|
188
|
+
--color-text-quiet: #67786F;
|
|
189
|
+
--color-text-inverse: #111613;
|
|
190
|
+
--color-text-on-accent: #0F1713;
|
|
191
|
+
--color-text-on-soft-accent: #DDF7E9;
|
|
192
|
+
|
|
193
|
+
/* Accent */
|
|
194
|
+
--color-accent-primary: #53B487;
|
|
195
|
+
--color-accent-primary-hover: #69C598;
|
|
196
|
+
--color-accent-primary-active: #84D8AE;
|
|
197
|
+
--color-accent-secondary: #9AE7C7;
|
|
198
|
+
--color-accent-secondary-hover: #B2F0D5;
|
|
199
|
+
--color-accent-secondary-active: #C7F6E0;
|
|
200
|
+
--color-accent-soft: #294235;
|
|
201
|
+
--color-accent-soft-hover: #31503F;
|
|
202
|
+
|
|
203
|
+
/* Semantic */
|
|
204
|
+
--color-semantic-success: #45C787;
|
|
205
|
+
--color-semantic-success-soft: #1E3A2C;
|
|
206
|
+
--color-semantic-warning: #E7B04D;
|
|
207
|
+
--color-semantic-warning-soft: #3E3117;
|
|
208
|
+
--color-semantic-error: #F07A84;
|
|
209
|
+
--color-semantic-error-soft: #3D2024;
|
|
210
|
+
--color-semantic-info: #64B6E8;
|
|
211
|
+
--color-semantic-info-soft: #183444;
|
|
212
|
+
|
|
213
|
+
/* Field */
|
|
214
|
+
--color-field-fill: #202D25;
|
|
215
|
+
--color-field-editable: #23372B;
|
|
216
|
+
--color-field-focus: #294235;
|
|
217
|
+
--color-field-invalid: #3D2024;
|
|
218
|
+
--color-field-warning: #3E3117;
|
|
219
|
+
|
|
220
|
+
/* Status */
|
|
221
|
+
--color-status-ready: #45C787;
|
|
222
|
+
--color-status-in-progress: #64B6E8;
|
|
223
|
+
--color-status-paused: #7F9187;
|
|
224
|
+
--color-status-blocked: #F07A84;
|
|
225
|
+
--color-status-review: #53B487;
|
|
226
|
+
--color-status-draft: #7DA38F;
|
|
227
|
+
|
|
228
|
+
/* Comment */
|
|
229
|
+
--color-comment-marker: #53B487;
|
|
230
|
+
--color-comment-marker-hover: #69C598;
|
|
231
|
+
--color-comment-thread-bg: #1A2A22;
|
|
232
|
+
|
|
233
|
+
/* Change */
|
|
234
|
+
--color-change-insertion: #1E3A2C;
|
|
235
|
+
--color-change-deletion: #3D2024;
|
|
236
|
+
--color-change-comment: #21342A;
|
|
237
|
+
--color-change-selection: #294235;
|
|
238
|
+
|
|
239
|
+
/* Chart — categorical */
|
|
240
|
+
--color-chart-categorical-1: #53B487;
|
|
241
|
+
--color-chart-categorical-2: #9AE7C7;
|
|
242
|
+
--color-chart-categorical-3: #64B6E8;
|
|
243
|
+
--color-chart-categorical-4: #E7B04D;
|
|
244
|
+
--color-chart-categorical-5: #A996FF;
|
|
245
|
+
--color-chart-categorical-6: #F07A84;
|
|
246
|
+
--color-chart-categorical-7: #7DA38F;
|
|
247
|
+
--color-chart-categorical-8: #355746;
|
|
248
|
+
|
|
249
|
+
/* Chart — sequential */
|
|
250
|
+
--color-chart-sequential-1: #16211B;
|
|
251
|
+
--color-chart-sequential-2: #1D2E25;
|
|
252
|
+
--color-chart-sequential-3: #274234;
|
|
253
|
+
--color-chart-sequential-4: #35654F;
|
|
254
|
+
--color-chart-sequential-5: #53B487;
|
|
255
|
+
--color-chart-sequential-6: #9AE7C7;
|
|
256
|
+
|
|
257
|
+
/* Chart — diverging */
|
|
258
|
+
--color-chart-diverging-neg-strong: #F07A84;
|
|
259
|
+
--color-chart-diverging-neg: #C76069;
|
|
260
|
+
--color-chart-diverging-neutral: #2A3530;
|
|
261
|
+
--color-chart-diverging-pos: #69C598;
|
|
262
|
+
--color-chart-diverging-pos-strong: #9AE7C7;
|
|
263
|
+
|
|
264
|
+
/* Scope tints (§3.7.2) */
|
|
265
|
+
--color-scope-tint-blocked: #3D2024;
|
|
266
|
+
--color-scope-tint-in-scope: #274234;
|
|
267
|
+
--color-scope-tint-suggest: #3E3117;
|
|
268
|
+
--color-scope-tint-comment: #1A2A22;
|
|
269
|
+
--color-scope-tint-scheduled: #183444;
|
|
270
|
+
--color-scope-tint-proposed: #21342A;
|
|
271
|
+
|
|
272
|
+
/* Shadows */
|
|
273
|
+
--shadow-soft: 0 8px 24px rgba(0, 0, 0, 0.28);
|
|
274
|
+
--shadow-float: 0 16px 40px rgba(0, 0, 0, 0.4);
|
|
275
|
+
--shadow-focus: 0 0 0 3px rgba(154, 231, 199, 0.22);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/*
|
|
279
|
+
* Reduced-motion contract (designsystem §4.6 / §7.3).
|
|
280
|
+
* Collapses every motion token so any transition consuming `var(--motion-*)`
|
|
281
|
+
* becomes functionally instant. Components MUST read these tokens — never
|
|
282
|
+
* hardcode a numeric duration.
|
|
283
|
+
*/
|
|
284
|
+
@media (prefers-reduced-motion: reduce) {
|
|
285
|
+
:root {
|
|
286
|
+
--motion-fast: 1ms;
|
|
287
|
+
--motion-default: 1ms;
|
|
288
|
+
--motion-slow: 1ms;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/*
|
|
293
|
+
* Density scale (designsystem §4.2 / Lane 6b.U5 consumer wiring).
|
|
294
|
+
*
|
|
295
|
+
* Components multiply spacing by `--space-density-multiplier`.
|
|
296
|
+
* Standard (1.0) is the default; compact (0.85) and comfortable (1.15)
|
|
297
|
+
* are opt-in via `data-density` on the root element.
|
|
298
|
+
* The hook `use-density.ts` reads and writes this attribute.
|
|
299
|
+
*/
|
|
300
|
+
:root {
|
|
301
|
+
--space-density-multiplier: 1;
|
|
302
|
+
}
|
|
303
|
+
:root[data-density="compact"] {
|
|
304
|
+
--space-density-multiplier: 0.85;
|
|
305
|
+
}
|
|
306
|
+
:root[data-density="standard"] {
|
|
307
|
+
--space-density-multiplier: 1;
|
|
308
|
+
}
|
|
309
|
+
:root[data-density="comfortable"] {
|
|
310
|
+
--space-density-multiplier: 1.15;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/*
|
|
314
|
+
* Back-compat aliases (temporary — remove after full consumer sweep).
|
|
315
|
+
*
|
|
316
|
+
* These bind pre-6a names to their post-6a equivalents so that the
|
|
317
|
+
* existing @theme {} block in editor-theme.css and already-shipped
|
|
318
|
+
* component markup continue to resolve during the phased migration.
|
|
319
|
+
*/
|
|
320
|
+
:root {
|
|
321
|
+
/* Legacy accent seed (was teal) → forest-green primary family */
|
|
322
|
+
--color-accent: var(--color-accent-primary);
|
|
323
|
+
/* Legacy single-name semantic tokens → canonical semantic family */
|
|
324
|
+
--color-danger: var(--color-semantic-error);
|
|
325
|
+
--color-danger-soft: var(--color-semantic-error-soft);
|
|
326
|
+
--color-warning: var(--color-semantic-warning);
|
|
327
|
+
--color-warning-soft: var(--color-semantic-warning-soft);
|
|
328
|
+
--color-success: var(--color-semantic-success);
|
|
329
|
+
--color-success-soft: var(--color-semantic-success-soft);
|
|
330
|
+
--color-info: var(--color-semantic-info);
|
|
331
|
+
--color-info-soft: var(--color-semantic-info-soft);
|
|
332
|
+
/* Legacy review markup names → change family */
|
|
333
|
+
--color-insert: var(--color-accent-primary);
|
|
334
|
+
--color-insert-soft: var(--color-change-insertion);
|
|
335
|
+
--color-delete: var(--color-semantic-error);
|
|
336
|
+
--color-delete-soft: var(--color-change-deletion);
|
|
337
|
+
--color-comment: var(--color-comment-marker);
|
|
338
|
+
--color-comment-soft: var(--color-change-comment);
|
|
339
|
+
--color-comment-strong: var(--color-comment-marker-hover);
|
|
340
|
+
/* Legacy L8 Phase A radius names → §4.3 scale */
|
|
341
|
+
--radius-panel: var(--radius-md);
|
|
342
|
+
--radius-card: var(--radius-sm);
|
|
343
|
+
--radius-control: var(--radius-sm);
|
|
344
|
+
--radius-page: 2px;
|
|
345
|
+
}
|