@elaraai/east-ui 1.0.97 → 1.0.98

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 (99) hide show
  1. package/dist/src/collections/index.d.ts +0 -1
  2. package/dist/src/collections/index.d.ts.map +1 -1
  3. package/dist/src/collections/index.js +0 -1
  4. package/dist/src/collections/index.js.map +1 -1
  5. package/dist/src/component.d.ts +0 -999
  6. package/dist/src/component.d.ts.map +1 -1
  7. package/dist/src/component.js +0 -44
  8. package/dist/src/component.js.map +1 -1
  9. package/dist/src/contracts/drag.d.ts +2 -2
  10. package/dist/src/contracts/drag.js +2 -2
  11. package/dist/src/contracts/editing.d.ts +4 -0
  12. package/dist/src/contracts/editing.d.ts.map +1 -1
  13. package/dist/src/contracts/editing.js +2 -1
  14. package/dist/src/contracts/editing.js.map +1 -1
  15. package/dist/src/index.d.ts +2 -1
  16. package/dist/src/index.d.ts.map +1 -1
  17. package/dist/src/index.js +4 -1
  18. package/dist/src/index.js.map +1 -1
  19. package/dist/src/internal.d.ts +4 -1
  20. package/dist/src/internal.d.ts.map +1 -1
  21. package/dist/src/internal.js +5 -2
  22. package/dist/src/internal.js.map +1 -1
  23. package/dist/src/layout/snap-grid/index.d.ts +1 -0
  24. package/dist/src/layout/snap-grid/index.d.ts.map +1 -1
  25. package/dist/src/pick/panel/index.js +1 -1
  26. package/dist/src/pick/panel/index.js.map +1 -1
  27. package/dist/src/platform/slice/index.d.ts +4 -7
  28. package/dist/src/platform/slice/index.d.ts.map +1 -1
  29. package/dist/src/platform/slice/index.js +5 -8
  30. package/dist/src/platform/slice/index.js.map +1 -1
  31. package/dist/src/platform/slice/record-area.d.ts +181 -0
  32. package/dist/src/platform/slice/record-area.d.ts.map +1 -0
  33. package/dist/src/platform/slice/record-area.js +304 -0
  34. package/dist/src/platform/slice/record-area.js.map +1 -0
  35. package/dist/src/platform/slice/record-chrome.d.ts +138 -0
  36. package/dist/src/platform/slice/record-chrome.d.ts.map +1 -1
  37. package/dist/src/platform/slice/record-plan.d.ts +34 -1
  38. package/dist/src/platform/slice/record-plan.d.ts.map +1 -1
  39. package/dist/src/platform/slice/record-plan.js +126 -3
  40. package/dist/src/platform/slice/record-plan.js.map +1 -1
  41. package/dist/src/platform/slice/record-series.d.ts +166 -0
  42. package/dist/src/platform/slice/record-series.d.ts.map +1 -0
  43. package/dist/src/platform/slice/record-series.js +258 -0
  44. package/dist/src/platform/slice/record-series.js.map +1 -0
  45. package/dist/src/platform/slice/record-types.d.ts +1862 -13
  46. package/dist/src/platform/slice/record-types.d.ts.map +1 -1
  47. package/dist/src/platform/slice/record-types.js +50 -4
  48. package/dist/src/platform/slice/record-types.js.map +1 -1
  49. package/dist/src/platform/slice/record.d.ts +17 -2
  50. package/dist/src/platform/slice/record.d.ts.map +1 -1
  51. package/dist/src/platform/slice/record.js +62 -9
  52. package/dist/src/platform/slice/record.js.map +1 -1
  53. package/dist/src/runtime/collections/index.d.ts +0 -1
  54. package/dist/src/runtime/collections/index.d.ts.map +1 -1
  55. package/dist/src/runtime/collections/index.js +0 -1
  56. package/dist/src/runtime/collections/index.js.map +1 -1
  57. package/dist/src/runtime/record-slice-source.d.ts +298 -0
  58. package/dist/src/runtime/record-slice-source.d.ts.map +1 -1
  59. package/dist/src/runtime/record-slice-source.js +554 -16
  60. package/dist/src/runtime/record-slice-source.js.map +1 -1
  61. package/dist/src/runtime/record-slice.d.ts +87 -3
  62. package/dist/src/runtime/record-slice.d.ts.map +1 -1
  63. package/dist/src/runtime/record-slice.js +175 -12
  64. package/dist/src/runtime/record-slice.js.map +1 -1
  65. package/dist/src/slice/record/index.d.ts +69 -0
  66. package/dist/src/slice/record/index.d.ts.map +1 -1
  67. package/dist/src/style/color.d.ts +237 -0
  68. package/dist/src/style/color.d.ts.map +1 -0
  69. package/dist/src/style/color.js +105 -0
  70. package/dist/src/style/color.js.map +1 -0
  71. package/dist/src/style/namespace.d.ts +151 -1
  72. package/dist/src/style/namespace.d.ts.map +1 -1
  73. package/dist/src/style/namespace.js +9 -1
  74. package/dist/src/style/namespace.js.map +1 -1
  75. package/dist/src/style.d.ts +3 -0
  76. package/dist/src/style.d.ts.map +1 -1
  77. package/dist/src/style.js +3 -0
  78. package/dist/src/style.js.map +1 -1
  79. package/dist/test/style.examples.d.ts +1 -0
  80. package/dist/test/style.examples.d.ts.map +1 -1
  81. package/dist/test/style.examples.js +17 -2
  82. package/dist/test/style.examples.js.map +1 -1
  83. package/package.json +4 -4
  84. package/dist/src/collections/schematic/index.d.ts +0 -1390
  85. package/dist/src/collections/schematic/index.d.ts.map +0 -1
  86. package/dist/src/collections/schematic/index.js +0 -815
  87. package/dist/src/collections/schematic/index.js.map +0 -1
  88. package/dist/src/collections/schematic/types.d.ts +0 -1183
  89. package/dist/src/collections/schematic/types.d.ts.map +0 -1
  90. package/dist/src/collections/schematic/types.js +0 -724
  91. package/dist/src/collections/schematic/types.js.map +0 -1
  92. package/dist/src/runtime/collections/schematic.d.ts +0 -73
  93. package/dist/src/runtime/collections/schematic.d.ts.map +0 -1
  94. package/dist/src/runtime/collections/schematic.js +0 -69
  95. package/dist/src/runtime/collections/schematic.js.map +0 -1
  96. package/dist/test/collections/schematic.examples.d.ts +0 -23
  97. package/dist/test/collections/schematic.examples.d.ts.map +0 -1
  98. package/dist/test/collections/schematic.examples.js +0 -602
  99. package/dist/test/collections/schematic.examples.js.map +0 -1
@@ -1,602 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@elaraai/east-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/east-ui */
7
- import { East, ArrayType, BooleanType, FloatType, IntegerType, NullType, OptionType, StringType, StructType, example, variant, some, none } from "@elaraai/east";
8
- import { State, StatusTokenType, UIComponentType } from "@elaraai/east-ui";
9
- import { Configurator, HStack, Reactive, Schematic, Select, Separator, Slice, Slider, Sparkline, Switch, Text, VStack } from "@elaraai/east-ui";
10
- // ============================================================================
11
- // Module-scope fixtures — one per merged example (consolidation epic #455).
12
- // ============================================================================
13
- // Equipment with real footprints: `round` ⇒ circle body (a tank),
14
- // else `fp` ⇒ polygon body, else point + icon. The `x/y` anchor stays
15
- // the item identity used by the sidebar, links, and declutter;
16
- // `footprint` is additive (a circle centres on that anchor).
17
- // Zones with shape geometry: a rotated polygon hall and a curvy
18
- // polyline service road whose bends are true arcs (vertex `bulge`),
19
- // widened into a world-space band. The required x/y/w/h bounding box
20
- // still drives the navigator / minimap / fly-to.
21
- // Each unit carries an explicit CSS colour: `color` tints the stroke /
22
- // marker, `bg` fills the circle footprint — a category palette that is
23
- // independent of `status`.
24
- // Small extent ⇒ items render as CARDS, where the ghost / desaturate
25
- // / ring effects read clearly (on labelled pins they'd be too subtle).
26
- // Each carries a status tone so `desaturate` visibly drains its colour.
27
- // The ONE shared canvas fixture for the interaction configurator — old
28
- // schematicInteractive's items (the other merged examples' fixtures are
29
- // superseded; their distinctive features are prop-level, not data-level),
30
- // plus schematicZoneSelect's M1 / P1 / P2 rows so the Hall B and Dock zones
31
- // below keep child items and the childItemKeys log line stays meaningful.
32
- // Zone bodies for the zone tool + the always-on zoneHover cards — verbatim
33
- // from the OLD schematicZoneSelect example (the only zone source among the
34
- // six merged interaction examples).
35
- export const schematicPlant = example({
36
- keywords: ["Schematic", "canvas", "items", "zones", "links", "meter", "status", "hatch", "label", "metric", "parallel", "fan-out", "flow"],
37
- description: "Plant floor — tanks and lines in halls with a walkway band and pipe runs",
38
- fn: East.function([], UIComponentType, ($) => {
39
- const equipment = $.const([
40
- { id: "UNIT-04", x: 3.0, y: 2.6, kind: "unit · 40 kL", fill: 28.8, cap: 40.0, metric: "28.8 kL", state: some(variant("success", null)), w: 4.5 },
41
- { id: "UNIT-05", x: 8.0, y: 2.6, kind: "unit · 40 kL", fill: 36.8, cap: 40.0, metric: "36.8 kL", state: some(variant("warning", null)), w: 4.5 },
42
- { id: "UNIT-06", x: 13.0, y: 2.6, kind: "unit · 40 kL", fill: 20.4, cap: 40.0, metric: "20.4 kL", state: some(variant("success", null)), w: 4.5 },
43
- { id: "UNIT-07", x: 18.0, y: 2.6, kind: "unit · 60 kL", fill: 0.0, cap: 60.0, metric: "empty", state: some(variant("neutral", null)), w: 4.5 },
44
- { id: "QA-1", x: 25.0, y: 2.6, kind: "qa hold · 8h", fill: 4.0, cap: 8.0, metric: "4h left", state: some(variant("info", null)), w: 4.5 },
45
- { id: "LINE-2", x: 8.0, y: 9.8, kind: "pack · sku-241", fill: 0.0, cap: 0.0, metric: "1,800 u/h", state: some(variant("success", null)), w: 13.0 },
46
- { id: "BAY-OUT", x: 24.0, y: 9.8, kind: "pallets · 5 slots", fill: 3.0, cap: 5.0, metric: "3 / 5", state: some(variant("success", null)), w: 4.5 },
47
- ]);
48
- const areas = $.const([
49
- { id: "hall-b", name: "Hall B", x: 0.6, y: 0.6, w: 20.0, h: 4.4, pattern: Schematic.outline() },
50
- { id: "qa-cell", name: "QA Cell", x: 22.5, y: 0.6, w: 5.5, h: 4.4, pattern: Schematic.outline() },
51
- { id: "aisle-3", name: "Aisle 3 · 1.6 m walkway", x: 0.6, y: 6.2, w: 28.0, h: 1.6, pattern: Schematic.hatch() },
52
- { id: "dispatch", name: "Dispatch", x: 20.5, y: 8.4, w: 8.1, h: 3.2, pattern: Schematic.outline() },
53
- ]);
54
- // Already the resolved link type — passed through with no `link` mapper.
55
- const orthogonal = variant("orthogonal", { corner: none });
56
- // p2 + p2b share the same endpoint pair — the renderer fans them into
57
- // parallel lanes (#180) so both edges (feed + CIP return) stay readable;
58
- // labels/metrics render mid-path at label zoom.
59
- const pipes = $.const([
60
- { key: "p1", from: "UNIT-04", to: "LINE-2", label: some("feed"), metric: some("12 m³/h"), style: Schematic.solid(), route: orthogonal, via: [], layer: none },
61
- { key: "p2", from: "UNIT-05", to: "LINE-2", label: some("feed"), metric: some("9 m³/h"), style: Schematic.solid(), route: orthogonal, via: [], layer: none },
62
- { key: "p2b", from: "UNIT-05", to: "LINE-2", label: some("CIP return"), metric: none, style: Schematic.dashed(), route: orthogonal, via: [], layer: none },
63
- { key: "p3", from: "UNIT-06", to: "LINE-2", label: none, metric: none, style: Schematic.solid(), route: orthogonal, via: [], layer: none },
64
- { key: "p4", from: "QA-1", to: "BAY-OUT", label: none, metric: some("3 pallets/h"), style: Schematic.dashed(), route: orthogonal, via: [{ x: 26.5, y: 6.8 }], layer: none },
65
- ], ArrayType(Schematic.Types.Link));
66
- return (_jsx(Schematic, { extent: { width: 29, height: 12.5 }, height: "440px", items: equipment, item: e => ({
67
- key: e.id, x: e.x, y: e.y, label: e.id,
68
- sublabel: e.kind, icon: "database",
69
- status: e.state,
70
- meter: { value: e.fill, max: e.cap },
71
- metric: e.metric,
72
- width: e.w,
73
- }), zones: areas, zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h, pattern: z.pattern }), links: pipes, scaleUnit: "m", grid: true }));
74
- }),
75
- inputs: [],
76
- });
77
- // 320 generated demo units across 4 bays — authored at MODULE scope (an East
78
- // function's body must be East all the way down; authoring-time constants are
79
- // host-declared outside it).
80
- const STRESS_KINDS = ["unit", "pack", "pallet", "tank"];
81
- // A large generated grid — the count is the perf-probe knob (#302-adjacent
82
- // schematic-slice-perf): bump it to reproduce the slice-on pan/zoom slowdown at
83
- // scale. 3,000 sits above the 2,000-item pan budget.
84
- const STRESS_GRID_ITEMS = Array.from({ length: 3000 }, (_, i) => {
85
- const col = i % 50, row = Math.floor(i / 50);
86
- return {
87
- id: `U-${String(i).padStart(4, "0")}`,
88
- x: col * 2.0 + 2.0,
89
- y: row * 2.4 + 2.0,
90
- load: (i * 37 % 100) / 100,
91
- kind: STRESS_KINDS[i % STRESS_KINDS.length],
92
- };
93
- });
94
- export const schematicStress = example({
95
- keywords: ["Schematic", "stress", "performance", "LOD", "semantic zoom", "declutter", "minimap", "large", "many items", "slice", "sliceEffect", "pan", "zoom", "10k"],
96
- description: "Stress probe — 3,000 generated items exercise the LOD ladder and Slice chrome (rail + ghosting) at scale; the pan/zoom perf budget with slice on",
97
- fn: East.function([], UIComponentType, (_$) => {
98
- const EquipType = StructType({ id: StringType, x: FloatType, y: FloatType, load: FloatType, kind: StringType });
99
- return (_jsx(Reactive, { children: $ => {
100
- const data = $.const(STRESS_GRID_ITEMS, ArrayType(EquipType));
101
- // Seed a filter so ~3/4 of the items are slice-excluded (ghosted) —
102
- // exercises the slice-effect paint path as well as the rail chrome.
103
- const slice = $.let(Slice.bind("ex.schematic.stress", data, {
104
- fields: { id: { label: "ID" }, kind: { label: "Kind" } }, search: ["id", "kind"],
105
- initial: { kind: ["unit"] },
106
- }));
107
- const tagged = $.let(Slice.partition([EquipType], slice));
108
- return (_jsx(Schematic, { extent: { width: 104, height: 100 }, height: "460px", items: tagged, item: t => ({
109
- key: t.value.id, x: t.value.x, y: t.value.y, label: t.value.id,
110
- icon: "microchip", meter: { value: t.value.load, max: 1.0 },
111
- excluded: t.matched.not(),
112
- }), slice: slice, affordances: ["search", "filter"], sliceOpacity: 0.35, sliceDesaturate: true, selectionMode: "multiple", minimap: true, scaleUnit: "m" }));
113
- } }));
114
- }),
115
- inputs: [],
116
- });
117
- export const schematicLinkEdit = example({
118
- keywords: ["Schematic", "link", "editing", "connect", "linkMode", "session", "onCreateLink", "onSelectLink", "onEditLink", "onDeleteLink", "readOnlyLinks", "readOnly", "draw", "Reactive", "State", "Switch"],
119
- description: "Link editing — connect drags item→item (draw adds locally, connect is event-only), Shift+drag grows the session, endpoint handles re-target, Del deletes; canConnect vetoes mixer→shipping",
120
- fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
121
- const log = $.let(State.bind([StringType], "schematic_link_log", "—"));
122
- const onCreateLink = $.const(East.function([Schematic.Types.LinkCreateEvent], NullType, ($, ev) => {
123
- $(log.write(East.str `created ${ev.link.from}→${ev.link.to} · session ${East.print(ev.links.size())} · existing ${East.print(ev.existing.size())}`));
124
- }));
125
- const onEditLink = $.const(East.function([Schematic.Types.LinkEditEvent], NullType, ($, ev) => {
126
- $(log.write(East.str `edited ${ev.key} → ${ev.from}→${ev.to}`));
127
- }));
128
- const onDeleteLink = $.const(East.function([StringType], NullType, ($, key) => {
129
- $(log.write(East.str `deleted ${key}`));
130
- }));
131
- // Reactive mode switches: `connect` = event-only (plan an operation,
132
- // nothing drawn); editable off = readOnlyLinks (tool + handles hidden).
133
- const connectMode = $.let(State.bind([BooleanType], "ex.link.connectmode", false));
134
- const cOn = $.let(connectMode.read());
135
- const onC = $.const(East.function([BooleanType], NullType, ($, v) => { $(connectMode.write(v)); }));
136
- const lm = $.let(cOn.ifElse(_$ => variant("connect", null), _$ => variant("draw", null)), Schematic.Types.LinkMode);
137
- const editable = $.let(State.bind([BooleanType], "ex.link.editable", true));
138
- const eOn = $.let(editable.read());
139
- const onE = $.const(East.function([BooleanType], NullType, ($, v) => { $(editable.write(v)); }));
140
- const roLinks = $.let(eOn.not(), BooleanType);
141
- // Connection validator: mixers never connect DIRECTLY to shipping —
142
- // product must pass through a packer (drag MIX-1 → SHIP: no snap).
143
- const canConnect = $.const(East.function([StringType, StringType], BooleanType, (_$, from, to) => from.substring(0n, 3n).equal("MIX").and(() => to.equal("SHIP")).not()));
144
- // The mode READOUT follows the switch — the description must never
145
- // claim event-only while draw mode is adding locally.
146
- const modeTxt = $.let(cOn.ifElse(_$ => "CONNECT — event-only, nothing added", _$ => "DRAW — adds locally"));
147
- const txt = $.let(log.read());
148
- return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsxs(HStack, { gap: "4", align: "center", children: [_jsx(Switch, { checked: eOn, label: "Links editable", onChange: onE }), _jsx(Switch, { checked: cOn, label: "Connect mode", onChange: onC }), _jsx(Text.MonoLabel, { children: East.str `${modeTxt} · ${txt}` })] }), _jsx(Schematic, { extent: { width: 22, height: 11 }, height: "420px", items: [
149
- { id: "MIX-1", x: 3.0, y: 3.0 }, { id: "MIX-2", x: 3.0, y: 8.0 },
150
- { id: "PACK-A", x: 12.0, y: 3.0 }, { id: "PACK-B", x: 12.0, y: 8.0 },
151
- { id: "SHIP", x: 19.0, y: 5.5 },
152
- ], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "industry" }), links: [{ id: "l1", a: "PACK-A", b: "SHIP" }], link: l => ({ key: l.id, from: l.a, to: l.b }), linkMode: lm, readOnlyLinks: roLinks, onCreateLink: onCreateLink, onEditLink: onEditLink, onDeleteLink: onDeleteLink, canConnect: canConnect })] }));
153
- } }))),
154
- inputs: [],
155
- });
156
- export const schematicNets = example({
157
- keywords: ["Schematic", "net", "nets", "manifold", "bus", "trunk", "header", "bar", "stubs", "sources", "destinations", "via", "label", "linkMode", "onCreateLink", "session", "Reactive", "State", "Switch"],
158
- description: "Nets — a manifold as ONE row (header bar + stubs, no pairwise explosion); the connect tool grows nets, stub-level selection edits one leg; canConnect keeps CIP-1 supply-only",
159
- fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
160
- const units = $.const([
161
- { id: "CIP-1", x: 2.0, y: 6.0 },
162
- { id: "U-01", x: 9.0, y: 2.0 }, { id: "U-02", x: 9.0, y: 4.5 },
163
- { id: "U-03", x: 9.0, y: 7.0 }, { id: "U-04", x: 9.0, y: 9.5 },
164
- { id: "PK-A", x: 17.0, y: 3.5 }, { id: "PK-B", x: 17.0, y: 8.0 },
165
- { id: "DOCK", x: 23.0, y: 6.0 },
166
- ]);
167
- const manifolds = $.const([
168
- { id: "cip", srcs: ["CIP-1"], dsts: ["U-01", "U-02", "U-03", "U-04"], name: "CIP supply", flow: "12 m³/h", path: [] },
169
- { id: "header", srcs: ["PK-A", "PK-B"], dsts: ["DOCK"], name: "outfeed header", flow: "", path: [{ x: 20.0, y: 6.0 }] },
170
- ], ArrayType(StructType({
171
- id: StringType,
172
- srcs: ArrayType(StringType),
173
- dsts: ArrayType(StringType),
174
- name: StringType,
175
- flow: StringType,
176
- path: ArrayType(StructType({ x: FloatType, y: FloatType })),
177
- })));
178
- const log = $.let(State.bind([StringType], "schematic_net_log", "—"));
179
- // A Shift-session commit reports the WHOLE growing net — upsert by
180
- // `net.key` to materialise it as one manifold row.
181
- const onCreateLink = $.const(East.function([Schematic.Types.LinkCreateEvent], NullType, ($, ev) => {
182
- $(log.write(East.str `net ${ev.net.key} · ${East.print(ev.net.sources.size())} src → ${East.print(ev.net.destinations.size())} dst · additive ${East.print(ev.additive)}`));
183
- }));
184
- // Click a STUB to select one leg (narrow halo), Del removes just that
185
- // endpoint — onEditNet reports the net's endpoints AFTER the removal.
186
- const onEditNet = $.const(East.function([Schematic.Types.NetEndpoints], NullType, ($, ev) => {
187
- $(log.write(East.str `net ${ev.key} edited · ${East.print(ev.sources.size())} src → ${East.print(ev.destinations.size())} dst`));
188
- }));
189
- // Connection validator: CIP-1 is supply-only — the connect draft
190
- // never snaps onto it (covers links, session/net extensions, and
191
- // re-targets alike).
192
- const canConnect = $.const(East.function([StringType, StringType], BooleanType, (_$, _from, to) => to.notEqual("CIP-1")));
193
- // Reactive mode switches: `connect` = event-only (plan the manifold,
194
- // nothing drawn); editable off = readOnlyLinks (connect tool hidden).
195
- const connectMode = $.let(State.bind([BooleanType], "ex.net.connectmode", false));
196
- const cOn = $.let(connectMode.read());
197
- const onC = $.const(East.function([BooleanType], NullType, ($, v) => { $(connectMode.write(v)); }));
198
- const lm = $.let(cOn.ifElse(_$ => variant("connect", null), _$ => variant("draw", null)), Schematic.Types.LinkMode);
199
- const editable = $.let(State.bind([BooleanType], "ex.net.editable", true));
200
- const eOn = $.let(editable.read());
201
- const onE = $.const(East.function([BooleanType], NullType, ($, v) => { $(editable.write(v)); }));
202
- const roLinks = $.let(eOn.not(), BooleanType);
203
- // The mode READOUT follows the switch — the description must never
204
- // claim event-only while draw mode is adding locally.
205
- const modeTxt = $.let(cOn.ifElse(_$ => "CONNECT — event-only, nothing added", _$ => "DRAW — adds locally"));
206
- const txt = $.let(log.read());
207
- return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsxs(HStack, { gap: "4", align: "center", children: [_jsx(Switch, { checked: eOn, label: "Links editable", onChange: onE }), _jsx(Switch, { checked: cOn, label: "Connect mode", onChange: onC }), _jsx(Text.MonoLabel, { children: East.str `${modeTxt} · ${txt}` })] }), _jsx(Schematic, { extent: { width: 26, height: 12 }, height: "420px", items: units, item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "industry" }), nets: manifolds, net: m => ({ key: m.id, sources: m.srcs, destinations: m.dsts, label: m.name, via: m.path }), linkMode: lm, readOnlyLinks: roLinks, onCreateLink: onCreateLink, onEditNet: onEditNet, canConnect: canConnect })] }));
208
- } }))),
209
- inputs: [],
210
- });
211
- export const schematicVariants = example({
212
- keywords: ["Schematic", "canvas", "minimal", "readOnly", "static", "layers", "layer", "visibility", "solo", "lock", "opacity", "toggle", "legend", "geometry", "polygon", "polyline", "circle", "arc", "bulge", "footprint", "zone", "CAD", "shape", "color", "tone", "bg", "override", "style", "facility", "navigator", "minimap", "zoom", "LOD", "click-to-fly", "large", "generate", "Reactive", "State", "SegmentGroup", "Switch", "Configurator", "getTag", "configurator"],
213
- description: "Schematic canvas configurator — a canvas preset axis (minimal / layers / geometry / color / facility) plus a read-only switch driving one live canvas",
214
- fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
215
- // readOnly ON makes the shown canvas a pure static picture — the
216
- // connect / move edit tools never render, leaving just pan / zoom /
217
- // selection (the old MINIMAL row's fixed prop, now a live switch).
218
- const roBind = $.let(State.bind([BooleanType], "schematic_readonly", false));
219
- const roOn = $.let(roBind.read());
220
- const onRo = $.const(East.function([BooleanType], NullType, ($, v) => { $(roBind.write(v)); }));
221
- // ---- FACILITY preset (schematicFacility fold-in) — 306 units:
222
- // navigator rail, minimap, semantic zoom, click-to-fly from the
223
- // navigator; rows generated with East.Array.generate, each carrying
224
- // a varied footprint shape/size (circle / square / triangle / diamond).
225
- const UnitType = StructType({
226
- key: StringType,
227
- x: FloatType,
228
- y: FloatType,
229
- kind: StringType,
230
- fill: FloatType,
231
- cap: FloatType,
232
- metric: StringType,
233
- status: OptionType(StatusTokenType),
234
- // Footprint discriminator + half-size (world units) — the item
235
- // mapper turns these into a circle / square / triangle / diamond.
236
- shape: IntegerType,
237
- size: FloatType,
238
- });
239
- const statuses = $.const([
240
- some(variant("success", null)),
241
- some(variant("success", null)),
242
- some(variant("success", null)),
243
- some(variant("warning", null)),
244
- some(variant("info", null)),
245
- some(variant("neutral", null)),
246
- ], ArrayType(OptionType(StatusTokenType)));
247
- // One generated grid block per zone — geometry and pseudo-random
248
- // fill computed with East expressions over the unit index. Blocks
249
- // mix row spacing (tight ⇢ sparse) and add hash jitter so the
250
- // semantic-zoom declutter has real density variation to chew on.
251
- const block = $.const(East.function([StringType, FloatType, FloatType, IntegerType, IntegerType, FloatType, FloatType], ArrayType(UnitType), (_$, prefix, x0, y0, count, cols, spacing, cap) => East.Array.generate(count, UnitType, ($, i) => {
252
- const col = $.let(i.remainder(cols));
253
- const row = $.let(i.subtract(col).divide(cols));
254
- const fill = $.let(i.add(1n).multiply(7919n).remainder(100n).toFloat().divide(100.0).multiply(cap));
255
- const jx = $.let(i.multiply(2654435761n).remainder(97n).toFloat().divide(97.0).subtract(0.5).multiply(spacing.multiply(0.3)));
256
- const jy = $.let(i.multiply(40503n).remainder(89n).toFloat().divide(89.0).subtract(0.5).multiply(spacing.multiply(0.3)));
257
- // Cycle the four footprint shapes (period 4) and three sizes
258
- // (period 3) independently, so consecutive cells vary in both.
259
- const shape = $.let(i.remainder(4n));
260
- const size = $.let(i.remainder(3n).toFloat().multiply(0.3).add(0.55));
261
- return {
262
- key: East.str `${prefix}-${East.print(i.add(1n))}`,
263
- x: x0.add(col.toFloat().multiply(spacing)).add(jx),
264
- y: y0.add(row.toFloat().multiply(spacing)).add(jy),
265
- kind: East.str `${East.Float.printFixed(cap, 0n)} t cell`,
266
- fill,
267
- cap,
268
- metric: East.str `${East.Float.printFixed(fill, 1n)} t`,
269
- status: statuses.get(i.remainder(6n)),
270
- shape,
271
- size,
272
- };
273
- })));
274
- const units = $.let(block("IN", 3.0, 3.5, 16n, 8n, 3.1, 20.0)
275
- .concat(block("PA", 33.0, 3.5, 84n, 14n, 3.1, 40.0))
276
- .concat(block("PB", 33.0, 27.5, 84n, 21n, 2.0, 40.0))
277
- .concat(block("ST", 3.0, 15.5, 80n, 10n, 1.6, 12.0))
278
- .concat(block("QA", 81.0, 3.5, 30n, 5n, 3.6, 60.0))
279
- .concat(block("OUT", 81.0, 27.5, 12n, 4n, 4.8, 24.0)));
280
- const facilityAreas = $.const([
281
- { id: "inbound", name: "Inbound", x: 1.0, y: 1.0, w: 28.0, h: 10.0 },
282
- { id: "hall-a", name: "Process Hall A", x: 31.0, y: 1.0, w: 46.0, h: 22.0 },
283
- { id: "hall-b", name: "Process Hall B", x: 31.0, y: 25.0, w: 46.0, h: 22.0 },
284
- { id: "storage", name: "Storage", x: 1.0, y: 13.0, w: 28.0, h: 34.0 },
285
- { id: "qa", name: "Quality", x: 79.0, y: 1.0, w: 20.0, h: 22.0 },
286
- { id: "outbound", name: "Outbound", x: 79.0, y: 25.0, w: 20.0, h: 22.0 },
287
- ]);
288
- return (_jsx(Configurator, { controls: [
289
- Configurator.Slot("Editing", _jsx(HStack, { gap: "5", align: "center", wrap: "wrap", children: _jsx(Switch, { checked: roOn, label: "Read-only", onChange: onRo }) })),
290
- ], preview: _jsx(Schematic, { extent: { width: 100, height: 48 }, height: "440px", items: units, item: u => ({
291
- key: u.key, x: u.x, y: u.y, label: u.key,
292
- sublabel: u.kind, icon: "cube",
293
- status: u.status,
294
- meter: { value: u.fill, max: u.cap },
295
- metric: u.metric,
296
- // Four footprint shapes of varying size, centred on the
297
- // unit's (x, y) anchor — polygon vertices are absolute world
298
- // coords, so they are offset from the anchor by ±size.
299
- footprint: u.shape.equal(0n).ifElse(_$ => Schematic.circle(u.size), _$ => u.shape.equal(1n).ifElse(_$ => Schematic.polygon([
300
- { x: u.x.subtract(u.size), y: u.y.subtract(u.size) },
301
- { x: u.x.add(u.size), y: u.y.subtract(u.size) },
302
- { x: u.x.add(u.size), y: u.y.add(u.size) },
303
- { x: u.x.subtract(u.size), y: u.y.add(u.size) },
304
- ]), _$ => u.shape.equal(2n).ifElse(_$ => Schematic.polygon([
305
- { x: u.x, y: u.y.subtract(u.size) },
306
- { x: u.x.add(u.size), y: u.y.add(u.size) },
307
- { x: u.x.subtract(u.size), y: u.y.add(u.size) },
308
- ]), _$ => Schematic.polygon([
309
- { x: u.x, y: u.y.subtract(u.size) },
310
- { x: u.x.add(u.size), y: u.y },
311
- { x: u.x, y: u.y.add(u.size) },
312
- { x: u.x.subtract(u.size), y: u.y },
313
- ])))),
314
- }), zones: facilityAreas, zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h }), scaleUnit: "m", grid: true, navigator: true, minimap: true, readOnly: roOn }), spec: [
315
- Configurator.Spec("readOnly", roOn.ifElse(_$ => "on", _$ => "off")),
316
- ] }));
317
- } }))),
318
- inputs: [],
319
- });
320
- /**
321
- * Layers — items / zones / links grouped into toggleable layers; the canvas
322
- * layer button opens a panel to show / hide / solo / lock each layer.
323
- */
324
- export const schematicLayers = example({
325
- keywords: ["Schematic", "layers", "layer", "visibility", "solo", "lock", "opacity", "toggle", "legend"],
326
- description: "Layer chrome — shell locked and dimmed, maintenance shipped hidden; the layer panel shows / hides / solos / locks each",
327
- fn: East.function([], UIComponentType, (_$) => {
328
- const SCHEMATIC_LAYERS_DATA = [
329
- { id: "GATE", x: 2.5, y: 6.0, kind: "entry", sys: "shell" },
330
- { id: "PUMP-1", x: 6.0, y: 4.0, kind: "pump", sys: "process" },
331
- { id: "TANK-2", x: 12.0, y: 4.0, kind: "tank", sys: "process" },
332
- { id: "VALVE-3", x: 18.0, y: 7.0, kind: "valve", sys: "utilities" },
333
- { id: "SENS-4", x: 9.0, y: 9.0, kind: "sensor", sys: "maintenance" },
334
- ];
335
- const SCHEMATIC_LAYERS_ROOMS_DATA = [
336
- { id: "hall", name: "Hall A", x: 1.0, y: 1.0, w: 22.0, h: 11.0 },
337
- ];
338
- const SCHEMATIC_LAYERS_PIPES_DATA = [
339
- { id: "p1", a: "PUMP-1", b: "TANK-2" },
340
- { id: "p2", a: "TANK-2", b: "VALVE-3" },
341
- ];
342
- return (_jsx(Schematic, { extent: { width: 24, height: 13 }, height: "420px", items: SCHEMATIC_LAYERS_DATA, item: e => ({ key: e.id, x: e.x, y: e.y, label: e.id, sublabel: e.kind, icon: "gear", layer: e.sys }), zones: SCHEMATIC_LAYERS_ROOMS_DATA, zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h, layer: "shell" }), links: SCHEMATIC_LAYERS_PIPES_DATA, link: l => ({ key: l.id, from: l.a, to: l.b, layer: "utilities" }), layers: [
343
- { key: "shell", label: "Building shell", tone: "muted", locked: true, opacity: 0.45 },
344
- { key: "process", label: "Process", tone: "brand" },
345
- { key: "utilities", label: "Utilities", tone: "success" },
346
- { key: "maintenance", label: "Maintenance", tone: "warning", visible: false },
347
- ], scaleUnit: "m" }));
348
- }),
349
- inputs: [],
350
- });
351
- /**
352
- * Geometry — polygon & arc-aware polyline zones plus polygon / circle item
353
- * footprints.
354
- */
355
- export const schematicGeometry = example({
356
- keywords: ["Schematic", "geometry", "polygon", "polyline", "circle", "arc", "bulge", "footprint", "zone", "CAD", "shape", "grid"],
357
- description: "CAD geometry — polygon and arc-aware polyline zones with polygon / circle item footprints on the metric grid",
358
- fn: East.function([], UIComponentType, (_$) => {
359
- const SCHEMATIC_GEOMETRY_DATA = [
360
- { id: "PUMP-1", x: 6.0, y: 4.0, kind: "transfer pump", state: some(variant("success", null)), fp: true, round: false, r: 0.0,
361
- pts: [{ x: 3.5, y: 2.2, bulge: 0.0 }, { x: 8.6, y: 3.0, bulge: 0.0 }, { x: 8.0, y: 6.0, bulge: 0.0 }, { x: 2.9, y: 5.2, bulge: 0.0 }] },
362
- { id: "UNIT-9", x: 16.0, y: 4.5, kind: "storage tank", state: some(variant("warning", null)), fp: false, round: true, r: 2.4,
363
- pts: [{ x: 16.0, y: 4.5, bulge: 0.0 }] },
364
- { id: "VALVE-3", x: 21.6, y: 4.5, kind: "manifold", state: some(variant("info", null)), fp: false, round: false, r: 0.0,
365
- pts: [{ x: 21.6, y: 4.5, bulge: 0.0 }] },
366
- ];
367
- const SCHEMATIC_GEOMETRY_AREAS_DATA = [
368
- { id: "hall-c", name: "Hall C", x: 1.5, y: 1.2, w: 9.1, h: 6.4, road: false,
369
- pts: [{ x: 1.8, y: 2.0, bulge: 0.0 }, { x: 10.2, y: 1.3, bulge: 0.0 }, { x: 10.6, y: 7.0, bulge: 0.0 }, { x: 2.2, y: 7.6, bulge: 0.0 }] },
370
- { id: "svc-rd", name: "Service Rd", x: 1.0, y: 9.0, w: 23.5, h: 3.4, road: true,
371
- pts: [{ x: 1.5, y: 11.6, bulge: 0.0 }, { x: 7.0, y: 9.8, bulge: 0.5 }, { x: 13.0, y: 11.4, bulge: -0.5 }, { x: 19.0, y: 9.6, bulge: 0.4 }, { x: 24.0, y: 10.8, bulge: 0.0 }] },
372
- ];
373
- return (_jsx(Schematic, { extent: { width: 26, height: 14 }, height: "440px", items: SCHEMATIC_GEOMETRY_DATA, item: e => ({
374
- key: e.id, x: e.x, y: e.y, label: e.id,
375
- sublabel: e.kind, status: e.state, icon: "industry",
376
- footprint: e.round.ifElse(_$ => Schematic.circle(e.r), _$ => e.fp.ifElse(_$ => Schematic.polygon(e.pts), _$ => Schematic.rect())),
377
- }), zones: SCHEMATIC_GEOMETRY_AREAS_DATA, zone: z => ({
378
- key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h,
379
- geometry: z.road.ifElse(_$ => Schematic.polyline(z.pts, { width: 1.4 }), _$ => Schematic.polygon(z.pts)),
380
- }), scaleUnit: "m", grid: true }));
381
- }),
382
- inputs: [],
383
- });
384
- /**
385
- * Colour overrides — raw color + bg on item footprints (category palette
386
- * independent of status) and a toned, filled area.
387
- */
388
- export const schematicColorOverrides = example({
389
- keywords: ["Schematic", "color", "tone", "bg", "override", "fillOpacity", "palette", "style"],
390
- description: "Colour overrides — raw color/bg per item footprint and a toned filled zone, independent of status",
391
- fn: East.function([], UIComponentType, (_$) => {
392
- const SCHEMATIC_COLOR_OVERRIDE_DATA = [
393
- { id: "U-1", x: 4.0, y: 4.0, r: 1.4, fill: "bg.brand.subtle" },
394
- { id: "U-2", x: 8.0, y: 4.0, r: 1.4, fill: "bg.success.subtle" },
395
- { id: "U-3", x: 12.0, y: 4.0, r: 1.4, fill: "bg.subtle" },
396
- ];
397
- const SCHEMATIC_COLOR_OVERRIDE_AREAS_DATA = [
398
- { id: "bay", name: "Bay", x: 1.5, y: 1.5, w: 13.0, h: 5.5 },
399
- ];
400
- return (_jsx(Schematic, { extent: { width: 16, height: 8 }, height: "360px", items: SCHEMATIC_COLOR_OVERRIDE_DATA, item: e => ({
401
- key: e.id, x: e.x, y: e.y, label: e.id,
402
- footprint: Schematic.circle(e.r),
403
- color: e.fill,
404
- bg: e.fill,
405
- fillOpacity: 0.18,
406
- }), zones: SCHEMATIC_COLOR_OVERRIDE_AREAS_DATA, zone: z => ({
407
- key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h,
408
- tone: "brand",
409
- bg: "bg.brand.subtle",
410
- }), scaleUnit: "m" }));
411
- }),
412
- inputs: [],
413
- });
414
- export const schematicSlice = example({
415
- keywords: ["Schematic", "slice", "sliceEffect", "excluded", "ghost", "desaturate", "pulse", "halo", "frame", "partition", "filter", "reactive", "switch", "State", "selection", "selectionMode", "sliceSelectField", "in", "marquee", "onSelectionChange"],
416
- description: "Slice panel — slice effect (Slice.partition tags rows; excluded ghost/desaturate reactively via slice* props) and select filter (marquee selection writes an in-filter; the rest ghost)",
417
- fn: East.function([], UIComponentType, (_$) => {
418
- const SCHEMATIC_SLICE_EFFECT_DATA = [
419
- { id: "UNIT-04", x: 3.5, y: 2.6, kind: "unit", st: some(variant("success", null)) },
420
- { id: "UNIT-05", x: 11.5, y: 2.6, kind: "unit", st: some(variant("success", null)) },
421
- { id: "LINE-2", x: 4.5, y: 6.2, kind: "pack", st: some(variant("warning", null)) },
422
- { id: "BAY-OUT", x: 12.0, y: 6.2, kind: "pallets", st: some(variant("info", null)) },
423
- ];
424
- const SCHEMATIC_SELECT_FILTER_DATA = [
425
- { id: "A", x: 3.5, y: 3.0, kind: "unit" },
426
- { id: "B", x: 8.0, y: 3.0, kind: "unit" },
427
- { id: "C", x: 12.5, y: 3.0, kind: "pack" },
428
- { id: "D", x: 5.5, y: 6.4, kind: "unit" },
429
- { id: "E", x: 10.0, y: 6.4, kind: "pack" },
430
- ];
431
- const EffectEquipType = StructType({ id: StringType, x: FloatType, y: FloatType, kind: StringType, st: OptionType(StatusTokenType) });
432
- const FilterEquipType = StructType({ id: StringType, x: FloatType, y: FloatType, kind: StringType });
433
- return (_jsxs(VStack, { gap: "4", align: "stretch", children: [_jsx(Separator, { label: "SLICE EFFECT", align: "start" }), _jsx(Reactive, { children: $ => {
434
- const data = $.const(SCHEMATIC_SLICE_EFFECT_DATA, ArrayType(EffectEquipType));
435
- // Seed an active filter (kind = "unit") so two rows already fail
436
- // the narrowing — the effect is visible at first render: the
437
- // "pack" / "pallets" units ghost out, the "unit" survivors pulse.
438
- const slice = $.let(Slice.bind("ex.schematic.effect", data, {
439
- fields: { id: { label: "ID" }, kind: { label: "Kind" } }, search: ["id", "kind"],
440
- initial: { kind: ["unit"] },
441
- }));
442
- // Full set tagged with pass/fail — excluded rows STAY (ghosted),
443
- // rather than the pre-narrowed `Slice.rows`.
444
- const tagged = $.let(Slice.partition([EffectEquipType], slice));
445
- // Every effect setting is a flat `slice*` prop (SubtypeExprOrValue),
446
- // so a State-bound switch drives it reactively — flip a switch, the
447
- // schematic re-renders in place. No builder, no escape hatch.
448
- const hide = $.let(State.bind([BooleanType], "ex.effect.hide", false));
449
- const desat = $.let(State.bind([BooleanType], "ex.effect.desat", true));
450
- const pulse = $.let(State.bind([BooleanType], "ex.effect.pulse", true));
451
- const frame = $.let(State.bind([BooleanType], "ex.effect.frame", true));
452
- const opacity = $.let(State.bind([FloatType], "ex.effect.opacity", 0.35));
453
- const hideOn = $.let(hide.read());
454
- const desatOn = $.let(desat.read());
455
- const pulseOn = $.let(pulse.read());
456
- const frameOn = $.let(frame.read());
457
- const opacityVal = $.let(opacity.read());
458
- const onHide = $.const(East.function([BooleanType], NullType, ($, v) => { $(hide.write(v)); }));
459
- const onDesat = $.const(East.function([BooleanType], NullType, ($, v) => { $(desat.write(v)); }));
460
- const onPulse = $.const(East.function([BooleanType], NullType, ($, v) => { $(pulse.write(v)); }));
461
- const onFrame = $.const(East.function([BooleanType], NullType, ($, v) => { $(frame.write(v)); }));
462
- const onOpacity = $.const(East.function([FloatType], NullType, ($, v) => { $(opacity.write(v)); }));
463
- // Reactive emphasis option — `some(pulse)` on, `none` (ring off) off.
464
- const emphasis = $.let(pulseOn.ifElse(_$ => some(variant("pulse", null)), _$ => none), OptionType(Schematic.Types.Emphasis));
465
- return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsxs(HStack, { gap: "4", children: [_jsx(Switch, { checked: hideOn, label: "Hide filtered", onChange: onHide }), _jsx(Switch, { checked: desatOn, label: "Desaturate", onChange: onDesat }), _jsx(Switch, { checked: pulseOn, label: "Pulse ring", onChange: onPulse }), _jsx(Switch, { checked: frameOn, label: "Frame", onChange: onFrame })] }), _jsxs(HStack, { gap: "3", align: "center", children: [_jsx(Text.MonoLabel, { children: "OPACITY" }), _jsx(Slider, { value: opacityVal, min: 0, max: 1, step: 0.05, onChange: onOpacity })] }), _jsx(Schematic, { extent: { width: 16, height: 9 }, height: "400px", items: tagged, item: t => ({
466
- key: t.value.id, x: t.value.x, y: t.value.y, label: t.value.id,
467
- sublabel: t.value.kind, icon: "database", status: t.value.st,
468
- excluded: t.matched.not(),
469
- }), slice: slice, affordances: ["search", "filter"], sliceOpacity: opacityVal, sliceDesaturate: desatOn, sliceEmphasis: emphasis, sliceFrame: frameOn, sliceHidden: hideOn })] }));
470
- } }), _jsx(Separator, { label: "SELECT FILTER", align: "start" }), _jsx(Reactive, { children: $ => {
471
- const data = $.const(SCHEMATIC_SELECT_FILTER_DATA, ArrayType(FilterEquipType));
472
- // No initial filter — everything matches until a selection writes one.
473
- const slice = $.let(Slice.bind("ex.schematic.selfilter", data, {
474
- fields: { id: { label: "ID" }, kind: { label: "Kind" } }, search: ["id", "kind"],
475
- }));
476
- // Full set tagged pass/fail; a marquee selection writes `in(id, keys)`
477
- // via sliceSelectField, so the non-selected re-tag excluded → ghost.
478
- const tagged = $.let(Slice.partition([FilterEquipType], slice));
479
- return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsx(Schematic, { extent: { width: 16, height: 9 }, height: "400px", items: tagged, item: t => ({
480
- key: t.value.id, x: t.value.x, y: t.value.y, label: t.value.id,
481
- sublabel: t.value.kind, icon: "database", excluded: t.matched.not(),
482
- }), slice: slice, affordances: ["filter"], selectionMode: "multiple", sliceSelectField: "id", sliceOpacity: 0.2, sliceDesaturate: true }), _jsx(Text.MonoLabel, { children: "DRAG A BOX TO SELECT \u00B7 the rest ghost via the slice" })] }));
483
- } })] }));
484
- }),
485
- inputs: [],
486
- });
487
- export const schematicInteractions = example({
488
- keywords: ["Schematic", "Reactive", "State", "onSelect", "onItemOpen", "double-click", "open", "drill-in", "interactive", "selection", "selectionMode", "single", "multiple", "marquee", "onSelectionChange", "selectZoomFocus", "focus", "zoom", "multi-select", "Switch", "zone", "area", "onSelectZone", "onZoneSelectionChange", "childItemKeys", "move", "reposition", "drag", "onMoveItem", "readOnlyItems", "editing", "group", "hover", "HoverCard", "itemHover", "zoneHover", "linkHover", "Sparkline", "chart", "inspection", "lazy", "viewport", "onViewportChange", "camera", "bounds", "settle", "SegmentGroup", "Configurator", "getTag", "configurator"],
489
- description: "Schematic interaction configurator — a tool axis (select / marquee / zone / move) plus multi-select, zoom-focus and movable switches; hover cards stay on; the aside logs five event lines",
490
- fn: East.function([], UIComponentType, (_$) => {
491
- const SCHEMATIC_INTERACTIONS_ITEMS = [
492
- { id: "CELL-A", x: 3.0, y: 3.0 },
493
- { id: "CELL-B", x: 9.0, y: 3.0 },
494
- { id: "M1", x: 15.0, y: 3.0 },
495
- { id: "P1", x: 6.0, y: 9.0 }, { id: "P2", x: 18.0, y: 9.0 },
496
- ];
497
- const SCHEMATIC_INTERACTIONS_ZONES = [
498
- { id: "hall-a", name: "Hall A", x: 1.0, y: 1.0, w: 10.0, h: 4.5 },
499
- { id: "hall-b", name: "Hall B", x: 12.5, y: 1.0, w: 10.5, h: 4.5 },
500
- { id: "dock", name: "Dock", x: 1.0, y: 7.0, w: 22.0, h: 4.0 },
501
- ];
502
- return (_jsx(Reactive, { children: $ => {
503
- // The tool axis is a bare label array — the control and the
504
- // per-tool prop mapping below read the same four keys.
505
- const tools = $.const(["select", "marquee", "zone", "move"], ArrayType(StringType));
506
- // Tool mode — select / marquee / zone / move.
507
- const toolBind = $.let(State.bind([StringType], "schematic_tool", "select"));
508
- const tool = $.let(toolBind.read());
509
- const onToolChange = $.const(East.function([StringType], NullType, ($, next) => {
510
- $(toolBind.write(next));
511
- }));
512
- // Event log binds + callbacks (verbatim from schematicInteractive).
513
- const bind = $.let(State.bind([StringType], "schematic_selected", "none"));
514
- const opened = $.let(State.bind([StringType], "schematic_opened", "none"));
515
- const onSelect = $.const(East.function([StringType], NullType, ($, key) => {
516
- $(bind.write(key));
517
- }));
518
- const onItemOpen = $.const(East.function([StringType], NullType, ($, key) => {
519
- $(opened.write(key));
520
- }));
521
- const selected = $.let(bind.read());
522
- const openedKey = $.let(opened.read());
523
- // The full selected-key set is mirrored into State on every change
524
- // (verbatim from schematicRangeSelect).
525
- const keysBind = $.let(State.bind([ArrayType(StringType)], "schematic_selected_keys", []));
526
- const onSelectionChange = $.const(East.function([Schematic.Types.SelectionEvent], NullType, ($, ev) => {
527
- $(keysBind.write(ev.selectedKeys));
528
- }));
529
- const keys = $.let(keysBind.read());
530
- const count = $.let(keys.size());
531
- // Reactive toggle for the camera-on-select behaviour (schematicRangeSelect's
532
- // switch, original State key) — applied under the marquee tool.
533
- const focus = $.let(State.bind([BooleanType], "ex.schematic.focus", true));
534
- const focusOn = $.let(focus.read());
535
- const onFocus = $.const(East.function([BooleanType], NullType, ($, v) => { $(focus.write(v)); }));
536
- // Multi-select switch (schematicRangeSelect's original key; the zone
537
- // example's ex.zone.multi toggled the same selectionMode variant and
538
- // folds into this one control).
539
- const multi = $.let(State.bind([BooleanType], "ex.schematic.multi", true));
540
- const multiOn = $.let(multi.read());
541
- const onMulti = $.const(East.function([BooleanType], NullType, ($, v) => { $(multi.write(v)); }));
542
- // Zone-selection log line (verbatim from schematicZoneSelect).
543
- const readout = $.let(State.bind([StringType], "schematic_zone_sel", "—"));
544
- const onZoneSelectionChange = $.const(East.function([Schematic.Types.ZoneSelectionEvent], NullType, ($, ev) => {
545
- $(readout.write(East.str `${East.print(ev.selectedKeys.size())} zone(s) · ${East.print(ev.childItemKeys.size())} item(s) inside`));
546
- }));
547
- const zoneTxt = $.let(readout.read());
548
- // Move log + movable switch (verbatim from schematicItemMove).
549
- const log = $.let(State.bind([StringType], "schematic_move_log", "—"));
550
- const onMoveItem = $.const(East.function([Schematic.Types.ItemMoveEvent], NullType, ($, ev) => {
551
- $(log.write(East.str `moved ${East.print(ev.keys.size())} item(s) · ${ev.key} → ${East.Float.printFixed(ev.x, 1n)}, ${East.Float.printFixed(ev.y, 1n)}`));
552
- }));
553
- const movable = $.let(State.bind([BooleanType], "ex.move.on", true));
554
- const mOn = $.let(movable.read());
555
- const onM = $.const(East.function([BooleanType], NullType, ($, v) => { $(movable.write(v)); }));
556
- const moveTxt = $.let(log.read());
557
- // Debounced viewport line (verbatim from schematicViewport).
558
- const viewportBind = $.let(State.bind([StringType], "schematic_viewport", "—"));
559
- const onViewportChange = $.const(East.function([Schematic.Types.ViewportEvent], NullType, ($, ev) => {
560
- $(viewportBind.write(East.str `zoom ${East.Float.printFixed(ev.zoom, 1n)} · x ${East.Float.printFixed(ev.minX, 1n)}..${East.Float.printFixed(ev.maxX, 1n)} · y ${East.Float.printFixed(ev.minY, 1n)}..${East.Float.printFixed(ev.maxY, 1n)}`));
561
- }));
562
- const viewportTxt = $.let(viewportBind.read());
563
- // Hover cards (verbatim from schematicHover) — enabled in ALL modes;
564
- // hover config is orthogonal to the tool.
565
- const itemHover = $.const(East.function([StringType], UIComponentType, (_$, key) => (_jsxs(VStack, { gap: "1", align: "flex-start", children: [_jsx(Text.MonoLabel, { children: East.str `${key} · throughput (7d)` }), _jsx(Sparkline, { data: [3.2, 4.1, 3.8, 5.0, 4.6, 5.4, 5.1], type: "area", width: "180px", height: "44px" })] }))));
566
- const zoneHover = $.const(East.function([StringType], UIComponentType, (_$, key) => (_jsx(Text.MonoLabel, { children: East.str `${key} — CIP window 14:00–15:00` }))));
567
- const linkHover = $.const(East.function([StringType], UIComponentType, (_$, key) => (_jsx(Text.MonoLabel, { children: East.str `${key} · 12.4 m³/h` }))));
568
- // Per-tool prop mapping — where a prop differs per tool mode it is
569
- // derived from the mode value with ifElse.
570
- const selMode = $.let(tool.equal("select").ifElse(
571
- // Select — single-tap inspection.
572
- _$ => variant("single", null), _$ => tool.equal("move").ifElse(
573
- // Move — keeps `multiple` so dragging a SELECTED item moves
574
- // the whole selection rigidly (schematicItemMove).
575
- _$ => variant("multiple", null),
576
- // Marquee / zone — honour the Multi-select switch (marquee
577
- // and Shift-extend need `multiple`).
578
- _$ => multiOn.ifElse(_$ => variant("multiple", null), _$ => variant("single", null)))), Schematic.Types.SelectionMode);
579
- // Camera-on-select only under the marquee tool: focus ON flies / fits,
580
- // OFF leaves the camera put (schematicRangeSelect).
581
- const zoomFocus = $.let(tool.equal("marquee").ifElse(_$ => focusOn, _$ => false), BooleanType);
582
- // Items reposition only under the move tool, gated by its switch.
583
- const roItems = $.let(tool.equal("move").ifElse(_$ => mOn.not(), _$ => true), BooleanType);
584
- return (_jsx(Configurator, { controls: [
585
- Configurator.Control("Tool", tool, _jsx(Select, { value: tool, onChange: onToolChange, size: "sm", items: tools.map((_$, t) => Select.Item(t, t)) })),
586
- // Slots, not Controls: the switches report through the
587
- // aside's event log rather than as one value each.
588
- Configurator.Slot("Selection", _jsx(HStack, { gap: "5", align: "center", wrap: "wrap", children: _jsx(Switch, { checked: multiOn, label: "Multi-select (marquee/zone)", onChange: onMulti }) })),
589
- Configurator.Slot("Camera", _jsx(HStack, { gap: "5", align: "center", wrap: "wrap", children: _jsx(Switch, { checked: focusOn, label: "Zoom focus (marquee)", onChange: onFocus }) })),
590
- Configurator.Slot("Items", _jsx(HStack, { gap: "5", align: "center", wrap: "wrap", children: _jsx(Switch, { checked: mOn, label: "Movable (move)", onChange: onM }) })),
591
- ], preview:
592
- /* schematicZoneSelect's 24 × 12 extent — the zone bodies (and
593
- the M1 / P1 / P2 rows inside them) need the wider world rect. */
594
- _jsx(Schematic, { navigator: false, extent: { width: 24, height: 12 }, height: "440px", items: SCHEMATIC_INTERACTIONS_ITEMS, item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "industry" }), zones: SCHEMATIC_INTERACTIONS_ZONES, zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h }), onSelect: onSelect, onItemOpen: onItemOpen, selectionMode: selMode, selectZoomFocus: zoomFocus, onSelectionChange: onSelectionChange, onZoneSelectionChange: onZoneSelectionChange, readOnlyItems: roItems, onMoveItem: onMoveItem, itemHover: itemHover, zoneHover: zoneHover, linkHover: linkHover, onViewportChange: onViewportChange }), aside: {
595
- label: "Event log · Reactive",
596
- body: (_jsxs(VStack, { gap: "1", align: "stretch", children: [_jsx(Text, { fontFamily: "mono", children: East.str `INSPECTING · ${selected} · OPENED · ${openedKey}` }), _jsx(Text, { fontFamily: "mono", children: East.str `SELECTED · ${East.print(count)}` }), _jsx(Text, { fontFamily: "mono", children: East.str `ZONES · ${zoneTxt}` }), _jsx(Text, { fontFamily: "mono", children: East.str `MOVE · ${moveTxt}` }), _jsx(Text, { fontFamily: "mono", children: East.str `VIEW · ${viewportTxt}` })] })),
597
- } }));
598
- } }));
599
- }),
600
- inputs: [],
601
- });
602
- //# sourceMappingURL=schematic.examples.js.map