@bison-lab/payload-blocks 3.1.0 → 3.3.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/README.md +150 -1
- package/dist/index.d.mts +139 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +632 -6
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +123 -7
- package/dist/react.d.mts.map +1 -1
- package/dist/react.mjs +312 -72
- package/dist/react.mjs.map +1 -1
- package/dist/rich-text.d.mts +3 -1
- package/dist/rich-text.d.mts.map +1 -1
- package/dist/rich-text.mjs +12 -6
- package/dist/rich-text.mjs.map +1 -1
- package/dist/seam-BDFZlV3F.mjs +54 -0
- package/dist/seam-BDFZlV3F.mjs.map +1 -0
- package/dist/{types-BBumyFd-.d.mts → types-D9rg0BoW.d.mts} +132 -8
- package/dist/types-D9rg0BoW.d.mts.map +1 -0
- package/package.json +2 -2
- package/dist/cx-BKHSv3xT.mjs +0 -17
- package/dist/cx-BKHSv3xT.mjs.map +0 -1
- package/dist/types-BBumyFd-.d.mts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -323,21 +323,27 @@ const ProcessStepsBlock = {
|
|
|
323
323
|
* puts the least-optional copy behind a click. The field names match the
|
|
324
324
|
* `@bison-lab/ui` prop names so the renderers stay a pass-through.
|
|
325
325
|
*/
|
|
326
|
-
function headingFields({ required = true, eyebrowDescription = "Small label above the heading. Leave empty to hide the row." } = {}) {
|
|
326
|
+
function headingFields({ required = true, eyebrowDescription = "Small label above the heading. Leave empty to hide the row.", condition } = {}) {
|
|
327
|
+
const when = condition ? { condition } : {};
|
|
327
328
|
return [
|
|
328
329
|
{
|
|
329
330
|
name: "eyebrow",
|
|
330
331
|
type: "text",
|
|
331
|
-
admin: {
|
|
332
|
+
admin: {
|
|
333
|
+
description: eyebrowDescription,
|
|
334
|
+
...when
|
|
335
|
+
}
|
|
332
336
|
},
|
|
333
337
|
{
|
|
334
338
|
name: "title",
|
|
335
339
|
type: "text",
|
|
336
|
-
required
|
|
340
|
+
required,
|
|
341
|
+
admin: when
|
|
337
342
|
},
|
|
338
343
|
{
|
|
339
344
|
name: "description",
|
|
340
|
-
type: "textarea"
|
|
345
|
+
type: "textarea",
|
|
346
|
+
admin: when
|
|
341
347
|
}
|
|
342
348
|
];
|
|
343
349
|
}
|
|
@@ -641,6 +647,442 @@ const NapBlock = {
|
|
|
641
647
|
]
|
|
642
648
|
};
|
|
643
649
|
//#endregion
|
|
650
|
+
//#region src/fields/row-limits.ts
|
|
651
|
+
/**
|
|
652
|
+
* A custom `validate` replaces Payload's stock array check, so any array
|
|
653
|
+
* with its own rule re-applies the row limits first or `minRows` and
|
|
654
|
+
* `maxRows` stop being enforced. Same messages as the stock check, through
|
|
655
|
+
* the request's translator when the admin supplies one.
|
|
656
|
+
*/
|
|
657
|
+
function rowLimits(value, { minRows, maxRows, required, req }) {
|
|
658
|
+
const count = value?.length ?? 0;
|
|
659
|
+
const t = req?.t;
|
|
660
|
+
if (required && count === 0) return t ? t("validation:required") : "This field is required.";
|
|
661
|
+
if (minRows && count < minRows) return t ? t("validation:requiresAtLeast", {
|
|
662
|
+
count: minRows,
|
|
663
|
+
label: t("general:rows")
|
|
664
|
+
}) : `This field requires at least ${minRows} rows.`;
|
|
665
|
+
if (maxRows && count > maxRows) return t ? t("validation:requiresNoMoreThan", {
|
|
666
|
+
count: maxRows,
|
|
667
|
+
label: t("general:rows")
|
|
668
|
+
}) : `This field requires no more than ${maxRows} rows.`;
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
//#endregion
|
|
672
|
+
//#region src/blocks/stats-band/config.ts
|
|
673
|
+
/**
|
|
674
|
+
* The rule on `wide`: on phones the band is two per row, so only an odd
|
|
675
|
+
* count has a stat on a row of its own, only one stat can take it, and it
|
|
676
|
+
* has to be a stat that starts a row (the 1st, 3rd or 5th), since a full-row
|
|
677
|
+
* cell beside another cell would leave a hole. The array's own `validate`,
|
|
678
|
+
* so the editor sees the message as they build, and Payload runs it again on
|
|
679
|
+
* publish.
|
|
680
|
+
*/
|
|
681
|
+
const validateWideFlag = (value, options) => {
|
|
682
|
+
const limits = rowLimits(value, options);
|
|
683
|
+
if (limits !== true) return limits;
|
|
684
|
+
const rows = value ?? [];
|
|
685
|
+
const wide = rows.flatMap((row, i) => row?.wide ? [i] : []);
|
|
686
|
+
if (wide.length > 1) return "Only one stat can be full width on phones.";
|
|
687
|
+
if (wide.length === 0) return true;
|
|
688
|
+
if (rows.length % 2 === 0) return "Full width on phones only applies to an odd number of stats. With an even count every row is already full.";
|
|
689
|
+
if (wide[0] % 2 !== 0) return "Only a stat that starts a phone row can be full width: the 1st, 3rd or 5th. Move it up or down one place, or flag another.";
|
|
690
|
+
return true;
|
|
691
|
+
};
|
|
692
|
+
/**
|
|
693
|
+
* An overlapping band is headless: it floats across the seam as a card, and a
|
|
694
|
+
* heading pulled up into the block above would land on the wrong surface.
|
|
695
|
+
* The heading fields disappear from the admin the moment `overlap` is on,
|
|
696
|
+
* and the renderer ignores them if they were filled in first.
|
|
697
|
+
*/
|
|
698
|
+
const unlessOverlap = (_data, siblingData) => !siblingData?.overlap;
|
|
699
|
+
/**
|
|
700
|
+
* A strip of figures: the facts a visitor should take in at a glance.
|
|
701
|
+
*
|
|
702
|
+
* The count, the order and the desktop column count are the editor's. The
|
|
703
|
+
* phone and tablet layouts are the library's: two per row and three per row,
|
|
704
|
+
* with `wide` naming the one stat that takes a full phone row when the count
|
|
705
|
+
* is odd.
|
|
706
|
+
*/
|
|
707
|
+
const StatsBandBlock = {
|
|
708
|
+
slug: "statsBand",
|
|
709
|
+
interfaceName: "StatsBandBlock",
|
|
710
|
+
labels: {
|
|
711
|
+
singular: "Stats Band",
|
|
712
|
+
plural: "Stats Bands"
|
|
713
|
+
},
|
|
714
|
+
fields: [
|
|
715
|
+
...headingFields({
|
|
716
|
+
required: false,
|
|
717
|
+
eyebrowDescription: "Small label above the heading. The heading and eyebrow are optional; without them the band stands alone.",
|
|
718
|
+
condition: unlessOverlap
|
|
719
|
+
}),
|
|
720
|
+
{
|
|
721
|
+
name: "items",
|
|
722
|
+
type: "array",
|
|
723
|
+
required: true,
|
|
724
|
+
minRows: 2,
|
|
725
|
+
maxRows: 6,
|
|
726
|
+
defaultValue: emptyRows(2),
|
|
727
|
+
labels: {
|
|
728
|
+
singular: "Stat",
|
|
729
|
+
plural: "Stats"
|
|
730
|
+
},
|
|
731
|
+
admin: { components: { Field: MIN_ROWS_ARRAY_FIELD } },
|
|
732
|
+
validate: validateWideFlag,
|
|
733
|
+
fields: [
|
|
734
|
+
{
|
|
735
|
+
name: "value",
|
|
736
|
+
type: "text",
|
|
737
|
+
required: true,
|
|
738
|
+
admin: { description: "The figure, as it should read: \"98%\", \"12,000+\", \"L1–S1\"." }
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
name: "label",
|
|
742
|
+
type: "textarea",
|
|
743
|
+
required: true
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
name: "href",
|
|
747
|
+
type: "text",
|
|
748
|
+
admin: { description: "Optional. Makes the whole stat a link: a site path (\"/outcomes\") or a full URL." }
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
name: "wide",
|
|
752
|
+
type: "checkbox",
|
|
753
|
+
label: "Full width on phones",
|
|
754
|
+
defaultValue: false,
|
|
755
|
+
admin: { description: "Phones show two per row. With an odd number of stats, this one takes a row to itself. Only the 1st, 3rd or 5th stat can." }
|
|
756
|
+
}
|
|
757
|
+
]
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
name: "columns",
|
|
761
|
+
type: "select",
|
|
762
|
+
defaultValue: "4",
|
|
763
|
+
options: [
|
|
764
|
+
{
|
|
765
|
+
label: "2",
|
|
766
|
+
value: "2"
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
label: "3",
|
|
770
|
+
value: "3"
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
label: "4",
|
|
774
|
+
value: "4"
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
label: "5",
|
|
778
|
+
value: "5"
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
label: "6",
|
|
782
|
+
value: "6"
|
|
783
|
+
}
|
|
784
|
+
],
|
|
785
|
+
admin: { description: "From large screens up, and never more than there are stats. Phones show two per row and tablets three." }
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
name: "tone",
|
|
789
|
+
type: "select",
|
|
790
|
+
defaultValue: "card",
|
|
791
|
+
options: [{
|
|
792
|
+
label: "Card (bordered, raised)",
|
|
793
|
+
value: "card"
|
|
794
|
+
}, {
|
|
795
|
+
label: "Plain (dividers only)",
|
|
796
|
+
value: "plain"
|
|
797
|
+
}]
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "align",
|
|
801
|
+
type: "select",
|
|
802
|
+
defaultValue: "start",
|
|
803
|
+
options: [{
|
|
804
|
+
label: "Left",
|
|
805
|
+
value: "start"
|
|
806
|
+
}, {
|
|
807
|
+
label: "Centred",
|
|
808
|
+
value: "center"
|
|
809
|
+
}]
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
name: "overlap",
|
|
813
|
+
type: "checkbox",
|
|
814
|
+
label: "Float over the seam with the block above",
|
|
815
|
+
defaultValue: false,
|
|
816
|
+
admin: { description: "The band sits across the join between the block above and the block below. Both make room for it automatically. A floating band is headless: the heading fields above are hidden while this is on." }
|
|
817
|
+
}
|
|
818
|
+
]
|
|
819
|
+
};
|
|
820
|
+
//#endregion
|
|
821
|
+
//#region src/blocks/mega-menu/rem-width.ts
|
|
822
|
+
/**
|
|
823
|
+
* The one rule for a typed panel width, shared by the config's validator and
|
|
824
|
+
* the renderer's reader so the two cannot drift: if the validator accepted a
|
|
825
|
+
* value the renderer dropped, the editor would be back to a width that
|
|
826
|
+
* silently does nothing. React-free, because `config.ts` ships from the Node
|
|
827
|
+
* entry.
|
|
828
|
+
*/
|
|
829
|
+
const REM_WIDTH = /^\s*(\d+(?:\.\d+)?)\s*(rem)?\s*$/;
|
|
830
|
+
/** "30" and "30rem" both mean 30rem; anything else is not a width. */
|
|
831
|
+
function remWidth(value) {
|
|
832
|
+
const match = REM_WIDTH.exec(value ?? "");
|
|
833
|
+
return match ? `${Number(match[1])}rem` : null;
|
|
834
|
+
}
|
|
835
|
+
//#endregion
|
|
836
|
+
//#region src/blocks/mega-menu/config.ts
|
|
837
|
+
/** The percent tokens a column can take, as Payload stores them. */
|
|
838
|
+
const MEGA_MENU_WIDTHS = [
|
|
839
|
+
"25",
|
|
840
|
+
"33",
|
|
841
|
+
"50",
|
|
842
|
+
"66",
|
|
843
|
+
"75",
|
|
844
|
+
"100"
|
|
845
|
+
];
|
|
846
|
+
/** Twelfths, so 33 and 66 are real thirds and 33 + 33 + 33 is a full row. */
|
|
847
|
+
const TWELFTHS = {
|
|
848
|
+
"25": 3,
|
|
849
|
+
"33": 4,
|
|
850
|
+
"50": 6,
|
|
851
|
+
"66": 8,
|
|
852
|
+
"75": 9,
|
|
853
|
+
"100": 12
|
|
854
|
+
};
|
|
855
|
+
/**
|
|
856
|
+
* The rule on `columns`: read as fractions, the widths must total 100%. It is
|
|
857
|
+
* the array's own `validate`, so the editor sees the message as they build,
|
|
858
|
+
* and Payload runs field validation again on publish (only draft saves skip
|
|
859
|
+
* it), so nothing publishes with a short row. Skipped when Advanced has custom
|
|
860
|
+
* widths on.
|
|
861
|
+
*/
|
|
862
|
+
const validateColumnWidths = (value, options) => {
|
|
863
|
+
const limits = rowLimits(value, options);
|
|
864
|
+
if (limits !== true) return limits;
|
|
865
|
+
if (options.siblingData?.customWidths || !value?.length) return true;
|
|
866
|
+
const twelfths = value.reduce((sum, row) => sum + TWELFTHS[row?.width ?? "100"], 0);
|
|
867
|
+
if (twelfths === 12) return true;
|
|
868
|
+
return `The columns add up to ${Math.round(twelfths / 12 * 100)}%. They need to add up to 100%.`;
|
|
869
|
+
};
|
|
870
|
+
/**
|
|
871
|
+
* The row `levels` segments above the field at `path`, read off the whole
|
|
872
|
+
* document. A condition on a link needs its section; a condition on a column
|
|
873
|
+
* needs its panel. `data` carries the full form, so the path is enough.
|
|
874
|
+
*/
|
|
875
|
+
function ancestor(data, path, levels) {
|
|
876
|
+
let node = data;
|
|
877
|
+
for (const segment of path.slice(0, path.length - levels)) {
|
|
878
|
+
if (node === null || typeof node !== "object") return void 0;
|
|
879
|
+
node = node[segment];
|
|
880
|
+
}
|
|
881
|
+
return node !== null && typeof node === "object" ? node : void 0;
|
|
882
|
+
}
|
|
883
|
+
/** `links.N.variant` → its section, three segments up. */
|
|
884
|
+
const whenSectionFeatured = (data, _siblingData, { path }) => ancestor(data, path, 3)?.display === "featured";
|
|
885
|
+
/** A featured link's glyph comes from its variant, so `icon` is a list link's field. */
|
|
886
|
+
const unlessSectionFeatured = (data, siblingData, ctx) => !whenSectionFeatured(data, siblingData, ctx);
|
|
887
|
+
/** The renderer would fall back to the preset silently; the editor should hear it here instead. */
|
|
888
|
+
const validateRemWidth = (value) => !value || remWidth(value) !== null ? true : "Type a width in rem, like 30 or 30rem.";
|
|
889
|
+
/** `columns.N.width` → its panel, three segments up. */
|
|
890
|
+
const whenCustomWidths = (data, _siblingData, { path }) => Boolean(ancestor(data, path, 3)?.customWidths);
|
|
891
|
+
const unlessCustomWidths = (data, siblingData, ctx) => !whenCustomWidths(data, siblingData, ctx);
|
|
892
|
+
function approvedSelect(name, options, admin) {
|
|
893
|
+
if (!options?.length) return [];
|
|
894
|
+
return [{
|
|
895
|
+
name,
|
|
896
|
+
type: "select",
|
|
897
|
+
options,
|
|
898
|
+
admin
|
|
899
|
+
}];
|
|
900
|
+
}
|
|
901
|
+
function megaMenuBlock({ variants, icons } = {}) {
|
|
902
|
+
const linkRowFields = [
|
|
903
|
+
...linkFields({ required: true }),
|
|
904
|
+
{
|
|
905
|
+
name: "description",
|
|
906
|
+
type: "textarea",
|
|
907
|
+
admin: { description: "Supporting line under the label. Optional." }
|
|
908
|
+
},
|
|
909
|
+
...approvedSelect("variant", variants, {
|
|
910
|
+
description: "The look of this featured link.",
|
|
911
|
+
condition: whenSectionFeatured
|
|
912
|
+
}),
|
|
913
|
+
...approvedSelect("icon", icons, {
|
|
914
|
+
description: "Glyph shown before a list link. Optional.",
|
|
915
|
+
condition: unlessSectionFeatured
|
|
916
|
+
})
|
|
917
|
+
];
|
|
918
|
+
return {
|
|
919
|
+
slug: "megaMenu",
|
|
920
|
+
interfaceName: "MegaMenuBlock",
|
|
921
|
+
labels: {
|
|
922
|
+
singular: "Mega menu",
|
|
923
|
+
plural: "Mega menus"
|
|
924
|
+
},
|
|
925
|
+
fields: [
|
|
926
|
+
{
|
|
927
|
+
name: "label",
|
|
928
|
+
type: "text",
|
|
929
|
+
required: true
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
name: "href",
|
|
933
|
+
type: "text",
|
|
934
|
+
admin: { description: "The landing page this menu opens. Optional: a trigger with no landing page is allowed." }
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
name: "panel",
|
|
938
|
+
type: "group",
|
|
939
|
+
fields: [
|
|
940
|
+
{
|
|
941
|
+
name: "maxWidth",
|
|
942
|
+
type: "select",
|
|
943
|
+
defaultValue: "standard",
|
|
944
|
+
options: [
|
|
945
|
+
{
|
|
946
|
+
label: "Narrow",
|
|
947
|
+
value: "narrow"
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
label: "Standard",
|
|
951
|
+
value: "standard"
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
label: "Wide",
|
|
955
|
+
value: "wide"
|
|
956
|
+
}
|
|
957
|
+
]
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
name: "columns",
|
|
961
|
+
type: "array",
|
|
962
|
+
required: true,
|
|
963
|
+
minRows: 1,
|
|
964
|
+
maxRows: 4,
|
|
965
|
+
defaultValue: emptyRows(1),
|
|
966
|
+
labels: {
|
|
967
|
+
singular: "Column",
|
|
968
|
+
plural: "Columns"
|
|
969
|
+
},
|
|
970
|
+
validate: validateColumnWidths,
|
|
971
|
+
admin: { components: { Field: MIN_ROWS_ARRAY_FIELD } },
|
|
972
|
+
fields: [
|
|
973
|
+
{
|
|
974
|
+
name: "width",
|
|
975
|
+
type: "select",
|
|
976
|
+
defaultValue: "100",
|
|
977
|
+
options: MEGA_MENU_WIDTHS.map((value) => ({
|
|
978
|
+
label: `${value}%`,
|
|
979
|
+
value
|
|
980
|
+
})),
|
|
981
|
+
admin: { condition: unlessCustomWidths }
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
name: "customWidth",
|
|
985
|
+
type: "text",
|
|
986
|
+
admin: {
|
|
987
|
+
description: "A CSS width: 13rem, 1fr, minmax(0, 1fr)",
|
|
988
|
+
condition: whenCustomWidths
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
name: "divider",
|
|
993
|
+
type: "checkbox",
|
|
994
|
+
label: "Draw a line on the left of this column",
|
|
995
|
+
defaultValue: false
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
name: "sections",
|
|
999
|
+
type: "array",
|
|
1000
|
+
labels: {
|
|
1001
|
+
singular: "Section",
|
|
1002
|
+
plural: "Sections"
|
|
1003
|
+
},
|
|
1004
|
+
fields: [
|
|
1005
|
+
{
|
|
1006
|
+
name: "eyebrow",
|
|
1007
|
+
type: "text",
|
|
1008
|
+
admin: { description: "Small heading above this group; leave empty for none" }
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
name: "display",
|
|
1012
|
+
type: "select",
|
|
1013
|
+
defaultValue: "list",
|
|
1014
|
+
options: [{
|
|
1015
|
+
label: "Featured",
|
|
1016
|
+
value: "featured"
|
|
1017
|
+
}, {
|
|
1018
|
+
label: "List",
|
|
1019
|
+
value: "list"
|
|
1020
|
+
}]
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
name: "hideDescriptionsOnMobile",
|
|
1024
|
+
type: "checkbox",
|
|
1025
|
+
label: "Hide descriptions on mobile",
|
|
1026
|
+
defaultValue: true
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
name: "links",
|
|
1030
|
+
type: "array",
|
|
1031
|
+
labels: {
|
|
1032
|
+
singular: "Link",
|
|
1033
|
+
plural: "Links"
|
|
1034
|
+
},
|
|
1035
|
+
fields: linkRowFields
|
|
1036
|
+
}
|
|
1037
|
+
]
|
|
1038
|
+
}
|
|
1039
|
+
]
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
name: "footer",
|
|
1043
|
+
type: "group",
|
|
1044
|
+
admin: { description: "The strip under the columns. Leave both empty for no footer." },
|
|
1045
|
+
fields: [linkField({
|
|
1046
|
+
name: "overview",
|
|
1047
|
+
label: "Overview link",
|
|
1048
|
+
admin: { description: "The section's own landing page, so it stays reachable from the bar." }
|
|
1049
|
+
}), linkField({
|
|
1050
|
+
name: "cta",
|
|
1051
|
+
label: "Call to action"
|
|
1052
|
+
})]
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
type: "collapsible",
|
|
1056
|
+
label: "Advanced",
|
|
1057
|
+
admin: { initCollapsed: true },
|
|
1058
|
+
fields: [{
|
|
1059
|
+
name: "customWidths",
|
|
1060
|
+
type: "checkbox",
|
|
1061
|
+
label: "Type a CSS width for each column instead of choosing a percentage",
|
|
1062
|
+
defaultValue: false
|
|
1063
|
+
}, {
|
|
1064
|
+
name: "customMaxWidth",
|
|
1065
|
+
type: "text",
|
|
1066
|
+
validate: validateRemWidth,
|
|
1067
|
+
admin: { description: "Panel width in rem, e.g. 30. Leave empty to use the preset above." }
|
|
1068
|
+
}]
|
|
1069
|
+
}
|
|
1070
|
+
]
|
|
1071
|
+
}
|
|
1072
|
+
]
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
/** A plain bar item: label and destination, nothing to open. */
|
|
1076
|
+
const LinkBlock = {
|
|
1077
|
+
slug: "navLink",
|
|
1078
|
+
interfaceName: "NavLinkBlock",
|
|
1079
|
+
labels: {
|
|
1080
|
+
singular: "Link",
|
|
1081
|
+
plural: "Links"
|
|
1082
|
+
},
|
|
1083
|
+
fields: linkFields({ required: true })
|
|
1084
|
+
};
|
|
1085
|
+
//#endregion
|
|
644
1086
|
//#region src/media.ts
|
|
645
1087
|
function isMediaDoc(value) {
|
|
646
1088
|
return typeof value === "object" && value !== null;
|
|
@@ -770,6 +1212,143 @@ const heroSample = {
|
|
|
770
1212
|
}]
|
|
771
1213
|
};
|
|
772
1214
|
//#endregion
|
|
1215
|
+
//#region src/blocks/mega-menu/sample.ts
|
|
1216
|
+
/**
|
|
1217
|
+
* The options the mega menu sample was written against. A factory block's
|
|
1218
|
+
* sample only fits a config built with the same approved values, so a
|
|
1219
|
+
* preview builds its block with `megaMenuBlock(megaMenuSampleOptions)`.
|
|
1220
|
+
*/
|
|
1221
|
+
const megaMenuSampleOptions = {
|
|
1222
|
+
variants: [{
|
|
1223
|
+
label: "Lumbar",
|
|
1224
|
+
value: "lumbar"
|
|
1225
|
+
}, {
|
|
1226
|
+
label: "SI joint",
|
|
1227
|
+
value: "si"
|
|
1228
|
+
}],
|
|
1229
|
+
icons: [{
|
|
1230
|
+
label: "Help",
|
|
1231
|
+
value: "help"
|
|
1232
|
+
}, {
|
|
1233
|
+
label: "Mail",
|
|
1234
|
+
value: "mail"
|
|
1235
|
+
}]
|
|
1236
|
+
};
|
|
1237
|
+
/**
|
|
1238
|
+
* Spinal Simplicity's Patients panel as a saved row: two featured territories
|
|
1239
|
+
* in a 75% column, two rail sections in a divided 25% column, overview and
|
|
1240
|
+
* CTA. Every field is set at least once; the Advanced fields are set but off,
|
|
1241
|
+
* so the percent widths are what renders.
|
|
1242
|
+
*/
|
|
1243
|
+
const megaMenuSample = {
|
|
1244
|
+
id: "sample-mega-menu",
|
|
1245
|
+
blockType: "megaMenu",
|
|
1246
|
+
label: "Patients",
|
|
1247
|
+
href: "/patients",
|
|
1248
|
+
panel: {
|
|
1249
|
+
maxWidth: "standard",
|
|
1250
|
+
columns: [{
|
|
1251
|
+
id: "treatment",
|
|
1252
|
+
width: "75",
|
|
1253
|
+
customWidth: "minmax(0, 1fr)",
|
|
1254
|
+
divider: false,
|
|
1255
|
+
sections: [{
|
|
1256
|
+
id: "territories",
|
|
1257
|
+
eyebrow: "Treatment",
|
|
1258
|
+
display: "featured",
|
|
1259
|
+
hideDescriptionsOnMobile: true,
|
|
1260
|
+
links: [{
|
|
1261
|
+
id: "lumbar",
|
|
1262
|
+
label: "Low Back Pain",
|
|
1263
|
+
href: "/patients/low-back-pain",
|
|
1264
|
+
newTab: false,
|
|
1265
|
+
description: "Persistent low back pain from lumbar instability, often with leg pain that limits standing or walking.",
|
|
1266
|
+
variant: "lumbar"
|
|
1267
|
+
}, {
|
|
1268
|
+
id: "si",
|
|
1269
|
+
label: "Hip Pain",
|
|
1270
|
+
href: "/patients/hip-pain",
|
|
1271
|
+
newTab: false,
|
|
1272
|
+
description: "Pain centered on the sacroiliac joint, often worse with sitting or climbing stairs.",
|
|
1273
|
+
variant: "si"
|
|
1274
|
+
}]
|
|
1275
|
+
}]
|
|
1276
|
+
}, {
|
|
1277
|
+
id: "rail",
|
|
1278
|
+
width: "25",
|
|
1279
|
+
customWidth: "13rem",
|
|
1280
|
+
divider: true,
|
|
1281
|
+
sections: [{
|
|
1282
|
+
id: "outcomes",
|
|
1283
|
+
eyebrow: "Patient Outcomes",
|
|
1284
|
+
display: "list",
|
|
1285
|
+
hideDescriptionsOnMobile: true,
|
|
1286
|
+
links: [
|
|
1287
|
+
{
|
|
1288
|
+
id: "stories",
|
|
1289
|
+
label: "Testimonials",
|
|
1290
|
+
href: "/patients/stories",
|
|
1291
|
+
newTab: false
|
|
1292
|
+
},
|
|
1293
|
+
{
|
|
1294
|
+
id: "research",
|
|
1295
|
+
label: "Research",
|
|
1296
|
+
href: "/patients/research",
|
|
1297
|
+
newTab: false
|
|
1298
|
+
},
|
|
1299
|
+
{
|
|
1300
|
+
id: "path",
|
|
1301
|
+
label: "Path to Relief",
|
|
1302
|
+
href: "/patients/path-to-relief",
|
|
1303
|
+
newTab: false
|
|
1304
|
+
}
|
|
1305
|
+
]
|
|
1306
|
+
}, {
|
|
1307
|
+
id: "support",
|
|
1308
|
+
eyebrow: "Support",
|
|
1309
|
+
display: "list",
|
|
1310
|
+
hideDescriptionsOnMobile: false,
|
|
1311
|
+
links: [{
|
|
1312
|
+
id: "faqs",
|
|
1313
|
+
label: "FAQs",
|
|
1314
|
+
href: "/patients/faqs",
|
|
1315
|
+
newTab: false,
|
|
1316
|
+
description: "Short answers to the questions patients ask first.",
|
|
1317
|
+
icon: "help"
|
|
1318
|
+
}, {
|
|
1319
|
+
id: "contact",
|
|
1320
|
+
label: "Contact",
|
|
1321
|
+
href: "https://example.com/contact",
|
|
1322
|
+
newTab: true,
|
|
1323
|
+
icon: "mail"
|
|
1324
|
+
}]
|
|
1325
|
+
}]
|
|
1326
|
+
}],
|
|
1327
|
+
footer: {
|
|
1328
|
+
overview: {
|
|
1329
|
+
label: "All patient resources",
|
|
1330
|
+
href: "/patients",
|
|
1331
|
+
newTab: false
|
|
1332
|
+
},
|
|
1333
|
+
cta: {
|
|
1334
|
+
label: "Find a Doctor",
|
|
1335
|
+
href: "/find-a-doctor",
|
|
1336
|
+
newTab: false
|
|
1337
|
+
}
|
|
1338
|
+
},
|
|
1339
|
+
customWidths: false,
|
|
1340
|
+
customMaxWidth: "42rem"
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
/** A plain bar item. */
|
|
1344
|
+
const navLinkSample = {
|
|
1345
|
+
id: "sample-nav-link",
|
|
1346
|
+
blockType: "navLink",
|
|
1347
|
+
label: "Contact",
|
|
1348
|
+
href: "/contact",
|
|
1349
|
+
newTab: false
|
|
1350
|
+
};
|
|
1351
|
+
//#endregion
|
|
773
1352
|
//#region src/blocks/nap/sample.ts
|
|
774
1353
|
/**
|
|
775
1354
|
* A fictional clinic. `emitJsonLd` is off: the block emits schema.org
|
|
@@ -1001,6 +1580,50 @@ const showcasePanelsSample = {
|
|
|
1001
1580
|
defaultActiveIndex: 0
|
|
1002
1581
|
};
|
|
1003
1582
|
//#endregion
|
|
1583
|
+
//#region src/blocks/stats-band/sample.ts
|
|
1584
|
+
/**
|
|
1585
|
+
* Four figures, the count the strip was designed around: one row on a
|
|
1586
|
+
* desktop, two by two on a tablet and a phone. `wide` is set (to `false`) so
|
|
1587
|
+
* the preview exercises the field, and an even count is where it is ignored.
|
|
1588
|
+
* `overlap` is off so the heading shows: a floating band is headless, and a
|
|
1589
|
+
* preview page has no hero for it to float over.
|
|
1590
|
+
*/
|
|
1591
|
+
const statsBandSample = {
|
|
1592
|
+
id: "sample-stats-band",
|
|
1593
|
+
blockType: "statsBand",
|
|
1594
|
+
eyebrow: "At a glance",
|
|
1595
|
+
title: "The clinic in numbers",
|
|
1596
|
+
description: "What a year looks like across our two rooms, counted from the front desk rather than estimated.",
|
|
1597
|
+
items: [
|
|
1598
|
+
{
|
|
1599
|
+
id: "sample-stat-pain",
|
|
1600
|
+
value: "94%",
|
|
1601
|
+
label: "of patients report less pain by their sixth session.",
|
|
1602
|
+
href: "/outcomes",
|
|
1603
|
+
wide: false
|
|
1604
|
+
},
|
|
1605
|
+
{
|
|
1606
|
+
id: "sample-stat-visits",
|
|
1607
|
+
value: "4,200+",
|
|
1608
|
+
label: "appointments a year across two treatment rooms."
|
|
1609
|
+
},
|
|
1610
|
+
{
|
|
1611
|
+
id: "sample-stat-wait",
|
|
1612
|
+
value: "15 min",
|
|
1613
|
+
label: "average wait from the front desk to the treatment room."
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
id: "sample-stat-years",
|
|
1617
|
+
value: "12",
|
|
1618
|
+
label: "years in the same building, on the same street."
|
|
1619
|
+
}
|
|
1620
|
+
],
|
|
1621
|
+
columns: "4",
|
|
1622
|
+
tone: "card",
|
|
1623
|
+
align: "start",
|
|
1624
|
+
overlap: false
|
|
1625
|
+
};
|
|
1626
|
+
//#endregion
|
|
1004
1627
|
//#region src/blocks/testimonial-masonry/sample.ts
|
|
1005
1628
|
function avatar(name) {
|
|
1006
1629
|
return sampleImage({
|
|
@@ -1098,9 +1721,12 @@ const blockSamples = {
|
|
|
1098
1721
|
minItemsForFade: 6,
|
|
1099
1722
|
maxVisibleRows: 2
|
|
1100
1723
|
},
|
|
1101
|
-
nap: napSample
|
|
1724
|
+
nap: napSample,
|
|
1725
|
+
statsBand: statsBandSample,
|
|
1726
|
+
megaMenu: megaMenuSample,
|
|
1727
|
+
navLink: navLinkSample
|
|
1102
1728
|
};
|
|
1103
1729
|
//#endregion
|
|
1104
|
-
export { FaqColumnsBlock, HeroBlock, MIN_ROWS_ARRAY_FIELD, NapBlock, ProcessStepsBlock, RichTextBlock, ShowcasePanelsBlock, TestimonialMasonryBlock, blockSamples, emptyRows, headingFields, imageField, linkField, linkFields, resolveMedia, sampleImage };
|
|
1730
|
+
export { FaqColumnsBlock, HeroBlock, LinkBlock, MEGA_MENU_WIDTHS, MIN_ROWS_ARRAY_FIELD, NapBlock, ProcessStepsBlock, RichTextBlock, ShowcasePanelsBlock, StatsBandBlock, TestimonialMasonryBlock, blockSamples, emptyRows, headingFields, imageField, linkField, linkFields, megaMenuBlock, megaMenuSampleOptions, resolveMedia, sampleImage, validateColumnWidths, validateRemWidth };
|
|
1105
1731
|
|
|
1106
1732
|
//# sourceMappingURL=index.mjs.map
|