@elaraai/e3-ui 1.0.59 → 1.0.61
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/dist/test/bind/data/data.examples.d.ts +2 -7
- package/dist/test/bind/data/data.examples.d.ts.map +1 -1
- package/dist/test/bind/data/data.examples.js +50 -80
- package/dist/test/bind/data/data.examples.js.map +1 -1
- package/dist/test/decision/queue.examples.d.ts +2 -5
- package/dist/test/decision/queue.examples.d.ts.map +1 -1
- package/dist/test/decision/queue.examples.js +48 -72
- package/dist/test/decision/queue.examples.js.map +1 -1
- package/dist/test/diff/diff.examples.d.ts +33 -61
- package/dist/test/diff/diff.examples.d.ts.map +1 -1
- package/dist/test/diff/diff.examples.js +200 -317
- package/dist/test/diff/diff.examples.js.map +1 -1
- package/dist/test/experiment/experiment.examples.d.ts +7 -9
- package/dist/test/experiment/experiment.examples.d.ts.map +1 -1
- package/dist/test/experiment/experiment.examples.js +56 -68
- package/dist/test/experiment/experiment.examples.js.map +1 -1
- package/package.json +8 -8
|
@@ -10,11 +10,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "@elaraai/e3-ui/jsx-runtime";
|
|
|
10
10
|
* surfacing the pending changes for sign-off.
|
|
11
11
|
*
|
|
12
12
|
* Coverage:
|
|
13
|
-
* 1. Slider-driven editor
|
|
14
|
-
* 2.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* 1. Slider-driven editor → workforcePolicyEditor
|
|
14
|
+
* 2. Editor variants panel → diffEditorVariants (heterogeneous inputs /
|
|
15
|
+
* mixed sliders + inputs / Set / Dict / Variant / density presets)
|
|
16
|
+
* 3. Editable Table cells → rosterTableEditor
|
|
17
|
+
* 4. Minimal call site → diffDefaults (IR-roundtrip)
|
|
18
|
+
* 5. Merge-conflict chooser → mergeConflictDemo
|
|
19
|
+
* 6. Overlay-mode patches → diffOverlayVariants
|
|
20
|
+
* 7. Staged + patch datasets → diffStagedPatchVariants
|
|
18
21
|
*
|
|
19
22
|
* Pattern:
|
|
20
23
|
* 1. Declare an `e3.input(name, type, default)` per editable scalar.
|
|
@@ -25,7 +28,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "@elaraai/e3-ui/jsx-runtime";
|
|
|
25
28
|
* the merged batch; Discard drops the buffer.
|
|
26
29
|
*/
|
|
27
30
|
import { East, FloatType, IntegerType, StringType, BooleanType, DateTimeType, ArrayType, StructType, SetType, DictType, VariantType, NullType, FunctionType, 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";
|
|
31
|
+
import { Card, HStack, VStack, Slider, Input, Switch, Select, Separator, Text, Button, Reactive, Table, UIComponentType, } from "@elaraai/east-ui";
|
|
29
32
|
import { Data, Diff } from "@elaraai/e3-ui";
|
|
30
33
|
import * as e3 from "@elaraai/e3";
|
|
31
34
|
// ============================================================================
|
|
@@ -102,25 +105,84 @@ export const workforcePolicyEditor = example({
|
|
|
102
105
|
inputs: [],
|
|
103
106
|
});
|
|
104
107
|
// ============================================================================
|
|
105
|
-
// 2.
|
|
106
|
-
//
|
|
108
|
+
// 2. Editor variants panel — the type-coverage enumeration: heterogeneous
|
|
109
|
+
// scalar inputs (String / Integer / Bool / DateTime / Select), mixed
|
|
110
|
+
// sliders + inputs (side-by-side Diff), Set / Dict / Variant bindings,
|
|
111
|
+
// and the two non-default density presets.
|
|
107
112
|
// ============================================================================
|
|
108
|
-
export const
|
|
109
|
-
keywords: ["Diff", "Input", "Switch", "Select", "DateTime", "Toast", "onCommitted"],
|
|
110
|
-
description: "
|
|
113
|
+
export const diffEditorVariants = example({
|
|
114
|
+
keywords: ["Diff", "Input", "Switch", "Select", "DateTime", "Toast", "onCommitted", "side-by-side", "Slider", "pricing", "discount", "mixed", "Set", "feature flags", "bindStaged", "Dict", "regional pricing", "Variant", "Button", "deployment status", "density", "compact", "condensed"],
|
|
115
|
+
description: "Editor variant panel — SERVICE CONFIG FORM: heterogeneous String / Integer / Bool / DateTime / Select inputs, commit fires a success Toast; PRICING RULES: sliders for list price/discount, IntegerInput for min order qty, StringInput for currency, Diff in side-by-side mode; FEATURE FLAGS: Switch per known flag toggles inclusion in a staged Set, Diff shows insertions / deletions; REGIONAL PRICING: Input.Float per region writes back to a staged Dict, Diff shows per-key updates; DEPLOYMENT STATUS: buttons set a Variant binding, Diff shows the status tag change; PRICING RULES COMPACT: `density: \"compact\"` — denser rows; PRICING RULES CONDENSED: `density: \"condensed\"` — mission-control sizing for read-heavy views",
|
|
111
116
|
fn: East.function([], UIComponentType, (_$) => {
|
|
112
|
-
return (_jsx(Reactive, { children: $ => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
return (_jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Separator, { label: "SERVICE CONFIG FORM", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
118
|
+
const svcName = $.let(Data.bind(serviceNameInput, { mode: "staged" }));
|
|
119
|
+
const replicas = $.let(Data.bind(replicasInput, { mode: "staged" }));
|
|
120
|
+
const autoScale = $.let(Data.bind(autoScaleInput, { mode: "staged" }));
|
|
121
|
+
const region = $.let(Data.bind(regionInput, { mode: "staged" }));
|
|
122
|
+
const deployAfter = $.let(Data.bind(deployAfterInput, { mode: "staged" }));
|
|
123
|
+
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: [
|
|
124
|
+
Select.Item("ap-southeast-2", "ap-southeast-2 (Sydney)"),
|
|
125
|
+
Select.Item("us-east-1", "us-east-1 (N. Virginia)"),
|
|
126
|
+
Select.Item("eu-west-1", "eu-west-1 (Ireland)"),
|
|
127
|
+
], 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] })] }) }));
|
|
128
|
+
} }), _jsx(Separator, { label: "PRICING RULES", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
129
|
+
const listPrice = $.let(Data.bind(listPriceInput, { mode: "staged" }));
|
|
130
|
+
const discountPct = $.let(Data.bind(discountPctInput, { mode: "staged" }));
|
|
131
|
+
const minOrderQty = $.let(Data.bind(minOrderQtyInput, { mode: "staged" }));
|
|
132
|
+
const currency = $.let(Data.bind(currencyCodeInput, { mode: "staged" }));
|
|
133
|
+
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) })] }) }));
|
|
134
|
+
} }), _jsx(Separator, { label: "FEATURE FLAGS", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
135
|
+
const flags = $.let(Data.bind(featureFlagsInput, { mode: "staged" }));
|
|
136
|
+
const flagsRead = $.let(flags.read(), SetType(StringType));
|
|
137
|
+
// ONE East closure factory: `toggle(flag)` returns the per-switch
|
|
138
|
+
// handler as a real East function value (captures `flag` in East).
|
|
139
|
+
const toggle = $.const(East.function([StringType], FunctionType([BooleanType], NullType), (_$, flag) => East.function([BooleanType], NullType, ($, isOn) => {
|
|
140
|
+
const next = $.let(flags.read(), SetType(StringType));
|
|
141
|
+
$.if(isOn, $ => { $(next.insert(flag)); }).else($ => { $(next.delete(flag)); });
|
|
142
|
+
$(flags.write(next));
|
|
143
|
+
})));
|
|
144
|
+
const onDarkMode = $.const(toggle("dark_mode"));
|
|
145
|
+
const onExperiments = $.const(toggle("experiments"));
|
|
146
|
+
const onNotifications = $.const(toggle("notifications"));
|
|
147
|
+
const onAnalytics = $.const(toggle("analytics"));
|
|
148
|
+
const onAiAssist = $.const(toggle("ai_assist"));
|
|
149
|
+
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: onDarkMode })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "experiments" }), _jsx(Switch, { checked: flagsRead.has("experiments"), onChange: onExperiments })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "notifications" }), _jsx(Switch, { checked: flagsRead.has("notifications"), onChange: onNotifications })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "analytics" }), _jsx(Switch, { checked: flagsRead.has("analytics"), onChange: onAnalytics })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "ai_assist" }), _jsx(Switch, { checked: flagsRead.has("ai_assist"), onChange: onAiAssist })] }), _jsx(Diff, { bindings: [flags.binding], hideUnchanged: some(true) })] }) }));
|
|
150
|
+
} }), _jsx(Separator, { label: "REGIONAL PRICING", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
151
|
+
const prices = $.let(Data.bind(regionalPricesInput, { mode: "staged" }));
|
|
152
|
+
const pricesRead = $.let(prices.read(), DictType(StringType, FloatType));
|
|
153
|
+
// ONE East closure factory: `setPrice(region)` returns the
|
|
154
|
+
// per-region handler as a real East function value.
|
|
155
|
+
const setPrice = $.const(East.function([StringType], FunctionType([FloatType], NullType), (_$, region) => East.function([FloatType], NullType, ($, newPrice) => {
|
|
156
|
+
const next = $.let(prices.read(), DictType(StringType, FloatType));
|
|
157
|
+
$(next.insertOrUpdate(region, newPrice));
|
|
158
|
+
$(prices.write(next));
|
|
159
|
+
})));
|
|
160
|
+
const onAu = $.const(setPrice("AU"));
|
|
161
|
+
const onUs = $.const(setPrice("US"));
|
|
162
|
+
const onEu = $.const(setPrice("EU"));
|
|
163
|
+
const onJp = $.const(setPrice("JP"));
|
|
164
|
+
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: onAu })] }), _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: onUs })] }), _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: onEu })] }), _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: onJp })] }), _jsx(Diff, { bindings: [prices.binding], hideUnchanged: some(true) })] }) }));
|
|
165
|
+
} }), _jsx(Separator, { label: "DEPLOYMENT STATUS", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
166
|
+
const status = $.let(Data.bind(deploymentStatusInput, { mode: "staged" }));
|
|
167
|
+
const statusRead = $.let(status.read(), DeploymentStatusType);
|
|
168
|
+
const setPending = $.const(East.function([], NullType, $ => $(status.write(variant("pending", null)))));
|
|
169
|
+
const setInProgress = $.const(East.function([], NullType, $ => $(status.write(variant("in_progress", null)))));
|
|
170
|
+
const setComplete = $.const(East.function([], NullType, $ => $(status.write(variant("complete", null)))));
|
|
171
|
+
const setFailed = $.const(East.function([], NullType, $ => $(status.write(variant("failed", null)))));
|
|
172
|
+
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: setPending, children: "Pending" }), _jsx(Button, { onClick: setInProgress, children: "In progress" }), _jsx(Button, { onClick: setComplete, children: "Complete" }), _jsx(Button, { onClick: setFailed, children: "Failed" })] }), _jsx(Diff, { bindings: [status.binding], hideUnchanged: some(true) })] }) }));
|
|
173
|
+
} }), _jsx(Separator, { label: "PRICING RULES COMPACT", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
174
|
+
const listPrice = $.let(Data.bind(listPriceInput, { mode: "staged" }));
|
|
175
|
+
const discountPct = $.let(Data.bind(discountPctInput, { mode: "staged" }));
|
|
176
|
+
const minOrderQty = $.let(Data.bind(minOrderQtyInput, { mode: "staged" }));
|
|
177
|
+
const currency = $.let(Data.bind(currencyCodeInput, { mode: "staged" }));
|
|
178
|
+
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) })] }) }));
|
|
179
|
+
} }), _jsx(Separator, { label: "PRICING RULES CONDENSED", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
180
|
+
const listPrice = $.let(Data.bind(listPriceInput, { mode: "staged" }));
|
|
181
|
+
const discountPct = $.let(Data.bind(discountPctInput, { mode: "staged" }));
|
|
182
|
+
const minOrderQty = $.let(Data.bind(minOrderQtyInput, { mode: "staged" }));
|
|
183
|
+
const currency = $.let(Data.bind(currencyCodeInput, { mode: "staged" }));
|
|
184
|
+
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) })] }) }));
|
|
185
|
+
} })] }));
|
|
124
186
|
}),
|
|
125
187
|
inputs: [],
|
|
126
188
|
});
|
|
@@ -173,100 +235,7 @@ export const rosterTableEditor = example({
|
|
|
173
235
|
inputs: [],
|
|
174
236
|
});
|
|
175
237
|
// ============================================================================
|
|
176
|
-
// 4.
|
|
177
|
-
// side-by-side Diff mode for a wider review surface.
|
|
178
|
-
// ============================================================================
|
|
179
|
-
export const pricingRulesEditor = example({
|
|
180
|
-
keywords: ["Diff", "side-by-side", "Slider", "Input", "pricing", "discount", "mixed"],
|
|
181
|
-
description: "Pricing rules editor — sliders for list price/discount, IntegerInput for min order qty, StringInput for currency; Diff in side-by-side mode",
|
|
182
|
-
fn: East.function([], UIComponentType, (_$) => {
|
|
183
|
-
return (_jsx(Reactive, { children: $ => {
|
|
184
|
-
const listPrice = $.let(Data.bind(listPriceInput, { mode: "staged" }));
|
|
185
|
-
const discountPct = $.let(Data.bind(discountPctInput, { mode: "staged" }));
|
|
186
|
-
const minOrderQty = $.let(Data.bind(minOrderQtyInput, { mode: "staged" }));
|
|
187
|
-
const currency = $.let(Data.bind(currencyCodeInput, { mode: "staged" }));
|
|
188
|
-
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) })] }) }));
|
|
189
|
-
} }));
|
|
190
|
-
}),
|
|
191
|
-
inputs: [],
|
|
192
|
-
});
|
|
193
|
-
// ============================================================================
|
|
194
|
-
// 5. Feature flags editor — Set<String> binding; Switch per known flag.
|
|
195
|
-
// Demonstrates Set insert/delete patches in the Diff.
|
|
196
|
-
// ============================================================================
|
|
197
|
-
export const featureFlagsEditor = example({
|
|
198
|
-
keywords: ["Diff", "Set", "Switch", "feature flags", "bindStaged"],
|
|
199
|
-
description: "Feature-flags editor — Switch per known flag toggles inclusion in a staged Set; Diff shows insertions / deletions",
|
|
200
|
-
fn: East.function([], UIComponentType, (_$) => {
|
|
201
|
-
return (_jsx(Reactive, { children: $ => {
|
|
202
|
-
const flags = $.let(Data.bind(featureFlagsInput, { mode: "staged" }));
|
|
203
|
-
const flagsRead = $.let(flags.read(), SetType(StringType));
|
|
204
|
-
// ONE East closure factory: `toggle(flag)` returns the per-switch
|
|
205
|
-
// handler as a real East function value (captures `flag` in East).
|
|
206
|
-
const toggle = $.const(East.function([StringType], FunctionType([BooleanType], NullType), (_$, flag) => East.function([BooleanType], NullType, ($, isOn) => {
|
|
207
|
-
const next = $.let(flags.read(), SetType(StringType));
|
|
208
|
-
$.if(isOn, $ => { $(next.insert(flag)); }).else($ => { $(next.delete(flag)); });
|
|
209
|
-
$(flags.write(next));
|
|
210
|
-
})));
|
|
211
|
-
const onDarkMode = $.const(toggle("dark_mode"));
|
|
212
|
-
const onExperiments = $.const(toggle("experiments"));
|
|
213
|
-
const onNotifications = $.const(toggle("notifications"));
|
|
214
|
-
const onAnalytics = $.const(toggle("analytics"));
|
|
215
|
-
const onAiAssist = $.const(toggle("ai_assist"));
|
|
216
|
-
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: onDarkMode })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "experiments" }), _jsx(Switch, { checked: flagsRead.has("experiments"), onChange: onExperiments })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "notifications" }), _jsx(Switch, { checked: flagsRead.has("notifications"), onChange: onNotifications })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "analytics" }), _jsx(Switch, { checked: flagsRead.has("analytics"), onChange: onAnalytics })] }), _jsxs(VStack, { gap: "3", justify: "space-between", children: [_jsx(Text, { textStyle: "label-sm", children: "ai_assist" }), _jsx(Switch, { checked: flagsRead.has("ai_assist"), onChange: onAiAssist })] }), _jsx(Diff, { bindings: [flags.binding], hideUnchanged: some(true) })] }) }));
|
|
217
|
-
} }));
|
|
218
|
-
}),
|
|
219
|
-
inputs: [],
|
|
220
|
-
});
|
|
221
|
-
// ============================================================================
|
|
222
|
-
// 6. Regional pricing editor — Dict<String, Float>; Input per known key.
|
|
223
|
-
// Demonstrates Dict update patches per key in the Diff.
|
|
224
|
-
// ============================================================================
|
|
225
|
-
export const regionalPricingEditor = example({
|
|
226
|
-
keywords: ["Diff", "Dict", "Input", "regional pricing", "bindStaged"],
|
|
227
|
-
description: "Regional-pricing editor — Input.Float per region writes back to a staged Dict; Diff shows per-key updates",
|
|
228
|
-
fn: East.function([], UIComponentType, (_$) => {
|
|
229
|
-
return (_jsx(Reactive, { children: $ => {
|
|
230
|
-
const prices = $.let(Data.bind(regionalPricesInput, { mode: "staged" }));
|
|
231
|
-
const pricesRead = $.let(prices.read(), DictType(StringType, FloatType));
|
|
232
|
-
// ONE East closure factory: `setPrice(region)` returns the
|
|
233
|
-
// per-region handler as a real East function value.
|
|
234
|
-
const setPrice = $.const(East.function([StringType], FunctionType([FloatType], NullType), (_$, region) => East.function([FloatType], NullType, ($, newPrice) => {
|
|
235
|
-
const next = $.let(prices.read(), DictType(StringType, FloatType));
|
|
236
|
-
$(next.insertOrUpdate(region, newPrice));
|
|
237
|
-
$(prices.write(next));
|
|
238
|
-
})));
|
|
239
|
-
const onAu = $.const(setPrice("AU"));
|
|
240
|
-
const onUs = $.const(setPrice("US"));
|
|
241
|
-
const onEu = $.const(setPrice("EU"));
|
|
242
|
-
const onJp = $.const(setPrice("JP"));
|
|
243
|
-
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: onAu })] }), _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: onUs })] }), _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: onEu })] }), _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: onJp })] }), _jsx(Diff, { bindings: [prices.binding], hideUnchanged: some(true) })] }) }));
|
|
244
|
-
} }));
|
|
245
|
-
}),
|
|
246
|
-
inputs: [],
|
|
247
|
-
});
|
|
248
|
-
// ============================================================================
|
|
249
|
-
// 7. Deployment status editor — Variant binding; one Button per status.
|
|
250
|
-
// Demonstrates Variant tag changes in the Diff.
|
|
251
|
-
// ============================================================================
|
|
252
|
-
export const deploymentStatusEditor = example({
|
|
253
|
-
keywords: ["Diff", "Variant", "Button", "deployment status", "bindStaged"],
|
|
254
|
-
description: "Deployment-status editor — buttons set a Variant binding; Diff shows the status tag change",
|
|
255
|
-
fn: East.function([], UIComponentType, (_$) => {
|
|
256
|
-
return (_jsx(Reactive, { children: $ => {
|
|
257
|
-
const status = $.let(Data.bind(deploymentStatusInput, { mode: "staged" }));
|
|
258
|
-
const statusRead = $.let(status.read(), DeploymentStatusType);
|
|
259
|
-
const setPending = $.const(East.function([], NullType, $ => $(status.write(variant("pending", null)))));
|
|
260
|
-
const setInProgress = $.const(East.function([], NullType, $ => $(status.write(variant("in_progress", null)))));
|
|
261
|
-
const setComplete = $.const(East.function([], NullType, $ => $(status.write(variant("complete", null)))));
|
|
262
|
-
const setFailed = $.const(East.function([], NullType, $ => $(status.write(variant("failed", null)))));
|
|
263
|
-
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: setPending, children: "Pending" }), _jsx(Button, { onClick: setInProgress, children: "In progress" }), _jsx(Button, { onClick: setComplete, children: "Complete" }), _jsx(Button, { onClick: setFailed, children: "Failed" })] }), _jsx(Diff, { bindings: [status.binding], hideUnchanged: some(true) })] }) }));
|
|
264
|
-
} }));
|
|
265
|
-
}),
|
|
266
|
-
inputs: [],
|
|
267
|
-
});
|
|
268
|
-
// ============================================================================
|
|
269
|
-
// 8. Minimal call site — defaults only (used by IR-roundtrip + smoke tests)
|
|
238
|
+
// 4. Minimal call site — defaults only (used by IR-roundtrip + smoke tests)
|
|
270
239
|
// ============================================================================
|
|
271
240
|
export const diffDefaults = example({
|
|
272
241
|
keywords: ["Diff", "Root", "defaults", "minimal"],
|
|
@@ -318,50 +287,6 @@ export const mergeConflictDemo = example({
|
|
|
318
287
|
inputs: [],
|
|
319
288
|
});
|
|
320
289
|
// ============================================================================
|
|
321
|
-
// Density variants — same pricing-rules content rendered at the two
|
|
322
|
-
// non-default density presets, so the showcase can compare side-by-side
|
|
323
|
-
// against the default (`pricingRulesEditor` above).
|
|
324
|
-
// ============================================================================
|
|
325
|
-
/**
|
|
326
|
-
* Pricing-rules editor at `compact` density — tighter row padding and smaller
|
|
327
|
-
* type scale than the default `comfortable`. Suited to data-dense pages where
|
|
328
|
-
* the Diff card is one of several panels competing for vertical space.
|
|
329
|
-
*/
|
|
330
|
-
export const pricingRulesEditorCompact = example({
|
|
331
|
-
keywords: ["Diff", "density", "compact", "Slider", "Input", "pricing"],
|
|
332
|
-
description: "Pricing-rules editor with `density: \"compact\"` — same content as pricingRulesEditor, denser rows",
|
|
333
|
-
fn: East.function([], UIComponentType, (_$) => {
|
|
334
|
-
return (_jsx(Reactive, { children: $ => {
|
|
335
|
-
const listPrice = $.let(Data.bind(listPriceInput, { mode: "staged" }));
|
|
336
|
-
const discountPct = $.let(Data.bind(discountPctInput, { mode: "staged" }));
|
|
337
|
-
const minOrderQty = $.let(Data.bind(minOrderQtyInput, { mode: "staged" }));
|
|
338
|
-
const currency = $.let(Data.bind(currencyCodeInput, { mode: "staged" }));
|
|
339
|
-
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) })] }) }));
|
|
340
|
-
} }));
|
|
341
|
-
}),
|
|
342
|
-
inputs: [],
|
|
343
|
-
});
|
|
344
|
-
/**
|
|
345
|
-
* Pricing-rules editor at `condensed` density — mission-control sizing.
|
|
346
|
-
* Tightest row padding and smallest type scale; pairs with status dashboards
|
|
347
|
-
* and other read-heavy contexts where a diff list is reference data, not the
|
|
348
|
-
* main interaction surface.
|
|
349
|
-
*/
|
|
350
|
-
export const pricingRulesEditorCondensed = example({
|
|
351
|
-
keywords: ["Diff", "density", "condensed", "Slider", "Input", "pricing"],
|
|
352
|
-
description: "Pricing-rules editor with `density: \"condensed\"` — mission-control sizing for read-heavy views",
|
|
353
|
-
fn: East.function([], UIComponentType, (_$) => {
|
|
354
|
-
return (_jsx(Reactive, { children: $ => {
|
|
355
|
-
const listPrice = $.let(Data.bind(listPriceInput, { mode: "staged" }));
|
|
356
|
-
const discountPct = $.let(Data.bind(discountPctInput, { mode: "staged" }));
|
|
357
|
-
const minOrderQty = $.let(Data.bind(minOrderQtyInput, { mode: "staged" }));
|
|
358
|
-
const currency = $.let(Data.bind(currencyCodeInput, { mode: "staged" }));
|
|
359
|
-
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) })] }) }));
|
|
360
|
-
} }));
|
|
361
|
-
}),
|
|
362
|
-
inputs: [],
|
|
363
|
-
});
|
|
364
|
-
// ============================================================================
|
|
365
290
|
// Overlay-mode bindings — patches stored in a sibling `e3.input` typed
|
|
366
291
|
// `PatchType(T)`. The Diff component surfaces them via the `overlay` option
|
|
367
292
|
// instead of `staged`. See `Data.bindOverlay`.
|
|
@@ -372,9 +297,9 @@ export const regionalPricesPatchInput = e3.input("regional_prices_patch", PatchT
|
|
|
372
297
|
export const rosterPatchInput = e3.input("roster_patch", PatchType(RosterArrayType), variant("unchanged", null));
|
|
373
298
|
// Drift-laden patch input — defaults to a non-trivial patch whose ops are
|
|
374
299
|
// stale relative to the source dict `{AU: 49.95, US: 39.95, EU: 44.95, JP:
|
|
375
|
-
// 5499.0}`. Used by `
|
|
376
|
-
// Diff card surfaces when a server-stored
|
|
377
|
-
// older version of its source. Conflicts (per `apply.ts` semantics):
|
|
300
|
+
// 5499.0}`. Used by `diffOverlayVariants` (the REGIONAL PRICING OVERLAY
|
|
301
|
+
// DRIFT row) to demonstrate what the Diff card surfaces when a server-stored
|
|
302
|
+
// patch was authored against an older version of its source. Conflicts (per `apply.ts` semantics):
|
|
378
303
|
// - `delete "MX"` — key not in source → stale delete
|
|
379
304
|
// - `insert "AU"` — key already exists in source → stale insert
|
|
380
305
|
// - `update "US"` with `replace(before=30 → 25)` — before mismatches source's 39.95
|
|
@@ -403,108 +328,75 @@ const rosterDriftEdited = [
|
|
|
403
328
|
];
|
|
404
329
|
export const rosterDriftPatchInput = e3.input("roster_drift_patch", PatchType(RosterArrayType), diffFor(RosterArrayType)(rosterDriftBase, rosterDriftEdited));
|
|
405
330
|
/**
|
|
406
|
-
*
|
|
407
|
-
* the Diff card surfaces the patch against the
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
* Overlay binding whose patch input *starts* with a non-trivial patch that
|
|
422
|
-
* is stale relative to the source. Demonstrates what the Diff card displays
|
|
423
|
-
* when a server-stored patch was authored against an older revision of its
|
|
424
|
-
* source — stale delete, stale insert, stale replace.
|
|
425
|
-
*
|
|
426
|
-
* No form components: `view.read()` calls `apply(source, patch)`, which
|
|
427
|
-
* throws `ConflictError` on the stale ops. The Diff card walks the patch IR
|
|
428
|
-
* directly from cache bytes (no apply) so it renders cleanly. The
|
|
429
|
-
* `bindOverlay` call is kept so the renderer's overlay-type registry knows
|
|
430
|
-
* how to decode the patch bytes for this binding.
|
|
331
|
+
* Overlay-mode variant panel. POLICY OVERLAY: Slider edits go to
|
|
332
|
+
* `max_weekly_hours_patch`, the Diff card surfaces the patch against the
|
|
333
|
+
* source. REGIONAL PRICING OVERLAY DRIFT: the patch input *starts* with a
|
|
334
|
+
* non-trivial patch that is stale relative to the source — what the Diff card
|
|
335
|
+
* displays when a server-stored patch was authored against an older revision
|
|
336
|
+
* (stale delete, stale insert, stale replace); no form components, because
|
|
337
|
+
* `view.read()` calls `apply(source, patch)` which throws `ConflictError` on
|
|
338
|
+
* the stale ops, while the Diff card walks the patch IR directly from cache
|
|
339
|
+
* bytes (no apply) so it renders cleanly (the bind is kept so the renderer's
|
|
340
|
+
* overlay-type registry knows how to decode the patch bytes). ROSTER OVERLAY
|
|
341
|
+
* DRIFT: an array-of-structs patch exercising nested grouping (binding →
|
|
342
|
+
* `[index]` → struct field) — only `rate` of entries 0 and 1 change, so the
|
|
343
|
+
* card renders `ROSTER → [0] → rate`, `[1] → rate`. ROSTER TABLE OVERLAY:
|
|
344
|
+
* the roster table editor with patches stored in `roster_patch`, surviving
|
|
345
|
+
* page reload and visible to other workspace sessions.
|
|
431
346
|
*/
|
|
432
|
-
export const
|
|
433
|
-
keywords: ["Diff", "bindOverlay", "Dict", "conflict", "drift", "
|
|
434
|
-
description: "Overlay
|
|
347
|
+
export const diffOverlayVariants = example({
|
|
348
|
+
keywords: ["Diff", "bindOverlay", "Slider", "overlay", "policy", "patch", "Dict", "conflict", "drift", "roster", "array", "nested", "Table"],
|
|
349
|
+
description: "Overlay variant panel — POLICY OVERLAY: Slider writes patches to a sibling e3.input, Diff shows them; REGIONAL PRICING OVERLAY DRIFT: a stale patch — the Diff card surfaces ops that don't match the source; ROSTER OVERLAY DRIFT: an overlay roster patch — the Diff card surfaces nested array-element field changes; ROSTER TABLE OVERLAY: an editable table backed by a separate patch e3.input — patches persist across sessions",
|
|
435
350
|
fn: East.function([], UIComponentType, (_$) => {
|
|
436
|
-
return (_jsx(Reactive, { children: $ => {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
})
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const onRateChange = $.const(East.function([FloatType], NullType, ($, v) => {
|
|
486
|
-
const fresh = $.let(view.read(), RosterArrayType);
|
|
487
|
-
const next = $.let(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, rate: v }), _$ => r)), RosterArrayType);
|
|
488
|
-
$(view.write(next));
|
|
489
|
-
}));
|
|
490
|
-
return (_jsx(Input.Float, { value: row.rate, min: 15.0, max: 80.0, step: 0.25, onChange: onRateChange }));
|
|
491
|
-
}),
|
|
492
|
-
},
|
|
493
|
-
shiftLength: {
|
|
494
|
-
header: "Shift length (h)",
|
|
495
|
-
render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
|
|
496
|
-
const idx = $.let(ctx.rowIndex, IntegerType);
|
|
497
|
-
const row = $.let(rosterArray.get(idx), RosterEntryType);
|
|
498
|
-
const onShiftChange = $.const(East.function([IntegerType], NullType, ($, v) => {
|
|
499
|
-
const fresh = $.let(view.read(), RosterArrayType);
|
|
500
|
-
const next = $.let(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, shiftLength: v }), _$ => r)), RosterArrayType);
|
|
501
|
-
$(view.write(next));
|
|
502
|
-
}));
|
|
503
|
-
return (_jsx(Input.Integer, { value: row.shiftLength, min: 4n, max: 12n, onChange: onShiftChange }));
|
|
504
|
-
}),
|
|
505
|
-
},
|
|
506
|
-
}, variant: "line", striped: true }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
|
|
507
|
-
} }));
|
|
351
|
+
return (_jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Separator, { label: "POLICY OVERLAY", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
352
|
+
const view = $.let(Data.bind(maxWeeklyHoursInput, { mode: "direct", patch: maxWeeklyHoursPatchInput }));
|
|
353
|
+
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) })] }) }));
|
|
354
|
+
} }), _jsx(Separator, { label: "REGIONAL PRICING OVERLAY DRIFT", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
355
|
+
const view = $.let(Data.bind(regionalPricesInput, { mode: "direct", patch: regionalPricesDriftPatchInput }));
|
|
356
|
+
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 "
|
|
357
|
+
+ "shows: a stale delete (MX missing from source), a stale insert (AU already "
|
|
358
|
+
+ "exists), a stale replace (US before=30 doesn't match current 39.95), and "
|
|
359
|
+
+ "one clean replace (EU 44.95 → 39.95). Apply would throw ConflictError on "
|
|
360
|
+
+ "the stale ops; this example exists to show what the Diff renderer surfaces "
|
|
361
|
+
+ "when a server-stored patch has drifted from its source." }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
|
|
362
|
+
} }), _jsx(Separator, { label: "ROSTER OVERLAY DRIFT", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
363
|
+
const view = $.let(Data.bind(rosterInput, { mode: "direct", patch: rosterDriftPatchInput }));
|
|
364
|
+
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 "
|
|
365
|
+
+ "Diff card groups each change under its array index, demonstrating the "
|
|
366
|
+
+ "binding → [index] → field nesting." }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
|
|
367
|
+
} }), _jsx(Separator, { label: "ROSTER TABLE OVERLAY", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
368
|
+
const view = $.let(Data.bind(rosterInput, { mode: "direct", patch: rosterPatchInput }));
|
|
369
|
+
const rosterArray = $.let(view.read(), RosterArrayType);
|
|
370
|
+
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: {
|
|
371
|
+
name: { header: "Name" },
|
|
372
|
+
rate: {
|
|
373
|
+
header: "Hourly rate ($)",
|
|
374
|
+
render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
|
|
375
|
+
const idx = $.let(ctx.rowIndex, IntegerType);
|
|
376
|
+
const row = $.let(rosterArray.get(idx), RosterEntryType);
|
|
377
|
+
const onRateChange = $.const(East.function([FloatType], NullType, ($, v) => {
|
|
378
|
+
const fresh = $.let(view.read(), RosterArrayType);
|
|
379
|
+
const next = $.let(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, rate: v }), _$ => r)), RosterArrayType);
|
|
380
|
+
$(view.write(next));
|
|
381
|
+
}));
|
|
382
|
+
return (_jsx(Input.Float, { value: row.rate, min: 15.0, max: 80.0, step: 0.25, onChange: onRateChange }));
|
|
383
|
+
}),
|
|
384
|
+
},
|
|
385
|
+
shiftLength: {
|
|
386
|
+
header: "Shift length (h)",
|
|
387
|
+
render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
|
|
388
|
+
const idx = $.let(ctx.rowIndex, IntegerType);
|
|
389
|
+
const row = $.let(rosterArray.get(idx), RosterEntryType);
|
|
390
|
+
const onShiftChange = $.const(East.function([IntegerType], NullType, ($, v) => {
|
|
391
|
+
const fresh = $.let(view.read(), RosterArrayType);
|
|
392
|
+
const next = $.let(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, shiftLength: v }), _$ => r)), RosterArrayType);
|
|
393
|
+
$(view.write(next));
|
|
394
|
+
}));
|
|
395
|
+
return (_jsx(Input.Integer, { value: row.shiftLength, min: 4n, max: 12n, onChange: onShiftChange }));
|
|
396
|
+
}),
|
|
397
|
+
},
|
|
398
|
+
}, variant: "line", striped: true }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
|
|
399
|
+
} })] }));
|
|
508
400
|
}),
|
|
509
401
|
inputs: [],
|
|
510
402
|
});
|
|
@@ -516,62 +408,53 @@ export const rosterTableEditorOverlay = example({
|
|
|
516
408
|
// the unit of review.
|
|
517
409
|
// ============================================================================
|
|
518
410
|
/**
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
fn: East.function([], UIComponentType, (_$) => {
|
|
527
|
-
return (_jsx(Reactive, { children: $ => {
|
|
528
|
-
const view = $.let(Data.bind(maxWeeklyHoursInput, { mode: "staged", patch: maxWeeklyHoursPatchInput }));
|
|
529
|
-
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) })] }) }));
|
|
530
|
-
} }));
|
|
531
|
-
}),
|
|
532
|
-
inputs: [],
|
|
533
|
-
});
|
|
534
|
-
/**
|
|
535
|
-
* Roster table editor in staged + patch mode. Cell edits buffer in
|
|
536
|
-
* IndexedDB until Apply, which publishes a fresh patch to `roster_patch`.
|
|
537
|
-
* Survives reload as a draft; multi-session reviewers see the patch only
|
|
411
|
+
* Staged + patch variant panel. POLICY STAGED PATCH: single-Float
|
|
412
|
+
* staged-with-patch editor — buffered Slider edits publish to
|
|
413
|
+
* `max_weekly_hours_patch` on Apply; the source `max_weekly_hours` stays
|
|
414
|
+
* untouched until a separate apply-patch-to-source step. ROSTER STAGED
|
|
415
|
+
* PATCH: the roster table editor in staged + patch mode — cell edits buffer
|
|
416
|
+
* in IndexedDB until Apply, which publishes a fresh patch to `roster_patch`;
|
|
417
|
+
* survives reload as a draft, and multi-session reviewers see the patch only
|
|
538
418
|
* after the author commits.
|
|
539
419
|
*/
|
|
540
|
-
export const
|
|
541
|
-
keywords: ["Diff", "
|
|
542
|
-
description: "
|
|
420
|
+
export const diffStagedPatchVariants = example({
|
|
421
|
+
keywords: ["Diff", "Slider", "staged", "patch", "publish", "policy", "Table", "roster"],
|
|
422
|
+
description: "Staged + patch variant panel — POLICY STAGED PATCH: Slider edits buffered locally, Apply publishes the draft to a server-backed patch dataset; ROSTER STAGED PATCH: an editable roster whose buffered cell edits publish a fresh patch to the patch dataset on Apply",
|
|
543
423
|
fn: East.function([], UIComponentType, (_$) => {
|
|
544
|
-
return (_jsx(Reactive, { children: $ => {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
424
|
+
return (_jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Separator, { label: "POLICY STAGED PATCH", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
425
|
+
const view = $.let(Data.bind(maxWeeklyHoursInput, { mode: "staged", patch: maxWeeklyHoursPatchInput }));
|
|
426
|
+
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) })] }) }));
|
|
427
|
+
} }), _jsx(Separator, { label: "ROSTER STAGED PATCH", align: "start" }), _jsx(Reactive, { children: $ => {
|
|
428
|
+
const view = $.let(Data.bind(rosterInput, { mode: "staged", patch: rosterPatchInput }));
|
|
429
|
+
const rosterArray = $.let(view.read(), RosterArrayType);
|
|
430
|
+
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: {
|
|
431
|
+
name: { header: "Name" },
|
|
432
|
+
rate: {
|
|
433
|
+
header: "Hourly rate ($)",
|
|
434
|
+
render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
|
|
435
|
+
const idx = $.let(ctx.rowIndex, IntegerType);
|
|
436
|
+
const row = $.let(rosterArray.get(idx), RosterEntryType);
|
|
437
|
+
const onRateChange = $.const(East.function([FloatType], NullType, ($, v) => {
|
|
438
|
+
const fresh = $.let(view.read(), RosterArrayType);
|
|
439
|
+
$(view.write(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, rate: v }), () => r))));
|
|
440
|
+
}));
|
|
441
|
+
return (_jsx(Input.Float, { value: row.rate, min: 15.0, max: 80.0, step: 0.25, onChange: onRateChange }));
|
|
442
|
+
}),
|
|
443
|
+
},
|
|
444
|
+
shiftLength: {
|
|
445
|
+
header: "Shift length (h)",
|
|
446
|
+
render: East.function([Table.Types.CellRenderContext], UIComponentType, ($, ctx) => {
|
|
447
|
+
const idx = $.let(ctx.rowIndex, IntegerType);
|
|
448
|
+
const row = $.let(rosterArray.get(idx), RosterEntryType);
|
|
449
|
+
const onShiftChange = $.const(East.function([IntegerType], NullType, ($, v) => {
|
|
450
|
+
const fresh = $.let(view.read(), RosterArrayType);
|
|
451
|
+
$(view.write(fresh.map(($, r, i) => i.equal(idx).ifElse(_$ => ({ ...r, shiftLength: v }), () => r))));
|
|
452
|
+
}));
|
|
453
|
+
return (_jsx(Input.Integer, { value: row.shiftLength, min: 4n, max: 12n, onChange: onShiftChange }));
|
|
454
|
+
}),
|
|
455
|
+
},
|
|
456
|
+
}, variant: "line", striped: true }), _jsx(Diff, { bindings: [view.binding], hideUnchanged: some(true) })] }) }));
|
|
457
|
+
} })] }));
|
|
575
458
|
}),
|
|
576
459
|
inputs: [],
|
|
577
460
|
});
|