Skip to content

§14/§15: rename CustomNode public API around node-vs-component#324

Merged
CarlosNZ merged 3 commits into
v2.0-devfrom
feat/v2.0-customnode-naming
Jun 4, 2026
Merged

§14/§15: rename CustomNode public API around node-vs-component#324
CarlosNZ merged 3 commits into
v2.0-devfrom
feat/v2.0-customnode-naming

Conversation

@CarlosNZ
Copy link
Copy Markdown
Owner

@CarlosNZ CarlosNZ commented Jun 4, 2026

Implements roadmap §14 (terminology — "node, not component") + §15 (CustomNode flags audit) together. Closes #253, closes #254.

Final naming decided in the #253/#254 comment threads. The organizing principle: a node is a position in the data tree; a component is the React function that renders it.

Renames (breaking, v2)

old → new
Render slots elementcomponent, customKeykeyComponent, wrapperElementwrapperComponent
Config customNodePropscomponentProps (feeds component + keyComponent)
Visibility hideKeyshowKey (polarity inverted, default true), showInTypesSelectorshowInTypeSelector
Type CustomNodePropsCustomComponentProps (also resolves the CustomNodeProps/CustomNodeDefinition name clash)
  • New CustomWrapperProps types wrapperComponent, which now receives its config as wrapperProps (previously delivered as customNodeProps) — the only genuine set≠read asymmetry.
  • Internal CustomNodeData FC fields gained the Custom prefix (CustomComponent/CustomWrapperComponent/CustomKeyComponent).
  • CustomNodeDefinition and CustomKeyProps keep their names. No fields removed; passOriginalNode stays opt-in (perf), showOnView:true/showOnEdit:false asymmetry kept — both now documented in types.ts.

Scope

  • Core (src/): types, getCustomNode, CollectionNode, ValueNodeWrapper, KeyDisplay, exports.
  • @json-edit-react/components: all 12 definitions + component bodies.
  • Consumers: demo (demo/src/) and custom-component-library. demo/src/v1/ left on published v1.
  • Docs: README custom-nodes section (fields, slot table, prose) + light node-vs-component terminology pass (Custom Text untouched), CustomWrapperProps added to the exported-types list, migration-guide §13 with before/after, components CLAUDE.md.
  • Changesets: one major/major for the rename; two existing changesets aligned to componentProps so the v2 changelog stays coherent.

Tests

New test/customNode.test.tsx23 tests pinning the DOM/setData contract of every CustomNodeDefinition field (slots, props pass-through incl. a wrapperProps-delivery regression guard, the view/edit visibility matrix, chrome flags, type selector + defaultValue, passOriginalNode, collection flags, and both JSON hooks).

These caught a real regression: the hideKeyshowKey polarity flip hid keys on non-custom nodes (no matching definition → showKey undefined → falsy), because the default only applied inside getCustomNode. Fixed by defaulting showKey = true at the consumption sites (mirrors the existing showEditTools pattern).

Verification

  • pnpm compile (tsc + ts-prune) ✅ · pnpm lint ✅ · 337 tests pass (2 pre-existing todos) ✅ · pnpm -r build (all 4 packages) ✅
  • Demo typechecks clean against local v2 (@json-edit-react../src) ✅
  • CCL's standalone tsc shows pre-existing @types/react-version-mismatch errors in core's JsonEditor.tsx/JsonViewer.tsx (identical count with this branch stashed) — unrelated to this change.

🤖 Generated with Claude Code

Aligns the CustomNodeDefinition surface on one distinction: a node is a
position in the data tree; a component is the React function that renders it.

Renames (breaking, v2):
- element → component, customKey → keyComponent, wrapperElement → wrapperComponent
- customNodeProps → componentProps (feeds component + keyComponent)
- hideKey → showKey (polarity inverted; default true)
- showInTypesSelector → showInTypeSelector
- type CustomNodeProps → CustomComponentProps (resolves the
  CustomNodeProps/CustomNodeDefinition name clash)

Also: new CustomWrapperProps types wrapperComponent, which now receives its
config as wrapperProps (was delivered as customNodeProps) — the only genuine
set≠read asymmetry. Internal CustomNodeData FC fields gain the Custom prefix
(CustomComponent/CustomWrapperComponent/CustomKeyComponent). CustomNodeDefinition
and CustomKeyProps keep their names.

Updates all 12 @json-edit-react/components definitions + bodies, the demo and
custom-component-library consumers (demo/src/v1 left on published v1), README
custom-nodes section + a light node-vs-component terminology pass, and adds
migration-guide §13.

Tests: new test/customNode.test.tsx (23 tests) pinning the DOM/setData contract
of every CustomNodeDefinition field, including a wrapperProps-delivery regression
guard. These caught a polarity regression — non-custom nodes hid their keys
because showKey defaulted only inside getCustomNode; fixed by defaulting
showKey = true at the consumption sites.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

Bundle size impact

json-edit-react

Format Base raw PR raw Δ raw Base gzip PR gzip Δ gzip
esm 54.11 KB 54.18 KB 🔺 +70 B (+0.13%) 18.95 KB 18.94 KB 🟢 -6 B (-0.03%)
cjs 55.59 KB 55.66 KB 🔺 +70 B (+0.12%) 19.01 KB 19.01 KB 🟢 -4 B (-0.02%)

@json-edit-react/components

Format Base raw PR raw Δ raw Base gzip PR gzip Δ gzip
esm 11.52 KB 11.51 KB 🟢 -2 B (-0.02%) 3.91 KB 3.91 KB 🟢 -3 B (-0.07%)
cjs 12.09 KB 12.09 KB 🟢 -2 B (-0.02%) 3.88 KB 3.88 KB 🟢 -2 B (-0.05%)

Measured from build/index.{cjs,esm}.js. Gzip at level 9.

Comment thread migration-guide.md Outdated
> Same mental model as `useState<T>`: `T` describes the data you provided, not a runtime invariant. If structural edits are unrestricted, post-edit values may not conform to `T` — pair with `allowAdd` / `allowDelete` / `allowTypeSelection`, or validate in `onUpdate`, if you depend on the shape.

`CustomNodeDefinition` is intentionally **not** generic on the data type — its two existing generics (for `customNodeProps` and wrapper props) are unchanged, and custom-node `condition` / `element` continue to receive `NodeData<JsonData>`.
`CustomNodeDefinition` is intentionally **not** generic on the data type — its two existing generics (for `componentProps` and wrapper props) are unchanged, and custom-node `condition` / `component` continue to receive `NodeData<JsonData>`.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is CustomNodeDefinition not generic?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because customNodeDefinitions is a single array whose entries each match (via condition) differently-shaped nodes anywhere in the tree — a date string here, a {lat,lng} object there. One document-level T can't describe that heterogeneous set, and making CustomNodeDefinition generic would force every entry in the array to share a T, making mixed-shape definition arrays unusable. So it keeps only its two existing generics (componentProps / wrapper props), and condition / component receive NodeData<JsonData>. I've expanded the note in the guide to say this.

 review)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@CarlosNZ CarlosNZ merged commit b82f8db into v2.0-dev Jun 4, 2026
2 checks passed
@CarlosNZ CarlosNZ deleted the feat/v2.0-customnode-naming branch June 4, 2026 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

V2 §15: CustomNode flags audit V2 §14: Terminology — "node", not "component"

1 participant