@atom.io/template-preact-svg-editor 0.0.93 → 0.1.1
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/CHANGELOG.md +20 -0
- package/COLLABORATION.md +132 -0
- package/README.md +43 -10
- package/eslint.config.ts +1 -1
- package/package.json +30 -16
- package/src/BezierPlayground.tsx +179 -320
- package/src/preact-logo.ts +155 -0
- package/src/svg-contour.test.ts +89 -0
- package/src/svg-contour.ts +579 -0
- package/src/svg-convergence.test.ts +264 -0
- package/src/svg-convergence.ts +566 -0
- package/src/svg-domain-realtime.test.ts +369 -0
- package/src/svg-domain.test.ts +618 -0
- package/src/svg-domain.ts +939 -0
- package/src/svg-editor-state.test.ts +401 -0
- package/src/svg-editor-state.ts +1102 -0
- package/vite.config.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atom.io/template-preact-svg-editor
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- bb1d8de: Expose reusable contour, convergence, Domain, and editor-model modules for collaborative consumers while retaining the local Bezier editor. Harden subpath reordering against selective-undo holes. Report rejection using each contour edit's own submission receipt so another edit or accepted broadcast cannot overwrite its outcome.
|
|
8
|
+
|
|
9
|
+
Use the standalone `@atom.io/react`, `@atom.io/realtime`, and `@atom.io/eslint-plugin` packages. Build with TypeScript 7 while providing TypeScript 6 for ESLint's compiler API. Pin dprint 0.64.1 to distrust the compromised eMudhra certificates when downloading formatter plugins.
|
|
10
|
+
- Updated dependencies [bb1d8de]
|
|
11
|
+
- Updated dependencies [aa30b42]
|
|
12
|
+
- Updated dependencies [bb1d8de]
|
|
13
|
+
- atom.io@0.54.0
|
|
14
|
+
- @atom.io/realtime@0.1.0
|
|
15
|
+
- @atom.io/react@0.1.0
|
|
16
|
+
|
|
17
|
+
## 0.1.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- 6f1c669: Upgrade the SVG editor template from Preact 10.29.8 to Preact 11.0.0. Newly generated projects use Preact 11, including its breaking changes.
|
|
22
|
+
|
|
3
23
|
## 0.0.93
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/COLLABORATION.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Collaborative SVG Model Decisions
|
|
2
|
+
|
|
3
|
+
This template is the model-level fixture beneath Atom.io's collaborative vector
|
|
4
|
+
design vertical. The same ordinary atoms, families, selectors, and transactions
|
|
5
|
+
remain useful in a local editor and are now registered directly in a public
|
|
6
|
+
Mosaic Domain.
|
|
7
|
+
|
|
8
|
+
## Durable Shape
|
|
9
|
+
|
|
10
|
+
Path order, path entities, subpath order, subpath entities, nodes, and edges are
|
|
11
|
+
separate ordinary Atom.io states. Drawing is a selector projection. There is no
|
|
12
|
+
SVG registry in the renderer or in realtime core.
|
|
13
|
+
|
|
14
|
+
Order members use rational ranks and immutable, idempotent operations. Concurrent
|
|
15
|
+
placements at the same rank use stable entry identity as their tie-breaker.
|
|
16
|
+
Geometry and entity members use deterministic last-operation-wins registers.
|
|
17
|
+
Both reducers are independent of delivery order, reject operation-ID collisions,
|
|
18
|
+
and publish strict Zod schemas for the future MOS-11 member-model hook.
|
|
19
|
+
Register receipts remain in the fixture state so that reuse of a superseded
|
|
20
|
+
operation ID still fails closed regardless of delivery order. The reducers and
|
|
21
|
+
their Standard-Schema operation boundaries register directly with the public
|
|
22
|
+
Domain member-model API. Bounding retained receipts is deliberately reserved
|
|
23
|
+
for MOS-16 model-aware compaction.
|
|
24
|
+
|
|
25
|
+
The local structural operations are transactions. Import validates the complete
|
|
26
|
+
fixture before writing. Insert, delete, split, and reorder update every required
|
|
27
|
+
member and its order state within one observable settlement. The invariant
|
|
28
|
+
selector reports duplicate references, absent entities, wrong ownership, absent
|
|
29
|
+
node or edge registers, and invalid close-node pairs.
|
|
30
|
+
|
|
31
|
+
## Gesture and Presence Boundary
|
|
32
|
+
|
|
33
|
+
One pointer-down creates one actor/session-scoped gesture identity backed by a
|
|
34
|
+
logical clock. All member operations produced by that gesture derive stable,
|
|
35
|
+
totally ordered operation identities from it.
|
|
36
|
+
|
|
37
|
+
Pointer moves update only ephemeral presence in SVG document coordinates. The
|
|
38
|
+
ordinary drawing selector projects that preview for immediate feedback. Pointer-up
|
|
39
|
+
coalesces the entire drag into one durable geometry transaction; cancellation
|
|
40
|
+
drops the presence and writes nothing durable. Rejection still releases local
|
|
41
|
+
pointer and presence state. A disconnect can therefore expire the preview rather
|
|
42
|
+
than leaving partially committed geometry.
|
|
43
|
+
|
|
44
|
+
DOM references, the actual pointer-capture owner, active drag, zoom, pan,
|
|
45
|
+
selection, and workspace state have explicit local atoms. Presence is keyed by
|
|
46
|
+
logical actor and session, so concurrent sessions for one identity cannot
|
|
47
|
+
overwrite or clear each other. It carries a logical resource target and
|
|
48
|
+
coordinates, never a DOM identity or client viewport coordinate.
|
|
49
|
+
|
|
50
|
+
## Why This Takes Its Own Path
|
|
51
|
+
|
|
52
|
+
The public Mosaic Domain contract classifies and addresses members, and its
|
|
53
|
+
atomic heterogeneous batches invoke registered per-member convergence models.
|
|
54
|
+
This fixture plugs synchronous pure reducers and Standard-Schema-compatible
|
|
55
|
+
operation schemas into those public seams without inventing a private batch
|
|
56
|
+
envelope or registration system.
|
|
57
|
+
|
|
58
|
+
The current `OList` transceiver is intentionally not used for collaborative
|
|
59
|
+
ordering. Its index-based mutations are useful locally but do not by themselves
|
|
60
|
+
converge when concurrent operations arrive in different orders. Rational order
|
|
61
|
+
operations make the required contention behavior executable while remaining
|
|
62
|
+
ordinary atom values.
|
|
63
|
+
|
|
64
|
+
## Domain Batches and Observation
|
|
65
|
+
|
|
66
|
+
`svg-domain.ts` registers path order, paths, subpath order, subpaths, nodes, and
|
|
67
|
+
edges as durable Domain members with their public value models. Import, insert,
|
|
68
|
+
delete, split, reorder, and coalesced geometry commits plan explicit public
|
|
69
|
+
member operations and submit one heterogeneous batch carrying the stable gesture
|
|
70
|
+
ID. The application does not maintain a parallel registry.
|
|
71
|
+
|
|
72
|
+
Complete preflight precedes a single Store settlement. A rejected final member
|
|
73
|
+
therefore rolls back the whole optimistic gesture, and the invariant selector
|
|
74
|
+
never observes an accepted subpath order entry without its entity, node, and
|
|
75
|
+
edge. Duplicate delivery is idempotent. Offline work remains a complete pending
|
|
76
|
+
batch and replays after recovery.
|
|
77
|
+
|
|
78
|
+
Independent node families settle independently. Same-node register operations
|
|
79
|
+
retain immutable receipts and choose by stable operation identity, so arrival
|
|
80
|
+
order and a durable mutex do not affect the result.
|
|
81
|
+
|
|
82
|
+
## Selective Compensation
|
|
83
|
+
|
|
84
|
+
Undo does not rewind an Atom.io timeline. Each reducer can accept a compensation
|
|
85
|
+
receipt naming exact earlier operation IDs to hide. The editor records only its
|
|
86
|
+
own successfully submitted gestures and appends all receipts for one undo in one
|
|
87
|
+
new batch. Later foreign operations remain candidates and therefore remain
|
|
88
|
+
visible.
|
|
89
|
+
|
|
90
|
+
Every Domain operation also carries its claimed actor. The member model compares
|
|
91
|
+
that actor with authenticated batch context and permits compensation targets only
|
|
92
|
+
when their retained receipt belongs to the same actor. A client cannot construct
|
|
93
|
+
a compensating batch that hides another participant's work.
|
|
94
|
+
|
|
95
|
+
## Generic Presence Innovation
|
|
96
|
+
|
|
97
|
+
MOS-11 supplied durable batching but no public ephemeral controller. This work
|
|
98
|
+
adds a generic Mosaic Domain presence protocol, client, server, and Socket.IO
|
|
99
|
+
adapter rather than hiding an SVG-specific event channel in the template.
|
|
100
|
+
|
|
101
|
+
Presence addresses public ephemeral members and passes their Standard Schema
|
|
102
|
+
boundary. The server binds authorship to the authenticated actor and session,
|
|
103
|
+
requires a monotonically increasing session sequence, and retains cleared
|
|
104
|
+
session cursors so a delayed update cannot resurrect a preview. One physical
|
|
105
|
+
presence address has one live actor-session owner; separate sessions for one
|
|
106
|
+
actor use separate family keys and cannot overwrite or clear each other.
|
|
107
|
+
|
|
108
|
+
Payload size, update rate, live session count, client queue, server queue, and
|
|
109
|
+
socket request queue are bounded. Disconnect and expiry publish monotonic clear
|
|
110
|
+
envelopes, do not append durable history, and expose cleanup subscriptions plus
|
|
111
|
+
an explicit quiescent-session retirement hook for future residency work.
|
|
112
|
+
|
|
113
|
+
The SVG projection carries only logical target identity and document
|
|
114
|
+
coordinates. DOM nodes, pointer capture, active drag, viewport, zoom, and
|
|
115
|
+
workspace state remain local atoms. Pointer moves update ephemeral presence;
|
|
116
|
+
pointer-up contributes at most one durable geometry operation.
|
|
117
|
+
Presence publication is advisory: a transient transport failure updates the
|
|
118
|
+
controller's status but never aborts a local drag or its durable commit. Disposing
|
|
119
|
+
the controller immediately removes every ephemeral projection it owns, so a
|
|
120
|
+
recreated client cannot briefly display a cursor or preview from its predecessor.
|
|
121
|
+
|
|
122
|
+
## Executable Conformance and Remaining Gates
|
|
123
|
+
|
|
124
|
+
The local suite covers every structural planner, settled invariants, independent
|
|
125
|
+
and contended geometry, malicious foreign compensation, whole-batch rejection,
|
|
126
|
+
offline replay, and selective undo. The `@atom.io/realtime/testing` suite drives
|
|
127
|
+
real Socket.IO clients through the public Domain, server, client, batch, and
|
|
128
|
+
presence seams. It covers duplicate delivery, final-member rejection, offline
|
|
129
|
+
replay, same-node contention, and disconnect during drag.
|
|
130
|
+
|
|
131
|
+
Partial residency, checkpoint recovery, and process restart remain explicitly
|
|
132
|
+
gated on MOS-12 and MOS-13. The canonical multiplayer renderer remains MOS-23.
|
package/README.md
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
# Preact SVG Editor
|
|
2
2
|
|
|
3
|
-
A Preact + Vite starter that uses `atom.io` to model an editable SVG path.
|
|
3
|
+
A Preact + Vite starter that uses `atom.io` to model an editable SVG path. Its
|
|
4
|
+
state model is also the local conformance foundation for collaborative vector
|
|
5
|
+
editing with Mosaic Domains.
|
|
4
6
|
|
|
5
7
|
## What It Shows
|
|
6
8
|
|
|
7
|
-
- atom families for
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
9
|
+
- ordinary atoms and atom families for path order, paths, subpath order,
|
|
10
|
+
subpaths, nodes, and edges
|
|
11
|
+
- deterministic sequence and register reducers with strict operation schemas
|
|
12
|
+
- selector families that derive SVG path data from the ordinary state graph
|
|
13
|
+
- atomic transactions for import, insert, delete, split, reorder, and geometry
|
|
14
|
+
gestures
|
|
15
|
+
- public Mosaic Domain registration and heterogeneous batch planners for every
|
|
16
|
+
structural gesture
|
|
17
|
+
- deterministic same-node contention, offline replay, duplicate delivery,
|
|
18
|
+
whole-batch rejection, and actor-selective compensation
|
|
19
|
+
- actor/session-scoped logical-coordinate drag presence with one durable commit
|
|
20
|
+
at pointer-up
|
|
21
|
+
- explicit local-only workspace, viewport, DOM reference, pointer capture, and
|
|
22
|
+
active-drag state
|
|
23
|
+
- `useAtomicRef` for keeping the local SVG element available to atom.io logic
|
|
11
24
|
|
|
12
25
|
## Run It
|
|
13
26
|
|
|
@@ -26,14 +39,34 @@ npm run preview
|
|
|
26
39
|
|
|
27
40
|
Run `npm run lint` before committing. It enforces ESLint, type-aware Oxlint, React hook call-order correctness, and TypeScript with zero warnings. Run `npm run fmt:check` in CI and `npm run fmt` to apply the pinned dprint configuration locally.
|
|
28
41
|
|
|
42
|
+
Run the model conformance tests:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
npm test
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quality Checks
|
|
49
|
+
|
|
50
|
+
Run `npm run lint` before committing. It enforces ESLint, type-aware Oxlint, and TypeScript with zero warnings. Run `npm run fmt:check` in CI and `npm run fmt` to apply the pinned dprint configuration locally.
|
|
51
|
+
|
|
29
52
|
## Where To Look
|
|
30
53
|
|
|
31
54
|
- `src/index.tsx`: Preact entry point and resource links.
|
|
32
|
-
- `src/
|
|
55
|
+
- `src/svg-convergence.ts`: pure convergent sequence/register schemas and
|
|
56
|
+
reducers.
|
|
57
|
+
- `src/svg-editor-state.ts`: the durable graph, local/ephemeral boundaries,
|
|
58
|
+
selectors, transactions, and gesture identities.
|
|
59
|
+
- `src/svg-domain.ts`: public Domain registration, structural batch planning,
|
|
60
|
+
presence projection, and actor-selective compensating batches.
|
|
61
|
+
- `src/BezierPlayground.tsx`: the Preact renderer and pointer adapter.
|
|
62
|
+
- `COLLABORATION.md`: correctness decisions, innovations, and remaining
|
|
63
|
+
persistence gates.
|
|
33
64
|
- `src/style.css`: layout and editor styling.
|
|
34
65
|
|
|
35
|
-
##
|
|
66
|
+
## Realtime Boundary
|
|
36
67
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
-
|
|
68
|
+
The reusable model fixture now synchronizes through public Mosaic Domain batch
|
|
69
|
+
and presence APIs. The visible playground intentionally remains a small local
|
|
70
|
+
renderer; MOS-23 consumes this fixture in the canonical realtime vector-editor
|
|
71
|
+
template. Partial residency, checkpoints, and process restart remain gated on
|
|
72
|
+
MOS-12 and MOS-13 rather than being simulated by application state.
|
package/eslint.config.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import AtomIOPlugin from "@atom.io/eslint-plugin"
|
|
1
2
|
import { default as TypeScriptPlugin } from "@typescript-eslint/eslint-plugin"
|
|
2
3
|
import * as parser from "@typescript-eslint/parser"
|
|
3
|
-
import AtomIOPlugin from "atom.io/eslint-plugin"
|
|
4
4
|
import type { Linter } from "eslint"
|
|
5
5
|
import * as ImportPlugin from "eslint-plugin-import-x"
|
|
6
6
|
import { default as SimpleImportSortPlugin } from "eslint-plugin-simple-import-sort"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atom.io/template-preact-svg-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/jeremybanka/atom.io.git",
|
|
@@ -8,28 +8,40 @@
|
|
|
8
8
|
},
|
|
9
9
|
"license": "Apache-2.0",
|
|
10
10
|
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
"./contour": "./src/svg-contour.ts",
|
|
13
|
+
"./convergence": "./src/svg-convergence.ts",
|
|
14
|
+
"./domain": "./src/svg-domain.ts",
|
|
15
|
+
"./model": "./src/svg-editor-state.ts"
|
|
16
|
+
},
|
|
11
17
|
"dependencies": {
|
|
12
|
-
"atom.io": "0.
|
|
13
|
-
"
|
|
18
|
+
"@atom.io/react": "0.1.0",
|
|
19
|
+
"@atom.io/realtime": "0.1.0",
|
|
20
|
+
"atom.io": "0.54.0",
|
|
21
|
+
"preact": "11.0.1",
|
|
14
22
|
"react": "npm:@preact/compat@18.3.2",
|
|
15
|
-
"react-dom": "npm:@preact/compat@18.3.2"
|
|
23
|
+
"react-dom": "npm:@preact/compat@18.3.2",
|
|
24
|
+
"zod": "4.6.7"
|
|
16
25
|
},
|
|
17
26
|
"devDependencies": {
|
|
18
|
-
"@
|
|
19
|
-
"@dprint/
|
|
20
|
-
"@dprint/
|
|
27
|
+
"@atom.io/eslint-plugin": "0.1.0",
|
|
28
|
+
"@dprint/json": "0.25.2",
|
|
29
|
+
"@dprint/markdown": "0.28.0",
|
|
30
|
+
"@dprint/oxc": "0.47.0",
|
|
21
31
|
"@preact/preset-vite": "2.10.6",
|
|
22
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
23
|
-
"@typescript-eslint/parser": "8.
|
|
24
|
-
"
|
|
32
|
+
"@typescript-eslint/eslint-plugin": "8.72.0",
|
|
33
|
+
"@typescript-eslint/parser": "8.72.0",
|
|
34
|
+
"@typescript/native": "npm:typescript@7.0.2",
|
|
35
|
+
"dprint": "0.64.1",
|
|
25
36
|
"dprint-plugin-malva": "0.16.0",
|
|
26
|
-
"eslint": "10.
|
|
37
|
+
"eslint": "10.13.0",
|
|
27
38
|
"eslint-plugin-import-x": "4.17.1",
|
|
28
39
|
"eslint-plugin-simple-import-sort": "14.0.0",
|
|
29
|
-
"oxlint": "1.
|
|
30
|
-
"oxlint-tsgolint": "7.0.
|
|
31
|
-
"typescript": "
|
|
32
|
-
"vite": "8.3.
|
|
40
|
+
"oxlint": "1.89.0",
|
|
41
|
+
"oxlint-tsgolint": "7.0.2004",
|
|
42
|
+
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
43
|
+
"vite": "8.3.5",
|
|
44
|
+
"vitest": "5.0.5"
|
|
33
45
|
},
|
|
34
46
|
"publishConfig": {
|
|
35
47
|
"access": "public"
|
|
@@ -43,6 +55,8 @@
|
|
|
43
55
|
"lint:eslint": "eslint --max-warnings 0 .",
|
|
44
56
|
"lint:oxlint": "oxlint --deny-warnings .",
|
|
45
57
|
"lint:types": "tsc -b",
|
|
46
|
-
"preview": "vite preview"
|
|
58
|
+
"preview": "vite preview",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:once": "vitest run"
|
|
47
61
|
}
|
|
48
62
|
}
|