@elaraai/east-ui 1.0.28 → 1.0.30
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/README.md +3 -3
- package/dist/src/charts/chart/index.d.ts +102 -0
- package/dist/src/charts/chart/index.d.ts.map +1 -1
- package/dist/src/charts/chart/index.js +30 -11
- package/dist/src/charts/chart/index.js.map +1 -1
- package/dist/src/charts/spec/index.d.ts +204 -0
- package/dist/src/charts/spec/index.d.ts.map +1 -1
- package/dist/src/charts/spec/types.d.ts +3 -11
- package/dist/src/charts/spec/types.d.ts.map +1 -1
- package/dist/src/charts/spec/types.js +5 -20
- package/dist/src/charts/spec/types.js.map +1 -1
- package/dist/src/collections/blend/index.d.ts.map +1 -1
- package/dist/src/collections/blend/index.js +2 -1
- package/dist/src/collections/blend/index.js.map +1 -1
- package/dist/src/collections/board/index.d.ts +490 -0
- package/dist/src/collections/board/index.d.ts.map +1 -0
- package/dist/src/collections/board/index.js +282 -0
- package/dist/src/collections/board/index.js.map +1 -0
- package/dist/src/collections/board/types.d.ts +308 -0
- package/dist/src/collections/board/types.d.ts.map +1 -0
- package/dist/src/collections/board/types.js +156 -0
- package/dist/src/collections/board/types.js.map +1 -0
- package/dist/src/collections/calendar/index.d.ts.map +1 -1
- package/dist/src/collections/calendar/index.js +2 -1
- package/dist/src/collections/calendar/index.js.map +1 -1
- package/dist/src/collections/gantt/index.d.ts +1 -1
- package/dist/src/collections/gantt/index.d.ts.map +1 -1
- package/dist/src/collections/gantt/index.js +45 -52
- package/dist/src/collections/gantt/index.js.map +1 -1
- package/dist/src/collections/index.d.ts +1 -0
- package/dist/src/collections/index.d.ts.map +1 -1
- package/dist/src/collections/index.js +1 -0
- package/dist/src/collections/index.js.map +1 -1
- package/dist/src/collections/library/index.d.ts.map +1 -1
- package/dist/src/collections/library/index.js +2 -1
- package/dist/src/collections/library/index.js.map +1 -1
- package/dist/src/collections/map/index.d.ts.map +1 -1
- package/dist/src/collections/map/index.js +5 -4
- package/dist/src/collections/map/index.js.map +1 -1
- package/dist/src/collections/matrix/index.d.ts.map +1 -1
- package/dist/src/collections/matrix/index.js +2 -1
- package/dist/src/collections/matrix/index.js.map +1 -1
- package/dist/src/collections/planner/index.d.ts.map +1 -1
- package/dist/src/collections/planner/index.js +2 -1
- package/dist/src/collections/planner/index.js.map +1 -1
- package/dist/src/collections/roster/index.d.ts +3 -0
- package/dist/src/collections/roster/index.d.ts.map +1 -1
- package/dist/src/collections/roster/index.js +4 -2
- package/dist/src/collections/roster/index.js.map +1 -1
- package/dist/src/collections/roster/types.d.ts +3 -0
- package/dist/src/collections/roster/types.d.ts.map +1 -1
- package/dist/src/collections/roster/types.js +3 -0
- package/dist/src/collections/roster/types.js.map +1 -1
- package/dist/src/collections/schematic/index.d.ts +537 -709
- package/dist/src/collections/schematic/index.d.ts.map +1 -1
- package/dist/src/collections/schematic/index.js +289 -9
- package/dist/src/collections/schematic/index.js.map +1 -1
- package/dist/src/collections/schematic/types.d.ts +562 -841
- package/dist/src/collections/schematic/types.d.ts.map +1 -1
- package/dist/src/collections/schematic/types.js +416 -46
- package/dist/src/collections/schematic/types.js.map +1 -1
- package/dist/src/collections/table/index.d.ts +19 -11
- package/dist/src/collections/table/index.d.ts.map +1 -1
- package/dist/src/collections/table/index.js +65 -78
- package/dist/src/collections/table/index.js.map +1 -1
- package/dist/src/component.d.ts +1572 -63
- package/dist/src/component.d.ts.map +1 -1
- package/dist/src/component.js +55 -15
- package/dist/src/component.js.map +1 -1
- package/dist/src/contracts/format.d.ts +39 -0
- package/dist/src/contracts/format.d.ts.map +1 -0
- package/dist/src/contracts/format.js +38 -0
- package/dist/src/contracts/format.js.map +1 -0
- package/dist/src/contracts/index.d.ts +1 -0
- package/dist/src/contracts/index.d.ts.map +1 -1
- package/dist/src/contracts/index.js +1 -0
- package/dist/src/contracts/index.js.map +1 -1
- package/dist/src/contracts/slice-affordances.d.ts +13 -3
- package/dist/src/contracts/slice-affordances.d.ts.map +1 -1
- package/dist/src/contracts/slice-affordances.js +12 -2
- package/dist/src/contracts/slice-affordances.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +1 -1
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +1 -1
- package/dist/src/internal.js.map +1 -1
- package/dist/src/platform/slice/impl.d.ts +1 -0
- package/dist/src/platform/slice/impl.d.ts.map +1 -1
- package/dist/src/platform/slice/impl.js +85 -34
- package/dist/src/platform/slice/impl.js.map +1 -1
- package/dist/src/platform/slice/index.d.ts +2098 -29
- package/dist/src/platform/slice/index.d.ts.map +1 -1
- package/dist/src/platform/slice/index.js +145 -12
- package/dist/src/platform/slice/index.js.map +1 -1
- package/dist/src/runtime/collections/board.d.ts +73 -0
- package/dist/src/runtime/collections/board.d.ts.map +1 -0
- package/dist/src/runtime/collections/board.js +68 -0
- package/dist/src/runtime/collections/board.js.map +1 -0
- package/dist/src/runtime/collections/index.d.ts +1 -0
- package/dist/src/runtime/collections/index.d.ts.map +1 -1
- package/dist/src/runtime/collections/index.js +1 -0
- package/dist/src/runtime/collections/index.js.map +1 -1
- package/dist/src/runtime/collections/schematic.d.ts +11 -4
- package/dist/src/runtime/collections/schematic.d.ts.map +1 -1
- package/dist/src/runtime/collections/schematic.js +8 -2
- package/dist/src/runtime/collections/schematic.js.map +1 -1
- package/dist/src/runtime/slice.d.ts +7 -3
- package/dist/src/runtime/slice.d.ts.map +1 -1
- package/dist/src/runtime/slice.js +62 -14
- package/dist/src/runtime/slice.js.map +1 -1
- package/dist/src/shared/reify.d.ts +76 -0
- package/dist/src/shared/reify.d.ts.map +1 -0
- package/dist/src/shared/reify.js +85 -0
- package/dist/src/shared/reify.js.map +1 -0
- package/dist/src/slice/breakdown/index.d.ts +100 -0
- package/dist/src/slice/breakdown/index.d.ts.map +1 -1
- package/dist/src/slice/breakdown/types.d.ts +100 -0
- package/dist/src/slice/breakdown/types.d.ts.map +1 -1
- package/dist/src/slice/cohort/index.d.ts +787 -10
- package/dist/src/slice/cohort/index.d.ts.map +1 -1
- package/dist/src/slice/cohort/index.js +33 -10
- package/dist/src/slice/cohort/index.js.map +1 -1
- package/dist/src/slice/cohort/types.d.ts +225 -99
- package/dist/src/slice/cohort/types.d.ts.map +1 -1
- package/dist/src/slice/cohort/types.js +31 -9
- package/dist/src/slice/cohort/types.js.map +1 -1
- package/dist/src/slice/filter/index.d.ts +100 -0
- package/dist/src/slice/filter/index.d.ts.map +1 -1
- package/dist/src/slice/filter/types.d.ts +100 -0
- package/dist/src/slice/filter/types.d.ts.map +1 -1
- package/dist/src/slice/index.d.ts +2862 -126
- package/dist/src/slice/index.d.ts.map +1 -1
- package/dist/src/slice/index.js +6 -4
- package/dist/src/slice/index.js.map +1 -1
- package/dist/src/slice/legend/index.d.ts +124 -7
- package/dist/src/slice/legend/index.d.ts.map +1 -1
- package/dist/src/slice/legend/index.js +20 -10
- package/dist/src/slice/legend/index.js.map +1 -1
- package/dist/src/slice/legend/types.d.ts +233 -108
- package/dist/src/slice/legend/types.d.ts.map +1 -1
- package/dist/src/slice/legend/types.js +26 -5
- package/dist/src/slice/legend/types.js.map +1 -1
- package/dist/src/slice/rail/index.d.ts +22 -0
- package/dist/src/slice/rail/index.d.ts.map +1 -1
- package/dist/src/slice/rail/index.js +9 -1
- package/dist/src/slice/rail/index.js.map +1 -1
- package/dist/src/slice/range/index.d.ts +100 -0
- package/dist/src/slice/range/index.d.ts.map +1 -1
- package/dist/src/slice/range/types.d.ts +100 -0
- package/dist/src/slice/range/types.d.ts.map +1 -1
- package/dist/src/slice/search/index.d.ts +100 -0
- package/dist/src/slice/search/index.d.ts.map +1 -1
- package/dist/src/slice/search/types.d.ts +100 -0
- package/dist/src/slice/search/types.d.ts.map +1 -1
- package/dist/src/slice/summary/index.d.ts +100 -0
- package/dist/src/slice/summary/index.d.ts.map +1 -1
- package/dist/src/slice/summary/types.d.ts +100 -0
- package/dist/src/slice/summary/types.d.ts.map +1 -1
- package/dist/test/collections/board.examples.d.ts +7 -0
- package/dist/test/collections/board.examples.d.ts.map +1 -0
- package/dist/test/collections/board.examples.js +191 -0
- package/dist/test/collections/board.examples.js.map +1 -0
- package/dist/test/collections/gantt.examples.js +2 -2
- package/dist/test/collections/gantt.examples.js.map +1 -1
- package/dist/test/collections/matrix.examples.d.ts.map +1 -1
- package/dist/test/collections/matrix.examples.js +4 -3
- package/dist/test/collections/matrix.examples.js.map +1 -1
- package/dist/test/collections/schematic.examples.d.ts +11 -1
- package/dist/test/collections/schematic.examples.d.ts.map +1 -1
- package/dist/test/collections/schematic.examples.js +354 -24
- package/dist/test/collections/schematic.examples.js.map +1 -1
- package/dist/test/collections/table.examples.d.ts.map +1 -1
- package/dist/test/collections/table.examples.js +9 -6
- package/dist/test/collections/table.examples.js.map +1 -1
- package/dist/test/disclosure/story.examples.js +1 -1
- package/dist/test/disclosure/story.examples.js.map +1 -1
- package/dist/test/display/combine.examples.js +2 -2
- package/dist/test/display/combine.examples.js.map +1 -1
- package/dist/test/display/editable-chip.examples.js +1 -1
- package/dist/test/display/editable-chip.examples.js.map +1 -1
- package/dist/test/slice/slice.examples.d.ts +5 -0
- package/dist/test/slice/slice.examples.d.ts.map +1 -1
- package/dist/test/slice/slice.examples.js +216 -6
- package/dist/test/slice/slice.examples.js.map +1 -1
- package/package.json +3 -3
|
@@ -4,11 +4,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "@elaraai/east-ui/jsx-runtime";
|
|
|
4
4
|
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
5
5
|
*/
|
|
6
6
|
/** @jsxImportSource @elaraai/east-ui */
|
|
7
|
-
import { East, ArrayType, FloatType, IntegerType, NullType, OptionType, StringType, StructType, example, variant, some, none } from "@elaraai/east";
|
|
7
|
+
import { East, ArrayType, BooleanType, FloatType, IntegerType, NullType, OptionType, StringType, StructType, example, variant, some, none } from "@elaraai/east";
|
|
8
8
|
import { State, StatusTokenType, UIComponentType } from "@elaraai/east-ui";
|
|
9
|
-
import { Reactive, Schematic, Slice, Text, VStack } from "@elaraai/east-ui";
|
|
9
|
+
import { HStack, Reactive, Schematic, Slice, Slider, Sparkline, Switch, Text, VStack } from "@elaraai/east-ui";
|
|
10
10
|
export const schematicPlant = example({
|
|
11
|
-
keywords: ["Schematic", "canvas", "items", "zones", "links", "meter", "status", "hatch"],
|
|
11
|
+
keywords: ["Schematic", "canvas", "items", "zones", "links", "meter", "status", "hatch", "label", "metric", "parallel", "fan-out", "flow"],
|
|
12
12
|
description: "Plant floor — tanks and lines in halls with a walkway band and pipe runs",
|
|
13
13
|
fn: East.function([], UIComponentType, ($) => {
|
|
14
14
|
const equipment = $.const([
|
|
@@ -28,11 +28,15 @@ export const schematicPlant = example({
|
|
|
28
28
|
]);
|
|
29
29
|
// Already the resolved link type — passed through with no `link` mapper.
|
|
30
30
|
const orthogonal = variant("orthogonal", { corner: none });
|
|
31
|
+
// p2 + p2b share the same endpoint pair — the renderer fans them into
|
|
32
|
+
// parallel lanes (#180) so both edges (feed + CIP return) stay readable;
|
|
33
|
+
// labels/metrics render mid-path at label zoom.
|
|
31
34
|
const pipes = $.const([
|
|
32
|
-
{ key: "p1", from: "UNIT-04", to: "LINE-2", style: Schematic.solid(), route: orthogonal, via: [] },
|
|
33
|
-
{ key: "p2", from: "UNIT-05", to: "LINE-2", style: Schematic.solid(), route: orthogonal, via: [] },
|
|
34
|
-
{ key: "
|
|
35
|
-
{ key: "
|
|
35
|
+
{ key: "p1", from: "UNIT-04", to: "LINE-2", label: some("feed"), metric: some("12 m³/h"), style: Schematic.solid(), route: orthogonal, via: [], layer: none },
|
|
36
|
+
{ key: "p2", from: "UNIT-05", to: "LINE-2", label: some("feed"), metric: some("9 m³/h"), style: Schematic.solid(), route: orthogonal, via: [], layer: none },
|
|
37
|
+
{ key: "p2b", from: "UNIT-05", to: "LINE-2", label: some("CIP return"), metric: none, style: Schematic.dashed(), route: orthogonal, via: [], layer: none },
|
|
38
|
+
{ key: "p3", from: "UNIT-06", to: "LINE-2", label: none, metric: none, style: Schematic.solid(), route: orthogonal, via: [], layer: none },
|
|
39
|
+
{ 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 },
|
|
36
40
|
], ArrayType(Schematic.Types.Link));
|
|
37
41
|
return (_jsx(Schematic, { extent: { width: 29, height: 12.5 }, height: "440px", items: equipment, item: e => ({
|
|
38
42
|
key: e.id, x: e.x, y: e.y, label: e.id,
|
|
@@ -45,58 +49,384 @@ export const schematicPlant = example({
|
|
|
45
49
|
}),
|
|
46
50
|
inputs: [],
|
|
47
51
|
});
|
|
48
|
-
export const
|
|
49
|
-
keywords: ["Schematic", "slice", "
|
|
50
|
-
description: "Schematic
|
|
52
|
+
export const schematicSliceEffect = example({
|
|
53
|
+
keywords: ["Schematic", "slice", "sliceEffect", "excluded", "ghost", "desaturate", "pulse", "halo", "frame", "partition", "filter", "reactive", "switch", "State"],
|
|
54
|
+
description: "Schematic slice effect — filtered-out items stay as ghosted / desaturated context (Slice.partition tags each row, `excluded` marks the losers) while the matched remainder is emphasised, instead of vanishing; the flat `slice*` props are SubtypeExprOrValue, so State-bound switches toggle pulse / frame / desaturate reactively",
|
|
51
55
|
fn: East.function([], UIComponentType, (_$) => {
|
|
52
|
-
const EquipType = StructType({ id: StringType, x: FloatType, y: FloatType, kind: StringType });
|
|
56
|
+
const EquipType = StructType({ id: StringType, x: FloatType, y: FloatType, kind: StringType, st: OptionType(StatusTokenType) });
|
|
53
57
|
const cfg = Slice.config(EquipType, {
|
|
54
58
|
fields: { id: { label: "ID" }, kind: { label: "Kind" } },
|
|
55
59
|
searchFieldIds: ["id", "kind"],
|
|
56
60
|
});
|
|
57
61
|
return (_jsx(Reactive, { children: $ => {
|
|
62
|
+
// Small extent ⇒ items render as CARDS, where the ghost / desaturate
|
|
63
|
+
// / ring effects read clearly (on labelled pins they'd be too subtle).
|
|
64
|
+
// Each carries a status tone so `desaturate` visibly drains its colour.
|
|
58
65
|
const data = $.const([
|
|
59
|
-
{ id: "UNIT-04", x: 3.
|
|
60
|
-
{ id: "UNIT-05", x:
|
|
61
|
-
{ id: "LINE-2", x:
|
|
62
|
-
{ id: "BAY-OUT", x:
|
|
66
|
+
{ id: "UNIT-04", x: 3.5, y: 2.6, kind: "unit", st: some(variant("success", null)) },
|
|
67
|
+
{ id: "UNIT-05", x: 11.5, y: 2.6, kind: "unit", st: some(variant("success", null)) },
|
|
68
|
+
{ id: "LINE-2", x: 4.5, y: 6.2, kind: "pack", st: some(variant("warning", null)) },
|
|
69
|
+
{ id: "BAY-OUT", x: 12.0, y: 6.2, kind: "pallets", st: some(variant("info", null)) },
|
|
63
70
|
], ArrayType(EquipType));
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
// Seed an active filter (kind = "unit") so two rows already fail
|
|
72
|
+
// the narrowing — the effect is visible at first render: the
|
|
73
|
+
// "pack" / "pallets" units ghost out, the "unit" survivors pulse.
|
|
74
|
+
const slice = $.let(Slice.bind([EquipType], "ex.schematic.effect", cfg, Slice.state({
|
|
75
|
+
filters: [variant("string", { fieldId: "kind", op: variant("eq", "unit") })],
|
|
76
|
+
}), data, none));
|
|
77
|
+
// Full set tagged with pass/fail — excluded rows STAY (ghosted),
|
|
78
|
+
// rather than the pre-narrowed `Slice.rows`.
|
|
79
|
+
const tagged = $.let(Slice.partition([EquipType], slice));
|
|
80
|
+
// Every effect setting is a flat `slice*` prop (SubtypeExprOrValue),
|
|
81
|
+
// so a State-bound switch drives it reactively — flip a switch, the
|
|
82
|
+
// schematic re-renders in place. No builder, no escape hatch.
|
|
83
|
+
const hide = $.let(State.bind([BooleanType], "ex.effect.hide", false));
|
|
84
|
+
const desat = $.let(State.bind([BooleanType], "ex.effect.desat", true));
|
|
85
|
+
const pulse = $.let(State.bind([BooleanType], "ex.effect.pulse", true));
|
|
86
|
+
const frame = $.let(State.bind([BooleanType], "ex.effect.frame", true));
|
|
87
|
+
const opacity = $.let(State.bind([FloatType], "ex.effect.opacity", 0.35));
|
|
88
|
+
const hideOn = $.let(hide.read());
|
|
89
|
+
const desatOn = $.let(desat.read());
|
|
90
|
+
const pulseOn = $.let(pulse.read());
|
|
91
|
+
const frameOn = $.let(frame.read());
|
|
92
|
+
const opacityVal = $.let(opacity.read());
|
|
93
|
+
const onHide = $.const(East.function([BooleanType], NullType, ($, v) => { $(hide.write(v)); }));
|
|
94
|
+
const onDesat = $.const(East.function([BooleanType], NullType, ($, v) => { $(desat.write(v)); }));
|
|
95
|
+
const onPulse = $.const(East.function([BooleanType], NullType, ($, v) => { $(pulse.write(v)); }));
|
|
96
|
+
const onFrame = $.const(East.function([BooleanType], NullType, ($, v) => { $(frame.write(v)); }));
|
|
97
|
+
const onOpacity = $.const(East.function([FloatType], NullType, ($, v) => { $(opacity.write(v)); }));
|
|
98
|
+
// Reactive emphasis option — `some(pulse)` on, `none` (ring off) off.
|
|
99
|
+
const emphasis = $.let(pulseOn.ifElse(_$ => some(variant("pulse", null)), _$ => none), OptionType(Schematic.Types.Emphasis));
|
|
100
|
+
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 => ({
|
|
101
|
+
key: t.value.id, x: t.value.x, y: t.value.y, label: t.value.id,
|
|
102
|
+
sublabel: t.value.kind, icon: "database", status: t.value.st,
|
|
103
|
+
excluded: t.matched.not(),
|
|
104
|
+
}), slice: slice, affordances: ["search", "filter"], sliceOpacity: opacityVal, sliceDesaturate: desatOn, sliceEmphasis: emphasis, sliceFrame: frameOn, sliceHidden: hideOn })] }));
|
|
67
105
|
} }));
|
|
68
106
|
}),
|
|
69
107
|
inputs: [],
|
|
70
108
|
});
|
|
109
|
+
export const schematicLayers = example({
|
|
110
|
+
keywords: ["Schematic", "layers", "layer", "visibility", "solo", "lock", "opacity", "toggle", "legend"],
|
|
111
|
+
description: "Named layers — items / zones / links grouped into toggleable layers (a locked + dimmed building shell, and a maintenance layer that ships hidden); the canvas layer button opens a panel to show / hide / solo / lock each layer",
|
|
112
|
+
fn: East.function([], UIComponentType, ($) => {
|
|
113
|
+
const equipment = $.const([
|
|
114
|
+
{ id: "GATE", x: 2.5, y: 6.0, kind: "entry", sys: "shell" },
|
|
115
|
+
{ id: "PUMP-1", x: 6.0, y: 4.0, kind: "pump", sys: "process" },
|
|
116
|
+
{ id: "TANK-2", x: 12.0, y: 4.0, kind: "tank", sys: "process" },
|
|
117
|
+
{ id: "VALVE-3", x: 18.0, y: 7.0, kind: "valve", sys: "utilities" },
|
|
118
|
+
{ id: "SENS-4", x: 9.0, y: 9.0, kind: "sensor", sys: "maintenance" },
|
|
119
|
+
]);
|
|
120
|
+
const rooms = $.const([
|
|
121
|
+
{ id: "hall", name: "Hall A", x: 1.0, y: 1.0, w: 22.0, h: 11.0 },
|
|
122
|
+
]);
|
|
123
|
+
const pipes = $.const([
|
|
124
|
+
{ id: "p1", a: "PUMP-1", b: "TANK-2" },
|
|
125
|
+
{ id: "p2", a: "TANK-2", b: "VALVE-3" },
|
|
126
|
+
]);
|
|
127
|
+
return (_jsx(Schematic, { extent: { width: 24, height: 13 }, height: "420px", items: equipment, item: e => ({ key: e.id, x: e.x, y: e.y, label: e.id, sublabel: e.kind, icon: "gear", layer: e.sys }), zones: rooms, zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h, layer: "shell" }), links: pipes, link: l => ({ key: l.id, from: l.a, to: l.b, layer: "utilities" }), layers: [
|
|
128
|
+
// Locked + dimmed backdrop (the GATE item + Hall zone read as context).
|
|
129
|
+
{ key: "shell", label: "Building shell", tone: "muted", locked: true, opacity: 0.45 },
|
|
130
|
+
{ key: "process", label: "Process", tone: "brand" },
|
|
131
|
+
{ key: "utilities", label: "Utilities", tone: "success" },
|
|
132
|
+
// Ships hidden — SENS-4 is absent until toggled on in the panel.
|
|
133
|
+
{ key: "maintenance", label: "Maintenance", tone: "warning", visible: false },
|
|
134
|
+
], scaleUnit: "m" }));
|
|
135
|
+
}),
|
|
136
|
+
inputs: [],
|
|
137
|
+
});
|
|
71
138
|
export const schematicMinimal = example({
|
|
72
|
-
keywords: ["Schematic", "canvas", "minimal"],
|
|
73
|
-
description: "Minimal placement — items only, no zones or links",
|
|
139
|
+
keywords: ["Schematic", "canvas", "minimal", "readOnly", "static"],
|
|
140
|
+
description: "Minimal placement — items only, no zones or links; readOnly makes it a pure static picture (the connect / move edit tools never render), leaving just pan / zoom / selection",
|
|
74
141
|
fn: East.function([], UIComponentType, ($) => {
|
|
75
142
|
const rooms = $.const([
|
|
76
143
|
{ id: "DOCK-1", x: 3.0, y: 2.0 },
|
|
77
144
|
{ id: "DOCK-2", x: 9.0, y: 2.0 },
|
|
78
145
|
{ id: "STAGE", x: 6.0, y: 5.5 },
|
|
79
146
|
]);
|
|
80
|
-
return (_jsx(Schematic, { extent: { width: 12, height: 7 }, height: "440px", items: rooms, item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "warehouse" }) }));
|
|
147
|
+
return (_jsx(Schematic, { extent: { width: 12, height: 7 }, height: "440px", items: rooms, item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "warehouse" }), readOnly: true }));
|
|
81
148
|
}),
|
|
82
149
|
inputs: [],
|
|
83
150
|
});
|
|
84
151
|
export const schematicInteractive = example({
|
|
85
|
-
keywords: ["Schematic", "Reactive", "State", "onSelect", "interactive"],
|
|
86
|
-
description: "Canvas whose onSelect tracks the inspected item",
|
|
152
|
+
keywords: ["Schematic", "Reactive", "State", "onSelect", "onItemOpen", "double-click", "open", "drill-in", "interactive"],
|
|
153
|
+
description: "Canvas whose onSelect tracks the inspected item and onItemOpen (double-click drill-in) tracks the opened one; a background double-click still resets the view",
|
|
87
154
|
fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
|
|
88
155
|
const bind = $.let(State.bind([StringType], "schematic_selected", "none"));
|
|
156
|
+
const opened = $.let(State.bind([StringType], "schematic_opened", "none"));
|
|
89
157
|
const onSelect = $.const(East.function([StringType], NullType, ($, key) => {
|
|
90
158
|
$(bind.write(key));
|
|
91
159
|
}));
|
|
160
|
+
const onItemOpen = $.const(East.function([StringType], NullType, ($, key) => {
|
|
161
|
+
$(opened.write(key));
|
|
162
|
+
}));
|
|
92
163
|
const selected = $.let(bind.read());
|
|
164
|
+
const openedKey = $.let(opened.read());
|
|
93
165
|
return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsx(Schematic, { extent: { width: 12, height: 6 }, height: "440px", items: [
|
|
94
166
|
{ id: "CELL-A", x: 3.0, y: 3.0 },
|
|
95
167
|
{ id: "CELL-B", x: 9.0, y: 3.0 },
|
|
96
|
-
], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "industry" }), onSelect: onSelect }), _jsx(Text.MonoLabel, { children: East.str `INSPECTING · ${selected}` })] }));
|
|
168
|
+
], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "industry" }), onSelect: onSelect, onItemOpen: onItemOpen }), _jsx(Text.MonoLabel, { children: East.str `INSPECTING · ${selected} · OPENED · ${openedKey}` })] }));
|
|
169
|
+
} }))),
|
|
170
|
+
inputs: [],
|
|
171
|
+
});
|
|
172
|
+
export const schematicRangeSelect = example({
|
|
173
|
+
keywords: ["Schematic", "selection", "selectionMode", "single", "multiple", "marquee", "onSelectionChange", "selectZoomFocus", "focus", "zoom", "multi-select", "Reactive", "State", "Switch"],
|
|
174
|
+
description: "Multi-select — drag a marquee (or Shift-click) to select many items; onSelectionChange writes the whole key set to State. A reactive Switch toggles `selectZoomFocus`: when on, a tap flies to the item and a marquee fits the camera to the selected set; when off, selection never moves the camera",
|
|
175
|
+
fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
|
|
176
|
+
// The full selected-key set is mirrored into State on every change.
|
|
177
|
+
const bind = $.let(State.bind([ArrayType(StringType)], "schematic_selected_keys", []));
|
|
178
|
+
const onSelectionChange = $.const(East.function([Schematic.Types.SelectionEvent], NullType, ($, ev) => {
|
|
179
|
+
$(bind.write(ev.selectedKeys));
|
|
180
|
+
}));
|
|
181
|
+
const keys = $.let(bind.read());
|
|
182
|
+
const count = $.let(keys.size());
|
|
183
|
+
// Reactive toggle for the camera-on-select behaviour — flip it and click /
|
|
184
|
+
// marquee to compare: focus ON flies / fits, OFF leaves the camera put.
|
|
185
|
+
const focus = $.let(State.bind([BooleanType], "ex.schematic.focus", true));
|
|
186
|
+
const focusOn = $.let(focus.read());
|
|
187
|
+
const onFocus = $.const(East.function([BooleanType], NullType, ($, v) => { $(focus.write(v)); }));
|
|
188
|
+
// Reactive selection mode — Switch between `single` (one item, no marquee)
|
|
189
|
+
// and `multiple` (marquee + Shift-extend), as an East variant expression.
|
|
190
|
+
const multi = $.let(State.bind([BooleanType], "ex.schematic.multi", true));
|
|
191
|
+
const multiOn = $.let(multi.read());
|
|
192
|
+
const onMulti = $.const(East.function([BooleanType], NullType, ($, v) => { $(multi.write(v)); }));
|
|
193
|
+
const selMode = $.let(multiOn.ifElse(_$ => variant("multiple", null), _$ => variant("single", null)), Schematic.Types.SelectionMode);
|
|
194
|
+
return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsxs(HStack, { gap: "4", align: "center", children: [_jsx(Switch, { checked: multiOn, label: "Multi-select", onChange: onMulti }), _jsx(Switch, { checked: focusOn, label: "Zoom to focus on select", onChange: onFocus }), _jsx(Text.MonoLabel, { children: East.str `SELECTED · ${East.print(count)}` })] }), _jsx(Schematic, { extent: { width: 40, height: 24 }, height: "440px", items: [
|
|
195
|
+
// Spread across a large extent + clustered, so focus is
|
|
196
|
+
// obvious: a tap zooms in hard, a marquee fits to a cluster.
|
|
197
|
+
{ id: "A", x: 4.0, y: 4.0 }, { id: "B", x: 7.0, y: 6.5 }, { id: "C", x: 5.0, y: 9.0 },
|
|
198
|
+
{ id: "D", x: 31.0, y: 4.0 }, { id: "E", x: 35.0, y: 6.0 }, { id: "F", x: 33.0, y: 9.5 },
|
|
199
|
+
{ id: "G", x: 18.0, y: 18.0 }, { id: "H", x: 22.0, y: 20.0 }, { id: "I", x: 20.0, y: 14.5 },
|
|
200
|
+
{ id: "J", x: 34.0, y: 19.0 }, { id: "K", x: 37.0, y: 21.5 }, { id: "L", x: 13.0, y: 11.5 },
|
|
201
|
+
], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "cube" }), selectionMode: selMode, selectZoomFocus: focusOn, onSelectionChange: onSelectionChange })] }));
|
|
97
202
|
} }))),
|
|
98
203
|
inputs: [],
|
|
99
204
|
});
|
|
205
|
+
export const schematicZoneSelect = example({
|
|
206
|
+
keywords: ["Schematic", "zone", "area", "selection", "onSelectZone", "onZoneSelectionChange", "childItemKeys", "Reactive", "State", "Switch"],
|
|
207
|
+
description: "Zone (area) selection — click a hall / cell body to select the zone (items take hit-test precedence; innermost zone wins); onZoneSelectionChange reports the selected zones AND their child items; the Multi-select switch turns on Shift-extend",
|
|
208
|
+
fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
|
|
209
|
+
const readout = $.let(State.bind([StringType], "schematic_zone_sel", "—"));
|
|
210
|
+
const onZoneSelectionChange = $.const(East.function([Schematic.Types.ZoneSelectionEvent], NullType, ($, ev) => {
|
|
211
|
+
$(readout.write(East.str `${East.print(ev.selectedKeys.size())} zone(s) · ${East.print(ev.childItemKeys.size())} item(s) inside`));
|
|
212
|
+
}));
|
|
213
|
+
// Zone gestures follow the same selectionMode as items — flip the
|
|
214
|
+
// switch and Shift+click zones to extend the area set.
|
|
215
|
+
const multi = $.let(State.bind([BooleanType], "ex.zone.multi", true));
|
|
216
|
+
const multiOn = $.let(multi.read());
|
|
217
|
+
const onMulti = $.const(East.function([BooleanType], NullType, ($, v) => { $(multi.write(v)); }));
|
|
218
|
+
const selMode = $.let(multiOn.ifElse(_$ => variant("multiple", null), _$ => variant("single", null)), Schematic.Types.SelectionMode);
|
|
219
|
+
const txt = $.let(readout.read());
|
|
220
|
+
return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsxs(HStack, { gap: "4", align: "center", children: [_jsx(Switch, { checked: multiOn, label: "Multi-select (Shift extends)", onChange: onMulti }), _jsx(Text.MonoLabel, { children: East.str `ZONES · ${txt}` })] }), _jsx(Schematic, { extent: { width: 24, height: 12 }, height: "420px", items: [
|
|
221
|
+
{ id: "T1", x: 3.0, y: 3.0 }, { id: "T2", x: 7.0, y: 3.0 },
|
|
222
|
+
{ id: "M1", x: 15.0, y: 3.0 },
|
|
223
|
+
{ id: "P1", x: 6.0, y: 9.0 }, { id: "P2", x: 18.0, y: 9.0 },
|
|
224
|
+
], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "cube" }), zones: [
|
|
225
|
+
{ id: "hall-a", name: "Hall A", x: 1.0, y: 1.0, w: 10.0, h: 4.5 },
|
|
226
|
+
{ id: "hall-b", name: "Hall B", x: 12.5, y: 1.0, w: 10.5, h: 4.5 },
|
|
227
|
+
{ id: "dock", name: "Dock", x: 1.0, y: 7.0, w: 22.0, h: 4.0 },
|
|
228
|
+
], zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h }), selectionMode: selMode, onZoneSelectionChange: onZoneSelectionChange })] }));
|
|
229
|
+
} }))),
|
|
230
|
+
inputs: [],
|
|
231
|
+
});
|
|
232
|
+
export const schematicLinkEdit = example({
|
|
233
|
+
keywords: ["Schematic", "link", "editing", "connect", "linkMode", "session", "onCreateLink", "onSelectLink", "onEditLink", "onDeleteLink", "readOnlyLinks", "readOnly", "draw", "Reactive", "State", "Switch"],
|
|
234
|
+
description: "Link editing — the connect tool drags item→item to create links (draw mode adds them locally, form-input style; connect mode is event-only for planning operations between areas); Shift+drag ADDS to the session and onCreateLink reports the accumulated links + the pair's existing links; click a link to select it, drag an endpoint handle to re-target (SHIFT-drag from an endpoint instead SEEDS a net session that absorbs the link), Del deletes; switches flip linkMode and readOnlyLinks reactively; canConnect forbids mixer→shipping directly (product must pass a packer)",
|
|
235
|
+
fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
|
|
236
|
+
const log = $.let(State.bind([StringType], "schematic_link_log", "—"));
|
|
237
|
+
const onCreateLink = $.const(East.function([Schematic.Types.LinkCreateEvent], NullType, ($, ev) => {
|
|
238
|
+
$(log.write(East.str `created ${ev.link.from}→${ev.link.to} · session ${East.print(ev.links.size())} · existing ${East.print(ev.existing.size())}`));
|
|
239
|
+
}));
|
|
240
|
+
const onEditLink = $.const(East.function([Schematic.Types.LinkEditEvent], NullType, ($, ev) => {
|
|
241
|
+
$(log.write(East.str `edited ${ev.key} → ${ev.from}→${ev.to}`));
|
|
242
|
+
}));
|
|
243
|
+
const onDeleteLink = $.const(East.function([StringType], NullType, ($, key) => {
|
|
244
|
+
$(log.write(East.str `deleted ${key}`));
|
|
245
|
+
}));
|
|
246
|
+
// Reactive mode switches: `connect` = event-only (plan an operation,
|
|
247
|
+
// nothing drawn); editable off = readOnlyLinks (tool + handles hidden).
|
|
248
|
+
const connectMode = $.let(State.bind([BooleanType], "ex.link.connectmode", false));
|
|
249
|
+
const cOn = $.let(connectMode.read());
|
|
250
|
+
const onC = $.const(East.function([BooleanType], NullType, ($, v) => { $(connectMode.write(v)); }));
|
|
251
|
+
const lm = $.let(cOn.ifElse(_$ => variant("connect", null), _$ => variant("draw", null)), Schematic.Types.LinkMode);
|
|
252
|
+
const editable = $.let(State.bind([BooleanType], "ex.link.editable", true));
|
|
253
|
+
const eOn = $.let(editable.read());
|
|
254
|
+
const onE = $.const(East.function([BooleanType], NullType, ($, v) => { $(editable.write(v)); }));
|
|
255
|
+
const roLinks = $.let(eOn.not(), BooleanType);
|
|
256
|
+
// Connection validator: mixers never connect DIRECTLY to shipping —
|
|
257
|
+
// product must pass through a packer (drag MIX-1 → SHIP: no snap).
|
|
258
|
+
const canConnect = $.const(East.function([StringType, StringType], BooleanType, (_$, from, to) => from.substring(0n, 3n).equal("MIX").and(() => to.equal("SHIP")).not()));
|
|
259
|
+
// The mode READOUT follows the switch — the description must never
|
|
260
|
+
// claim event-only while draw mode is adding locally.
|
|
261
|
+
const modeTxt = $.let(cOn.ifElse(_$ => "CONNECT — event-only, nothing added", _$ => "DRAW — adds locally"));
|
|
262
|
+
const txt = $.let(log.read());
|
|
263
|
+
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: [
|
|
264
|
+
{ id: "MIX-1", x: 3.0, y: 3.0 }, { id: "MIX-2", x: 3.0, y: 8.0 },
|
|
265
|
+
{ id: "PACK-A", x: 12.0, y: 3.0 }, { id: "PACK-B", x: 12.0, y: 8.0 },
|
|
266
|
+
{ id: "SHIP", x: 19.0, y: 5.5 },
|
|
267
|
+
], 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 })] }));
|
|
268
|
+
} }))),
|
|
269
|
+
inputs: [],
|
|
270
|
+
});
|
|
271
|
+
export const schematicItemMove = example({
|
|
272
|
+
keywords: ["Schematic", "move", "reposition", "drag", "onMoveItem", "readOnlyItems", "editing", "group", "Reactive", "State", "Switch"],
|
|
273
|
+
description: "Item drag-to-reposition — the move tool drags an item to a new world position (dragging a SELECTED item moves the whole selection rigidly); positions are local-first (form-input style) and onMoveItem fires once per gesture with the final position, every moved key, and the shared delta; the switch flips readOnlyItems reactively",
|
|
274
|
+
fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
|
|
275
|
+
const log = $.let(State.bind([StringType], "schematic_move_log", "—"));
|
|
276
|
+
const onMoveItem = $.const(East.function([Schematic.Types.ItemMoveEvent], NullType, ($, ev) => {
|
|
277
|
+
$(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)}`));
|
|
278
|
+
}));
|
|
279
|
+
const movable = $.let(State.bind([BooleanType], "ex.move.on", true));
|
|
280
|
+
const mOn = $.let(movable.read());
|
|
281
|
+
const onM = $.const(East.function([BooleanType], NullType, ($, v) => { $(movable.write(v)); }));
|
|
282
|
+
const roItems = $.let(mOn.not(), BooleanType);
|
|
283
|
+
const txt = $.let(log.read());
|
|
284
|
+
return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsxs(HStack, { gap: "4", align: "center", children: [_jsx(Switch, { checked: mOn, label: "Items movable", onChange: onM }), _jsx(Text.MonoLabel, { children: East.str `MOVE · ${txt}` })] }), _jsx(Schematic, { extent: { width: 20, height: 10 }, height: "420px", items: [
|
|
285
|
+
{ id: "T1", x: 4.0, y: 3.0 }, { id: "T2", x: 8.0, y: 3.0 },
|
|
286
|
+
{ id: "T3", x: 12.0, y: 3.0 }, { id: "PK", x: 8.0, y: 7.5 },
|
|
287
|
+
], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "industry" }), links: [{ id: "l1", a: "T2", b: "PK" }], link: l => ({ key: l.id, from: l.a, to: l.b }), selectionMode: "multiple", readOnlyItems: roItems, onMoveItem: onMoveItem })] }));
|
|
288
|
+
} }))),
|
|
289
|
+
inputs: [],
|
|
290
|
+
});
|
|
291
|
+
// 320 generated demo units across 4 bays — authored at MODULE scope (an East
|
|
292
|
+
// function's body must be East all the way down; authoring-time constants are
|
|
293
|
+
// host-declared outside it).
|
|
294
|
+
const STRESS_GRID_ITEMS = Array.from({ length: 320 }, (_, i) => {
|
|
295
|
+
const bay = Math.floor(i / 80), col = i % 16, row = Math.floor((i % 80) / 16);
|
|
296
|
+
return {
|
|
297
|
+
id: `U-${String(i).padStart(3, "0")}`,
|
|
298
|
+
x: (bay % 2) * 32 + col * 1.9 + 2.0,
|
|
299
|
+
y: Math.floor(bay / 2) * 17 + row * 2.9 + 2.5,
|
|
300
|
+
load: (i * 37 % 100) / 100,
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
export const schematicStress = example({
|
|
304
|
+
keywords: ["Schematic", "stress", "performance", "LOD", "semantic zoom", "declutter", "minimap", "large", "many items"],
|
|
305
|
+
description: "Semantic-zoom stress probe — 320 generated items across 4 bays exercise the LOD ladder (cards ⇢ labelled dots ⇢ dots as you zoom out, dense rows degrading as one block instead of checkerboarding), the minimap, and 60 fps pan; the manual perf budget probe for the renderer",
|
|
306
|
+
fn: East.function([], UIComponentType, (_$) => (_jsx(Schematic, { extent: { width: 64, height: 34 }, height: "460px", items: STRESS_GRID_ITEMS, item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "microchip", meter: { value: r.load, max: 1.0 } }), zones: [
|
|
307
|
+
{ id: "bay-a", name: "Bay A", x: 0.5, y: 0.5, w: 31.0, h: 16.0 },
|
|
308
|
+
{ id: "bay-b", name: "Bay B", x: 32.5, y: 0.5, w: 31.0, h: 16.0 },
|
|
309
|
+
{ id: "bay-c", name: "Bay C", x: 0.5, y: 17.5, w: 31.0, h: 16.0 },
|
|
310
|
+
{ id: "bay-d", name: "Bay D", x: 32.5, y: 17.5, w: 31.0, h: 16.0 },
|
|
311
|
+
], zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h, pattern: Schematic.outline() }), selectionMode: "multiple", minimap: true, scaleUnit: "m" }))),
|
|
312
|
+
inputs: [],
|
|
313
|
+
});
|
|
314
|
+
export const schematicHover = example({
|
|
315
|
+
keywords: ["Schematic", "hover", "HoverCard", "itemHover", "zoneHover", "linkHover", "Sparkline", "chart", "inspection", "lazy"],
|
|
316
|
+
description: "Hover cards — dwell on an item, zone body, or link/net stroke to open a card whose content an East function builds LAZILY from the hovered KEY (a Sparkline chart over the entity's history is the headline case); the card survives the pointer moving onto it, and any camera or edit gesture closes it",
|
|
317
|
+
fn: East.function([], UIComponentType, ($) => {
|
|
318
|
+
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" })] }))));
|
|
319
|
+
const zoneHover = $.const(East.function([StringType], UIComponentType, (_$, key) => (_jsx(Text.MonoLabel, { children: East.str `${key} — CIP window 14:00–15:00` }))));
|
|
320
|
+
const linkHover = $.const(East.function([StringType], UIComponentType, (_$, key) => (_jsx(Text.MonoLabel, { children: East.str `${key} · 12.4 m³/h` }))));
|
|
321
|
+
return (_jsx(Schematic, { extent: { width: 20, height: 10 }, height: "420px", items: [
|
|
322
|
+
{ id: "UNIT-01", x: 3.5, y: 3.0 }, { id: "UNIT-02", x: 8.0, y: 3.0 },
|
|
323
|
+
{ id: "CIP-1", x: 3.5, y: 7.5 }, { id: "PK-1", x: 13.0, y: 5.0 },
|
|
324
|
+
], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "industry" }), zones: [{ id: "hall-a", name: "Hall A", x: 1.0, y: 1.0, w: 9.5, h: 8.5 }], zone: z => ({ key: z.id, label: z.name, x: z.x, y: z.y, width: z.w, height: z.h, pattern: Schematic.outline() }), links: [{ id: "feed", a: "UNIT-02", b: "PK-1" }], link: l => ({ key: l.id, from: l.a, to: l.b, label: l.id }), itemHover: itemHover, zoneHover: zoneHover, linkHover: linkHover }));
|
|
325
|
+
}),
|
|
326
|
+
inputs: [],
|
|
327
|
+
});
|
|
328
|
+
export const schematicNets = example({
|
|
329
|
+
keywords: ["Schematic", "net", "nets", "manifold", "bus", "trunk", "header", "bar", "stubs", "sources", "destinations", "via", "label", "linkMode", "onCreateLink", "session", "Reactive", "State", "Switch"],
|
|
330
|
+
description: "Nets — a manifold as ONE row: many sources feeding many destinations drawn as a header BAR with stubs and junction-tap dots (no pairwise explosion); the second net bridges two banks along an explicit via trunk path; the connect tool creates nets too (Shift+drag grows the session into one net — draw adds locally, connect mode is event-only; Shift-drag OUT of a selected net's member adds the target as a new leg via onEditNet), with switches flipping linkMode and readOnlyLinks reactively; click a stub to select ONE leg and Del removes just that endpoint (onEditNet); canConnect makes CIP-1 supply-only — drafts never snap onto it",
|
|
331
|
+
fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
|
|
332
|
+
const units = $.const([
|
|
333
|
+
{ id: "CIP-1", x: 2.0, y: 6.0 },
|
|
334
|
+
{ id: "U-01", x: 9.0, y: 2.0 }, { id: "U-02", x: 9.0, y: 4.5 },
|
|
335
|
+
{ id: "U-03", x: 9.0, y: 7.0 }, { id: "U-04", x: 9.0, y: 9.5 },
|
|
336
|
+
{ id: "PK-A", x: 17.0, y: 3.5 }, { id: "PK-B", x: 17.0, y: 8.0 },
|
|
337
|
+
{ id: "DOCK", x: 23.0, y: 6.0 },
|
|
338
|
+
]);
|
|
339
|
+
const manifolds = $.const([
|
|
340
|
+
{ id: "cip", srcs: ["CIP-1"], dsts: ["U-01", "U-02", "U-03", "U-04"], name: "CIP supply", flow: "12 m³/h", path: [] },
|
|
341
|
+
{ id: "header", srcs: ["PK-A", "PK-B"], dsts: ["DOCK"], name: "outfeed header", flow: "", path: [{ x: 20.0, y: 6.0 }] },
|
|
342
|
+
], ArrayType(StructType({
|
|
343
|
+
id: StringType,
|
|
344
|
+
srcs: ArrayType(StringType),
|
|
345
|
+
dsts: ArrayType(StringType),
|
|
346
|
+
name: StringType,
|
|
347
|
+
flow: StringType,
|
|
348
|
+
path: ArrayType(StructType({ x: FloatType, y: FloatType })),
|
|
349
|
+
})));
|
|
350
|
+
const log = $.let(State.bind([StringType], "schematic_net_log", "—"));
|
|
351
|
+
// A Shift-session commit reports the WHOLE growing net — upsert by
|
|
352
|
+
// `net.key` to materialise it as one manifold row.
|
|
353
|
+
const onCreateLink = $.const(East.function([Schematic.Types.LinkCreateEvent], NullType, ($, ev) => {
|
|
354
|
+
$(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)}`));
|
|
355
|
+
}));
|
|
356
|
+
// Click a STUB to select one leg (narrow halo), Del removes just that
|
|
357
|
+
// endpoint — onEditNet reports the net's endpoints AFTER the removal.
|
|
358
|
+
const onEditNet = $.const(East.function([Schematic.Types.NetEndpoints], NullType, ($, ev) => {
|
|
359
|
+
$(log.write(East.str `net ${ev.key} edited · ${East.print(ev.sources.size())} src → ${East.print(ev.destinations.size())} dst`));
|
|
360
|
+
}));
|
|
361
|
+
// Connection validator: CIP-1 is supply-only — the connect draft
|
|
362
|
+
// never snaps onto it (covers links, session/net extensions, and
|
|
363
|
+
// re-targets alike).
|
|
364
|
+
const canConnect = $.const(East.function([StringType, StringType], BooleanType, (_$, _from, to) => to.notEqual("CIP-1")));
|
|
365
|
+
// Reactive mode switches: `connect` = event-only (plan the manifold,
|
|
366
|
+
// nothing drawn); editable off = readOnlyLinks (connect tool hidden).
|
|
367
|
+
const connectMode = $.let(State.bind([BooleanType], "ex.net.connectmode", false));
|
|
368
|
+
const cOn = $.let(connectMode.read());
|
|
369
|
+
const onC = $.const(East.function([BooleanType], NullType, ($, v) => { $(connectMode.write(v)); }));
|
|
370
|
+
const lm = $.let(cOn.ifElse(_$ => variant("connect", null), _$ => variant("draw", null)), Schematic.Types.LinkMode);
|
|
371
|
+
const editable = $.let(State.bind([BooleanType], "ex.net.editable", true));
|
|
372
|
+
const eOn = $.let(editable.read());
|
|
373
|
+
const onE = $.const(East.function([BooleanType], NullType, ($, v) => { $(editable.write(v)); }));
|
|
374
|
+
const roLinks = $.let(eOn.not(), BooleanType);
|
|
375
|
+
// The mode READOUT follows the switch — the description must never
|
|
376
|
+
// claim event-only while draw mode is adding locally.
|
|
377
|
+
const modeTxt = $.let(cOn.ifElse(_$ => "CONNECT — event-only, nothing added", _$ => "DRAW — adds locally"));
|
|
378
|
+
const txt = $.let(log.read());
|
|
379
|
+
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 })] }));
|
|
380
|
+
} }))),
|
|
381
|
+
inputs: [],
|
|
382
|
+
});
|
|
383
|
+
export const schematicViewport = example({
|
|
384
|
+
keywords: ["Schematic", "viewport", "onViewportChange", "camera", "zoom", "bounds", "settle", "Reactive", "State"],
|
|
385
|
+
description: "Debounced viewport reporting — onViewportChange fires after a pan / zoom / fly settles with the zoom + the visible world rect, written to State as a live readout (never per-frame)",
|
|
386
|
+
fn: East.function([], UIComponentType, (_$) => (_jsx(Reactive, { children: $ => {
|
|
387
|
+
const bind = $.let(State.bind([StringType], "schematic_viewport", "—"));
|
|
388
|
+
const onViewportChange = $.const(East.function([Schematic.Types.ViewportEvent], NullType, ($, ev) => {
|
|
389
|
+
$(bind.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)}`));
|
|
390
|
+
}));
|
|
391
|
+
const readout = $.let(bind.read());
|
|
392
|
+
return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsx(Schematic, { extent: { width: 24, height: 12 }, height: "400px", items: [
|
|
393
|
+
{ id: "A", x: 4.0, y: 4.0 },
|
|
394
|
+
{ id: "B", x: 12.0, y: 6.0 },
|
|
395
|
+
{ id: "C", x: 20.0, y: 8.0 },
|
|
396
|
+
], item: r => ({ key: r.id, x: r.x, y: r.y, label: r.id, icon: "cube" }), onViewportChange: onViewportChange }), _jsx(Text.MonoLabel, { children: East.str `VIEW · ${readout}` })] }));
|
|
397
|
+
} }))),
|
|
398
|
+
inputs: [],
|
|
399
|
+
});
|
|
400
|
+
export const schematicSelectFilter = example({
|
|
401
|
+
keywords: ["Schematic", "selection", "selectionMode", "sliceSelectField", "slice", "in", "filter", "marquee", "onSelectionChange", "partition", "ghost"],
|
|
402
|
+
description: "Marquee-select drives the bound slice — sliceSelectField writes an `in` filter of the selected keys, so Slice.partition re-tags the rest as excluded and the ghost slice effect fades them (selection → slice → ghost, one-directional)",
|
|
403
|
+
fn: East.function([], UIComponentType, (_$) => {
|
|
404
|
+
const EquipType = StructType({ id: StringType, x: FloatType, y: FloatType, kind: StringType });
|
|
405
|
+
const cfg = Slice.config(EquipType, {
|
|
406
|
+
fields: { id: { label: "ID" }, kind: { label: "Kind" } },
|
|
407
|
+
searchFieldIds: ["id", "kind"],
|
|
408
|
+
});
|
|
409
|
+
return (_jsx(Reactive, { children: $ => {
|
|
410
|
+
const data = $.const([
|
|
411
|
+
{ id: "A", x: 3.5, y: 3.0, kind: "unit" },
|
|
412
|
+
{ id: "B", x: 8.0, y: 3.0, kind: "unit" },
|
|
413
|
+
{ id: "C", x: 12.5, y: 3.0, kind: "pack" },
|
|
414
|
+
{ id: "D", x: 5.5, y: 6.4, kind: "unit" },
|
|
415
|
+
{ id: "E", x: 10.0, y: 6.4, kind: "pack" },
|
|
416
|
+
], ArrayType(EquipType));
|
|
417
|
+
// No initial filter — everything matches until a selection writes one.
|
|
418
|
+
const slice = $.let(Slice.bind([EquipType], "ex.schematic.selfilter", cfg, Slice.state({}), data, none));
|
|
419
|
+
// Full set tagged pass/fail; a marquee selection writes `in(id, keys)`
|
|
420
|
+
// via sliceSelectField, so the non-selected re-tag excluded → ghost.
|
|
421
|
+
const tagged = $.let(Slice.partition([EquipType], slice));
|
|
422
|
+
return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsx(Schematic, { extent: { width: 16, height: 9 }, height: "400px", items: tagged, item: t => ({
|
|
423
|
+
key: t.value.id, x: t.value.x, y: t.value.y, label: t.value.id,
|
|
424
|
+
sublabel: t.value.kind, icon: "database", excluded: t.matched.not(),
|
|
425
|
+
}), 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" })] }));
|
|
426
|
+
} }));
|
|
427
|
+
}),
|
|
428
|
+
inputs: [],
|
|
429
|
+
});
|
|
100
430
|
export const schematicFacility = example({
|
|
101
431
|
keywords: ["Schematic", "facility", "navigator", "minimap", "zoom", "LOD", "click-to-fly", "large", "generate", "footprint", "geometry", "circle", "polygon", "shape"],
|
|
102
432
|
description: "500-unit facility — navigator rail, minimap, semantic zoom, click-to-fly from the navigator; rows generated with East.Array.generate, each carrying a varied footprint shape/size (circle / square / triangle / diamond)",
|