rita-workspace 0.3.0 β†’ 0.3.2

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 CHANGED
@@ -8,6 +8,7 @@ Multi-drawing workspace feature for Rita (Excalidraw fork based on B310-digital/
8
8
  - **Menu integration** - Seamlessly integrates with Excalidraw's hamburger menu
9
9
  - **Auto-save** - All drawings saved locally in IndexedDB
10
10
  - **Rename & delete** - Full drawing management via dialog
11
+ - **i18n support** - Swedish and English with automatic Excalidraw language sync
11
12
 
12
13
  ## Installation
13
14
 
@@ -29,17 +30,34 @@ Two files need to be modified in the B310/Excalidraw fork:
29
30
  import { WorkspaceProvider } from "rita-workspace";
30
31
  ```
31
32
 
32
- **Wrap with WorkspaceProvider** (in the `ExcalidrawApp` component):
33
+ **Wrap with WorkspaceProvider** (in the `ExcalidrawWrapper` component to access `langCode`):
34
+
35
+ ```tsx
36
+ const ExcalidrawWrapper = () => {
37
+ const [langCode] = useAppLangCode(); // Excalidraw's language hook
38
+
39
+ // ... existing code ...
40
+
41
+ return (
42
+ <WorkspaceProvider lang={langCode}> {/* <-- Pass langCode here */}
43
+ <div style={{ height: "100%" }}>
44
+ <Excalidraw ... />
45
+ </div>
46
+ </WorkspaceProvider>
47
+ );
48
+ };
49
+ ```
50
+
51
+ Or if you prefer wrapping at the app level:
33
52
 
34
53
  ```tsx
35
54
  const ExcalidrawApp = () => {
36
- // ...
37
55
  return (
38
56
  <TopErrorBoundary>
39
57
  <Provider store={appJotaiStore}>
40
- <WorkspaceProvider> {/* <-- Add this */}
58
+ <WorkspaceProvider lang="sv"> {/* <-- Or hardcode language */}
41
59
  <ExcalidrawWrapper />
42
- </WorkspaceProvider> {/* <-- And this */}
60
+ </WorkspaceProvider>
43
61
  </Provider>
44
62
  </TopErrorBoundary>
45
63
  );
@@ -61,15 +79,15 @@ import { WorkspaceMenuItems, DrawingsDialog } from "rita-workspace";
61
79
 
62
80
  ```tsx
63
81
  export const AppMainMenu: React.FC<{...}> = React.memo((props) => {
64
- const [showDrawingsDialog, setShowDrawingsDialog] = useState(false); // Add this
82
+ const [showDrawingsDialog, setShowDrawingsDialog] = useState(false);
65
83
 
66
84
  return (
67
- <> {/* Add fragment */}
85
+ <>
68
86
  <MainMenu>
69
87
  <MainMenu.DefaultItems.LoadScene />
70
88
  <MainMenu.DefaultItems.SaveToActiveFile />
71
89
 
72
- {/* === RITA WORKSPACE: Add this block === */}
90
+ {/* === RITA WORKSPACE === */}
73
91
  <MainMenu.Sub>
74
92
  <MainMenu.Sub.Trigger>πŸ“„ Ritningar</MainMenu.Sub.Trigger>
75
93
  <MainMenu.Sub.Content>
@@ -78,25 +96,59 @@ export const AppMainMenu: React.FC<{...}> = React.memo((props) => {
78
96
  />
79
97
  </MainMenu.Sub.Content>
80
98
  </MainMenu.Sub>
81
- {/* === END RITA WORKSPACE === */}
82
99
 
83
100
  <MainMenu.DefaultItems.Export />
84
101
  {/* ... rest of menu items ... */}
85
102
  </MainMenu>
86
103
 
87
- {/* === RITA WORKSPACE: Add dialog === */}
88
104
  <DrawingsDialog
89
105
  open={showDrawingsDialog}
90
106
  onClose={() => setShowDrawingsDialog(false)}
91
107
  />
92
- </> {/* Close fragment */}
108
+ </>
93
109
  );
94
110
  });
95
111
  ```
96
112
 
113
+ ## Language Support (i18n)
114
+
115
+ Rita Workspace supports **Swedish** and **English**, with automatic sync to Excalidraw's language setting.
116
+
117
+ ### Automatic Language Sync
118
+
119
+ Pass Excalidraw's `langCode` to `WorkspaceProvider` - all child components inherit the language automatically:
120
+
121
+ ```tsx
122
+ const [langCode] = useAppLangCode(); // From Excalidraw
123
+
124
+ <WorkspaceProvider lang={langCode}>
125
+ {/* All components automatically use the same language */}
126
+ <WorkspaceMenuItems ... />
127
+ <DrawingsDialog ... />
128
+ </WorkspaceProvider>
129
+ ```
130
+
131
+ ### Manual Override
132
+
133
+ You can override the language on individual components if needed:
134
+
135
+ ```tsx
136
+ <WorkspaceProvider lang="en">
137
+ {/* This dialog will be in Swedish despite provider being English */}
138
+ <DrawingsDialog lang="sv" ... />
139
+ </WorkspaceProvider>
140
+ ```
141
+
142
+ ### Supported Languages
143
+
144
+ | Code | Language |
145
+ |------|----------|
146
+ | `sv`, `sv-SE` | πŸ‡ΈπŸ‡ͺ Swedish |
147
+ | `en`, `en-US` | πŸ‡¬πŸ‡§ English (default) |
148
+
97
149
  ## Result
98
150
 
99
- After integration, a "πŸ“„ Ritningar" submenu appears in the hamburger menu:
151
+ After integration, a "πŸ“„ Ritningar" (or "πŸ“„ Drawings") submenu appears in the hamburger menu:
100
152
 
101
153
  ```
102
154
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
@@ -119,28 +171,37 @@ After integration, a "πŸ“„ Ritningar" submenu appears in the hamburger menu:
119
171
 
120
172
  | Component | Description |
121
173
  |-----------|-------------|
122
- | `WorkspaceProvider` | React context provider - wrap your app with this |
123
- | `WorkspaceMenuItems` | Menu items for Excalidraw's MainMenu |
124
- | `DrawingsDialog` | Modal dialog for managing all drawings |
174
+ | `WorkspaceProvider` | React context provider - wrap your app with this. Accepts `lang` prop. |
175
+ | `WorkspaceMenuItems` | Menu items for Excalidraw's MainMenu. Optional `lang` prop for override. |
176
+ | `DrawingsDialog` | Modal dialog for managing all drawings. Optional `lang` prop for override. |
125
177
 
126
178
  ### Hooks
127
179
 
128
180
  | Hook | Description |
129
181
  |------|-------------|
130
- | `useWorkspace()` | Access workspace state and actions |
182
+ | `useWorkspace()` | Access workspace state, actions, and current language |
183
+ | `useWorkspaceLang()` | Get just the current language and translations |
131
184
 
132
185
  ### useWorkspace() returns
133
186
 
134
187
  ```tsx
135
188
  const {
189
+ // State
136
190
  drawings, // Drawing[] - all drawings
137
191
  activeDrawing, // Drawing | null - currently active
138
192
  isLoading, // boolean
139
- createNewDrawing, // () => Promise<Drawing>
193
+ error, // string | null
194
+
195
+ // Language
196
+ lang, // string - current language code
197
+ t, // Translations object
198
+
199
+ // Actions
200
+ createNewDrawing, // (name?: string) => Promise<Drawing>
140
201
  switchDrawing, // (id: string) => Promise<void>
141
202
  renameDrawing, // (id: string, name: string) => Promise<void>
142
203
  removeDrawing, // (id: string) => Promise<void>
143
- saveCurrentDrawing, // (elements, appState, files?) => Promise<void>
204
+ saveCurrentDrawing, // (elements, appState) => Promise<void>
144
205
  } = useWorkspace();
145
206
  ```
146
207
 
package/dist/index.d.mts CHANGED
@@ -52,12 +52,48 @@ declare function addDrawingToWorkspace(workspaceId: string, drawingId: string):
52
52
  declare function removeDrawingFromWorkspace(workspaceId: string, drawingId: string): Promise<Workspace | undefined>;
53
53
  declare function setActiveDrawing(workspaceId: string, drawingId: string): Promise<Workspace | undefined>;
54
54
 
55
+ /**
56
+ * Rita Workspace Translations
57
+ *
58
+ * Supports Swedish (sv) and English (en)
59
+ */
60
+ type SupportedLanguage = 'sv' | 'en';
61
+ interface Translations {
62
+ drawings: string;
63
+ newDrawing: string;
64
+ manageDrawings: string;
65
+ dialogTitle: string;
66
+ close: string;
67
+ open: string;
68
+ rename: string;
69
+ delete: string;
70
+ save: string;
71
+ cancel: string;
72
+ confirm: string;
73
+ noDrawingsYet: string;
74
+ clickNewToStart: string;
75
+ modified: string;
76
+ confirmDelete: string;
77
+ shortcutNewDrawing: string;
78
+ }
79
+ /**
80
+ * Get translations for a language code
81
+ * Falls back to English if language is not supported
82
+ */
83
+ declare function getTranslations(langCode?: string): Translations;
84
+ /**
85
+ * Check if a language is supported
86
+ */
87
+ declare function isLanguageSupported(langCode?: string): boolean;
88
+
55
89
  interface WorkspaceContextValue {
56
90
  workspace: Workspace | null;
57
91
  drawings: Drawing[];
58
92
  activeDrawing: Drawing | null;
59
93
  isLoading: boolean;
60
94
  error: string | null;
95
+ lang: string;
96
+ t: Translations;
61
97
  createNewDrawing: (name?: string) => Promise<Drawing | null>;
62
98
  switchDrawing: (id: string) => Promise<void>;
63
99
  renameDrawing: (id: string, name: string) => Promise<void>;
@@ -66,10 +102,24 @@ interface WorkspaceContextValue {
66
102
  saveCurrentDrawing: (elements: unknown[], appState: Record<string, unknown>) => Promise<void>;
67
103
  }
68
104
  declare function useWorkspace(): WorkspaceContextValue;
105
+ /**
106
+ * Hook to get current language and translations
107
+ * Can be used by any component within WorkspaceProvider
108
+ */
109
+ declare function useWorkspaceLang(): {
110
+ lang: string;
111
+ t: Translations;
112
+ };
69
113
  interface WorkspaceProviderProps {
70
114
  children: ReactNode;
115
+ /**
116
+ * Language code (e.g., 'sv', 'en', 'sv-SE')
117
+ * Pass Excalidraw's langCode here to sync languages
118
+ * Falls back to English if not supported
119
+ */
120
+ lang?: string;
71
121
  }
72
- declare function WorkspaceProvider({ children }: WorkspaceProviderProps): react_jsx_runtime.JSX.Element;
122
+ declare function WorkspaceProvider({ children, lang }: WorkspaceProviderProps): react_jsx_runtime.JSX.Element;
73
123
 
74
124
  interface SidebarProps {
75
125
  isOpen?: boolean;
@@ -212,40 +262,6 @@ declare function useExcalidrawBridge({ excalidrawAPI, autoSaveInterval, }: UseEx
212
262
  scheduleSave: () => void;
213
263
  };
214
264
 
215
- /**
216
- * Rita Workspace Translations
217
- *
218
- * Supports Swedish (sv) and English (en)
219
- */
220
- type SupportedLanguage = 'sv' | 'en';
221
- interface Translations {
222
- drawings: string;
223
- newDrawing: string;
224
- manageDrawings: string;
225
- dialogTitle: string;
226
- close: string;
227
- open: string;
228
- rename: string;
229
- delete: string;
230
- save: string;
231
- cancel: string;
232
- confirm: string;
233
- noDrawingsYet: string;
234
- clickNewToStart: string;
235
- modified: string;
236
- confirmDelete: string;
237
- shortcutNewDrawing: string;
238
- }
239
- /**
240
- * Get translations for a language code
241
- * Falls back to English if language is not supported
242
- */
243
- declare function getTranslations(langCode?: string): Translations;
244
- /**
245
- * Check if a language is supported
246
- */
247
- declare function isLanguageSupported(langCode?: string): boolean;
248
-
249
265
  interface WorkspacePluginProps {
250
266
  children: ReactNode;
251
267
  defaultSidebarOpen?: boolean;
@@ -269,4 +285,4 @@ interface WorkspacePluginProps {
269
285
  */
270
286
  declare function WorkspacePlugin(props: WorkspacePluginProps): react_jsx_runtime.JSX.Element;
271
287
 
272
- export { type Drawing, DrawingList, DrawingListItem, DrawingsDialog, type DrawingsDialogProps, Sidebar, type SupportedLanguage, type Translations, type Workspace, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, deleteDrawing, duplicateDrawing, getAllDrawings, getDB, getDrawing, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isLanguageSupported, removeDrawingFromWorkspace, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace };
288
+ export { type Drawing, DrawingList, DrawingListItem, DrawingsDialog, type DrawingsDialogProps, Sidebar, type SupportedLanguage, type Translations, type Workspace, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, deleteDrawing, duplicateDrawing, getAllDrawings, getDB, getDrawing, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isLanguageSupported, removeDrawingFromWorkspace, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace, useWorkspaceLang };
package/dist/index.d.ts CHANGED
@@ -52,12 +52,48 @@ declare function addDrawingToWorkspace(workspaceId: string, drawingId: string):
52
52
  declare function removeDrawingFromWorkspace(workspaceId: string, drawingId: string): Promise<Workspace | undefined>;
53
53
  declare function setActiveDrawing(workspaceId: string, drawingId: string): Promise<Workspace | undefined>;
54
54
 
55
+ /**
56
+ * Rita Workspace Translations
57
+ *
58
+ * Supports Swedish (sv) and English (en)
59
+ */
60
+ type SupportedLanguage = 'sv' | 'en';
61
+ interface Translations {
62
+ drawings: string;
63
+ newDrawing: string;
64
+ manageDrawings: string;
65
+ dialogTitle: string;
66
+ close: string;
67
+ open: string;
68
+ rename: string;
69
+ delete: string;
70
+ save: string;
71
+ cancel: string;
72
+ confirm: string;
73
+ noDrawingsYet: string;
74
+ clickNewToStart: string;
75
+ modified: string;
76
+ confirmDelete: string;
77
+ shortcutNewDrawing: string;
78
+ }
79
+ /**
80
+ * Get translations for a language code
81
+ * Falls back to English if language is not supported
82
+ */
83
+ declare function getTranslations(langCode?: string): Translations;
84
+ /**
85
+ * Check if a language is supported
86
+ */
87
+ declare function isLanguageSupported(langCode?: string): boolean;
88
+
55
89
  interface WorkspaceContextValue {
56
90
  workspace: Workspace | null;
57
91
  drawings: Drawing[];
58
92
  activeDrawing: Drawing | null;
59
93
  isLoading: boolean;
60
94
  error: string | null;
95
+ lang: string;
96
+ t: Translations;
61
97
  createNewDrawing: (name?: string) => Promise<Drawing | null>;
62
98
  switchDrawing: (id: string) => Promise<void>;
63
99
  renameDrawing: (id: string, name: string) => Promise<void>;
@@ -66,10 +102,24 @@ interface WorkspaceContextValue {
66
102
  saveCurrentDrawing: (elements: unknown[], appState: Record<string, unknown>) => Promise<void>;
67
103
  }
68
104
  declare function useWorkspace(): WorkspaceContextValue;
105
+ /**
106
+ * Hook to get current language and translations
107
+ * Can be used by any component within WorkspaceProvider
108
+ */
109
+ declare function useWorkspaceLang(): {
110
+ lang: string;
111
+ t: Translations;
112
+ };
69
113
  interface WorkspaceProviderProps {
70
114
  children: ReactNode;
115
+ /**
116
+ * Language code (e.g., 'sv', 'en', 'sv-SE')
117
+ * Pass Excalidraw's langCode here to sync languages
118
+ * Falls back to English if not supported
119
+ */
120
+ lang?: string;
71
121
  }
72
- declare function WorkspaceProvider({ children }: WorkspaceProviderProps): react_jsx_runtime.JSX.Element;
122
+ declare function WorkspaceProvider({ children, lang }: WorkspaceProviderProps): react_jsx_runtime.JSX.Element;
73
123
 
74
124
  interface SidebarProps {
75
125
  isOpen?: boolean;
@@ -212,40 +262,6 @@ declare function useExcalidrawBridge({ excalidrawAPI, autoSaveInterval, }: UseEx
212
262
  scheduleSave: () => void;
213
263
  };
214
264
 
215
- /**
216
- * Rita Workspace Translations
217
- *
218
- * Supports Swedish (sv) and English (en)
219
- */
220
- type SupportedLanguage = 'sv' | 'en';
221
- interface Translations {
222
- drawings: string;
223
- newDrawing: string;
224
- manageDrawings: string;
225
- dialogTitle: string;
226
- close: string;
227
- open: string;
228
- rename: string;
229
- delete: string;
230
- save: string;
231
- cancel: string;
232
- confirm: string;
233
- noDrawingsYet: string;
234
- clickNewToStart: string;
235
- modified: string;
236
- confirmDelete: string;
237
- shortcutNewDrawing: string;
238
- }
239
- /**
240
- * Get translations for a language code
241
- * Falls back to English if language is not supported
242
- */
243
- declare function getTranslations(langCode?: string): Translations;
244
- /**
245
- * Check if a language is supported
246
- */
247
- declare function isLanguageSupported(langCode?: string): boolean;
248
-
249
265
  interface WorkspacePluginProps {
250
266
  children: ReactNode;
251
267
  defaultSidebarOpen?: boolean;
@@ -269,4 +285,4 @@ interface WorkspacePluginProps {
269
285
  */
270
286
  declare function WorkspacePlugin(props: WorkspacePluginProps): react_jsx_runtime.JSX.Element;
271
287
 
272
- export { type Drawing, DrawingList, DrawingListItem, DrawingsDialog, type DrawingsDialogProps, Sidebar, type SupportedLanguage, type Translations, type Workspace, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, deleteDrawing, duplicateDrawing, getAllDrawings, getDB, getDrawing, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isLanguageSupported, removeDrawingFromWorkspace, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace };
288
+ export { type Drawing, DrawingList, DrawingListItem, DrawingsDialog, type DrawingsDialogProps, Sidebar, type SupportedLanguage, type Translations, type Workspace, type WorkspaceContextValue, WorkspaceMenuItems, type WorkspaceMenuItemsProps, WorkspacePlugin, WorkspaceProvider, addDrawingToWorkspace, closeDB, createDrawing, deleteDrawing, duplicateDrawing, getAllDrawings, getDB, getDrawing, getOrCreateDefaultWorkspace, getTranslations, getWorkspace, isLanguageSupported, removeDrawingFromWorkspace, setActiveDrawing, updateDrawing, updateWorkspace, useExcalidrawBridge, useWorkspace, useWorkspaceLang };
package/dist/index.js CHANGED
@@ -54,7 +54,8 @@ __export(index_exports, {
54
54
  updateDrawing: () => updateDrawing,
55
55
  updateWorkspace: () => updateWorkspace,
56
56
  useExcalidrawBridge: () => useExcalidrawBridge,
57
- useWorkspace: () => useWorkspace
57
+ useWorkspace: () => useWorkspace,
58
+ useWorkspaceLang: () => useWorkspaceLang
58
59
  });
59
60
  module.exports = __toCommonJS(index_exports);
60
61
 
@@ -206,6 +207,71 @@ async function setActiveDrawing(workspaceId, drawingId) {
206
207
 
207
208
  // src/state/WorkspaceContext.tsx
208
209
  var import_react = require("react");
210
+
211
+ // src/i18n/translations.ts
212
+ var sv = {
213
+ // Menu
214
+ drawings: "Ritningar",
215
+ newDrawing: "Ny ritning",
216
+ manageDrawings: "Hantera ritningar...",
217
+ // Dialog
218
+ dialogTitle: "Ritningar",
219
+ close: "St\xE4ng",
220
+ open: "\xD6ppna",
221
+ rename: "Byt namn",
222
+ delete: "Ta bort",
223
+ save: "Spara",
224
+ cancel: "Avbryt",
225
+ confirm: "Bekr\xE4fta",
226
+ // Messages
227
+ noDrawingsYet: "Inga ritningar \xE4nnu.",
228
+ clickNewToStart: 'Klicka "Ny ritning" f\xF6r att b\xF6rja.',
229
+ modified: "\xC4ndrad",
230
+ confirmDelete: "Vill du ta bort denna ritning?",
231
+ // Shortcuts
232
+ shortcutNewDrawing: "Ctrl+Alt+N"
233
+ };
234
+ var en = {
235
+ // Menu
236
+ drawings: "Drawings",
237
+ newDrawing: "New drawing",
238
+ manageDrawings: "Manage drawings...",
239
+ // Dialog
240
+ dialogTitle: "Drawings",
241
+ close: "Close",
242
+ open: "Open",
243
+ rename: "Rename",
244
+ delete: "Delete",
245
+ save: "Save",
246
+ cancel: "Cancel",
247
+ confirm: "Confirm",
248
+ // Messages
249
+ noDrawingsYet: "No drawings yet.",
250
+ clickNewToStart: 'Click "New drawing" to start.',
251
+ modified: "Modified",
252
+ confirmDelete: "Do you want to delete this drawing?",
253
+ // Shortcuts
254
+ shortcutNewDrawing: "Ctrl+Alt+N"
255
+ };
256
+ var translations = {
257
+ sv,
258
+ en
259
+ };
260
+ function getTranslations(langCode) {
261
+ if (!langCode) return en;
262
+ const lang = langCode.split("-")[0].toLowerCase();
263
+ if (lang in translations) {
264
+ return translations[lang];
265
+ }
266
+ return en;
267
+ }
268
+ function isLanguageSupported(langCode) {
269
+ if (!langCode) return false;
270
+ const lang = langCode.split("-")[0].toLowerCase();
271
+ return lang in translations;
272
+ }
273
+
274
+ // src/state/WorkspaceContext.tsx
209
275
  var import_jsx_runtime = require("react/jsx-runtime");
210
276
  var WorkspaceContext = (0, import_react.createContext)(null);
211
277
  function useWorkspace() {
@@ -215,12 +281,20 @@ function useWorkspace() {
215
281
  }
216
282
  return context;
217
283
  }
218
- function WorkspaceProvider({ children }) {
284
+ function useWorkspaceLang() {
285
+ const context = (0, import_react.useContext)(WorkspaceContext);
286
+ if (!context) {
287
+ return { lang: "en", t: getTranslations("en") };
288
+ }
289
+ return { lang: context.lang, t: context.t };
290
+ }
291
+ function WorkspaceProvider({ children, lang = "en" }) {
219
292
  const [workspace, setWorkspace] = (0, import_react.useState)(null);
220
293
  const [drawings, setDrawings] = (0, import_react.useState)([]);
221
294
  const [activeDrawing, setActiveDrawing2] = (0, import_react.useState)(null);
222
295
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
223
296
  const [error, setError] = (0, import_react.useState)(null);
297
+ const t = getTranslations(lang);
224
298
  (0, import_react.useEffect)(() => {
225
299
  async function init() {
226
300
  try {
@@ -245,7 +319,8 @@ function WorkspaceProvider({ children }) {
245
319
  const createNewDrawing = (0, import_react.useCallback)(async (name) => {
246
320
  if (!workspace) return null;
247
321
  try {
248
- const drawing = await createDrawing(name || `Ritning ${drawings.length + 1}`);
322
+ const defaultName = `${t.newDrawing} ${drawings.length + 1}`;
323
+ const drawing = await createDrawing(name || defaultName);
249
324
  await addDrawingToWorkspace(workspace.id, drawing.id);
250
325
  await setActiveDrawing(workspace.id, drawing.id);
251
326
  setDrawings((prev) => [...prev, drawing]);
@@ -260,7 +335,7 @@ function WorkspaceProvider({ children }) {
260
335
  setError(err instanceof Error ? err.message : "Failed to create drawing");
261
336
  return null;
262
337
  }
263
- }, [workspace, drawings.length]);
338
+ }, [workspace, drawings.length, t]);
264
339
  const switchDrawing = (0, import_react.useCallback)(async (id) => {
265
340
  if (!workspace) return;
266
341
  try {
@@ -341,6 +416,8 @@ function WorkspaceProvider({ children }) {
341
416
  activeDrawing,
342
417
  isLoading,
343
418
  error,
419
+ lang,
420
+ t,
344
421
  createNewDrawing,
345
422
  switchDrawing,
346
423
  renameDrawing,
@@ -545,71 +622,6 @@ function Sidebar({ isOpen = true, onToggle, width = 250 }) {
545
622
 
546
623
  // src/ui/Menu/WorkspaceMenuItems.tsx
547
624
  var import_react4 = __toESM(require("react"));
548
-
549
- // src/i18n/translations.ts
550
- var sv = {
551
- // Menu
552
- drawings: "Ritningar",
553
- newDrawing: "Ny ritning",
554
- manageDrawings: "Hantera ritningar...",
555
- // Dialog
556
- dialogTitle: "Ritningar",
557
- close: "St\xE4ng",
558
- open: "\xD6ppna",
559
- rename: "Byt namn",
560
- delete: "Ta bort",
561
- save: "Spara",
562
- cancel: "Avbryt",
563
- confirm: "Bekr\xE4fta",
564
- // Messages
565
- noDrawingsYet: "Inga ritningar \xE4nnu.",
566
- clickNewToStart: 'Klicka "Ny ritning" f\xF6r att b\xF6rja.',
567
- modified: "\xC4ndrad",
568
- confirmDelete: "Vill du ta bort denna ritning?",
569
- // Shortcuts
570
- shortcutNewDrawing: "Ctrl+Alt+N"
571
- };
572
- var en = {
573
- // Menu
574
- drawings: "Drawings",
575
- newDrawing: "New drawing",
576
- manageDrawings: "Manage drawings...",
577
- // Dialog
578
- dialogTitle: "Drawings",
579
- close: "Close",
580
- open: "Open",
581
- rename: "Rename",
582
- delete: "Delete",
583
- save: "Save",
584
- cancel: "Cancel",
585
- confirm: "Confirm",
586
- // Messages
587
- noDrawingsYet: "No drawings yet.",
588
- clickNewToStart: 'Click "New drawing" to start.',
589
- modified: "Modified",
590
- confirmDelete: "Do you want to delete this drawing?",
591
- // Shortcuts
592
- shortcutNewDrawing: "Ctrl+Alt+N"
593
- };
594
- var translations = {
595
- sv,
596
- en
597
- };
598
- function getTranslations(langCode) {
599
- if (!langCode) return en;
600
- const lang = langCode.split("-")[0].toLowerCase();
601
- if (lang in translations) {
602
- return translations[lang];
603
- }
604
- return en;
605
- }
606
- function isLanguageSupported(langCode) {
607
- if (!langCode) return false;
608
- const lang = langCode.split("-")[0].toLowerCase();
609
- return lang in translations;
610
- }
611
-
612
- // src/ui/Menu/WorkspaceMenuItems.tsx
613
625
  var import_jsx_runtime5 = require("react/jsx-runtime");
614
626
  var DrawingsIcon = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
615
627
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
@@ -653,8 +665,8 @@ var WorkspaceMenuItems = ({
653
665
  renderSubMenu,
654
666
  renderSeparator
655
667
  }) => {
656
- const { drawings, activeDrawing, switchDrawing, createNewDrawing } = useWorkspace();
657
- const t = getTranslations(lang);
668
+ const { drawings, activeDrawing, switchDrawing, createNewDrawing, t: contextT, lang: contextLang } = useWorkspace();
669
+ const t = lang ? getTranslations(lang) : contextT;
658
670
  const MenuItem = renderMenuItem || ((props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DefaultMenuItem, { ...props }));
659
671
  const Separator = renderSeparator || (() => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("hr", { style: { margin: "4px 0", border: "none", borderTop: "1px solid #ccc" } }));
660
672
  const handleDrawingSelect = async (drawing) => {
@@ -734,9 +746,12 @@ var DrawingsDialog = ({
734
746
  switchDrawing,
735
747
  createNewDrawing,
736
748
  renameDrawing,
737
- removeDrawing
749
+ removeDrawing,
750
+ t: contextT,
751
+ lang: contextLang
738
752
  } = useWorkspace();
739
- const t = getTranslations(lang);
753
+ const t = lang ? getTranslations(lang) : contextT;
754
+ const effectiveLang = lang || contextLang;
740
755
  const [editingId, setEditingId] = (0, import_react5.useState)(null);
741
756
  const [editName, setEditName] = (0, import_react5.useState)("");
742
757
  const [confirmDeleteId, setConfirmDeleteId] = (0, import_react5.useState)(null);
@@ -772,8 +787,8 @@ var DrawingsDialog = ({
772
787
  setConfirmDeleteId(null);
773
788
  }, [removeDrawing]);
774
789
  const getLocale = () => {
775
- if (!lang) return "en-US";
776
- const baseLang = lang.split("-")[0].toLowerCase();
790
+ if (!effectiveLang) return "en-US";
791
+ const baseLang = effectiveLang.split("-")[0].toLowerCase();
777
792
  if (baseLang === "sv") return "sv-SE";
778
793
  return "en-US";
779
794
  };
@@ -1257,5 +1272,6 @@ function WorkspacePlugin(props) {
1257
1272
  updateDrawing,
1258
1273
  updateWorkspace,
1259
1274
  useExcalidrawBridge,
1260
- useWorkspace
1275
+ useWorkspace,
1276
+ useWorkspaceLang
1261
1277
  });
package/dist/index.mjs CHANGED
@@ -146,6 +146,71 @@ async function setActiveDrawing(workspaceId, drawingId) {
146
146
 
147
147
  // src/state/WorkspaceContext.tsx
148
148
  import { createContext, useContext, useEffect, useState, useCallback } from "react";
149
+
150
+ // src/i18n/translations.ts
151
+ var sv = {
152
+ // Menu
153
+ drawings: "Ritningar",
154
+ newDrawing: "Ny ritning",
155
+ manageDrawings: "Hantera ritningar...",
156
+ // Dialog
157
+ dialogTitle: "Ritningar",
158
+ close: "St\xE4ng",
159
+ open: "\xD6ppna",
160
+ rename: "Byt namn",
161
+ delete: "Ta bort",
162
+ save: "Spara",
163
+ cancel: "Avbryt",
164
+ confirm: "Bekr\xE4fta",
165
+ // Messages
166
+ noDrawingsYet: "Inga ritningar \xE4nnu.",
167
+ clickNewToStart: 'Klicka "Ny ritning" f\xF6r att b\xF6rja.',
168
+ modified: "\xC4ndrad",
169
+ confirmDelete: "Vill du ta bort denna ritning?",
170
+ // Shortcuts
171
+ shortcutNewDrawing: "Ctrl+Alt+N"
172
+ };
173
+ var en = {
174
+ // Menu
175
+ drawings: "Drawings",
176
+ newDrawing: "New drawing",
177
+ manageDrawings: "Manage drawings...",
178
+ // Dialog
179
+ dialogTitle: "Drawings",
180
+ close: "Close",
181
+ open: "Open",
182
+ rename: "Rename",
183
+ delete: "Delete",
184
+ save: "Save",
185
+ cancel: "Cancel",
186
+ confirm: "Confirm",
187
+ // Messages
188
+ noDrawingsYet: "No drawings yet.",
189
+ clickNewToStart: 'Click "New drawing" to start.',
190
+ modified: "Modified",
191
+ confirmDelete: "Do you want to delete this drawing?",
192
+ // Shortcuts
193
+ shortcutNewDrawing: "Ctrl+Alt+N"
194
+ };
195
+ var translations = {
196
+ sv,
197
+ en
198
+ };
199
+ function getTranslations(langCode) {
200
+ if (!langCode) return en;
201
+ const lang = langCode.split("-")[0].toLowerCase();
202
+ if (lang in translations) {
203
+ return translations[lang];
204
+ }
205
+ return en;
206
+ }
207
+ function isLanguageSupported(langCode) {
208
+ if (!langCode) return false;
209
+ const lang = langCode.split("-")[0].toLowerCase();
210
+ return lang in translations;
211
+ }
212
+
213
+ // src/state/WorkspaceContext.tsx
149
214
  import { jsx } from "react/jsx-runtime";
150
215
  var WorkspaceContext = createContext(null);
151
216
  function useWorkspace() {
@@ -155,12 +220,20 @@ function useWorkspace() {
155
220
  }
156
221
  return context;
157
222
  }
158
- function WorkspaceProvider({ children }) {
223
+ function useWorkspaceLang() {
224
+ const context = useContext(WorkspaceContext);
225
+ if (!context) {
226
+ return { lang: "en", t: getTranslations("en") };
227
+ }
228
+ return { lang: context.lang, t: context.t };
229
+ }
230
+ function WorkspaceProvider({ children, lang = "en" }) {
159
231
  const [workspace, setWorkspace] = useState(null);
160
232
  const [drawings, setDrawings] = useState([]);
161
233
  const [activeDrawing, setActiveDrawing2] = useState(null);
162
234
  const [isLoading, setIsLoading] = useState(true);
163
235
  const [error, setError] = useState(null);
236
+ const t = getTranslations(lang);
164
237
  useEffect(() => {
165
238
  async function init() {
166
239
  try {
@@ -185,7 +258,8 @@ function WorkspaceProvider({ children }) {
185
258
  const createNewDrawing = useCallback(async (name) => {
186
259
  if (!workspace) return null;
187
260
  try {
188
- const drawing = await createDrawing(name || `Ritning ${drawings.length + 1}`);
261
+ const defaultName = `${t.newDrawing} ${drawings.length + 1}`;
262
+ const drawing = await createDrawing(name || defaultName);
189
263
  await addDrawingToWorkspace(workspace.id, drawing.id);
190
264
  await setActiveDrawing(workspace.id, drawing.id);
191
265
  setDrawings((prev) => [...prev, drawing]);
@@ -200,7 +274,7 @@ function WorkspaceProvider({ children }) {
200
274
  setError(err instanceof Error ? err.message : "Failed to create drawing");
201
275
  return null;
202
276
  }
203
- }, [workspace, drawings.length]);
277
+ }, [workspace, drawings.length, t]);
204
278
  const switchDrawing = useCallback(async (id) => {
205
279
  if (!workspace) return;
206
280
  try {
@@ -281,6 +355,8 @@ function WorkspaceProvider({ children }) {
281
355
  activeDrawing,
282
356
  isLoading,
283
357
  error,
358
+ lang,
359
+ t,
284
360
  createNewDrawing,
285
361
  switchDrawing,
286
362
  renameDrawing,
@@ -485,71 +561,6 @@ function Sidebar({ isOpen = true, onToggle, width = 250 }) {
485
561
 
486
562
  // src/ui/Menu/WorkspaceMenuItems.tsx
487
563
  import React4 from "react";
488
-
489
- // src/i18n/translations.ts
490
- var sv = {
491
- // Menu
492
- drawings: "Ritningar",
493
- newDrawing: "Ny ritning",
494
- manageDrawings: "Hantera ritningar...",
495
- // Dialog
496
- dialogTitle: "Ritningar",
497
- close: "St\xE4ng",
498
- open: "\xD6ppna",
499
- rename: "Byt namn",
500
- delete: "Ta bort",
501
- save: "Spara",
502
- cancel: "Avbryt",
503
- confirm: "Bekr\xE4fta",
504
- // Messages
505
- noDrawingsYet: "Inga ritningar \xE4nnu.",
506
- clickNewToStart: 'Klicka "Ny ritning" f\xF6r att b\xF6rja.',
507
- modified: "\xC4ndrad",
508
- confirmDelete: "Vill du ta bort denna ritning?",
509
- // Shortcuts
510
- shortcutNewDrawing: "Ctrl+Alt+N"
511
- };
512
- var en = {
513
- // Menu
514
- drawings: "Drawings",
515
- newDrawing: "New drawing",
516
- manageDrawings: "Manage drawings...",
517
- // Dialog
518
- dialogTitle: "Drawings",
519
- close: "Close",
520
- open: "Open",
521
- rename: "Rename",
522
- delete: "Delete",
523
- save: "Save",
524
- cancel: "Cancel",
525
- confirm: "Confirm",
526
- // Messages
527
- noDrawingsYet: "No drawings yet.",
528
- clickNewToStart: 'Click "New drawing" to start.',
529
- modified: "Modified",
530
- confirmDelete: "Do you want to delete this drawing?",
531
- // Shortcuts
532
- shortcutNewDrawing: "Ctrl+Alt+N"
533
- };
534
- var translations = {
535
- sv,
536
- en
537
- };
538
- function getTranslations(langCode) {
539
- if (!langCode) return en;
540
- const lang = langCode.split("-")[0].toLowerCase();
541
- if (lang in translations) {
542
- return translations[lang];
543
- }
544
- return en;
545
- }
546
- function isLanguageSupported(langCode) {
547
- if (!langCode) return false;
548
- const lang = langCode.split("-")[0].toLowerCase();
549
- return lang in translations;
550
- }
551
-
552
- // src/ui/Menu/WorkspaceMenuItems.tsx
553
564
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
554
565
  var DrawingsIcon = /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
555
566
  /* @__PURE__ */ jsx5("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
@@ -593,8 +604,8 @@ var WorkspaceMenuItems = ({
593
604
  renderSubMenu,
594
605
  renderSeparator
595
606
  }) => {
596
- const { drawings, activeDrawing, switchDrawing, createNewDrawing } = useWorkspace();
597
- const t = getTranslations(lang);
607
+ const { drawings, activeDrawing, switchDrawing, createNewDrawing, t: contextT, lang: contextLang } = useWorkspace();
608
+ const t = lang ? getTranslations(lang) : contextT;
598
609
  const MenuItem = renderMenuItem || ((props) => /* @__PURE__ */ jsx5(DefaultMenuItem, { ...props }));
599
610
  const Separator = renderSeparator || (() => /* @__PURE__ */ jsx5("hr", { style: { margin: "4px 0", border: "none", borderTop: "1px solid #ccc" } }));
600
611
  const handleDrawingSelect = async (drawing) => {
@@ -674,9 +685,12 @@ var DrawingsDialog = ({
674
685
  switchDrawing,
675
686
  createNewDrawing,
676
687
  renameDrawing,
677
- removeDrawing
688
+ removeDrawing,
689
+ t: contextT,
690
+ lang: contextLang
678
691
  } = useWorkspace();
679
- const t = getTranslations(lang);
692
+ const t = lang ? getTranslations(lang) : contextT;
693
+ const effectiveLang = lang || contextLang;
680
694
  const [editingId, setEditingId] = useState4(null);
681
695
  const [editName, setEditName] = useState4("");
682
696
  const [confirmDeleteId, setConfirmDeleteId] = useState4(null);
@@ -712,8 +726,8 @@ var DrawingsDialog = ({
712
726
  setConfirmDeleteId(null);
713
727
  }, [removeDrawing]);
714
728
  const getLocale = () => {
715
- if (!lang) return "en-US";
716
- const baseLang = lang.split("-")[0].toLowerCase();
729
+ if (!effectiveLang) return "en-US";
730
+ const baseLang = effectiveLang.split("-")[0].toLowerCase();
717
731
  if (baseLang === "sv") return "sv-SE";
718
732
  return "en-US";
719
733
  };
@@ -1196,5 +1210,6 @@ export {
1196
1210
  updateDrawing,
1197
1211
  updateWorkspace,
1198
1212
  useExcalidrawBridge,
1199
- useWorkspace
1213
+ useWorkspace,
1214
+ useWorkspaceLang
1200
1215
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rita-workspace",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Multi-drawing workspace feature for Rita (Excalidraw fork)",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",