@bison-lab/payload-core 3.11.0 → 3.12.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 CHANGED
@@ -1,9 +1,9 @@
1
1
  # `@bison-lab/payload-core`
2
2
 
3
3
  Site-agnostic Payload CMS configuration for Bison Lab sites: the SEO tab on
4
- a collection, the Theme Global, and the readers a page route and a root
5
- layout use. The rest of the shared CMS layer (access matrix, collection
6
- factories, slug field) joins it here as it is extracted.
4
+ a collection, the Theme Global, the Roles Global, and the readers a page
5
+ route and a root layout use. Collection factories join it here as they
6
+ are extracted.
7
7
 
8
8
  Full guide: <https://payload.bisonlab.ai/site/seo/>
9
9
 
@@ -22,10 +22,10 @@ lockstep.
22
22
 
23
23
  | Import | Contents | Runs where |
24
24
  | ---------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
25
- | `@bison-lab/payload-core` | `seoPlugin`, `createTheme`, `createBrandAssets`, `seedTheme`, `lookField`, `colorTokenField`, import-map strings, title and text helpers, types | Node. What `payload.config.ts` imports; it loads the plugin. |
25
+ | `@bison-lab/payload-core` | `seoPlugin`, `createTheme`, `createBrandAssets`, `createRoles`, `createPages`, `createUsers`, `createMedia`, `adminOnlyApiTab`, `seedTheme`, `seedRoles`, predicates, `lookField`, `colorTokenField`, import-map strings, title and text helpers, types | Node. What `payload.config.ts` imports; it loads the plugin. |
26
26
  | `@bison-lab/payload-core/metadata` | `pageMetadata`, the title helpers, the same types | Server. What a page route imports; it does not load the plugin. |
27
27
  | `@bison-lab/payload-core/theme` | `getPublishedTheme`, `getPublishedIdentity`, `themeConfigFromDoc`, `themeHead`, `themeHeadFromDoc` | Server. What a root layout imports; it does not load the plugin or React. |
28
- | `@bison-lab/payload-core/admin` | Theme child fields (color scale, library, gray family, fonts, appearance, publish) | Admin. Referenced by import-map string; `generate:importmap` writes it. |
28
+ | `@bison-lab/payload-core/admin` | Theme child fields, the Roles matrix field, and the Users Roles checklist | Admin. Referenced by import-map string; `generate:importmap` writes it. |
29
29
  | `@bison-lab/payload-core/react` | `ThemePreview` (legacy; Theme has no preview pane) | Client. Kept so an older site import does not break. |
30
30
 
31
31
  ## What editors get
@@ -137,15 +137,20 @@ is never enforced and lives in the Needs-attention modal, not on the page.
137
137
  Pass `destructive` (or `seed.brandDestructive`); otherwise Theme uses the
138
138
  library’s `DESTRUCTIVE_SCALE_HEX` (`#ef4444`). Success falls back to `#22c55e`.
139
139
 
140
- **1. Register the Global.** Access is required — the predicates live in the
141
- site's `src/platform` until they move here. Pass `canManageBrand` as
142
- `update`.
140
+ **1. Register the Global.** Access is required — Theme does not read the
141
+ Roles Global. Pass `canManageBrand` as `update`.
143
142
 
144
143
  ```ts
145
144
  // payload.config.ts
146
- import { BRAND_ASSETS_SLUG, createBrandAssets, createTheme } from "@bison-lab/payload-core";
145
+ import {
146
+ BRAND_ASSETS_SLUG,
147
+ canManageBrand,
148
+ createBrandAssets,
149
+ createRoles,
150
+ createTheme,
151
+ isAuthenticated,
152
+ } from "@bison-lab/payload-core";
147
153
  import bisonConfig from "../bison.config.json";
148
- import { canManageBrand, isAuthenticated } from "@/platform/access";
149
154
 
150
155
  export default buildConfig({
151
156
  collections: [
@@ -154,6 +159,7 @@ export default buildConfig({
154
159
  }),
155
160
  ],
156
161
  globals: [
162
+ createRoles(),
157
163
  ...createTheme({
158
164
  access: { read: isAuthenticated, update: canManageBrand },
159
165
  seed: bisonConfig,
@@ -181,11 +187,12 @@ so the site renders what `bison-theme.css` rendered before anyone opens the
181
187
  admin:
182
188
 
183
189
  ```ts
184
- import { seedTheme } from "@bison-lab/payload-core";
190
+ import { seedRoles, seedTheme } from "@bison-lab/payload-core";
185
191
  import bisonConfig from "../bison.config.json";
186
192
 
187
193
  export async function up({ payload }) {
188
194
  await seedTheme(payload, bisonConfig);
195
+ await seedRoles(payload);
189
196
  }
190
197
  ```
191
198
 
@@ -233,17 +240,35 @@ Versions stay on so a replaced file can be rolled back.
233
240
  Each row carries a label, usage notes, and required alt text so a logo
234
241
  has its accessible name. Then `payload migrate:create`.
235
242
 
243
+ ## Roles
244
+
245
+ Settings → Roles is an Admin-editable array. Rank is drag-to-reorder.
246
+ Ticks are Content, Brand, Publish, and Users. The API tab is locked to
247
+ Developer — it is not a column. Defaults ship in the package (Brand on
248
+ Designer only; Admin + Designer both store; Developer is exclusive).
249
+ `canManageBrand` and the other predicates read the saved Global and fall
250
+ back to that seed. The package never writes `developer` onto a user row.
251
+
252
+ ## Pages, users, and media
253
+
254
+ `createPages`, `createUsers`, `createMedia`, `slugField`, and
255
+ `adminOnlyApiTab` ship from the same React-free entry. Pages take the
256
+ site's hero and layout blocks, reserved-slug predicate, and preview
257
+ path. Users take `secureCookies`; the Roles checklist reads the Global
258
+ (or the seed) and has no second ORDER / WHAT list. `adminOnlyApiTab`
259
+ shows the document API tab only to Developer.
260
+
236
261
  ## No generated types
237
262
 
238
263
  The package cannot import a site's `payload-types`, so the shapes it reads
239
- (`SeoMeta`, `SeoImageDoc`, `SeoPage`, `ThemeDoc`) are hand-written and
264
+ (`SeoMeta`, `SeoImageDoc`, `SeoPage`, `ThemeDoc`, `RolesDoc`) are hand-written and
240
265
  structural. A generated `Page`, `Media` or Theme Global is assignable to
241
266
  them; nothing carries an index signature, since an interface will not assign
242
267
  to a type that has one.
243
268
 
244
269
  ## Changing a field
245
270
 
246
- `noIndexField`, the plugin's own fields, the Theme Global fields, and the
247
- brand-assets collection fields are columns in every consuming site. A
248
- change to them is a schema change: say "run `payload migrate:create`" in
249
- the changeset.
271
+ `noIndexField`, the plugin's own fields, the Theme Global fields, the
272
+ Roles Global fields, and the brand-assets collection fields are columns
273
+ in every consuming site. A change to them is a schema change: say "run
274
+ `payload migrate:create`" in the changeset.
package/dist/admin.d.mts CHANGED
@@ -101,5 +101,20 @@ declare const IdentityFallback: UIFieldClientComponent;
101
101
  */
102
102
  declare const LookField: TextFieldClientComponent;
103
103
  //#endregion
104
- export { AppearanceField, ColorField, ColorScaleField, ContrastReport, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
104
+ //#region src/admin/roles-matrix-field.d.ts
105
+ /**
106
+ * Payload's array field: drag rank stays, add/remove go away. Reset writes
107
+ * the package seed back onto the field.
108
+ */
109
+ declare const RolesMatrixField: ArrayFieldClientComponent;
110
+ //#endregion
111
+ //#region src/admin/roles-field.d.ts
112
+ /**
113
+ * Users Roles checklist. Order and labels come from the field options (the
114
+ * Roles Global, or the seed). Copy is `roleDescription`. Developer is
115
+ * exclusive; Admin does not swallow Designer.
116
+ */
117
+ declare const RolesField: SelectFieldClientComponent;
118
+ //#endregion
119
+ export { AppearanceField, ColorField, ColorScaleField, ContrastReport, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RolesField, RolesMatrixField, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
105
120
  //# sourceMappingURL=admin.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin.d.mts","names":[],"sources":["../src/admin/color-field.tsx","../src/admin/color-scale-field.tsx","../src/admin/library-field.tsx","../src/admin/font-field.tsx","../src/admin/pairing-field.tsx","../src/admin/appearance-field.tsx","../src/admin/grey-scale-field.tsx","../src/admin/contrast-report.tsx","../src/admin/section-heading.tsx","../src/admin/publish-child.tsx","../src/admin/save-button.tsx","../src/admin/identity-fallback.tsx","../src/admin/look-field.tsx"],"mappings":";;;;;;;;;;cAWa,UAAA,EAAY,wBAAA;;;;;;;cCsBZ,eAAA,EAAiB,yBAAA;;;;;;;;ADtB9B;cEca,YAAA,EAAc,yBAAA;;;;;;;;AFd3B;cGOa,SAAA,EAAW,0BAAA;;;;;;;cCNX,YAAA,EAAc,sBAAA;;;;;;;cCCd,eAAA,EAAiB,yBAAA;;;;;;;cCuDjB,cAAA,EAAgB,0BAAA;;;;;;;cChDhB,cAAA,EAAgB,sBAAA;;;;;;cCbhB,cAAA,EAAgB,sBAAA;;;cCgJhB,YAAA,EAAc,sBAAA;;;;;;;;iBC3IX,qBAAA,CAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA;AVDrC;;;;AAAA,iBUgBgB,eAAA,CAAA,GAAe,kBAAA,CAAA,GAAA,CAAA,OAAA;;iBA0Bf,gBAAA,CAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;cC7CnB,gBAAA,EAAkB,sBAAA;;;;;;;cCIlB,SAAA,EAAW,wBAAA"}
1
+ {"version":3,"file":"admin.d.mts","names":[],"sources":["../src/admin/color-field.tsx","../src/admin/color-scale-field.tsx","../src/admin/library-field.tsx","../src/admin/font-field.tsx","../src/admin/pairing-field.tsx","../src/admin/appearance-field.tsx","../src/admin/grey-scale-field.tsx","../src/admin/contrast-report.tsx","../src/admin/section-heading.tsx","../src/admin/publish-child.tsx","../src/admin/save-button.tsx","../src/admin/identity-fallback.tsx","../src/admin/look-field.tsx","../src/admin/roles-matrix-field.tsx","../src/admin/roles-field.tsx"],"mappings":";;;;;;;;;;cAWa,UAAA,EAAY,wBAAA;;;;;;;cCsBZ,eAAA,EAAiB,yBAAA;;;;;;;;ADtB9B;cEca,YAAA,EAAc,yBAAA;;;;;;;;AFd3B;cGOa,SAAA,EAAW,0BAAA;;;;;;;cCNX,YAAA,EAAc,sBAAA;;;;;;;cCCd,eAAA,EAAiB,yBAAA;;;;;;;cCuDjB,cAAA,EAAgB,0BAAA;;;;;;;cChDhB,cAAA,EAAgB,sBAAA;;;;;;cCbhB,cAAA,EAAgB,sBAAA;;;cCgJhB,YAAA,EAAc,sBAAA;;;;;;;;iBC3IX,qBAAA,CAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA;AVDrC;;;;AAAA,iBUgBgB,eAAA,CAAA,GAAe,kBAAA,CAAA,GAAA,CAAA,OAAA;;iBA0Bf,gBAAA,CAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;cC7CnB,gBAAA,EAAkB,sBAAA;;;;;;;cCIlB,SAAA,EAAW,wBAAA;;;;;;;cCDX,gBAAA,EAAkB,yBAAA;;;;;;;;cCkBlB,UAAA,EAAY,0BAAA"}
package/dist/admin.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { a as colorDocFromState, i as SYSTEM_COLOR_KEYS, n as pageEditorLooks, r as pageEditorTokens, s as stateFromColorDoc } from "./looks-BbL309kO.mjs";
3
- import { FieldDescription, FieldError, FieldLabel, useConfig, useField, useForm, useFormFields } from "@payloadcms/ui";
3
+ import { ArrayField, CheckboxInput, FieldDescription, FieldError, FieldLabel, fieldBaseClass, useConfig, useField, useForm, useFormFields } from "@payloadcms/ui";
4
4
  import { GREY_SCALES, SHADE_STEPS, contrastForeground, contrastRatio, createColorScale, deriveDarkPalette, deriveLightPalette, hexToHSL, hslToString, includedShadeSteps, isThemeHex, presetHints, setColorScaleInclude } from "@bison-lab/tokens";
5
- import { useEffect, useId, useMemo, useRef, useState } from "react";
5
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { createPortal } from "react-dom";
8
8
  import { findFont, fontFaceCss, isFontId } from "@bison-lab/fonts";
@@ -2406,6 +2406,239 @@ const LookField = ({ field, path, readOnly }) => {
2406
2406
  });
2407
2407
  };
2408
2408
  //#endregion
2409
- export { AppearanceField, ColorField, ColorScaleField, ContrastReport, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
2409
+ //#region src/roles/types.ts
2410
+ /**
2411
+ * The Roles Global a site's generated types will describe. Optional and
2412
+ * nullable, no index signature: a generated Global is assignable to this,
2413
+ * never the reverse.
2414
+ */
2415
+ const ROLES = [
2416
+ "developer",
2417
+ "admin",
2418
+ "designer",
2419
+ "author"
2420
+ ];
2421
+ const ROLE_LABELS = {
2422
+ developer: "Developer",
2423
+ admin: "Admin",
2424
+ designer: "Designer",
2425
+ author: "Author"
2426
+ };
2427
+ const CAPABILITIES = [
2428
+ "content",
2429
+ "brand",
2430
+ "publish",
2431
+ "users"
2432
+ ];
2433
+ function isRole(value) {
2434
+ return typeof value === "string" && ROLES.includes(value);
2435
+ }
2436
+ //#endregion
2437
+ //#region src/roles/matrix.ts
2438
+ /**
2439
+ * Default rank and ticks. Brand is Designer only. The API tab is not a
2440
+ * column — it is locked to Developer in `isDeveloper`.
2441
+ */
2442
+ const DEFAULT_ROLE_MATRIX = [
2443
+ {
2444
+ role: "developer",
2445
+ content: true,
2446
+ brand: true,
2447
+ publish: true,
2448
+ users: true
2449
+ },
2450
+ {
2451
+ role: "admin",
2452
+ content: true,
2453
+ brand: false,
2454
+ publish: true,
2455
+ users: true
2456
+ },
2457
+ {
2458
+ role: "designer",
2459
+ content: false,
2460
+ brand: true,
2461
+ publish: false,
2462
+ users: false
2463
+ },
2464
+ {
2465
+ role: "author",
2466
+ content: true,
2467
+ brand: false,
2468
+ publish: false,
2469
+ users: false
2470
+ }
2471
+ ];
2472
+ const DEVELOPER_DESCRIPTION = "Everything Admin can do, plus the document API tab.";
2473
+ const CAPABILITY_LABELS = {
2474
+ content: "Content",
2475
+ brand: "Brand",
2476
+ publish: "Publish",
2477
+ users: "Users"
2478
+ };
2479
+ function defaultRolesFieldValue() {
2480
+ return DEFAULT_ROLE_MATRIX.map((row) => ({
2481
+ id: row.role,
2482
+ ...row
2483
+ }));
2484
+ }
2485
+ function roleSelectOptions(matrix = DEFAULT_ROLE_MATRIX) {
2486
+ return matrix.map((row) => ({
2487
+ label: ROLE_LABELS[row.role],
2488
+ value: row.role
2489
+ }));
2490
+ }
2491
+ /** Capability copy only. Developer names the API tab; nothing about MCP or seed. */
2492
+ function roleDescription(role, matrix = DEFAULT_ROLE_MATRIX) {
2493
+ if (role === "developer") return DEVELOPER_DESCRIPTION;
2494
+ const row = matrix.find((entry) => entry.role === role);
2495
+ if (!row) return "No capabilities";
2496
+ return CAPABILITIES.filter((capability) => row[capability]).map((capability) => CAPABILITY_LABELS[capability]).join(", ") || "No capabilities";
2497
+ }
2498
+ //#endregion
2499
+ //#region src/admin/roles-matrix-field.tsx
2500
+ const HIDE_ROW_CHROME = `.bl-roles-matrix .array-field__add-row,.bl-roles-matrix .array-actions__add,.bl-roles-matrix .array-actions__remove,.bl-roles-matrix .array-actions__duplicate,.bl-roles-matrix .array-actions__copy{display:none}.bl-roles-matrix__toolbar{display:flex;justify-content:flex-end;margin-block-end:.75rem}.bl-roles-matrix__reset{min-height:2.25rem;padding:.35rem .9rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:8px;background:transparent;color:inherit;font:inherit;cursor:pointer}`;
2501
+ /**
2502
+ * Payload's array field: drag rank stays, add/remove go away. Reset writes
2503
+ * the package seed back onto the field.
2504
+ */
2505
+ const RolesMatrixField = (props) => {
2506
+ const { setValue } = useField({ path: props.path });
2507
+ return /* @__PURE__ */ jsxs("div", {
2508
+ className: "bl-roles-matrix",
2509
+ children: [
2510
+ /* @__PURE__ */ jsx("style", {
2511
+ href: "bl-roles-matrix",
2512
+ precedence: "default",
2513
+ children: HIDE_ROW_CHROME
2514
+ }),
2515
+ /* @__PURE__ */ jsx("div", {
2516
+ className: "bl-roles-matrix__toolbar",
2517
+ children: /* @__PURE__ */ jsx("button", {
2518
+ type: "button",
2519
+ className: "bl-roles-matrix__reset",
2520
+ onClick: () => setValue(defaultRolesFieldValue()),
2521
+ children: "Reset to defaults"
2522
+ })
2523
+ }),
2524
+ /* @__PURE__ */ jsx(ArrayField, { ...props })
2525
+ ]
2526
+ });
2527
+ };
2528
+ //#endregion
2529
+ //#region src/admin/roles-field.tsx
2530
+ const GRID_CSS = `.bl-roles__grid{display:grid;gap:.75rem;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));margin-block:.35rem 0}.bl-roles__option{display:flex;flex-direction:column;gap:.25rem;padding:.65rem .75rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:8px}.bl-roles__option.is-checked{border-color:var(--theme-elevation-400,#94a3b8)}.bl-roles__option.is-included{opacity:.7}.bl-roles__what{font-size:.8rem;line-height:1.35;color:var(--theme-elevation-500,#64748b)}`;
2531
+ function optionValue(option) {
2532
+ return typeof option === "string" ? option : String(option.value);
2533
+ }
2534
+ function optionLabel(option) {
2535
+ return typeof option === "string" ? option : String(option.label);
2536
+ }
2537
+ /**
2538
+ * Users Roles checklist. Order and labels come from the field options (the
2539
+ * Roles Global, or the seed). Copy is `roleDescription`. Developer is
2540
+ * exclusive; Admin does not swallow Designer.
2541
+ */
2542
+ const RolesField = ({ field, path: pathFromProps, readOnly, validate }) => {
2543
+ const { admin: { description } = {}, label, localized, options = [], required } = field;
2544
+ const offered = (options.length ? options : roleSelectOptions()).map((option) => ({
2545
+ value: optionValue(option),
2546
+ label: optionLabel(option)
2547
+ }));
2548
+ const { disabled, errorMessage, path, setValue, showError, value } = useField({
2549
+ potentiallyStalePath: pathFromProps,
2550
+ validate: useCallback((value, validationOptions) => {
2551
+ if (typeof validate === "function") return validate(value, {
2552
+ ...validationOptions,
2553
+ hasMany: true,
2554
+ options,
2555
+ required
2556
+ });
2557
+ return true;
2558
+ }, [
2559
+ validate,
2560
+ options,
2561
+ required
2562
+ ])
2563
+ });
2564
+ const selected = Array.isArray(value) ? value : [];
2565
+ const exclusive = selected.includes("developer") ? "developer" : null;
2566
+ const locked = Boolean(readOnly) || disabled;
2567
+ function toggle(role) {
2568
+ if (locked) return;
2569
+ if (role === "developer") {
2570
+ setValue(selected.includes(role) ? [] : ["developer"]);
2571
+ return;
2572
+ }
2573
+ if (exclusive) return;
2574
+ setValue(selected.includes(role) ? selected.filter((entry) => entry !== role) : [...selected, role]);
2575
+ }
2576
+ const groupLabel = typeof label === "string" ? label : "Roles";
2577
+ return /* @__PURE__ */ jsxs("div", {
2578
+ className: [
2579
+ fieldBaseClass,
2580
+ "select",
2581
+ "bl-roles",
2582
+ showError && "error",
2583
+ locked && "read-only"
2584
+ ].filter(Boolean).join(" "),
2585
+ id: `field-${path.replace(/\./g, "__")}`,
2586
+ children: [
2587
+ /* @__PURE__ */ jsx("style", {
2588
+ href: "bl-roles",
2589
+ precedence: "default",
2590
+ children: GRID_CSS
2591
+ }),
2592
+ /* @__PURE__ */ jsx(FieldLabel, {
2593
+ as: "span",
2594
+ label,
2595
+ localized,
2596
+ path,
2597
+ required
2598
+ }),
2599
+ /* @__PURE__ */ jsxs("div", {
2600
+ className: `${fieldBaseClass}__wrap`,
2601
+ children: [/* @__PURE__ */ jsx(FieldError, {
2602
+ message: errorMessage,
2603
+ path,
2604
+ showError
2605
+ }), /* @__PURE__ */ jsx("div", {
2606
+ "aria-label": groupLabel,
2607
+ className: "bl-roles__grid",
2608
+ role: "group",
2609
+ children: offered.map((option) => {
2610
+ const role = isRole(option.value) ? option.value : null;
2611
+ if (!role) return null;
2612
+ const included = exclusive !== null && role !== exclusive;
2613
+ const checked = selected.includes(role);
2614
+ return /* @__PURE__ */ jsxs("div", {
2615
+ className: [
2616
+ "bl-roles__option",
2617
+ checked && "is-checked",
2618
+ included && "is-included"
2619
+ ].filter(Boolean).join(" "),
2620
+ children: [/* @__PURE__ */ jsx(CheckboxInput, {
2621
+ checked,
2622
+ id: `${path}-${role}`,
2623
+ label: option.label || ROLE_LABELS[role],
2624
+ onToggle: () => toggle(role),
2625
+ readOnly: locked || included
2626
+ }), /* @__PURE__ */ jsx("span", {
2627
+ className: "bl-roles__what",
2628
+ children: included ? "Included in Developer" : roleDescription(role)
2629
+ })]
2630
+ }, role);
2631
+ })
2632
+ })]
2633
+ }),
2634
+ /* @__PURE__ */ jsx(FieldDescription, {
2635
+ description,
2636
+ path
2637
+ })
2638
+ ]
2639
+ });
2640
+ };
2641
+ //#endregion
2642
+ export { AppearanceField, ColorField, ColorScaleField, ContrastReport, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RolesField, RolesMatrixField, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
2410
2643
 
2411
2644
  //# sourceMappingURL=admin.mjs.map