@dtour/viewer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Dtour.d.ts +46 -0
- package/dist/Dtour.d.ts.map +1 -0
- package/dist/DtourViewer.d.ts +24 -0
- package/dist/DtourViewer.d.ts.map +1 -0
- package/dist/components/AxisOverlay.d.ts +9 -0
- package/dist/components/AxisOverlay.d.ts.map +1 -0
- package/dist/components/CircularSlider.d.ts +16 -0
- package/dist/components/CircularSlider.d.ts.map +1 -0
- package/dist/components/ColorLegend.d.ts +2 -0
- package/dist/components/ColorLegend.d.ts.map +1 -0
- package/dist/components/DtourToolbar.d.ts +5 -0
- package/dist/components/DtourToolbar.d.ts.map +1 -0
- package/dist/components/Gallery.d.ts +12 -0
- package/dist/components/Gallery.d.ts.map +1 -0
- package/dist/components/LassoOverlay.d.ts +9 -0
- package/dist/components/LassoOverlay.d.ts.map +1 -0
- package/dist/components/Logo.d.ts +2 -0
- package/dist/components/Logo.d.ts.map +1 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +10 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/slider.d.ts +6 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/tooltip.d.ts +8 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/hooks/useAnimatePosition.d.ts +13 -0
- package/dist/hooks/useAnimatePosition.d.ts.map +1 -0
- package/dist/hooks/useGrandTour.d.ts +14 -0
- package/dist/hooks/useGrandTour.d.ts.map +1 -0
- package/dist/hooks/useLongPressIndicator.d.ts +5 -0
- package/dist/hooks/useLongPressIndicator.d.ts.map +1 -0
- package/dist/hooks/useModeCycling.d.ts +12 -0
- package/dist/hooks/useModeCycling.d.ts.map +1 -0
- package/dist/hooks/usePlayback.d.ts +9 -0
- package/dist/hooks/usePlayback.d.ts.map +1 -0
- package/dist/hooks/useScatter.d.ts +10 -0
- package/dist/hooks/useScatter.d.ts.map +1 -0
- package/dist/hooks/useSystemTheme.d.ts +6 -0
- package/dist/hooks/useSystemTheme.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/layout/gallery-positions.d.ts +38 -0
- package/dist/layout/gallery-positions.d.ts.map +1 -0
- package/dist/layout/selector-size.d.ts +15 -0
- package/dist/layout/selector-size.d.ts.map +1 -0
- package/dist/lib/color-utils.d.ts +7 -0
- package/dist/lib/color-utils.d.ts.map +1 -0
- package/dist/lib/gram-schmidt.d.ts +9 -0
- package/dist/lib/gram-schmidt.d.ts.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/portal-container.d.ts +10 -0
- package/dist/portal-container.d.ts.map +1 -0
- package/dist/radial-chart/RadialChart.d.ts +13 -0
- package/dist/radial-chart/RadialChart.d.ts.map +1 -0
- package/dist/radial-chart/arc-path.d.ts +23 -0
- package/dist/radial-chart/arc-path.d.ts.map +1 -0
- package/dist/radial-chart/index.d.ts +5 -0
- package/dist/radial-chart/index.d.ts.map +1 -0
- package/dist/radial-chart/parse-metrics.d.ts +10 -0
- package/dist/radial-chart/parse-metrics.d.ts.map +1 -0
- package/dist/radial-chart/types.d.ts +23 -0
- package/dist/radial-chart/types.d.ts.map +1 -0
- package/dist/spec.d.ts +42 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/state/atoms.d.ts +150 -0
- package/dist/state/atoms.d.ts.map +1 -0
- package/dist/state/spec-sync.d.ts +5 -0
- package/dist/state/spec-sync.d.ts.map +1 -0
- package/dist/viewer.css +3 -0
- package/dist/viewer.js +14501 -0
- package/dist/views.d.ts +30 -0
- package/dist/views.d.ts.map +1 -0
- package/package.json +48 -0
- package/src/Dtour.tsx +300 -0
- package/src/DtourViewer.tsx +541 -0
- package/src/components/AxisOverlay.tsx +224 -0
- package/src/components/CircularSlider.tsx +202 -0
- package/src/components/ColorLegend.tsx +178 -0
- package/src/components/DtourToolbar.tsx +642 -0
- package/src/components/Gallery.tsx +166 -0
- package/src/components/LassoOverlay.tsx +240 -0
- package/src/components/Logo.tsx +37 -0
- package/src/components/ui/button.tsx +36 -0
- package/src/components/ui/dropdown-menu.tsx +92 -0
- package/src/components/ui/slider.tsx +89 -0
- package/src/components/ui/tooltip.tsx +45 -0
- package/src/hooks/useAnimatePosition.ts +102 -0
- package/src/hooks/useGrandTour.ts +176 -0
- package/src/hooks/useLongPressIndicator.ts +342 -0
- package/src/hooks/useModeCycling.ts +64 -0
- package/src/hooks/usePlayback.ts +54 -0
- package/src/hooks/useScatter.ts +162 -0
- package/src/hooks/useSystemTheme.ts +19 -0
- package/src/index.ts +55 -0
- package/src/layout/gallery-positions.ts +105 -0
- package/src/layout/selector-size.ts +135 -0
- package/src/lib/color-utils.ts +22 -0
- package/src/lib/gram-schmidt.ts +41 -0
- package/src/lib/utils.ts +4 -0
- package/src/portal-container.tsx +14 -0
- package/src/radial-chart/RadialChart.tsx +184 -0
- package/src/radial-chart/arc-path.ts +80 -0
- package/src/radial-chart/index.ts +4 -0
- package/src/radial-chart/parse-metrics.ts +99 -0
- package/src/radial-chart/types.ts +23 -0
- package/src/spec.ts +48 -0
- package/src/state/atoms.ts +169 -0
- package/src/state/spec-sync.ts +190 -0
- package/src/styles.css +44 -0
- package/src/views.ts +76 -0
- package/tsconfig.json +12 -0
- package/vite.config.ts +21 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { WritableAtom } from 'jotai';
|
|
2
|
+
import { useStore } from 'jotai';
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import type { DtourSpec } from '../spec.ts';
|
|
5
|
+
import {
|
|
6
|
+
cameraPanXAtom,
|
|
7
|
+
cameraPanYAtom,
|
|
8
|
+
cameraZoomAtom,
|
|
9
|
+
pointColorAtom,
|
|
10
|
+
pointOpacityAtom,
|
|
11
|
+
pointSizeAtom,
|
|
12
|
+
previewCountAtom,
|
|
13
|
+
previewPaddingAtom,
|
|
14
|
+
previewScaleAtom,
|
|
15
|
+
showLegendAtom,
|
|
16
|
+
themeModeAtom,
|
|
17
|
+
tourByAtom,
|
|
18
|
+
tourDirectionAtom,
|
|
19
|
+
tourPlayingAtom,
|
|
20
|
+
tourPositionAtom,
|
|
21
|
+
tourSpeedAtom,
|
|
22
|
+
viewModeAtom,
|
|
23
|
+
} from './atoms.ts';
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Spec ↔ Atom mapping
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
type SpecEntry<S, A> = {
|
|
30
|
+
atom: WritableAtom<A, [A], void>;
|
|
31
|
+
toAtom: (v: S) => A;
|
|
32
|
+
fromAtom: (v: A) => S;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function identity<T>(v: T): T {
|
|
36
|
+
return v;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function entry<T>(atom: WritableAtom<T, [T], void>): SpecEntry<T, T> {
|
|
40
|
+
return { atom, toAtom: identity, fromAtom: identity };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const SPEC_ATOM_MAP = {
|
|
44
|
+
tourBy: entry(tourByAtom),
|
|
45
|
+
tourPosition: entry(tourPositionAtom),
|
|
46
|
+
tourPlaying: entry(tourPlayingAtom),
|
|
47
|
+
tourSpeed: entry(tourSpeedAtom),
|
|
48
|
+
tourDirection: {
|
|
49
|
+
atom: tourDirectionAtom,
|
|
50
|
+
toAtom: (v: 'forward' | 'backward') => (v === 'forward' ? 1 : -1) as 1 | -1,
|
|
51
|
+
fromAtom: (v: 1 | -1): 'forward' | 'backward' => (v === 1 ? 'forward' : 'backward'),
|
|
52
|
+
},
|
|
53
|
+
previewCount: entry(previewCountAtom),
|
|
54
|
+
previewScale: entry(previewScaleAtom),
|
|
55
|
+
previewPadding: entry(previewPaddingAtom),
|
|
56
|
+
pointSize: entry(pointSizeAtom),
|
|
57
|
+
pointOpacity: entry(pointOpacityAtom),
|
|
58
|
+
pointColor: entry(pointColorAtom),
|
|
59
|
+
cameraPanX: entry(cameraPanXAtom),
|
|
60
|
+
cameraPanY: entry(cameraPanYAtom),
|
|
61
|
+
cameraZoom: entry(cameraZoomAtom),
|
|
62
|
+
viewMode: entry(viewModeAtom),
|
|
63
|
+
showLegend: entry(showLegendAtom),
|
|
64
|
+
themeMode: entry(themeModeAtom),
|
|
65
|
+
} as const;
|
|
66
|
+
|
|
67
|
+
type SpecKey = keyof typeof SPEC_ATOM_MAP;
|
|
68
|
+
const SPEC_KEYS = Object.keys(SPEC_ATOM_MAP) as SpecKey[];
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Helpers
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
function shallowEqual(a: unknown, b: unknown): boolean {
|
|
75
|
+
if (a === b) return true;
|
|
76
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
77
|
+
if (a.length !== b.length) return false;
|
|
78
|
+
for (let i = 0; i < a.length; i++) {
|
|
79
|
+
if (a[i] !== b[i]) return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Read all atoms from the store and build a full resolved spec. */
|
|
87
|
+
function readFullSpec(store: ReturnType<typeof useStore>): Required<DtourSpec> {
|
|
88
|
+
const spec = {} as Record<string, unknown>;
|
|
89
|
+
for (const key of SPEC_KEYS) {
|
|
90
|
+
const mapping = SPEC_ATOM_MAP[key];
|
|
91
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic atom mapping
|
|
92
|
+
const raw = store.get(mapping.atom as any);
|
|
93
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic transform
|
|
94
|
+
spec[key] = (mapping as any).fromAtom(raw);
|
|
95
|
+
}
|
|
96
|
+
return spec as Required<DtourSpec>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Hook: initialize store from spec (called once before first render)
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
export function initStoreFromSpec(
|
|
104
|
+
store: ReturnType<typeof useStore>,
|
|
105
|
+
spec: DtourSpec | undefined,
|
|
106
|
+
): void {
|
|
107
|
+
if (!spec) return;
|
|
108
|
+
for (const key of SPEC_KEYS) {
|
|
109
|
+
const value = spec[key];
|
|
110
|
+
if (value !== undefined) {
|
|
111
|
+
const mapping = SPEC_ATOM_MAP[key];
|
|
112
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic atom mapping
|
|
113
|
+
store.set(mapping.atom as any, (mapping as any).toAtom(value));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Hook: bidirectional spec ↔ atoms sync
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
const DEBOUNCE_MS = 250;
|
|
123
|
+
|
|
124
|
+
export function useSpecSync(
|
|
125
|
+
spec: DtourSpec | undefined,
|
|
126
|
+
onSpecChange: ((spec: Required<DtourSpec>) => void) | undefined,
|
|
127
|
+
): void {
|
|
128
|
+
const store = useStore();
|
|
129
|
+
const suppressRef = useRef(false);
|
|
130
|
+
const onSpecChangeRef = useRef(onSpecChange);
|
|
131
|
+
onSpecChangeRef.current = onSpecChange;
|
|
132
|
+
|
|
133
|
+
// Inbound: spec prop → atoms
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (!spec) return;
|
|
136
|
+
suppressRef.current = true;
|
|
137
|
+
|
|
138
|
+
for (const key of SPEC_KEYS) {
|
|
139
|
+
const value = spec[key];
|
|
140
|
+
if (value === undefined) continue;
|
|
141
|
+
const mapping = SPEC_ATOM_MAP[key];
|
|
142
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic atom mapping
|
|
143
|
+
const atomValue = (mapping as any).toAtom(value);
|
|
144
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic atom mapping
|
|
145
|
+
const current = store.get(mapping.atom as any);
|
|
146
|
+
if (!shallowEqual(atomValue, current)) {
|
|
147
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic atom mapping
|
|
148
|
+
store.set(mapping.atom as any, atomValue);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
queueMicrotask(() => {
|
|
153
|
+
suppressRef.current = false;
|
|
154
|
+
});
|
|
155
|
+
}, [spec, store]);
|
|
156
|
+
|
|
157
|
+
// Outbound: atoms → onSpecChange (debounced)
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
if (!onSpecChangeRef.current) return;
|
|
160
|
+
|
|
161
|
+
let dirty = false;
|
|
162
|
+
let timerId: ReturnType<typeof setTimeout> | null = null;
|
|
163
|
+
|
|
164
|
+
const flush = () => {
|
|
165
|
+
timerId = null;
|
|
166
|
+
if (suppressRef.current || !dirty) return;
|
|
167
|
+
dirty = false;
|
|
168
|
+
onSpecChangeRef.current?.(readFullSpec(store));
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const scheduleFlush = () => {
|
|
172
|
+
dirty = true;
|
|
173
|
+
if (timerId === null) {
|
|
174
|
+
timerId = setTimeout(flush, DEBOUNCE_MS);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const unsubs: (() => void)[] = [];
|
|
179
|
+
for (const key of SPEC_KEYS) {
|
|
180
|
+
const mapping = SPEC_ATOM_MAP[key];
|
|
181
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic atom mapping
|
|
182
|
+
unsubs.push(store.sub(mapping.atom as any, scheduleFlush));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return () => {
|
|
186
|
+
for (const unsub of unsubs) unsub();
|
|
187
|
+
if (timerId !== null) clearTimeout(timerId);
|
|
188
|
+
};
|
|
189
|
+
}, [store]);
|
|
190
|
+
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
@import "tailwindcss/theme";
|
|
2
|
+
@import "tailwindcss/utilities";
|
|
3
|
+
@import "tw-animate-css";
|
|
4
|
+
|
|
5
|
+
@theme {
|
|
6
|
+
--color-dtour-bg: #000000;
|
|
7
|
+
--color-dtour-surface: #222222;
|
|
8
|
+
--color-dtour-border: #333333;
|
|
9
|
+
--color-dtour-text: #bbbbbb;
|
|
10
|
+
--color-dtour-text-muted: #888888;
|
|
11
|
+
--color-dtour-accent: #4080e8;
|
|
12
|
+
--color-dtour-accent-hover: #5090f0;
|
|
13
|
+
--color-dtour-highlight: #ffffff;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* --- Light theme overrides --- */
|
|
17
|
+
|
|
18
|
+
:where(.dtour-light) {
|
|
19
|
+
--color-dtour-bg: #ffffff;
|
|
20
|
+
--color-dtour-surface: #f0f0f0;
|
|
21
|
+
--color-dtour-border: #d0d0d0;
|
|
22
|
+
--color-dtour-text: #333333;
|
|
23
|
+
--color-dtour-text-muted: #777777;
|
|
24
|
+
--color-dtour-accent: #2060c0;
|
|
25
|
+
--color-dtour-accent-hover: #1850a8;
|
|
26
|
+
--color-dtour-highlight: #000000;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* --- Animation easing utility for tw-animate-css --- */
|
|
30
|
+
|
|
31
|
+
@utility animate-ease-out {
|
|
32
|
+
animation-timing-function: ease-out;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@media (prefers-reduced-motion: reduce) {
|
|
36
|
+
*,
|
|
37
|
+
*::before,
|
|
38
|
+
*::after {
|
|
39
|
+
animation-duration: 0.01ms;
|
|
40
|
+
animation-delay: 0ms;
|
|
41
|
+
animation-iteration-count: 1;
|
|
42
|
+
transition-duration: 0.01ms;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/views.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create default "little tour" view matrices that cycle through consecutive
|
|
3
|
+
* dimension pairs: (d0,d1), (d1,d2), ..., wrapping back to the start.
|
|
4
|
+
*
|
|
5
|
+
* Each view is a p×2 column-major Float32Array:
|
|
6
|
+
* [x0, x1, ..., xp-1, y0, y1, ..., yp-1]
|
|
7
|
+
*
|
|
8
|
+
* When `activeIndices` is provided, only those dimensions get non-zero
|
|
9
|
+
* basis weights — inactive dimensions contribute zero to the projection.
|
|
10
|
+
*
|
|
11
|
+
* @param dims - total number of dimensions (p)
|
|
12
|
+
* @param count - number of views to generate (defaults to active dim count)
|
|
13
|
+
* @param activeIndices - sorted array of active dimension indices (defaults to all)
|
|
14
|
+
* @returns array of view matrices
|
|
15
|
+
*/
|
|
16
|
+
export const createDefaultViews = (
|
|
17
|
+
dims: number,
|
|
18
|
+
count?: number,
|
|
19
|
+
activeIndices?: number[],
|
|
20
|
+
): Float32Array[] => {
|
|
21
|
+
const indices = activeIndices ?? Array.from({ length: dims }, (_, i) => i);
|
|
22
|
+
const activeDims = indices.length;
|
|
23
|
+
const n = count ?? activeDims;
|
|
24
|
+
const views: Float32Array[] = [];
|
|
25
|
+
for (let i = 0; i < n; i++) {
|
|
26
|
+
const basis = new Float32Array(dims * 2);
|
|
27
|
+
const idx = Math.floor((i / n) * activeDims);
|
|
28
|
+
basis[indices[idx]!] = 1; // active dim → x
|
|
29
|
+
basis[dims + indices[(idx + 1) % activeDims]!] = 1; // next active dim → y
|
|
30
|
+
views.push(basis);
|
|
31
|
+
}
|
|
32
|
+
return views;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create tour views from PCA eigenvectors.
|
|
37
|
+
* Cycles through consecutive PC pairs: [PC1,PC2], [PC2,PC3], ..., wrapping.
|
|
38
|
+
*
|
|
39
|
+
* Each eigenvector becomes a column of the p×2 basis matrix. Eigenvectors
|
|
40
|
+
* are assumed to be in the normalized space matching the projection shader.
|
|
41
|
+
*
|
|
42
|
+
* @param eigenvectors - sorted by descending eigenvalue, each of length pcaDims
|
|
43
|
+
* @param totalDims - total number of dimensions in the dataset (p)
|
|
44
|
+
* @param pcaDims - number of PCA dimensions (may be < totalDims if capped)
|
|
45
|
+
* @param count - number of views to generate (defaults to number of PCs)
|
|
46
|
+
*/
|
|
47
|
+
export const createPCAViews = (
|
|
48
|
+
eigenvectors: Float32Array[],
|
|
49
|
+
totalDims: number,
|
|
50
|
+
pcaDims: number,
|
|
51
|
+
count?: number,
|
|
52
|
+
): Float32Array[] => {
|
|
53
|
+
const numPCs = eigenvectors.length;
|
|
54
|
+
const n = count ?? numPCs;
|
|
55
|
+
const views: Float32Array[] = [];
|
|
56
|
+
|
|
57
|
+
for (let i = 0; i < n; i++) {
|
|
58
|
+
const basis = new Float32Array(totalDims * 2);
|
|
59
|
+
const pcX = i % numPCs;
|
|
60
|
+
const pcY = (i + 1) % numPCs;
|
|
61
|
+
|
|
62
|
+
const evX = eigenvectors[pcX]!;
|
|
63
|
+
for (let d = 0; d < pcaDims; d++) {
|
|
64
|
+
basis[d] = evX[d]!;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const evY = eigenvectors[pcY]!;
|
|
68
|
+
for (let d = 0; d < pcaDims; d++) {
|
|
69
|
+
basis[totalDims + d] = evY[d]!;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
views.push(basis);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return views;
|
|
76
|
+
};
|
package/tsconfig.json
ADDED
package/vite.config.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
3
|
+
import react from '@vitejs/plugin-react';
|
|
4
|
+
import { defineConfig } from 'vite';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [tailwindcss(), react()],
|
|
8
|
+
build: {
|
|
9
|
+
lib: {
|
|
10
|
+
entry: resolve(__dirname, 'src/index.ts'),
|
|
11
|
+
name: 'DtourViewer',
|
|
12
|
+
fileName: 'viewer',
|
|
13
|
+
formats: ['es'],
|
|
14
|
+
cssFileName: 'viewer',
|
|
15
|
+
},
|
|
16
|
+
rolldownOptions: {
|
|
17
|
+
// Peer dependencies — consumers provide these
|
|
18
|
+
external: ['react', 'react-dom', 'react/jsx-runtime', 'jotai'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|