@elaraai/e3-ui 1.0.4 → 1.0.6

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.
Files changed (100) hide show
  1. package/README.md +3 -2
  2. package/dist/src/data.d.ts +22 -1
  3. package/dist/src/data.d.ts.map +1 -1
  4. package/dist/src/data.js.map +1 -1
  5. package/dist/src/decision/bind.d.ts +4594 -0
  6. package/dist/src/decision/bind.d.ts.map +1 -0
  7. package/dist/src/decision/bind.js +156 -0
  8. package/dist/src/decision/bind.js.map +1 -0
  9. package/dist/src/decision/index.d.ts +1787 -0
  10. package/dist/src/decision/index.d.ts.map +1 -0
  11. package/dist/src/decision/index.js +36 -0
  12. package/dist/src/decision/index.js.map +1 -0
  13. package/dist/src/decision/journal.d.ts +405 -0
  14. package/dist/src/decision/journal.d.ts.map +1 -0
  15. package/dist/src/decision/journal.js +74 -0
  16. package/dist/src/decision/journal.js.map +1 -0
  17. package/dist/src/decision/queue.d.ts +2876 -0
  18. package/dist/src/decision/queue.d.ts.map +1 -0
  19. package/dist/src/decision/queue.js +166 -0
  20. package/dist/src/decision/queue.js.map +1 -0
  21. package/dist/src/decision/types.d.ts +1338 -0
  22. package/dist/src/decision/types.d.ts.map +1 -0
  23. package/dist/src/decision/types.js +389 -0
  24. package/dist/src/decision/types.js.map +1 -0
  25. package/dist/src/diff.d.ts +72 -0
  26. package/dist/src/diff.d.ts.map +1 -1
  27. package/dist/src/diff.js +6 -0
  28. package/dist/src/diff.js.map +1 -1
  29. package/dist/src/index.d.ts +27 -11
  30. package/dist/src/index.d.ts.map +1 -1
  31. package/dist/src/index.js +30 -10
  32. package/dist/src/index.js.map +1 -1
  33. package/dist/src/internal.d.ts +28 -0
  34. package/dist/src/internal.d.ts.map +1 -0
  35. package/dist/src/internal.js +28 -0
  36. package/dist/src/internal.js.map +1 -0
  37. package/dist/src/ontology.d.ts +205 -10
  38. package/dist/src/ontology.d.ts.map +1 -1
  39. package/dist/src/ontology.js +23 -4
  40. package/dist/src/ontology.js.map +1 -1
  41. package/dist/src/runtime/decision/journal.d.ts +29 -0
  42. package/dist/src/runtime/decision/journal.d.ts.map +1 -0
  43. package/dist/src/runtime/decision/journal.js +27 -0
  44. package/dist/src/runtime/decision/journal.js.map +1 -0
  45. package/dist/src/runtime/decision/queue.d.ts +47 -0
  46. package/dist/src/runtime/decision/queue.d.ts.map +1 -0
  47. package/dist/src/runtime/decision/queue.js +45 -0
  48. package/dist/src/runtime/decision/queue.js.map +1 -0
  49. package/dist/src/runtime/diff.d.ts +36 -0
  50. package/dist/src/runtime/diff.d.ts.map +1 -0
  51. package/dist/src/runtime/diff.js +34 -0
  52. package/dist/src/runtime/diff.js.map +1 -0
  53. package/dist/src/runtime/index.d.ts +15 -0
  54. package/dist/src/runtime/index.d.ts.map +1 -0
  55. package/dist/src/runtime/index.js +15 -0
  56. package/dist/src/runtime/index.js.map +1 -0
  57. package/dist/src/runtime/ontology.d.ts +36 -0
  58. package/dist/src/runtime/ontology.d.ts.map +1 -0
  59. package/dist/src/runtime/ontology.js +34 -0
  60. package/dist/src/runtime/ontology.js.map +1 -0
  61. package/dist/src/runtime/runtime.d.ts +7 -0
  62. package/dist/src/runtime/runtime.d.ts.map +1 -0
  63. package/dist/src/runtime/runtime.js +7 -0
  64. package/dist/src/runtime/runtime.js.map +1 -0
  65. package/dist/src/ui.d.ts +6 -6
  66. package/dist/src/ui.d.ts.map +1 -1
  67. package/dist/src/ui.js +9 -1
  68. package/dist/src/ui.js.map +1 -1
  69. package/dist/test/{data.examples.d.ts → data/data.examples.d.ts} +1 -0
  70. package/dist/test/data/data.examples.d.ts.map +1 -0
  71. package/dist/test/{data.examples.js → data/data.examples.js} +30 -68
  72. package/dist/test/data/data.examples.js.map +1 -0
  73. package/dist/test/decision/journal.examples.d.ts +266 -0
  74. package/dist/test/decision/journal.examples.d.ts.map +1 -0
  75. package/dist/test/decision/journal.examples.js +107 -0
  76. package/dist/test/decision/journal.examples.js.map +1 -0
  77. package/dist/test/decision/loop.examples.d.ts +455 -0
  78. package/dist/test/decision/loop.examples.d.ts.map +1 -0
  79. package/dist/test/decision/loop.examples.js +120 -0
  80. package/dist/test/decision/loop.examples.js.map +1 -0
  81. package/dist/test/decision/queue.examples.d.ts +269 -0
  82. package/dist/test/decision/queue.examples.d.ts.map +1 -0
  83. package/dist/test/decision/queue.examples.js +273 -0
  84. package/dist/test/decision/queue.examples.js.map +1 -0
  85. package/dist/test/{diff.examples.d.ts → diff/diff.examples.d.ts} +5 -4
  86. package/dist/test/diff/diff.examples.d.ts.map +1 -0
  87. package/dist/test/diff/diff.examples.js +582 -0
  88. package/dist/test/diff/diff.examples.js.map +1 -0
  89. package/dist/test/{ontology.examples.d.ts → ontology/ontology.examples.d.ts} +6 -4
  90. package/dist/test/ontology/ontology.examples.d.ts.map +1 -0
  91. package/dist/test/{ontology.examples.js → ontology/ontology.examples.js} +37 -57
  92. package/dist/test/ontology/ontology.examples.js.map +1 -0
  93. package/package.json +19 -19
  94. package/dist/test/data.examples.d.ts.map +0 -1
  95. package/dist/test/data.examples.js.map +0 -1
  96. package/dist/test/diff.examples.d.ts.map +0 -1
  97. package/dist/test/diff.examples.js +0 -964
  98. package/dist/test/diff.examples.js.map +0 -1
  99. package/dist/test/ontology.examples.d.ts.map +0 -1
  100. package/dist/test/ontology.examples.js.map +0 -1
@@ -0,0 +1,582 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@elaraai/e3-ui/jsx-runtime";
2
+ /**
3
+ * Copyright (c) 2025 Elara AI Pty Ltd
4
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
5
+ */
6
+ /** @jsxImportSource @elaraai/e3-ui */
7
+ /**
8
+ * Diff component examples — realistic editing scenes that combine
9
+ * `Data.bind` with east-ui form components and a `<Diff>` panel
10
+ * surfacing the pending changes for sign-off.
11
+ *
12
+ * Coverage:
13
+ * 1. Slider-driven editor → workforcePolicyEditor
14
+ * 2. Heterogeneous inputs → serviceConfigForm
15
+ * 3. Editable Table cells → rosterTableEditor
16
+ * 4. Mixed sliders + inputs → pricingRulesEditor (side-by-side mode)
17
+ * 5. Minimal call site → diffDefaults (IR-roundtrip)
18
+ *
19
+ * Pattern:
20
+ * 1. Declare an `e3.input(name, type, default)` per editable scalar.
21
+ * 2. Inside `<Reactive>`, bind each via `Data.bind`.
22
+ * 3. Wire form components — `read()` for the current value,
23
+ * `write()` on change.
24
+ * 4. Close the scene with `<Diff bindings={[...]} />` — Apply commits
25
+ * the merged batch; Discard drops the buffer.
26
+ */
27
+ import { East, FloatType, IntegerType, StringType, BooleanType, DateTimeType, ArrayType, StructType, SetType, DictType, VariantType, NullType, PatchType, diffFor, some, variant, example, } from "@elaraai/east";
28
+ import { Card, HStack, VStack, Slider, Input, Switch, Select, Text, Button, Reactive, Table, UIComponentType, } from "@elaraai/east-ui";
29
+ import { Data, Diff } from "@elaraai/e3-ui";
30
+ import * as e3 from "@elaraai/e3";
31
+ // ============================================================================
32
+ // Inputs — flat scalars for slider/input examples; one ArrayType binding for
33
+ // the table example so Diff can surface array-element patches end-to-end.
34
+ // ============================================================================
35
+ // Workforce-policy scenario (sliders)
36
+ export const maxWeeklyHoursInput = e3.input("max_weekly_hours", FloatType, 38.0);
37
+ export const overtimeThresholdInput = e3.input("overtime_threshold_hours", FloatType, 38.0);
38
+ export const restGapHoursInput = e3.input("mandatory_rest_gap_hours", FloatType, 12.0);
39
+ export const holidayPenaltyInput = e3.input("public_holiday_penalty", FloatType, 1.5);
40
+ // Service-config scenario (heterogeneous inputs)
41
+ export const serviceNameInput = e3.input("service_name", StringType, "auth-svc");
42
+ export const replicasInput = e3.input("replicas", IntegerType, 3n);
43
+ export const autoScaleInput = e3.input("auto_scale", BooleanType, false);
44
+ export const regionInput = e3.input("region", StringType, "ap-southeast-2");
45
+ export const deployAfterInput = e3.input("deploy_after", DateTimeType, new Date("2026-05-01T08:00:00Z"));
46
+ // Roster table scenario (single ArrayType<Struct> binding)
47
+ const RosterEntryType = StructType({
48
+ id: StringType,
49
+ name: StringType,
50
+ rate: FloatType,
51
+ shiftLength: IntegerType,
52
+ });
53
+ const RosterArrayType = ArrayType(RosterEntryType);
54
+ export const rosterInput = e3.input("roster", RosterArrayType, [
55
+ { id: "alice", name: "Alice Chen", rate: 32.50, shiftLength: 8n },
56
+ { id: "bob", name: "Bob Romero", rate: 28.00, shiftLength: 8n },
57
+ { id: "charlie", name: "Charlie Patel", rate: 35.75, shiftLength: 10n },
58
+ { id: "diana", name: "Diana Wallace", rate: 30.25, shiftLength: 8n },
59
+ ]);
60
+ // Merge-conflict demo scenario — single Float; both bindStaged (for the user's
61
+ // pending edit) and bindDirect (for the "simulate concurrent edit" button)
62
+ // point at the same path so writes via the button drift the server view away
63
+ // from the staged buffer's pinned snapshot.
64
+ export const mergeDemoHoursInput = e3.input("merge_demo_hours", FloatType, 38.0);
65
+ // Pricing-rules scenario (mixed slider + integer/string input)
66
+ export const listPriceInput = e3.input("list_price", FloatType, 49.95);
67
+ export const discountPctInput = e3.input("discount_pct", FloatType, 10.0);
68
+ export const minOrderQtyInput = e3.input("min_order_qty", IntegerType, 1n);
69
+ export const currencyCodeInput = e3.input("currency_code", StringType, "AUD");
70
+ // Feature flags scenario (Set<String>)
71
+ export const featureFlagsInput = e3.input("feature_flags", SetType(StringType), new Set(["dark_mode", "experiments"]));
72
+ // Regional pricing scenario (Dict<String, Float>)
73
+ export const regionalPricesInput = e3.input("regional_prices", DictType(StringType, FloatType), new Map([
74
+ ["AU", 49.95],
75
+ ["US", 39.95],
76
+ ["EU", 44.95],
77
+ ["JP", 5499.0],
78
+ ]));
79
+ // Deployment status scenario (Variant)
80
+ const DeploymentStatusType = VariantType({
81
+ pending: NullType,
82
+ in_progress: NullType,
83
+ complete: NullType,
84
+ failed: NullType,
85
+ });
86
+ export const deploymentStatusInput = e3.input("deployment_status", DeploymentStatusType, variant("pending", null));
87
+ // ============================================================================
88
+ // 1. Workforce-policy editor — slider-driven edits across 4 staged scalars
89
+ // ============================================================================
90
+ export const workforcePolicyEditor = example({
91
+ keywords: ["Diff", "Slider", "bindStaged", "workforce", "policy", "Card"],
92
+ description: "Slider-driven workforce-policy editor — 4 staged Float scalars; Diff surfaces pending edits",
93
+ fn: East.function([], UIComponentType, (_$) => {
94
+ return (_jsx(Reactive, { children: $ => {
95
+ const maxHours = $.let(Data.bind([FloatType], maxWeeklyHoursInput.path));
96
+ const otThresh = $.let(Data.bind([FloatType], overtimeThresholdInput.path));
97
+ const restGap = $.let(Data.bind([FloatType], restGapHoursInput.path));
98
+ const penalty = $.let(Data.bind([FloatType], holidayPenaltyInput.path));
99
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Workforce policy" }), _jsx(Text, { children: "Drag the sliders to stage policy changes \u2014 review in the Diff card before applying." }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Max weekly hours" }), _jsx(Slider, { value: maxHours.read(), min: 30.0, max: 60.0, step: 1.0, onChangeEnd: ($, v) => $(maxHours.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Overtime threshold (h)" }), _jsx(Slider, { value: otThresh.read(), min: 30.0, max: 60.0, step: 1.0, onChangeEnd: ($, v) => $(otThresh.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Mandatory rest gap (h)" }), _jsx(Slider, { value: restGap.read(), min: 8.0, max: 16.0, step: 1.0, onChangeEnd: ($, v) => $(restGap.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Public holiday penalty (\u00D7)" }), _jsx(Slider, { value: penalty.read(), min: 1.0, max: 3.0, step: 0.25, onChangeEnd: ($, v) => $(penalty.write(v)) })] }), _jsx(Diff, { bindings: [maxHours.binding, otThresh.binding, restGap.binding, penalty.binding], hideUnchanged: some(true) })] }) }));
100
+ } }));
101
+ }),
102
+ inputs: [],
103
+ });
104
+ // ============================================================================
105
+ // 2. Service-config form — heterogeneous Inputs (String / Integer / DateTime),
106
+ // Switch, Select; commit fires a Toast.
107
+ // ============================================================================
108
+ export const serviceConfigForm = example({
109
+ keywords: ["Diff", "Input", "Switch", "Select", "DateTime", "Toast", "onCommitted"],
110
+ description: "Service-config form covering String / Integer / Bool / DateTime / Select; commit fires a success Toast",
111
+ fn: East.function([], UIComponentType, (_$) => {
112
+ return (_jsx(Reactive, { children: $ => {
113
+ const svcName = $.let(Data.bind([StringType], serviceNameInput.path));
114
+ const replicas = $.let(Data.bind([IntegerType], replicasInput.path));
115
+ const autoScale = $.let(Data.bind([BooleanType], autoScaleInput.path));
116
+ const region = $.let(Data.bind([StringType], regionInput.path));
117
+ const deployAfter = $.let(Data.bind([DateTimeType], deployAfterInput.path));
118
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Service configuration" }), _jsx(Text, { children: "Stage edits across heterogeneous types; on apply you\u2019ll see a confirmation toast." }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Service name" }), _jsx(Input.String, { value: svcName.read(), placeholder: "service-name", onChange: ($, v) => $(svcName.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Replicas" }), _jsx(Input.Integer, { value: replicas.read(), min: 1n, max: 50n, onChange: ($, v) => $(replicas.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Auto-scale" }), _jsx(Switch, { checked: autoScale.read(), onChange: ($, v) => $(autoScale.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Region" }), _jsx(Select, { value: region.read(), items: [
119
+ Select.Item("ap-southeast-2", "ap-southeast-2 (Sydney)"),
120
+ Select.Item("us-east-1", "us-east-1 (N. Virginia)"),
121
+ Select.Item("eu-west-1", "eu-west-1 (Ireland)"),
122
+ ], onChange: ($, v) => $(region.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Deploy after" }), _jsx(Input.DateTime, { value: deployAfter.read(), precision: "datetime", onChange: ($, v) => $(deployAfter.write(v)) })] }), _jsx(Diff, { bindings: [svcName.binding, replicas.binding, autoScale.binding, region.binding, deployAfter.binding] })] }) }));
123
+ } }));
124
+ }),
125
+ inputs: [],
126
+ });
127
+ // ============================================================================
128
+ // 3. Roster Table — editable cells (Float / Integer Inputs) writing back to
129
+ // a single ArrayType<Struct> staged binding. Diff visualises array
130
+ // patches per row.
131
+ // ============================================================================
132
+ export const rosterTableEditor = example({
133
+ keywords: ["Diff", "Table", "cell", "render", "Input", "Array", "bindStaged", "roster"],
134
+ description: "Editable Table — Input.Float / Input.Integer cells write back to a staged roster array; Diff shows per-row updates",
135
+ fn: East.function([], UIComponentType, (_$) => {
136
+ return (_jsx(Reactive, { children: $ => {
137
+ const roster = $.let(Data.bind([RosterArrayType], rosterInput.path));
138
+ // Get the roster array fresh inside the render closures to ensure edits to sibling
139
+ const rosterArray = $.let(roster.read(), RosterArrayType);
140
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Worker roster" }), _jsx(Text, { children: "Edit hourly rates and default shift lengths inline; Diff card below tracks pending changes." }), _jsx(Table, { data: rosterArray, columns: {
141
+ name: { header: "Name" },
142
+ rate: {
143
+ header: "Hourly rate ($)",
144
+ render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
145
+ const idx = $.let(ctx.rowIndex, IntegerType);
146
+ const row = $.let(rosterArray.get(idx), RosterEntryType);
147
+ return (_jsx(Input.Float, { value: row.rate, min: 15.0, max: 80.0, step: 0.25,
148
+ // Re-read fresh inside the handler so a sibling cell's
149
+ // edit on the same row isn't overwritten by a stale
150
+ // capture of `row`. Merge via the map iterator's `r`.
151
+ onChange: East.function([FloatType], NullType, ($, v) => {
152
+ const fresh = $.let(roster.read(), RosterArrayType);
153
+ const next = $.let(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, rate: v }), () => r)), RosterArrayType);
154
+ $(roster.write(next));
155
+ }) }));
156
+ }),
157
+ },
158
+ shiftLength: {
159
+ header: "Shift length (h)",
160
+ render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
161
+ const idx = $.let(ctx.rowIndex, IntegerType);
162
+ const row = $.let(rosterArray.get(idx), RosterEntryType);
163
+ return (_jsx(Input.Integer, { value: row.shiftLength, min: 4n, max: 12n, onChange: East.function([IntegerType], NullType, ($, v) => {
164
+ const fresh = $.let(roster.read(), RosterArrayType);
165
+ $(roster.write(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, shiftLength: v }), () => r))));
166
+ }) }));
167
+ }),
168
+ },
169
+ }, variant: "line", striped: true }), _jsx(Diff, { bindings: [roster.binding], hideUnchanged: some(true) })] }) }));
170
+ } }));
171
+ }),
172
+ inputs: [],
173
+ });
174
+ // ============================================================================
175
+ // 4. Pricing-rules editor — sliders + integer/string inputs together;
176
+ // side-by-side Diff mode for a wider review surface.
177
+ // ============================================================================
178
+ export const pricingRulesEditor = example({
179
+ keywords: ["Diff", "side-by-side", "Slider", "Input", "pricing", "discount", "mixed"],
180
+ description: "Pricing rules editor — sliders for list price/discount, IntegerInput for min order qty, StringInput for currency; Diff in side-by-side mode",
181
+ fn: East.function([], UIComponentType, (_$) => {
182
+ return (_jsx(Reactive, { children: $ => {
183
+ const listPrice = $.let(Data.bind([FloatType], listPriceInput.path));
184
+ const discountPct = $.let(Data.bind([FloatType], discountPctInput.path));
185
+ const minOrderQty = $.let(Data.bind([IntegerType], minOrderQtyInput.path));
186
+ const currency = $.let(Data.bind([StringType], currencyCodeInput.path));
187
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Pricing rules" }), _jsx(Text, { children: "Stage pricing changes \u2014 review side-by-side before applying to the catalog." }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "List price" }), _jsx(Slider, { value: listPrice.read(), min: 0.0, max: 999.95, step: 0.05, onChangeEnd: ($, v) => $(listPrice.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Discount (%)" }), _jsx(Slider, { value: discountPct.read(), min: 0.0, max: 75.0, step: 0.5, onChangeEnd: ($, v) => $(discountPct.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Minimum order quantity" }), _jsx(Input.Integer, { value: minOrderQty.read(), min: 1n, max: 1000n, onChange: ($, v) => $(minOrderQty.write(v)) })] }), _jsxs(VStack, { gap: "1", children: [_jsx(Text, { textStyle: "label-sm", children: "Currency code" }), _jsx(Input.String, { value: currency.read(), placeholder: "AUD", onChange: ($, v) => $(currency.write(v)) })] }), _jsx(Diff, { bindings: [listPrice.binding, discountPct.binding, minOrderQty.binding, currency.binding], hideUnchanged: some(true) })] }) }));
188
+ } }));
189
+ }),
190
+ inputs: [],
191
+ });
192
+ // ============================================================================
193
+ // 5. Feature flags editor — Set<String> binding; Switch per known flag.
194
+ // Demonstrates Set insert/delete patches in the Diff.
195
+ // ============================================================================
196
+ export const featureFlagsEditor = example({
197
+ keywords: ["Diff", "Set", "Switch", "feature flags", "bindStaged"],
198
+ description: "Feature-flags editor — Switch per known flag toggles inclusion in a staged Set; Diff shows insertions / deletions",
199
+ fn: East.function([], UIComponentType, (_$) => {
200
+ return (_jsx(Reactive, { children: $ => {
201
+ const flags = $.let(Data.bind([SetType(StringType)], featureFlagsInput.path));
202
+ const flagsRead = $.let(flags.read(), SetType(StringType));
203
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Feature flags" }), _jsx(Text, { children: "Toggle flags to stage changes; Diff card below shows the set delta." }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "dark_mode" }), _jsx(Switch, { checked: flagsRead.has("dark_mode"), onChange: East.function([BooleanType], NullType, ($, isOn) => {
204
+ const next = $.let(flags.read(), SetType(StringType));
205
+ $.if(isOn, $ => { $(next.insert("dark_mode")); }).else($ => { $(next.delete("dark_mode")); });
206
+ $(flags.write(next));
207
+ }) })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "experiments" }), _jsx(Switch, { checked: flagsRead.has("experiments"), onChange: East.function([BooleanType], NullType, ($, isOn) => {
208
+ const next = $.let(flags.read(), SetType(StringType));
209
+ $.if(isOn, $ => { $(next.insert("experiments")); }).else($ => { $(next.delete("experiments")); });
210
+ $(flags.write(next));
211
+ }) })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "notifications" }), _jsx(Switch, { checked: flagsRead.has("notifications"), onChange: East.function([BooleanType], NullType, ($, isOn) => {
212
+ const next = $.let(flags.read(), SetType(StringType));
213
+ $.if(isOn, $ => { $(next.insert("notifications")); }).else($ => { $(next.delete("notifications")); });
214
+ $(flags.write(next));
215
+ }) })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "analytics" }), _jsx(Switch, { checked: flagsRead.has("analytics"), onChange: East.function([BooleanType], NullType, ($, isOn) => {
216
+ const next = $.let(flags.read(), SetType(StringType));
217
+ $.if(isOn, $ => { $(next.insert("analytics")); }).else($ => { $(next.delete("analytics")); });
218
+ $(flags.write(next));
219
+ }) })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "ai_assist" }), _jsx(Switch, { checked: flagsRead.has("ai_assist"), onChange: East.function([BooleanType], NullType, ($, isOn) => {
220
+ const next = $.let(flags.read(), SetType(StringType));
221
+ $.if(isOn, $ => { $(next.insert("ai_assist")); }).else($ => { $(next.delete("ai_assist")); });
222
+ $(flags.write(next));
223
+ }) })] }), _jsx(Diff, { bindings: [flags.binding], hideUnchanged: some(true) })] }) }));
224
+ } }));
225
+ }),
226
+ inputs: [],
227
+ });
228
+ // ============================================================================
229
+ // 6. Regional pricing editor — Dict<String, Float>; Input per known key.
230
+ // Demonstrates Dict update patches per key in the Diff.
231
+ // ============================================================================
232
+ export const regionalPricingEditor = example({
233
+ keywords: ["Diff", "Dict", "Input", "regional pricing", "bindStaged"],
234
+ description: "Regional-pricing editor — Input.Float per region writes back to a staged Dict; Diff shows per-key updates",
235
+ fn: East.function([], UIComponentType, (_$) => {
236
+ return (_jsx(Reactive, { children: $ => {
237
+ const prices = $.let(Data.bind([DictType(StringType, FloatType)], regionalPricesInput.path));
238
+ const pricesRead = $.let(prices.read(), DictType(StringType, FloatType));
239
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Regional pricing" }), _jsx(Text, { children: "Edit per-region prices; Diff card below tracks pending updates." }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "AU" }), _jsx(Input.Float, { value: pricesRead.get("AU", East.function([StringType], FloatType, _$ => 0.0)), min: 0.0, max: 99999.0, step: 0.05, onChange: East.function([FloatType], NullType, ($, newPrice) => {
240
+ const next = $.let(prices.read(), DictType(StringType, FloatType));
241
+ $(next.insertOrUpdate("AU", newPrice));
242
+ $(prices.write(next));
243
+ }) })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "US" }), _jsx(Input.Float, { value: pricesRead.get("US", East.function([StringType], FloatType, _$ => 0.0)), min: 0.0, max: 99999.0, step: 0.05, onChange: East.function([FloatType], NullType, ($, newPrice) => {
244
+ const next = $.let(prices.read(), DictType(StringType, FloatType));
245
+ $(next.insertOrUpdate("US", newPrice));
246
+ $(prices.write(next));
247
+ }) })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "EU" }), _jsx(Input.Float, { value: pricesRead.get("EU", East.function([StringType], FloatType, _$ => 0.0)), min: 0.0, max: 99999.0, step: 0.05, onChange: East.function([FloatType], NullType, ($, newPrice) => {
248
+ const next = $.let(prices.read(), DictType(StringType, FloatType));
249
+ $(next.insertOrUpdate("EU", newPrice));
250
+ $(prices.write(next));
251
+ }) })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "JP" }), _jsx(Input.Float, { value: pricesRead.get("JP", East.function([StringType], FloatType, _$ => 0.0)), min: 0.0, max: 99999.0, step: 0.05, onChange: East.function([FloatType], NullType, ($, newPrice) => {
252
+ const next = $.let(prices.read(), DictType(StringType, FloatType));
253
+ $(next.insertOrUpdate("JP", newPrice));
254
+ $(prices.write(next));
255
+ }) })] }), _jsx(Diff, { bindings: [prices.binding], hideUnchanged: some(true) })] }) }));
256
+ } }));
257
+ }),
258
+ inputs: [],
259
+ });
260
+ // ============================================================================
261
+ // 7. Deployment status editor — Variant binding; one Button per status.
262
+ // Demonstrates Variant tag changes in the Diff.
263
+ // ============================================================================
264
+ export const deploymentStatusEditor = example({
265
+ keywords: ["Diff", "Variant", "Button", "deployment status", "bindStaged"],
266
+ description: "Deployment-status editor — buttons set a Variant binding; Diff shows the status tag change",
267
+ fn: East.function([], UIComponentType, (_$) => {
268
+ return (_jsx(Reactive, { children: $ => {
269
+ const status = $.let(Data.bind([DeploymentStatusType], deploymentStatusInput.path));
270
+ const statusRead = $.let(status.read(), DeploymentStatusType);
271
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Deployment status" }), _jsx(Text, { children: "Current:" }), _jsx(Text, { textStyle: "label-md", children: statusRead.getTag() }), _jsxs(HStack, { gap: "2", children: [_jsx(Button, { onClick: East.function([], NullType, $ => $(status.write(variant("pending", null)))), children: "Pending" }), _jsx(Button, { onClick: East.function([], NullType, $ => $(status.write(variant("in_progress", null)))), children: "In progress" }), _jsx(Button, { onClick: East.function([], NullType, $ => $(status.write(variant("complete", null)))), children: "Complete" }), _jsx(Button, { onClick: East.function([], NullType, $ => $(status.write(variant("failed", null)))), children: "Failed" })] }), _jsx(Diff, { bindings: [status.binding], hideUnchanged: some(true) })] }) }));
272
+ } }));
273
+ }),
274
+ inputs: [],
275
+ });
276
+ // ============================================================================
277
+ // 8. Minimal call site — defaults only (used by IR-roundtrip + smoke tests)
278
+ // ============================================================================
279
+ export const diffDefaults = example({
280
+ keywords: ["Diff", "Root", "defaults", "minimal"],
281
+ description: "Minimal Diff — single binding, all options omitted (defaults from IR)",
282
+ fn: East.function([], UIComponentType, (_$) => {
283
+ return (_jsx(Reactive, { children: $ => {
284
+ const view = $.let(Data.bind([FloatType], maxWeeklyHoursInput.path));
285
+ return _jsx(Diff, { bindings: [view.binding] });
286
+ } }));
287
+ }),
288
+ inputs: [],
289
+ });
290
+ // ============================================================================
291
+ // Merge-conflict demo — bindStaged for the user's edit + bindDirect on the
292
+ // SAME path for a "simulate concurrent edit" button. Clicking the button
293
+ // writes a different value through the live cache, so the staged buffer's
294
+ // pinned snapshot drifts away from the current server value. Hitting Apply
295
+ // on the Diff card then triggers the orange chooser flow.
296
+ // ============================================================================
297
+ /**
298
+ * Demonstrates the staged-mode merge tool / orange chooser. Workflow:
299
+ *
300
+ * 1. Drag the slider — your edit gets staged (snapshot pinned in StagedStore).
301
+ * 2. Click "Simulate concurrent edit" — `Data.bind.write(42.0)` writes 42 to
302
+ * the same path through the live cache, mimicking another session
303
+ * committing while you have edits open. Server view is now 42; your
304
+ * pinned snapshot is still 38; your buffer is whatever you dragged to.
305
+ * 3. Click Apply — `detectConflictsFor(userPatch, serverPatch)` finds both
306
+ * sides touching the root, switches the renderer to conflict mode, and
307
+ * shows the orange chooser row: keep yours (your dragged value), keep
308
+ * theirs (42), or manual (type a fresh number).
309
+ */
310
+ export const mergeConflictDemo = example({
311
+ keywords: ["Diff", "merge", "conflict", "chooser", "bindStaged", "Slider"],
312
+ description: "Demo of the merge tool's orange chooser — drag, click Simulate, then Apply",
313
+ fn: East.function([], UIComponentType, (_$) => {
314
+ return (_jsx(Reactive, { children: $ => {
315
+ const staged = $.let(Data.bind([FloatType], mergeDemoHoursInput.path));
316
+ const direct = $.let(Data.bind([FloatType], mergeDemoHoursInput.path, { mode: "direct" }));
317
+ const stagedValue = $.let(staged.read(), FloatType);
318
+ const serverValue = $.let(direct.read(), FloatType);
319
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Merge-conflict demo" }), _jsx(Text, { children: "1. Drag the slider — your edit lands in the StagedStore (snapshot pinned). "
320
+ + "2. Click \"Simulate concurrent edit\" — writes 42 through the live cache, "
321
+ + "mimicking another session committing while you have edits open. "
322
+ + "3. Click Apply on the Diff card — the merge tool detects drift and fires "
323
+ + "the orange chooser row." }), _jsxs(VStack, { gap: "2", children: [_jsx(Text, { textStyle: "label-sm", children: "Server (live cache):" }), _jsx(Text, { children: East.str `${serverValue}` })] }), _jsxs(VStack, { gap: "2", children: [_jsx(Text, { textStyle: "label-sm", children: "Your staged value:" }), _jsx(Text, { children: East.str `${stagedValue}` })] }), _jsx(Slider, { value: stagedValue, min: 30.0, max: 60.0, step: 1.0, onChangeEnd: ($, v) => $(staged.write(v)) }), _jsxs(VStack, { gap: "2", children: [_jsx(Button, { onClick: $ => $(direct.write(42.0)), children: "Simulate concurrent edit (server \u2190 42)" }), _jsx(Button, { onClick: $ => $(direct.write(38.0)), children: "Reset server to 38" })] }), _jsx(Diff, { bindings: [staged.binding], hideUnchanged: some(true) })] }) }));
324
+ } }));
325
+ }),
326
+ inputs: [],
327
+ });
328
+ // ============================================================================
329
+ // Density variants — same pricing-rules content rendered at the two
330
+ // non-default density presets, so the showcase can compare side-by-side
331
+ // against the default (`pricingRulesEditor` above).
332
+ // ============================================================================
333
+ /**
334
+ * Pricing-rules editor at `compact` density — tighter row padding and smaller
335
+ * type scale than the default `comfortable`. Suited to data-dense pages where
336
+ * the Diff card is one of several panels competing for vertical space.
337
+ */
338
+ export const pricingRulesEditorCompact = example({
339
+ keywords: ["Diff", "density", "compact", "Slider", "Input", "pricing"],
340
+ description: "Pricing-rules editor with `density: \"compact\"` — same content as pricingRulesEditor, denser rows",
341
+ fn: East.function([], UIComponentType, (_$) => {
342
+ return (_jsx(Reactive, { children: $ => {
343
+ const listPrice = $.let(Data.bind([FloatType], listPriceInput.path));
344
+ const discountPct = $.let(Data.bind([FloatType], discountPctInput.path));
345
+ const minOrderQty = $.let(Data.bind([IntegerType], minOrderQtyInput.path));
346
+ const currency = $.let(Data.bind([StringType], currencyCodeInput.path));
347
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Pricing rules \u2014 compact" }), _jsx(Slider, { value: listPrice.read(), min: 0.0, max: 999.95, step: 0.05, onChangeEnd: ($, v) => $(listPrice.write(v)) }), _jsx(Slider, { value: discountPct.read(), min: 0.0, max: 75.0, step: 0.5, onChangeEnd: ($, v) => $(discountPct.write(v)) }), _jsx(Input.Integer, { value: minOrderQty.read(), min: 1n, max: 1000n, onChange: ($, v) => $(minOrderQty.write(v)) }), _jsx(Input.String, { value: currency.read(), placeholder: "AUD", onChange: ($, v) => $(currency.write(v)) }), _jsx(Diff, { bindings: [listPrice.binding, discountPct.binding, minOrderQty.binding, currency.binding], density: "compact", hideUnchanged: some(true) })] }) }));
348
+ } }));
349
+ }),
350
+ inputs: [],
351
+ });
352
+ /**
353
+ * Pricing-rules editor at `condensed` density — mission-control sizing.
354
+ * Tightest row padding and smallest type scale; pairs with status dashboards
355
+ * and other read-heavy contexts where a diff list is reference data, not the
356
+ * main interaction surface.
357
+ */
358
+ export const pricingRulesEditorCondensed = example({
359
+ keywords: ["Diff", "density", "condensed", "Slider", "Input", "pricing"],
360
+ description: "Pricing-rules editor with `density: \"condensed\"` — mission-control sizing for read-heavy views",
361
+ fn: East.function([], UIComponentType, (_$) => {
362
+ return (_jsx(Reactive, { children: $ => {
363
+ const listPrice = $.let(Data.bind([FloatType], listPriceInput.path));
364
+ const discountPct = $.let(Data.bind([FloatType], discountPctInput.path));
365
+ const minOrderQty = $.let(Data.bind([IntegerType], minOrderQtyInput.path));
366
+ const currency = $.let(Data.bind([StringType], currencyCodeInput.path));
367
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Pricing rules \u2014 condensed" }), _jsx(Slider, { value: listPrice.read(), min: 0.0, max: 999.95, step: 0.05, onChangeEnd: ($, v) => $(listPrice.write(v)) }), _jsx(Slider, { value: discountPct.read(), min: 0.0, max: 75.0, step: 0.5, onChangeEnd: ($, v) => $(discountPct.write(v)) }), _jsx(Input.Integer, { value: minOrderQty.read(), min: 1n, max: 1000n, onChange: ($, v) => $(minOrderQty.write(v)) }), _jsx(Input.String, { value: currency.read(), placeholder: "AUD", onChange: ($, v) => $(currency.write(v)) }), _jsx(Diff, { bindings: [listPrice.binding, discountPct.binding, minOrderQty.binding, currency.binding], density: "condensed", hideUnchanged: some(true) })] }) }));
368
+ } }));
369
+ }),
370
+ inputs: [],
371
+ });
372
+ // ============================================================================
373
+ // Overlay-mode bindings — patches stored in a sibling `e3.input` typed
374
+ // `PatchType(T)`. The Diff component surfaces them via the `overlay` option
375
+ // instead of `staged`. See `Data.bindOverlay`.
376
+ // ============================================================================
377
+ // Patch inputs for overlay-mode examples. Each defaults to `unchanged`.
378
+ export const maxWeeklyHoursPatchInput = e3.input("max_weekly_hours_patch", PatchType(FloatType), variant("unchanged", null));
379
+ export const regionalPricesPatchInput = e3.input("regional_prices_patch", PatchType(DictType(StringType, FloatType)), variant("unchanged", null));
380
+ export const rosterPatchInput = e3.input("roster_patch", PatchType(RosterArrayType), variant("unchanged", null));
381
+ // Drift-laden patch input — defaults to a non-trivial patch whose ops are
382
+ // stale relative to the source dict `{AU: 49.95, US: 39.95, EU: 44.95, JP:
383
+ // 5499.0}`. Used by `regionalPricingOverlayDrift` to demonstrate what the
384
+ // Diff card surfaces when a server-stored patch was authored against an
385
+ // older version of its source. Conflicts (per `apply.ts` semantics):
386
+ // - `delete "MX"` — key not in source → stale delete
387
+ // - `insert "AU"` — key already exists in source → stale insert
388
+ // - `update "US"` with `replace(before=30 → 25)` — before mismatches source's 39.95
389
+ // - `update "EU"` with `replace(before=44.95 → 39.95)` — clean (for contrast)
390
+ export const regionalPricesDriftPatchInput = e3.input("regional_prices_drift_patch", PatchType(DictType(StringType, FloatType)), variant("patch", new Map([
391
+ ["MX", variant("delete", 99.0)],
392
+ ["AU", variant("insert", 100.0)],
393
+ ["US", variant("update", variant("replace", { before: 30.0, after: 25.0 }))],
394
+ ["EU", variant("update", variant("replace", { before: 44.95, after: 39.95 }))],
395
+ ])));
396
+ // Roster overlay drift — a patch over the array-of-structs source. Built with
397
+ // `diffFor` (base matches the bound source, so ops are clean) so the Diff card
398
+ // exercises its nested grouping: binding → array index → struct field. Only
399
+ // the `rate` of entries 0 and 1 change, producing `[0] → rate`, `[1] → rate`.
400
+ const rosterDriftBase = [
401
+ { id: "alice", name: "Alice Chen", rate: 32.50, shiftLength: 8n },
402
+ { id: "bob", name: "Bob Romero", rate: 28.00, shiftLength: 8n },
403
+ { id: "charlie", name: "Charlie Patel", rate: 35.75, shiftLength: 10n },
404
+ { id: "diana", name: "Diana Wallace", rate: 30.25, shiftLength: 8n },
405
+ ];
406
+ const rosterDriftEdited = [
407
+ { id: "alice", name: "Alice Chen", rate: 6.00, shiftLength: 8n },
408
+ { id: "bob", name: "Bob Romero", rate: 29.00, shiftLength: 8n },
409
+ { id: "charlie", name: "Charlie Patel", rate: 35.75, shiftLength: 10n },
410
+ { id: "diana", name: "Diana Wallace", rate: 30.25, shiftLength: 8n },
411
+ ];
412
+ export const rosterDriftPatchInput = e3.input("roster_drift_patch", PatchType(RosterArrayType), diffFor(RosterArrayType)(rosterDriftBase, rosterDriftEdited));
413
+ /**
414
+ * Single-Float overlay editor — Slider edits go to `max_weekly_hours_patch`,
415
+ * the Diff card surfaces the patch against the source.
416
+ */
417
+ export const policyOverlayEditor = example({
418
+ keywords: ["Diff", "bindOverlay", "Slider", "overlay", "policy", "patch"],
419
+ description: "Overlay-mode editor — Slider writes patches to a sibling e3.input; Diff shows them",
420
+ fn: East.function([], UIComponentType, (_$) => {
421
+ return (_jsx(Reactive, { children: $ => {
422
+ const view = $.let(Data.bind([FloatType], maxWeeklyHoursInput.path, { mode: "direct", patch: maxWeeklyHoursPatchInput.path }));
423
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Max weekly hours (overlay)" }), _jsx(Slider, { value: view.read(), min: 30.0, max: 60.0, step: 1.0, onChangeEnd: ($, v) => $(view.write(v)) }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
424
+ } }));
425
+ }),
426
+ inputs: [],
427
+ });
428
+ /**
429
+ * Overlay binding whose patch input *starts* with a non-trivial patch that
430
+ * is stale relative to the source. Demonstrates what the Diff card displays
431
+ * when a server-stored patch was authored against an older revision of its
432
+ * source — stale delete, stale insert, stale replace.
433
+ *
434
+ * No form components: `view.read()` calls `apply(source, patch)`, which
435
+ * throws `ConflictError` on the stale ops. The Diff card walks the patch IR
436
+ * directly from cache bytes (no apply) so it renders cleanly. The
437
+ * `bindOverlay` call is kept so the renderer's overlay-type registry knows
438
+ * how to decode the patch bytes for this binding.
439
+ */
440
+ export const regionalPricingOverlayDrift = example({
441
+ keywords: ["Diff", "bindOverlay", "Dict", "conflict", "drift", "patch"],
442
+ description: "Overlay-mode example with a stale patch — Diff card surfaces ops that don't match the source",
443
+ fn: East.function([], UIComponentType, (_$) => {
444
+ return (_jsx(Reactive, { children: $ => {
445
+ const view = $.let(Data.bind([DictType(StringType, FloatType)], regionalPricesInput.path, { mode: "direct", patch: regionalPricesDriftPatchInput.path }));
446
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Regional pricing \u2014 overlay with stale patch" }), _jsx(Text, { children: "The patch input was authored against an older source. The Diff card below "
447
+ + "shows: a stale delete (MX missing from source), a stale insert (AU already "
448
+ + "exists), a stale replace (US before=30 doesn't match current 39.95), and "
449
+ + "one clean replace (EU 44.95 → 39.95). Apply would throw ConflictError on "
450
+ + "the stale ops; this example exists to show what the Diff renderer surfaces "
451
+ + "when a server-stored patch has drifted from its source." }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
452
+ } }));
453
+ }),
454
+ inputs: [],
455
+ });
456
+ /**
457
+ * Roster overlay drift — array-of-structs patch surfaced by the Diff card,
458
+ * exercising nested grouping (binding → `[index]` → struct field). The patch
459
+ * touches only `rate` on the first two entries, so the card renders
460
+ * `ROSTER → [0] → rate`, `[1] → rate`.
461
+ */
462
+ export const rosterOverlayDrift = example({
463
+ keywords: ["Diff", "overlay", "roster", "array", "nested", "patch"],
464
+ description: "Overlay-mode roster patch — Diff card surfaces nested array-element field changes",
465
+ fn: East.function([], UIComponentType, (_$) => {
466
+ return (_jsx(Reactive, { children: $ => {
467
+ const view = $.let(Data.bind([RosterArrayType], rosterInput.path, { mode: "direct", patch: rosterDriftPatchInput.path }));
468
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Roster \u2014 overlay patch (nested)" }), _jsx(Text, { children: "The patch changes the hourly rate of the first two roster entries. The "
469
+ + "Diff card groups each change under its array index, demonstrating the "
470
+ + "binding → [index] → field nesting." }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
471
+ } }));
472
+ }),
473
+ inputs: [],
474
+ });
475
+ /**
476
+ * Roster table editor in overlay mode — patches stored in `roster_patch`,
477
+ * survive page reload and are visible to other workspace sessions.
478
+ */
479
+ export const rosterTableEditorOverlay = example({
480
+ keywords: ["Diff", "Table", "bindOverlay", "patch", "overlay", "roster"],
481
+ description: "Editable table backed by a separate patch e3.input — patches persist across sessions",
482
+ fn: East.function([], UIComponentType, (_$) => {
483
+ return (_jsx(Reactive, { children: $ => {
484
+ const view = $.let(Data.bind([RosterArrayType], rosterInput.path, { mode: "direct", patch: rosterPatchInput.path }));
485
+ const rosterArray = $.let(view.read(), RosterArrayType);
486
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Worker roster (overlay-mode)" }), _jsx(Text, { children: "Patches stored in a sibling dataset \u2014 survive reload, visible to other sessions." }), _jsx(Table, { data: rosterArray, columns: {
487
+ name: { header: "Name" },
488
+ rate: {
489
+ header: "Hourly rate ($)",
490
+ render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
491
+ const idx = $.let(ctx.rowIndex, IntegerType);
492
+ const row = $.let(rosterArray.get(idx), RosterEntryType);
493
+ return (_jsx(Input.Float, { value: row.rate, min: 15.0, max: 80.0, step: 0.25, onChange: East.function([FloatType], NullType, ($, v) => {
494
+ const fresh = $.let(view.read(), RosterArrayType);
495
+ const next = $.let(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, rate: v }), _$ => r)), RosterArrayType);
496
+ $(view.write(next));
497
+ }) }));
498
+ }),
499
+ },
500
+ shiftLength: {
501
+ header: "Shift length (h)",
502
+ render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
503
+ const idx = $.let(ctx.rowIndex, IntegerType);
504
+ const row = $.let(rosterArray.get(idx), RosterEntryType);
505
+ return (_jsx(Input.Integer, { value: row.shiftLength, min: 4n, max: 12n, onChange: East.function([IntegerType], NullType, ($, v) => {
506
+ const fresh = $.let(view.read(), RosterArrayType);
507
+ const next = $.let(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, shiftLength: v }), _$ => r)), RosterArrayType);
508
+ $(view.write(next));
509
+ }) }));
510
+ }),
511
+ },
512
+ }, variant: "line", striped: true }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
513
+ } }));
514
+ }),
515
+ inputs: [],
516
+ });
517
+ // ============================================================================
518
+ // Staged + patch dataset — the fourth mode. Edits buffer locally (IndexedDB)
519
+ // while the user iterates; commit publishes a fresh patch IR to the patch
520
+ // dataset (the source is not touched until a separate apply step). Pairs
521
+ // well with reviewer / approval workflows where the patch dataset becomes
522
+ // the unit of review.
523
+ // ============================================================================
524
+ /**
525
+ * Single-Float staged-with-patch editor — buffered Slider edits publish to
526
+ * `max_weekly_hours_patch` on Apply. The source `max_weekly_hours` stays
527
+ * untouched until a separate apply-patch-to-source step.
528
+ */
529
+ export const policyStagedPatchEditor = example({
530
+ keywords: ["Diff", "Slider", "staged", "patch", "publish", "policy"],
531
+ description: "Slider edits buffered locally; Apply publishes draft to a server-backed patch dataset",
532
+ fn: East.function([], UIComponentType, (_$) => {
533
+ return (_jsx(Reactive, { children: $ => {
534
+ const view = $.let(Data.bind([FloatType], maxWeeklyHoursInput.path, { mode: "staged", patch: maxWeeklyHoursPatchInput.path }));
535
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Max weekly hours (staged + patch)" }), _jsx(Text, { children: "Drag to buffer locally; Apply publishes the draft as a patch to the patch dataset (source untouched)." }), _jsx(Slider, { value: view.read(), min: 30.0, max: 60.0, step: 1.0, onChange: ($, v) => $(view.write(v)) }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
536
+ } }));
537
+ }),
538
+ inputs: [],
539
+ });
540
+ /**
541
+ * Roster table editor in staged + patch mode. Cell edits buffer in
542
+ * IndexedDB until Apply, which publishes a fresh patch to `roster_patch`.
543
+ * Survives reload as a draft; multi-session reviewers see the patch only
544
+ * after the author commits.
545
+ */
546
+ export const rosterStagedPatchEditor = example({
547
+ keywords: ["Diff", "Table", "staged", "patch", "publish", "roster"],
548
+ description: "Editable roster — edits buffered locally; Apply publishes a fresh patch to a server-backed patch dataset",
549
+ fn: East.function([], UIComponentType, (_$) => {
550
+ return (_jsx(Reactive, { children: $ => {
551
+ const view = $.let(Data.bind([RosterArrayType], rosterInput.path, { mode: "staged", patch: rosterPatchInput.path }));
552
+ const rosterArray = $.let(view.read(), RosterArrayType);
553
+ return (_jsx(Card, { children: _jsxs(VStack, { gap: "5", align: "stretch", children: [_jsx(Text, { textStyle: "heading-md", children: "Worker roster (staged + patch)" }), _jsx(Text, { children: "Edits buffer locally until Apply, which publishes a draft patch to the patch dataset for review." }), _jsx(Table, { data: rosterArray, columns: {
554
+ name: { header: "Name" },
555
+ rate: {
556
+ header: "Hourly rate ($)",
557
+ render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
558
+ const idx = $.let(ctx.rowIndex, IntegerType);
559
+ const row = $.let(rosterArray.get(idx), RosterEntryType);
560
+ return (_jsx(Input.Float, { value: row.rate, min: 15.0, max: 80.0, step: 0.25, onChange: East.function([FloatType], NullType, ($, v) => {
561
+ const fresh = $.let(view.read(), RosterArrayType);
562
+ $(view.write(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, rate: v }), () => r))));
563
+ }) }));
564
+ }),
565
+ },
566
+ shiftLength: {
567
+ header: "Shift length (h)",
568
+ render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
569
+ const idx = $.let(ctx.rowIndex, IntegerType);
570
+ const row = $.let(rosterArray.get(idx), RosterEntryType);
571
+ return (_jsx(Input.Integer, { value: row.shiftLength, min: 4n, max: 12n, onChange: East.function([IntegerType], NullType, ($, v) => {
572
+ const fresh = $.let(view.read(), RosterArrayType);
573
+ $(view.write(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, shiftLength: v }), () => r))));
574
+ }) }));
575
+ }),
576
+ },
577
+ }, variant: "line", striped: true }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
578
+ } }));
579
+ }),
580
+ inputs: [],
581
+ });
582
+ //# sourceMappingURL=diff.examples.js.map