@bison-lab/payload-core 3.10.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`, 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
- | `@bison-lab/payload-core/theme` | `getPublishedTheme`, `getPublishedIdentity`, `themeConfigFromDoc`, `themeHead` | 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. |
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, 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
@@ -125,22 +125,32 @@ The sitemap is the site's: filter `meta.noIndex` out of it.
125
125
 
126
126
  ## Adopting the Theme global
127
127
 
128
- Settings Theme is one Global with field tabs: Colors, Typography, Appearance,
129
- and Identity. Publish in the document Save slot writes the open tab only.
130
- Theme has no draft mode and no preview pane. Contrast is the automatic label
131
- on editable fills at 7:1; it is never enforced. `bison.config.json` is the seed
132
- a site starts from, not the source of truth. Pass `destructive` (or
133
- `seed.brandDestructive`); there is no package default.
134
-
135
- **1. Register the Global.** Access is required the predicates live in the
136
- site's `src/platform` until they move here. Pass `canManageBrand` as
137
- `update`.
128
+ Theme in the admin nav is a group like Content and Settings: Colors,
129
+ Typography, Appearance, and Identity. Those are ordinary Payload Globals
130
+ (`admin.group: "Theme"`), not custom views. `createTheme` returns them plus
131
+ a hidden store (`theme`) that `getPublishedTheme` already reads. Save on a
132
+ page is Payload's Save; it writes that slice onto the store. Document
133
+ locking is off — these are settings forms. Theme has no draft mode and
134
+ no preview pane. Contrast is the automatic label on editable fills at 7:1; it
135
+ is never enforced and lives in the Needs-attention modal, not on the page.
136
+ `bison.config.json` is the seed a site starts from, not the source of truth.
137
+ Pass `destructive` (or `seed.brandDestructive`); otherwise Theme uses the
138
+ library’s `DESTRUCTIVE_SCALE_HEX` (`#ef4444`). Success falls back to `#22c55e`.
139
+
140
+ **1. Register the Global.** Access is required — Theme does not read the
141
+ Roles Global. Pass `canManageBrand` as `update`.
138
142
 
139
143
  ```ts
140
144
  // payload.config.ts
141
- 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";
142
153
  import bisonConfig from "../bison.config.json";
143
- import { canManageBrand, isAuthenticated } from "@/platform/access";
144
154
 
145
155
  export default buildConfig({
146
156
  collections: [
@@ -149,7 +159,8 @@ export default buildConfig({
149
159
  }),
150
160
  ],
151
161
  globals: [
152
- createTheme({
162
+ createRoles(),
163
+ ...createTheme({
153
164
  access: { read: isAuthenticated, update: canManageBrand },
154
165
  seed: bisonConfig,
155
166
  logo: { collection: BRAND_ASSETS_SLUG },
@@ -176,11 +187,12 @@ so the site renders what `bison-theme.css` rendered before anyone opens the
176
187
  admin:
177
188
 
178
189
  ```ts
179
- import { seedTheme } from "@bison-lab/payload-core";
190
+ import { seedRoles, seedTheme } from "@bison-lab/payload-core";
180
191
  import bisonConfig from "../bison.config.json";
181
192
 
182
193
  export async function up({ payload }) {
183
194
  await seedTheme(payload, bisonConfig);
195
+ await seedRoles(payload);
184
196
  }
185
197
  ```
186
198
 
@@ -201,6 +213,8 @@ const identity = await getPublishedIdentity(payload, {
201
213
  mark: { url: "/logo-mark.svg", alt: "Acme mark" },
202
214
  });
203
215
  const { css, preloads } = themeHead(theme, { identity });
216
+ // Custom Colors need the Theme document: themeHeadFromDoc(doc, bisonConfig, { identity })
217
+ // emits --coral-* and [data-look] so lookField keys paint.
204
218
 
205
219
  // <link rel="preload" as="font" type="font/woff2" crossOrigin="" href={href} />
206
220
  // <style dangerouslySetInnerHTML={{ __html: css }} />
@@ -226,17 +240,35 @@ Versions stay on so a replaced file can be rolled back.
226
240
  Each row carries a label, usage notes, and required alt text so a logo
227
241
  has its accessible name. Then `payload migrate:create`.
228
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
+
229
261
  ## No generated types
230
262
 
231
263
  The package cannot import a site's `payload-types`, so the shapes it reads
232
- (`SeoMeta`, `SeoImageDoc`, `SeoPage`, `ThemeDoc`) are hand-written and
264
+ (`SeoMeta`, `SeoImageDoc`, `SeoPage`, `ThemeDoc`, `RolesDoc`) are hand-written and
233
265
  structural. A generated `Page`, `Media` or Theme Global is assignable to
234
266
  them; nothing carries an index signature, since an interface will not assign
235
267
  to a type that has one.
236
268
 
237
269
  ## Changing a field
238
270
 
239
- `noIndexField`, the plugin's own fields, the Theme Global fields, and the
240
- brand-assets collection fields are columns in every consuming site. A
241
- change to them is a schema change: say "run `payload migrate:create`" in
242
- 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
@@ -12,15 +12,17 @@ declare const ColorField: TextFieldClientComponent;
12
12
  //#endregion
13
13
  //#region src/admin/color-scale-field.d.ts
14
14
  /**
15
- * One system (or library row) color: hex, source step, regenerate, stale,
16
- * include/exclude, automatic label. Writes the group's stored fields.
15
+ * One system (or library row) color: hex, source step, include/exclude.
16
+ * Writes the group's stored fields. A committed hex or step rebuilds the scale.
17
17
  */
18
18
  declare const ColorScaleField: GroupFieldClientComponent;
19
19
  //#endregion
20
20
  //#region src/admin/library-field.d.ts
21
21
  /**
22
- * Custom colors: the same scale controls as system colors, plus add and
23
- * in-use delete (one replacement scale; unused rows delete immediately).
22
+ * Custom colors: the same scale controls as system colors. A row that is
23
+ * not referenced on a page deletes immediately. Rewriting in-use tokens
24
+ * (`rewriteColorToken`) waits on a site usage lookup — Theme cannot see
25
+ * page assignments by itself.
24
26
  */
25
27
  declare const LibraryField: ArrayFieldClientComponent;
26
28
  //#endregion
@@ -56,9 +58,8 @@ declare const GreyScaleField: SelectFieldClientComponent;
56
58
  //#endregion
57
59
  //#region src/admin/contrast-report.d.ts
58
60
  /**
59
- * Contrast used to be a Colors-tab list. Readability now lives on each
60
- * color card: Needs attention opens a popup. This field stays in the
61
- * schema so `contrastTarget` is still a Theme option; it paints nothing.
61
+ * Fill + automatic label only. Target 7:1, Light and Dark. No gray
62
+ * ContrastStrip. Warnings do not block save.
62
63
  */
63
64
  declare const ContrastReport: UIFieldClientComponent;
64
65
  //#endregion
@@ -69,18 +70,22 @@ declare const ContrastReport: UIFieldClientComponent;
69
70
  declare const SectionHeading: UIFieldClientComponent;
70
71
  //#endregion
71
72
  //#region src/admin/publish-child.d.ts
72
- /** @deprecated Theme publish is the document Save button */
73
73
  declare const PublishChild: UIFieldClientComponent;
74
74
  //#endregion
75
75
  //#region src/admin/save-button.d.ts
76
76
  /**
77
- * Payload's document Save slot the same control row as Pages'
78
- * "Publish changes". Theme has no drafts; this publishes only the
79
- * open field tab. The tab is read after mount so SSR matches.
77
+ * Light/Dark preview for Colors, Typography, and Appearance. Lives in
78
+ * `beforeDocumentControls` so Payload's Save stays in the Save slot.
79
+ * Save writes that page's slice onto the stored Theme row.
80
+ */
81
+ declare function ThemeDocumentControls(): react_jsx_runtime0.JSX.Element;
82
+ /**
83
+ * Import-map Save slot used by the older single-Global Theme. Theme pages
84
+ * keep Payload's Save and put Light/Dark in `ThemeDocumentControls`.
80
85
  */
81
86
  declare function ThemeSaveButton(): react_jsx_runtime0.JSX.Element;
82
- /** Import-map alias — Theme still points `SaveButton` at this name. */
83
- declare const HiddenSaveButton: typeof ThemeSaveButton;
87
+ /** @deprecated Import map alias — ThemeDocumentControls is the Save-adjacent slot. */
88
+ declare function HiddenSaveButton(): react_jsx_runtime0.JSX.Element;
84
89
  //#endregion
85
90
  //#region src/admin/identity-fallback.d.ts
86
91
  /**
@@ -89,5 +94,27 @@ declare const HiddenSaveButton: typeof ThemeSaveButton;
89
94
  */
90
95
  declare const IdentityFallback: UIFieldClientComponent;
91
96
  //#endregion
92
- export { AppearanceField, ColorField, ColorScaleField, ContrastReport, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, PairingField, PublishChild, SectionHeading, ThemeSaveButton };
97
+ //#region src/admin/look-field.d.ts
98
+ /**
99
+ * Loads the Theme global and offers page-editor looks or included steps.
100
+ * A custom scale published on Colors appears here on the next load.
101
+ */
102
+ declare const LookField: TextFieldClientComponent;
103
+ //#endregion
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 };
93
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"],"mappings":";;;;;;;;;;cAWa,UAAA,EAAY,wBAAA;;;;;;;cCGZ,eAAA,EAAiB,yBAAA;;;;;;;cCQjB,YAAA,EAAc,yBAAA;;;;;;;;AFX3B;cGMa,SAAA,EAAW,0BAAA;;;;;;;cCNX,YAAA,EAAc,sBAAA;;;;;;;cCCd,eAAA,EAAiB,yBAAA;;;;;;;cCiDjB,cAAA,EAAgB,0BAAA;;;;;;;;cCtDhB,cAAA,EAAgB,sBAAA;;;;;;cCFhB,cAAA,EAAgB,sBAAA;;;;cCmIhB,YAAA,EAAc,sBAAA;;;;;;;;iBC7HX,eAAA,CAAA,GAAe,kBAAA,CAAA,GAAA,CAAA,OAAA;AVA/B;AAAA,cU0Ba,gBAAA,SAAgB,eAAA;;;;;;;cC7BhB,gBAAA,EAAkB,sBAAA"}
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"}