@selvajs/ui 5.0.1 → 6.0.0-beta.1
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 +42 -9
- package/dist/components/compute/ComputeApp.svelte +36 -12
- package/dist/components/compute/ComputeApp.svelte.d.ts +14 -3
- package/dist/components/primitives/textarea/textarea.svelte +1 -2
- package/dist/components/viewer/SceneManager.svelte +75 -160
- package/dist/components/viewer/SceneManager.svelte.d.ts +8 -3
- package/dist/components/viewer/Viewer.svelte +22 -5
- package/dist/compute/useSolveSession.svelte.d.ts +12 -0
- package/dist/compute/useSolveSession.svelte.js +79 -0
- package/dist/external/storage.d.ts +1 -15
- package/dist/external/storage.js +4 -54
- package/dist/index.d.ts +4 -3
- package/dist/index.js +7 -4
- package/dist/public.d.ts +4 -3
- package/dist/public.js +9 -5
- package/package.json +9 -4
- package/src/lib/components/compute/ComputeApp.svelte +36 -12
- package/src/lib/components/primitives/textarea/textarea.svelte +1 -2
- package/src/lib/components/viewer/SceneManager.svelte +75 -160
- package/src/lib/components/viewer/Viewer.svelte +22 -5
- package/src/lib/compute/useSolveSession.svelte.ts +86 -0
- package/src/lib/external/storage.ts +12 -64
- package/src/lib/index.ts +15 -5
- package/src/lib/public.ts +17 -6
- package/dist/compute/computeThrottle.svelte.d.ts +0 -24
- package/dist/compute/computeThrottle.svelte.js +0 -82
- package/dist/compute/createSolveSession.svelte.d.ts +0 -66
- package/dist/compute/createSolveSession.svelte.js +0 -159
- package/dist/compute/solve-session-core.d.ts +0 -54
- package/dist/compute/solve-session-core.js +0 -87
- package/dist/compute/solveMemo.d.ts +0 -22
- package/dist/compute/solveMemo.js +0 -124
- package/dist/types/solveFn.d.ts +0 -25
- package/dist/types/solveFn.js +0 -1
- package/src/lib/compute/computeThrottle.svelte.ts +0 -109
- package/src/lib/compute/computeThrottle.test.ts +0 -106
- package/src/lib/compute/createSolveSession.svelte.ts +0 -239
- package/src/lib/compute/createSolveSession.test.ts +0 -168
- package/src/lib/compute/solve-session-core.test.ts +0 -153
- package/src/lib/compute/solve-session-core.ts +0 -122
- package/src/lib/compute/solveMemo.test.ts +0 -220
- package/src/lib/compute/solveMemo.ts +0 -140
- package/src/lib/external/storage.test.ts +0 -99
- package/src/lib/schema/dynamic-value-list.test.ts +0 -150
- package/src/lib/schema/param-exporter.test.ts +0 -136
- package/src/lib/schema/traversal.test.ts +0 -92
- package/src/lib/schema/visibility-rules.test.ts +0 -173
- package/src/lib/types/solveFn.ts +0 -29
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// The Svelte binding for a Solve Session.
|
|
2
|
+
//
|
|
3
|
+
// The session itself lives in `@selvajs/solve/client` and is framework-free: it
|
|
4
|
+
// exposes plain getters plus a `subscribe()` seam. That makes it usable headless, but a
|
|
5
|
+
// plain getter read inside Svelte markup is NOT reactive — nothing tells the component to
|
|
6
|
+
// re-run. This adapter closes that gap: it subscribes once, bumps a `$state` version
|
|
7
|
+
// counter on every notification, and reads that counter inside each getter so any
|
|
8
|
+
// component touching one re-runs when the session changes.
|
|
9
|
+
//
|
|
10
|
+
// The counter (rather than mirroring each field into its own `$state`) keeps this a pure
|
|
11
|
+
// republish: no field list to keep in sync as the session grows, and no risk of a mirrored
|
|
12
|
+
// copy drifting from the source of truth.
|
|
13
|
+
import { createSolveSession } from '@selvajs/solve/client';
|
|
14
|
+
/**
|
|
15
|
+
* Wraps a Solve Session so its state reads reactively inside Svelte components.
|
|
16
|
+
*
|
|
17
|
+
* Returns the same `SolveSession` surface — every method delegates untouched, and every
|
|
18
|
+
* getter additionally depends on the version counter. Callers use it exactly like the
|
|
19
|
+
* session it wraps.
|
|
20
|
+
*
|
|
21
|
+
* Must be called during component initialization (it uses `$effect` to manage the
|
|
22
|
+
* subscription, so teardown follows the owning component's lifecycle).
|
|
23
|
+
*/
|
|
24
|
+
export function useSolveSession(args) {
|
|
25
|
+
const session = createSolveSession(args);
|
|
26
|
+
// Bumped on every session notification. Reading it inside a getter is what registers
|
|
27
|
+
// the dependency; the value itself is never meaningful.
|
|
28
|
+
let version = $state(0);
|
|
29
|
+
$effect(() => {
|
|
30
|
+
// Re-read on mount and unsubscribe on teardown. The session outlives no component
|
|
31
|
+
// here — it is created alongside this adapter — so dropping the subscription is the
|
|
32
|
+
// whole cleanup.
|
|
33
|
+
return session.subscribe(() => {
|
|
34
|
+
version += 1;
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
/** Registers the reactive dependency, then returns the live value. */
|
|
38
|
+
function track(read) {
|
|
39
|
+
void version;
|
|
40
|
+
return read();
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
get values() {
|
|
44
|
+
return track(() => session.values);
|
|
45
|
+
},
|
|
46
|
+
get error() {
|
|
47
|
+
return track(() => session.error);
|
|
48
|
+
},
|
|
49
|
+
get computeErrors() {
|
|
50
|
+
return track(() => session.computeErrors);
|
|
51
|
+
},
|
|
52
|
+
get computeWarnings() {
|
|
53
|
+
return track(() => session.computeWarnings);
|
|
54
|
+
},
|
|
55
|
+
get meshes() {
|
|
56
|
+
return track(() => session.meshes);
|
|
57
|
+
},
|
|
58
|
+
get lastResult() {
|
|
59
|
+
return track(() => session.lastResult);
|
|
60
|
+
},
|
|
61
|
+
get hasPendingChanges() {
|
|
62
|
+
return track(() => session.hasPendingChanges);
|
|
63
|
+
},
|
|
64
|
+
get hasNeverSolved() {
|
|
65
|
+
return track(() => session.hasNeverSolved);
|
|
66
|
+
},
|
|
67
|
+
get isSolving() {
|
|
68
|
+
return track(() => session.isSolving);
|
|
69
|
+
},
|
|
70
|
+
setValue: (id, value, forceSolve) => session.setValue(id, value, forceSolve),
|
|
71
|
+
solve: () => session.solve(),
|
|
72
|
+
loadValues: (incoming) => session.loadValues(incoming),
|
|
73
|
+
rebuild: (schema, scopeKey) => session.rebuild(schema, scopeKey),
|
|
74
|
+
report: (result) => session.report(result),
|
|
75
|
+
reportError: (message) => session.reportError(message),
|
|
76
|
+
subscribe: (listener) => session.subscribe(listener),
|
|
77
|
+
notify: () => session.notify()
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -1,15 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export interface ExternalValueRef {
|
|
3
|
-
scopeKey: string;
|
|
4
|
-
inputId: string;
|
|
5
|
-
}
|
|
6
|
-
export declare function writeExternalValue(args: ExternalValueRef & {
|
|
7
|
-
value: unknown;
|
|
8
|
-
}): void;
|
|
9
|
-
export declare function readExternalValue(ref: ExternalValueRef): unknown | undefined;
|
|
10
|
-
export declare function clearExternalValue(ref: ExternalValueRef): void;
|
|
11
|
-
export interface ExternalInput {
|
|
12
|
-
paramId: string;
|
|
13
|
-
displayName: string;
|
|
14
|
-
}
|
|
15
|
-
export declare function getExternalInputs(schema: UISchema): ExternalInput[];
|
|
1
|
+
export { writeExternalValue, readExternalValue, clearExternalValue, getExternalInputs, type ExternalValueRef, type ExternalInput } from '@selvajs/solve/client';
|
package/dist/external/storage.js
CHANGED
|
@@ -1,54 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
// values for one solver/input don't bleed into another. The scope key is whatever
|
|
6
|
-
// uniquely identifies the solver context — sessionId in plugin-ui/preview,
|
|
7
|
-
// definition guid in selva/library, etc.
|
|
8
|
-
//
|
|
9
|
-
// inputId is the Grasshopper parameter instance GUID (LayoutItem.paramId / SchemaInput.id).
|
|
10
|
-
import { getInputItems } from '@selvajs/schemas';
|
|
11
|
-
const STORAGE_PREFIX = 'external';
|
|
12
|
-
function makeKey(scopeKey, inputId) {
|
|
13
|
-
return `${STORAGE_PREFIX}:${scopeKey}:${inputId}`;
|
|
14
|
-
}
|
|
15
|
-
export function writeExternalValue(args) {
|
|
16
|
-
const { scopeKey, inputId, value } = args;
|
|
17
|
-
if (!scopeKey || !inputId)
|
|
18
|
-
return;
|
|
19
|
-
if (typeof sessionStorage === 'undefined')
|
|
20
|
-
return;
|
|
21
|
-
sessionStorage.setItem(makeKey(scopeKey, inputId), JSON.stringify(value));
|
|
22
|
-
}
|
|
23
|
-
export function readExternalValue(ref) {
|
|
24
|
-
const { scopeKey, inputId } = ref;
|
|
25
|
-
if (!scopeKey || !inputId)
|
|
26
|
-
return undefined;
|
|
27
|
-
if (typeof sessionStorage === 'undefined')
|
|
28
|
-
return undefined;
|
|
29
|
-
const raw = sessionStorage.getItem(makeKey(scopeKey, inputId));
|
|
30
|
-
if (raw === null)
|
|
31
|
-
return undefined;
|
|
32
|
-
try {
|
|
33
|
-
return JSON.parse(raw);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return undefined;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export function clearExternalValue(ref) {
|
|
40
|
-
const { scopeKey, inputId } = ref;
|
|
41
|
-
if (!scopeKey || !inputId)
|
|
42
|
-
return;
|
|
43
|
-
if (typeof sessionStorage === 'undefined')
|
|
44
|
-
return;
|
|
45
|
-
sessionStorage.removeItem(makeKey(scopeKey, inputId));
|
|
46
|
-
}
|
|
47
|
-
export function getExternalInputs(schema) {
|
|
48
|
-
return getInputItems(schema)
|
|
49
|
-
.filter((item) => item.source?.kind === 'client')
|
|
50
|
-
.map((item) => ({
|
|
51
|
-
paramId: item.paramId,
|
|
52
|
-
displayName: item.displayName ?? item.paramId
|
|
53
|
-
}));
|
|
54
|
-
}
|
|
1
|
+
// Moved to `@selvajs/solve/client`, where the Solve Session that hydrates from it
|
|
2
|
+
// now lives. Re-exported here to keep the published `@selvajs/ui/external` sub-path — and
|
|
3
|
+
// the pre-step producer routes that import it — working unchanged.
|
|
4
|
+
export { writeExternalValue, readExternalValue, clearExternalValue, getExternalInputs } from '@selvajs/solve/client';
|
package/dist/index.d.ts
CHANGED
|
@@ -9,13 +9,14 @@ export * from './schema/defaults';
|
|
|
9
9
|
export * from './schema/dynamic-value-list';
|
|
10
10
|
export * from './schema/traversal';
|
|
11
11
|
export * from './compute/solving.svelte';
|
|
12
|
-
export {
|
|
13
|
-
export
|
|
12
|
+
export { useSolveSession } from './compute/useSolveSession.svelte';
|
|
13
|
+
export { createSolveSession, createRequestResponseDriver, type SolveSession, type SolveSessionArgs, type SolveDriver, type SolveReporter } from '@selvajs/solve/client';
|
|
14
|
+
export { writeExternalValue, readExternalValue, clearExternalValue, getExternalInputs, type ExternalValueRef, type ExternalInput } from '@selvajs/solve/client';
|
|
14
15
|
export * from './contexts/footerContext.svelte';
|
|
15
16
|
export * from './contexts/clientSlotContext.svelte';
|
|
16
17
|
export * from './composables/useFooterItem.svelte';
|
|
17
18
|
export * from './utils';
|
|
18
19
|
export { randomId } from './utils/randomId';
|
|
19
20
|
export type { ActionButton } from './types/actionButton';
|
|
20
|
-
export type { SolveFn, SolveResult } from '
|
|
21
|
+
export type { SolveFn, SolveResult } from '@selvajs/solve/shared';
|
|
21
22
|
export { DEFAULT_PRESET_LABELS, type PresetLabels } from './types/presetLabels';
|
package/dist/index.js
CHANGED
|
@@ -15,12 +15,15 @@ export * from './schema/defaults';
|
|
|
15
15
|
export * from './schema/dynamic-value-list';
|
|
16
16
|
export * from './schema/traversal';
|
|
17
17
|
export * from './compute/solving.svelte';
|
|
18
|
-
// Solve Session seam
|
|
19
|
-
//
|
|
18
|
+
// Solve Session seam. The session itself now lives in `@selvajs/solve/client`
|
|
19
|
+
// (framework-free); `useSolveSession` is this package's Svelte binding, which republishes
|
|
20
|
+
// the session's subscribe() notifications as rune state so its getters read reactively in
|
|
21
|
+
// markup. Re-exported so transports outside this package — e.g. plugin-ui's WebSocket
|
|
20
22
|
// driver — can satisfy SolveDriver and drive a session. See CONTEXT.md.
|
|
21
|
-
export {
|
|
23
|
+
export { useSolveSession } from './compute/useSolveSession.svelte';
|
|
24
|
+
export { createSolveSession, createRequestResponseDriver } from '@selvajs/solve/client';
|
|
22
25
|
// External-input transit storage (used by routes that wire pre-step producers)
|
|
23
|
-
export
|
|
26
|
+
export { writeExternalValue, readExternalValue, clearExternalValue, getExternalInputs } from '@selvajs/solve/client';
|
|
24
27
|
// Contexts & Composables
|
|
25
28
|
export * from './contexts/footerContext.svelte';
|
|
26
29
|
export * from './contexts/clientSlotContext.svelte';
|
package/dist/public.d.ts
CHANGED
|
@@ -5,12 +5,13 @@ export type { Locale, ViewerMessages } from './i18n/messages';
|
|
|
5
5
|
export { VIEWER_MESSAGES, DEFAULT_LOCALE, messagesFor } from './i18n/messages';
|
|
6
6
|
export { setLocaleContext, getLocaleContext, type LocaleContext } from './i18n/localeContext.svelte';
|
|
7
7
|
export { default as ErrorScreen } from './components/ErrorScreen.svelte';
|
|
8
|
-
export {
|
|
8
|
+
export { useSolveSession } from './compute/useSolveSession.svelte';
|
|
9
|
+
export { createSolveSession, createRequestResponseDriver, type SolveSession, type SolveSessionArgs, type SolveDriver, type SolveReporter } from '@selvajs/solve/client';
|
|
9
10
|
export type { ClientSlotArgs, ClientSlot } from './contexts/clientSlotContext.svelte';
|
|
10
|
-
export
|
|
11
|
+
export { writeExternalValue, readExternalValue, clearExternalValue, getExternalInputs, type ExternalValueRef, type ExternalInput } from '@selvajs/solve/client';
|
|
11
12
|
export * from './schema/defaults';
|
|
12
13
|
export * from './schema/traversal';
|
|
13
14
|
export * from './schema/dynamic-value-list';
|
|
14
15
|
export type { ActionButton } from './types/actionButton';
|
|
15
|
-
export type { SolveFn, SolveResult } from '
|
|
16
|
+
export type { SolveFn, SolveResult } from '@selvajs/solve/shared';
|
|
16
17
|
export { DEFAULT_PRESET_LABELS, type PresetLabels } from './types/presetLabels';
|
package/dist/public.js
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
// Scope: the compute-app SDK — everything an external host app needs to embed a
|
|
9
9
|
// Grasshopper-driven app (ComputeApp), drive solves, and wire pre-step
|
|
10
10
|
// producers. Verified against real external host apps: they import
|
|
11
|
-
// ComputeApp + its types, the solve seam, and external
|
|
11
|
+
// ComputeApp + its types, the solve seam, and the external-input storage
|
|
12
|
+
// helpers. Nothing else.
|
|
12
13
|
//
|
|
13
14
|
// Deliberately NOT public: design-system primitives (Button, Card, Dialog, …),
|
|
14
15
|
// page-chrome layout (AppShell, SideNav, …), toast/Toaster, ThemeSwitcher,
|
|
@@ -30,11 +31,14 @@ export { setLocaleContext, getLocaleContext } from './i18n/localeContext.svelte'
|
|
|
30
31
|
// Full-screen states a host app renders
|
|
31
32
|
export { default as ErrorScreen } from './components/ErrorScreen.svelte';
|
|
32
33
|
// Solve Session seam (transport-agnostic value/lifecycle state machine + its
|
|
33
|
-
// driver interface).
|
|
34
|
-
//
|
|
35
|
-
|
|
34
|
+
// driver interface). The session lives in `@selvajs/solve/client` and is
|
|
35
|
+
// framework-free; `useSolveSession` is the Svelte binding that makes its getters
|
|
36
|
+
// read reactively inside components. A host embedding <ComputeApp> needs neither —
|
|
37
|
+
// both are re-exported for hosts driving a session themselves. See CONTEXT.md.
|
|
38
|
+
export { useSolveSession } from './compute/useSolveSession.svelte';
|
|
39
|
+
export { createSolveSession, createRequestResponseDriver } from '@selvajs/solve/client';
|
|
36
40
|
// Pre-step producer transit storage (host apps wire producers via these).
|
|
37
|
-
export
|
|
41
|
+
export { writeExternalValue, readExternalValue, clearExternalValue, getExternalInputs } from '@selvajs/solve/client';
|
|
38
42
|
// Schema utilities a ComputeApp host reasonably needs to read/shape values.
|
|
39
43
|
export * from './schema/defaults';
|
|
40
44
|
export * from './schema/traversal';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@selvajs/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0-beta.1",
|
|
4
4
|
"description": "Shared UI components and utilities for Selva applications",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "VektorNode",
|
|
@@ -60,8 +60,10 @@
|
|
|
60
60
|
"svelte": "^5",
|
|
61
61
|
"tailwind-variants": "^3.3.0",
|
|
62
62
|
"three": "^0.185.1",
|
|
63
|
+
"@selvajs/compute": "^4.0.0-beta.1",
|
|
63
64
|
"@selvajs/schemas": "^4.7.0",
|
|
64
|
-
"@selvajs/
|
|
65
|
+
"@selvajs/solve": "^1.0.0-beta.5",
|
|
66
|
+
"@selvajs/visualization": "^1.0.0-beta.0"
|
|
65
67
|
},
|
|
66
68
|
"peerDependenciesMeta": {
|
|
67
69
|
"three": {
|
|
@@ -89,9 +91,12 @@
|
|
|
89
91
|
"rimraf": "^6.0.1",
|
|
90
92
|
"svelte": "5.56.8",
|
|
91
93
|
"tailwind-variants": "^3.3.0",
|
|
92
|
-
"vitest": "^
|
|
94
|
+
"vitest": "^4.1.10",
|
|
93
95
|
"@selvajs/config": "0.0.3",
|
|
94
|
-
"@selvajs/schemas": "4.7.0"
|
|
96
|
+
"@selvajs/schemas": "4.7.0",
|
|
97
|
+
"@selvajs/visualization": "1.0.0-beta.0",
|
|
98
|
+
"@selvajs/solve": "1.0.0-beta.5",
|
|
99
|
+
"@selvajs/compute": "4.0.0-beta.1"
|
|
95
100
|
},
|
|
96
101
|
"scripts": {
|
|
97
102
|
"predev": "node ../../scripts/sync-shared-assets.js",
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
import { page } from '$app/state';
|
|
4
4
|
import type { UISchema, ParameterPreset } from '@selvajs/schemas';
|
|
5
5
|
import type { ActionButton } from '../../types/actionButton';
|
|
6
|
-
import type { SolveFn } from '
|
|
6
|
+
import type { SolveFn } from '@selvajs/solve/shared';
|
|
7
7
|
import type { PresetLabels } from '../../types/presetLabels';
|
|
8
8
|
import { createSolvingIndicator } from '../../compute/solving.svelte';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from '../../compute/
|
|
9
|
+
import { createRequestResponseDriver } from '@selvajs/solve/client';
|
|
10
|
+
import type { RetainedSolveResult } from '@selvajs/solve/client';
|
|
11
|
+
import { meshPolicy } from '@selvajs/visualization/parse';
|
|
12
|
+
import { useSolveSession } from '../../compute/useSolveSession.svelte';
|
|
13
13
|
import { useFooterItem } from '../../composables/useFooterItem.svelte';
|
|
14
14
|
import { hexToOklch } from '../../utils/color';
|
|
15
15
|
import AppShell from '../layout/AppShell.svelte';
|
|
@@ -44,13 +44,25 @@
|
|
|
44
44
|
copyrightName?: string;
|
|
45
45
|
/** Fully overrides the footer copyright line. `{name}` and `{year}` are substituted. */
|
|
46
46
|
footerText?: string;
|
|
47
|
-
/**
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* How long one solve may take before the client aborts it (ms). Required: pass
|
|
49
|
+
* the same value the server enforces (`COMPUTE_SOLVE_DEADLINE_MS`), so the client
|
|
50
|
+
* doesn't abort a solve that would have finished.
|
|
51
|
+
*/
|
|
52
|
+
solveDeadlineMs: number;
|
|
49
53
|
footerComponent?: any;
|
|
50
54
|
footerComponentProps?: () => Record<string, unknown>;
|
|
51
55
|
footerItemId?: string;
|
|
52
56
|
footerItemPriority?: number;
|
|
53
|
-
onReady?: (api: {
|
|
57
|
+
onReady?: (api: {
|
|
58
|
+
loadValues: (values: Record<string, unknown>) => void;
|
|
59
|
+
/**
|
|
60
|
+
* The last result reported to the session — the one the viewer is showing, carrying
|
|
61
|
+
* `source`/`values` even when a memo hit served it. Null before the first solve.
|
|
62
|
+
* A getter, not a snapshot: `onReady` fires once.
|
|
63
|
+
*/
|
|
64
|
+
getLastResult: () => RetainedSolveResult | null;
|
|
65
|
+
}) => void;
|
|
54
66
|
headerRight?: Snippet;
|
|
55
67
|
// Replaces the built-in header; takes precedence over `headerRight`.
|
|
56
68
|
header?: Snippet;
|
|
@@ -84,7 +96,7 @@
|
|
|
84
96
|
presetLabels,
|
|
85
97
|
copyrightName,
|
|
86
98
|
footerText,
|
|
87
|
-
|
|
99
|
+
solveDeadlineMs,
|
|
88
100
|
footerComponent,
|
|
89
101
|
footerComponentProps,
|
|
90
102
|
footerItemId = 'footer-item',
|
|
@@ -115,10 +127,19 @@
|
|
|
115
127
|
// reads the reporter lazily so it can capture the session it's wired into.
|
|
116
128
|
// svelte-ignore state_referenced_locally
|
|
117
129
|
const driver = createRequestResponseDriver(onSolve, () => session, {
|
|
118
|
-
|
|
130
|
+
solveDeadlineMs,
|
|
131
|
+
// The driver's result memo caches whole solve results, meshes included — and the viewer
|
|
132
|
+
// disposes what it renders on the next scene update. `@selvajs/solve` keeps meshes opaque,
|
|
133
|
+
// so the three.js clone/dispose rules are injected from the renderer that owns them
|
|
134
|
+
// (audit C1). Without this a memo hit serves an already-disposed mesh.
|
|
135
|
+
meshPolicy,
|
|
136
|
+
// `session.isSolving` forwards to the driver, which the session can't observe on its
|
|
137
|
+
// own — republish so the spinner and disabled states track it. Deferred into a
|
|
138
|
+
// callback, so it reads `session` after initialization rather than during it.
|
|
139
|
+
onChange: () => session.notify()
|
|
119
140
|
});
|
|
120
141
|
// svelte-ignore state_referenced_locally
|
|
121
|
-
const session =
|
|
142
|
+
const session = useSolveSession({
|
|
122
143
|
schema,
|
|
123
144
|
scopeKey: externalScopeKey || definitionKey || schema?.id || '',
|
|
124
145
|
driver
|
|
@@ -129,7 +150,10 @@
|
|
|
129
150
|
const solvingIndicator = createSolvingIndicator(() => session.isSolving);
|
|
130
151
|
|
|
131
152
|
$effect(() => {
|
|
132
|
-
onReady?.({
|
|
153
|
+
onReady?.({
|
|
154
|
+
loadValues: (incoming) => session.loadValues(incoming),
|
|
155
|
+
getLastResult: () => session.lastResult
|
|
156
|
+
});
|
|
133
157
|
});
|
|
134
158
|
|
|
135
159
|
let previousDefinitionKey = $state('');
|