@bison-lab/payload-core 3.21.0 → 3.24.0

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/admin.mjs CHANGED
@@ -4,6 +4,8 @@ import { ArrayField, Button, CheckboxInput, FieldDescription, FieldError, FieldL
4
4
  import { GREY_SCALES, SHADE_STEPS, contrastForeground, contrastRatio, createColorScale, deriveDarkPalette, deriveLightPalette, hexToHSL, hslToString, includedShadeSteps, isThemeHex, presetHints, setColorScaleInclude } from "@bison-lab/tokens";
5
5
  import { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { Badge, Dialog, Field, Input, KitProvider, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@bison-lab/admin-ui";
8
+ import { HexColorPicker } from "react-colorful";
7
9
  import { createPortal } from "react-dom";
8
10
  import { findFont, fontFaceCss, isFontId } from "@bison-lab/fonts";
9
11
  //#region src/admin/color-field.tsx
@@ -41,7 +43,7 @@ const ColorField = ({ field, path, readOnly }) => {
41
43
  /* @__PURE__ */ jsx("style", {
42
44
  href: "bl-color-field",
43
45
  precedence: "default",
44
- children: CSS$4
46
+ children: CSS$5
45
47
  }),
46
48
  /* @__PURE__ */ jsx(FieldLabel, {
47
49
  htmlFor: hexId,
@@ -100,7 +102,7 @@ const ColorField = ({ field, path, readOnly }) => {
100
102
  ]
101
103
  });
102
104
  };
103
- const CSS$4 = `
105
+ const CSS$5 = `
104
106
  .bl-color-field__control{display:flex;align-items:center;gap:calc(var(--base) * .4)}
105
107
  .bl-color-field__swatch{flex:none;width:calc(var(--base) * 1.6);height:calc(var(--base) * 1.6);border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-elevation-50)}
106
108
  .bl-color-field__picker{flex:none;width:calc(var(--base) * 2);height:calc(var(--base) * 2);padding:0;border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:transparent;cursor:pointer}
@@ -345,6 +347,123 @@ function readabilityRatioLine(sample, target = 7) {
345
347
  const READABILITY_FIX = "Darken or lighten the hex, then regenerate the scale. The site picks light or dark type for you.";
346
348
  const READABILITY_PUBLISH_NOTE = "You can still publish. To improve a color, darken or lighten it and regenerate.";
347
349
  //#endregion
350
+ //#region src/admin/portal.tsx
351
+ /** Theme overlays must leave Payload's transformed/clipped admin tree. */
352
+ function ThemePortal({ children }) {
353
+ if (typeof document === "undefined") return null;
354
+ return createPortal(children, document.body);
355
+ }
356
+ //#endregion
357
+ //#region src/admin/brand-hex-field.tsx
358
+ /** Keep a leading # and at most six hex digits. Drop everything else. */
359
+ function filterThemeHexInput(raw) {
360
+ const trimmed = raw.trim();
361
+ if (trimmed === "") return "";
362
+ return `#${trimmed.replace(/^#/, "").replace(/[^0-9a-fA-F]/g, "").slice(0, 6)}`;
363
+ }
364
+ function BrandHexField({ name, value, onChange, readOnly, placeholder = "#DB0082", picker = "dialog" }) {
365
+ const [draft, setDraft] = useState(value);
366
+ const [open, setOpen] = useState(false);
367
+ const [pickerDraft, setPickerDraft] = useState(value);
368
+ useEffect(() => {
369
+ setDraft(value);
370
+ }, [value]);
371
+ function typeHex(next) {
372
+ const filtered = filterThemeHexInput(next);
373
+ setDraft(filtered);
374
+ if (isThemeHex(filtered)) onChange(filtered);
375
+ }
376
+ function openPicker() {
377
+ setPickerDraft(isThemeHex(draft) ? draft : value);
378
+ setOpen(true);
379
+ }
380
+ function applyPicker() {
381
+ if (!isThemeHex(pickerDraft)) return;
382
+ onChange(pickerDraft);
383
+ setDraft(pickerDraft);
384
+ setOpen(false);
385
+ }
386
+ const input = /* @__PURE__ */ jsx(Input, {
387
+ "aria-label": `${name} hex`,
388
+ value: draft,
389
+ placeholder,
390
+ spellCheck: false,
391
+ autoComplete: "off",
392
+ disabled: readOnly,
393
+ onChange: (event) => typeHex(event.target.value),
394
+ onBlur: () => {
395
+ if (!isThemeHex(draft)) setDraft(value);
396
+ }
397
+ });
398
+ return /* @__PURE__ */ jsxs(KitProvider, { children: [
399
+ /* @__PURE__ */ jsx("style", {
400
+ href: "bl-brand-hex",
401
+ precedence: "default",
402
+ children: CSS$4
403
+ }),
404
+ picker === "inline" ? /* @__PURE__ */ jsxs("div", {
405
+ className: "bl-brand-hex bl-brand-hex--inline",
406
+ children: [/* @__PURE__ */ jsx(HexColorPicker, {
407
+ color: isThemeHex(draft) ? draft : "#000000",
408
+ onChange: (hex) => {
409
+ setDraft(hex);
410
+ onChange(hex);
411
+ }
412
+ }), /* @__PURE__ */ jsxs(Field, {
413
+ as: "div",
414
+ children: [/* @__PURE__ */ jsx(Label, { children: "Hex" }), input]
415
+ })]
416
+ }) : /* @__PURE__ */ jsxs("div", {
417
+ className: "bl-brand-hex",
418
+ children: [/* @__PURE__ */ jsx("button", {
419
+ type: "button",
420
+ className: "bl-brand-hex__swatch",
421
+ "aria-label": `${name} picker`,
422
+ disabled: readOnly,
423
+ style: { background: isThemeHex(draft) ? draft : "transparent" },
424
+ onClick: openPicker
425
+ }), input]
426
+ }),
427
+ picker === "dialog" ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
428
+ className: "bl-theme-dialog",
429
+ children: /* @__PURE__ */ jsx(Dialog, {
430
+ open,
431
+ title: `Pick ${name}`,
432
+ onCancel: () => setOpen(false),
433
+ confirmLabel: "Apply",
434
+ onConfirm: applyPicker,
435
+ confirmDisabled: !isThemeHex(pickerDraft),
436
+ children: /* @__PURE__ */ jsxs("div", {
437
+ className: "bl-brand-hex bl-brand-hex--inline",
438
+ children: [/* @__PURE__ */ jsx(HexColorPicker, {
439
+ color: isThemeHex(pickerDraft) ? pickerDraft : "#000000",
440
+ onChange: setPickerDraft
441
+ }), /* @__PURE__ */ jsxs(Field, {
442
+ as: "div",
443
+ children: [/* @__PURE__ */ jsx(Label, { children: "Hex" }), /* @__PURE__ */ jsx(Input, {
444
+ "aria-label": `${name} picker hex`,
445
+ value: pickerDraft,
446
+ placeholder,
447
+ spellCheck: false,
448
+ autoComplete: "off",
449
+ onChange: (event) => setPickerDraft(filterThemeHexInput(event.target.value))
450
+ })]
451
+ })]
452
+ })
453
+ })
454
+ }) }) : null
455
+ ] });
456
+ }
457
+ const CSS$4 = `
458
+ .bl-brand-hex{display:flex;align-items:stretch;gap:8px;min-width:0}
459
+ .bl-brand-hex--inline{flex-direction:column;gap:12px}
460
+ .bl-brand-hex .react-colorful{width:100%;height:200px}
461
+ .bl-brand-hex__swatch{flex:none;width:38px;border:1px solid #3a3d46;border-radius:8px;padding:0;cursor:pointer;background:#1d1f24}
462
+ .bl-brand-hex__swatch:disabled{opacity:.5;cursor:not-allowed}
463
+ .bl-brand-hex .bl-nav-kit__input{font-family:var(--font-mono,ui-monospace,monospace)}
464
+ .bl-theme-dialog .bl-nav-kit__modal{z-index:10000}
465
+ `;
466
+ //#endregion
348
467
  //#region src/admin/colors-layout.ts
349
468
  /**
350
469
  * Theme Colors tab chrome. Payload group-in-group draws a left gutter;
@@ -386,13 +505,6 @@ const THEME_COLORS_LAYOUT_CSS = `
386
505
  }
387
506
  `;
388
507
  //#endregion
389
- //#region src/admin/portal.tsx
390
- /** Theme overlays must leave Payload's transformed/clipped admin tree. */
391
- function ThemePortal({ children }) {
392
- if (typeof document === "undefined") return null;
393
- return createPortal(children, document.body);
394
- }
395
- //#endregion
396
508
  //#region src/admin/preview-mode.tsx
397
509
  const ATTR = "data-bl-theme-preview";
398
510
  const EVENT = "bl-theme-preview";
@@ -410,7 +522,11 @@ const PREVIEW_BRAND = {
410
522
  secondary: "#111111",
411
523
  success: "#111111"
412
524
  };
413
- let currentMode = "light";
525
+ function readDocumentTheme() {
526
+ if (typeof document === "undefined") return "light";
527
+ return document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light";
528
+ }
529
+ let currentMode = readDocumentTheme();
414
530
  function readMode() {
415
531
  return currentMode;
416
532
  }
@@ -450,7 +566,10 @@ function previewVarsFor(grey, mode) {
450
566
  "--bl-preview-border": `hsl(${palette.border})`,
451
567
  "--bl-preview-text": `hsl(${palette.foreground})`,
452
568
  "--bl-preview-muted": `hsl(${palette["muted-foreground"]})`,
453
- "--bl-preview-input": `hsl(${palette.input})`
569
+ "--bl-preview-input": `hsl(${palette.input})`,
570
+ "--theme-elevation-0": `hsl(${palette.card})`,
571
+ "--theme-elevation-150": `hsl(${palette.border})`,
572
+ "--theme-elevation-800": `hsl(${palette.foreground})`
454
573
  };
455
574
  }
456
575
  function useGreyScale() {
@@ -471,30 +590,6 @@ function usePreviewCanvas() {
471
590
  style: previewVarsFor(useGreyScale(), mode)
472
591
  };
473
592
  }
474
- function ThemePreviewToggle() {
475
- const mode = useThemePreviewMode();
476
- return /* @__PURE__ */ jsxs("div", {
477
- className: "bl-preview-toggle",
478
- role: "group",
479
- "aria-label": "Preview theme in",
480
- children: [/* @__PURE__ */ jsx("button", {
481
- type: "button",
482
- "data-on": mode === "light" ? "" : void 0,
483
- onClick: () => setThemePreviewMode("light"),
484
- children: "Light"
485
- }), /* @__PURE__ */ jsx("button", {
486
- type: "button",
487
- "data-on": mode === "dark" ? "" : void 0,
488
- onClick: () => setThemePreviewMode("dark"),
489
- children: "Dark"
490
- })]
491
- });
492
- }
493
- const THEME_PREVIEW_TOGGLE_CSS = `
494
- .bl-preview-toggle{display:inline-flex;padding:3px;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:10px;background:var(--theme-elevation-0,#fff)}
495
- .bl-preview-toggle button{min-height:2rem;padding:.25rem .75rem;border:0;border-radius:7px;background:transparent;color:var(--theme-elevation-600,#475569);font:inherit;font-size:13px;font-weight:600;cursor:pointer}
496
- .bl-preview-toggle button[data-on]{background:var(--theme-text,#0f172a);color:var(--theme-bg,#fff)}
497
- `;
498
593
  //#endregion
499
594
  //#region src/admin/readability-list.tsx
500
595
  function ReadabilityDetail({ item, target = 7 }) {
@@ -614,13 +709,9 @@ function ColorScaleCard({ id, name, hint, required, custom, state, onChange, onD
614
709
  const canvas = usePreviewCanvas();
615
710
  const [attentionOpen, setAttentionOpen] = useState(false);
616
711
  const [shakeStep, setShakeStep] = useState(null);
617
- const [hexDraft, setHexDraft] = useState(state.hex);
618
712
  const titleId = useId();
619
713
  const included = new Set(includedShadeSteps(state));
620
714
  const hueDrift = role === "success" ? Boolean(successHueWarning(state.hex)) : role === "destructive" ? Boolean(destructiveHueWarning(state.hex)) : false;
621
- useEffect(() => {
622
- setHexDraft(state.hex);
623
- }, [state.hex]);
624
715
  function commitHex(hex) {
625
716
  onChange(createColorScale(hex, state.sourceStep, state.include));
626
717
  }
@@ -638,211 +729,182 @@ function ColorScaleCard({ id, name, hint, required, custom, state, onChange, onD
638
729
  else next.add(step);
639
730
  onChange(setColorScaleInclude(state, SHADE_STEPS.filter((item) => next.has(item))));
640
731
  }
641
- return /* @__PURE__ */ jsxs("article", {
642
- className: `bl-scale-card ${canvas.className}`,
643
- "data-preview": canvas.mode,
644
- style: canvas.style,
645
- children: [
646
- /* @__PURE__ */ jsxs("header", {
647
- className: "bl-scale-card__head",
648
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
649
- className: "bl-scale-card__title-row",
650
- children: [
651
- /* @__PURE__ */ jsx("h3", {
652
- className: "bl-scale-card__title",
653
- children: name
732
+ return /* @__PURE__ */ jsx(KitProvider, {
733
+ accent: id === "primary" && isThemeHex(state.hex) ? state.hex : void 0,
734
+ children: /* @__PURE__ */ jsxs("article", {
735
+ className: `bl-scale-card ${canvas.className}`,
736
+ "data-preview": canvas.mode,
737
+ style: canvas.style,
738
+ children: [
739
+ /* @__PURE__ */ jsxs("header", {
740
+ className: "bl-scale-card__head",
741
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
742
+ className: "bl-scale-card__title-row",
743
+ children: [
744
+ /* @__PURE__ */ jsx("h3", {
745
+ className: "bl-scale-card__title",
746
+ children: name
747
+ }),
748
+ required ? /* @__PURE__ */ jsx(Badge, { children: "Required" }) : null,
749
+ custom ? /* @__PURE__ */ jsx(Badge, { children: "Optional" }) : null,
750
+ warning && !warning.meets ? /* @__PURE__ */ jsx(Badge, {
751
+ as: "button",
752
+ variant: "danger",
753
+ "aria-haspopup": "dialog",
754
+ onClick: () => setAttentionOpen(true),
755
+ children: "Needs attention"
756
+ }) : null
757
+ ]
758
+ }), hint ? /* @__PURE__ */ jsx("p", {
759
+ className: "bl-scale-card__hint",
760
+ children: hint
761
+ }) : null] }), onDelete ? /* @__PURE__ */ jsx("button", {
762
+ type: "button",
763
+ className: "bl-scale-card__delete",
764
+ disabled: readOnly,
765
+ onClick: onDelete,
766
+ children: "Delete"
767
+ }) : null]
768
+ }),
769
+ /* @__PURE__ */ jsxs("div", {
770
+ className: "bl-scale-card__row",
771
+ children: [/* @__PURE__ */ jsxs(Field, {
772
+ as: "div",
773
+ children: [/* @__PURE__ */ jsx(Label, { children: "Brand hex" }), /* @__PURE__ */ jsx(BrandHexField, {
774
+ name,
775
+ value: state.hex,
776
+ onChange: commitHex,
777
+ readOnly
778
+ })]
779
+ }), /* @__PURE__ */ jsxs(Field, {
780
+ as: "div",
781
+ children: [/* @__PURE__ */ jsx(Label, { children: "This color is" }), /* @__PURE__ */ jsxs(Select, {
782
+ value: String(state.sourceStep),
783
+ onValueChange: (value) => commitStep(Number(value)),
784
+ disabled: readOnly,
785
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
786
+ "aria-label": "This color is",
787
+ children: /* @__PURE__ */ jsx(SelectValue, {})
788
+ }), /* @__PURE__ */ jsx(SelectContent, { children: SHADE_STEPS.map((step) => /* @__PURE__ */ jsx(SelectItem, {
789
+ value: String(step),
790
+ children: step
791
+ }, step)) })]
792
+ })]
793
+ })]
794
+ }),
795
+ role ? /* @__PURE__ */ jsxs("div", {
796
+ className: "bl-scale-card__family",
797
+ "data-role": role,
798
+ "data-drift": hueDrift ? "" : void 0,
799
+ children: [/* @__PURE__ */ jsx("div", {
800
+ className: "bl-scale-card__family-mark",
801
+ "aria-hidden": "true",
802
+ children: "!"
803
+ }), /* @__PURE__ */ jsxs("div", { children: [
804
+ /* @__PURE__ */ jsx("div", {
805
+ className: "bl-scale-card__family-title",
806
+ children: STATUS_COPY[role].title
654
807
  }),
655
- required ? /* @__PURE__ */ jsx("span", {
656
- className: "bl-scale-card__badge",
657
- children: "Required"
658
- }) : null,
659
- custom ? /* @__PURE__ */ jsx("span", {
660
- className: "bl-scale-card__badge",
661
- children: "Optional"
662
- }) : null,
663
- warning && !warning.meets ? /* @__PURE__ */ jsx("button", {
664
- type: "button",
665
- className: "bl-scale-card__badge bl-scale-card__badge--attention",
666
- "aria-haspopup": "dialog",
667
- onClick: () => setAttentionOpen(true),
668
- children: "Needs attention"
808
+ /* @__PURE__ */ jsx("p", { children: STATUS_COPY[role].body }),
809
+ hueDrift ? /* @__PURE__ */ jsx("p", {
810
+ className: "bl-scale-card__family-drift",
811
+ children: STATUS_COPY[role].drift
669
812
  }) : null
670
- ]
671
- }), hint ? /* @__PURE__ */ jsx("p", {
672
- className: "bl-scale-card__hint",
673
- children: hint
674
- }) : null] }), onDelete ? /* @__PURE__ */ jsx("button", {
675
- type: "button",
676
- className: "bl-scale-card__delete",
677
- disabled: readOnly,
678
- onClick: onDelete,
679
- children: "Delete"
680
- }) : null]
681
- }),
682
- /* @__PURE__ */ jsxs("div", {
683
- className: "bl-scale-card__row",
684
- children: [/* @__PURE__ */ jsxs("div", {
685
- className: "bl-scale-card__field",
686
- children: [/* @__PURE__ */ jsx("span", { children: "Brand hex" }), /* @__PURE__ */ jsxs("span", {
687
- className: "bl-scale-card__hex-wrap",
688
- children: [/* @__PURE__ */ jsx("input", {
689
- type: "color",
690
- "aria-label": `${name} picker`,
813
+ ] })]
814
+ }) : null,
815
+ /* @__PURE__ */ jsxs("div", {
816
+ className: "bl-scale-card__scale-head",
817
+ children: [/* @__PURE__ */ jsx("span", { children: "Generated scale" }), /* @__PURE__ */ jsxs("span", { children: [SHADE_STEPS.length, " shades"] })]
818
+ }),
819
+ /* @__PURE__ */ jsx("div", {
820
+ className: "bl-scale-card__steps",
821
+ role: "group",
822
+ "aria-label": `${name} scale steps`,
823
+ children: SHADE_STEPS.map((step) => {
824
+ const source = step === state.sourceStep;
825
+ const on = included.has(step);
826
+ return /* @__PURE__ */ jsxs("button", {
827
+ type: "button",
828
+ className: "bl-scale-card__step",
829
+ "data-source": source ? "" : void 0,
830
+ "data-excluded": on ? void 0 : "",
831
+ "data-shake": shakeStep === step ? "" : void 0,
691
832
  disabled: readOnly,
692
- value: isThemeHex(state.hex) ? state.hex : "#000000",
693
- onPointerDown: (event) => {
694
- const input = event.currentTarget;
695
- if (typeof input.showPicker !== "function") return;
833
+ "aria-pressed": on,
834
+ "aria-label": source ? `Source step ${step} cannot be excluded` : on ? `Shade ${step}, available — click to exclude from the palette` : `Shade ${step}, excluded — click to include in the palette`,
835
+ title: source ? `Source step ${step} cannot be excluded` : on ? "Available to page editors — click to exclude" : "Excluded from page editors — click to include",
836
+ onClick: (event) => {
696
837
  event.preventDefault();
697
- try {
698
- input.showPicker();
699
- } catch {
700
- input.click();
701
- }
702
- },
703
- onChange: (event) => commitHex(event.target.value)
704
- }), /* @__PURE__ */ jsx("input", {
705
- type: "text",
706
- spellCheck: false,
707
- autoComplete: "off",
708
- disabled: readOnly,
709
- "aria-label": `${name} hex`,
710
- value: hexDraft,
711
- onChange: (event) => {
712
- const next = event.target.value.trim();
713
- setHexDraft(next);
714
- if (isThemeHex(next)) commitHex(next);
838
+ event.stopPropagation();
839
+ toggleStep(step);
715
840
  },
716
- onBlur: () => {
717
- if (!isThemeHex(hexDraft)) setHexDraft(state.hex);
718
- }
719
- })]
720
- })]
721
- }), /* @__PURE__ */ jsxs("label", {
722
- className: "bl-scale-card__field",
723
- children: [/* @__PURE__ */ jsx("span", { children: "This color is" }), /* @__PURE__ */ jsx("select", {
841
+ children: [/* @__PURE__ */ jsxs("span", {
842
+ className: "bl-scale-card__chip-wrap",
843
+ children: [/* @__PURE__ */ jsx("span", {
844
+ className: "bl-scale-card__chip",
845
+ style: { backgroundColor: hslCss(state.scale[step]) }
846
+ }), /* @__PURE__ */ jsx(IncludeMark, { on })]
847
+ }), /* @__PURE__ */ jsx("span", {
848
+ className: "bl-scale-card__step-label",
849
+ children: step
850
+ })]
851
+ }, step);
852
+ })
853
+ }),
854
+ /* @__PURE__ */ jsxs("div", {
855
+ className: "bl-scale-card__editors",
856
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: "Available to page editors" }), /* @__PURE__ */ jsxs("p", { children: [
857
+ included.size,
858
+ " of ",
859
+ SHADE_STEPS.length,
860
+ " shades available · Choose which shades editors can select when building pages."
861
+ ] })] }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("button", {
862
+ type: "button",
724
863
  disabled: readOnly,
725
- value: String(state.sourceStep),
726
- onChange: (event) => commitStep(Number(event.target.value)),
727
- children: SHADE_STEPS.map((step) => /* @__PURE__ */ jsx("option", {
728
- value: step,
729
- children: step
730
- }, step))
731
- })]
732
- })]
733
- }),
734
- role ? /* @__PURE__ */ jsxs("div", {
735
- className: "bl-scale-card__family",
736
- "data-role": role,
737
- "data-drift": hueDrift ? "" : void 0,
738
- children: [/* @__PURE__ */ jsx("div", {
739
- className: "bl-scale-card__family-mark",
740
- "aria-hidden": "true",
741
- children: "!"
742
- }), /* @__PURE__ */ jsxs("div", { children: [
743
- /* @__PURE__ */ jsx("div", {
744
- className: "bl-scale-card__family-title",
745
- children: STATUS_COPY[role].title
746
- }),
747
- /* @__PURE__ */ jsx("p", { children: STATUS_COPY[role].body }),
748
- hueDrift ? /* @__PURE__ */ jsx("p", {
749
- className: "bl-scale-card__family-drift",
750
- children: STATUS_COPY[role].drift
751
- }) : null
752
- ] })]
753
- }) : null,
754
- /* @__PURE__ */ jsxs("div", {
755
- className: "bl-scale-card__scale-head",
756
- children: [/* @__PURE__ */ jsx("span", { children: "Generated scale" }), /* @__PURE__ */ jsxs("span", { children: [SHADE_STEPS.length, " shades"] })]
757
- }),
758
- /* @__PURE__ */ jsx("div", {
759
- className: "bl-scale-card__steps",
760
- role: "group",
761
- "aria-label": `${name} scale steps`,
762
- children: SHADE_STEPS.map((step) => {
763
- const source = step === state.sourceStep;
764
- const on = included.has(step);
765
- return /* @__PURE__ */ jsxs("button", {
864
+ onClick: () => onChange(setColorScaleInclude(state, "all")),
865
+ children: "Include all"
866
+ }), /* @__PURE__ */ jsx("button", {
766
867
  type: "button",
767
- className: "bl-scale-card__step",
768
- "data-source": source ? "" : void 0,
769
- "data-excluded": on ? void 0 : "",
770
- "data-shake": shakeStep === step ? "" : void 0,
771
868
  disabled: readOnly,
772
- "aria-pressed": on,
773
- "aria-label": source ? `Source step ${step} cannot be excluded` : on ? `Shade ${step}, available — click to exclude from the palette` : `Shade ${step}, excluded — click to include in the palette`,
774
- title: source ? `Source step ${step} cannot be excluded` : on ? "Available to page editors — click to exclude" : "Excluded from page editors — click to include",
775
- onClick: (event) => {
776
- event.preventDefault();
777
- event.stopPropagation();
778
- toggleStep(step);
779
- },
780
- children: [/* @__PURE__ */ jsxs("span", {
781
- className: "bl-scale-card__chip-wrap",
782
- children: [/* @__PURE__ */ jsx("span", {
783
- className: "bl-scale-card__chip",
784
- style: { backgroundColor: hslCss(state.scale[step]) }
785
- }), /* @__PURE__ */ jsx(IncludeMark, { on })]
786
- }), /* @__PURE__ */ jsx("span", {
787
- className: "bl-scale-card__step-label",
788
- children: step
789
- })]
790
- }, step);
791
- })
792
- }),
793
- /* @__PURE__ */ jsxs("div", {
794
- className: "bl-scale-card__editors",
795
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: "Available to page editors" }), /* @__PURE__ */ jsxs("p", { children: [
796
- included.size,
797
- " of ",
798
- SHADE_STEPS.length,
799
- " shades available · Choose which shades editors can select when building pages."
800
- ] })] }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("button", {
801
- type: "button",
802
- disabled: readOnly,
803
- onClick: () => onChange(setColorScaleInclude(state, "all")),
804
- children: "Include all"
805
- }), /* @__PURE__ */ jsx("button", {
806
- type: "button",
807
- disabled: readOnly,
808
- onClick: () => onChange(setColorScaleInclude(state, "source")),
809
- children: "Source only"
810
- })] })]
811
- }),
812
- attentionOpen && warning ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
813
- className: "bl-scale-card__modal",
814
- role: "dialog",
815
- "aria-modal": "true",
816
- "aria-labelledby": titleId,
817
- onClick: (event) => {
818
- if (event.target === event.currentTarget) setAttentionOpen(false);
819
- },
820
- children: /* @__PURE__ */ jsxs("div", {
821
- className: "bl-scale-card__panel",
822
- children: [
823
- /* @__PURE__ */ jsxs("div", {
824
- className: "bl-scale-card__panel-head",
825
- children: [/* @__PURE__ */ jsx("h4", {
826
- id: titleId,
827
- children: readabilityHeadline(warning)
828
- }), /* @__PURE__ */ jsx("button", {
869
+ onClick: () => onChange(setColorScaleInclude(state, "source")),
870
+ children: "Source only"
871
+ })] })]
872
+ }),
873
+ attentionOpen && warning ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
874
+ className: "bl-scale-card__modal",
875
+ role: "dialog",
876
+ "aria-modal": "true",
877
+ "aria-labelledby": titleId,
878
+ onClick: (event) => {
879
+ if (event.target === event.currentTarget) setAttentionOpen(false);
880
+ },
881
+ children: /* @__PURE__ */ jsxs("div", {
882
+ className: "bl-scale-card__panel",
883
+ children: [
884
+ /* @__PURE__ */ jsxs("div", {
885
+ className: "bl-scale-card__panel-head",
886
+ children: [/* @__PURE__ */ jsx("h4", {
887
+ id: titleId,
888
+ children: readabilityHeadline(warning)
889
+ }), /* @__PURE__ */ jsx("button", {
890
+ type: "button",
891
+ onClick: () => setAttentionOpen(false),
892
+ "aria-label": "Close",
893
+ children: "×"
894
+ })]
895
+ }),
896
+ /* @__PURE__ */ jsx(ReadabilityDetail, { item: warning }),
897
+ /* @__PURE__ */ jsx("button", {
829
898
  type: "button",
899
+ className: "bl-scale-card__panel-done",
830
900
  onClick: () => setAttentionOpen(false),
831
- "aria-label": "Close",
832
- children: "×"
833
- })]
834
- }),
835
- /* @__PURE__ */ jsx(ReadabilityDetail, { item: warning }),
836
- /* @__PURE__ */ jsx("button", {
837
- type: "button",
838
- className: "bl-scale-card__panel-done",
839
- onClick: () => setAttentionOpen(false),
840
- children: "Keep editing this color"
841
- })
842
- ]
843
- })
844
- }) }) : null
845
- ]
901
+ children: "Keep editing this color"
902
+ })
903
+ ]
904
+ })
905
+ }) }) : null
906
+ ]
907
+ })
846
908
  });
847
909
  }
848
910
  const COLOR_SCALE_CARD_CSS = `
@@ -850,18 +912,10 @@ const COLOR_SCALE_CARD_CSS = `
850
912
  .bl-scale-card__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}
851
913
  .bl-scale-card__title-row{position:relative;display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}
852
914
  .bl-scale-card__title{margin:0;font-size:1rem}
853
- .bl-scale-card__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;border:0;background:#e2e8f0;color:#0f172a}
854
- .bl-scale-card__badge--attention{background:#fff1f2;color:#be123c;cursor:pointer}
855
915
  .bl-scale-card__hint{margin:.35rem 0 0;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b));font-size:12px}
856
916
  .bl-scale-card__delete{border:0;background:none;color:#be123c;font:inherit;font-size:13px;font-weight:600;cursor:pointer}
857
- .bl-scale-card__row{display:grid;grid-template-columns:1fr 8rem;gap:.75rem;margin-top:1rem}
858
- .bl-scale-card__field{display:flex;flex-direction:column;gap:.35rem;font-size:12px;font-weight:600;color:var(--bl-preview-muted,var(--theme-elevation-600,#475569))}
859
- .bl-scale-card__hex-wrap{display:flex;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px;background:var(--bl-preview-card,var(--theme-input-bg,#fff))}
860
- .bl-scale-card__hex-wrap input[type=color]{width:2.75rem;height:2.25rem;padding:0;border:0;border-right:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px 0 0 8px;background:transparent;cursor:pointer;color-scheme:light;appearance:none;-webkit-appearance:none}
861
- .bl-scale-card__hex-wrap input[type=color]::-webkit-color-swatch-wrapper{padding:0}
862
- .bl-scale-card__hex-wrap input[type=color]::-webkit-color-swatch{border:0;border-radius:0;width:100%;height:100%}
863
- .bl-scale-card__hex-wrap input[type=text]{flex:1;min-width:0;border:0;padding:.4rem .7rem;font-family:var(--font-mono,ui-monospace,monospace);font-size:13px;background:transparent;color:inherit;border-radius:0 8px 8px 0}
864
- .bl-scale-card__field select{min-height:2.25rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px;padding:.35rem .5rem;background:var(--bl-preview-card,var(--theme-input-bg,#fff));color:inherit}
917
+ .bl-scale-card__row{display:grid;grid-template-columns:1fr 8rem;gap:.75rem;margin-top:1rem;align-items:start}
918
+ .bl-scale-card__row .bl-nav-kit__field{margin-bottom:0}
865
919
  .bl-scale-card__family{display:flex;gap:.75rem;align-items:flex-start;margin-top:1rem;padding:.75rem .85rem;border-radius:8px}
866
920
  .bl-scale-card__family[data-role=success]{border:1px solid #a7f3d0;background:#ecfdf5;color:#065f46}
867
921
  .bl-scale-card__family[data-role=destructive]{border:1px solid #fecdd3;background:#fff1f2;color:#9f1239}
@@ -1122,63 +1176,52 @@ const LibraryField = ({ field, path, readOnly }) => {
1122
1176
  })]
1123
1177
  }),
1124
1178
  adding ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
1125
- className: "bl-library__modal",
1126
- role: "dialog",
1127
- "aria-modal": "true",
1128
- "aria-labelledby": "bl-library-add-title",
1129
- onClick: (event) => {
1130
- if (event.target === event.currentTarget) setAdding(false);
1131
- },
1132
- children: /* @__PURE__ */ jsxs("div", {
1133
- className: "bl-library__panel",
1179
+ className: "bl-theme-dialog",
1180
+ children: /* @__PURE__ */ jsx(KitProvider, { children: /* @__PURE__ */ jsxs(Dialog, {
1181
+ open: true,
1182
+ title: "New color",
1183
+ onCancel: () => {
1184
+ setAdding(false);
1185
+ setName("");
1186
+ setHex("");
1187
+ setSourceStep(500);
1188
+ },
1189
+ confirmLabel: "Create color scale",
1190
+ onConfirm: add,
1191
+ confirmDisabled: !slugify(name) || !isThemeHex(hex),
1134
1192
  children: [
1135
- /* @__PURE__ */ jsxs("div", {
1136
- className: "bl-library__panel-head",
1137
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
1138
- id: "bl-library-add-title",
1139
- children: "New color"
1140
- }), /* @__PURE__ */ jsx("p", { children: "Give it a useful name, enter your brand hex, then say which scale step that hex is." })] }), /* @__PURE__ */ jsx("button", {
1141
- type: "button",
1142
- onClick: () => setAdding(false),
1143
- "aria-label": "Close",
1144
- children: "×"
1145
- })]
1146
- }),
1147
- /* @__PURE__ */ jsxs("label", { children: ["Name", /* @__PURE__ */ jsx("input", {
1193
+ /* @__PURE__ */ jsx("p", { children: "Give it a useful name, enter your brand hex, then say which scale step that hex is." }),
1194
+ /* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(Label, { children: "Name" }), /* @__PURE__ */ jsx(Input, {
1195
+ "aria-label": "Name",
1148
1196
  value: name,
1149
1197
  placeholder: "e.g. Coral",
1150
1198
  onChange: (event) => setName(event.target.value)
1151
1199
  })] }),
1152
- /* @__PURE__ */ jsxs("label", { children: ["Brand hex", /* @__PURE__ */ jsx("input", {
1153
- value: hex,
1154
- placeholder: "#DB0082",
1155
- spellCheck: false,
1156
- autoComplete: "off",
1157
- onChange: (event) => setHex(event.target.value.trim())
1158
- })] }),
1159
- /* @__PURE__ */ jsxs("label", { children: ["This color is", /* @__PURE__ */ jsx("select", {
1160
- value: String(sourceStep),
1161
- onChange: (event) => setSourceStep(Number(event.target.value)),
1162
- children: SHADE_STEPS.map((step) => /* @__PURE__ */ jsx("option", {
1163
- value: step,
1164
- children: step
1165
- }, step))
1166
- })] }),
1167
- /* @__PURE__ */ jsxs("div", {
1168
- className: "bl-library__actions",
1169
- children: [/* @__PURE__ */ jsx("button", {
1170
- type: "button",
1171
- onClick: () => setAdding(false),
1172
- children: "Cancel"
1173
- }), /* @__PURE__ */ jsx("button", {
1174
- type: "button",
1175
- disabled: !slugify(name) || !isThemeHex(hex),
1176
- onClick: add,
1177
- children: "Create color scale"
1200
+ /* @__PURE__ */ jsxs(Field, {
1201
+ as: "div",
1202
+ children: [/* @__PURE__ */ jsx(Label, { children: "Brand hex" }), /* @__PURE__ */ jsx(BrandHexField, {
1203
+ name: "Brand",
1204
+ value: hex,
1205
+ onChange: setHex,
1206
+ picker: "inline"
1207
+ })]
1208
+ }),
1209
+ /* @__PURE__ */ jsxs(Field, {
1210
+ as: "div",
1211
+ children: [/* @__PURE__ */ jsx(Label, { children: "This color is" }), /* @__PURE__ */ jsxs(Select, {
1212
+ value: String(sourceStep),
1213
+ onValueChange: (value) => setSourceStep(Number(value)),
1214
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
1215
+ "aria-label": "This color is",
1216
+ children: /* @__PURE__ */ jsx(SelectValue, {})
1217
+ }), /* @__PURE__ */ jsx(SelectContent, { children: SHADE_STEPS.map((step) => /* @__PURE__ */ jsx(SelectItem, {
1218
+ value: String(step),
1219
+ children: step
1220
+ }, step)) })]
1178
1221
  })]
1179
1222
  })
1180
1223
  ]
1181
- })
1224
+ }) })
1182
1225
  }) }) : null,
1183
1226
  replacing ? /* @__PURE__ */ jsx(ThemePortal, { children: /* @__PURE__ */ jsx("div", {
1184
1227
  className: "bl-library__modal",
@@ -1278,26 +1321,24 @@ const CSS$3 = `
1278
1321
  .bl-library__panel-head button{border:0;background:none;font:inherit;font-size:1.25rem;line-height:1;color:#94a3b8;cursor:pointer}
1279
1322
  .bl-library__panel h2{margin:0}
1280
1323
  .bl-library__panel p{margin:.5rem 0 0;color:#475569;font-size:14px}
1281
- .bl-library__panel label{display:flex;flex-direction:column;gap:.4rem;margin-top:1rem;font-size:13px;font-weight:600}
1324
+ .bl-library__panel label,.bl-library__field{display:flex;flex-direction:column;gap:.4rem;margin-top:1rem;font-size:13px;font-weight:600}
1282
1325
  .bl-library__panel input,.bl-library__panel select{min-height:2.25rem;border:1px solid #cbd5e1;border-radius:8px;padding:.35rem .5rem;background:#fff;color:#0f172a}
1283
1326
  .bl-library__usages{margin:1rem 0 0;padding-left:1.1rem;color:#475569;font-size:13px;font-weight:400}
1284
1327
  .bl-library__usages li{margin:.25rem 0}
1285
1328
  .bl-library__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.5rem;margin-top:1rem}
1286
1329
  .bl-library__actions button:last-child{border:0;background:#0f172a;color:#fff;font-weight:600}
1287
1330
  .bl-library__actions button:last-child:disabled{opacity:.4;cursor:not-allowed}
1331
+ .bl-theme-dialog .bl-nav-kit__modal{z-index:10000}
1288
1332
  `;
1289
1333
  //#endregion
1290
1334
  //#region src/admin/typography-pairing.tsx
1291
1335
  function FontRoleCard({ title, hint, required, family, preview, children }) {
1292
- return /* @__PURE__ */ jsxs("article", {
1336
+ return /* @__PURE__ */ jsx(KitProvider, { children: /* @__PURE__ */ jsxs("article", {
1293
1337
  className: "bl-font-role",
1294
1338
  children: [
1295
1339
  /* @__PURE__ */ jsxs("header", {
1296
1340
  className: "bl-font-role__head",
1297
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", { children: title }), /* @__PURE__ */ jsx("p", { children: hint })] }), required ? /* @__PURE__ */ jsx("span", {
1298
- className: "bl-font-role__badge",
1299
- children: "Required"
1300
- }) : null]
1341
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", { children: title }), /* @__PURE__ */ jsx("p", { children: hint })] }), required ? /* @__PURE__ */ jsx(Badge, { children: "Required" }) : null]
1301
1342
  }),
1302
1343
  children,
1303
1344
  /* @__PURE__ */ jsxs("div", {
@@ -1313,7 +1354,7 @@ function FontRoleCard({ title, hint, required, family, preview, children }) {
1313
1354
  })]
1314
1355
  })
1315
1356
  ]
1316
- });
1357
+ }) });
1317
1358
  }
1318
1359
  function TypographyPairing({ headingFamily, bodyFamily }) {
1319
1360
  return /* @__PURE__ */ jsxs("section", {
@@ -1358,7 +1399,6 @@ const TYPOGRAPHY_PAIRING_CSS = `
1358
1399
  .bl-font-role__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}
1359
1400
  .bl-font-role__head h3{margin:0;font-size:1rem}
1360
1401
  .bl-font-role__head p{margin:.3rem 0 0;font-size:12px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}
1361
- .bl-font-role__badge{font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:#e2e8f0;color:#0f172a}
1362
1402
  .bl-font-role__preview{margin-top:1rem;padding:.85rem .9rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-bg,var(--theme-elevation-50,#f8fafc))}
1363
1403
  .bl-font-role__preview > span{display:block;margin-bottom:.4rem;font-size:11px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}
1364
1404
  .bl-font-role__heading{margin:0;font-size:1.5rem;line-height:1.2;font-weight:600}
@@ -1889,7 +1929,7 @@ const SWATCHES = [
1889
1929
  ];
1890
1930
  function GreyScaleChoices({ value, onChange, readOnly }) {
1891
1931
  const canvas = usePreviewCanvas();
1892
- return /* @__PURE__ */ jsxs("section", {
1932
+ return /* @__PURE__ */ jsx(KitProvider, { children: /* @__PURE__ */ jsxs("section", {
1893
1933
  className: `bl-grey ${canvas.className}`,
1894
1934
  "data-preview": canvas.mode,
1895
1935
  style: canvas.style,
@@ -1900,10 +1940,7 @@ function GreyScaleChoices({ value, onChange, readOnly }) {
1900
1940
  }),
1901
1941
  /* @__PURE__ */ jsxs("header", {
1902
1942
  className: "bl-grey__head",
1903
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", { children: "Gray family" }), /* @__PURE__ */ jsx("p", { children: "Choose the neutral family used for page backgrounds, cards, borders, inputs, and muted text. Readability for these system neutrals is handled automatically." })] }), /* @__PURE__ */ jsx("span", {
1904
- className: "bl-grey__badge",
1905
- children: "Required"
1906
- })]
1943
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", { children: "Gray family" }), /* @__PURE__ */ jsx("p", { children: "Choose the neutral family used for page backgrounds, cards, borders, inputs, and muted text. Readability for these system neutrals is handled automatically." })] }), /* @__PURE__ */ jsx(Badge, { children: "Required" })]
1907
1944
  }),
1908
1945
  /* @__PURE__ */ jsx("div", {
1909
1946
  className: "bl-grey__choices",
@@ -1937,7 +1974,7 @@ function GreyScaleChoices({ value, onChange, readOnly }) {
1937
1974
  })
1938
1975
  })
1939
1976
  ]
1940
- });
1977
+ }) });
1941
1978
  }
1942
1979
  /**
1943
1980
  * Visual picker over the five grey-scale presets. Replaces the stock select
@@ -1966,7 +2003,6 @@ const GREY_SCALE_FIELD_CSS = `
1966
2003
  .bl-grey__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem;margin:0;padding:1.1rem 1.15rem .85rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-bottom:0;border-radius:12px 12px 0 0;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}
1967
2004
  .bl-grey__head h2{margin:0;font-size:1.1rem}
1968
2005
  .bl-grey__head p{margin:.35rem 0 0;max-width:40rem;font-size:13px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}
1969
- .bl-grey__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:#e2e8f0;color:#0f172a}
1970
2006
  .bl-grey__choices{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:.6rem;padding:0 1.15rem 1.15rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-top:0;border-radius:0 0 12px 12px;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}
1971
2007
  .bl-grey__choice{display:flex;flex-direction:column;gap:.45rem;padding:.75rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-bg,var(--theme-elevation-0,#fff));color:inherit;cursor:pointer}
1972
2008
  .bl-grey__choice[data-selected]{box-shadow:inset 0 0 0 2px var(--bl-preview-text,#0f172a);border-color:var(--bl-preview-text,#0f172a)}
@@ -2325,9 +2361,8 @@ function ThemePublishActions({ child }) {
2325
2361
  /* @__PURE__ */ jsx("style", {
2326
2362
  href: "bl-publish-child",
2327
2363
  precedence: "default",
2328
- children: `${THEME_PREVIEW_TOGGLE_CSS}.bl-publish-child{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.bl-publish-child__button{min-height:2.25rem;padding:.4rem 1rem;border:0;border-radius:8px;background:var(--theme-text,#0f172a);color:var(--theme-bg,#fff);font:inherit;font-weight:600;cursor:pointer}`
2364
+ children: `.bl-publish-child{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.bl-publish-child__button{min-height:2.25rem;padding:.4rem 1rem;border:0;border-radius:8px;background:var(--theme-text,#0f172a);color:var(--theme-bg,#fff);font:inherit;font-weight:600;cursor:pointer}`
2329
2365
  }),
2330
- child !== "identity" ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ThemePreviewToggle, {}) }) : null,
2331
2366
  /* @__PURE__ */ jsxs("button", {
2332
2367
  type: "button",
2333
2368
  className: "bl-publish-child__button",
@@ -2374,16 +2409,12 @@ function readActiveThemeTab(root = typeof document === "undefined" ? null : docu
2374
2409
  //#endregion
2375
2410
  //#region src/admin/save-button.tsx
2376
2411
  /**
2377
- * Light/Dark preview for Colors, Typography, and Appearance. Lives in
2378
- * `beforeDocumentControls` so Payload's Save stays in the Save slot.
2379
- * Save writes that page's slice onto the stored Theme row.
2412
+ * Theme used to put a Light/Dark pair here. Admin chrome now follows
2413
+ * Payload's own theme from the header sun/moon, so this slot is empty
2414
+ * and Save stays in the Save slot.
2380
2415
  */
2381
2416
  function ThemeDocumentControls() {
2382
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", {
2383
- href: "bl-doc-controls",
2384
- precedence: "default",
2385
- children: THEME_PREVIEW_TOGGLE_CSS
2386
- }), /* @__PURE__ */ jsx(ThemePreviewToggle, {})] });
2417
+ return null;
2387
2418
  }
2388
2419
  /**
2389
2420
  * Import-map Save slot used by the older single-Global Theme. Theme pages
@@ -3316,6 +3347,44 @@ const FeaturesMatrixField = (props) => {
3316
3347
  });
3317
3348
  };
3318
3349
  //#endregion
3350
+ //#region src/admin/theme-kit-accent.tsx
3351
+ function primaryHex(doc) {
3352
+ const hex = doc?.colors?.brand?.primary?.hex;
3353
+ return typeof hex === "string" && isThemeHex(hex) ? hex : void 0;
3354
+ }
3355
+ /**
3356
+ * Site Theme primary → `--bl-kit-accent`. Saved value for the whole
3357
+ * admin; the Primary color card also writes the live hex so pickers
3358
+ * and kit chrome update as the field is edited.
3359
+ */
3360
+ function ThemeKitAccent({ children }) {
3361
+ const { config } = useConfig();
3362
+ const [accent, setAccent] = useState();
3363
+ useEffect(() => {
3364
+ const url = `${config.serverURL}${config.routes.api}/globals/theme?depth=0`;
3365
+ let cancelled = false;
3366
+ function load() {
3367
+ fetch(url, { credentials: "include" }).then((response) => response.ok ? response.json() : null).then((doc) => {
3368
+ const hex = primaryHex(doc);
3369
+ if (!cancelled && hex) setAccent(hex);
3370
+ }).catch(() => void 0);
3371
+ }
3372
+ load();
3373
+ const onVis = () => {
3374
+ if (document.visibilityState === "visible") load();
3375
+ };
3376
+ document.addEventListener("visibilitychange", onVis);
3377
+ return () => {
3378
+ cancelled = true;
3379
+ document.removeEventListener("visibilitychange", onVis);
3380
+ };
3381
+ }, [config.serverURL, config.routes.api]);
3382
+ return /* @__PURE__ */ jsx(KitProvider, {
3383
+ accent,
3384
+ children
3385
+ });
3386
+ }
3387
+ //#endregion
3319
3388
  //#region src/admin/document-title-actions.tsx
3320
3389
  /**
3321
3390
  * Shared document header: title on the left, primary actions on the
@@ -3357,7 +3426,7 @@ function DocumentTitleActions({ children }) {
3357
3426
  });
3358
3427
  return () => observer.disconnect();
3359
3428
  }, []);
3360
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", {
3429
+ return /* @__PURE__ */ jsxs(ThemeKitAccent, { children: [/* @__PURE__ */ jsx("style", {
3361
3430
  href: "bl-doc-title-actions",
3362
3431
  precedence: "default",
3363
3432
  children: TITLE_ACTIONS_CSS
@@ -3497,6 +3566,8 @@ function resolveAdminNav({ config, doc, visibleEntities }) {
3497
3566
  //#endregion
3498
3567
  //#region src/admin/admin-nav.tsx
3499
3568
  const BASE = "nav";
3569
+ /** Survives AdminNav remounting on every admin route so the first-seen walk does not flash. */
3570
+ let cachedDoc;
3500
3571
  function isAbortError(error) {
3501
3572
  return error instanceof DOMException ? error.name === "AbortError" : error instanceof Error && error.name === "AbortError";
3502
3573
  }
@@ -3529,7 +3600,7 @@ function AdminNavShell({ children }) {
3529
3600
  */
3530
3601
  function AdminNav({ visibleEntities }) {
3531
3602
  const { config } = useConfig();
3532
- const [doc, setDoc] = useState(null);
3603
+ const [doc, setDoc] = useState(() => cachedDoc ?? null);
3533
3604
  const adminRoute = config.routes.admin ?? "/admin";
3534
3605
  const apiRoute = config.routes.api ?? "/api";
3535
3606
  useEffect(() => {
@@ -3540,9 +3611,12 @@ function AdminNav({ visibleEntities }) {
3540
3611
  signal: controller.signal
3541
3612
  }).then((response) => response.ok ? response.json() : null).then((payload) => {
3542
3613
  if (controller.signal.aborted) return;
3614
+ cachedDoc = payload;
3543
3615
  setDoc(payload);
3544
3616
  }).catch((error) => {
3545
3617
  if (isAbortError(error) || controller.signal.aborted) return;
3618
+ if (cachedDoc !== void 0) return;
3619
+ cachedDoc = null;
3546
3620
  setDoc(null);
3547
3621
  });
3548
3622
  return () => controller.abort();
@@ -3669,6 +3743,6 @@ const AdminNavEntityField = ({ field, path, permissions, readOnly, schemaPath })
3669
3743
  });
3670
3744
  };
3671
3745
  //#endregion
3672
- export { AdminNav, AdminNavEntityField, AdminNavItemRowLabel, AdminNavRowLabel, AppearanceField, ColorField, ColorScaleField, ContrastReport, DocumentCreateNew, DocumentTitleActions, FeaturesMatrixField, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RoleNameField, RoleSlugField, RolesField, RolesGrantsField, RolesMatrixField, RolesRowLabel, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
3746
+ export { AdminNav, AdminNavEntityField, AdminNavItemRowLabel, AdminNavRowLabel, AppearanceField, ColorField, ColorScaleField, ContrastReport, DocumentCreateNew, DocumentTitleActions, FeaturesMatrixField, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RoleNameField, RoleSlugField, RolesField, RolesGrantsField, RolesMatrixField, RolesRowLabel, SectionHeading, ThemeDocumentControls, ThemeSaveButton, setThemePreviewMode };
3673
3747
 
3674
3748
  //# sourceMappingURL=admin.mjs.map