@casualoffice/sheets 0.13.0 → 0.14.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/chrome.cjs +1568 -283
- package/dist/chrome.cjs.map +1 -1
- package/dist/chrome.d.cts +35 -2
- package/dist/chrome.d.ts +35 -2
- package/dist/chrome.js +1566 -291
- package/dist/chrome.js.map +1 -1
- package/dist/embed/embed-runtime.js +131 -131
- package/dist/embed.cjs +3 -3
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.js +3 -3
- package/dist/embed.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/chrome/MenuBar.tsx +1246 -104
- package/src/chrome/Toolbar.tsx +546 -216
- package/src/embed/EmbedTransport.ts +3 -3
- package/src/embed-runtime/index.tsx +56 -8
|
@@ -235,13 +235,13 @@ export class EmbedTransport {
|
|
|
235
235
|
await this.handlers.onHostHello?.(env.data as HostHelloData);
|
|
236
236
|
this.sendReady();
|
|
237
237
|
return;
|
|
238
|
-
case 'casual.command.
|
|
238
|
+
case 'casual.command.set.readonly':
|
|
239
239
|
await this.handlers.onCommandSetReadOnly?.(env.data as CommandSetReadOnlyData);
|
|
240
240
|
return;
|
|
241
|
-
case 'casual.command.
|
|
241
|
+
case 'casual.command.set.theme':
|
|
242
242
|
await this.handlers.onCommandSetTheme?.(env.data as CommandSetThemeData);
|
|
243
243
|
return;
|
|
244
|
-
case 'casual.command.
|
|
244
|
+
case 'casual.command.set.locale':
|
|
245
245
|
await this.handlers.onCommandSetLocale?.(env.data as CommandSetLocaleData);
|
|
246
246
|
return;
|
|
247
247
|
case 'casual.command.set.viewmode':
|
|
@@ -32,6 +32,7 @@ interface EmbedUrlConfig {
|
|
|
32
32
|
app: CasualApp;
|
|
33
33
|
docId: string;
|
|
34
34
|
viewMode: 'preview' | 'editor';
|
|
35
|
+
theme: 'light' | 'dark' | 'system';
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
function parseUrlConfig(search: string): EmbedUrlConfig {
|
|
@@ -40,7 +41,22 @@ function parseUrlConfig(search: string): EmbedUrlConfig {
|
|
|
40
41
|
const docId = params.get('docId') ?? '';
|
|
41
42
|
const viewModeParam = params.get('viewMode');
|
|
42
43
|
const viewMode: 'preview' | 'editor' = viewModeParam === 'editor' ? 'editor' : 'preview';
|
|
43
|
-
|
|
44
|
+
// The host passes its theme so the embedded editor matches light/dark.
|
|
45
|
+
// Default `system` follows the OS/host colour-scheme; the host can also
|
|
46
|
+
// push live changes over `casual.command.set.theme`.
|
|
47
|
+
const themeParam = params.get('theme');
|
|
48
|
+
const theme: 'light' | 'dark' | 'system' =
|
|
49
|
+
themeParam === 'dark' ? 'dark' : themeParam === 'light' ? 'light' : 'system';
|
|
50
|
+
return { app, docId, viewMode, theme };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Resolve `system` against the iframe's media query; `light`/`dark` pass through. */
|
|
54
|
+
function resolveAppearance(theme: 'light' | 'dark' | 'system'): 'light' | 'dark' {
|
|
55
|
+
if (theme === 'light' || theme === 'dark') return theme;
|
|
56
|
+
if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
|
|
57
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
58
|
+
}
|
|
59
|
+
return 'light';
|
|
44
60
|
}
|
|
45
61
|
|
|
46
62
|
export interface MountEmbeddedOptions {
|
|
@@ -112,7 +128,12 @@ export function mountEmbedded(opts: MountEmbeddedOptions): void {
|
|
|
112
128
|
|
|
113
129
|
const reactRoot = createRoot(opts.root);
|
|
114
130
|
reactRoot.render(
|
|
115
|
-
<EmbeddedSheets
|
|
131
|
+
<EmbeddedSheets
|
|
132
|
+
transport={transport}
|
|
133
|
+
docId={config.docId}
|
|
134
|
+
initialViewMode={config.viewMode}
|
|
135
|
+
initialTheme={config.theme}
|
|
136
|
+
/>,
|
|
116
137
|
);
|
|
117
138
|
}
|
|
118
139
|
|
|
@@ -123,14 +144,34 @@ function EmbeddedSheets({
|
|
|
123
144
|
transport,
|
|
124
145
|
docId,
|
|
125
146
|
initialViewMode,
|
|
147
|
+
initialTheme,
|
|
126
148
|
}: {
|
|
127
149
|
transport: EmbedTransport;
|
|
128
150
|
docId: string;
|
|
129
151
|
initialViewMode: 'preview' | 'editor';
|
|
152
|
+
initialTheme: 'light' | 'dark' | 'system';
|
|
130
153
|
}) {
|
|
131
154
|
const [data, setData] = useState<IWorkbookData | null>(null);
|
|
132
155
|
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
|
133
156
|
|
|
157
|
+
// Theme: track the host's choice (light/dark/system) and resolve `system`
|
|
158
|
+
// live against the iframe's prefers-color-scheme. The host pushes changes
|
|
159
|
+
// over `casual.command.set.theme`; passed to <CasualSheets appearance>,
|
|
160
|
+
// which flips Univer's `univer-dark` class + ThemeService so the canvas,
|
|
161
|
+
// headers, gridlines and chrome all match.
|
|
162
|
+
const [theme, setTheme] = useState<'light' | 'dark' | 'system'>(initialTheme);
|
|
163
|
+
const [appearance, setAppearance] = useState<'light' | 'dark'>(() =>
|
|
164
|
+
resolveAppearance(initialTheme),
|
|
165
|
+
);
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
setAppearance(resolveAppearance(theme));
|
|
168
|
+
if (theme !== 'system' || typeof window === 'undefined' || !window.matchMedia) return;
|
|
169
|
+
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
|
170
|
+
const onChange = () => setAppearance(mq.matches ? 'dark' : 'light');
|
|
171
|
+
mq.addEventListener('change', onChange);
|
|
172
|
+
return () => mq.removeEventListener('change', onChange);
|
|
173
|
+
}, [theme]);
|
|
174
|
+
|
|
134
175
|
const [viewMode, setViewMode] = useState<'preview' | 'editor'>(initialViewMode);
|
|
135
176
|
// Editor mode renders the SDK's OWN React chrome (`chrome="full"`): the
|
|
136
177
|
// menu bar (Edit/Insert/Format/Data/View), the rich formatting toolbar,
|
|
@@ -149,6 +190,7 @@ function EmbeddedSheets({
|
|
|
149
190
|
|
|
150
191
|
useEffect(() => {
|
|
151
192
|
transport.on({
|
|
193
|
+
onCommandSetTheme: ({ theme: next }) => setTheme(next),
|
|
152
194
|
onCommandSetViewMode: ({ viewMode: next }) => setViewMode(next),
|
|
153
195
|
});
|
|
154
196
|
}, [transport]);
|
|
@@ -227,6 +269,7 @@ function EmbeddedSheets({
|
|
|
227
269
|
key={viewMode}
|
|
228
270
|
initialData={data}
|
|
229
271
|
chrome={chrome}
|
|
272
|
+
appearance={appearance}
|
|
230
273
|
ui={ui}
|
|
231
274
|
// Seed the en-US string bundle. Without `locales`, Univer's
|
|
232
275
|
// LocaleService throws "Locale not initialized" and the workbench
|
|
@@ -235,12 +278,17 @@ function EmbeddedSheets({
|
|
|
235
278
|
// this from the host's `locales` prop; the iframe has no host to
|
|
236
279
|
// pass one, so the self-contained runtime bundles a minimal set.
|
|
237
280
|
locales={EMBED_LOCALES}
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
|
|
281
|
+
// Enable the FULL feature set (tables, sort, filter, conditional
|
|
282
|
+
// formatting, data validation, drawing, hyperlinks, notes, comments,
|
|
283
|
+
// find/replace) so the embed matches the real app. The tsup embed
|
|
284
|
+
// config is `splitting: false` + `noExternal: /.*/`, so the lazy
|
|
285
|
+
// loader's dynamic `import()`s are INLINED into the single
|
|
286
|
+
// embed-runtime.js rather than emitted as separate chunks — the
|
|
287
|
+
// single-file deployment is preserved. With lazyPlugins on, the loader
|
|
288
|
+
// also eager-loads any feature whose data is already in the snapshot
|
|
289
|
+
// (so opening a file with tables/CF never silently drops it) and
|
|
290
|
+
// idle-loads the rest, so the toolbar/menu feature actions resolve.
|
|
291
|
+
lazyPlugins={true}
|
|
244
292
|
// Phase 2 save/exit contract — the iframe surface of the same
|
|
245
293
|
// `onSave` / `onExit` hooks the React component exposes. The editor
|
|
246
294
|
// never persists; it hands the snapshot to the host over postMessage
|