@naturaldesign/dev 0.0.0-stage → 0.0.12
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/LICENSE +21 -0
- package/README.md +100 -2
- package/dist/babel.cjs +15038 -0
- package/dist/cli.mjs +18073 -0
- package/dist/index.mjs +17840 -0
- package/dist/loader.cjs +17130 -0
- package/dist/types/ast.d.ts +24 -0
- package/dist/types/babel.d.ts +50 -0
- package/dist/types/component-index/babel-props.d.ts +35 -0
- package/dist/types/component-index/react-babel.d.ts +6 -0
- package/dist/types/component-index/react-ts.d.ts +8 -0
- package/dist/types/component-index/scan.d.ts +19 -0
- package/dist/types/component-index/sfc.d.ts +4 -0
- package/dist/types/component-index/types.d.ts +24 -0
- package/dist/types/derive/entry.d.ts +19 -0
- package/dist/types/derive/esbuild.d.ts +23 -0
- package/dist/types/derive/index.d.ts +34 -0
- package/dist/types/derive/postcss.d.ts +4 -0
- package/dist/types/derive/shims.d.ts +10 -0
- package/dist/types/derive/vite.d.ts +15 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/loader.d.ts +24 -0
- package/dist/types/next-index.d.ts +13 -0
- package/dist/types/owners.d.ts +26 -0
- package/dist/types/project.d.ts +12 -0
- package/dist/types/registry.d.ts +15 -0
- package/dist/types/stamp.d.ts +56 -0
- package/dist/types/styles.d.ts +7 -0
- package/dist/types/vite.d.ts +58 -0
- package/dist/vite.mjs +17439 -0
- package/package.json +62 -4
- package/src/next.cjs +34 -0
- package/src/next.d.ts +18 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sam Fitch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,101 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @naturaldesign/dev
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Optional, development-only plugin for apps you open in a Natural Design webframe or use as a component library. It stamps JSX so every element names its source exactly:
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<div data-nd-source="src/app/page.tsx:42:7" data-nd-owner="src/components/Hero.tsx:Hero">
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
- `data-nd-source`: the file (relative to the project root), line and column of a host element's opening tag (`div`, `p`, `section`…), where an edit to it lands.
|
|
10
|
+
- `data-nd-owner`: the exported component whose body the host element sits in (`file:ExportName`, `default` for a default export), so a component's elements group into one instance with no fiber, server components included. Omitted outside exported PascalCase components; an anonymous default export counts, named after its file.
|
|
11
|
+
- `data-nd-call`: on component elements (`<Card>`, `<ui.Card>`, `<motion.div>`), the call site, passed as a prop. React ignores a prop a component does not read; a component that spreads `...rest` onto a host element carries it to the DOM, harmlessly. `Fragment` and `*.Fragment` never get one. A component that iterates its props or uses exact prop-types goes in `exclude`.
|
|
12
|
+
|
|
13
|
+
With stamps on the page, the webframe names an element's source exactly, pairs re-rendered elements by their source, and recognises the page's render of markup it just wrote, instead of inferring all of that from the framework's debug data. Pages without the plugin keep working through the inference path. Nothing is stamped in production builds.
|
|
14
|
+
|
|
15
|
+
Every entry point takes the same stamp options: `exclude` (component names, `Foo` or `Foo.Bar`), `calls: false` and `owners: false` to turn either stamp off.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npx @naturaldesign/dev init # or: pnpm dlx / bunx @naturaldesign/dev init
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Adds the package as a dev dependency with the project's package manager (from its lockfile) and wires the plugin into `next.config.*` or `vite.config.*`, as below. A config that already uses the plugin is left alone. `--no-install` only edits the config. Restart the dev server afterwards.
|
|
24
|
+
|
|
25
|
+
## Next.js
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
// next.config.mjs
|
|
29
|
+
import { withNaturalDesign } from '@naturaldesign/dev/next'
|
|
30
|
+
export default withNaturalDesign({ /* your config */ }, { exclude: ['Trans'] })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Adds a loader for `.jsx`/`.tsx` outside `node_modules` under `next dev` (webpack and Turbopack). Server and client compiles both stamp, so server-rendered markup carries the attributes and hydration sees the same values on both sides. The loader also keeps the component index and the render registry (below). Options: `root`, `exclude`, `calls`, `owners`, `register`, `index`, `indexFolders`.
|
|
34
|
+
|
|
35
|
+
## Vite
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
// vite.config.ts
|
|
39
|
+
import naturalDesign from '@naturaldesign/dev/vite'
|
|
40
|
+
export default { plugins: [naturalDesign({ exclude: ['Trans'] }), react()] }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Runs before the JSX transform, in `vite dev` only. Options: `root`, `exclude`, `calls`, `owners`, `index`, `indexFolders`, `registry`, `styles`.
|
|
44
|
+
|
|
45
|
+
## Babel
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
plugins: [['@naturaldesign/dev/babel', { root: process.cwd(), exclude: ['Trans'] }]]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For `@vitejs/plugin-react`'s `babel` option or any Babel setup; a no-op when `NODE_ENV=production`. Stamps only (no index or registry).
|
|
52
|
+
|
|
53
|
+
## Component index
|
|
54
|
+
|
|
55
|
+
One entry per exported component in `src/components`, `components`, `src/lib/components`, `app/components` and `src/ui` (stories, tests and `.d.ts` skipped):
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{ "name": "Button", "file": "src/components/Button.tsx", "exportName": "Button", "framework": "react",
|
|
59
|
+
"props": [{ "name": "size", "type": "enum", "options": ["sm", "md", "lg"], "optional": true, "default": "md" }] }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Prop types are `enum` (string literal unions, with `options`), `text`, `number`, `boolean`, `slot` (`children`, `ReactNode`, `ReactElement`, Svelte `Snippet`, Vue/Svelte/Astro `<slot>`; an unnamed slot is `children`) and `other` (functions, objects, anything imported that does not resolve). Defaults are static values from destructuring, `withDefaults`, `export let` or Vue's `default:`.
|
|
63
|
+
|
|
64
|
+
- React (`.tsx`/`.jsx`, exported PascalCase function, const, `memo`/`forwardRef` or class): the type of the first parameter through the project's own `typescript` (loaded from its node_modules, reusing one program), so imported types and `VariantProps<typeof cva>` resolve. Props declared only in `node_modules` types (`ButtonHTMLAttributes`…) are left out, except `children`. Without `typescript`, `@babel/parser` reads local types only.
|
|
65
|
+
- Svelte: `let { … }: Props = $props()` (Svelte 5) or `export let` (Svelte 3/4).
|
|
66
|
+
- Vue: `defineProps<T>()`, `withDefaults(defineProps<T>(), {…})`, `defineProps({…})` or the Options API's `props`.
|
|
67
|
+
- Astro: `interface Props` / `type Props` in the frontmatter, defaults from `Astro.props`.
|
|
68
|
+
|
|
69
|
+
Where it is served:
|
|
70
|
+
|
|
71
|
+
- Vite: `GET /__natural/components.json` returns `{ root, components }` (CORS open, recomputed after source changes).
|
|
72
|
+
- Next (no routes from a config): the loader writes one descriptor per component file it compiles to `<root>/.next/natural/index/<encodeURIComponent(file)>.json`, `{ file, framework, components }`, shortly after the compile, and removes it when the file no longer exports a component. Only files a page has imported are compiled, so the folder fills as the app is used.
|
|
73
|
+
- CLI: `naturaldesign-dev index <root> [--folders a,b] [--no-typescript]` prints `{ root, components }`.
|
|
74
|
+
- Node: `indexComponents(root, { folders, typescript })` from `@naturaldesign/dev`.
|
|
75
|
+
|
|
76
|
+
## Render registry
|
|
77
|
+
|
|
78
|
+
Mounts a component by name inside the running app, with the app's own framework instance, so hooks and context work.
|
|
79
|
+
|
|
80
|
+
- Vite: the virtual module `virtual:natural-design/registry` is injected into the app's pages and installs `window.__nd`: `components` (name → `{ name, file, exportName, framework, load() }`; a clashing name is keyed `file#exportName`), `register(name, component, file, exportName)`, `render(name, props, element)` (resolves after mount and two frames) and `unmount(element)`. React 18/19 mounts through the project's `react-dom/client`; Svelte (5 `mount`, 4 `new`) and Vue (`createApp`) are best effort; Astro cannot mount in a browser. A prop value `{ "__html": "…" }` is slot markup, rendered as each framework's children.
|
|
81
|
+
- `GET /__natural/host` is a bare page (the project's `<html>`/`<body>` attributes, Vite's client, the React refresh preamble) with the project's global stylesheet (found from `index.html` and the entry's CSS imports; override with `styles`) and the registry, through `virtual:natural-design/host`. `?component=Button&props={…}` renders straight into `#nd-host-root`.
|
|
82
|
+
- `natural.config.(tsx|ts|jsx|js|mjs)` at the root may export `decorator`, a component that wraps every rendered component in the app's providers (React).
|
|
83
|
+
- Next: the loader appends `window.__nd.register(name, Component, file, exportName)` to `'use client'` files for each exported component with a binding (client only; never on the server). When the agent has not installed `register` yet, the component waits in `window.__nd.components[name].component`. Server components are not registered.
|
|
84
|
+
|
|
85
|
+
## Derive
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
naturaldesign-dev derive <root> <file> <exportName> --out <dir> [--props '{"size":"lg"}'] [--esbuild dir] [--node-paths a,b] [--bundler vite|esbuild] [--styles a,b]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Bundles one component into `<out>/component.js`, an ES module exporting `mount(element, props)` → `{ update(props), unmount() }`, `defaultProps` (from `--props`) and `meta`, and `<out>/component.css`. Host elements carry `data-nd-source` and `data-nd-owner` (React). A render error leaves the container empty with `data-nd-error` on it. Prints `{ ok, partial, js, css, warnings, bundler, framework, stubs }` and exits 1 when `ok` is false.
|
|
92
|
+
|
|
93
|
+
- With `node_modules` and Vite: the project's own Vite in library mode with its config file, so its plugins, Tailwind/PostCSS and aliases apply; everything bundled, the project's externals and chunking overridden.
|
|
94
|
+
- Otherwise esbuild: the project's, then `--esbuild` (an esbuild package folder, or a folder whose node_modules has one, e.g. the app's sidecar), then `$NATURAL_ESBUILD`, then this package's own. The project's PostCSS config runs over project CSS and Svelte compiles through the project's `svelte/compiler`; Vue and Astro need Vite. Every import that does not resolve becomes a stub whose exports are components rendering their children, and the result is `partial` (also whenever the project has no `node_modules`). If the framework runtime itself is stubbed, `ok` is false: `--node-paths` names folders to resolve `react`/`react-dom` from.
|
|
95
|
+
- `next/link`, `next/image`, `next/font/*`, `next/navigation`, `next/router`, `next/head`, `next/script`, `next/dynamic`, `server-only` and `client-only` are the plugin's own shims in both paths. Nothing else in a component is rewritten: one that does not build reports why.
|
|
96
|
+
- Async server components are refused (they cannot mount in a browser). Astro components are refused.
|
|
97
|
+
- In node: `derive({ root, file, exportName, out, props, esbuild, nodePaths, bundler, styles })` from `@naturaldesign/dev`. The CLI changes directory to `<root>` first, since Tailwind resolves its sources from there; do the same when calling `derive` directly.
|
|
98
|
+
|
|
99
|
+
## Svelte, Astro, Vue
|
|
100
|
+
|
|
101
|
+
The stamps are JSX-only: their dev builds already record each element's source, which the webframe reads directly. The index and the registry cover them as above.
|