@bison-lab/payload-blocks 2.0.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.
@@ -0,0 +1,307 @@
1
+
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { ComponentType, ReactElement } from "react";
4
+ //#region src/image.d.ts
5
+ /**
6
+ * The image injection point.
7
+ *
8
+ * The package deliberately does not depend on `next` — a Payload site is not
9
+ * necessarily a Next.js site, and `next/image` needs per-site configuration
10
+ * (`remotePatterns` for the media route) that a package cannot supply. So
11
+ * renderers never construct an image element themselves; they render the
12
+ * component they were handed. A Next site writes one adapter around
13
+ * `next/image` and every block gets optimisation from it.
14
+ *
15
+ * This is a *component type*, not a render function, on purpose: a Server
16
+ * Component may pass a client component reference across the boundary, but not
17
+ * a closure. `imageComponent` therefore survives the trip from a server page
18
+ * into these client renderers, where a `renderImage` callback would not.
19
+ */
20
+ interface BlockImageProps {
21
+ src: string;
22
+ /** Always a string — see `resolveMedia`. Empty means decorative. */
23
+ alt: string;
24
+ width?: number;
25
+ height?: number;
26
+ className?: string;
27
+ /** Passed through to `next/image`'s `sizes`; ignored by the default. */
28
+ sizes?: string;
29
+ /** Set on the one image above the fold, typically the hero's. */
30
+ priority?: boolean;
31
+ }
32
+ type BlockImageComponent = ComponentType<BlockImageProps>;
33
+ /**
34
+ * The fallback when no `imageComponent` is supplied: a plain `<img>`. Correct
35
+ * everywhere and optimised nowhere, which is the right default for a package
36
+ * that cannot know what framework it landed in.
37
+ */
38
+ declare function DefaultBlockImage({
39
+ src,
40
+ alt,
41
+ width,
42
+ height,
43
+ className,
44
+ sizes,
45
+ priority
46
+ }: BlockImageProps): react_jsx_runtime0.JSX.Element;
47
+ //#endregion
48
+ //#region src/render-blocks.d.ts
49
+ /** The minimum a row must be for the dispatch to place it. */
50
+ interface BlockLike {
51
+ blockType: string;
52
+ id?: string | null;
53
+ }
54
+ /**
55
+ * What every renderer is handed.
56
+ *
57
+ * The neighbour props let a block adapt to what sits around it: `prevType` to
58
+ * close a seam against the block above, `runIndex` to alternate surfaces across
59
+ * back-to-back blocks of one type, `isLast` because the final block sits
60
+ * against the site footer.
61
+ *
62
+ * `containerClassName` and `imageComponent` are the two things a package block
63
+ * cannot decide for itself — the site's page measure, and how an image gets
64
+ * optimised. Both arrive already defaulted, so a renderer never checks them.
65
+ */
66
+ interface BlockRendererProps<B extends BlockLike = BlockLike> {
67
+ block: B;
68
+ /** Position on the page, hero included. */
69
+ index: number;
70
+ /** The type of the block before this one; absent on the first block. */
71
+ prevType?: string;
72
+ /** Position within a run of consecutive same-type blocks, from 0. */
73
+ runIndex: number;
74
+ isLast: boolean;
75
+ /** The site's page measure, for the band wrapper. */
76
+ containerClassName: string;
77
+ /** How this block turns a resolved image into an element. */
78
+ imageComponent: BlockImageComponent;
79
+ }
80
+ /**
81
+ * One renderer per block type, each typed to its own block.
82
+ *
83
+ * Written as a mapped type over the union so `hero` gets `HeroBlockData`, not
84
+ * the whole union. A site writes `satisfies BlockRegistryFor<AnyBlock>` where
85
+ * `AnyBlock` comes off its *generated* `Page` type — that is the compile-time
86
+ * layout lock, and it has to stay in the site, because only the site has
87
+ * generated types. The registry is a parameter here for exactly that reason.
88
+ */
89
+ type BlockRegistryFor<B extends BlockLike> = { [K in B["blockType"]]: ComponentType<BlockRendererProps<Extract<B, {
90
+ blockType: K;
91
+ }>>> };
92
+ /** Fallback page measure for a site that does not pass its own. */
93
+ declare const DEFAULT_CONTAINER = "mx-auto w-full max-w-7xl px-6";
94
+ interface RenderBlocksProps<B extends BlockLike> {
95
+ /** Pass `[...page.hero, ...page.layout]`, so the hero counts as index 0. */
96
+ blocks: B[];
97
+ registry: BlockRegistryFor<B>;
98
+ /** The site's page measure. Defaults to `DEFAULT_CONTAINER`. */
99
+ containerClassName?: string;
100
+ /** Defaults to a plain `<img>`; a Next site passes a `next/image` adapter. */
101
+ imageComponent?: BlockImageComponent;
102
+ }
103
+ /**
104
+ * Renders a page's blocks in order through the registry. A Server Component:
105
+ * it only maps and looks up, and each renderer decides its own nature.
106
+ */
107
+ declare function RenderBlocks<B extends BlockLike>({
108
+ blocks,
109
+ registry,
110
+ containerClassName,
111
+ imageComponent
112
+ }: RenderBlocksProps<B>): ReactElement;
113
+ //#endregion
114
+ //#region src/fields/link.d.ts
115
+ /** The shape `linkField`/`linkFields` produce once Payload generates types. */
116
+ interface LinkValue {
117
+ label?: string | null;
118
+ href?: string | null;
119
+ newTab?: boolean | null;
120
+ }
121
+ //#endregion
122
+ //#region src/media.d.ts
123
+ /**
124
+ * The upload side of the boundary.
125
+ *
126
+ * A Payload upload field holds either the row's id or, once depth resolves it,
127
+ * the whole document. Neither shape can be imported from here: `Media` is
128
+ * generated per site, and this package must never reach for a site's
129
+ * `payload-types`. So the doc is described structurally, and every renderer
130
+ * goes through `resolveMedia` rather than reading `.url` itself.
131
+ */
132
+ /**
133
+ * The subset of a Payload upload document a block renderer actually reads.
134
+ * Every site's generated `Media` interface is assignable to this, whatever
135
+ * else it carries.
136
+ *
137
+ * Deliberately no index signature: TypeScript refuses to assign an interface
138
+ * to a type with one, and a site's generated `Media` is always an interface.
139
+ * An index signature here would break exactly the structural match this type
140
+ * exists to provide.
141
+ */
142
+ interface MediaDoc {
143
+ url?: string | null;
144
+ alt?: string | null;
145
+ width?: number | null;
146
+ height?: number | null;
147
+ }
148
+ /** What an upload field holds before and after `depth` populates it. */
149
+ type MediaValue = number | string | MediaDoc | null | undefined;
150
+ //#endregion
151
+ //#region src/types.d.ts
152
+ /**
153
+ * The data shape of every block in this package, hand-written.
154
+ *
155
+ * A package cannot import a site's `payload-types`: those are generated per
156
+ * site, from that site's own config. So each block's row shape is written out
157
+ * here to match what Payload generates from the config next to it, and a
158
+ * site's generated types then match *structurally* — no import, no adapter.
159
+ *
160
+ * Two conventions make that match reliable:
161
+ *
162
+ * 1. **Everything is optional and nullable**, `blockType` aside. A generated
163
+ * `title: string` is assignable to `title?: string | null`, never the other
164
+ * way round, so the permissive direction is the only safe one. It is also
165
+ * the honest one: Payload skips validation on draft saves, so a live-preview
166
+ * render genuinely can receive a row with its required fields still empty.
167
+ * Renderers guard rather than assume.
168
+ * 2. **No index signatures.** TypeScript will not assign an interface to a type
169
+ * that has one, and a generated block type is always an interface.
170
+ *
171
+ * The field-name lists in `src/__tests__/configs.test.ts` are the lock between
172
+ * a config and its interface here: rename a field and that test fails.
173
+ */
174
+ /** The tail Payload appends to every block row. */
175
+ interface BlockRow<T extends string> {
176
+ id?: string | null;
177
+ blockName?: string | null;
178
+ blockType: T;
179
+ }
180
+ /**
181
+ * A Lexical document, structurally. The generated type carries an index
182
+ * signature and a narrower `format` union; both are assignable to this.
183
+ */
184
+ interface RichTextContent {
185
+ root: {
186
+ type: string;
187
+ children: unknown[];
188
+ direction: ("ltr" | "rtl") | null;
189
+ format: string;
190
+ indent: number;
191
+ version: number;
192
+ };
193
+ }
194
+ interface HeroBlockData extends BlockRow<"hero"> {
195
+ eyebrow?: string | null;
196
+ heading?: string | null;
197
+ body?: string | null;
198
+ tone?: ("sweep" | "dark" | "light") | null;
199
+ image?: MediaValue;
200
+ links?: LinkValue[] | null;
201
+ }
202
+ interface RichTextBlockData extends BlockRow<"richText"> {
203
+ content?: RichTextContent | null;
204
+ }
205
+ interface ShowcasePanelsItemData {
206
+ title?: string | null;
207
+ summary?: string | null;
208
+ image?: MediaValue;
209
+ href?: string | null;
210
+ numeral?: string | null;
211
+ id?: string | null;
212
+ }
213
+ interface ShowcasePanelsBlockData extends BlockRow<"showcasePanels"> {
214
+ items?: ShowcasePanelsItemData[] | null;
215
+ watermark?: string | null;
216
+ spineVariant?: ("numbered" | "volume" | "minimal") | null;
217
+ defaultActiveIndex?: number | null;
218
+ ariaLabel?: string | null;
219
+ labels?: {
220
+ selected?: string | null;
221
+ preview?: string | null;
222
+ };
223
+ }
224
+ interface ProcessStepsItemData {
225
+ title?: string | null;
226
+ description?: string | null;
227
+ image?: MediaValue;
228
+ step?: number | null;
229
+ id?: string | null;
230
+ }
231
+ interface ProcessStepsBlockData extends BlockRow<"processSteps"> {
232
+ items?: ProcessStepsItemData[] | null;
233
+ defaultActiveIndex?: number | null;
234
+ autoAdvance?: boolean | null;
235
+ autoAdvanceDuration?: number | null;
236
+ pauseOnHover?: boolean | null;
237
+ ariaLabel?: string | null;
238
+ labels?: {
239
+ pause?: string | null;
240
+ resume?: string | null;
241
+ };
242
+ }
243
+ interface FaqColumnsItemData {
244
+ question?: string | null;
245
+ /** A textarea, not a Lexical document — see the block's config for why. */
246
+ answer?: string | null;
247
+ id?: string | null;
248
+ }
249
+ interface FaqColumnsBlockData extends BlockRow<"faqColumns"> {
250
+ eyebrow?: string | null;
251
+ title?: string | null;
252
+ description?: string | null;
253
+ items?: FaqColumnsItemData[] | null;
254
+ cta?: {
255
+ title?: string | null;
256
+ linkText?: string | null;
257
+ href?: string | null;
258
+ newTab?: boolean | null;
259
+ };
260
+ sticky?: boolean | null;
261
+ type?: ("single" | "multiple") | null;
262
+ collapsible?: boolean | null;
263
+ }
264
+ interface TestimonialMasonryItemData {
265
+ content?: string | null;
266
+ author?: {
267
+ name?: string | null;
268
+ title?: string | null;
269
+ avatar?: MediaValue;
270
+ };
271
+ id?: string | null;
272
+ }
273
+ interface TestimonialMasonryBlockData extends BlockRow<"testimonialMasonry"> {
274
+ eyebrow?: string | null;
275
+ title?: string | null;
276
+ description?: string | null;
277
+ items?: TestimonialMasonryItemData[] | null;
278
+ link?: LinkValue;
279
+ minItemsForFade?: number | null;
280
+ maxVisibleRows?: number | null;
281
+ }
282
+ interface NapDepartmentData {
283
+ name?: string | null;
284
+ departmentType?: string | null;
285
+ phoneE164?: string | null;
286
+ phoneDisplay?: string | null;
287
+ id?: string | null;
288
+ }
289
+ interface NapBlockData extends BlockRow<"nap"> {
290
+ businessName?: string | null;
291
+ businessType?: string | null;
292
+ address?: {
293
+ streetAddress?: string | null;
294
+ addressLocality?: string | null;
295
+ addressRegion?: string | null;
296
+ postalCode?: string | null;
297
+ addressCountry?: string | null;
298
+ };
299
+ departments?: NapDepartmentData[] | null;
300
+ url?: string | null;
301
+ showName?: boolean | null;
302
+ headingLevel?: ("h2" | "h3" | "h4") | null;
303
+ emitJsonLd?: boolean | null;
304
+ }
305
+ //#endregion
306
+ export { RichTextBlockData as a, BlockLike as c, DEFAULT_CONTAINER as d, RenderBlocks as f, DefaultBlockImage as g, BlockImageProps as h, ProcessStepsBlockData as i, BlockRegistryFor as l, BlockImageComponent as m, HeroBlockData as n, ShowcasePanelsBlockData as o, RenderBlocksProps as p, NapBlockData as r, TestimonialMasonryBlockData as s, FaqColumnsBlockData as t, BlockRendererProps as u };
307
+ //# sourceMappingURL=types-BvRvDCDT.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-BvRvDCDT.d.mts","names":[],"sources":["../src/image.tsx","../src/render-blocks.tsx","../src/fields/link.ts","../src/media.ts","../src/types.ts"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@bison-lab/payload-blocks",
3
+ "version": "2.0.0",
4
+ "description": "Payload CMS block configs and renderers for the Bison Lab marketing blocks",
5
+ "homepage": "https://components.bisonlab.ai",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Bison-Lab-LLC/bisonlab-component-library.git",
9
+ "directory": "packages/payload-blocks"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/Bison-Lab-LLC/bisonlab-component-library/issues"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/index.mjs",
16
+ "types": "./dist/index.d.mts",
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.mjs",
20
+ "types": "./dist/index.d.mts"
21
+ },
22
+ "./react": {
23
+ "import": "./dist/react.mjs",
24
+ "types": "./dist/react.d.mts"
25
+ },
26
+ "./rich-text": {
27
+ "import": "./dist/rich-text.mjs",
28
+ "types": "./dist/rich-text.d.mts"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "peerDependencies": {
35
+ "@bison-lab/ui": "^2.0.0",
36
+ "@payloadcms/richtext-lexical": "^3.0.0",
37
+ "payload": "^3.0.0",
38
+ "react": "^18.0.0 || ^19.0.0",
39
+ "react-dom": "^18.0.0 || ^19.0.0"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "@bison-lab/ui": {
43
+ "optional": true
44
+ },
45
+ "@payloadcms/richtext-lexical": {
46
+ "optional": true
47
+ },
48
+ "react": {
49
+ "optional": true
50
+ },
51
+ "react-dom": {
52
+ "optional": true
53
+ }
54
+ },
55
+ "devDependencies": {
56
+ "@payloadcms/richtext-lexical": "^3.88.0",
57
+ "@testing-library/jest-dom": "^6.9.1",
58
+ "@testing-library/react": "^16.3.2",
59
+ "@types/react": "^19.2.14",
60
+ "@types/react-dom": "^19.2.3",
61
+ "jsdom": "^29.0.1",
62
+ "payload": "^3.88.0",
63
+ "react": "^19.2.4",
64
+ "react-dom": "^19.2.4",
65
+ "tsdown": "^0.21.0",
66
+ "typescript": "^5.9.3",
67
+ "vitest": "^4.1.2",
68
+ "@bison-lab/ui": "2.0.0"
69
+ },
70
+ "publishConfig": {
71
+ "access": "public"
72
+ },
73
+ "scripts": {
74
+ "build": "tsdown",
75
+ "dev": "tsdown --watch",
76
+ "clean": "rm -rf dist",
77
+ "typecheck": "tsc --noEmit",
78
+ "test": "vitest run",
79
+ "test:watch": "vitest"
80
+ }
81
+ }