stylegallery 0.1.4 → 0.1.7
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/DOMAINS.md +11 -9
- package/GOVERNANCE.md +8 -2
- package/LICENSE +28 -0
- package/LICENSE-DOCS +42 -0
- package/NOTICE +38 -0
- package/README.md +43 -6
- package/consumer-reference/agent-native/README.md +7 -7
- package/consumer-reference/agent-native/v2/admission-policy.json +241 -1
- package/consumer-reference/agent-native/v2/material-registry.json +1 -1
- package/consumer-reference/agent-native/v2/schema/admission-policy.schema.json +2 -2
- package/design-engineering/component-contract.md +114 -0
- package/design-engineering/decision-tree.md +70 -0
- package/design-engineering/index.md +60 -2
- package/design-engineering/loading-and-feedback.md +91 -0
- package/design-engineering/native-interaction-contracts.md +94 -0
- package/design-engineering/state-management/decision-tree.md +60 -0
- package/design-engineering/state-management/index.md +61 -0
- package/design-engineering/state-management/patterns/derived-state.md +85 -0
- package/design-engineering/state-management/patterns/draft-and-baseline.md +86 -0
- package/design-engineering/state-management/patterns/id-selection.md +85 -0
- package/design-engineering/state-management/patterns/identity-reset.md +89 -0
- package/design-engineering/state-management/patterns/latest-request-wins.md +94 -0
- package/design-engineering/state-management/patterns/optimistic-overlay.md +98 -0
- package/design-engineering/state-management/patterns/single-flight.md +92 -0
- package/design-engineering/state-management/patterns/single-owner.md +89 -0
- package/design-engineering/state-management/patterns/submitted-snapshot.md +107 -0
- package/design-engineering/state-management/patterns/unsaved-navigation.md +100 -0
- package/design-engineering/state-management/patterns/url-state.md +96 -0
- package/design-engineering/state-management/patterns/versioned-restore.md +95 -0
- package/design-engineering/state-management/recipes/delete-undo.md +65 -0
- package/design-engineering/state-management/recipes/index.md +64 -0
- package/design-engineering/state-management/recipes/multi-step-form.md +65 -0
- package/design-engineering/state-management/recipes/search-detail.md +65 -0
- package/design-engineering/state-management/recipes/settings-save.md +64 -0
- package/design-engineering/state-management/state-brief.md +83 -0
- package/design-engineering/state-management/verification.md +65 -0
- package/design-engineering/text-input-and-internationalization.md +91 -0
- package/design-engineering/worked-examples.md +129 -0
- package/design-terminology/comparison-workflow.md +98 -0
- package/design-terminology/conflict-cases.md +87 -55
- package/design-terminology/index.md +19 -5
- package/design-terminology/interaction-semantics.md +87 -0
- package/design-terminology/relation-types.md +12 -6
- package/design-terminology/source-vocabularies.md +33 -3
- package/design-terminology/token-semantics.md +90 -0
- package/design-terminology/typography-semantics.md +86 -0
- package/game-ui/decision-tree.md +81 -0
- package/game-ui/index.md +11 -1
- package/game-ui/screen-recipes.md +101 -0
- package/game-ui/verification-workflow.md +100 -0
- package/index.md +8 -0
- package/log.md +67 -0
- package/motion/accessible-motion.md +90 -0
- package/motion/decision-tree.md +70 -0
- package/motion/index.md +21 -2
- package/motion/interaction-recipes.md +170 -0
- package/motion/interruption-and-retargeting.md +90 -0
- package/motion/motion-brief.md +125 -0
- package/motion/observed-choreography.md +73 -0
- package/motion/rendering-and-performance.md +89 -0
- package/motion/review-workflow.md +8 -0
- package/motion/vocabulary.md +2 -2
- package/package.json +74 -8
- package/platform-guides/adaptation-workflow.md +76 -0
- package/platform-guides/adaptive-navigation.md +85 -0
- package/platform-guides/android-interaction.md +74 -0
- package/platform-guides/apple-interaction.md +9 -1
- package/platform-guides/compatibility-matrix.md +97 -0
- package/platform-guides/index.md +19 -2
- package/platform-guides/input-and-focus.md +91 -0
- package/platform-guides/preferences-and-accessibility.md +90 -0
- package/platform-guides/windows-interaction.md +75 -0
- package/recipes/homepage.md +8 -0
- package/scripts/compiler/README.md +112 -0
- package/scripts/compiler/cli.mjs +51 -0
- package/scripts/compiler/mcp.mjs +53 -0
- package/scripts/compiler/operations.mjs +70 -0
- package/scripts/compiler/runtime.mjs +156 -0
- package/scripts/sg-entry.mjs +20 -0
- package/scripts/sg-server.mjs +20 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Single Owner And Controlled Inputs
|
|
4
|
+
description: Keep one authoritative value when several controls edit the same setting.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Single Owner And Controlled Inputs
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Keep one authoritative value when several controls edit the same setting. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use when sibling or nested controls must agree immediately. Keep a private disclosure local when no other surface needs its value. Choose the nearest owner that survives every participating control.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The owner stores `value`; controls receive it and emit an intent. Temporary text composition may stay local, but must have an explicit commit/reset boundary. Owner validation can reject an intent without creating a second accepted value.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Control proposes an allowed value | Owner replaces value | All readers observe the same accepted value |
|
|
29
|
+
| Control proposes an invalid value | Unchanged | Return rejection; do not pretend the value committed |
|
|
30
|
+
| Owner resets externally | New owner value | Every controlled reader reflects reset |
|
|
31
|
+
|
|
32
|
+
### Minimal Executable Example
|
|
33
|
+
|
|
34
|
+
Run this standalone JavaScript block with Node.js 22 or newer, or run all pattern examples from a repository checkout with `npm run test:state-management`. The assertions exercise the local model, not a browser or backend.
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import assert from "node:assert/strict";
|
|
38
|
+
let value = "compact";
|
|
39
|
+
function propose(next) {
|
|
40
|
+
if (!["compact", "comfortable"].includes(next)) return false;
|
|
41
|
+
value = next;
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
const toolbar = { read: () => value, change: propose };
|
|
45
|
+
const settings = { read: () => value, change: propose };
|
|
46
|
+
assert.equal(toolbar.change("comfortable"), true);
|
|
47
|
+
assert.equal(settings.read(), "comfortable");
|
|
48
|
+
assert.equal(settings.change("invalid"), false);
|
|
49
|
+
assert.equal(toolbar.read(), "comfortable");
|
|
50
|
+
value = "compact";
|
|
51
|
+
assert.equal(settings.read(), "compact");
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### What Breaks If Removed
|
|
55
|
+
|
|
56
|
+
If each control copies the initial value into its own accepted state, changing the toolbar leaves settings stale. Synchronizing both copies with reciprocal callbacks introduces a second ordering problem.
|
|
57
|
+
|
|
58
|
+
### Composition And Substitution
|
|
59
|
+
|
|
60
|
+
Compose with [derived state](derived-state.md) for summaries and [identity reset](identity-reset.md) for account changes. A framework context or store can transport this owner; it does not decide who owns the value.
|
|
61
|
+
|
|
62
|
+
## Opinionated Guidance
|
|
63
|
+
|
|
64
|
+
Name the write API as an intent when the owner may reject or normalize it. Distinguish a local editing buffer from the accepted value in component inputs.
|
|
65
|
+
|
|
66
|
+
## Platform-Specific Guidance
|
|
67
|
+
|
|
68
|
+
Native controls still need accessible names and correct value semantics. Preserve IME composition when adapting text inputs; do not normalize every keystroke without an input contract.
|
|
69
|
+
|
|
70
|
+
## Unsupported Absolutes
|
|
71
|
+
|
|
72
|
+
A shared owner does not require an application-wide store or prove efficient subscriptions.
|
|
73
|
+
|
|
74
|
+
## Verification Contract
|
|
75
|
+
|
|
76
|
+
- Edit from either control, then reset from the parent; both readers must agree.
|
|
77
|
+
- Reject an invalid intent and verify the UI exposes the rejection.
|
|
78
|
+
- Remove and recreate one reader; it must receive the current value.
|
|
79
|
+
|
|
80
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
81
|
+
|
|
82
|
+
## Source, License, And Attribution
|
|
83
|
+
|
|
84
|
+
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
|
|
85
|
+
|
|
86
|
+
## IA Navigation
|
|
87
|
+
|
|
88
|
+
Parent: [State Management](../index.md).
|
|
89
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Submitted Snapshot And Save Acknowledgement
|
|
4
|
+
description: Keep later edits dirty when an earlier submitted snapshot finishes saving.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Submitted Snapshot And Save Acknowledgement
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Keep later edits dirty when an earlier submitted snapshot finishes saving. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use whenever editing can continue during a save. If the UI locks editing, document that constraint but still correlate completions to the active operation.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The form owns draft and baseline; an active operation owns a copied snapshot and request ID. This string example allows one write in flight and assumes the server returns the same accepted value. Real adapters must define normalization and revision conflicts.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Submit while idle | Active snapshot and request ID | Persist exactly that snapshot |
|
|
29
|
+
| Edit while saving | New draft, same active operation | Do not mutate submitted data |
|
|
30
|
+
| Matching success | Baseline becomes acknowledged snapshot | Dirty compares current draft to new baseline |
|
|
31
|
+
| Matching failure | Active cleared, error retained | Keep current draft |
|
|
32
|
+
| Stale completion | Unchanged | Never commit another operation's result |
|
|
33
|
+
|
|
34
|
+
### Minimal Executable Example
|
|
35
|
+
|
|
36
|
+
Run this standalone JavaScript block with Node.js 22 or newer, or run all pattern examples from a repository checkout with `npm run test:state-management`. The assertions exercise the local model, not a browser or backend.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import assert from "node:assert/strict";
|
|
40
|
+
let draft = "A", baseline = "Original", active = null, serial = 0, error = null;
|
|
41
|
+
function submit() {
|
|
42
|
+
if (active) return null;
|
|
43
|
+
error = null;
|
|
44
|
+
active = { id: ++serial, snapshot: draft };
|
|
45
|
+
return { ...active };
|
|
46
|
+
}
|
|
47
|
+
function settle(id, ok, message = "Save failed") {
|
|
48
|
+
if (active?.id !== id) return;
|
|
49
|
+
if (ok) baseline = active.snapshot;
|
|
50
|
+
else error = message;
|
|
51
|
+
active = null;
|
|
52
|
+
}
|
|
53
|
+
const first = submit();
|
|
54
|
+
draft = "B";
|
|
55
|
+
assert.equal(submit(), null);
|
|
56
|
+
settle(first.id, true);
|
|
57
|
+
assert.equal(baseline, "A");
|
|
58
|
+
assert.equal(draft, "B");
|
|
59
|
+
assert.equal(draft !== baseline, true);
|
|
60
|
+
const second = submit();
|
|
61
|
+
settle(first.id, true);
|
|
62
|
+
assert.equal(active.id, second.id);
|
|
63
|
+
settle(second.id, false);
|
|
64
|
+
assert.equal(draft, "B");
|
|
65
|
+
assert.equal(error, "Save failed");
|
|
66
|
+
const retry = submit();
|
|
67
|
+
assert.equal(error, null);
|
|
68
|
+
settle(retry.id, true);
|
|
69
|
+
assert.equal(draft, baseline);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### What Breaks If Removed
|
|
73
|
+
|
|
74
|
+
If success assigns the current draft to baseline, saving A then editing B marks unsent B as saved. If the request holds a mutable object reference, editing B can also mutate the supposed A snapshot.
|
|
75
|
+
|
|
76
|
+
### Composition And Substitution
|
|
77
|
+
|
|
78
|
+
Combines [draft/baseline](draft-and-baseline.md) and [single flight](single-flight.md). This is the reusable core of the existing [save contract](../../component-contract.md#worked-contract-save-action).
|
|
79
|
+
|
|
80
|
+
## Opinionated Guidance
|
|
81
|
+
|
|
82
|
+
For objects, capture an appropriate immutable copy. Adopt a server-normalized result into the draft only if no later edit would be overwritten; otherwise reconcile visibly.
|
|
83
|
+
|
|
84
|
+
## Platform-Specific Guidance
|
|
85
|
+
|
|
86
|
+
Client request abort does not roll back a remote write. On transport uncertainty, reconcile with the server before claiming a retry is safe.
|
|
87
|
+
|
|
88
|
+
## Unsupported Absolutes
|
|
89
|
+
|
|
90
|
+
Client request IDs are not server idempotency keys or optimistic concurrency revisions.
|
|
91
|
+
|
|
92
|
+
## Verification Contract
|
|
93
|
+
|
|
94
|
+
- Submit A, edit B, acknowledge A; baseline A and dirty B must remain.
|
|
95
|
+
- Fail then retry; inputs survive and the new operation has its own identity.
|
|
96
|
+
- Deliver the old completion during a new save; it must not clear the new request.
|
|
97
|
+
|
|
98
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
99
|
+
|
|
100
|
+
## Source, License, And Attribution
|
|
101
|
+
|
|
102
|
+
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
|
|
103
|
+
|
|
104
|
+
## IA Navigation
|
|
105
|
+
|
|
106
|
+
Parent: [State Management](../index.md).
|
|
107
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Unsaved Changes And Navigation
|
|
4
|
+
description: Make leaving an edited screen an explicit decision without losing the current draft.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Unsaved Changes And Navigation
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Make leaving an edited screen an explicit decision without losing the current draft. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use when route changes can discard meaningful user work. Do not interrupt navigation for harmless transient selection or derived values.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The form owns dirty; the router integration owns a pending destination and guard status. The confirmation owns a decision, not a second copy of form data. Save-and-leave must recheck dirty after acknowledgement.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Navigate while clean | Destination committed | Leave normally |
|
|
29
|
+
| Navigate while dirty | Decision pending | Retain current screen and destination |
|
|
30
|
+
| Cancel decision | Pending cleared | Stay and return focus |
|
|
31
|
+
| Discard decision | Destination committed | Explicitly abandon draft |
|
|
32
|
+
| Save fails or later edits remain | Stay | Preserve draft and offer recovery |
|
|
33
|
+
|
|
34
|
+
### Minimal Executable Example
|
|
35
|
+
|
|
36
|
+
Run this standalone JavaScript block with Node.js 22 or newer, or run all pattern examples from a repository checkout with `npm run test:state-management`. The assertions exercise the local model, not a browser or backend.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import assert from "node:assert/strict";
|
|
40
|
+
let dirty = true, pending = null, location = "editor";
|
|
41
|
+
function navigate(to) {
|
|
42
|
+
if (dirty) pending = to;
|
|
43
|
+
else location = to;
|
|
44
|
+
}
|
|
45
|
+
function decide(choice) {
|
|
46
|
+
if (choice === "cancel") pending = null;
|
|
47
|
+
if (choice === "discard" && pending !== null) {
|
|
48
|
+
dirty = false;
|
|
49
|
+
location = pending;
|
|
50
|
+
pending = null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
navigate("list");
|
|
54
|
+
decide("cancel");
|
|
55
|
+
assert.equal(location, "editor");
|
|
56
|
+
assert.equal(dirty, true);
|
|
57
|
+
navigate("list");
|
|
58
|
+
decide("discard");
|
|
59
|
+
assert.equal(location, "list");
|
|
60
|
+
assert.equal(pending, null);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### What Breaks If Removed
|
|
64
|
+
|
|
65
|
+
If route mutation happens before the guard, the form may already be destroyed when Cancel runs. If any save success releases navigation, later unsaved edits can still be lost.
|
|
66
|
+
|
|
67
|
+
### Composition And Substitution
|
|
68
|
+
|
|
69
|
+
Use [submitted snapshot](submitted-snapshot.md) for Save-and-leave and [URL state](url-state.md) for committed destinations. A pending destination is not a committed URL.
|
|
70
|
+
|
|
71
|
+
## Opinionated Guidance
|
|
72
|
+
|
|
73
|
+
Declare what a second navigation attempt does while confirmation is open: this model replaces the destination with the latest attempt. Verify the displayed decision matches it.
|
|
74
|
+
|
|
75
|
+
## Platform-Specific Guidance
|
|
76
|
+
|
|
77
|
+
In-app routing and document unload have different capabilities. Browser unload prompts are constrained and unreliable as a sole recovery strategy; use optional draft persistence when needed. Verify keyboard focus entry/return for the confirmation.
|
|
78
|
+
|
|
79
|
+
Platform reference: [MDN API documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event), checked 2026-09-16. This supports the named browser boundary; the model and product policy remain local synthesis.
|
|
80
|
+
|
|
81
|
+
## Unsupported Absolutes
|
|
82
|
+
|
|
83
|
+
An in-memory guard cannot guarantee preservation after process termination or device failure.
|
|
84
|
+
|
|
85
|
+
## Verification Contract
|
|
86
|
+
|
|
87
|
+
- Cancel a guarded route change; values and focus return to the editor.
|
|
88
|
+
- Attempt another destination while the decision is open; apply the declared policy.
|
|
89
|
+
- Save A, edit B, then acknowledge A; do not leave with dirty B.
|
|
90
|
+
|
|
91
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
92
|
+
|
|
93
|
+
## Source, License, And Attribution
|
|
94
|
+
|
|
95
|
+
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
|
|
96
|
+
|
|
97
|
+
## IA Navigation
|
|
98
|
+
|
|
99
|
+
Parent: [State Management](../index.md).
|
|
100
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: URL State And History
|
|
4
|
+
description: Keep shareable screen state consistent across links, refresh, and browser history.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# URL State And History
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Keep shareable screen state consistent across links, refresh, and browser history. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use for committed search, filters, pagination, and selected IDs that should be shareable. Keep secrets, sensitive drafts, and hover state out of URLs.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The route owns committed query state; a text field may own an uncommitted buffer. Parsing supplies validated defaults. User commits write URL parameters; history navigation reads them without writing a new entry.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Open or history traversal | Parsed route state | Render without another push |
|
|
29
|
+
| Commit filter | New route; page reset | Push a meaningful navigation entry |
|
|
30
|
+
| Normalize invalid input | Validated defaults | Replace only under declared canonicalization policy |
|
|
31
|
+
|
|
32
|
+
### Minimal Executable Example
|
|
33
|
+
|
|
34
|
+
Run this standalone JavaScript block with Node.js 22 or newer, or run all pattern examples from a repository checkout with `npm run test:state-management`. The assertions exercise the local model, not a browser or backend.
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import assert from "node:assert/strict";
|
|
38
|
+
function readRoute(href) {
|
|
39
|
+
const u = new URL(href);
|
|
40
|
+
const raw = u.searchParams.get("page") ?? "1";
|
|
41
|
+
const n = /^\d+$/.test(raw) ? Number(raw) : NaN;
|
|
42
|
+
return { q: u.searchParams.get("q") ?? "", page: Number.isSafeInteger(n) && n > 0 ? n : 1 };
|
|
43
|
+
}
|
|
44
|
+
function commitQuery(href, q) {
|
|
45
|
+
const u = new URL(href);
|
|
46
|
+
if (q) u.searchParams.set("q", q); else u.searchParams.delete("q");
|
|
47
|
+
u.searchParams.delete("page");
|
|
48
|
+
return u.href;
|
|
49
|
+
}
|
|
50
|
+
const original = "https://example.test/items?q=A&page=3&view=grid#results";
|
|
51
|
+
const changed = commitQuery(original, "B & C");
|
|
52
|
+
assert.deepEqual(readRoute(changed), { q: "B & C", page: 1 });
|
|
53
|
+
assert.equal(new URL(changed).searchParams.get("view"), "grid");
|
|
54
|
+
assert.equal(new URL(changed).hash, "#results");
|
|
55
|
+
assert.deepEqual(readRoute(original), { q: "A", page: 3 }); // Back reads old URL.
|
|
56
|
+
assert.equal(readRoute("https://example.test/?page=Infinity").page, 1);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### What Breaks If Removed
|
|
60
|
+
|
|
61
|
+
Writing a new history entry in response to a history event creates a loop. Keeping the old page after changing the filter can display an apparently empty collection. Rebuilding the URL from scratch can drop unrelated parameters or fragments.
|
|
62
|
+
|
|
63
|
+
### Composition And Substitution
|
|
64
|
+
|
|
65
|
+
Use [latest request wins](latest-request-wins.md) for data reads and [unsaved navigation](unsaved-navigation.md) before committing a destructive route change. Reset local input from history only under the declared editing policy.
|
|
66
|
+
|
|
67
|
+
## Opinionated Guidance
|
|
68
|
+
|
|
69
|
+
Decide push versus replace from meaningful navigation steps. Do not make every keystroke a Back-button stop by accident.
|
|
70
|
+
|
|
71
|
+
## Platform-Specific Guidance
|
|
72
|
+
|
|
73
|
+
Browser adapters must handle popstate and their router's navigation API; the pure URL functions do not install listeners. SSR and client must use the same parser and defaults.
|
|
74
|
+
|
|
75
|
+
Platform reference: [MDN API documentation](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState), checked 2026-09-16. This supports the named browser boundary; the model and product policy remain local synthesis.
|
|
76
|
+
|
|
77
|
+
## Unsupported Absolutes
|
|
78
|
+
|
|
79
|
+
A URL is not a safe persistence medium for private data, nor does parsing prove authorization to access a selected entity.
|
|
80
|
+
|
|
81
|
+
## Verification Contract
|
|
82
|
+
|
|
83
|
+
- Commit query B from page 3; reset to page 1 and preserve unrelated parameters.
|
|
84
|
+
- Back, Forward, reload, and paste a deep link; displayed controls agree with the URL.
|
|
85
|
+
- Reject malformed page values; avoid URL-to-state-to-URL loops.
|
|
86
|
+
|
|
87
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
88
|
+
|
|
89
|
+
## Source, License, And Attribution
|
|
90
|
+
|
|
91
|
+
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
|
|
92
|
+
|
|
93
|
+
## IA Navigation
|
|
94
|
+
|
|
95
|
+
Parent: [State Management](../index.md).
|
|
96
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Versioned And Scoped State Restore
|
|
4
|
+
description: Restore persisted preferences only when their schema and ownership scope are valid.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Versioned And Scoped State Restore
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Restore persisted preferences only when their schema and ownership scope are valid. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use for intentional persistence of non-sensitive preferences or drafts with a declared retention policy. Keep state in memory if cross-session recovery has no user value.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The persistence adapter owns a versioned envelope and scope key. Decoding validates shape and allowed values before applying. This example rejects old versions; migration is a separate explicit function. Current user edits outrank a late restore.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Read valid current-scope record | Restored values | Apply only before later local edits |
|
|
29
|
+
| Malformed, old, or wrong-scope record | Defaults | Preserve current usable state |
|
|
30
|
+
| Write fails | In-memory state retained | Expose persistence failure where recovery matters |
|
|
31
|
+
| Logout or scope change | New scoped state | Do not reuse another account's envelope |
|
|
32
|
+
|
|
33
|
+
### Minimal Executable Example
|
|
34
|
+
|
|
35
|
+
Run this standalone JavaScript block with Node.js 22 or newer, or run all pattern examples from a repository checkout with `npm run test:state-management`. The assertions exercise the local model, not a browser or backend.
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import assert from "node:assert/strict";
|
|
39
|
+
function restore(raw, scope) {
|
|
40
|
+
try {
|
|
41
|
+
const record = JSON.parse(raw);
|
|
42
|
+
if (!record || record.version !== 1 || record.scope !== scope) return "compact";
|
|
43
|
+
return ["compact", "comfortable"].includes(record.density) ? record.density : "compact";
|
|
44
|
+
} catch { return "compact"; }
|
|
45
|
+
}
|
|
46
|
+
const raw = JSON.stringify({ version: 1, scope: "account:A", density: "comfortable" });
|
|
47
|
+
assert.equal(restore(raw, "account:A"), "comfortable");
|
|
48
|
+
assert.equal(restore(raw, "account:B"), "compact");
|
|
49
|
+
assert.equal(restore("{broken", "account:A"), "compact");
|
|
50
|
+
assert.equal(restore(JSON.stringify({ version: 0 }), "account:A"), "compact");
|
|
51
|
+
let editRevision = 0, density = "compact";
|
|
52
|
+
const restoreStartedAt = editRevision;
|
|
53
|
+
density = "comfortable"; editRevision++;
|
|
54
|
+
if (editRevision === restoreStartedAt) density = restore(null, "account:A");
|
|
55
|
+
assert.equal(density, "comfortable");
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### What Breaks If Removed
|
|
59
|
+
|
|
60
|
+
Blind JSON parsing can crash startup. An unscoped storage key leaks settings across accounts. Applying a delayed restore unconditionally overwrites edits made while storage was loading.
|
|
61
|
+
|
|
62
|
+
### Composition And Substitution
|
|
63
|
+
|
|
64
|
+
Use [identity reset](identity-reset.md) for account changes. Persist only source values from [derived state](derived-state.md); do not restore loading flags, request IDs, or obsolete cached errors.
|
|
65
|
+
|
|
66
|
+
## Opinionated Guidance
|
|
67
|
+
|
|
68
|
+
Choose migration, expiry, and multi-tab conflict policies before persisting. A version field without a decoder or migration rule is not a compatibility strategy.
|
|
69
|
+
|
|
70
|
+
## Platform-Specific Guidance
|
|
71
|
+
|
|
72
|
+
Browser storage access and writes can throw or be unavailable; guard the adapter as well as parsing. Server rendering cannot read browser storage. Define hydration fallback and cross-tab event handling separately.
|
|
73
|
+
|
|
74
|
+
Platform reference: [MDN API documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), checked 2026-09-16. This supports the named browser boundary; the model and product policy remain local synthesis.
|
|
75
|
+
|
|
76
|
+
## Unsupported Absolutes
|
|
77
|
+
|
|
78
|
+
Persistence does not guarantee availability, confidentiality, or synchronization across devices.
|
|
79
|
+
|
|
80
|
+
## Verification Contract
|
|
81
|
+
|
|
82
|
+
- Decode corrupt, missing, old-version, and wrong-account records; use valid defaults.
|
|
83
|
+
- Edit before an asynchronous restore finishes; preserve the edit.
|
|
84
|
+
- Simulate unavailable storage and quota failure; keep the screen usable.
|
|
85
|
+
|
|
86
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
87
|
+
|
|
88
|
+
## Source, License, And Attribution
|
|
89
|
+
|
|
90
|
+
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
|
|
91
|
+
|
|
92
|
+
## IA Navigation
|
|
93
|
+
|
|
94
|
+
Parent: [State Management](../index.md).
|
|
95
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Deletion And Supported Undo
|
|
4
|
+
description: Remove the intended entity and provide recovery that matches actual backend capabilities.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Deletion And Supported Undo
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Remove the intended entity and provide recovery that matches actual backend capabilities. This is a consumer interaction composition in Design Engineering. Spatial structure comes from [List Detail](../../../recipes/list-detail.md); this recipe adds no reusable Layout behavior.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
### Selected Pattern Stack
|
|
19
|
+
|
|
20
|
+
[ID selection](../patterns/id-selection.md), [single flight](../patterns/single-flight.md), optionally [optimistic overlay](../patterns/optimistic-overlay.md).
|
|
21
|
+
|
|
22
|
+
### Ownership And Event Flow
|
|
23
|
+
|
|
24
|
+
The collection owner tracks entities by ID. A per-entity deletion operation owns request identity and outcome. Confirmation owns a decision; an undo operation owns a real restore token or an explicitly cancellable pre-commit deletion.
|
|
25
|
+
|
|
26
|
+
Activate → confirm if required → submit deletion → reconcile acknowledgement → recover focus. Offer Undo only when a backend restore or a declared delayed-commit cancellation exists. A UI-only inverse patch cannot undo a committed deletion.
|
|
27
|
+
|
|
28
|
+
### Composition And Substitution
|
|
29
|
+
|
|
30
|
+
Use pending-until-confirmed deletion by default in this recipe. An optimistic overlay is substitutable only with a recovery contract. Confirmation and Undo solve different product decisions and are not interchangeable by appearance.
|
|
31
|
+
|
|
32
|
+
### Acceptance Sequences
|
|
33
|
+
|
|
34
|
+
| Sequence | Expected outcome |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| Cancel confirmation | No deletion effect; return focus to invoker |
|
|
37
|
+
| Fail definitively while filters change | Keep or restore the intended ID without reverting unrelated data |
|
|
38
|
+
| Lose response after submission | Mark outcome uncertain and reconcile before repeating |
|
|
39
|
+
| Delete the last row | Show empty state and move focus to a logical heading |
|
|
40
|
+
| Undo expires or restoration fails | Explain failure and reconcile actual collection state |
|
|
41
|
+
|
|
42
|
+
## Opinionated Guidance
|
|
43
|
+
|
|
44
|
+
Keep the ownership boundaries visible when composing the patterns. One screen can combine these mechanisms without making every value global. Record the rejected alternative and its user-visible cost in the [state brief](../state-brief.md).
|
|
45
|
+
|
|
46
|
+
## Platform-Specific Guidance
|
|
47
|
+
|
|
48
|
+
Restore focus after confirmation and after removal of the invoker. Announce the affected entity and the real undo availability; animation completion must not authorize deletion.
|
|
49
|
+
|
|
50
|
+
## Unsupported Absolutes
|
|
51
|
+
|
|
52
|
+
These acceptance sequences are proposed integration checks, not captured product evidence. Pattern model tests do not prove this entire screen, its backend, or its focus behavior.
|
|
53
|
+
|
|
54
|
+
## Verification Contract
|
|
55
|
+
|
|
56
|
+
Adapt every acceptance row to the consumer and record actual results with the [verification matrix](../verification.md). Include the ordinary successful task and at least one interrupted task. The initial handoff is `consumer_reference: not_applicable` because this fictional recipe selects no consumer profile or conformance record.
|
|
57
|
+
|
|
58
|
+
## Source, License, And Attribution
|
|
59
|
+
|
|
60
|
+
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
|
|
61
|
+
|
|
62
|
+
## IA Navigation
|
|
63
|
+
|
|
64
|
+
Parent: [State Management](index.md).
|
|
65
|
+
Next: [Continue the state management route](../verification.md).
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# State Management Recipes
|
|
2
|
+
|
|
3
|
+
Domain classification: design-engineering. Lifecycle: `experimental`.
|
|
4
|
+
|
|
5
|
+
## Repository Boundary
|
|
6
|
+
|
|
7
|
+
These are Design Engineering behavior recipes. The root `recipes/` directory remains the Layout corpus. A behavior recipe may reference a Layout recipe but cannot import state logic into its reusable CSS.
|
|
8
|
+
|
|
9
|
+
## Reusable Method
|
|
10
|
+
|
|
11
|
+
Choose a task, then review its owner map, event flow, substitution rules, and acceptance sequences.
|
|
12
|
+
|
|
13
|
+
- [Settings with explicit save](settings-save.md): draft, submission, acknowledgement, and guarded departure.
|
|
14
|
+
- [Search filters and detail](search-detail.md): route state, out-of-order reads, and stable selection.
|
|
15
|
+
- [Multi-step form](multi-step-form.md): retained fields, validation, branching, and final submit.
|
|
16
|
+
- [Deletion and supported undo](delete-undo.md): identity, duplicate policy, recovery, and actual reversibility.
|
|
17
|
+
|
|
18
|
+
### Composition Matrix
|
|
19
|
+
|
|
20
|
+
`E` means essential to this recipe's declared behavior; `S` means substitutable when the stated requirement changes; `O` is optional with its own contract; `—` means not required. Pattern names link to their standalone contracts.
|
|
21
|
+
|
|
22
|
+
| Pattern | Settings | Search/detail | Multi-step form | Delete/undo |
|
|
23
|
+
| --- | --- | --- | --- | --- |
|
|
24
|
+
| [Single owner](../patterns/single-owner.md) | E | E | E | E |
|
|
25
|
+
| [Derived state](../patterns/derived-state.md) | E | E | E | O |
|
|
26
|
+
| [ID selection](../patterns/id-selection.md) | — | E | — | E |
|
|
27
|
+
| [Draft/baseline](../patterns/draft-and-baseline.md) | E | — | E | — |
|
|
28
|
+
| [Submitted snapshot](../patterns/submitted-snapshot.md) | E | — | E | — |
|
|
29
|
+
| [Unsaved navigation](../patterns/unsaved-navigation.md) | E | — | E | — |
|
|
30
|
+
| [Latest request wins](../patterns/latest-request-wins.md) | O | E | O | — |
|
|
31
|
+
| [Single flight](../patterns/single-flight.md) | E | — | E | E |
|
|
32
|
+
| [Optimistic overlay](../patterns/optimistic-overlay.md) | O | — | — | S |
|
|
33
|
+
| [URL state](../patterns/url-state.md) | O | S | O | O |
|
|
34
|
+
| [Identity reset](../patterns/identity-reset.md) | E | E | E | E |
|
|
35
|
+
| [Versioned restore](../patterns/versioned-restore.md) | O | — | O | — |
|
|
36
|
+
|
|
37
|
+
Single owner and identity reset are lifecycle foundations in these recipes even where the short stack emphasizes task-specific mechanisms. For a fixed identity, reset may be implemented simply by disposal; reused screens must invalidate their old generation.
|
|
38
|
+
|
|
39
|
+
Substitution risks: replacing URL state loses history/deep-link recovery unless another navigation owner provides it. Replacing a pending deletion with an optimistic overlay requires definitive rejection versus uncertain-outcome handling. Replacing explicit save with autosave changes the recipe and needs a separate write ordering contract.
|
|
40
|
+
|
|
41
|
+
## Opinionated Guidance
|
|
42
|
+
|
|
43
|
+
Keep compositions smaller than the complete catalog. Optional restore and optimistic display should solve a named user need. Do not create a new primitive merely because a screen combines several existing ones.
|
|
44
|
+
|
|
45
|
+
## Platform-Specific Guidance
|
|
46
|
+
|
|
47
|
+
Keep native form behavior, router transitions, and focus restoration in the consuming UI. Model examples have no rendered geometry; use the linked Layout recipes to name scroll and source-order ownership.
|
|
48
|
+
|
|
49
|
+
## Unsupported Absolutes
|
|
50
|
+
|
|
51
|
+
The matrix describes proposed compositions, not universal requirements for every settings or search screen. It does not claim that all combinations have executed browser evidence.
|
|
52
|
+
|
|
53
|
+
## Verification Contract
|
|
54
|
+
|
|
55
|
+
Each recipe must expose a unique ownership map, a failure interleaving, and the consequence of replacing an essential choice. Execute consumer integration sequences separately from the 12 pattern model examples.
|
|
56
|
+
|
|
57
|
+
## Source, License, And Attribution
|
|
58
|
+
|
|
59
|
+
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
|
|
60
|
+
|
|
61
|
+
## IA Navigation
|
|
62
|
+
|
|
63
|
+
Parent: [State Management](../index.md).
|
|
64
|
+
Next: [Continue the state management route](../verification.md).
|