stylegallery 0.1.6 → 0.1.8
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/AGENTS.md +13 -1
- package/DOMAINS.md +10 -6
- package/GOVERNANCE.md +14 -12
- package/LICENSE +28 -0
- package/LICENSE-DOCS +42 -0
- package/NOTICE +38 -0
- package/README.md +47 -15
- package/consumer-reference/agent-native/README.md +7 -7
- package/consumer-reference/agent-native/v2/admission-policy.json +196 -31
- package/consumer-reference/agent-native/v2/material-registry.json +1 -1
- package/consumer-reference/agent-native/v2/schema/admission-policy.schema.json +3 -3
- package/consumer-reference/agent-native/v2/schema/material-record.schema.json +1 -1
- package/design-engineering/component-contract.md +19 -3
- package/design-engineering/decision-tree.md +1 -0
- package/design-engineering/index.md +48 -0
- 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 +2 -0
- package/design-terminology/conflict-cases.md +51 -8
- package/design-terminology/index.md +6 -0
- package/design-terminology/interaction-semantics.md +87 -0
- package/design-terminology/source-kinds.md +1 -1
- package/design-terminology/source-vocabularies.md +17 -1
- package/design-terminology/token-semantics.md +90 -0
- package/design-terminology/typography-semantics.md +86 -0
- package/expression/brand-studies.md +50 -0
- package/expression/direction-brief.md +71 -0
- package/expression/directions/nocturne-editorial.md +80 -0
- package/expression/directions/warm-print.md +73 -0
- package/expression/index.md +40 -0
- package/expression/techniques/gradient-atmosphere.md +107 -0
- package/expression/techniques/grain-and-texture.md +83 -0
- package/expression/techniques/webgl-hero.md +123 -0
- package/guides/vocabulary.md +1 -1
- package/index.md +3 -3
- package/log.md +64 -0
- package/motion/accessible-motion.md +90 -0
- package/motion/index.md +9 -0
- package/motion/interaction-recipes.md +8 -2
- package/motion/interruption-and-retargeting.md +90 -0
- package/motion/observed-choreography.md +73 -0
- package/motion/rendering-and-performance.md +89 -0
- package/motion/techniques/kinetic-type.md +145 -0
- package/motion/techniques/scroll-choreography.md +154 -0
- package/package.json +76 -21
- package/platform-guides/adaptive-navigation.md +85 -0
- package/platform-guides/compatibility-matrix.md +1 -1
- package/platform-guides/index.md +6 -0
- package/platform-guides/input-and-focus.md +91 -0
- package/platform-guides/preferences-and-accessibility.md +90 -0
- package/quality/claim-records/stylegallery-multidomain-scope.md +2 -2
- package/quality/evidence/executable-evidence.md +1 -1
- package/quality/index.md +1 -2
- package/scripts/agent-native/v2/material-admission.mjs +1 -1
- package/scripts/agent-native/v2/material-identity.mjs +2 -2
- 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
- package/showcase/README.md +113 -0
- package/game-ui/classification.md +0 -82
- package/game-ui/decision-tree.md +0 -81
- package/game-ui/index.md +0 -45
- package/game-ui/reference-record.md +0 -62
- package/game-ui/screen-hierarchy.md +0 -107
- package/game-ui/screen-recipes.md +0 -101
- package/game-ui/unity/architecture.md +0 -166
- package/game-ui/unity/cli-loop.md +0 -84
- package/game-ui/unity/org-wiki.md +0 -146
- package/game-ui/unity/repository-map.md +0 -102
- package/game-ui/unity/ui-systems.md +0 -85
- package/game-ui/verification-workflow.md +0 -100
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Draft And Persisted Baseline
|
|
4
|
+
description: Preserve editable work while distinguishing it from the last acknowledged saved value.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Draft And Persisted Baseline
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Preserve editable work while distinguishing it from the last acknowledged saved value. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use for explicit Save/Cancel forms. For immediate committed toggles, use an operation contract instead of inventing a long-lived draft.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The form owns a draft, persistence supplies the baseline, and dirty is derived using domain equality. This example uses a single string. A remote update while dirty needs merge, conflict, or reload policy; never silently replace the draft.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Edit | Draft changes | Baseline stays acknowledged |
|
|
29
|
+
| Discard | Draft becomes baseline | No persistence request |
|
|
30
|
+
| Remote update while dirty | Conflict retained | Keep draft until the user resolves it |
|
|
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 `bun 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 baseline = "Original";
|
|
39
|
+
let draft = baseline;
|
|
40
|
+
const dirty = () => draft !== baseline;
|
|
41
|
+
draft = "Edited";
|
|
42
|
+
assert.equal(dirty(), true);
|
|
43
|
+
const remote = "Remote edit";
|
|
44
|
+
const conflict = dirty() && remote !== baseline;
|
|
45
|
+
assert.equal(conflict, true);
|
|
46
|
+
assert.equal(draft, "Edited");
|
|
47
|
+
draft = baseline; // Explicit discard, not an automatic refresh.
|
|
48
|
+
assert.equal(dirty(), false);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### What Breaks If Removed
|
|
52
|
+
|
|
53
|
+
Binding fields directly to the cached saved object makes Cancel impossible and may tell other readers that unsaved edits are persisted. An independent dirty boolean can remain true after editing back to the baseline.
|
|
54
|
+
|
|
55
|
+
### Composition And Substitution
|
|
56
|
+
|
|
57
|
+
[Submitted snapshot](submitted-snapshot.md) owns save acknowledgement. [Unsaved navigation](unsaved-navigation.md) uses dirty as an input. Do not let the router own a second draft.
|
|
58
|
+
|
|
59
|
+
## Opinionated Guidance
|
|
60
|
+
|
|
61
|
+
Choose baseline equality and server normalization rules before wiring a generic deep comparison. For nested drafts, prevent shared mutable references to the baseline.
|
|
62
|
+
|
|
63
|
+
## Platform-Specific Guidance
|
|
64
|
+
|
|
65
|
+
Use native form labels and validation relationships. Route-level forms may outlive individual fields; unmounting a field should not implicitly discard the form.
|
|
66
|
+
|
|
67
|
+
## Unsupported Absolutes
|
|
68
|
+
|
|
69
|
+
A baseline is an acknowledged observation, not a guarantee that nobody else edited the server since then.
|
|
70
|
+
|
|
71
|
+
## Verification Contract
|
|
72
|
+
|
|
73
|
+
- Edit then restore the original value; dirty must become false.
|
|
74
|
+
- Receive a remote update while dirty; preserve entered values.
|
|
75
|
+
- Discard explicitly; restore the acknowledged baseline without sending a save.
|
|
76
|
+
|
|
77
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
78
|
+
|
|
79
|
+
## Source, License, And Attribution
|
|
80
|
+
|
|
81
|
+
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.
|
|
82
|
+
|
|
83
|
+
## IA Navigation
|
|
84
|
+
|
|
85
|
+
Parent: [State Management](../index.md).
|
|
86
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Selection By Stable Identity
|
|
4
|
+
description: Keep selection attached to an entity while a collection reorders or refreshes.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Selection By Stable Identity
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Keep selection attached to an entity while a collection reorders or refreshes. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use for lists, tables, and detail views with stable IDs. Index selection is sufficient only for immutable position-based options whose identity truly is their position.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The screen owns `selectedId`; the data owner supplies current entities. Detail is derived by ID. Missing from a filtered page does not imply deletion: choose a retained-detail fetch or an unavailable state based on actual knowledge.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Select an available ID | ID selected | Resolve current entity by identity |
|
|
29
|
+
| Collection reorders | Same ID | Detail still belongs to the same entity |
|
|
30
|
+
| Authoritative deletion removes ID | Null or unavailable | Apply the declared fallback and recover focus |
|
|
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 `bun 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 rows = [{ id: "a", name: "Alpha" }, { id: "b", name: "Beta" }];
|
|
39
|
+
let selectedId = "b";
|
|
40
|
+
const selected = () => rows.find(row => row.id === selectedId) ?? null;
|
|
41
|
+
rows = [...rows].reverse();
|
|
42
|
+
assert.equal(selected().name, "Beta");
|
|
43
|
+
rows = rows.map(row => row.id === "b" ? { ...row, name: "Updated" } : row);
|
|
44
|
+
assert.equal(selected().name, "Updated");
|
|
45
|
+
rows = rows.filter(row => row.id !== "b");
|
|
46
|
+
if (!selected()) selectedId = null; // This collection is authoritative and complete.
|
|
47
|
+
assert.equal(selected(), null);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### What Breaks If Removed
|
|
51
|
+
|
|
52
|
+
Keep row index 1, reverse the array, and the detail silently changes to another entity. Keep a copied selected object and a refresh can leave its fields stale.
|
|
53
|
+
|
|
54
|
+
### Composition And Substitution
|
|
55
|
+
|
|
56
|
+
Use [URL state](url-state.md) when selection should survive links and history. Use [latest request wins](latest-request-wins.md) for separately fetched detail; key requests by selected ID.
|
|
57
|
+
|
|
58
|
+
## Opinionated Guidance
|
|
59
|
+
|
|
60
|
+
Choose an explicit missing-item policy. Never infer remote deletion solely from pagination or filtering.
|
|
61
|
+
|
|
62
|
+
## Platform-Specific Guidance
|
|
63
|
+
|
|
64
|
+
After deleting a focused row, move focus to a logical neighbor or heading. A selected state and keyboard focus are separate responsibilities.
|
|
65
|
+
|
|
66
|
+
## Unsupported Absolutes
|
|
67
|
+
|
|
68
|
+
Stable keys do not prove stable identity if the server recycles identifiers across tenants or revisions.
|
|
69
|
+
|
|
70
|
+
## Verification Contract
|
|
71
|
+
|
|
72
|
+
- Reorder and update the selected row; detail must preserve ID and refresh fields.
|
|
73
|
+
- Filter it out without deleting it; apply the declared retained-detail policy.
|
|
74
|
+
- Delete the final item; verify empty detail and focus recovery in the UI.
|
|
75
|
+
|
|
76
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
77
|
+
|
|
78
|
+
## Source, License, And Attribution
|
|
79
|
+
|
|
80
|
+
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.
|
|
81
|
+
|
|
82
|
+
## IA Navigation
|
|
83
|
+
|
|
84
|
+
Parent: [State Management](../index.md).
|
|
85
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Identity Boundary And Reset
|
|
4
|
+
description: Prevent temporary state and pending outcomes from leaking across entity or account changes.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Identity Boundary And Reset
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Prevent temporary state and pending outcomes from leaking across entity or account changes. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use when a mounted editor is reused for a different document, tenant, or account. Preserve drafts per identity only when that is an explicit product feature.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The screen owner stores identity and generation. Entering a new identity clears identity-local values and invalidates previous operations. Generation matters even when the user goes A → B → A.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Enter identity | Fresh generation and local state | Invalidate earlier callbacks |
|
|
29
|
+
| Matching-generation completion | Apply within current identity | Accept only live work |
|
|
30
|
+
| Old-generation completion | Unchanged | Reject even if the entity ID matches again |
|
|
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 `bun 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 generation = 0, identity = null, draft = "";
|
|
39
|
+
function enter(id) { identity = id; generation++; draft = ""; }
|
|
40
|
+
function ticket() { return { identity, generation }; }
|
|
41
|
+
function receive(t, value) {
|
|
42
|
+
if (t.identity === identity && t.generation === generation) draft = value;
|
|
43
|
+
}
|
|
44
|
+
enter("A");
|
|
45
|
+
const oldA = ticket();
|
|
46
|
+
enter("B");
|
|
47
|
+
enter("A");
|
|
48
|
+
receive(oldA, "stale A");
|
|
49
|
+
assert.equal(draft, "");
|
|
50
|
+
receive(ticket(), "current A");
|
|
51
|
+
assert.equal(draft, "current A");
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### What Breaks If Removed
|
|
55
|
+
|
|
56
|
+
Checking entity ID alone accepts the old A request after returning from B to A. Resetting the draft without invalidating requests lets a late response repopulate it.
|
|
57
|
+
|
|
58
|
+
### Composition And Substitution
|
|
59
|
+
|
|
60
|
+
Combine [latest request wins](latest-request-wins.md) within each generation and [versioned restore](versioned-restore.md) for explicit per-identity persistence. Apply [unsaved navigation](unsaved-navigation.md) before abandoning dirty work.
|
|
61
|
+
|
|
62
|
+
## Opinionated Guidance
|
|
63
|
+
|
|
64
|
+
Define the identity tuple, including tenant when needed. Clear sensitive caches at the session boundary rather than relying solely on component unmount.
|
|
65
|
+
|
|
66
|
+
## Platform-Specific Guidance
|
|
67
|
+
|
|
68
|
+
Framework keys can recreate components, but external listeners, caches, timers, and requests still need explicit cleanup. Router reuse may preserve component instances.
|
|
69
|
+
|
|
70
|
+
## Unsupported Absolutes
|
|
71
|
+
|
|
72
|
+
A UI reset is not an authorization or secure data-erasure mechanism.
|
|
73
|
+
|
|
74
|
+
## Verification Contract
|
|
75
|
+
|
|
76
|
+
- Switch A → B while a read is pending; no A result appears in B.
|
|
77
|
+
- Switch A → B → A; reject the first generation's callback.
|
|
78
|
+
- Inspect focus, local errors, draft, and subscriptions after switching.
|
|
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,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Latest Request Wins
|
|
4
|
+
description: Prevent an older read response from replacing the result of a newer user intent.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Latest Request Wins
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Prevent an older read response from replacing the result of a newer user intent. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use for replaceable reads such as search and selected-item detail. Do not use this policy to discard the outcomes of independent writes that all matter.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The read owner stores a monotonically increasing identity, status, and last accepted result. Both success and failure must match the current request. Cancellation is an optional resource optimization; identity decides acceptance.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Start read | Pending with new ID | Previous IDs lose authority |
|
|
29
|
+
| Matching success | Ready with results | Accept only current intent |
|
|
30
|
+
| Matching failure | Error | Preserve or clear old results under explicit policy |
|
|
31
|
+
| Stale success or failure | Unchanged | No status, result, or error mutation |
|
|
32
|
+
| Dispose | Disposed and invalidated | Ignore all pending outcomes |
|
|
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 `bun 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 serial = 0, active = 0, status = "idle", result = null;
|
|
41
|
+
const begin = () => { active = ++serial; status = "pending"; return active; };
|
|
42
|
+
function settle(id, ok, value) {
|
|
43
|
+
if (id !== active) return;
|
|
44
|
+
status = ok ? "ready" : "error";
|
|
45
|
+
if (ok) result = value;
|
|
46
|
+
}
|
|
47
|
+
const a = begin(), b = begin();
|
|
48
|
+
settle(b, true, "B");
|
|
49
|
+
settle(a, true, "A");
|
|
50
|
+
settle(a, false, "old failure");
|
|
51
|
+
assert.equal(result, "B");
|
|
52
|
+
assert.equal(status, "ready");
|
|
53
|
+
const c = begin();
|
|
54
|
+
active = ++serial; status = "disposed";
|
|
55
|
+
settle(c, true, "C");
|
|
56
|
+
assert.equal(status, "disposed");
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### What Breaks If Removed
|
|
60
|
+
|
|
61
|
+
Remove the ID check: resolve B then A and the screen displays A under B's query. Guarding success only still allows A's error or finally handler to clear B's pending status.
|
|
62
|
+
|
|
63
|
+
### Composition And Substitution
|
|
64
|
+
|
|
65
|
+
Combine [URL state](url-state.md) for committed query inputs and [ID selection](id-selection.md) for detail. Use [single flight](single-flight.md) for duplicate writes rather than silently discarding their acknowledgements.
|
|
66
|
+
|
|
67
|
+
## Opinionated Guidance
|
|
68
|
+
|
|
69
|
+
Choose whether old results stay visible while refreshing and label their query identity. Debouncing reduces starts but does not establish response ordering.
|
|
70
|
+
|
|
71
|
+
## Platform-Specific Guidance
|
|
72
|
+
|
|
73
|
+
Check identity after each awaited stage, including body decoding or transformations. Dispose invalidation and listener cleanup belong to the framework adapter.
|
|
74
|
+
|
|
75
|
+
## Unsupported Absolutes
|
|
76
|
+
|
|
77
|
+
Latest-wins prevents this local overwrite; it does not guarantee fresh server data, cache coherence, or distributed consistency.
|
|
78
|
+
|
|
79
|
+
## Verification Contract
|
|
80
|
+
|
|
81
|
+
- Start A then B; resolve B then A, including an A failure.
|
|
82
|
+
- Start B while A is pending; A completion must not clear B's pending indicator.
|
|
83
|
+
- Dispose before completion; no displayed state may update.
|
|
84
|
+
|
|
85
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
86
|
+
|
|
87
|
+
## Source, License, And Attribution
|
|
88
|
+
|
|
89
|
+
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.
|
|
90
|
+
|
|
91
|
+
## IA Navigation
|
|
92
|
+
|
|
93
|
+
Parent: [State Management](../index.md).
|
|
94
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Optimistic Overlay And Recovery
|
|
4
|
+
description: Show a speculative change while preserving an authoritative base for recovery.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Optimistic Overlay And Recovery
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Show a speculative change while preserving an authoritative base for recovery. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use for a bounded reversible presentation change when failure is recoverable. Prefer pending-until-confirmed behavior for irreversible or high-consequence actions.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The cache owns base; the operation owns an overlay and ID. The displayed value is base plus overlay. This minimal example permits one edit at a time; concurrent mutations require ordered overlays or per-entity serialization.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Begin mutation while idle | Overlay pending | Display prediction without rewriting base |
|
|
29
|
+
| Matching rejection | Overlay removed | Reveal current base, not an old whole-cache snapshot |
|
|
30
|
+
| Matching acknowledgement | Base becomes server value | Remove overlay atomically |
|
|
31
|
+
| Uncertain outcome | Reconciliation required | Do not announce rollback of the server |
|
|
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 `bun 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
|
+
let base = { name: "Before", revision: 1 }, overlay = null, serial = 0;
|
|
40
|
+
const view = () => overlay ? { ...base, name: overlay.name } : base;
|
|
41
|
+
function begin(name) {
|
|
42
|
+
if (overlay) return null;
|
|
43
|
+
overlay = { id: ++serial, name };
|
|
44
|
+
return overlay.id;
|
|
45
|
+
}
|
|
46
|
+
function settle(id, accepted) {
|
|
47
|
+
if (overlay?.id !== id) return;
|
|
48
|
+
if (accepted) base = accepted;
|
|
49
|
+
overlay = null;
|
|
50
|
+
}
|
|
51
|
+
const a = begin("Predicted");
|
|
52
|
+
assert.equal(view().name, "Predicted");
|
|
53
|
+
base = { name: "Remote", revision: 2 }; // A newer authoritative observation.
|
|
54
|
+
settle(a, null); // Definitive rejection, not an ambiguous timeout.
|
|
55
|
+
assert.equal(view().name, "Remote");
|
|
56
|
+
const b = begin("Next");
|
|
57
|
+
settle(a, null);
|
|
58
|
+
assert.equal(view().name, "Next");
|
|
59
|
+
settle(b, { name: "Normalized", revision: 3 });
|
|
60
|
+
assert.equal(view().name, "Normalized");
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### What Breaks If Removed
|
|
64
|
+
|
|
65
|
+
Restoring a whole-cache snapshot on failure can erase unrelated or newer remote changes. Without correlation, an old failure can remove a newer optimistic operation.
|
|
66
|
+
|
|
67
|
+
### Composition And Substitution
|
|
68
|
+
|
|
69
|
+
Compose with [single flight](single-flight.md) for this serialized model. Use [ID selection](id-selection.md) for row mutations. Define version ordering before admitting concurrent acknowledgements into a shared cache.
|
|
70
|
+
|
|
71
|
+
## Opinionated Guidance
|
|
72
|
+
|
|
73
|
+
Separate a definitive rejection from a lost response: a timeout may have committed remotely. Reconcile uncertain results before promising the change was undone.
|
|
74
|
+
|
|
75
|
+
## Platform-Specific Guidance
|
|
76
|
+
|
|
77
|
+
Keep pending and error information available beyond color or animation. A disappearance animation must not decide whether the underlying entity exists.
|
|
78
|
+
|
|
79
|
+
## Unsupported Absolutes
|
|
80
|
+
|
|
81
|
+
An inverse UI patch is not a backend undo protocol. The sample does not implement concurrent multi-writer revision arbitration.
|
|
82
|
+
|
|
83
|
+
## Verification Contract
|
|
84
|
+
|
|
85
|
+
- Reject a speculative edit after a newer base arrives; preserve the newer base.
|
|
86
|
+
- Deliver an old failure during a new edit; retain the new overlay.
|
|
87
|
+
- Return a normalized server value and verify it replaces the prediction.
|
|
88
|
+
|
|
89
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
90
|
+
|
|
91
|
+
## Source, License, And Attribution
|
|
92
|
+
|
|
93
|
+
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.
|
|
94
|
+
|
|
95
|
+
## IA Navigation
|
|
96
|
+
|
|
97
|
+
Parent: [State Management](../index.md).
|
|
98
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Domain Guide
|
|
3
|
+
title: Single Flight And Duplicate Submission
|
|
4
|
+
description: Apply an explicit policy to repeated activation of one pending operation.
|
|
5
|
+
domain: design-engineering
|
|
6
|
+
lifecycle: experimental
|
|
7
|
+
provenance_kind: local
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Single Flight And Duplicate Submission
|
|
11
|
+
|
|
12
|
+
## Repository Boundary
|
|
13
|
+
|
|
14
|
+
Apply an explicit policy to repeated activation of one pending operation. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
|
|
15
|
+
|
|
16
|
+
## Reusable Method
|
|
17
|
+
|
|
18
|
+
Use when a duplicate Save or Delete should share or ignore the active attempt. Independent entities may need separate flight keys. A queue is preferable when every intent must execute.
|
|
19
|
+
|
|
20
|
+
### State Model And Ownership
|
|
21
|
+
|
|
22
|
+
The operation owner holds one pending promise per declared scope. This example shares it. The guard is set before the effect begins and clears on success or failure.
|
|
23
|
+
|
|
24
|
+
### Transitions
|
|
25
|
+
|
|
26
|
+
| Event and precondition | Next state | Effect or invariant |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Activate while idle | One pending operation | Run effect once |
|
|
29
|
+
| Activate while pending | Same pending operation | Return same promise |
|
|
30
|
+
| Settle | Idle | Release guard on success and failure |
|
|
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 `bun 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 pending = null, calls = 0;
|
|
39
|
+
function run(effect) {
|
|
40
|
+
if (pending) return pending;
|
|
41
|
+
pending = Promise.resolve().then(effect).finally(() => { pending = null; });
|
|
42
|
+
return pending;
|
|
43
|
+
}
|
|
44
|
+
let release;
|
|
45
|
+
const effect = () => { calls++; return new Promise(resolve => { release = resolve; }); };
|
|
46
|
+
const a = run(effect), b = run(effect);
|
|
47
|
+
assert.equal(a, b);
|
|
48
|
+
await Promise.resolve();
|
|
49
|
+
assert.equal(calls, 1);
|
|
50
|
+
release("saved");
|
|
51
|
+
await a;
|
|
52
|
+
await assert.rejects(run(() => { throw new Error("offline"); }));
|
|
53
|
+
assert.equal(pending, null);
|
|
54
|
+
assert.equal(await run(() => "retry"), "retry");
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### What Breaks If Removed
|
|
58
|
+
|
|
59
|
+
Disabling only the visible button misses keyboard submission or another caller. Setting pending after awaiting the effect permits two operations. Clearing only on success locks the action after a failure.
|
|
60
|
+
|
|
61
|
+
### Composition And Substitution
|
|
62
|
+
|
|
63
|
+
Use with [submitted snapshot](submitted-snapshot.md); duplicate activation must not silently replace the captured snapshot. For separate rows, scope the guard by stable entity ID.
|
|
64
|
+
|
|
65
|
+
## Opinionated Guidance
|
|
66
|
+
|
|
67
|
+
Pick ignore, share, queue, or replace deliberately. This example shares a result and does not implement queuing. After an ambiguous write failure, reconcile or use server-supported idempotency before retrying.
|
|
68
|
+
|
|
69
|
+
## Platform-Specific Guidance
|
|
70
|
+
|
|
71
|
+
Handle every caller's rejection and expose progress through accessible status. UI disabled semantics do not replace the operation guard.
|
|
72
|
+
|
|
73
|
+
## Unsupported Absolutes
|
|
74
|
+
|
|
75
|
+
One client promise cannot prevent another tab, device, or retry from executing the same server command.
|
|
76
|
+
|
|
77
|
+
## Verification Contract
|
|
78
|
+
|
|
79
|
+
- Activate from two entry points in the same turn; effect count remains one.
|
|
80
|
+
- Fail the operation; a subsequent explicit attempt can start.
|
|
81
|
+
- For per-entity scope, verify different entities do not block each other.
|
|
82
|
+
|
|
83
|
+
Record actual outcomes separately using the [verification matrix](../verification.md).
|
|
84
|
+
|
|
85
|
+
## Source, License, And Attribution
|
|
86
|
+
|
|
87
|
+
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.
|
|
88
|
+
|
|
89
|
+
## IA Navigation
|
|
90
|
+
|
|
91
|
+
Parent: [State Management](../index.md).
|
|
92
|
+
Next: [Continue the state management route](../recipes/index.md).
|
|
@@ -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 `bun 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).
|