@bison-lab/payload-blocks 3.11.0 → 3.21.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
@@ -1,8 +1,12 @@
1
1
  "use client";
2
- import { t as linkTypeOf } from "./link-CnwLtm47.mjs";
2
+ import "./link-32261jXB.mjs";
3
+ import { a as linkTypeOf, n as headerItemsFromBlocks, o as resolveAdminPreviewLink } from "./header-CV7K-3yB.mjs";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
- import { ArrayField, FieldDescription, FieldError, FieldLabel, toast, useConfig, useField, useFieldPath, useTranslation } from "@payloadcms/ui";
5
+ import { FloatingNavBlock } from "@bison-lab/ui";
6
+ import { ArrayField, FieldDescription, FieldError, FieldLabel, FieldPathContext, toast, useConfig, useField, useFieldPath, useForm, useTranslation } from "@payloadcms/ui";
5
7
  import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
8
+ import { ConfirmDialog, LinkGlyph, MegaGlyph, TypeCard, TypeCards } from "@bison-lab/admin-ui";
9
+ import { themeHeadFromDoc } from "@bison-lab/payload-core/theme";
6
10
  //#region src/admin/link-field.tsx
7
11
  /**
8
12
  * The link picker: one box in place of a link's `type`, `page` and `href`.
@@ -239,7 +243,7 @@ const LinkField = ({ field, path, readOnly }) => {
239
243
  /* @__PURE__ */ jsx("style", {
240
244
  href: "bl-link-field",
241
245
  precedence: "default",
242
- children: CSS
246
+ children: CSS$1
243
247
  }),
244
248
  /* @__PURE__ */ jsx(FieldLabel, {
245
249
  htmlFor: inputId,
@@ -341,7 +345,7 @@ const LinkField = ({ field, path, readOnly }) => {
341
345
  });
342
346
  };
343
347
  /** Theme variables only: a literal colour would be right in one theme and wrong in the other. */
344
- const CSS = `
348
+ const CSS$1 = `
345
349
  .bl-link-field__control{position:relative;display:flex;align-items:center;gap:calc(var(--base) * .4);min-height:calc(var(--base) * 2);padding:calc(var(--base) * .25) calc(var(--base) * .6);border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-input-bg);color:var(--theme-elevation-800);font-family:var(--font-body)}
346
350
  .bl-link-field__control:focus-within{border-color:var(--theme-elevation-400);box-shadow:0 0 0 1px var(--theme-elevation-400)}
347
351
  .bl-link-field__input{flex:1;min-width:0;border:0;background:transparent;color:inherit;font:inherit;outline:none}
@@ -435,6 +439,815 @@ function staticLabel(label, language) {
435
439
  }
436
440
  }
437
441
  //#endregion
438
- export { LinkField, MinRowsArrayField };
442
+ //#region src/admin/nav-items-field.tsx
443
+ const WIDTHS = [
444
+ "25",
445
+ "33",
446
+ "50",
447
+ "66",
448
+ "75",
449
+ "100"
450
+ ];
451
+ const LINK_ROW = {
452
+ type: "row",
453
+ fields: [
454
+ {
455
+ name: "type",
456
+ type: "radio"
457
+ },
458
+ {
459
+ name: "page",
460
+ type: "relationship",
461
+ relationTo: "pages"
462
+ },
463
+ {
464
+ name: "href",
465
+ type: "text"
466
+ }
467
+ ]
468
+ };
469
+ const emptySection = () => ({
470
+ display: "list",
471
+ hideDescriptionsOnMobile: true,
472
+ links: []
473
+ });
474
+ const emptyColumn = () => ({
475
+ width: "100",
476
+ divider: false,
477
+ sections: [emptySection()]
478
+ });
479
+ const emptyPanel = () => ({
480
+ maxWidth: "standard",
481
+ columns: [emptyColumn()],
482
+ footer: {
483
+ overview: {},
484
+ cta: {}
485
+ }
486
+ });
487
+ const emptyLink = () => ({
488
+ blockType: "navLink",
489
+ label: "New item",
490
+ type: "page",
491
+ page: null,
492
+ href: null,
493
+ newTab: false
494
+ });
495
+ const emptyMega = () => ({
496
+ blockType: "megaMenu",
497
+ label: "New item",
498
+ type: "page",
499
+ page: null,
500
+ href: null,
501
+ newTab: false,
502
+ panel: emptyPanel()
503
+ });
504
+ function destinationOf(row) {
505
+ return {
506
+ type: row.type,
507
+ page: row.page,
508
+ href: row.href,
509
+ newTab: row.newTab,
510
+ label: row.label
511
+ };
512
+ }
513
+ /** Missing Theme fields so `themeHeadFromDoc` can run; the fetched document wins. */
514
+ const THEME_SEED = {
515
+ brandPrimary: "#1e3a5f",
516
+ brandSecondary: "#2d9d6e",
517
+ brandAccent: "#e89b20",
518
+ brandHighlight: "#7c3aed",
519
+ brandSuccess: "#22c55e",
520
+ brandDestructive: "#b91c1c",
521
+ greyScale: "slate",
522
+ darkSelector: "[data-theme=\"dark\"]",
523
+ defaultTheme: "system",
524
+ radius: "rounded",
525
+ shadow: "subtle",
526
+ motion: "smooth",
527
+ density: "default",
528
+ fontBody: "inter",
529
+ fontHeading: "playfair-display",
530
+ fontWeights: {
531
+ normal: 400,
532
+ medium: 500,
533
+ semibold: 600,
534
+ bold: 700
535
+ }
536
+ };
537
+ const THEME_SCOPE = ".bl-nav-items";
538
+ function scopeThemeCss(css) {
539
+ return css.replace(/:root/g, THEME_SCOPE).replace(/\[data-theme="dark"\]/g, `${THEME_SCOPE}[data-theme="dark"]`);
540
+ }
541
+ function pageIdOf(value) {
542
+ if (value == null) return null;
543
+ if (typeof value === "object") {
544
+ const id = value.id;
545
+ return id == null ? null : String(id);
546
+ }
547
+ return String(value);
548
+ }
549
+ function collectPageIds(items) {
550
+ const ids = /* @__PURE__ */ new Set();
551
+ const take = (link) => {
552
+ const id = pageIdOf(link?.page);
553
+ if (id) ids.add(id);
554
+ };
555
+ for (const row of items) {
556
+ take(row);
557
+ const panel = row.panel;
558
+ take(panel?.footer?.overview);
559
+ take(panel?.footer?.cta);
560
+ for (const column of panel?.columns ?? []) for (const section of column.sections ?? []) for (const link of section.links ?? []) take(link);
561
+ }
562
+ return [...ids];
563
+ }
564
+ function ComposedLinkField({ path, parentPath, readOnly }) {
565
+ return /* @__PURE__ */ jsx(FieldPathContext.Provider, {
566
+ value: path,
567
+ children: /* @__PURE__ */ jsx(LinkField, {
568
+ field: LINK_ROW,
569
+ path,
570
+ parentPath,
571
+ indexPath: "0",
572
+ schemaPath: path,
573
+ readOnly
574
+ })
575
+ });
576
+ }
577
+ const NavItemsField = ({ field, path, readOnly }) => {
578
+ const itemsField = useField({ path });
579
+ const items = Array.isArray(itemsField.value) ? itemsField.value : [];
580
+ const { addFieldRow, replaceFieldRow, removeFieldRow, moveFieldRow } = useForm();
581
+ const { config } = useConfig();
582
+ const endpoint = `${config.serverURL}${config.routes.api}`;
583
+ const [selected, setSelected] = useState(0);
584
+ const [adding, setAdding] = useState(false);
585
+ const [confirmSwitch, setConfirmSwitch] = useState(false);
586
+ const [menu, setMenu] = useState(null);
587
+ const [atTop, setAtTop] = useState(true);
588
+ const sentinel = useRef(null);
589
+ useEffect(() => {
590
+ if (selected >= items.length) setSelected(Math.max(0, items.length - 1));
591
+ }, [items.length, selected]);
592
+ useEffect(() => {
593
+ const el = sentinel.current;
594
+ if (!el) return;
595
+ const leave = () => setAtTop(false);
596
+ const enter = () => setAtTop(true);
597
+ el.addEventListener("nav-items-preview-leave", leave);
598
+ el.addEventListener("nav-items-preview-enter", enter);
599
+ const io = new IntersectionObserver(([entry]) => {
600
+ if (entry) setAtTop(entry.isIntersecting);
601
+ });
602
+ io.observe(el);
603
+ return () => {
604
+ el.removeEventListener("nav-items-preview-leave", leave);
605
+ el.removeEventListener("nav-items-preview-enter", enter);
606
+ io.disconnect();
607
+ };
608
+ }, []);
609
+ const current = items[selected];
610
+ const [pages, setPages] = useState(() => /* @__PURE__ */ new Map());
611
+ const pageIds = useMemo(() => collectPageIds(items).sort().join(","), [items]);
612
+ useEffect(() => {
613
+ const ids = pageIds ? pageIds.split(",") : [];
614
+ if (ids.length === 0) return;
615
+ let cancelled = false;
616
+ Promise.all(ids.map((id) => fetch(`${endpoint}/pages/${id}?depth=0`, { credentials: "include" }).then((response) => response.ok ? response.json() : null))).then((docs) => {
617
+ if (cancelled) return;
618
+ setPages(() => {
619
+ const next = /* @__PURE__ */ new Map();
620
+ for (const doc of docs) if (doc?.id != null) next.set(String(doc.id), doc);
621
+ return next;
622
+ });
623
+ }).catch(() => void 0);
624
+ return () => {
625
+ cancelled = true;
626
+ };
627
+ }, [pageIds, endpoint]);
628
+ const previewItems = useMemo(() => headerItemsFromBlocks(items, { resolveLink: (link) => resolveAdminPreviewLink(link, pages) }), [items, pages]);
629
+ const openItem = atTop && current?.blockType === "megaMenu" && current.label ? current.label : void 0;
630
+ function add(blockType) {
631
+ const seed = blockType === "navLink" ? emptyLink() : emptyMega();
632
+ addFieldRow({
633
+ path,
634
+ schemaPath: path,
635
+ blockType,
636
+ subFieldState: Object.fromEntries(Object.entries(seed).filter(([key]) => key !== "blockType").map(([key, value]) => [key, {
637
+ value,
638
+ valid: true,
639
+ initialValue: value
640
+ }]))
641
+ });
642
+ setSelected(items.length);
643
+ setAdding(false);
644
+ }
645
+ function switchToLink() {
646
+ if (!current) return;
647
+ replaceFieldRow({
648
+ path,
649
+ schemaPath: path,
650
+ rowIndex: selected,
651
+ blockType: "navLink",
652
+ subFieldState: {
653
+ label: {
654
+ value: current.label,
655
+ valid: true
656
+ },
657
+ type: {
658
+ value: current.type,
659
+ valid: true
660
+ },
661
+ page: {
662
+ value: current.page,
663
+ valid: true
664
+ },
665
+ href: {
666
+ value: current.href,
667
+ valid: true
668
+ },
669
+ newTab: {
670
+ value: current.newTab,
671
+ valid: true
672
+ }
673
+ }
674
+ });
675
+ setConfirmSwitch(false);
676
+ }
677
+ function switchToMega() {
678
+ if (!current) return;
679
+ replaceFieldRow({
680
+ path,
681
+ schemaPath: path,
682
+ rowIndex: selected,
683
+ blockType: "megaMenu",
684
+ subFieldState: {
685
+ ...Object.fromEntries(Object.entries(destinationOf(current)).map(([key, value]) => [key, {
686
+ value,
687
+ valid: true
688
+ }])),
689
+ panel: {
690
+ value: emptyPanel(),
691
+ valid: true
692
+ }
693
+ }
694
+ });
695
+ }
696
+ function requestType(next) {
697
+ if (!current || current.blockType === next) return;
698
+ if (current.blockType === "megaMenu" && next === "navLink") {
699
+ setConfirmSwitch(true);
700
+ return;
701
+ }
702
+ switchToMega();
703
+ }
704
+ function setRow(name, value) {
705
+ itemsField.setValue(items.map((row, i) => i === selected ? {
706
+ ...row,
707
+ [name]: value
708
+ } : row));
709
+ }
710
+ function setPanel(patch) {
711
+ if (current?.blockType !== "megaMenu") return;
712
+ setRow("panel", {
713
+ ...current.panel ?? emptyPanel(),
714
+ ...patch
715
+ });
716
+ }
717
+ function setColumns(columns) {
718
+ setPanel({ columns: columns.map((column, i) => i === 0 ? {
719
+ ...column,
720
+ divider: false
721
+ } : column) });
722
+ }
723
+ function onPreviewClick(event) {
724
+ const target = event.target;
725
+ const label = target.closest("[data-preview-item]")?.getAttribute("data-preview-item") ?? items.find((row) => row.label && target.textContent?.includes(row.label))?.label;
726
+ if (!label) return;
727
+ const index = items.findIndex((row) => row.label === label);
728
+ if (index >= 0) setSelected(index);
729
+ }
730
+ const [themeCss, setThemeCss] = useState("");
731
+ useEffect(() => {
732
+ let cancelled = false;
733
+ fetch(`${endpoint}/globals/theme?depth=1`, { credentials: "include" }).then((response) => response.ok ? response.json() : null).then((doc) => {
734
+ if (cancelled || !doc) return;
735
+ setThemeCss(scopeThemeCss(themeHeadFromDoc(doc, THEME_SEED).css));
736
+ }).catch(() => void 0);
737
+ return () => {
738
+ cancelled = true;
739
+ };
740
+ }, [endpoint]);
741
+ return /* @__PURE__ */ jsxs("div", {
742
+ className: "bl-nav-items field-type",
743
+ children: [
744
+ /* @__PURE__ */ jsx("style", {
745
+ href: "bl-nav-items",
746
+ precedence: "default",
747
+ children: CSS
748
+ }),
749
+ themeCss ? /* @__PURE__ */ jsx("style", {
750
+ href: "bl-nav-items-theme",
751
+ precedence: "default",
752
+ children: themeCss
753
+ }) : null,
754
+ /* @__PURE__ */ jsxs("aside", {
755
+ className: "bl-nav-items__rail",
756
+ children: [
757
+ /* @__PURE__ */ jsxs("div", {
758
+ className: "bl-nav-items__rail-head",
759
+ children: [/* @__PURE__ */ jsx("p", {
760
+ className: "bl-nav-items__kicker",
761
+ children: "Header navigation"
762
+ }), /* @__PURE__ */ jsx("h2", { children: "Menu items" })]
763
+ }),
764
+ /* @__PURE__ */ jsx("ul", {
765
+ className: "bl-nav-items__list",
766
+ "aria-label": "Menu items",
767
+ children: items.map((row, index) => /* @__PURE__ */ jsxs("li", {
768
+ "data-selected": index === selected ? "true" : "false",
769
+ children: [/* @__PURE__ */ jsxs("div", {
770
+ className: "bl-nav-items__rail-row",
771
+ children: [
772
+ /* @__PURE__ */ jsx("span", {
773
+ className: "bl-nav-items__badge",
774
+ "data-kind": row.blockType,
775
+ "aria-hidden": true,
776
+ children: row.blockType === "megaMenu" ? /* @__PURE__ */ jsx(MegaGlyph, {}) : /* @__PURE__ */ jsx(LinkGlyph, {})
777
+ }),
778
+ /* @__PURE__ */ jsx("button", {
779
+ type: "button",
780
+ className: "bl-nav-items__rail-label",
781
+ onClick: () => setSelected(index),
782
+ children: row.label || "Untitled"
783
+ }),
784
+ readOnly ? null : /* @__PURE__ */ jsxs("div", {
785
+ className: "bl-nav-items__menu",
786
+ children: [/* @__PURE__ */ jsx("button", {
787
+ type: "button",
788
+ "aria-label": `${row.label || "Item"} actions`,
789
+ onClick: () => setMenu(menu === index ? null : index),
790
+ children: "⋯"
791
+ }), menu === index ? /* @__PURE__ */ jsxs("div", {
792
+ className: "bl-nav-items__menu-pop",
793
+ children: [
794
+ /* @__PURE__ */ jsx("button", {
795
+ type: "button",
796
+ disabled: index === 0,
797
+ onClick: () => {
798
+ moveFieldRow({
799
+ path,
800
+ moveFromIndex: index,
801
+ moveToIndex: index - 1
802
+ });
803
+ setSelected(index - 1);
804
+ setMenu(null);
805
+ },
806
+ children: "Move up"
807
+ }),
808
+ /* @__PURE__ */ jsx("button", {
809
+ type: "button",
810
+ disabled: index === items.length - 1,
811
+ onClick: () => {
812
+ moveFieldRow({
813
+ path,
814
+ moveFromIndex: index,
815
+ moveToIndex: index + 1
816
+ });
817
+ setSelected(index + 1);
818
+ setMenu(null);
819
+ },
820
+ children: "Move down"
821
+ }),
822
+ /* @__PURE__ */ jsx("button", {
823
+ type: "button",
824
+ className: "bl-nav-kit__danger",
825
+ onClick: () => {
826
+ removeFieldRow({
827
+ path,
828
+ rowIndex: index
829
+ });
830
+ setMenu(null);
831
+ },
832
+ children: "Delete"
833
+ })
834
+ ]
835
+ }) : null]
836
+ })
837
+ ]
838
+ }), index === selected ? /* @__PURE__ */ jsxs("div", {
839
+ className: "bl-nav-items__rail-edit",
840
+ children: [/* @__PURE__ */ jsxs(TypeCards, {
841
+ compact: true,
842
+ children: [/* @__PURE__ */ jsx(TypeCard, {
843
+ icon: /* @__PURE__ */ jsx(LinkGlyph, {}),
844
+ label: "Link",
845
+ onClick: () => requestType("navLink")
846
+ }), /* @__PURE__ */ jsx(TypeCard, {
847
+ icon: /* @__PURE__ */ jsx(MegaGlyph, {}),
848
+ label: "Mega",
849
+ onClick: () => requestType("megaMenu")
850
+ })]
851
+ }), /* @__PURE__ */ jsx(ItemBasics, {
852
+ path,
853
+ index,
854
+ readOnly
855
+ })]
856
+ }) : null]
857
+ }, String(row.id ?? index)))
858
+ }),
859
+ readOnly ? null : /* @__PURE__ */ jsx("button", {
860
+ type: "button",
861
+ className: "bl-nav-items__add",
862
+ onClick: () => setAdding(true),
863
+ children: "Add item"
864
+ })
865
+ ]
866
+ }),
867
+ /* @__PURE__ */ jsxs("div", {
868
+ className: "bl-nav-items__main",
869
+ children: [
870
+ /* @__PURE__ */ jsx("div", {
871
+ className: "bl-nav-items__sentinel",
872
+ "data-testid": "nav-items-preview-sentinel",
873
+ ref: sentinel,
874
+ "aria-hidden": true
875
+ }),
876
+ /* @__PURE__ */ jsx("div", {
877
+ "data-preview-chrome": true,
878
+ "data-sticky": "true",
879
+ className: "bl-nav-items__preview",
880
+ onClick: onPreviewClick,
881
+ children: /* @__PURE__ */ jsx(FloatingNavBlock, {
882
+ items: previewItems,
883
+ hideOnScroll: false,
884
+ breakpoint: "lg",
885
+ openItem,
886
+ className: "bl-nav-items__bar"
887
+ })
888
+ }),
889
+ current?.blockType === "megaMenu" ? /* @__PURE__ */ jsx(MegaEditor, {
890
+ path,
891
+ index: selected,
892
+ panel: current.panel ?? emptyPanel(),
893
+ readOnly: Boolean(readOnly),
894
+ onColumns: setColumns,
895
+ onPanel: setPanel
896
+ }) : current ? /* @__PURE__ */ jsx("p", {
897
+ className: "bl-nav-items__empty",
898
+ children: "A plain link is edited in the rail: label, destination, and new tab."
899
+ }) : /* @__PURE__ */ jsx("p", {
900
+ className: "bl-nav-items__empty",
901
+ children: "Add a link or a mega menu to start the header."
902
+ })
903
+ ]
904
+ }),
905
+ adding ? /* @__PURE__ */ jsx("div", {
906
+ className: "bl-nav-kit__modal",
907
+ role: "dialog",
908
+ "aria-labelledby": "bl-nav-add-title",
909
+ children: /* @__PURE__ */ jsxs("div", {
910
+ className: "bl-nav-kit__modal-card",
911
+ children: [
912
+ /* @__PURE__ */ jsx("h2", {
913
+ id: "bl-nav-add-title",
914
+ children: "Add menu item"
915
+ }),
916
+ /* @__PURE__ */ jsxs(TypeCards, { children: [/* @__PURE__ */ jsx(TypeCard, {
917
+ icon: /* @__PURE__ */ jsx(LinkGlyph, {}),
918
+ label: "Plain link",
919
+ description: "A bar item that goes to a page or URL.",
920
+ onClick: () => add("navLink")
921
+ }), /* @__PURE__ */ jsx(TypeCard, {
922
+ icon: /* @__PURE__ */ jsx(MegaGlyph, {}),
923
+ label: "Mega menu",
924
+ description: "A dropdown of columns, sections, and an optional footer.",
925
+ onClick: () => add("megaMenu")
926
+ })] }),
927
+ /* @__PURE__ */ jsx("button", {
928
+ type: "button",
929
+ className: "bl-nav-items__add",
930
+ onClick: () => setAdding(false),
931
+ children: "Cancel"
932
+ })
933
+ ]
934
+ })
935
+ }) : null,
936
+ /* @__PURE__ */ jsx(ConfirmDialog, {
937
+ open: confirmSwitch,
938
+ title: "Switch to a plain link?",
939
+ cancelLabel: "Keep mega menu",
940
+ confirmLabel: "Switch to link",
941
+ onCancel: () => setConfirmSwitch(false),
942
+ onConfirm: switchToLink,
943
+ children: "This drops the columns, sections, and footer. The label and destination stay."
944
+ })
945
+ ]
946
+ });
947
+ };
948
+ function ItemBasics({ path, index, readOnly }) {
949
+ const label = useField({ path: `${path}.${index}.label` });
950
+ const newTab = useField({ path: `${path}.${index}.newTab` });
951
+ return /* @__PURE__ */ jsxs("div", {
952
+ className: "bl-nav-items__basics",
953
+ children: [
954
+ /* @__PURE__ */ jsxs("label", {
955
+ className: "bl-nav-items__field",
956
+ children: [/* @__PURE__ */ jsx("span", { children: "Label" }), /* @__PURE__ */ jsx("input", {
957
+ value: label.value ?? "",
958
+ disabled: readOnly,
959
+ onChange: (event) => label.setValue(event.target.value)
960
+ })]
961
+ }),
962
+ /* @__PURE__ */ jsx(ComposedLinkField, {
963
+ path: `${path}.${index}._index-0`,
964
+ parentPath: `${path}.${index}`,
965
+ readOnly
966
+ }),
967
+ /* @__PURE__ */ jsxs("label", {
968
+ className: "bl-nav-items__check",
969
+ children: [/* @__PURE__ */ jsx("input", {
970
+ type: "checkbox",
971
+ checked: Boolean(newTab.value),
972
+ disabled: readOnly,
973
+ onChange: (event) => newTab.setValue(event.target.checked)
974
+ }), "Open in a new tab"]
975
+ })
976
+ ]
977
+ });
978
+ }
979
+ function MegaEditor({ path, index, panel, readOnly, onColumns, onPanel }) {
980
+ const columns = panel.columns ?? [];
981
+ const columnsError = useField({ path: `${path}.${index}.panel.columns` });
982
+ return /* @__PURE__ */ jsxs("div", {
983
+ className: "bl-nav-items__mega",
984
+ children: [
985
+ /* @__PURE__ */ jsxs("label", {
986
+ className: "bl-nav-items__field",
987
+ children: [/* @__PURE__ */ jsx("span", { children: "Dropdown width" }), /* @__PURE__ */ jsxs("select", {
988
+ value: panel.maxWidth ?? "standard",
989
+ disabled: readOnly,
990
+ onChange: (event) => onPanel({ maxWidth: event.target.value }),
991
+ children: [
992
+ /* @__PURE__ */ jsx("option", {
993
+ value: "narrow",
994
+ children: "Narrow"
995
+ }),
996
+ /* @__PURE__ */ jsx("option", {
997
+ value: "standard",
998
+ children: "Standard"
999
+ }),
1000
+ /* @__PURE__ */ jsx("option", {
1001
+ value: "wide",
1002
+ children: "Wide"
1003
+ })
1004
+ ]
1005
+ })]
1006
+ }),
1007
+ /* @__PURE__ */ jsx("div", {
1008
+ className: "bl-nav-items__columns",
1009
+ "data-testid": "nav-items-columns",
1010
+ style: { gridTemplateColumns: "repeat(2, minmax(0, 1fr))" },
1011
+ children: columns.map((column, columnIndex) => /* @__PURE__ */ jsxs("fieldset", {
1012
+ className: "bl-nav-items__column",
1013
+ "aria-label": `Column ${columnIndex + 1}`,
1014
+ children: [
1015
+ /* @__PURE__ */ jsxs("legend", { children: ["Column ", columnIndex + 1] }),
1016
+ /* @__PURE__ */ jsxs("div", {
1017
+ className: "bl-nav-items__column-settings",
1018
+ children: [/* @__PURE__ */ jsxs("label", {
1019
+ className: "bl-nav-items__field",
1020
+ children: [/* @__PURE__ */ jsx("span", { children: "Width" }), /* @__PURE__ */ jsx("select", {
1021
+ value: column.width ?? "100",
1022
+ disabled: readOnly,
1023
+ onChange: (event) => onColumns(columns.map((row, i) => i === columnIndex ? {
1024
+ ...row,
1025
+ width: event.target.value
1026
+ } : row)),
1027
+ children: WIDTHS.map((width) => /* @__PURE__ */ jsxs("option", {
1028
+ value: width,
1029
+ children: [width, "%"]
1030
+ }, width))
1031
+ })]
1032
+ }), columnIndex > 0 ? /* @__PURE__ */ jsxs("label", {
1033
+ className: "bl-nav-items__check",
1034
+ children: [/* @__PURE__ */ jsx("input", {
1035
+ type: "checkbox",
1036
+ checked: Boolean(column.divider),
1037
+ disabled: readOnly,
1038
+ onChange: (event) => onColumns(columns.map((row, i) => i === columnIndex ? {
1039
+ ...row,
1040
+ divider: event.target.checked
1041
+ } : row))
1042
+ }), "Draw a line on the left of this column"]
1043
+ }) : null]
1044
+ }),
1045
+ (column.sections ?? []).map((section, sectionIndex) => /* @__PURE__ */ jsx(SectionEditor, {
1046
+ path,
1047
+ itemIndex: index,
1048
+ columnIndex,
1049
+ sectionIndex,
1050
+ section,
1051
+ readOnly,
1052
+ onChange: (next) => onColumns(columns.map((row, i) => i === columnIndex ? {
1053
+ ...row,
1054
+ sections: (row.sections ?? []).map((entry, j) => j === sectionIndex ? next : entry)
1055
+ } : row))
1056
+ }, sectionIndex)),
1057
+ readOnly || (column.sections?.length ?? 0) >= 8 ? null : /* @__PURE__ */ jsx("button", {
1058
+ type: "button",
1059
+ className: "bl-nav-items__add",
1060
+ onClick: () => onColumns(columns.map((row, i) => i === columnIndex ? {
1061
+ ...row,
1062
+ sections: [...row.sections ?? [], emptySection()]
1063
+ } : row)),
1064
+ children: "Add section"
1065
+ })
1066
+ ]
1067
+ }, columnIndex))
1068
+ }),
1069
+ readOnly || columns.length >= 4 ? null : /* @__PURE__ */ jsx("button", {
1070
+ type: "button",
1071
+ className: "bl-nav-items__add",
1072
+ onClick: () => onColumns([...columns, {
1073
+ ...emptyColumn(),
1074
+ width: "25"
1075
+ }]),
1076
+ children: "Add column"
1077
+ }),
1078
+ /* @__PURE__ */ jsx(FieldError, {
1079
+ path: columnsError.path,
1080
+ showError: columnsError.showError,
1081
+ message: columnsError.errorMessage
1082
+ }),
1083
+ /* @__PURE__ */ jsxs("div", {
1084
+ className: "bl-nav-items__footer",
1085
+ children: [/* @__PURE__ */ jsx("h3", { children: "Footer" }), /* @__PURE__ */ jsxs("div", {
1086
+ className: "bl-nav-items__footer-grid",
1087
+ children: [/* @__PURE__ */ jsxs("div", { children: [
1088
+ /* @__PURE__ */ jsx("h4", { children: "Overview link" }),
1089
+ /* @__PURE__ */ jsx(ComposedLinkField, {
1090
+ path: `${path}.${index}.panel.footer.overview._index-0`,
1091
+ parentPath: `${path}.${index}.panel.footer.overview`,
1092
+ readOnly
1093
+ }),
1094
+ /* @__PURE__ */ jsxs("label", {
1095
+ className: "bl-nav-items__field",
1096
+ children: [/* @__PURE__ */ jsx("span", { children: "Label" }), /* @__PURE__ */ jsx(FooterText, {
1097
+ path: `${path}.${index}.panel.footer.overview.label`,
1098
+ readOnly
1099
+ })]
1100
+ })
1101
+ ] }), /* @__PURE__ */ jsxs("div", { children: [
1102
+ /* @__PURE__ */ jsx("h4", { children: "Call to action" }),
1103
+ /* @__PURE__ */ jsx(ComposedLinkField, {
1104
+ path: `${path}.${index}.panel.footer.cta._index-0`,
1105
+ parentPath: `${path}.${index}.panel.footer.cta`,
1106
+ readOnly
1107
+ }),
1108
+ /* @__PURE__ */ jsxs("label", {
1109
+ className: "bl-nav-items__field",
1110
+ children: [/* @__PURE__ */ jsx("span", { children: "Label" }), /* @__PURE__ */ jsx(FooterText, {
1111
+ path: `${path}.${index}.panel.footer.cta.label`,
1112
+ readOnly
1113
+ })]
1114
+ })
1115
+ ] })]
1116
+ })]
1117
+ })
1118
+ ]
1119
+ });
1120
+ }
1121
+ function FooterText({ path, readOnly }) {
1122
+ const field = useField({ path });
1123
+ return /* @__PURE__ */ jsx("input", {
1124
+ value: field.value ?? "",
1125
+ disabled: readOnly,
1126
+ onChange: (event) => field.setValue(event.target.value)
1127
+ });
1128
+ }
1129
+ function SectionEditor({ path, itemIndex, columnIndex, sectionIndex, section, readOnly, onChange }) {
1130
+ const links = section.links ?? [];
1131
+ return /* @__PURE__ */ jsxs("div", {
1132
+ className: "bl-nav-items__section",
1133
+ children: [
1134
+ /* @__PURE__ */ jsxs("label", {
1135
+ className: "bl-nav-items__field",
1136
+ children: [/* @__PURE__ */ jsx("span", { children: "Eyebrow" }), /* @__PURE__ */ jsx("input", {
1137
+ value: section.eyebrow ?? "",
1138
+ disabled: readOnly,
1139
+ onChange: (event) => onChange({
1140
+ ...section,
1141
+ eyebrow: event.target.value
1142
+ })
1143
+ })]
1144
+ }),
1145
+ /* @__PURE__ */ jsxs(TypeCards, {
1146
+ compact: true,
1147
+ children: [/* @__PURE__ */ jsx(TypeCard, {
1148
+ label: "Featured",
1149
+ active: section.display === "featured",
1150
+ disabled: readOnly,
1151
+ onClick: () => onChange({
1152
+ ...section,
1153
+ display: "featured"
1154
+ })
1155
+ }), /* @__PURE__ */ jsx(TypeCard, {
1156
+ label: "List",
1157
+ active: section.display !== "featured",
1158
+ disabled: readOnly,
1159
+ onClick: () => onChange({
1160
+ ...section,
1161
+ display: "list"
1162
+ })
1163
+ })]
1164
+ }),
1165
+ /* @__PURE__ */ jsxs("label", {
1166
+ className: "bl-nav-items__check",
1167
+ children: [/* @__PURE__ */ jsx("input", {
1168
+ type: "checkbox",
1169
+ checked: section.hideDescriptionsOnMobile !== false,
1170
+ disabled: readOnly,
1171
+ onChange: (event) => onChange({
1172
+ ...section,
1173
+ hideDescriptionsOnMobile: event.target.checked
1174
+ })
1175
+ }), "Hide descriptions on mobile"]
1176
+ }),
1177
+ links.map((link, linkIndex) => /* @__PURE__ */ jsxs("div", {
1178
+ className: "bl-nav-items__link",
1179
+ children: [/* @__PURE__ */ jsxs("label", {
1180
+ className: "bl-nav-items__field",
1181
+ children: [/* @__PURE__ */ jsx("span", { children: "Label" }), /* @__PURE__ */ jsx("input", {
1182
+ value: String(link.label ?? ""),
1183
+ disabled: readOnly,
1184
+ onChange: (event) => onChange({
1185
+ ...section,
1186
+ links: links.map((row, i) => i === linkIndex ? {
1187
+ ...row,
1188
+ label: event.target.value
1189
+ } : row)
1190
+ })
1191
+ })]
1192
+ }), /* @__PURE__ */ jsx(ComposedLinkField, {
1193
+ path: `${path}.${itemIndex}.panel.columns.${columnIndex}.sections.${sectionIndex}.links.${linkIndex}._index-0`,
1194
+ parentPath: `${path}.${itemIndex}.panel.columns.${columnIndex}.sections.${sectionIndex}.links.${linkIndex}`,
1195
+ readOnly
1196
+ })]
1197
+ }, linkIndex)),
1198
+ readOnly ? null : /* @__PURE__ */ jsx("button", {
1199
+ type: "button",
1200
+ className: "bl-nav-items__add",
1201
+ onClick: () => onChange({
1202
+ ...section,
1203
+ links: [...links, {
1204
+ label: "New link",
1205
+ type: "page",
1206
+ page: null,
1207
+ href: null
1208
+ }]
1209
+ }),
1210
+ children: "Add link"
1211
+ })
1212
+ ]
1213
+ });
1214
+ }
1215
+ const CSS = `
1216
+ .bl-nav-items{display:grid;grid-template-columns:minmax(16rem,20rem) minmax(0,1fr);gap:0;border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-elevation-0);color:var(--theme-elevation-800);font-family:var(--font-body)}
1217
+ .bl-nav-items__rail{border-right:1px solid var(--theme-elevation-150);padding:1rem;min-width:0}
1218
+ .bl-nav-items__rail-head h2{margin:.15rem 0 0;font-size:14px}
1219
+ .bl-nav-items__kicker{margin:0;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--theme-elevation-500)}
1220
+ .bl-nav-items__list{list-style:none;margin:0;padding:0}
1221
+ .bl-nav-items__list li{border:1px solid transparent;border-radius:8px;margin:.4rem 0}
1222
+ .bl-nav-items__list li[data-selected="true"]{border-color:var(--theme-elevation-250);background:var(--theme-elevation-50)}
1223
+ .bl-nav-items__rail-row{display:grid;grid-template-columns:28px 1fr auto;gap:.5rem;align-items:center;padding:.5rem}
1224
+ .bl-nav-items__rail-label{border:0;background:transparent;text-align:left;font:inherit;font-weight:650;color:inherit;cursor:pointer;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
1225
+ .bl-nav-items__badge{width:28px;height:28px;display:grid;place-items:center;border-radius:7px;background:var(--theme-elevation-100);color:var(--theme-elevation-600)}
1226
+ .bl-nav-items__badge[data-kind="megaMenu"]{background:color-mix(in srgb,var(--brand-primary,var(--theme-success-500)) 16%,var(--theme-elevation-50));color:var(--brand-primary,var(--theme-success-500))}
1227
+ .bl-nav-items__rail-edit{padding:0 .6rem .75rem}
1228
+ .bl-nav-items__add{width:100%;margin-top:.6rem;border:1px dashed var(--theme-elevation-250);background:transparent;border-radius:8px;padding:.65rem;color:var(--theme-elevation-700);cursor:pointer}
1229
+ .bl-nav-items__main{min-width:0;padding:1rem 1.25rem 2rem}
1230
+ .bl-nav-items__sentinel{height:1px}
1231
+ .bl-nav-items__preview{position:sticky;top:0;z-index:5;background:var(--theme-elevation-0);padding:.75rem 0 1rem}
1232
+ .bl-nav-items__bar{position:relative !important;inset:auto !important;pointer-events:auto !important;transform:none !important}
1233
+ .bl-nav-items__columns{display:grid;gap:.75rem;align-items:start}
1234
+ .bl-nav-items__column{border:1px solid var(--theme-elevation-150);border-radius:10px;padding:.75rem;margin:0;min-width:0}
1235
+ .bl-nav-items__column legend{font-weight:700;padding:0 .25rem}
1236
+ .bl-nav-items__column-settings{display:grid;grid-template-columns:1fr auto;gap:.6rem;align-items:end;margin-bottom:.75rem}
1237
+ .bl-nav-items__field{display:flex;flex-direction:column;gap:.35rem;font-size:12px;font-weight:700;margin:.5rem 0}
1238
+ .bl-nav-items__field input,.bl-nav-items__field select{font:inherit;font-weight:400;padding:.5rem .6rem;border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-input-bg);color:inherit}
1239
+ .bl-nav-items__check{display:flex;align-items:center;gap:.5rem;font-size:13px;font-weight:500}
1240
+ .bl-nav-items__section,.bl-nav-items__link{border:1px solid var(--theme-elevation-100);border-radius:8px;padding:.6rem;margin:.5rem 0}
1241
+ .bl-nav-items__footer{margin-top:1.25rem;border:1px solid var(--theme-elevation-150);border-radius:10px;padding:1rem}
1242
+ .bl-nav-items__footer-grid{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
1243
+ .bl-nav-items__empty{color:var(--theme-elevation-500)}
1244
+ .bl-nav-items__menu{position:relative}
1245
+ .bl-nav-items__menu > button{border:0;background:transparent;color:inherit;cursor:pointer}
1246
+ .bl-nav-items__menu-pop{position:absolute;right:0;top:1.4rem;z-index:6;min-width:8rem;padding:.2rem;border:1px solid var(--theme-elevation-150);border-radius:8px;background:var(--theme-elevation-0);box-shadow:0 8px 24px var(--theme-overlay)}
1247
+ .bl-nav-items__menu-pop button{display:block;width:100%;text-align:left;border:0;background:transparent;padding:.4rem .5rem;border-radius:6px;color:inherit;cursor:pointer}
1248
+ @media(max-width:800px){.bl-nav-items{grid-template-columns:1fr}.bl-nav-items__footer-grid,.bl-nav-items__columns{grid-template-columns:minmax(0,1fr) !important}}
1249
+ `;
1250
+ //#endregion
1251
+ export { LinkField, MinRowsArrayField, NavItemsField };
439
1252
 
440
1253
  //# sourceMappingURL=admin.mjs.map