RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/CLAUDE.md/dotCMS/core

CLAUDE.md

core-web/libs/new-block-editor/CLAUDE.md
CLAUDE.md

Quality

61/100

Scores the file, not the repository.

Length

2,134 words

20 headings · 1 code blocks

Repository

949

— · pushed 0 days ago

Last changed

3 days ago

First indexed 3 days ago.
dotCMS/core/core-web/libs/new-block-editor/CLAUDE.mdRawGitHub
1## Interaction Preferences
2 
3Act with constructive skepticism. You are a collaborator with strong reasoning ability.
4 
5Make decisions based on evidence. Do not assume you must agree with me.
6 
7You should:
8 
9- Question weak premises
10- Point out flaws in reasoning
11- Propose new approaches or mental models
12 
13If I am approaching a problem from the wrong perspective or with incorrect assumptions, explain it clearly and suggest a better starting point.
14 
15Be direct.
16Avoid unnecessary validation language, emojis, or marketing tone.
17 
18## Expected Response Format
19 
20Your responses should focus on:
21 
22- **Core insight**
23- **Key tradeoffs**
24- **Major risks**
25- **Recommended next move**
26 
27## TipTap Node Names Are Immutable
28 
29TipTap serializes editor content to JSON using the node's `name` as the `type` key:
30 
31```json
32{ "type": "dotImage", "attrs": { ... } }
33{ "type": "dotContent", "attrs": { ... } }
34```
35 
36dotCMS customers store this JSON in their database. **If a node name changes, TipTap will not recognize stored content and will silently drop those blocks on load — permanently destroying customer data.**
37 
38### Rule
39 
40**Never rename an existing node's `name` field without explicit approval from the developer.** This applies to any `.extension.ts` or node file where `name:` is set.
41 
42If asked to rename a node, you must:
431. Refuse and explain the data-loss risk
442. Present the trade-off: renaming requires a database migration to rewrite every stored document that contains that node type — not just a code change
453. Wait for explicit developer confirmation before proceeding
46 
47### Creating new nodes
48 
49When creating a new node, you may choose any name — but choose carefully, because **that name can never be changed** once real content has been written with it. Prefer descriptive, namespaced names (e.g. `dotVideo`, `dotContent`) over generic ones.
50 
51### Current node name registry
52 
53| Node | Name | File |
54|------|------|------|
55| Image | `dotImage` | `extensions/nodes/image.extension.ts` |
56| Video | `dotVideo` | `extensions/nodes/video.extension.ts` |
57| Audio | `dotAudio` | `extensions/nodes/audio.extension.ts` |
58| Contentlet | `dotContent` | `extensions/nodes/contentlet/contentlet.extension.ts` |
59| Grid block | `gridBlock` | `extensions/nodes/grid.extension.ts` |
60| Grid column | `gridColumn` | `extensions/nodes/grid.extension.ts` |
61| AI content | `aiContent` | `extensions/nodes/ai-content.extension.ts` |
62 
63Standard TipTap/StarterKit names (`paragraph`, `heading`, `bulletList`, `orderedList`, `blockquote`, `codeBlock`, `horizontalRule`, `table`, etc.) are owned by TipTap upstream and must not be changed either.
64 
65---
66 
67## Service Architecture
68 
69The lib follows a strict split: **data fetching** delegates to `@dotcms/data-access`; **state and orchestration** stays local. The legacy block-editor sets the precedent — use the data-access services directly rather than re-implementing them.
70 
71### Data services — consume from `@dotcms/data-access`
72 
73| Service | Used for |
74|---|---|
75| `DotContentTypeService` | Content type filtering for the slash-menu's content-type sub-picker (`filterContentTypes`) and per-type metadata reads (`getContentType`, used by `ContentletEditUrlService`). |
76| `DotContentSearchService` | Lucene search behind the slash-menu's contentlet drill-down (`/api/content/_search`). The editor-flavoured query string (`+contentType:X +languageId:Y +deleted:false +working:true +catchall:** title:''^15`) is built inline at the call site (`buildContentletByTypeQuery` in `slash-menu-catalog.ts`); the service itself stays generic. |
77| `DotLanguagesService` | Language metadata for the editor store (`getById`). |
78| `DotAiService` | AI text generation, AI image generation + publish, plugin status check. Identical surface to legacy block-editor usage. |
79| `DotUploadFileService` | Wrapped by the lib's local `DotUploadService` adapter (see below). |
80| `DotMessageService` | i18n. Used everywhere. |
81 
82Do **not** create custom HTTP services in this lib for any of the above. If you need a method that doesn't exist on a data-access service, extend the data-access service rather than rolling a new one here.
83 
84### Local services — editor-specific
85 
86| Service | Why it stays local |
87|---|---|
88| `EditorPopoverService` | Caret-anchored popover state (active id, anchor rect, per-popover payloads). Editor-only concern. |
89| `EditorModalService` | Lifecycle for centered `DialogService.open()` modals (AI content, AI image, image / video pickers). Editor-only concern. |
90| `EditorToolbarStore` | Signal mirror of TipTap mark/block/alignment state for the toolbar. Editor-only concern. |
91| `SlashMenuService` | Slash-menu catalog, filtering, sub-menu loading. Editor-only concern. |
92| `ContentletEditUrlService` | Resolves the legacy-vs-new content editor URL via per-content-type feature-flag cache. Caches the metadata read so repeated contentlet edits within one session don't re-hit the network. The wrapper exists *for* the cache; without it, every "Edit contentlet" click would re-fetch. |
93| `DotUploadService` (adapter) | Promise/async-await adapter around `DotUploadFileService.publishContent()`. Two responsibilities: bridge the async model for `handleMediaDrop` (which is `async` linear code) and unwrap the workflow PUBLISH endpoint's `Record<contentTypeKey, contentlet>` shape into the editor's narrower `UploadedImage` / `UploadedVideo` types. |
94 
95When in doubt: **state & orchestration → local. HTTP → data-access.**
96 
97---
98 
99## Overlay System Architecture
100 
101The editor uses two distinct overlay primitives. Pick by interaction model, not content type — the difference is whether the overlay anchors to the caret/trigger (popover) or sits centered over the page (modal dialog).
102 
103### Pick the right overlay primitive
104 
105| Primitive | Use | Anchored to | Modality | Examples |
106|-----------|-----|-------------|----------|----------|
107| `<dot-editor-popover>` shell | Compact, caret-anchored, single form | Caret / trigger rect via `@floating-ui/dom` | Non-modal — no backdrop, no focus trap, click-outside dismisses | link, table, image-properties, emoji |
108| PrimeNG `DialogService.open()` | Centered modal — large content, multi-pane, embeddable, or external library component | Viewport center | Modal — backdrop, focus trap, explicit close | AI content, AI image, image picker, video picker |
109 
110When an overlay has both an input area AND a result/preview area, default to a centered modal — caret-anchored popovers get cramped.
111 
112### Caret-anchored popover shell (`<dot-editor-popover>`)
113 
114All compact popovers (link, table, image-properties, emoji) share a single `EditorPopoverService` and an `<editor-popover>` shell component:
115 
116- `EditorPopoverService` (`services/editor-popover.service.ts`) — central state: which popover is open, its anchor rect, and per-popover payloads (`imagePropertiesPayload`, `linkPayload`).
117- `EditorPopoverComponent` (`components/editor-popover.component.ts`) — shell wrapper: absolute positioning via `@floating-ui/dom`, `display:none` toggle, Escape + click-outside dismiss (whitelisting body-portaled PrimeNG `.p-overlay` / `.p-select-overlay` so embedded `<p-select>` stays alive), `<ng-content>` projection, auto-focus on the first form control after first paint.
118 
119Each popover content component:
120- Takes `editor = input.required<Editor>()` and calls editor commands directly.
121- Wraps its form in `<dot-editor-popover popoverId="...">`.
122- Injects `EditorPopoverService` for open/close state and payloads.
123 
124### Centered modals via `DialogService.open()` (`EditorModalService`)
125 
126Every centered modal in the editor — AI content, AI image, image picker, video picker — is opened through PrimeNG's `DialogService.open()`, surfaced by `EditorModalService` (`services/editor-modal.service.ts`). One pattern, one teardown story:
127 
128- The editor component provides `DialogService` at the component scope so each editor instance gets its own dynamic-dialog factory. Provided in `editor.component.ts`.
129- `EditorModalService` keeps one private `DynamicDialogRef` per modal kind, set to `null` between opens.
130- Each `openX(editor)` method calls `dialogService.open(Component, config)` with the right `data` and subscribes to `dialogRef.onClose` to apply the result (insert nodes, mutate state) into the editor.
131- Modal components inject `DynamicDialogRef` and signal a result by calling `this.dialogRef.close(result)`. Cancel/Escape/X close with no value, which the `onClose` subscriber treats as "no-op".
132- `ngOnDestroy()` on the service closes every live ref so an editor unmount mid-dialog doesn't orphan an overlay.
133 
134When adding a new centered modal:
1351. Build the component as a normal standalone Angular component; inject `DynamicDialogRef` and call `this.dialogRef.close(result)` on confirm.
1362. Add `openYourModal(editor)` to `EditorModalService` mirroring the existing methods (private ref + idempotent guard + `onClose` subscription).
1373. Add a teardown line to `ngOnDestroy()`.
138 
139Do not embed `<p-dialog>` directly inside `editor.component.ts`. The pattern above gives consistent lifecycle, focus behavior, and per-editor isolation for free.
140 
141---
142 
143## Node + action inventory
144 
145What actions are available on each node type. **Slash** = appears in `/` menu (`slash-menu-catalog.ts`). **Toolbar** = button in `toolbar.component.ts`. **Marks** = inline marks that can be applied to text inside this node. **Commands** = TipTap commands declared on the node's extension. **Node-scoped** = appears only when the node is selected/active.
146 
147### Block-level nodes
148 
149| Node (`type`) | Source | Slash | Toolbar | Allowed-block key |
150|---------------|--------|-------|---------|-------------------|
151| `paragraph` | StarterKit | Text | Block-type select | always allowed |
152| `heading` (levels 1–6) | StarterKit | Heading 1 / 2 / 3 | Block-type select (1–3) | `heading1`…`heading6` |
153| `bulletList` | StarterKit | Bullet List | Bullet List | `bulletList` |
154| `orderedList` | StarterKit | Ordered List | Ordered List | `orderedList` |
155| `listItem` | StarterKit | — | indent / outdent | inherits list parent |
156| `blockquote` | StarterKit | Blockquote | Blockquote | `blockquote` |
157| `codeBlock` | StarterKit | Code Block | Code Block | `codeBlock` |
158| `horizontalRule` | StarterKit | — | Horizontal rule | `horizontalRule` |
159| `table` | TableKit | Table (popover) | Insert table + table sub-toolbar | `table` |
160| `dotImage` | `image.extension.ts` | Image (modal picker) | Insert image, wrap-left/right (node-scoped), align, image properties popover (node-scoped) | `image` |
161| `dotVideo` | `video.extension.ts` | Video (modal picker) | Insert video | `video` |
162| `dotAudio` | `audio.extension.ts` | Audio (modal picker) | Insert audio | `audio` |
163| `youtube` | `@tiptap/extension-youtube` | — (legacy slash entry) | — | `youtube` |
164| `dotContent` | `contentlet/contentlet.extension.ts` | Content type → submenu | Edit contentlet (node-scoped) | `dotContent` |
165| `gridBlock` | `grid.extension.ts` | Grid (2 columns) | — | `gridBlock` |
166| `gridColumn` | `grid.extension.ts` | — (created by `insertGrid`) | — | inherits gridBlock |
167| `aiContent` | `ai-content.extension.ts` | Ask AI (centered modal) | — | `aiContent` |
168| `uploadPlaceholder` | `upload-placeholder.extension.ts` | — (transient) | — | always (transient) |
169 
170### Marks
171 
172| Mark | Source | Toolbar | Applies to |
173|------|--------|---------|------------|
174| `bold` | StarterKit | Bold | any text |
175| `italic` | StarterKit | Italic | any text |
176| `underline` | StarterKit | Underline | any text |
177| `strike` | StarterKit | Strike | any text |
178| `code` | StarterKit | Inline code | any text |
179| `superscript` | `@tiptap/extension-superscript` | Sup | any text |
180| `subscript` | `@tiptap/extension-subscript` | Sub | any text |
181| `link` | `@tiptap/extension-link` | Link popover | any text (gated by `link` allowed-block) |
182| `textAlign` | `@tiptap/extension-text-align` | Align L/C/R/Justify | configured for `paragraph` + `heading` only |
183 
184### Special / node-scoped commands
185 
186| Command | Owner | What it does |
187|---------|-------|--------------|
188| `setImageTextWrap('left' \| 'right')` | `dotImage` | Toggles `image-wrap-left/right` class on the wrapping `<figure>`. Mutually exclusive with `setImageTextAlign`. |
189| `setImageTextAlign('left' \| 'center' \| 'right')` | `dotImage` | Sets `image-align-*` class on the wrapping `<figure>`. Clears `textWrap`. |
190| `insertGrid()` | `gridBlock` | Inserts a 2-column grid block at the selection. Equal default widths. |
191| `setGridColumns(columns: number[])` | `gridBlock` | Updates column-fraction widths for the active grid block. Used by the grid resize plugin. |
192 
193> **AI Content note:** the `aiContent` node has no custom commands. AI-generated HTML is inserted with the standard `commands.insertContent(html)` so each block becomes a normal editable node. The node registration only exists so legacy stored content (from the old block editor, which DID wrap in `aiContent`) still parses and renders — removing it would silently drop those blocks (see "TipTap Node Names Are Immutable").
194 
195### Slash-only "actions" (don't insert a single node)
196 
197These slash entries do not map 1:1 to a node — they trigger flows that mutate the editor:
198 
199| Slash entry | Trigger |
200|-------------|---------|
201| AI Image | Opens `DotAIImagePromptComponent` via `DialogService.open()` (centered modal). On accept, inserts a `dotImage` node. |
202| AI Content | Opens `AiContentDialogComponent` via `DialogService.open()` (centered modal). On insert, the generated HTML is parsed against the editor schema so each block becomes a normal editable node (paragraphs / headings / lists). Does NOT wrap in an `aiContent` block. |
203| Content type | Opens an in-place sub-menu of allowed content types, then a contentlet picker. Inserts a `dotContent` node. |
204| Image / Video | Opens `DotBrowserSelectorComponent` via `DialogService.open()` (centered modal picker). Inserts the corresponding `dotImage` / `dotVideo` node. |
205| Table / Link / Emoji | Opens a caret-anchored `<dot-editor-popover>`. Insert / mutate the corresponding node. |
206 
207### Customer-supplied remote commands (`customBlocks` field variable)
208 
209Each declared `Action` becomes a slash entry that calls `editor.commands[action.command]()` on selection. The TipTap extensions resolved from the remote URLs determine which commands actually exist; missing commands log a warning instead of throwing. See `extensions/remote-extensions.loader.ts`.
210 
211### Toolbar groups (visual order)
212 
2131. History — Undo, Redo
2142. Block type — paragraph / heading 1–3 select
2153. Inline format — Bold, Italic, Underline, Strike, Code, Superscript, Subscript
2164. Alignment — Left, Center, Right, Justify (heading + paragraph only)
2175. Image-only (visible when an image is selected) — Wrap L/R, Image properties
2186. Contentlet-only (visible when a contentlet is selected) — Edit
2197. Block formats — Bullet List, Ordered List, Blockquote, Code Block
2208. Indent / Outdent / Clear formatting
2219. Horizontal rule
22210. Insert dialogs — Link, Image, Video, Table
22311. Table sub-toolbar (when inside a table) — Insert row/col, Merge/Split, Toggle row/col header, Delete row/col/table
22412. Emoji
22513. Markdown copy / paste
22614. Fullscreen toggle
227 
228The `showInsertGroup`/`showBlockFormatsGroup` computeds and the `@if (allow*)` guards collapse dividers when a group is empty. See `toolbar.component.ts`.

Sections

  • Interaction Preferences
  • Expected Response Format
  • TipTap Node Names Are Immutable
  • Rule
  • Creating new nodes
  • Current node name registry
  • Service Architecture
  • Data services — consume from `@dotcms/data-access`
  • Local services — editor-specific
  • Overlay System Architecture
  • Pick the right overlay primitive
  • Caret-anchored popover shell (`<dot-editor-popover>`)
  • Centered modals via `DialogService.open()` (`EditorModalService`)
  • Node + action inventory
  • Block-level nodes
  • Marks
  • Special / node-scoped commands
  • Slash-only "actions" (don't insert a single node)
  • Customer-supplied remote commands (`customBlocks` field variable)
  • Toolbar groups (visual order)

What it covers

lint-formatcode-styledo-notagent-behaviour

Stack — with the evidence

typescript

(1.00)

java

(1.00)

node

(1.00)

jest

(1.00)

eslint

(1.00)

angular

(0.70)

pytest

(0.70)

vercel

(0.70)

github-actions

(0.60)

javascript

(0.50)

python

(0.50)

Format

CLAUDE.md

Claude Code's memory file. Shaped like AGENTS.md but with two things it lacks: @path imports, so shared rules live in one place, and a user-scope layer that follows the developer across repos rather than shipping with the code.

What the corpus says about it

Repository

Owner
dotCMS
Language
—
License
—
Archived
no

All configs in this repo

Also in dotCMS/core

Diff this repo’s formats

One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?

The other instruction files in this repository
RepositoryFormatStackCoversScoreChanged
dotCMS/core.github/copilot-instructions.md · 949Copilot instructionsjavanode+10setupbuildtestlint-format+1184/100today
dotCMS/corecore-web/apps/dotcms-ui-e2e/AGENTS.md · 949AGENTS.mdtypescriptjava+10setupstylearchtesting-strategy+278/1003 days ago
dotCMS/corecore-web/apps/mcp-server/CLAUDE.md · 949CLAUDE.mdtypescriptjava+9setupbuildtestlint-format+589/1003 days ago
dotCMS/core.cursor/rules/doc-updates.mdc · 949Cursor rulesjavanode+9docs30/1003 days ago
dotCMS/core.cursor/rules/dotcms-guide.mdc · 949Cursor rulesjavanode+9archdo-notdocs69/1003 days ago
dotCMS/core.cursor/rules/e2e-rules.mdc · 949Cursor rulesjavanode+9setupteststylearch+589/1003 days ago
dotCMS/core.cursor/rules/frontend-context.mdc · 949Cursor rulesjavanode+10teststyledocs78/1003 days ago
dotCMS/core.cursor/rules/java-context.mdc · 949Cursor rulesjavanode+9buildstyle44/1003 days ago
dotCMS/core.cursor/rules/test-context.mdc · 949Cursor rulesjavanode+9testtesting-strategy54/1003 days ago
dotCMS/core.github/instructions/frontend.instructions.md · 949Copilot instructionsjavanode+10testlint-formatstylearch+369/1003 days ago
dotCMS/coreCLAUDE.md · 949CLAUDE.mdjavanode+9setupbuildteststyle+799/100today
dotCMS/corecore-web/AGENTS.md · 949AGENTS.mdjavanode+13style63/1003 days ago
dotCMS/corecore-web/CLAUDE.md · 949CLAUDE.mdjavanode+13teststylearchtesting-strategy+3100/1003 days ago
dotCMS/corecore-web/apps/dotcms-ui/AGENTS.md · 949AGENTS.mdtypescriptjava+9buildteststyledependencies+394/1003 days ago
dotCMS/corecore-web/libs/block-editor/CLAUDE.md · 949CLAUDE.mdtypescriptjava+9archdo-not69/1003 days ago
dotCMS/corecore-web/libs/portlets/CLAUDE.md · 949CLAUDE.mdjavanode+9setupteststyleui+177/1003 days ago
dotCMS/corecore-web/libs/portlets/edit-ema/portlet/src/lib/store/CLAUDE.md · 949CLAUDE.mdjavanode+9teststylearchtypes+265/1003 days ago
dotCMS/corecore-web/libs/sdk/client/CLAUDE.md · 949CLAUDE.mdtypescriptjava+9setupbuildtestlint-format+997/1003 days ago
dotCMS/corecore-web/libs/sdk/react/CLAUDE.md · 949CLAUDE.mdtypescriptjava+10setupbuildtestlint-format+997/1003 days ago
dotCMS/coredotCMS/src/main/java/com/dotcms/rest/CLAUDE.md · 949CLAUDE.mdjavanode+9typesdatabaseapido-not+157/1003 days ago
Diff against .github/copilot-instructions.md Diff against core-web/apps/dotcms-ui-e2e/AGENTS.md Diff against core-web/apps/mcp-server/CLAUDE.md Diff against .cursor/rules/doc-updates.mdc Diff against .cursor/rules/dotcms-guide.mdc Diff against .cursor/rules/e2e-rules.mdc Diff against .cursor/rules/frontend-context.mdc Diff against .cursor/rules/java-context.mdc Diff against .cursor/rules/test-context.mdc Diff against .github/instructions/frontend.instructions.md Diff against CLAUDE.md Diff against core-web/AGENTS.md Diff against core-web/CLAUDE.md Diff against core-web/apps/dotcms-ui/AGENTS.md Diff against core-web/libs/block-editor/CLAUDE.md Diff against core-web/libs/portlets/CLAUDE.md Diff against core-web/libs/portlets/edit-ema/portlet/src/lib/store/CLAUDE.md Diff against core-web/libs/sdk/client/CLAUDE.md Diff against core-web/libs/sdk/react/CLAUDE.md Diff against dotCMS/src/main/java/com/dotcms/rest/CLAUDE.md

Similar configs

Same format, overlapping stack, ranked by quality.

Same format, overlapping stack, ranked by quality
RepositoryFormatStackCoversScoreChanged
Adit-Jain-srm/NightmareNetCLAUDE.md · 45CLAUDE.mdtypescriptpython+18buildtestlint-formatstyle+6100/1003 days ago
nimbalyst/nimbalystpackages/android/CLAUDE.md · 1.4kCLAUDE.mdtypescriptnode+16setupbuildstylearch+2100/1003 days ago
dotCMS/corecore-web/CLAUDE.md · 949CLAUDE.mdjavanode+13teststylearchtesting-strategy+3100/1003 days ago
microsoft/playwrightCLAUDE.md · 94kCLAUDE.mdtypescriptjavascript+10buildtestlint-formatstyle+7100/1003 days ago
filamentphp/filamentCLAUDE.md · 32kCLAUDE.mdphplaravel+5buildtestlint-formatstyle+7100/1003 days ago
bagisto/bagistoCLAUDE.md · 28kCLAUDE.mdphplaravel+8setupbuildteststyle+5100/1003 days ago
dotCMS/coreCLAUDE.md · 949CLAUDE.mdjavanode+9setupbuildteststyle+799/100today
lollipopkit/flutter_server_boxCLAUDE.md · 8.3kCLAUDE.mddartflutter+8buildteststylearch+298/1003 days ago
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack