blocks-dusted 0.1.0 → 0.1.2

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.
Files changed (50) hide show
  1. package/README.md +967 -3
  2. package/package.json +40 -40
  3. package/src/commands/add.js +143 -45
  4. package/src/commands/list.js +2 -2
  5. package/src/installers/checkRequirements.js +1 -0
  6. package/src/installers/copyTemplateFiles.js +23 -2
  7. package/src/installers/patchPayloadConfigCollections.js +92 -0
  8. package/src/installers/writeInstalledBlockReadme.js +17 -4
  9. package/src/registry/listTemplates.js +16 -7
  10. package/src/registry/loadTemplateManifest.js +20 -11
  11. package/src/registry/validateTemplateManifest.js +6 -5
  12. package/src/utils/paths.js +7 -0
  13. package/templates/blocks/DD-BookCall/Component.tsx +535 -573
  14. package/templates/blocks/DD-CardTemplate01/Component.tsx +45 -49
  15. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -266
  16. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -432
  17. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -272
  18. package/templates/blocks/DD-Contact/Component.tsx +434 -439
  19. package/templates/blocks/DD-Contact/config.ts +8 -3
  20. package/templates/blocks/DD-FeatCat/Component.tsx +302 -361
  21. package/templates/blocks/DD-FeatCat/config.ts +201 -204
  22. package/templates/blocks/DD-FeatStrip/Component.tsx +171 -201
  23. package/templates/blocks/DD-Hero/Component.tsx +297 -317
  24. package/templates/blocks/DD-HorizontalScroll/Component.tsx +244 -303
  25. package/templates/blocks/DD-MasonaryMedia/Component.tsx +202 -228
  26. package/templates/blocks/DD-MasonaryMedia/config.ts +13 -14
  27. package/templates/blocks/DD-Pricing/Component.tsx +372 -380
  28. package/templates/blocks/DD-Process/Component.tsx +149 -155
  29. package/templates/blocks/DD-Section/Component.tsx +266 -327
  30. package/templates/blocks/DD-Services/Component.tsx +176 -188
  31. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -317
  32. package/templates/blocks/DD-Slider-A/Component.tsx +237 -252
  33. package/templates/blocks/DD-StackCards/Component.tsx +137 -160
  34. package/templates/blocks/DD-Team/Component.tsx +247 -265
  35. package/templates/blocks/DD-TechStack/Component.tsx +57 -72
  36. package/templates/blocks/DD-Testimonials/Component.tsx +147 -147
  37. package/templates/blocks/DD-Testimonials/config.ts +66 -66
  38. package/templates/blocks/DD-Work/Component.tsx +315 -328
  39. package/templates/blocks/DD-Work-B/Component.tsx +294 -320
  40. package/templates/collections/Testimonials/README.md +11 -0
  41. package/templates/collections/Testimonials/Testimonials.ts +161 -0
  42. package/templates/collections/Testimonials/manifest.json +55 -0
  43. package/templates/components/RichText/README.md +13 -0
  44. package/templates/components/RichText/converter/componentConverter/blocks.tsx +43 -0
  45. package/templates/components/RichText/converter/componentConverter/types.ts +11 -0
  46. package/templates/components/RichText/converter/index.tsx +18 -0
  47. package/templates/components/RichText/converter/internalLinks.tsx +45 -0
  48. package/templates/components/RichText/converter/textConverter.tsx +27 -0
  49. package/templates/components/RichText/index.tsx +35 -0
  50. package/templates/components/RichText/manifest.json +80 -0
package/README.md CHANGED
@@ -4,6 +4,348 @@
4
4
 
5
5
  The GitHub source repository is private. That does not prevent installation from npm after the package is published, including when the published npm package is public.
6
6
 
7
+ ## Project Objective
8
+
9
+ `blocks-dusted` is a reusable Payload CMS CLI.
10
+
11
+ The end goal is **not** simply a block installer.
12
+
13
+ It is a complete installation framework capable of progressively installing reusable Payload features into existing Payload projects.
14
+
15
+ Everything should be manifest-driven, repeatable, safe, versionable, and easy to extend.
16
+
17
+ Eventually a developer should be able to build an entire Payload project from reusable packages.
18
+
19
+ Example:
20
+
21
+ ```bash
22
+ pnpm dlx blocks-dusted add DD-Hero
23
+ pnpm dlx blocks-dusted add DD-Contact
24
+ pnpm dlx blocks-dusted add DD-Header
25
+ pnpm dlx blocks-dusted add DD-Footer
26
+ ```
27
+
28
+ without manually copying files.
29
+
30
+ ## Current Status
31
+
32
+ Repository
33
+
34
+ ```text
35
+ https://github.com/Hadizainal/blocks-dusted
36
+ ```
37
+
38
+ Current visibility:
39
+
40
+ - Private
41
+
42
+ Current npm package:
43
+
44
+ ```text
45
+ blocks-dusted
46
+ ```
47
+
48
+ Current executable:
49
+
50
+ ```text
51
+ blocks-dusted
52
+ ```
53
+
54
+ Published version:
55
+
56
+ ```text
57
+ 0.1.1
58
+ ```
59
+
60
+ Verified working through:
61
+
62
+ ```text
63
+ pnpm dlx blocks-dusted
64
+ ```
65
+
66
+ The CLI has been successfully tested from a completely separate Payload project.
67
+
68
+ ## Current CLI Features
69
+
70
+ Implemented
71
+
72
+ - manifest-driven registry
73
+ - block listing
74
+ - doctor command
75
+ - dry-run support
76
+ - block installation
77
+ - shared file installation
78
+ - dependency detection
79
+ - manual dependency reporting
80
+ - RenderBlocks patching
81
+ - Collection block registration
82
+ - collision protection
83
+ - shared file protection
84
+ - automatic backups
85
+ - installed block README generation
86
+ - package validation
87
+ - packed tarball validation
88
+ - clean-room installation tests
89
+ - npm distribution
90
+
91
+ Not implemented intentionally
92
+
93
+ - automatic dependency installation
94
+ - automatic Payload generators
95
+ - automatic migrations
96
+ - automatic builds
97
+
98
+ These should remain manual unless explicitly changed later.
99
+
100
+ ## Immediate Next Work
101
+
102
+ The existing blocks are **not yet considered complete**.
103
+
104
+ Many were converted from Designs Dusted and now require updating.
105
+
106
+ Examples include:
107
+
108
+ ### Component cleanup
109
+
110
+ Replace unnecessary wrappers.
111
+
112
+ Example:
113
+
114
+ ```text
115
+ <section>
116
+ ```
117
+
118
+ should become
119
+
120
+ ```text
121
+ <div>
122
+ ```
123
+
124
+ where appropriate.
125
+
126
+ ### Section IDs
127
+
128
+ Blocks should consistently expose configurable section IDs.
129
+
130
+ Many currently require updating.
131
+
132
+ ### URL fields
133
+
134
+ Numerous blocks still contain older URL field implementations.
135
+
136
+ They should be migrated to the latest shared URL configuration.
137
+
138
+ ### Button configuration
139
+
140
+ Older button implementations still exist.
141
+
142
+ These should be replaced with the current shared implementation.
143
+
144
+ ### Shared utilities
145
+
146
+ Many older helper implementations still exist.
147
+
148
+ Future block updates should migrate toward shared reusable utilities instead of duplicated logic.
149
+
150
+ ## Future Development
151
+
152
+ The project is moving beyond simple blocks.
153
+
154
+ The next stage introduces reusable project infrastructure.
155
+
156
+ Think in layers.
157
+
158
+ ### Layer 1
159
+
160
+ Reusable Blocks
161
+
162
+ Examples
163
+
164
+ - Hero
165
+ - Contact
166
+ - Pricing
167
+ - Carousel
168
+ - Testimonials
169
+
170
+ These install independently.
171
+
172
+ ### Layer 2
173
+
174
+ Reusable Core Components
175
+
176
+ Examples
177
+
178
+ - Button
179
+ - Rich Text
180
+ - Section wrapper
181
+ - URL utilities
182
+ - Shared fields
183
+ - Icon picker
184
+ - Media helpers
185
+
186
+ These are dependencies used by many blocks.
187
+
188
+ ### Layer 3
189
+
190
+ Reusable Globals
191
+
192
+ Examples
193
+
194
+ - Header
195
+ - Footer
196
+ - Logos
197
+ - Cookie Consent
198
+ - Newsletter Modal
199
+
200
+ Installation should:
201
+
202
+ - copy component
203
+ - register Payload global
204
+ - patch payload.config.ts
205
+ - preserve user changes
206
+ - create backups
207
+
208
+ ### Layer 4
209
+
210
+ Frontend Infrastructure
211
+
212
+ Examples
213
+
214
+ - RenderBlocks
215
+ - Layout
216
+ - Providers
217
+ - Navigation
218
+ - Animations
219
+ - Utilities
220
+ - Hooks
221
+ - Context Providers
222
+
223
+ These require safe project patching.
224
+
225
+ ### Layer 5
226
+
227
+ Project Features
228
+
229
+ Entire reusable systems.
230
+
231
+ Examples
232
+
233
+ - Quote System
234
+ - Newsletter
235
+ - Analytics
236
+ - Search
237
+ - Commerce
238
+ - Authentication
239
+ - OpenPanel
240
+ - Stripe
241
+
242
+ Each should install as a complete feature rather than individual files.
243
+
244
+ ## Installation Philosophy
245
+
246
+ Everything should remain manifest-driven.
247
+
248
+ Avoid project-specific logic.
249
+
250
+ Every installer should know:
251
+
252
+ - files
253
+ - shared files
254
+ - dependencies
255
+ - registrations
256
+ - patch operations
257
+ - manual follow-up
258
+
259
+ from the manifest.
260
+
261
+ Avoid hardcoding block-specific behaviour.
262
+
263
+ ## Safety Philosophy
264
+
265
+ The CLI must remain conservative.
266
+
267
+ Never overwrite existing work.
268
+
269
+ Always prefer reporting over guessing.
270
+
271
+ Continue protecting:
272
+
273
+ - destination collisions
274
+ - shared files
275
+ - backups
276
+ - dry-run
277
+ - manual dependency installation
278
+ - manual generators
279
+
280
+ Safety is more important than convenience.
281
+
282
+ ## Future Installer Capabilities
283
+
284
+ The installer will become progressively smarter.
285
+
286
+ Potential future installers include:
287
+
288
+ - blocks
289
+ - globals
290
+ - components
291
+ - providers
292
+ - utilities
293
+ - hooks
294
+ - layouts
295
+ - Payload plugins
296
+ - admin customisations
297
+ - frontend features
298
+
299
+ Each installer should follow the same architecture.
300
+
301
+ ## Codex Guidance
302
+
303
+ Codex should optimise for:
304
+
305
+ - reusable architecture
306
+ - manifest-driven behaviour
307
+ - minimal hardcoding
308
+ - safe source patching
309
+ - deterministic installs
310
+ - idempotent operations
311
+ - backward compatibility where appropriate
312
+
313
+ Avoid writing project-specific installers.
314
+
315
+ Everything should remain generic.
316
+
317
+ ## Definition of Success
318
+
319
+ Eventually this should become a package where installing an entire Designs Dusted ecosystem into a fresh Payload project is largely declarative.
320
+
321
+ For example:
322
+
323
+ ```bash
324
+ pnpm dlx blocks-dusted add DD-Hero
325
+ pnpm dlx blocks-dusted add DD-Header
326
+ pnpm dlx blocks-dusted add DD-Footer
327
+ pnpm dlx blocks-dusted add DD-QuoteSystem
328
+ pnpm dlx blocks-dusted add DD-Newsletter
329
+ ```
330
+
331
+ Each command should:
332
+
333
+ - install files
334
+ - install shared resources
335
+ - safely patch the project
336
+ - report manual follow-up steps
337
+ - never destroy existing work
338
+
339
+ without requiring the installer to understand each feature individually.
340
+
341
+ ## Current Milestone
342
+
343
+ - Package published to npm.
344
+ - CLI verified from a clean Payload project.
345
+ - Manifest architecture established.
346
+
347
+ The next milestone is **improving the quality and breadth of installable assets**, not redesigning the CLI architecture. The architecture is now in place; future work should focus on expanding it while preserving its generic, manifest-driven design.
348
+
7
349
  ## Main Workflow
8
350
 
9
351
  Run commands from the root of your Payload project:
@@ -13,6 +355,7 @@ pnpm dlx blocks-dusted list
13
355
  pnpm dlx blocks-dusted doctor
14
356
  pnpm dlx blocks-dusted add DD-Hero --dry-run
15
357
  pnpm dlx blocks-dusted add DD-Hero
358
+ pnpm dlx blocks-dusted add RichText
16
359
  ```
17
360
 
18
361
  Use `blocks-dusted list` first to see the exact available block names in the package. `DD-Hero` is an existing block in the current manifest registry.
@@ -20,7 +363,7 @@ Use `blocks-dusted list` first to see the exact available block names in the pac
20
363
  The preferred install command after publication is:
21
364
 
22
365
  ```bash
23
- pnpm dlx blocks-dusted add <BlockName>
366
+ pnpm dlx blocks-dusted add <TemplateName>
24
367
  ```
25
368
 
26
369
  ## Commands
@@ -33,7 +376,8 @@ blocks-dusted doctor
33
376
  blocks-dusted doctor --cwd C:\Projects\my-payload-site
34
377
  blocks-dusted add DD-Hero --dry-run
35
378
  blocks-dusted add DD-Hero --no-register
36
- blocks-dusted add DD-Hero --cwd C:\Projects\my-payload-site
379
+ blocks-dusted add DD-Hero --cwd C:\Projects\my-payload-site
380
+ blocks-dusted add RichText --cwd C:\Projects\my-payload-site
37
381
  ```
38
382
 
39
383
  `--cwd` targets a Payload project directory without changing your shell directory. Relative `--cwd` values resolve from the directory where you launched the command.
@@ -59,10 +403,630 @@ pnpm payload generate:importmap
59
403
 
60
404
  The CLI does not run migrations or build the target project.
61
405
 
406
+ ## Payload Block Standard
407
+
408
+ ### Purpose
409
+
410
+ This standard defines the required structure for Payload CMS frontend blocks. The objective is consistent markup, predictable targeting, manageable admin configuration, and block-specific CSS support.
411
+
412
+ ### Component Standards
413
+
414
+ #### Top-Level Wrapper
415
+
416
+ If the original block uses a top-level `<section>`, convert it to a `<div>`. `RenderBlocks` provides the section wrapper.
417
+
418
+ The top-level wrapper must include:
419
+
420
+ ```tsx
421
+ id={sectionId ?? undefined}
422
+ data-block-type="[component_name]"
423
+ ```
424
+
425
+ #### Section ID
426
+
427
+ Every converted block must support `sectionId`.
428
+
429
+ Destructure it from the generated Payload block props and apply it to the top-level wrapper:
430
+
431
+ ```tsx
432
+ id={sectionId ?? undefined}
433
+ ```
434
+
435
+ #### Custom CSS
436
+
437
+ Every converted block must support `customCSS`.
438
+
439
+ ```tsx
440
+ <>
441
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
442
+ <div>{/* block */}</div>
443
+ </>
444
+ ```
445
+
446
+ Do not remove or rewrite supplied custom CSS.
447
+
448
+ #### `useInjectStyle` Pattern
449
+
450
+ When original component SCSS must be converted, use the project `useInjectStyle` pattern:
451
+
452
+ ```tsx
453
+ import { useInjectStyle } from "@/hooks/useInjectStyle";
454
+
455
+ const bannerStyles = `
456
+ /* converted styles */
457
+ `;
458
+
459
+ useInjectStyle(bannerStyles, "banner-inline-styles");
460
+ ```
461
+
462
+ Required naming format:
463
+
464
+ ```text
465
+ [component_name]Styles
466
+ [component_name]-inline-styles
467
+ ```
468
+
469
+ If no converted CSS is required, the standard commented placeholders may remain.
470
+
471
+ #### Data Attributes
472
+
473
+ The top-level block must include:
474
+
475
+ ```tsx
476
+ data-block-type="[component_name]"
477
+ ```
478
+
479
+ Inner structural elements may use `data-type` when useful for identifying block structure. This is optional and depends on block complexity.
480
+
481
+ Example:
482
+
483
+ ```tsx
484
+ data-type="banner-style"
485
+ ```
486
+
487
+ RichText components should include:
488
+
489
+ ```tsx
490
+ data-content-type="[component_name]-richtext"
491
+ ```
492
+
493
+ ### Payload Config Standards
494
+
495
+ #### Section ID Field
496
+
497
+ ```ts
498
+ {
499
+ name: 'sectionId',
500
+ type: 'text',
501
+ label: 'Section ID',
502
+ admin: {
503
+ description: 'Optional HTML ID used for anchor links and section targeting.'
504
+ }
505
+ }
506
+ ```
507
+
508
+ #### Custom CSS Field
509
+
510
+ Every converted block config must include:
511
+
512
+ ```ts
513
+ {
514
+ name: 'customCSS',
515
+ type: 'code',
516
+ label: 'Custom CSS',
517
+ admin: {
518
+ language: 'css'
519
+ }
520
+ }
521
+ ```
522
+
523
+ Do not use a plain textarea for custom CSS.
524
+
525
+ #### Admin Viewport Management
526
+
527
+ Do not place `customCSS` directly in a long flat field list. Custom CSS can become large and create excessive vertical scrolling in the Payload admin viewport.
528
+
529
+ Place `customCSS` in either:
530
+
531
+ - A dedicated `Custom CSS` tab.
532
+ - A collapsible field when tabs are unnecessary.
533
+
534
+ Prefer a dedicated `Custom CSS` tab when the block already benefits from grouped admin fields.
535
+
536
+ ```ts
537
+ {
538
+ type: 'tabs',
539
+ tabs: [
540
+ {
541
+ label: 'Content',
542
+ fields: [
543
+ // block content fields
544
+ ]
545
+ },
546
+ {
547
+ label: 'Custom CSS',
548
+ fields: [
549
+ {
550
+ name: 'customCSS',
551
+ type: 'code',
552
+ label: 'Custom CSS',
553
+ admin: {
554
+ language: 'css'
555
+ }
556
+ }
557
+ ]
558
+ }
559
+ ]
560
+ }
561
+ ```
562
+
563
+ #### Existing Fields and Behaviour
564
+
565
+ Preserve existing block fields, options, defaults, required states, frontend appearance, responsiveness, animations, pseudo-elements, specificity, and behaviour.
566
+
567
+ Do not invent new content fields beyond the standard `sectionId` and `customCSS` additions unless explicitly requested.
568
+
569
+ Do not manually alter generated Payload interfaces.
570
+
571
+ ### Canonical Component Pattern
572
+
573
+ ```tsx
574
+ import type { BannerBlock as BannerBlockProps } from "src/payload-types";
575
+
576
+ import { cn } from "@/utilities/ui";
577
+ import React from "react";
578
+ import RichText from "@/components/RichText";
579
+
580
+ // import { useInjectStyle } from '@/hooks/useInjectStyle' - uncomment if required
581
+
582
+ type Props = {
583
+ className?: string;
584
+ } & BannerBlockProps;
585
+
586
+ /* Inlined CSS (converted from the original SCSS to [component_name]Styles) format */
587
+ // const bannerStyles = `
588
+ // // add styles here if needed
589
+ // `
590
+
591
+ export const BannerBlock: React.FC<Props> = ({
592
+ className,
593
+ content,
594
+ style,
595
+ customCSS,
596
+ sectionId,
597
+ }) => {
598
+ // Inject styles once, regardless of how many instances are rendered.
599
+ // Keep format standardised: [component_name]Styles, [component_name]-inline-styles.
600
+ // useInjectStyle(bannerStyles, 'banner-inline-styles') - uncomment if required
601
+
602
+ return (
603
+ <>
604
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
605
+ <div
606
+ id={sectionId ?? undefined}
607
+ data-block-type="banner"
608
+ className={cn("mx-auto my-4 w-full", className)}
609
+ >
610
+ <div data-type="banner-style">
611
+ <RichText
612
+ data-content-type="banner-richtext"
613
+ data={content}
614
+ enableGutter={false}
615
+ enableProse={true}
616
+ />
617
+ </div>
618
+ </div>
619
+ </>
620
+ );
621
+ };
622
+ ```
623
+
624
+ ### Execution Prompt
625
+
626
+ > Review the target Payload CMS block component and its block config, then update both to comply with `Payload Block Standard.md`.
627
+ >
628
+ > Inspect the existing component and config before editing. Preserve the block's current appearance, responsive behaviour, animations, pseudo-elements, selectors, specificity, field options, defaults, required states, and functionality.
629
+ >
630
+ > Apply the standard carefully:
631
+ >
632
+ > - Convert a top-level `<section>` to `<div>` because `RenderBlocks` provides the section wrapper.
633
+ > - Add `sectionId` support and apply `id={sectionId ?? undefined}` to the top-level block wrapper.
634
+ > - Add `data-block-type="[component_name]"` to the top-level block wrapper.
635
+ > - Add useful `data-type` attributes only where inner structural identification is beneficial.
636
+ > - Add `data-content-type="[component_name]-richtext"` to RichText components.
637
+ > - Add `customCSS` support and render it with `<style dangerouslySetInnerHTML={{ __html: customCSS }} />`.
638
+ > - If component SCSS exists, convert it to the `useInjectStyle` pattern using `[component_name]Styles` and `[component_name]-inline-styles`.
639
+ > - Add matching `sectionId` and `customCSS` fields to the Payload block config.
640
+ > - `customCSS` must use `type: 'code'` with `admin.language: 'css'`.
641
+ > - Place `customCSS` in a dedicated tab or collapsible field so long CSS does not create excessive admin viewport scrolling.
642
+ > - Preserve all existing block-specific fields and behaviour.
643
+ > - Do not invent fields, redesign the component, refactor unrelated code, or change behaviour outside this standard.
644
+ >
645
+ > Update only the files required for this block. Review the final diff against the standard before completing the task.
646
+
647
+ ## Payload Rich Text Dusted Standard
648
+
649
+ ### Purpose - RichText Dusted Standard
650
+
651
+ This document defines the standard folder structure and implementation rules for a reusable frontend RichText component in a Payload CMS project.
652
+
653
+ This is a standard, not a requirement that every Payload project must contain every optional feature described below. Always inspect the target project before making changes. Preserve project-specific requirements and add only the parts that the project needs.
654
+
655
+ The objective is to keep RichText rendering:
656
+
657
+ - predictable;
658
+ - reusable;
659
+ - typed;
660
+ - easy to extend;
661
+ - separated by responsibility;
662
+ - compatible with the target project's Payload schema;
663
+ - free from unrelated project-specific assumptions.
664
+
665
+ ### Standard Folder Structure
666
+
667
+ ```text
668
+ src/
669
+ +-- components/
670
+ +-- RichText/
671
+ +-- index.tsx
672
+ +-- converter/
673
+ +-- index.tsx
674
+ +-- internalLinks.tsx
675
+ +-- textConverter.tsx
676
+ +-- componentConverter/
677
+ +-- blocks.tsx
678
+ +-- types.ts
679
+ ```
680
+
681
+ ### Base and Optional Files
682
+
683
+ #### Base RichText structure
684
+
685
+ These files form the base structure:
686
+
687
+ ```text
688
+ src/components/RichText/index.tsx
689
+ src/components/RichText/converter/index.tsx
690
+ src/components/RichText/converter/internalLinks.tsx
691
+ src/components/RichText/converter/textConverter.tsx
692
+ ```
693
+
694
+ #### Optional embedded-block extension
695
+
696
+ Add this folder only when the target project permits Payload blocks to be embedded inside RichText:
697
+
698
+ ```text
699
+ src/components/RichText/converter/componentConverter/blocks.tsx
700
+ src/components/RichText/converter/componentConverter/types.ts
701
+ ```
702
+
703
+ Do not create placeholder block mappings when RichText does not support embedded blocks.
704
+
705
+ ### Responsibility of Each File
706
+
707
+ #### `src/components/RichText/index.tsx`
708
+
709
+ This is the public RichText component and the only normal import entry point for other frontend components.
710
+
711
+ It must:
712
+
713
+ - accept the RichText value produced by the target Payload field;
714
+ - handle an empty or missing value safely;
715
+ - call the RichText renderer with the project's converter configuration;
716
+ - accept presentation props only when the project needs them;
717
+ - preserve the caller's `className` instead of replacing it;
718
+ - remain focused on rendering the complete RichText value.
719
+
720
+ Other files should normally import RichText from:
721
+
722
+ ```tsx
723
+ import { RichText } from "@/components/RichText";
724
+ ```
725
+
726
+ Use the actual export style already established by the target project. Do not change named exports to default exports, or default exports to named exports, unless the task explicitly requires it.
727
+
728
+ Do not place individual Lexical node conversion logic directly in this file.
729
+
730
+ #### `src/components/RichText/converter/index.tsx`
731
+
732
+ This is the converter entry point and orchestration layer.
733
+
734
+ It must:
735
+
736
+ - assemble the converters used by RichText;
737
+ - connect the text converter;
738
+ - connect the internal-link converter;
739
+ - connect embedded-block converters only when supported;
740
+ - preserve required default converters from the Payload Lexical renderer;
741
+ - keep converter registration in a clear and deterministic order;
742
+ - export the converter value or converter factory required by `RichText/index.tsx`.
743
+
744
+ Do not turn this file into one large converter containing all text, link, relationship, upload and block rendering logic.
745
+
746
+ #### `src/components/RichText/converter/internalLinks.tsx`
747
+
748
+ This file owns the rendering and URL resolution of Payload internal-document links.
749
+
750
+ It must:
751
+
752
+ - inspect the linked relationship safely;
753
+ - determine the linked document type using the actual project schema;
754
+ - resolve the URL from the linked document's real fields;
755
+ - support only collections or globals that exist in the target project;
756
+ - return a safe fallback when the relationship is missing, unresolved or unsupported;
757
+ - preserve link children and relevant attributes;
758
+ - use the project's existing link or URL utilities when available.
759
+
760
+ It must not:
761
+
762
+ - assume every project uses the same collections;
763
+ - assume every linked document has a `slug`;
764
+ - invent routes;
765
+ - hardcode a route copied from another project without verifying it;
766
+ - treat an unresolved relationship as a valid URL.
767
+
768
+ Examples of collection names, route prefixes and slug rules are project variations. They do not belong in the reusable standard unless the target project actually uses them.
769
+
770
+ #### `src/components/RichText/converter/textConverter.tsx`
771
+
772
+ This file owns the conversion and rendering of Lexical text nodes.
773
+
774
+ It must:
775
+
776
+ - preserve the text content;
777
+ - preserve every supported text format used by the target editor;
778
+ - combine compatible formats when more than one format is applied;
779
+ - render unsupported or unformatted text safely;
780
+ - use valid React elements;
781
+ - keep formatting behaviour independent from block rendering.
782
+
783
+ Possible text formats may include:
784
+
785
+ - bold;
786
+ - italic;
787
+ - underline;
788
+ - strikethrough;
789
+ - code;
790
+ - subscript;
791
+ - superscript.
792
+
793
+ The actual supported formats must be taken from the target project's editor configuration and existing implementation. Do not add formatting merely because it appears in this list.
794
+
795
+ #### `src/components/RichText/converter/componentConverter/blocks.tsx`
796
+
797
+ This file owns the mapping between RichText embedded-block nodes and their React components.
798
+
799
+ Create it only if blocks can be embedded in RichText.
800
+
801
+ It must:
802
+
803
+ - map each supported Payload block slug to the correct frontend component;
804
+ - pass the block data using the prop shape expected by that component;
805
+ - return a safe result for an unknown or malformed block;
806
+ - keep project-specific block imports in this file;
807
+ - make the list of supported embedded blocks easy to review;
808
+ - preserve type safety where the generated Payload types allow it.
809
+
810
+ It must not:
811
+
812
+ - import every block in the repository automatically;
813
+ - assume every page block is suitable inside RichText;
814
+ - reuse the main page `RenderBlocks` component unless its contract is verified as compatible;
815
+ - silently invent props for a block component;
816
+ - add block mappings that do not exist in the target Payload schema.
817
+
818
+ #### `src/components/RichText/converter/componentConverter/types.ts`
819
+
820
+ This file contains types used specifically by embedded component or block conversion.
821
+
822
+ It must:
823
+
824
+ - describe the actual embedded-block node or converter contract;
825
+ - reuse generated Payload types where practical;
826
+ - keep local helper types narrow;
827
+ - avoid duplicating the entire generated block schema;
828
+ - contain types only, unless a small type guard is genuinely required.
829
+
830
+ Do not manually edit `src/payload-types.ts` to make these types compile. Payload-generated types must be regenerated using the project's existing Payload type-generation command.
831
+
832
+ ### Required Implementation Process
833
+
834
+ An AI or developer implementing this standard must complete these steps in order.
835
+
836
+ #### 1. Inspect the target project
837
+
838
+ Before writing code, locate and read:
839
+
840
+ - the Payload RichText field configuration;
841
+ - the Lexical editor configuration;
842
+ - the generated RichText data type;
843
+ - existing link and URL utilities;
844
+ - collections or globals allowed as internal links;
845
+ - embedded block definitions, if any;
846
+ - existing frontend block components;
847
+ - the project's import alias configuration;
848
+ - the project's package versions and installed RichText packages.
849
+
850
+ Do not start by copying a RichText component from another repository.
851
+
852
+ #### 2. Classify the project variation
853
+
854
+ Determine whether the project needs:
855
+
856
+ - base RichText rendering only;
857
+ - internal links;
858
+ - uploads or media rendering;
859
+ - custom text formats;
860
+ - relationships;
861
+ - embedded blocks;
862
+ - project-specific converters.
863
+
864
+ Only install the necessary variation.
865
+
866
+ #### 3. Preserve existing behaviour
867
+
868
+ If RichText already exists, preserve:
869
+
870
+ - supported node types;
871
+ - internal-link routes;
872
+ - external-link behaviour;
873
+ - classes and styling hooks;
874
+ - media behaviour;
875
+ - embedded blocks;
876
+ - generated types;
877
+ - public component props;
878
+ - current import paths.
879
+
880
+ Refactoring the folder structure does not authorise removing behaviour.
881
+
882
+ #### 4. Separate responsibilities
883
+
884
+ Move logic to the file that owns it:
885
+
886
+ | Concern | File |
887
+ | -------------------------------- | ------------------------------- |
888
+ | Public RichText component | `RichText/index.tsx` |
889
+ | Converter assembly | `converter/index.tsx` |
890
+ | Internal-document URL resolution | `converter/internalLinks.tsx` |
891
+ | Text-node formatting | `converter/textConverter.tsx` |
892
+ | Embedded-block mapping | `componentConverter/blocks.tsx` |
893
+ | Embedded-block converter types | `componentConverter/types.ts` |
894
+
895
+ Do not create additional files without a real project requirement.
896
+
897
+ #### 5. Validate
898
+
899
+ Run the target project's existing:
900
+
901
+ - formatter;
902
+ - linter;
903
+ - TypeScript check;
904
+ - relevant tests;
905
+ - production build, when within the task scope.
906
+
907
+ If the Payload schema or generated types changed, run the project's existing Payload type-generation command before the final type check.
908
+
909
+ Do not report completion when imports, types or converter mappings are unverified.
910
+
911
+ ### Import and Dependency Rules
912
+
913
+ - Use packages already installed by the target project.
914
+ - Verify exact APIs against the installed package versions.
915
+ - Follow the project's existing alias and import conventions.
916
+ - Prefer generated Payload types over broad `any` types.
917
+ - Use `unknown` plus narrowing when incoming converter data cannot be trusted.
918
+ - Avoid circular imports between RichText and block components.
919
+ - Do not import server-only modules into client components.
920
+ - Add `'use client'` only when the component genuinely uses client-only React features.
921
+ - Do not add a package solely because another Dusted project uses it.
922
+ - Do not change package versions unless explicitly required.
923
+
924
+ ### Data and Safety Rules
925
+
926
+ - Treat RichText data as nullable unless the project type proves otherwise.
927
+ - Handle missing relationships and deleted linked documents safely.
928
+ - Do not render `undefined`, malformed URLs or invented fallbacks as working links.
929
+ - Do not use `dangerouslySetInnerHTML` merely to bypass converter work.
930
+ - Do not discard unknown content without making the fallback behaviour deliberate.
931
+ - Do not log the full RichText document in production.
932
+ - Do not place private Payload document data into frontend URLs or attributes.
933
+
934
+ ### Styling Rules
935
+
936
+ The RichText renderer provides structure and semantic output. Styling remains project-specific.
937
+
938
+ - Preserve existing classes and data attributes.
939
+ - Allow a caller-provided `className` when the current component contract supports it.
940
+ - Do not copy typography styles from another project as part of this standard.
941
+ - Do not hardcode a theme.
942
+ - Do not place an entire project's prose CSS inside the converter.
943
+ - Keep semantic elements such as headings, paragraphs, lists, links and code output intact.
944
+
945
+ For RichText used inside a reusable Payload block, follow the block standard for any required content hook, including:
946
+
947
+ ```tsx
948
+ data-content-type="[component_name]-richtext"
949
+ ```
950
+
951
+ Replace `[component_name]` with the actual component identifier. Do not use the placeholder literally.
952
+
953
+ ### Extension Rules
954
+
955
+ The structure may be extended when the target project genuinely requires another distinct converter concern.
956
+
957
+ Examples may include:
958
+
959
+ ```text
960
+ converter/
961
+ +-- uploads.tsx
962
+ +-- relationships.tsx
963
+ +-- headings.tsx
964
+ ```
965
+
966
+ Before adding a file, confirm that:
967
+
968
+ 1. the relevant node exists in the target editor configuration;
969
+ 2. the logic is substantial enough to deserve separation;
970
+ 3. the responsibility does not already belong to an existing file;
971
+ 4. the new file does not introduce a project-specific feature into the reusable base unnecessarily.
972
+
973
+ Variations must be documented rather than forced into all projects.
974
+
975
+ ### Prohibited Shortcuts
976
+
977
+ Do not:
978
+
979
+ - place all converter logic in `RichText/index.tsx`;
980
+ - copy imports, collection slugs or routes from another project without checking;
981
+ - create empty files solely to match the tree;
982
+ - add embedded-block support to a project that does not use it;
983
+ - map unsupported blocks;
984
+ - edit generated Payload types manually;
985
+ - replace strict types with `any` merely to silence errors;
986
+ - remove default Lexical converters accidentally;
987
+ - assume package APIs are identical across Payload versions;
988
+ - rename the public RichText import path without updating every consumer;
989
+ - claim the implementation is complete without running the available validation commands.
990
+
991
+ ### Completion Checklist
992
+
993
+ Before marking RichText work complete, confirm every applicable item:
994
+
995
+ - [ ] The target Payload editor configuration was inspected.
996
+ - [ ] The target project's existing RichText behaviour was inspected.
997
+ - [ ] The public component is located at `src/components/RichText/index.tsx`.
998
+ - [ ] Converter assembly is located at `converter/index.tsx`.
999
+ - [ ] Internal-link logic is isolated in `internalLinks.tsx`.
1000
+ - [ ] Text formatting is isolated in `textConverter.tsx`.
1001
+ - [ ] `componentConverter/` exists only if embedded blocks are supported.
1002
+ - [ ] Every embedded block mapping refers to a real schema block and real component.
1003
+ - [ ] Internal routes are derived from verified project rules.
1004
+ - [ ] Empty, missing and unresolved values are handled safely.
1005
+ - [ ] Existing styles, classes and attributes are preserved.
1006
+ - [ ] No generated Payload type file was manually edited.
1007
+ - [ ] No unnecessary dependency was added.
1008
+ - [ ] Formatting passed.
1009
+ - [ ] Linting passed.
1010
+ - [ ] Type checking passed.
1011
+ - [ ] Relevant tests passed.
1012
+ - [ ] The production build passed when it was part of the requested scope.
1013
+
1014
+ ### Definition of Done
1015
+
1016
+ The RichText standard is correctly implemented when:
1017
+
1018
+ 1. other components have one clear RichText import entry point;
1019
+ 2. converter responsibilities are separated into the standard files;
1020
+ 3. the implementation matches the target Payload schema and installed package versions;
1021
+ 4. project-specific variations are included only when needed;
1022
+ 5. existing behaviour has not been lost;
1023
+ 6. malformed or missing data fails safely;
1024
+ 7. the target project's validation commands pass.
1025
+
62
1026
  ## Publishing Identities
63
1027
 
64
1028
  - GitHub repository: `https://github.com/Hadizainal/blocks-dusted.git`
65
1029
  - npm package: `blocks-dusted`
66
1030
  - CLI executable: `blocks-dusted`
67
1031
 
68
- The repository can remain private while the npm package is published separately.
1032
+ The repository can remain private while the npm package is published separately.