impact-nova 3.0.0-alpha.7 → 3.0.0-alpha.9

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 (103) hide show
  1. package/README.md +1 -1
  2. package/dist/components/data/expandable-list-item/sku-picker-chrome.d.ts +4 -0
  3. package/dist/components/data/expandable-list-item/sku-picker-chrome.js +37 -42
  4. package/dist/components/data-display/stereo-scatter/index.d.ts +2 -0
  5. package/dist/components/data-display/stereo-scatter/index.js +10 -0
  6. package/dist/components/data-display/stereo-scatter/internals/stereo-engine-frame.d.ts +41 -0
  7. package/dist/components/data-display/stereo-scatter/internals/stereo-engine-frame.js +178 -0
  8. package/dist/components/data-display/stereo-scatter/internals/stereo-engine-theme.d.ts +14 -0
  9. package/dist/components/data-display/stereo-scatter/internals/stereo-engine-theme.js +29 -0
  10. package/dist/components/data-display/stereo-scatter/internals/stereo-engine-wedges.d.ts +23 -0
  11. package/dist/components/data-display/stereo-scatter/internals/stereo-engine-wedges.js +80 -0
  12. package/dist/components/data-display/stereo-scatter/internals/stereo-engine.d.ts +120 -0
  13. package/dist/components/data-display/stereo-scatter/internals/stereo-engine.js +519 -0
  14. package/dist/components/data-display/stereo-scatter/internals/stereo-math.d.ts +64 -0
  15. package/dist/components/data-display/stereo-scatter/internals/stereo-math.js +129 -0
  16. package/dist/components/data-display/stereo-scatter/internals/stereo-model.d.ts +37 -0
  17. package/dist/components/data-display/stereo-scatter/internals/stereo-model.js +71 -0
  18. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-context.d.ts +33 -0
  19. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-context.js +19 -0
  20. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-key.d.ts +4 -0
  21. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-key.js +19 -0
  22. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-legend.d.ts +2 -0
  23. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-legend.js +75 -0
  24. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-scene.d.ts +2 -0
  25. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-scene.js +149 -0
  26. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-toolbar.d.ts +13 -0
  27. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-toolbar.js +93 -0
  28. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-tooltip.d.ts +2 -0
  29. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-tooltip.js +62 -0
  30. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-viewport.d.ts +3 -0
  31. package/dist/components/data-display/stereo-scatter/internals/stereo-scatter-viewport.js +41 -0
  32. package/dist/components/data-display/stereo-scatter/stereo-scatter.d.ts +12 -0
  33. package/dist/components/data-display/stereo-scatter/stereo-scatter.js +107 -0
  34. package/dist/components/data-display/stereo-scatter/stereo-scatter.stories-data.d.ts +11 -0
  35. package/dist/components/data-display/stereo-scatter/stereo-scatter.types.d.ts +69 -0
  36. package/dist/components/data-display/stereo-scatter/stereo-scatter.variants.d.ts +13 -0
  37. package/dist/components/data-display/stereo-scatter/stereo-scatter.variants.js +42 -0
  38. package/dist/components/feedback/tooltip/button-icon-tooltip.d.ts +3 -1
  39. package/dist/components/feedback/tooltip/button-icon-tooltip.js +22 -19
  40. package/dist/components/flows/iris-chat/IrisChatComposerVoiceCapture.d.ts +5 -0
  41. package/dist/components/flows/iris-chat/IrisChatComposerVoiceCapture.js +73 -0
  42. package/dist/components/flows/iris-chat/IrisChatVoiceWaveform.d.ts +3 -0
  43. package/dist/components/flows/iris-chat/IrisChatVoiceWaveform.js +25 -0
  44. package/dist/components/flows/iris-chat/index.d.ts +3 -1
  45. package/dist/components/flows/iris-chat/index.js +58 -53
  46. package/dist/components/flows/iris-chat/iris-chat-chrome.d.ts +39 -0
  47. package/dist/components/flows/iris-chat/iris-chat-chrome.js +325 -0
  48. package/dist/components/flows/iris-chat/iris-chat-close-animation.d.ts +12 -0
  49. package/dist/components/flows/iris-chat/iris-chat-close-animation.js +21 -0
  50. package/dist/components/flows/iris-chat/iris-chat-composer.js +266 -238
  51. package/dist/components/flows/iris-chat/iris-chat-context.d.ts +13 -0
  52. package/dist/components/flows/iris-chat/iris-chat-context.js +14 -10
  53. package/dist/components/flows/iris-chat/iris-chat-copy-feedback.d.ts +4 -0
  54. package/dist/components/flows/iris-chat/iris-chat-copy-feedback.js +16 -0
  55. package/dist/components/flows/iris-chat/iris-chat-frame.d.ts +31 -0
  56. package/dist/components/flows/iris-chat/iris-chat-frame.js +79 -0
  57. package/dist/components/flows/iris-chat/iris-chat-icons.d.ts +1 -0
  58. package/dist/components/flows/iris-chat/iris-chat-icons.js +28 -15
  59. package/dist/components/flows/iris-chat/iris-chat-launch-animation.d.ts +11 -0
  60. package/dist/components/flows/iris-chat/iris-chat-launch-animation.js +35 -0
  61. package/dist/components/flows/iris-chat/iris-chat-markdown.js +70 -50
  62. package/dist/components/flows/iris-chat/iris-chat-menu.js +91 -86
  63. package/dist/components/flows/iris-chat/iris-chat-speech.d.ts +52 -0
  64. package/dist/components/flows/iris-chat/iris-chat-speech.js +121 -0
  65. package/dist/components/flows/iris-chat/iris-chat-thread.d.ts +3 -0
  66. package/dist/components/flows/iris-chat/iris-chat-thread.js +241 -190
  67. package/dist/components/flows/iris-chat/iris-chat-window-chrome.d.ts +30 -0
  68. package/dist/components/flows/iris-chat/iris-chat-window-chrome.js +34 -0
  69. package/dist/components/flows/iris-chat/iris-chat-window-geometry-context.d.ts +14 -0
  70. package/dist/components/flows/iris-chat/iris-chat-window-geometry-context.js +15 -0
  71. package/dist/components/flows/iris-chat/iris-chat-window-geometry.d.ts +12 -0
  72. package/dist/components/flows/iris-chat/iris-chat-window-geometry.js +113 -0
  73. package/dist/components/flows/iris-chat/iris-chat-window-handles.d.ts +6 -0
  74. package/dist/components/flows/iris-chat/iris-chat-window-handles.js +50 -0
  75. package/dist/components/flows/iris-chat/iris-chat-window-shell.d.ts +8 -0
  76. package/dist/components/flows/iris-chat/iris-chat-window-shell.js +37 -0
  77. package/dist/components/flows/iris-chat/iris-chat.d.ts +3 -39
  78. package/dist/components/flows/iris-chat/iris-chat.js +22 -330
  79. package/dist/components/flows/iris-chat/iris-chat.types.d.ts +18 -0
  80. package/dist/components/flows/iris-chat/iris-chat.variants.d.ts +3 -3
  81. package/dist/components/flows/iris-chat/iris-chat.variants.js +21 -16
  82. package/dist/components/flows/iris-chat/use-iris-chat-root.d.ts +26 -0
  83. package/dist/components/flows/iris-chat/use-iris-chat-root.js +140 -0
  84. package/dist/components/forms/choice-card/choice-card.d.ts +1 -0
  85. package/dist/components/forms/choice-card/choice-card.js +183 -186
  86. package/dist/components/layout/header/header.js +1 -0
  87. package/dist/form-react/Fields/SelectField.js +66 -57
  88. package/dist/form-react/Fields/VirtualizedListField.js +140 -96
  89. package/dist/form-react/index.d.ts +1 -1
  90. package/dist/form-react/types/fields.types.d.ts +27 -0
  91. package/dist/form-react/types/reactHookForm.types.d.ts +18 -1
  92. package/dist/i18n/defaultMessages.d.ts +37 -0
  93. package/dist/i18n/defaultMessages.js +54 -18
  94. package/dist/i18n/index.d.ts +1 -1
  95. package/dist/i18n/locales/de.js +36 -0
  96. package/dist/i18n/locales/es.js +36 -0
  97. package/dist/i18n/locales/hi.js +36 -0
  98. package/dist/i18n/locales/kn.js +36 -0
  99. package/dist/impact-nova-components.css +19 -0
  100. package/dist/impact-nova.css +1 -1
  101. package/dist/llms/rules/installation.js +1 -1
  102. package/dist/llms/rules/requirements.js +1 -1
  103. package/package.json +5 -1
@@ -0,0 +1,519 @@
1
+ import { Scene as N, Raycaster as _, Vector3 as m, WebGLRenderer as V, NeutralToneMapping as B, PCFSoftShadowMap as H, PerspectiveCamera as U, Box3 as W, SphereGeometry as R, MeshPhysicalMaterial as x, InstancedMesh as z, MeshBasicMaterial as j, Mesh as C, LineSegments as M, Color as I, PMREMGenerator as X, HemisphereLight as Y, DirectionalLight as q, PlaneGeometry as Z, ShadowMaterial as Q, DoubleSide as K, EdgesGeometry as J, LineBasicMaterial as $, BufferGeometry as ee, Float32BufferAttribute as te, LineDashedMaterial as se, Fog as ie, Matrix4 as A, Quaternion as oe, Vector2 as ne } from "three";
2
+ import { OrbitControls as re } from "three/addons/controls/OrbitControls.js";
3
+ import { CSS2DRenderer as ae, CSS2DObject as D } from "three/addons/renderers/CSS2DRenderer.js";
4
+ import { ConvexGeometry as he } from "three/addons/geometries/ConvexGeometry.js";
5
+ import { RoomEnvironment as ce } from "three/addons/environments/RoomEnvironment.js";
6
+ import { clamp as g, STEREO_ELEVATION_LIMIT as L, STEREO_VIEW_PRESETS as P, easeInOutCubic as de, lerp as T, shortestAngle as S, orbitOffset as le, easeOutCubic as ue, estimateLabelWidth as me, placeLabels as pe, wedgeStyleForDepth as fe, wedgeStrength as ge, solidWedgePath as be, hashedWedgePath as we, linePath as ve } from "./stereo-math.js";
7
+ import { readStereoTheme as ye } from "./stereo-engine-theme.js";
8
+ import { StereoWedgeBonds as xe } from "./stereo-engine-wedges.js";
9
+ import { StereoAxisFrame as ze } from "./stereo-engine-frame.js";
10
+ const Ce = {
11
+ molecule: { bonds: "all", hulls: !1, centroid: "atom", atomRadius: 0.042, stretchBonds: !0 },
12
+ crystal: { bonds: "active", hulls: !0, centroid: "core", atomRadius: 0.032, stretchBonds: !1 }
13
+ }, O = [-1, 1].flatMap((u) => [-1, 1].flatMap((e) => [-1, 1].map((t) => new m(u, e, t)))), F = { vertical: 0.2, horizontal: 0.34 }, E = 30, Me = 6, Ee = 3, Pe = 1.4, y = { top: 0, bottom: 44 }, Se = 950, Re = 720, Ie = 0.6, Ae = 3, De = 0.84, k = 20, Le = 0.24, Te = 120, Oe = 3.5, Fe = "pointer-events-none select-none ms-3 flex items-center gap-1.5 whitespace-nowrap rounded-full border border-stroke-hairline bg-canvas-elevated px-2 py-0.5 text-[11px] font-semibold leading-4 text-content shadow-elevation-card transition-opacity duration-200 motion-reduce:transition-none", G = "http://www.w3.org/2000/svg", ke = [
14
+ [1, 0, 0],
15
+ [-1, 0, 0],
16
+ [0, 1, 0],
17
+ [0, -1, 0],
18
+ [0, 0, 1],
19
+ [0, 0, -1],
20
+ [1, 1, 1],
21
+ [1, 1, -1],
22
+ [1, -1, 1],
23
+ [1, -1, -1],
24
+ [-1, 1, 1],
25
+ [-1, 1, -1],
26
+ [-1, -1, 1],
27
+ [-1, -1, -1]
28
+ ].map(([u, e, t]) => new m(u, e, t).normalize());
29
+ function f(u) {
30
+ return new m(u.x, u.y, u.z);
31
+ }
32
+ function Ge(u, e) {
33
+ let t = 0, s = 0;
34
+ for (const i of u)
35
+ t = Math.max(t, Math.abs(i.y - e.y)), s = Math.max(s, Math.hypot(i.x - e.x, i.z - e.z));
36
+ return { vertical: t, horizontal: s };
37
+ }
38
+ function Ne(u, e) {
39
+ let t = 0, s = 0, i = 0;
40
+ for (const a of u) {
41
+ const c = a.x - e.x, d = a.z - e.z;
42
+ t += c * c, s += d * d, i += c * d;
43
+ }
44
+ const o = P.iso;
45
+ if (t + s < 1e-6) return o;
46
+ const n = 0.5 * Math.atan2(2 * i, t - s);
47
+ return { azimuth: [-n, Math.PI - n].reduce(
48
+ (a, c) => Math.abs(S(c, o.azimuth)) < Math.abs(S(a, o.azimuth)) ? c : a
49
+ ), elevation: o.elevation };
50
+ }
51
+ class _e {
52
+ options;
53
+ config;
54
+ theme;
55
+ renderer;
56
+ labelRenderer;
57
+ scene = new N();
58
+ camera;
59
+ controls;
60
+ raycaster = new _();
61
+ disposables = [];
62
+ nodes;
63
+ positions;
64
+ targets;
65
+ sceneCenter = new m();
66
+ /** Atoms shrink as the store count grows so dense networks stay legible. */
67
+ atomRadius;
68
+ extents;
69
+ bestOrbit;
70
+ clusters;
71
+ centroidPositions;
72
+ atoms;
73
+ centroids;
74
+ bonds;
75
+ hulls = [];
76
+ labels = [];
77
+ axisFrame;
78
+ guides;
79
+ guideMarkers;
80
+ gizmoParts = [];
81
+ emphasis = {
82
+ hiddenClusterIds: /* @__PURE__ */ new Set(),
83
+ activeClusterId: null,
84
+ focusedClusterId: null
85
+ };
86
+ hoverTarget = null;
87
+ autoRotate;
88
+ zoom = 1;
89
+ baseDistance = 6;
90
+ size = { width: 1, height: 1 };
91
+ progress;
92
+ entranceStart = 0;
93
+ tween = null;
94
+ interacting = !1;
95
+ pointerInside = !1;
96
+ pointer = null;
97
+ pointerDown = null;
98
+ hoverPending = !1;
99
+ atomsDirty = !0;
100
+ cameraDirty = !0;
101
+ needsRender = !0;
102
+ onScreen = !0;
103
+ frameId = 0;
104
+ resizeObserver = null;
105
+ intersectionObserver = null;
106
+ envTexture = null;
107
+ constructor(e) {
108
+ this.options = e, this.config = Ce[e.variant], this.autoRotate = e.autoRotate, this.progress = e.reducedMotion ? 1 : 0;
109
+ const { container: t, model: s } = e;
110
+ this.theme = ye(t, s), this.renderer = new V({ antialias: !0, alpha: !0, powerPreference: "high-performance" }), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2)), this.renderer.setClearColor(0, 0), this.renderer.toneMapping = B, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = H;
111
+ const i = this.renderer.domElement;
112
+ i.style.display = "block", i.style.outline = "none", i.style.touchAction = "none", i.dataset.slot = "stereo-scatter-canvas", t.appendChild(i), this.labelRenderer = new ae();
113
+ const o = this.labelRenderer.domElement;
114
+ o.style.position = "absolute", o.style.inset = "0", o.style.pointerEvents = "none", o.style.overflow = "hidden", o.style.zIndex = "0", t.appendChild(o), this.camera = new U(E, 1, 0.1, 60), this.clusters = s.clusters.filter((l) => l.nodes.length > 0), this.centroidPositions = new Map(
115
+ this.clusters.map((l) => [l.cluster.id, f(l.centroid)])
116
+ ), this.nodes = this.clusters.flatMap((l) => l.nodes.map((b) => ({ node: b, cluster: l }))), this.positions = this.nodes.map((l) => f(l.node.position)), this.atomRadius = this.config.atomRadius * g(Math.sqrt(Te / Math.max(1, this.nodes.length)), 0.55, 1);
117
+ const n = this.nodes.map((l) => f(l.node.position).sub(f(l.cluster.centroid))), h = n.reduce((l, b) => l + b.length(), 0) / Math.max(1, n.length), r = this.config.stretchBonds && h > 0 ? g(Le / h, 1, Oe) : 1;
118
+ this.targets = this.nodes.map(
119
+ (l, b) => f(l.cluster.centroid).addScaledVector(n[b], r)
120
+ ), new W().setFromPoints([...this.targets, ...O]).getCenter(this.sceneCenter);
121
+ const c = Ge([...this.targets, ...O], this.sceneCenter);
122
+ this.extents = {
123
+ vertical: c.vertical + F.vertical,
124
+ horizontal: c.horizontal + F.horizontal
125
+ }, this.bestOrbit = Ne(this.targets, this.sceneCenter), this.setupLighting();
126
+ const d = new R(1, 32, 24);
127
+ this.disposables.push(d);
128
+ const p = new x({ roughness: 0.3, metalness: 0, clearcoat: 0.85, clearcoatRoughness: 0.22 }), w = new x({ roughness: 0.2, metalness: 0.05, clearcoat: 1, clearcoatRoughness: 0.12 });
129
+ this.disposables.push(p, w), this.atoms = this.createInstances(d, p, this.nodes.length), this.centroids = this.createInstances(d, w, this.clusters.length), this.bonds = new xe(this.nodes.length), this.scene.add(this.bonds.group), this.disposables.push(this.bonds), this.config.hulls && this.buildHulls(), this.axisFrame = new ze(s, this.theme, e.axes), this.scene.add(this.axisFrame.group), this.disposables.push(this.axisFrame), this.buildShadowPlane(), this.guides = this.buildGuides();
130
+ const v = new R(1, 16, 12);
131
+ this.disposables.push(v), this.guideMarkers = new z(
132
+ v,
133
+ new j({ color: this.theme.brand, fog: !1 }),
134
+ Ee
135
+ ), this.guideMarkers.visible = !1, this.guideMarkers.frustumCulled = !1, this.scene.add(this.guideMarkers), this.buildLabels(), this.buildGizmo(), this.controls = new re(this.camera, i), this.controls.enableZoom = !1, this.controls.enablePan = !1, this.controls.enableDamping = !e.reducedMotion, this.controls.dampingFactor = 0.08, this.controls.rotateSpeed = 0.75, this.controls.autoRotateSpeed = 0.9, this.controls.minPolarAngle = Math.PI / 2 - L, this.controls.maxPolarAngle = Math.PI / 2 + 0.35, this.controls.addEventListener("change", this.handleControlsChange), this.controls.addEventListener("start", this.handleControlsStart), this.controls.addEventListener("end", this.handleControlsEnd), i.addEventListener("pointermove", this.handlePointerMove), i.addEventListener("pointerleave", this.handlePointerLeave), i.addEventListener("pointerdown", this.handlePointerDown), i.addEventListener("pointerup", this.handlePointerUp), i.style.cursor = "grab", this.resizeObserver = new ResizeObserver(() => this.resize()), this.resizeObserver.observe(t), typeof IntersectionObserver < "u" && (this.intersectionObserver = new IntersectionObserver((l) => {
136
+ this.onScreen = l.some((b) => b.isIntersecting), this.onScreen && (this.needsRender = !0);
137
+ }), this.intersectionObserver.observe(t)), this.resize(), this.applyPose({
138
+ target: this.sceneCenter.clone(),
139
+ orbit: this.orbitForView(e.defaultView),
140
+ zoom: 1
141
+ }), this.entranceStart = performance.now(), this.frameId = requestAnimationFrame(this.tick);
142
+ }
143
+ setEmphasis(e) {
144
+ const t = e.focusedClusterId !== this.emphasis.focusedClusterId;
145
+ if (this.emphasis = e, this.atomsDirty = !0, this.needsRender = !0, !t) return;
146
+ const s = e.focusedClusterId ? this.clusters.find((o) => o.cluster.id === e.focusedClusterId) : void 0, i = this.readPose();
147
+ s ? this.tweenTo({
148
+ target: f(s.centroid),
149
+ orbit: i.orbit,
150
+ zoom: g(1.1 / (s.spread * 1.4 + 0.3), 1.3, 2.6)
151
+ }) : this.tweenTo({ target: this.sceneCenter.clone(), orbit: i.orbit, zoom: 1 });
152
+ }
153
+ setAutoRotate(e) {
154
+ this.autoRotate = e;
155
+ }
156
+ setView(e) {
157
+ this.tweenTo({ ...this.readPose(), orbit: this.orbitForView(e) });
158
+ }
159
+ rotateBy(e, t) {
160
+ const s = this.readPose();
161
+ this.tweenTo(
162
+ {
163
+ ...s,
164
+ orbit: {
165
+ azimuth: s.orbit.azimuth + e,
166
+ elevation: g(s.orbit.elevation + t, -0.35, L)
167
+ }
168
+ },
169
+ 260
170
+ );
171
+ }
172
+ zoomBy(e) {
173
+ const t = this.readPose();
174
+ this.tweenTo({ ...t, zoom: g(t.zoom * e, Ie, Ae) }, 320);
175
+ }
176
+ resetView() {
177
+ this.tweenTo({
178
+ target: this.sceneCenter.clone(),
179
+ orbit: this.orbitForView(this.options.defaultView),
180
+ zoom: 1
181
+ });
182
+ }
183
+ dispose() {
184
+ cancelAnimationFrame(this.frameId), this.resizeObserver?.disconnect(), this.intersectionObserver?.disconnect();
185
+ const e = this.renderer.domElement;
186
+ e.removeEventListener("pointermove", this.handlePointerMove), e.removeEventListener("pointerleave", this.handlePointerLeave), e.removeEventListener("pointerdown", this.handlePointerDown), e.removeEventListener("pointerup", this.handlePointerUp), this.controls.removeEventListener("change", this.handleControlsChange), this.controls.removeEventListener("start", this.handleControlsStart), this.controls.removeEventListener("end", this.handleControlsEnd), this.controls.dispose(), this.scene.traverse((t) => {
187
+ if (t instanceof C || t instanceof M || t instanceof z) {
188
+ t.geometry.dispose();
189
+ const s = t.material;
190
+ Array.isArray(s) ? s.forEach((i) => i.dispose()) : s.dispose();
191
+ }
192
+ t instanceof D && t.element.remove();
193
+ });
194
+ for (const t of this.disposables) t.dispose();
195
+ this.atoms.dispose(), this.centroids.dispose(), this.envTexture?.dispose(), this.renderer.dispose(), this.renderer.forceContextLoss(), e.remove(), this.labelRenderer.domElement.remove();
196
+ for (const t of this.gizmoParts)
197
+ t.path.remove(), t.text.remove();
198
+ }
199
+ orbitForView(e) {
200
+ return e === "iso" ? this.bestOrbit : P[e];
201
+ }
202
+ createInstances(e, t, s) {
203
+ const i = new z(e, t, Math.max(1, s)), o = new I(1, 1, 1);
204
+ for (let n = 0; n < i.count; n += 1) i.setColorAt(n, o);
205
+ return i.count = s, i.castShadow = !0, this.scene.add(i), i;
206
+ }
207
+ setupLighting() {
208
+ const e = new X(this.renderer), t = new ce();
209
+ this.envTexture = e.fromScene(t, 0.04).texture, t.dispose(), e.dispose(), this.scene.environment = this.envTexture, this.scene.environmentIntensity = 0.55;
210
+ const s = new I(1, 1, 1);
211
+ this.scene.add(new Y(s, this.theme.foreground, 0.55));
212
+ const i = new q(s, 1.9);
213
+ i.position.set(2.4, 5, 3.6), i.castShadow = !0, i.shadow.mapSize.set(1024, 1024), i.shadow.camera.left = -2.4, i.shadow.camera.right = 2.4, i.shadow.camera.top = 2.4, i.shadow.camera.bottom = -2.4, i.shadow.camera.near = 0.5, i.shadow.camera.far = 14, i.shadow.bias = -4e-4, i.shadow.normalBias = 0.02, this.scene.add(i);
214
+ }
215
+ buildShadowPlane() {
216
+ const e = new C(
217
+ new Z(2.6, 2.6),
218
+ new Q({ color: this.theme.foreground, opacity: 0.1, transparent: !0 })
219
+ );
220
+ e.rotation.x = -Math.PI / 2, e.position.y = -1.001, e.receiveShadow = !0, this.scene.add(e);
221
+ }
222
+ buildHulls() {
223
+ for (const e of this.clusters) {
224
+ const t = f(e.centroid), s = 0.07, i = [];
225
+ for (const a of e.nodes) {
226
+ const c = f(a.position).sub(t);
227
+ for (const d of ke)
228
+ i.push(c.clone().addScaledVector(d, s));
229
+ }
230
+ const o = this.theme.clusterColors.get(e.cluster.id) ?? this.theme.foreground, n = new he(i), h = new C(
231
+ n,
232
+ new x({
233
+ color: o,
234
+ transparent: !0,
235
+ opacity: 0.18,
236
+ roughness: 0.12,
237
+ metalness: 0,
238
+ clearcoat: 1,
239
+ clearcoatRoughness: 0.08,
240
+ side: K,
241
+ depthWrite: !1
242
+ })
243
+ );
244
+ h.position.copy(t), h.userData.clusterId = e.cluster.id, h.renderOrder = 1;
245
+ const r = new M(
246
+ new J(n, 28),
247
+ new $({ color: o, transparent: !0, opacity: 0.5, depthWrite: !1 })
248
+ );
249
+ h.add(r), this.scene.add(h), this.hulls.push({ cluster: e, mesh: h, edges: r });
250
+ }
251
+ }
252
+ buildGuides() {
253
+ const e = new ee();
254
+ e.setAttribute("position", new te(new Float32Array(Me * 3), 3));
255
+ const t = new M(
256
+ e,
257
+ new se({ color: this.theme.brand, dashSize: 0.04, gapSize: 0.022, fog: !1 })
258
+ );
259
+ return t.visible = !1, t.frustumCulled = !1, this.scene.add(t), t;
260
+ }
261
+ buildLabels() {
262
+ for (const e of this.clusters) {
263
+ const t = document.createElement("div");
264
+ t.className = Fe, t.dataset.clusterId = e.cluster.id;
265
+ const s = document.createElement("span");
266
+ s.className = "size-2 shrink-0 rounded-full", s.style.backgroundColor = e.color;
267
+ const i = document.createElement("span");
268
+ i.textContent = e.cluster.label;
269
+ const o = document.createElement("span");
270
+ o.className = "font-medium tabular-nums text-content-muted", o.textContent = String(e.nodes.length), t.append(s, i, o), t.setAttribute("aria-hidden", "true");
271
+ const n = new D(t);
272
+ n.center.set(0, 0.5), n.position.copy(f(e.centroid)), this.scene.add(n), this.labels.push({ cluster: e, object: n });
273
+ }
274
+ }
275
+ buildGizmo() {
276
+ const e = this.options.gizmo;
277
+ if (!e) return;
278
+ const t = [
279
+ ["X", new m(1, 0, 0)],
280
+ ["Y", new m(0, 1, 0)],
281
+ ["Z", new m(0, 0, 1)]
282
+ ];
283
+ for (const [s, i] of t) {
284
+ const o = document.createElementNS(G, "path"), n = document.createElementNS(G, "text");
285
+ n.textContent = s, n.setAttribute("text-anchor", "middle"), n.setAttribute("dominant-baseline", "central"), n.setAttribute("font-size", "9"), n.setAttribute("font-weight", "700"), n.setAttribute("fill", "currentColor"), e.append(o, n), this.gizmoParts.push({ path: o, text: n, axis: i });
286
+ }
287
+ }
288
+ handleControlsChange = () => {
289
+ this.cameraDirty = !0, this.needsRender = !0;
290
+ };
291
+ handleControlsStart = () => {
292
+ this.interacting = !0, this.tween = null, this.renderer.domElement.style.cursor = "grabbing", this.setHover(null);
293
+ };
294
+ handleControlsEnd = () => {
295
+ this.interacting = !1, this.renderer.domElement.style.cursor = "grab";
296
+ };
297
+ handlePointerMove = (e) => {
298
+ const t = this.renderer.domElement.getBoundingClientRect();
299
+ this.pointer = { x: e.clientX - t.left, y: e.clientY - t.top }, this.pointerInside = !0, this.hoverPending = !0;
300
+ };
301
+ handlePointerLeave = () => {
302
+ this.pointerInside = !1, this.pointer = null, this.setHover(null);
303
+ };
304
+ handlePointerDown = (e) => {
305
+ this.pointerDown = { x: e.clientX, y: e.clientY };
306
+ };
307
+ handlePointerUp = (e) => {
308
+ const t = this.pointerDown;
309
+ if (this.pointerDown = null, !t || Math.hypot(e.clientX - t.x, e.clientY - t.y) > 5) return;
310
+ const s = this.renderer.domElement.getBoundingClientRect();
311
+ this.pointer = { x: e.clientX - s.left, y: e.clientY - s.top }, this.options.onClick(this.pick());
312
+ };
313
+ tick = (e) => {
314
+ if (this.frameId = requestAnimationFrame(this.tick), !(!this.onScreen || document.hidden)) {
315
+ if (this.tween) {
316
+ const t = this.tween.duration <= 0 ? 1 : g((e - this.tween.start) / this.tween.duration, 0, 1);
317
+ this.applyPose(this.lerpPose(this.tween.from, this.tween.to, de(t))), t >= 1 && (this.tween = null);
318
+ }
319
+ this.progress < 1 && (this.progress = g((e - this.entranceStart) / Se, 0, 1), this.atomsDirty = !0), this.controls.autoRotate = this.autoRotate && !this.options.reducedMotion && !this.pointerInside && !this.interacting && !this.tween && !this.emphasis.focusedClusterId, this.controls.update(), this.atomsDirty && (this.updateAtoms(), this.atomsDirty = !1, this.cameraDirty = !0, this.needsRender = !0), this.cameraDirty && (this.updateCameraDependents(), this.cameraDirty = !1, this.needsRender = !0), this.hoverPending && !this.interacting && (this.hoverPending = !1, this.updateHoverFromPointer()), this.needsRender && (this.needsRender = !1, this.renderer.render(this.scene, this.camera), this.labelRenderer.render(this.scene, this.camera), this.layoutLabels(), this.updateGizmo());
320
+ }
321
+ };
322
+ resize() {
323
+ const { container: e } = this.options, t = Math.max(1, e.clientWidth), s = Math.max(1, e.clientHeight);
324
+ this.size = { width: t, height: s }, this.renderer.setSize(t, s), this.labelRenderer.setSize(t, s), this.camera.aspect = t / s;
325
+ const i = Math.max(1, s - y.top - y.bottom), o = Math.tan(E * Math.PI / 360) * (i / s), n = Math.tan(E * Math.PI / 360) * (t / s), h = 0.06, r = P.iso.elevation, a = this.extents.vertical * Math.cos(r) + this.extents.horizontal * Math.sin(r) + h;
326
+ this.baseDistance = Math.max(a / o, (this.extents.horizontal + h) / n) + this.extents.horizontal * 0.3, this.scene.fog = new ie(this.theme.surface, this.baseDistance - 0.4, this.baseDistance + 4.5), this.camera.setViewOffset(t, s, 0, (y.bottom - y.top) / 2, t, s), this.camera.updateProjectionMatrix(), this.controls && this.applyPose(this.readPose()), this.needsRender = !0;
327
+ }
328
+ readPose() {
329
+ const e = this.controls.target.clone(), t = this.camera.position.clone().sub(e), s = t.length() || 1;
330
+ return {
331
+ target: e,
332
+ orbit: {
333
+ azimuth: Math.atan2(t.x, t.z),
334
+ elevation: Math.asin(g(t.y / s, -1, 1))
335
+ },
336
+ zoom: this.zoom
337
+ };
338
+ }
339
+ lerpPose(e, t, s) {
340
+ return {
341
+ target: e.target.clone().lerp(t.target, s),
342
+ orbit: {
343
+ azimuth: e.orbit.azimuth + S(e.orbit.azimuth, t.orbit.azimuth) * s,
344
+ elevation: T(e.orbit.elevation, t.orbit.elevation, s)
345
+ },
346
+ zoom: T(e.zoom, t.zoom, s)
347
+ };
348
+ }
349
+ applyPose(e) {
350
+ this.zoom = e.zoom;
351
+ const t = le(e.orbit, this.baseDistance / e.zoom);
352
+ this.camera.position.set(e.target.x + t.x, e.target.y + t.y, e.target.z + t.z), this.camera.lookAt(e.target), this.controls?.target.copy(e.target), this.controls?.update(), this.cameraDirty = !0, this.needsRender = !0;
353
+ }
354
+ tweenTo(e, t = Re) {
355
+ if (this.options.reducedMotion) {
356
+ this.tween = null, this.applyPose(e);
357
+ return;
358
+ }
359
+ this.tween = { from: this.readPose(), to: e, start: performance.now(), duration: t };
360
+ }
361
+ effectiveActiveCluster() {
362
+ return this.hoverTarget?.type === "cluster" ? this.hoverTarget.id : this.emphasis.activeClusterId;
363
+ }
364
+ colorFor(e, t) {
365
+ const s = this.theme.clusterColors.get(e.cluster.id) ?? this.theme.foreground;
366
+ return !t || t === e.cluster.id ? s : s.clone().lerp(this.theme.surface, De);
367
+ }
368
+ centroidRadius(e) {
369
+ return this.config.centroid === "core" ? 0.03 : Math.min(this.atomRadius * 1.85, this.atomRadius * (1.25 + 0.15 * Math.sqrt(e.nodes.length)));
370
+ }
371
+ updateAtoms() {
372
+ const e = new A(), t = new oe(), s = new m(), i = ue(this.progress), o = this.effectiveActiveCluster(), n = this.emphasis.hiddenClusterIds, h = this.hoverTarget?.type === "point" ? this.hoverTarget.id : null;
373
+ this.nodes.forEach((r, a) => {
374
+ const c = this.centroidPositions.get(r.cluster.cluster.id), d = this.positions[a];
375
+ d.copy(c).lerp(this.targets[a], i);
376
+ const p = n.has(r.cluster.cluster.id), w = this.config.hulls && this.emphasis.focusedClusterId === r.cluster.cluster.id, v = p ? 0 : this.atomRadius * (w ? Pe : 1) * (h === r.node.point.id ? 1.6 : 1);
377
+ e.compose(d, t, s.setScalar(v)), this.atoms.setMatrixAt(a, e), this.atoms.setColorAt(a, this.colorFor(r.cluster, o));
378
+ }), this.atoms.instanceMatrix.needsUpdate = !0, this.atoms.instanceColor && (this.atoms.instanceColor.needsUpdate = !0), this.atoms.computeBoundingSphere(), this.clusters.forEach((r, a) => {
379
+ const c = r.cluster.id, d = n.has(c);
380
+ let p = this.centroidRadius(r);
381
+ d && (p = 0), this.hoverTarget?.type === "cluster" && this.hoverTarget.id === c && (p *= 1.18), e.compose(this.centroidPositions.get(c), t, s.setScalar(p * Math.max(i, 0.35))), this.centroids.setMatrixAt(a, e), this.centroids.setColorAt(a, this.colorFor(r, o));
382
+ }), this.centroids.instanceMatrix.needsUpdate = !0, this.centroids.instanceColor && (this.centroids.instanceColor.needsUpdate = !0), this.centroids.computeBoundingSphere();
383
+ for (const r of this.hulls) {
384
+ const a = r.cluster.cluster.id;
385
+ r.mesh.visible = !n.has(a), r.mesh.scale.setScalar(Math.max(1e-3, i));
386
+ const c = o === a, d = this.emphasis.focusedClusterId === a;
387
+ r.mesh.material.opacity = o ? c ? d ? 0.12 : 0.32 : 0.04 : 0.17, r.edges.material.opacity = o ? c ? 0.9 : 0.08 : 0.45;
388
+ }
389
+ for (const r of this.labels) {
390
+ const a = r.cluster.cluster.id;
391
+ r.object.visible = !n.has(a);
392
+ }
393
+ }
394
+ updateCameraDependents() {
395
+ this.axisFrame.update(this.camera, this.controls.target), this.updateBonds(), this.updateGuides();
396
+ }
397
+ updateBonds() {
398
+ const e = this.effectiveActiveCluster(), t = this.emphasis.hiddenClusterIds, s = [];
399
+ this.nodes.forEach((i, o) => {
400
+ const n = i.cluster.cluster.id;
401
+ t.has(n) || this.config.bonds === "active" && e !== n || s.push({
402
+ from: this.centroidPositions.get(n),
403
+ to: this.positions[o],
404
+ fromRadius: this.centroidRadius(i.cluster) * 0.85,
405
+ toRadius: this.atomRadius,
406
+ color: this.colorFor(i.cluster, e)
407
+ });
408
+ }), this.bonds.update(s, this.camera);
409
+ }
410
+ updateGuides() {
411
+ const e = this.hoverTarget?.type === "point" ? this.hoverTarget.id : null, t = e ? this.nodes.findIndex((a) => a.node.point.id === e) : -1;
412
+ if (t < 0) {
413
+ this.guides.visible = !1, this.guideMarkers.visible = !1;
414
+ return;
415
+ }
416
+ const s = this.positions[t], i = this.axisFrame.nearEdges(), o = [
417
+ [s.x, s.y, s.z],
418
+ [s.x, -1, s.z],
419
+ [s.x, -1, s.z],
420
+ [s.x, -1, i.z],
421
+ [s.x, -1, s.z],
422
+ [i.x, -1, s.z]
423
+ ], n = this.guides.geometry.getAttribute("position");
424
+ o.forEach(([a, c, d], p) => n.setXYZ(p, a, c, d)), n.needsUpdate = !0, this.guides.computeLineDistances(), this.guides.visible = !0;
425
+ const h = new A();
426
+ [
427
+ new m(s.x, -1, s.z),
428
+ new m(s.x, -1, i.z),
429
+ new m(i.x, -1, s.z)
430
+ ].forEach((a, c) => {
431
+ this.guideMarkers.setMatrixAt(c, h.makeScale(0.016, 0.016, 0.016).setPosition(a));
432
+ }), this.guideMarkers.instanceMatrix.needsUpdate = !0, this.guideMarkers.visible = !0;
433
+ }
434
+ layoutLabels() {
435
+ const e = this.effectiveActiveCluster(), t = new m(), s = [];
436
+ for (const o of this.labels) {
437
+ if (!o.object.visible || (t.copy(o.object.position).project(this.camera), t.z > 1)) continue;
438
+ const n = (t.x + 1) / 2 * this.size.width, h = (1 - t.y) / 2 * this.size.height, r = o.cluster.cluster.id;
439
+ s.push({
440
+ id: r,
441
+ x: n + 12,
442
+ y: h - k / 2,
443
+ width: me(o.cluster.cluster.label) + 44,
444
+ height: k,
445
+ priority: (e === r ? 1e6 : 0) + o.cluster.nodes.length * 100 + (1 - t.z) * 50
446
+ });
447
+ }
448
+ const i = pe(s, this.size);
449
+ for (const o of this.labels) {
450
+ const n = o.cluster.cluster.id, h = i.has(n);
451
+ o.object.element.style.opacity = h ? e && e !== n ? "0.35" : "1" : "0";
452
+ }
453
+ }
454
+ updateGizmo() {
455
+ if (this.gizmoParts.length === 0) return;
456
+ const e = this.camera.quaternion.clone().invert(), t = { x: 28, y: 28 }, s = 17, i = this.gizmoParts.map((o) => ({ part: o, view: o.axis.clone().applyQuaternion(e) })).sort((o, n) => o.view.z - n.view.z);
457
+ for (const { part: o, view: n } of i) {
458
+ const h = { x: t.x + n.x * s, y: t.y - n.y * s }, r = fe(n.z, 0.15), a = 1.2 + 2.6 * ge(n.z * 0.5);
459
+ r === "solid" ? (o.path.setAttribute("d", be(t, h, a)), o.path.setAttribute("fill", "currentColor"), o.path.setAttribute("stroke", "none")) : (o.path.setAttribute("d", r === "hashed" ? we(t, h, a, 2.4) : ve(t, h)), o.path.setAttribute("fill", "none"), o.path.setAttribute("stroke", "currentColor"), o.path.setAttribute("stroke-width", r === "hashed" ? "1" : "1.4"), o.path.setAttribute("stroke-linecap", "round")), o.text.setAttribute("x", (t.x + n.x * (s + 7)).toFixed(1)), o.text.setAttribute("y", (t.y - n.y * (s + 7)).toFixed(1)), o.text.setAttribute("opacity", n.z < -0.15 ? "0.55" : "1"), o.path.parentNode?.appendChild(o.path), o.text.parentNode?.appendChild(o.text);
460
+ }
461
+ }
462
+ pick() {
463
+ if (!this.pointer) return null;
464
+ const e = new ne(
465
+ this.pointer.x / this.size.width * 2 - 1,
466
+ -(this.pointer.y / this.size.height) * 2 + 1
467
+ );
468
+ this.raycaster.setFromCamera(e, this.camera);
469
+ const t = [this.atoms, this.centroids, ...this.hulls.map((n) => n.mesh)], s = this.raycaster.intersectObjects(t, !1), i = this.emphasis.focusedClusterId;
470
+ let o = null;
471
+ for (const n of s) {
472
+ if (n.object === this.atoms && n.instanceId !== void 0) {
473
+ const r = this.nodes[n.instanceId];
474
+ if (!r || this.emphasis.hiddenClusterIds.has(r.cluster.cluster.id)) continue;
475
+ return this.config.hulls && r.cluster.cluster.id !== i ? { type: "cluster", id: r.cluster.cluster.id } : { type: "point", id: r.node.point.id };
476
+ }
477
+ if (n.object === this.centroids && n.instanceId !== void 0) {
478
+ const r = this.clusters[n.instanceId];
479
+ if (r && !this.emphasis.hiddenClusterIds.has(r.cluster.id))
480
+ return { type: "cluster", id: r.cluster.id };
481
+ continue;
482
+ }
483
+ const h = n.object.userData.clusterId;
484
+ if (!(typeof h != "string" || !n.object.visible)) {
485
+ if (h === i) {
486
+ o ??= { type: "cluster", id: h };
487
+ continue;
488
+ }
489
+ return { type: "cluster", id: h };
490
+ }
491
+ }
492
+ return o;
493
+ }
494
+ updateHoverFromPointer() {
495
+ const e = this.pick();
496
+ this.setHover(e);
497
+ }
498
+ setHover(e) {
499
+ const t = e?.type !== this.hoverTarget?.type || e?.id !== this.hoverTarget?.id;
500
+ this.hoverTarget = e, t && (this.atomsDirty = !0, this.renderer.domElement.style.cursor = e ? "pointer" : this.interacting ? "grabbing" : "grab"), e && this.pointer ? this.options.onHover({
501
+ target: e,
502
+ x: this.pointer.x,
503
+ y: this.pointer.y,
504
+ viewportWidth: this.size.width,
505
+ viewportHeight: this.size.height
506
+ }) : t && this.options.onHover(null);
507
+ }
508
+ }
509
+ function Ze(u) {
510
+ try {
511
+ return new _e(u);
512
+ } catch {
513
+ return null;
514
+ }
515
+ }
516
+ export {
517
+ _e as StereoEngine,
518
+ Ze as createStereoEngine
519
+ };
@@ -0,0 +1,64 @@
1
+ import { StereoScatterView } from '../stereo-scatter.types';
2
+ export interface Vec3 {
3
+ x: number;
4
+ y: number;
5
+ z: number;
6
+ }
7
+ export interface ScreenPoint {
8
+ x: number;
9
+ y: number;
10
+ }
11
+ export interface NiceDomain {
12
+ min: number;
13
+ max: number;
14
+ ticks: number[];
15
+ }
16
+ export type WedgeStyle = "solid" | "hashed" | "plain";
17
+ /** Orbit around the scene target. Azimuth 0 looks down −Z with +X right and +Y up. */
18
+ export interface StereoOrbit {
19
+ azimuth: number;
20
+ elevation: number;
21
+ }
22
+ export declare const STEREO_ELEVATION_LIMIT: number;
23
+ export declare const STEREO_WEDGE_THRESHOLD = 0.06;
24
+ export declare const STEREO_VIEW_PRESETS: Record<StereoScatterView, StereoOrbit>;
25
+ export declare function clamp(value: number, min: number, max: number): number;
26
+ export declare function lerp(from: number, to: number, t: number): number;
27
+ export declare function easeOutCubic(t: number): number;
28
+ export declare function easeInOutCubic(t: number): number;
29
+ /** Shortest signed angular distance so camera tweens never spin the long way round. */
30
+ export declare function shortestAngle(from: number, to: number): number;
31
+ /** Camera offset from the target for an orbit at `distance`. */
32
+ export declare function orbitOffset(orbit: StereoOrbit, distance: number): Vec3;
33
+ /** Rounded axis domain with evenly spaced ticks covering every value. */
34
+ export declare function niceDomain(values: readonly number[], targetCount?: number): NiceDomain;
35
+ /** Maps a value into the `[-1, 1]` scene cube. */
36
+ export declare function normalizeToCube(value: number, domain: NiceDomain): number;
37
+ /**
38
+ * Natta projection rule: a substituent closer to the viewer than its stereocentre
39
+ * is a solid wedge, farther is a hashed wedge, level is a plain bond.
40
+ */
41
+ export declare function wedgeStyleForDepth(depthDelta: number, threshold?: number): WedgeStyle;
42
+ /** 0 for an in-plane bond, 1 once the bond leaves the page by half the scene radius. */
43
+ export declare function wedgeStrength(depthDelta: number): number;
44
+ /** 2D solid wedge for SVG glyphs: narrow at the stereocentre, wide at the substituent. */
45
+ export declare function solidWedgePath(from: ScreenPoint, to: ScreenPoint, halfWidth: number): string;
46
+ /** 2D hashed wedge for SVG glyphs: perpendicular rungs that widen toward the substituent. */
47
+ export declare function hashedWedgePath(from: ScreenPoint, to: ScreenPoint, halfWidth: number, spacing?: number): string;
48
+ export declare function linePath(from: ScreenPoint, to: ScreenPoint): string;
49
+ export interface LabelCandidate {
50
+ id: string;
51
+ x: number;
52
+ y: number;
53
+ width: number;
54
+ height: number;
55
+ priority: number;
56
+ }
57
+ /** Greedy label placement: highest priority wins, overlapping or clipped labels are dropped. */
58
+ export declare function placeLabels(candidates: readonly LabelCandidate[], bounds: {
59
+ width: number;
60
+ height: number;
61
+ }, padding?: number): Set<string>;
62
+ /** Rough text width for 11px UI type; good enough for collision tests. */
63
+ export declare function estimateLabelWidth(text: string, fontSize?: number): number;
64
+ export declare function formatCompactNumber(value: number): string;