@bison-lab/payload-core 3.12.0 → 3.13.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
@@ -22,10 +22,10 @@ lockstep.
22
22
 
23
23
  | Import | Contents | Runs where |
24
24
  | ---------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
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. |
25
+ | `@bison-lab/payload-core` | `seoPlugin`, `createTheme`, `createBrandAssets`, `createRoles`, `createFeatures`, `createPages`, `createUsers`, `createMedia`, `adminOnlyApiTab`, `seedTheme`, `seedRoles`, `seedFeatures`, 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, the Roles matrix field, and the Users Roles checklist | Admin. Referenced by import-map string; `generate:importmap` writes it. |
28
+ | `@bison-lab/payload-core/admin` | Theme child fields, the Roles and Features matrices, 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
@@ -138,14 +138,16 @@ 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
140
  **1. Register the Global.** Access is required — Theme does not read the
141
- Roles Global. Pass `canManageBrand` as `update`.
141
+ Roles or Features Global. Pass `canUseFeature("theme")` as `update`
142
+ (sites can keep `canManageBrand` until they adopt the switchboard).
142
143
 
143
144
  ```ts
144
145
  // payload.config.ts
145
146
  import {
146
147
  BRAND_ASSETS_SLUG,
147
- canManageBrand,
148
148
  createBrandAssets,
149
+ canUseFeature,
150
+ createFeatures,
149
151
  createRoles,
150
152
  createTheme,
151
153
  isAuthenticated,
@@ -155,13 +157,14 @@ import bisonConfig from "../bison.config.json";
155
157
  export default buildConfig({
156
158
  collections: [
157
159
  createBrandAssets({
158
- access: { read: () => true, update: canManageBrand },
160
+ access: { read: () => true, update: canUseFeature("brand-assets") },
159
161
  }),
160
162
  ],
161
163
  globals: [
162
164
  createRoles(),
165
+ createFeatures(),
163
166
  ...createTheme({
164
- access: { read: isAuthenticated, update: canManageBrand },
167
+ access: { read: isAuthenticated, update: canUseFeature("theme") },
165
168
  seed: bisonConfig,
166
169
  logo: { collection: BRAND_ASSETS_SLUG },
167
170
  identity: {
@@ -170,6 +173,10 @@ export default buildConfig({
170
173
  mark: { url: "/logo-mark.svg", alt: "Acme mark" },
171
174
  },
172
175
  },
176
+ colorUsages: {
177
+ collections: ["pages"],
178
+ globals: ["navigation"],
179
+ },
173
180
  onPublish: async () => {
174
181
  revalidateTag("theme");
175
182
  },
@@ -178,6 +185,15 @@ export default buildConfig({
178
185
  });
179
186
  ```
180
187
 
188
+ **Color usages.** `createTheme({ colorUsages })` is the only site wiring for
189
+ "is this custom color assigned?" Name every collection and global that
190
+ stores a `lookField` / `colorTokenField` (or a string token those fields
191
+ wrote). The package scans those documents — drafts included — and
192
+ rewrites tokens when Colors Delete needs a replacement. Omit the option,
193
+ or pass empty arrays, and every additional color is unused and deletes
194
+ immediately. A new look surface is added to `colorUsages`, not copied
195
+ into a site helper. Site adopt names the slugs (SPI-93).
196
+
181
197
  Then `payload generate:importmap` (the Theme child fields resolve from
182
198
  `@bison-lab/payload-core/admin`), `payload generate:types`, and
183
199
  `payload migrate:create`.
@@ -187,12 +203,13 @@ so the site renders what `bison-theme.css` rendered before anyone opens the
187
203
  admin:
188
204
 
189
205
  ```ts
190
- import { seedRoles, seedTheme } from "@bison-lab/payload-core";
206
+ import { seedFeatures, seedRoles, seedTheme } from "@bison-lab/payload-core";
191
207
  import bisonConfig from "../bison.config.json";
192
208
 
193
209
  export async function up({ payload }) {
194
210
  await seedTheme(payload, bisonConfig);
195
- await seedRoles(payload);
211
+ await seedRoles(payload); // pass the same extras as createRoles, if any
212
+ await seedFeatures(payload); // pass the same extras as createFeatures, if any
196
213
  }
197
214
  ```
198
215
 
@@ -233,7 +250,8 @@ Logo, favicon, and mobile-menu mark live in a locked cupboard, not in
233
250
  ordinary Media. Call `createBrandAssets` and point Theme at
234
251
  `BRAND_ASSETS_SLUG`. Access is the same shape as `createTheme`: `read` is
235
252
  typically public so the live site can load the file; `update` is
236
- `canManageBrand` and covers create, update, delete, and version history.
253
+ `canUseFeature("brand-assets")` (or `canManageBrand` until the site
254
+ adopts the switchboard) and covers create, update, delete, and version history.
237
255
  SVG preferred, PNG and ICO allowed; an SVG is sanitized on upload.
238
256
  Versions stay on so a replaced file can be rolled back.
239
257
 
@@ -243,20 +261,49 @@ has its accessible name. Then `payload migrate:create`.
243
261
  ## Roles
244
262
 
245
263
  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).
264
+ Ticks are Content, Brand, Publish, and Users. Defaults ship in the
265
+ package (Brand on Designer only; Admin + Designer both store; Developer
266
+ is exclusive). A site may pass `extras` into `createRoles` — each extra
267
+ is a slug, a display label, and default ticks — and an Admin can add
268
+ further custom rows and edit any row’s name. Seed slugs stay read-only.
249
269
  `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.
270
+ back to that seed (plus extras). The package never writes `developer`
271
+ onto a user row.
272
+
273
+ ```ts
274
+ createRoles({
275
+ extras: [{ role: "editor", label: "Editor", content: true, brand: false, publish: false, users: false }],
276
+ });
277
+ ```
278
+
279
+ ## Features
280
+
281
+ Settings → Features is a feature × role grid. The catalogue is code:
282
+ Pages, Media, Theme, Brand assets, Users, Roles, and Features. A site
283
+ may pass `extras` into `createFeatures` — those rows appear only there.
284
+ `canUseFeature(slug)` reads the saved grid and falls back to Content →
285
+ Pages/Media and Brand → Theme/Brand assets when the Global is empty.
286
+ Users, Roles, and Features cannot be turned off; Developer is always
287
+ allowed. `createPages` / `createMedia` use `canUseFeature` for create
288
+ and update (and `admin.hidden`). Theme and brand-assets still take
289
+ `access` arguments — pass `canUseFeature("theme")` /
290
+ `canUseFeature("brand-assets")` as `update`.
291
+
292
+ ```ts
293
+ createFeatures({
294
+ extras: [{ slug: "doctors", label: "Doctor search" }],
295
+ });
296
+ ```
251
297
 
252
298
  ## Pages, users, and media
253
299
 
254
300
  `createPages`, `createUsers`, `createMedia`, `slugField`, and
255
301
  `adminOnlyApiTab` ship from the same React-free entry. Pages take the
256
302
  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.
303
+ path. Users sit under Settings next to Roles, take `secureCookies`, and
304
+ offer whatever rows the Global (or the seed plus the same `extras`) has.
305
+ The checklist labels are the editable names. `adminOnlyApiTab` shows the
306
+ document API tab only to Developer.
260
307
 
261
308
  ## No generated types
262
309
 
package/dist/admin.d.mts CHANGED
@@ -19,10 +19,10 @@ 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. 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.
22
+ * Custom colors: the same scale controls as system colors. Unused: the
23
+ * Theme store's color-usages endpoint returns nothing and the row is
24
+ * gone. In use: pick a live replacement; confirm rewrites stored tokens
25
+ * then drops the row. Success and Destructive stay off that list.
26
26
  */
27
27
  declare const LibraryField: ArrayFieldClientComponent;
28
28
  //#endregion
@@ -103,18 +103,37 @@ declare const LookField: TextFieldClientComponent;
103
103
  //#endregion
104
104
  //#region src/admin/roles-matrix-field.d.ts
105
105
  /**
106
- * Payload's array field: drag rank stays, add/remove go away. Reset writes
107
- * the package seed back onto the field.
106
+ * Payload's array field: drag rank stays, add is for custom rows, seed
107
+ * rows have no remove. Reset restores seed ticks and package labels.
108
108
  */
109
109
  declare const RolesMatrixField: ArrayFieldClientComponent;
110
110
  //#endregion
111
+ //#region src/admin/roles-row-label.d.ts
112
+ /**
113
+ * Array row header. Shows the current display name, not “Role 01”.
114
+ */
115
+ declare function RolesRowLabel(): react_jsx_runtime0.JSX.Element;
116
+ //#endregion
117
+ //#region src/admin/role-slug-field.d.ts
118
+ /**
119
+ * Seed slugs stay read-only. A custom row's slug is typed here.
120
+ */
121
+ declare const RoleSlugField: TextFieldClientComponent;
122
+ //#endregion
111
123
  //#region src/admin/roles-field.d.ts
112
124
  /**
113
125
  * 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.
126
+ * Roles Global, or the seed plus extras). Copy is `roleDescription`.
127
+ * Developer is exclusive; a custom role does not clear Designer.
116
128
  */
117
129
  declare const RolesField: SelectFieldClientComponent;
118
130
  //#endregion
119
- export { AppearanceField, ColorField, ColorScaleField, ContrastReport, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RolesField, RolesMatrixField, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
131
+ //#region src/admin/features-matrix-field.d.ts
132
+ /**
133
+ * Feature × role grid. Columns come from the Roles Global (or the seed).
134
+ * Locked rows and Developer cannot be cleared.
135
+ */
136
+ declare const FeaturesMatrixField: ArrayFieldClientComponent;
137
+ //#endregion
138
+ export { AppearanceField, ColorField, ColorScaleField, ContrastReport, FeaturesMatrixField, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RoleSlugField, RolesField, RolesMatrixField, RolesRowLabel, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
120
139
  //# 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","../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"}
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-row-label.tsx","../src/admin/role-slug-field.tsx","../src/admin/roles-field.tsx","../src/admin/features-matrix-field.tsx"],"mappings":";;;;;;;;;;cAWa,UAAA,EAAY,wBAAA;;;;;;;cCsBZ,eAAA,EAAiB,yBAAA;;;;;;;;ADtB9B;cEgBa,YAAA,EAAc,yBAAA;;;;;;;;AFhB3B;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;;;;;;;cCYX,gBAAA,EAAkB,yBAAA;;;;;;iBCjBf,aAAA,CAAA,GAAa,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;cCChB,aAAA,EAAe,wBAAA;;;;;;;;cC+Cf,UAAA,EAAY,0BAAA;;;;;;;cCtCZ,mBAAA,EAAqB,yBAAA"}