machinalayout 0.1.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.
- package/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.js +1068 -0
- package/docs/forbidden-concepts.md +60 -0
- package/docs/frames-and-stack.md +135 -0
- package/docs/m0-contract.md +70 -0
- package/docs/machina-text-m2a-plan.md +319 -0
- package/docs/machina-text-parser.md +24 -0
- package/docs/machina-text-react.md +68 -0
- package/docs/npm-prepublish-m2z-audit.md +233 -0
- package/docs/npm-prepublish-m3c-cleanup.md +105 -0
- package/docs/react-adapter.md +110 -0
- package/docs/row-model.md +82 -0
- package/docs/z-order-and-containment.md +38 -0
- package/package.json +60 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# MachinaLayout M2z npm prepublish readiness audit
|
|
2
|
+
|
|
3
|
+
Date: 2026-05-02 (UTC)
|
|
4
|
+
Scope: prepublish readiness for a future `0.1.0` npm publish (audit only, no publish action).
|
|
5
|
+
|
|
6
|
+
## 1) Executive summary
|
|
7
|
+
|
|
8
|
+
Current repo state is **not publish-ready** for npm consumers. The biggest blockers are:
|
|
9
|
+
|
|
10
|
+
1. Root package is marked `"private": true` and has no runtime entrypoint metadata (`main`/`exports`/`types`), while README demonstrates package consumption by name.
|
|
11
|
+
2. Build script is typecheck-only (`tsc --noEmit`), so there is no emitted JS or declaration output for consumers.
|
|
12
|
+
3. Tarball currently includes raw source/tests/sample/docs and excludes any built dist folder (none exists).
|
|
13
|
+
4. Consumer smoke test via packed tarball fails to resolve `machinalayout` module/types.
|
|
14
|
+
|
|
15
|
+
No feature/API behavior changes were made in this pass.
|
|
16
|
+
|
|
17
|
+
## 2) Current package metadata status
|
|
18
|
+
|
|
19
|
+
Observed in root `package.json`:
|
|
20
|
+
|
|
21
|
+
- `name`: `machinalayout`
|
|
22
|
+
- `version`: `0.1.0`
|
|
23
|
+
- `private`: `true`
|
|
24
|
+
- `type`: `module`
|
|
25
|
+
- Missing: `description`, `license` field, `author`, `repository`, `homepage`, `bugs`, `keywords`, `main`, `module`, `types`, `exports`, `files`, `sideEffects`, `dependencies`
|
|
26
|
+
- Present scripts: `build`, `test`
|
|
27
|
+
- `peerDependencies`: `react`, `react-dom`
|
|
28
|
+
- `devDependencies`: test/build tooling only (TypeScript, Vitest, jsdom, testing-library, React type packages)
|
|
29
|
+
|
|
30
|
+
Assessment:
|
|
31
|
+
|
|
32
|
+
- Package name appears npm-compatible syntactically (unscoped), but final naming strategy is unresolved from metadata alone.
|
|
33
|
+
- Package is currently **unscoped**.
|
|
34
|
+
- Version `0.1.0` is consistent with first publish intent, but `private: true` currently blocks publish.
|
|
35
|
+
- React/ReactDOM are correctly peer dependencies, not runtime dependencies.
|
|
36
|
+
- Tooling is correctly in devDependencies.
|
|
37
|
+
- Export surface metadata is not declared at package boundary (no `exports`/`main`/`types`).
|
|
38
|
+
- README/docs are currently included by default due no restrictive `files` list.
|
|
39
|
+
- Sample is also included by default and should likely be excluded for library publish unless intentionally bundled.
|
|
40
|
+
|
|
41
|
+
## 3) Build output status
|
|
42
|
+
|
|
43
|
+
Command run: `npm run build`
|
|
44
|
+
|
|
45
|
+
Result: pass, but script is `tsc --noEmit` (typecheck only).
|
|
46
|
+
|
|
47
|
+
Implications:
|
|
48
|
+
|
|
49
|
+
- No compiled JS output emitted.
|
|
50
|
+
- No `.d.ts` output emitted.
|
|
51
|
+
- No source maps emitted.
|
|
52
|
+
- No ESM/CJS build artifacts produced.
|
|
53
|
+
- Therefore output cannot match package runtime entrypoints (none configured).
|
|
54
|
+
- React/text modules exist in source, but not in emitted build artifacts.
|
|
55
|
+
|
|
56
|
+
## 4) Public exports/API surface status
|
|
57
|
+
|
|
58
|
+
`src/index.ts` re-exports core modules (`types`, `errors`, validation/padding/length/offset helpers, compile/resolve functions, resolved tree helpers), plus `./react` and `./text`.
|
|
59
|
+
|
|
60
|
+
Findings:
|
|
61
|
+
|
|
62
|
+
- Major APIs appear reachable from root source barrel in-repo.
|
|
63
|
+
- React exports are intentionally included via `export * from "./react"`.
|
|
64
|
+
- Text parser/types and React text view are intentionally included via `export * from "./text"` and nested text/react barrel.
|
|
65
|
+
- No obvious accidental internal export from top-level barrel based on current file list.
|
|
66
|
+
- Before publish, explicit package `exports` map (root + optional subpaths) is recommended for stability.
|
|
67
|
+
|
|
68
|
+
## 5) Type declaration status
|
|
69
|
+
|
|
70
|
+
Post-build status: **no declarations emitted** because build uses `--noEmit`.
|
|
71
|
+
|
|
72
|
+
- `types` field is absent in `package.json`.
|
|
73
|
+
- `.d.ts` distribution is absent.
|
|
74
|
+
- This is a **publish blocker**.
|
|
75
|
+
|
|
76
|
+
## 6) React peer dependency status
|
|
77
|
+
|
|
78
|
+
Root package uses:
|
|
79
|
+
|
|
80
|
+
- `peerDependencies.react: ^19.2.5`
|
|
81
|
+
- `peerDependencies.react-dom: ^19.2.5`
|
|
82
|
+
|
|
83
|
+
Assessment:
|
|
84
|
+
|
|
85
|
+
- Correct placement as peer deps for adapter components.
|
|
86
|
+
- No runtime `dependencies` are declared.
|
|
87
|
+
- Consider whether peer range should be broadened for ecosystem compatibility in M3.
|
|
88
|
+
|
|
89
|
+
## 7) Package contents / `npm pack --dry-run` status
|
|
90
|
+
|
|
91
|
+
Command run: `npm pack --dry-run`
|
|
92
|
+
|
|
93
|
+
Result:
|
|
94
|
+
|
|
95
|
+
- Tarball name: `machinalayout-0.1.0.tgz`
|
|
96
|
+
- Package size: 57.1 kB
|
|
97
|
+
- Unpacked size: 247.2 kB
|
|
98
|
+
- Total files: 67
|
|
99
|
+
|
|
100
|
+
Included content highlights:
|
|
101
|
+
|
|
102
|
+
- `src/**` TypeScript sources
|
|
103
|
+
- `test/**` test sources
|
|
104
|
+
- `samples/control-room/**` including its `package-lock.json`
|
|
105
|
+
- `docs/**`
|
|
106
|
+
- `README.md`, `LICENSE`, `tsconfig.json`
|
|
107
|
+
|
|
108
|
+
Not included: no `dist/**` output (none exists).
|
|
109
|
+
|
|
110
|
+
Assessment:
|
|
111
|
+
|
|
112
|
+
- Current pack contents look like a source repository bundle, not a focused library distribution.
|
|
113
|
+
- Inclusion of tests and sample app is likely unintentional for npm consumers unless explicitly desired.
|
|
114
|
+
- README and LICENSE are present (good).
|
|
115
|
+
|
|
116
|
+
## 8) README/docs publish-readiness status
|
|
117
|
+
|
|
118
|
+
README currently:
|
|
119
|
+
|
|
120
|
+
- Uses install/import examples with package name `machinalayout`.
|
|
121
|
+
- Demonstrates `resolveLayoutRows`, `LayoutRow`, `MachinaReactView` usage.
|
|
122
|
+
- Mentions sample run instructions (`cd samples/control-room`, `npm install`, `npm run dev`).
|
|
123
|
+
- Explicitly states boundaries like no intrinsic sizing / no CSS layout authority.
|
|
124
|
+
|
|
125
|
+
Assessment:
|
|
126
|
+
|
|
127
|
+
- API narrative is mostly aligned with current source exports.
|
|
128
|
+
- Install instructions will remain provisional until package metadata/export strategy is finalized.
|
|
129
|
+
- No obvious critical stale claims found during this pass.
|
|
130
|
+
|
|
131
|
+
## 9) Sample package status
|
|
132
|
+
|
|
133
|
+
Command run in sample: `cd samples/control-room && npm run build`
|
|
134
|
+
|
|
135
|
+
Result: pass.
|
|
136
|
+
|
|
137
|
+
Sample dependency model:
|
|
138
|
+
|
|
139
|
+
- `machinalayout` is consumed via local file dependency: `"file:../.."`.
|
|
140
|
+
|
|
141
|
+
Assessment:
|
|
142
|
+
|
|
143
|
+
- Sample is wired to root workspace package path, useful for local integration.
|
|
144
|
+
- Sample should likely be excluded from root publish tarball unless intentional.
|
|
145
|
+
|
|
146
|
+
## 10) Consumer smoke-test status
|
|
147
|
+
|
|
148
|
+
Method used:
|
|
149
|
+
|
|
150
|
+
1. Created real tarball via `npm pack`.
|
|
151
|
+
2. Created temporary external consumer at `/tmp/machina-consumer-smoke/consumer`.
|
|
152
|
+
3. Installed tarball + minimal deps.
|
|
153
|
+
4. Created `smoke.ts` importing:
|
|
154
|
+
- `resolveLayoutRows`
|
|
155
|
+
- `RootFrame` type
|
|
156
|
+
- `MachinaReactView`
|
|
157
|
+
- `parseMachinaText`
|
|
158
|
+
- `MachinaTextView`
|
|
159
|
+
5. Ran TypeScript compile check.
|
|
160
|
+
|
|
161
|
+
Result: **fail**.
|
|
162
|
+
|
|
163
|
+
Error:
|
|
164
|
+
|
|
165
|
+
- `TS2307: Cannot find module 'machinalayout' or its corresponding type declarations.`
|
|
166
|
+
|
|
167
|
+
Interpretation:
|
|
168
|
+
|
|
169
|
+
- Packed package is not consumable as a normal npm dependency due missing entrypoint/type declarations.
|
|
170
|
+
|
|
171
|
+
## 11) Risks/blockers before 0.1.0
|
|
172
|
+
|
|
173
|
+
Blockers:
|
|
174
|
+
|
|
175
|
+
1. `private: true` in root package metadata.
|
|
176
|
+
2. Missing entrypoint metadata (`main`/`exports`/`types`).
|
|
177
|
+
3. No emitted build artifacts (JS/d.ts).
|
|
178
|
+
4. Consumer smoke test fails module/type resolution.
|
|
179
|
+
|
|
180
|
+
Risks (non-blocker but important):
|
|
181
|
+
|
|
182
|
+
1. Over-inclusive tarball (tests/samples/docs/source-only) may confuse consumers and bloat installs.
|
|
183
|
+
2. Missing discoverability metadata (`description`, repository/homepage/bugs/keywords).
|
|
184
|
+
3. No explicit `sideEffects` declaration; tree-shaking semantics are implicit.
|
|
185
|
+
|
|
186
|
+
## 12) Recommended M3 cleanup checklist
|
|
187
|
+
|
|
188
|
+
### Package metadata
|
|
189
|
+
|
|
190
|
+
- [ ] Decide final npm name strategy (keep unscoped `machinalayout` or scope it).
|
|
191
|
+
- [ ] Remove/adjust `private` for publish pipeline.
|
|
192
|
+
- [ ] Add `description`, `license` field, `author`, `repository`, `homepage`, `bugs`, `keywords`.
|
|
193
|
+
- [ ] Add explicit runtime/type entrypoints: `main`/`module` (if dual), `types`, and `exports` map.
|
|
194
|
+
- [ ] Add `sideEffects` policy.
|
|
195
|
+
|
|
196
|
+
### Build/distribution
|
|
197
|
+
|
|
198
|
+
- [ ] Add actual emit build (e.g., dist JS + d.ts, optional sourcemaps).
|
|
199
|
+
- [ ] Ensure build output paths align with package entrypoints.
|
|
200
|
+
- [ ] Confirm React/text modules are included in emitted artifacts.
|
|
201
|
+
|
|
202
|
+
### Packaging contents
|
|
203
|
+
|
|
204
|
+
- [ ] Add `files` allowlist (or `.npmignore`) to publish intended artifacts only.
|
|
205
|
+
- [ ] Exclude tests/sample sources and lockfiles from library tarball unless intentionally shipped.
|
|
206
|
+
- [ ] Re-run `npm pack --dry-run` and validate final file list.
|
|
207
|
+
|
|
208
|
+
### Consumer validation
|
|
209
|
+
|
|
210
|
+
- [ ] Re-run tarball-based smoke test after metadata/build fixes.
|
|
211
|
+
- [ ] Add a lightweight CI smoke-check that installs packed tarball and typechecks imports.
|
|
212
|
+
|
|
213
|
+
### Docs/readiness
|
|
214
|
+
|
|
215
|
+
- [ ] Update README install command once final package name/scope is confirmed.
|
|
216
|
+
- [ ] Ensure docs state publish support level and adapter peer dependency expectations.
|
|
217
|
+
|
|
218
|
+
## 13) Exact commands run and results
|
|
219
|
+
|
|
220
|
+
1. `npm test` → **pass** (17 files, 170 tests). Observed benign environment stderr in jsdom test: "Not implemented: navigation to another Document".
|
|
221
|
+
2. `npm run build` → **pass** as typecheck-only (`tsc --noEmit`), no distributable output.
|
|
222
|
+
3. `cd samples/control-room && npm run build` → **pass** (`tsc -b && vite build`).
|
|
223
|
+
4. `npm pack --dry-run` → **pass**, tarball preview generated with 67 files, includes src/test/sample/docs.
|
|
224
|
+
5. Consumer smoke sequence using `npm pack` + external temp project + `npx tsc smoke.ts ...` → **fail** with TS2307 unable to resolve `machinalayout` module/types.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
Non-goal compliance check:
|
|
229
|
+
|
|
230
|
+
- No `npm publish` run.
|
|
231
|
+
- No release tags created.
|
|
232
|
+
- No version bumps performed.
|
|
233
|
+
- No runtime/layout/text feature changes performed.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# MachinaLayout M3c npm packaging cleanup
|
|
2
|
+
|
|
3
|
+
Date: 2026-05-02 (UTC)
|
|
4
|
+
Scope: packaging/distribution readiness for future npm `0.1.0` publish (no publish action performed).
|
|
5
|
+
|
|
6
|
+
## 1) What changed
|
|
7
|
+
|
|
8
|
+
- Replaced typecheck-only build with a real package build that emits ESM JavaScript and declarations under `dist/`.
|
|
9
|
+
- Added `tsup` build configuration for `src/index.ts` with externalized React dependencies.
|
|
10
|
+
- Added root package entrypoint metadata (`main`, `module`, `types`, `exports`) and a `files` allowlist.
|
|
11
|
+
- Removed `private: true` from root package to unblock publish readiness.
|
|
12
|
+
- Broadened React peer dependency ranges to `>=18 <20`.
|
|
13
|
+
- Added npm install guidance to README.
|
|
14
|
+
- Verified package contents with `npm pack --dry-run`.
|
|
15
|
+
- Verified packed tarball consumer typecheck in an external temporary consumer project.
|
|
16
|
+
|
|
17
|
+
## 2) Package metadata decisions
|
|
18
|
+
|
|
19
|
+
- Package name kept as `machinalayout`.
|
|
20
|
+
- Version kept as `0.1.0`.
|
|
21
|
+
- Kept ESM-only distribution for this pass (`type: module`, ESM `dist/index.js`).
|
|
22
|
+
- Added:
|
|
23
|
+
- `description`, `license`, `author`, `repository`, `homepage`, `bugs`, `keywords`
|
|
24
|
+
- `main`, `module`, `types`, `exports`
|
|
25
|
+
- `files` allowlist
|
|
26
|
+
- `sideEffects: false`
|
|
27
|
+
- React and ReactDOM remain peer dependencies and are not bundled.
|
|
28
|
+
|
|
29
|
+
## 3) Build output shape
|
|
30
|
+
|
|
31
|
+
`npm run build` now does:
|
|
32
|
+
|
|
33
|
+
1. `npm run typecheck` (`tsc --noEmit`)
|
|
34
|
+
2. `tsup --config tsup.config.ts --tsconfig tsconfig.build.json`
|
|
35
|
+
|
|
36
|
+
Expected emitted artifacts:
|
|
37
|
+
|
|
38
|
+
- `dist/index.js`
|
|
39
|
+
- `dist/index.d.ts`
|
|
40
|
+
|
|
41
|
+
## 4) Package exports shape
|
|
42
|
+
|
|
43
|
+
Root package exports are configured as:
|
|
44
|
+
|
|
45
|
+
- `exports["."].import -> ./dist/index.js`
|
|
46
|
+
- `exports["."].types -> ./dist/index.d.ts`
|
|
47
|
+
|
|
48
|
+
No subpath exports were introduced in this pass.
|
|
49
|
+
|
|
50
|
+
## 5) Files/tarball contents
|
|
51
|
+
|
|
52
|
+
`npm pack --dry-run` now shows a focused tarball containing:
|
|
53
|
+
|
|
54
|
+
- `dist/**`
|
|
55
|
+
- `README.md`
|
|
56
|
+
- `LICENSE`
|
|
57
|
+
- `docs/**`
|
|
58
|
+
- `package.json`
|
|
59
|
+
|
|
60
|
+
Observed exclusions (desired):
|
|
61
|
+
|
|
62
|
+
- `src/**` excluded
|
|
63
|
+
- `test/**` excluded
|
|
64
|
+
- `samples/**` excluded
|
|
65
|
+
|
|
66
|
+
Dry-run snapshot:
|
|
67
|
+
|
|
68
|
+
- package size: `28.2 kB`
|
|
69
|
+
- unpacked size: `93.5 kB`
|
|
70
|
+
- total files: `15`
|
|
71
|
+
|
|
72
|
+
No unexpected runtime payloads were observed.
|
|
73
|
+
|
|
74
|
+
## 6) Consumer smoke result
|
|
75
|
+
|
|
76
|
+
Smoke validation used a real packed tarball installed into `/tmp/machina-m3c-smoke` and compiled a TypeScript file importing:
|
|
77
|
+
|
|
78
|
+
- `resolveLayoutRows`
|
|
79
|
+
- `RootFrame` (type)
|
|
80
|
+
- `MachinaReactView`
|
|
81
|
+
- `parseMachinaText`
|
|
82
|
+
- `MachinaTextView`
|
|
83
|
+
|
|
84
|
+
TypeScript compile succeeded with no module/type resolution errors.
|
|
85
|
+
|
|
86
|
+
## 7) Remaining manual publish steps (not executed here)
|
|
87
|
+
|
|
88
|
+
1. Confirm npm auth:
|
|
89
|
+
- `npm whoami`
|
|
90
|
+
2. Login if needed:
|
|
91
|
+
- `npm login`
|
|
92
|
+
3. Optional name availability check:
|
|
93
|
+
- `npm view machinalayout`
|
|
94
|
+
4. Final packaging check:
|
|
95
|
+
- `npm pack --dry-run`
|
|
96
|
+
5. Publish:
|
|
97
|
+
- `npm publish --access public`
|
|
98
|
+
- Note: for unscoped packages, npm may not require/accept `--access public`; retry without flag if npm rejects it.
|
|
99
|
+
6. Validate org policy for npm 2FA/token/trusted publishing.
|
|
100
|
+
|
|
101
|
+
## 8) Remaining risks before npm publish
|
|
102
|
+
|
|
103
|
+
- Repository/homepage/bugs URLs should be confirmed against the canonical upstream repository if different from current metadata.
|
|
104
|
+
- No CJS build is included (intentional for this ESM-first pass); consumers requiring CJS will need transpilation/interoperability handling.
|
|
105
|
+
- Moderate security advisories remain in current dev dependency graph (non-blocking for packaging outcome, but worth auditing).
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# React Adapter
|
|
2
|
+
|
|
3
|
+
## Boundary
|
|
4
|
+
|
|
5
|
+
- Core layout resolution has no React dependency.
|
|
6
|
+
- The React adapter consumes a `ResolvedLayoutDocument`.
|
|
7
|
+
- The adapter renders absolutely positioned wrappers.
|
|
8
|
+
- Slot components render inside those wrappers.
|
|
9
|
+
|
|
10
|
+
## Basic usage
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import { MachinaReactView, resolveLayoutRows } from "machinalayout";
|
|
14
|
+
|
|
15
|
+
const resolved = resolveLayoutRows(rows, rootRect);
|
|
16
|
+
|
|
17
|
+
const views = {
|
|
18
|
+
header: HeaderView,
|
|
19
|
+
sidebar: SidebarView,
|
|
20
|
+
toolbarButton: ToolbarButtonView,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
<MachinaReactView layout={resolved} views={views} />;
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Slot props
|
|
27
|
+
|
|
28
|
+
Slot views receive:
|
|
29
|
+
|
|
30
|
+
- `id`
|
|
31
|
+
- `rect`
|
|
32
|
+
- `debugLabel`
|
|
33
|
+
- `node`
|
|
34
|
+
|
|
35
|
+
## Coordinate normalization
|
|
36
|
+
|
|
37
|
+
Core resolved rects are global/root-space coordinates.
|
|
38
|
+
|
|
39
|
+
The React adapter renders nested absolutely positioned DOM wrappers, so each node
|
|
40
|
+
wrapper is positioned in its parent-local DOM coordinate space:
|
|
41
|
+
|
|
42
|
+
- `left = node.rect.x - parent.rect.x`
|
|
43
|
+
- `top = node.rect.y - parent.rect.y`
|
|
44
|
+
|
|
45
|
+
The outer wrapper represents the root coordinate space and uses the resolved root
|
|
46
|
+
width/height. The root node itself renders at local `left: 0` and `top: 0`.
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
|
|
50
|
+
- root rect `{ x: 100, y: 200, width: 800, height: 600 }`
|
|
51
|
+
- child rect `{ x: 116, y: 212, width: 100, height: 50 }`
|
|
52
|
+
- rendered child CSS `left: 16px; top: 12px;`
|
|
53
|
+
|
|
54
|
+
Nested example:
|
|
55
|
+
|
|
56
|
+
- parent rect `{ x: 268, y: 88, width: 816, height: 616 }`
|
|
57
|
+
- child rect `{ x: 284, y: 104, width: 784, height: 48 }`
|
|
58
|
+
- rendered child CSS `left: 16px; top: 16px;`
|
|
59
|
+
|
|
60
|
+
## CSS boundary
|
|
61
|
+
|
|
62
|
+
Allowed for Machina wrappers:
|
|
63
|
+
|
|
64
|
+
- position (`relative`/`absolute`)
|
|
65
|
+
- `left` / `top` / `width` / `height`
|
|
66
|
+
- `box-sizing`
|
|
67
|
+
- `z-index`
|
|
68
|
+
- containment/content-visibility
|
|
69
|
+
- cosmetic/debug styles
|
|
70
|
+
|
|
71
|
+
Not allowed as Machina geometry authority:
|
|
72
|
+
|
|
73
|
+
- flexbox
|
|
74
|
+
- grid
|
|
75
|
+
- margins
|
|
76
|
+
- transforms
|
|
77
|
+
- DOM measurement
|
|
78
|
+
- CSS classes determining geometry
|
|
79
|
+
|
|
80
|
+
Slot internals may use normal React/CSS/shadcn-style components. Machina controls only the outer rectangle.
|
|
81
|
+
|
|
82
|
+
## Stable view registry and data channels
|
|
83
|
+
|
|
84
|
+
`views` should be a stable registry of component types, not inline factories recreated from state.
|
|
85
|
+
|
|
86
|
+
Bad (new component identity each render):
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
const views = {
|
|
90
|
+
Inspector: () => <Inspector sidebarLeft={sidebarLeft} />,
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Good (stable component type + dynamic data):
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
const views = { Inspector };
|
|
98
|
+
|
|
99
|
+
<MachinaReactView
|
|
100
|
+
layout={resolved}
|
|
101
|
+
views={views}
|
|
102
|
+
viewData={{ Inspector: { sidebarLeft } }}
|
|
103
|
+
/>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Use adapter data channels for changing values:
|
|
107
|
+
|
|
108
|
+
- `viewData`: keyed by effective `view ?? slot` key.
|
|
109
|
+
- `nodeData`: keyed by concrete node id.
|
|
110
|
+
- slot props include `viewKey`, `viewData`, and `nodeData`.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Row Model
|
|
2
|
+
|
|
3
|
+
`LayoutRow[]` is the canonical authoring model.
|
|
4
|
+
|
|
5
|
+
## Why rows
|
|
6
|
+
|
|
7
|
+
Rows are:
|
|
8
|
+
|
|
9
|
+
- easy to read,
|
|
10
|
+
- easy to diff,
|
|
11
|
+
- easy to patch,
|
|
12
|
+
- easy to serialize,
|
|
13
|
+
- easy for humans and LLMs,
|
|
14
|
+
- naturally table/record-shaped.
|
|
15
|
+
|
|
16
|
+
> Nesting is an output shape, not an authoring strategy.
|
|
17
|
+
|
|
18
|
+
## Row fields
|
|
19
|
+
|
|
20
|
+
- `id`: stable node identifier.
|
|
21
|
+
- `parent`: parent node id (omit only for root).
|
|
22
|
+
- `order`: sibling order key.
|
|
23
|
+
- `frame`: geometry primitive (`absolute`, `anchor`, `fixed`).
|
|
24
|
+
- `arrange`: optional arrangement strategy (currently `stack`).
|
|
25
|
+
- `slot`: renderer view key.
|
|
26
|
+
- `debugLabel`: optional debug-facing label.
|
|
27
|
+
- `z`: optional sibling-local paint layer metadata.
|
|
28
|
+
|
|
29
|
+
## Parent-child meaning
|
|
30
|
+
|
|
31
|
+
Parent-child means only:
|
|
32
|
+
|
|
33
|
+
- resolve this child rectangle in the parent coordinate space.
|
|
34
|
+
|
|
35
|
+
It does **not** imply:
|
|
36
|
+
|
|
37
|
+
- component ownership,
|
|
38
|
+
- state ownership,
|
|
39
|
+
- event ownership,
|
|
40
|
+
- routing hierarchy,
|
|
41
|
+
- semantic DOM hierarchy,
|
|
42
|
+
- styling inheritance.
|
|
43
|
+
|
|
44
|
+
## Deterministic sibling order
|
|
45
|
+
|
|
46
|
+
Siblings are ordered by:
|
|
47
|
+
|
|
48
|
+
1. `order ?? 0`
|
|
49
|
+
2. original row index (tie-break)
|
|
50
|
+
|
|
51
|
+
This keeps compile and resolve deterministic.
|
|
52
|
+
|
|
53
|
+
## Compile validation guarantees
|
|
54
|
+
|
|
55
|
+
`compileLayoutRows` rejects invalid row graphs:
|
|
56
|
+
|
|
57
|
+
- exactly one root required,
|
|
58
|
+
- duplicate ids rejected,
|
|
59
|
+
- unknown parents rejected,
|
|
60
|
+
- cycles rejected,
|
|
61
|
+
- invalid `z` rejected.
|
|
62
|
+
|
|
63
|
+
## Compact row table example
|
|
64
|
+
|
|
65
|
+
| id | parent | order | frame | arrange | slot | z |
|
|
66
|
+
|------------------|---------|-------|--------------------------------------|---------|---------------|---|
|
|
67
|
+
| root | — | 0 | absolute `{x:0,y:0,w:1024,h:640}` | — | — | — |
|
|
68
|
+
| header | root | 0 | anchor `{left:0,right:0,top:0,h:64}`| — | `header` | 0 |
|
|
69
|
+
| sidebar | root | 1 | anchor `{left:0,top:64,bottom:0,w:240}` | — | `sidebar` | 0 |
|
|
70
|
+
| toolbar | root | 2 | anchor `{left:240,right:0,top:64,h:56}` | stack | — | 0 |
|
|
71
|
+
| toolbar-button-1 | toolbar | 0 | fixed `{w:120,h:40}` | — | `toolbarButton` | 0 |
|
|
72
|
+
|
|
73
|
+
- `offset`: optional post-placement local translation (`OffsetSpec` using `UiLength`), not margin and does not affect siblings.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Root row frame guidance (M3a)
|
|
77
|
+
|
|
78
|
+
Use `RootFrame` on the root row. Root geometry is sourced from caller `rootRect`, not from row frame numbers.
|
|
79
|
+
|
|
80
|
+
- Root `FillFrame` is invalid (`FillFrameWithoutArranger`).
|
|
81
|
+
- Root `FixedFrame` is invalid (`FixedFrameWithoutArranger`).
|
|
82
|
+
- Root `AbsoluteFrame` and `AnchorFrame` remain accepted for compatibility, but `RootFrame` is preferred.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Z-order and Containment
|
|
2
|
+
|
|
3
|
+
## Z-order
|
|
4
|
+
|
|
5
|
+
- `z?: number` is node metadata.
|
|
6
|
+
- Explicit `z` must be an integer in `-5..5`.
|
|
7
|
+
- Omitted `z` defaults to effective `0`.
|
|
8
|
+
- `z` is sibling-local.
|
|
9
|
+
- Higher `z` paints in front.
|
|
10
|
+
- Same `z` uses sibling order as tie-break.
|
|
11
|
+
- `z` does not affect geometry.
|
|
12
|
+
- `z` does not affect stack placement.
|
|
13
|
+
- `z` does not reorder compiled/resolved/tree children.
|
|
14
|
+
- React adapter sorts sibling render order by effective `z` for paint only.
|
|
15
|
+
|
|
16
|
+
Rationale: if a UI needs more than eleven sibling-local paint layers, the layout structure should be reconsidered.
|
|
17
|
+
|
|
18
|
+
## Containment policy
|
|
19
|
+
|
|
20
|
+
Containment is adapter policy, not core layout semantics.
|
|
21
|
+
|
|
22
|
+
React adapter props:
|
|
23
|
+
|
|
24
|
+
- `nodeContainment?: "none" | "layout-paint" | "strict"`
|
|
25
|
+
- `nodeContentVisibility?: "none" | "auto"`
|
|
26
|
+
- `nodeContainIntrinsicSize?: string`
|
|
27
|
+
|
|
28
|
+
Defaults:
|
|
29
|
+
|
|
30
|
+
- `nodeContainment = "layout-paint"`
|
|
31
|
+
- `nodeContentVisibility = "none"`
|
|
32
|
+
|
|
33
|
+
Guidance:
|
|
34
|
+
|
|
35
|
+
- `layout-paint` is the default safe performance posture.
|
|
36
|
+
- `strict` is stronger and opt-in.
|
|
37
|
+
- `content-visibility: auto` is powerful for large/offscreen content but opt-in.
|
|
38
|
+
- `contain-intrinsic-size` can be supplied when using content visibility.
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "machinalayout",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"typecheck": "tsc --noEmit",
|
|
7
|
+
"build": "npm run typecheck && tsup --config tsup.config.ts --tsconfig tsconfig.build.json",
|
|
8
|
+
"test": "vitest run"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
12
|
+
"@testing-library/react": "^16.3.2",
|
|
13
|
+
"@types/react": "^19.2.14",
|
|
14
|
+
"@types/react-dom": "^19.2.3",
|
|
15
|
+
"jsdom": "^29.1.1",
|
|
16
|
+
"typescript": "^5.6.3",
|
|
17
|
+
"vitest": "^2.1.8",
|
|
18
|
+
"tsup": "^8.5.1"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"react": ">=18 <20",
|
|
22
|
+
"react-dom": ">=18 <20"
|
|
23
|
+
},
|
|
24
|
+
"description": "Machine-native layout and text primitives for deterministic app UI records.",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": "MachinaLayout contributors",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/machinalayout/MachinaLayout.JS.git"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/machinalayout/MachinaLayout.JS#readme",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/machinalayout/MachinaLayout.JS/issues"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"layout",
|
|
37
|
+
"ui",
|
|
38
|
+
"react",
|
|
39
|
+
"typescript",
|
|
40
|
+
"machina",
|
|
41
|
+
"text",
|
|
42
|
+
"rectangles"
|
|
43
|
+
],
|
|
44
|
+
"main": "./dist/index.js",
|
|
45
|
+
"module": "./dist/index.js",
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"exports": {
|
|
48
|
+
".": {
|
|
49
|
+
"types": "./dist/index.d.ts",
|
|
50
|
+
"import": "./dist/index.js"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"files": [
|
|
54
|
+
"dist",
|
|
55
|
+
"README.md",
|
|
56
|
+
"LICENSE",
|
|
57
|
+
"docs"
|
|
58
|
+
],
|
|
59
|
+
"sideEffects": false
|
|
60
|
+
}
|