rune-lab 0.4.1 → 0.4.2-beta.10

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 (208) hide show
  1. package/dist/RuneProvider.svelte.d.ts +30 -0
  2. package/dist/i18n/message-resolver.d.ts +41 -0
  3. package/dist/i18n/message-resolver.js +47 -0
  4. package/dist/i18n/message-resolver.test.js +77 -0
  5. package/dist/kernel/src/actions/portal.d.ts +7 -0
  6. package/dist/kernel/src/actions/portal.js +32 -0
  7. package/dist/kernel/src/actions/shortcut-listener.d.ts +15 -0
  8. package/dist/kernel/src/actions/shortcut-listener.js +34 -0
  9. package/dist/kernel/src/context/app.svelte.d.ts +45 -0
  10. package/dist/kernel/src/context/app.svelte.js +78 -0
  11. package/dist/kernel/src/context/context.d.ts +15 -0
  12. package/dist/kernel/src/context/context.js +16 -0
  13. package/dist/kernel/src/context/stores.svelte.d.ts +60 -0
  14. package/dist/kernel/src/context/stores.svelte.js +49 -0
  15. package/dist/kernel/src/context/types.d.ts +98 -0
  16. package/dist/kernel/src/context/types.js +1 -0
  17. package/dist/kernel/src/context/useRuneLab.d.ts +16 -0
  18. package/dist/kernel/src/context/useRuneLab.js +17 -0
  19. package/dist/kernel/src/mod.js +13 -0
  20. package/dist/kernel/src/persistence/createConfigStore.svelte.d.ts +28 -0
  21. package/dist/kernel/src/persistence/createConfigStore.svelte.js +72 -0
  22. package/dist/kernel/src/persistence/drivers.d.ts +12 -0
  23. package/dist/kernel/src/persistence/drivers.js +75 -0
  24. package/dist/kernel/src/persistence/drivers.test.js +79 -0
  25. package/dist/kernel/src/persistence/provider.d.ts +23 -0
  26. package/{src/kernel/src/persistence/provider.ts → dist/kernel/src/persistence/provider.js} +14 -29
  27. package/dist/kernel/src/persistence/provider.test.js +51 -0
  28. package/dist/kernel/src/persistence/types.d.ts +17 -0
  29. package/dist/kernel/src/persistence/types.js +2 -0
  30. package/dist/kernel/src/persistence/usePersistence.d.ts +2 -0
  31. package/dist/kernel/src/persistence/usePersistence.js +5 -0
  32. package/dist/kernel/src/registry/mod.d.ts +105 -0
  33. package/dist/kernel/src/registry/mod.js +131 -0
  34. package/dist/kernel/src/registry/registry.test.js +114 -0
  35. package/dist/kernel/src/tokens/props.d.ts +51 -0
  36. package/dist/kernel/src/tokens/props.js +34 -0
  37. package/dist/mod.d.ts +6 -0
  38. package/dist/mod.js +8 -0
  39. package/dist/runes/layout/src/APP_CONFIGURATIONS.d.ts +29 -0
  40. package/dist/runes/layout/src/APP_CONFIGURATIONS.js +38 -0
  41. package/dist/runes/layout/src/AppSettingSelector.svelte.d.ts +16 -0
  42. package/dist/runes/layout/src/ConnectedNavigationPanel.svelte.d.ts +16 -0
  43. package/dist/runes/layout/src/ConnectedWorkspaceStrip.svelte.d.ts +16 -0
  44. package/dist/runes/layout/src/ContentArea.svelte.d.ts +16 -0
  45. package/dist/runes/layout/src/DetailPanel.svelte.d.ts +16 -0
  46. package/dist/runes/layout/src/Icon.svelte.d.ts +16 -0
  47. package/dist/runes/layout/src/LanguageSelector.svelte.d.ts +16 -0
  48. package/dist/runes/layout/src/NavigationPanel.svelte.d.ts +16 -0
  49. package/dist/runes/layout/src/ResourceSelector.svelte.d.ts +19 -0
  50. package/dist/runes/layout/src/ThemeSelector.svelte.d.ts +16 -0
  51. package/dist/runes/layout/src/WorkspaceLayout.svelte.d.ts +45 -0
  52. package/dist/runes/layout/src/WorkspaceStrip.svelte.d.ts +16 -0
  53. package/dist/runes/layout/src/connection-factory.d.ts +50 -0
  54. package/dist/runes/layout/src/connection-factory.js +58 -0
  55. package/dist/runes/layout/src/language.svelte.d.ts +46 -0
  56. package/dist/runes/layout/src/language.svelte.js +30 -0
  57. package/dist/runes/layout/src/mod.d.ts +22 -0
  58. package/dist/runes/layout/src/mod.js +63 -0
  59. package/dist/runes/layout/src/store.svelte.d.ts +28 -0
  60. package/dist/runes/layout/src/store.svelte.js +105 -0
  61. package/dist/runes/layout/src/theme.svelte.d.ts +6 -0
  62. package/dist/runes/layout/src/theme.svelte.js +62 -0
  63. package/dist/runes/layout/src/types.d.ts +6 -0
  64. package/{src/runes/layout/src/types.ts → dist/runes/layout/src/types.js} +0 -3
  65. package/dist/runes/palettes/src/commands/CommandPalette.svelte.d.ts +16 -0
  66. package/dist/runes/palettes/src/commands/mod.js +2 -0
  67. package/dist/runes/palettes/src/commands/store.svelte.d.ts +31 -0
  68. package/dist/runes/palettes/src/commands/store.svelte.js +57 -0
  69. package/dist/runes/palettes/src/mod.d.ts +9 -0
  70. package/dist/runes/palettes/src/mod.js +46 -0
  71. package/dist/runes/palettes/src/notifications/NotificationBell.svelte.d.ts +24 -0
  72. package/dist/runes/palettes/src/notifications/Toaster.svelte.d.ts +16 -0
  73. package/dist/runes/palettes/src/notifications/bridge.d.ts +29 -0
  74. package/dist/runes/palettes/src/notifications/bridge.js +43 -0
  75. package/dist/runes/palettes/src/notifications/mod.js +4 -0
  76. package/dist/runes/palettes/src/notifications/store.svelte.d.ts +23 -0
  77. package/dist/runes/palettes/src/notifications/store.svelte.js +43 -0
  78. package/dist/runes/palettes/src/shortcuts/ShortcutPalette.svelte.d.ts +21 -0
  79. package/dist/runes/palettes/src/shortcuts/mod.js +4 -0
  80. package/dist/runes/palettes/src/shortcuts/store.svelte.d.ts +37 -0
  81. package/dist/runes/palettes/src/shortcuts/store.svelte.js +76 -0
  82. package/dist/runes/palettes/src/shortcuts/types.d.ts +1 -0
  83. package/{src/runes/palettes/src/shortcuts/types.ts → dist/runes/palettes/src/shortcuts/types.js} +1 -2
  84. package/dist/runes/palettes/src/shortcuts/useShortcuts.d.ts +32 -0
  85. package/dist/runes/palettes/src/shortcuts/useShortcuts.js +75 -0
  86. package/dist/runes/plugins/money/src/CurrencySelector.svelte.d.ts +16 -0
  87. package/dist/runes/plugins/money/src/MoneyDisplay.svelte.d.ts +16 -0
  88. package/dist/runes/plugins/money/src/MoneyInput.svelte.d.ts +47 -0
  89. package/dist/runes/plugins/money/src/currency.svelte.d.ts +25 -0
  90. package/dist/runes/plugins/money/src/currency.svelte.js +70 -0
  91. package/dist/runes/plugins/money/src/currency.test.js +32 -0
  92. package/dist/runes/plugins/money/src/exchange-rate.svelte.d.ts +44 -0
  93. package/dist/runes/plugins/money/src/exchange-rate.svelte.js +146 -0
  94. package/dist/runes/plugins/money/src/exchange-rate.test.js +74 -0
  95. package/dist/runes/plugins/money/src/mod.d.ts +13 -0
  96. package/dist/runes/plugins/money/src/mod.js +53 -0
  97. package/dist/runes/plugins/money/src/money-primitive.d.ts +100 -0
  98. package/dist/runes/plugins/money/src/money-primitive.js +161 -0
  99. package/dist/runes/plugins/money/src/money-primitive.test.js +175 -0
  100. package/dist/runes/plugins/money/src/money.d.ts +128 -0
  101. package/dist/runes/plugins/money/src/money.js +250 -0
  102. package/dist/runes/plugins/money/src/money.test.js +139 -0
  103. package/dist/runes/plugins/money/src/strategies.d.ts +51 -0
  104. package/{src/runes/plugins/money/src/strategies.ts → dist/runes/plugins/money/src/strategies.js} +22 -45
  105. package/dist/runes/plugins/money/src/strategies.test.js +100 -0
  106. package/dist/runes/plugins/money/src/types.d.ts +1 -0
  107. package/dist/runes/plugins/money/src/types.js +1 -0
  108. package/dist/runes/plugins/money/src/useMoney.d.ts +32 -0
  109. package/dist/runes/plugins/money/src/useMoney.js +126 -0
  110. package/dist/runes/plugins/money/src/useMoneyFilter.d.ts +21 -0
  111. package/dist/runes/plugins/money/src/useMoneyFilter.js +84 -0
  112. package/package.json +54 -2
  113. package/.gitignore +0 -12
  114. package/deno.json +0 -50
  115. package/justfile +0 -5
  116. package/scripts/build_pkg.ts +0 -51
  117. package/scripts/ci.just +0 -26
  118. package/scripts/deploy.just +0 -21
  119. package/scripts/dev.just +0 -4
  120. package/scripts/inject.just +0 -72
  121. package/src/i18n/message-resolver.test.ts +0 -103
  122. package/src/i18n/message-resolver.ts +0 -89
  123. package/src/kernel/deno.json +0 -5
  124. package/src/kernel/src/actions/portal.ts +0 -41
  125. package/src/kernel/src/actions/shortcut-listener.ts +0 -50
  126. package/src/kernel/src/context/app.svelte.ts +0 -98
  127. package/src/kernel/src/context/context.ts +0 -31
  128. package/src/kernel/src/context/stores.svelte.ts +0 -96
  129. package/src/kernel/src/context/types.ts +0 -110
  130. package/src/kernel/src/context/useRuneLab.ts +0 -38
  131. package/src/kernel/src/persistence/createConfigStore.svelte.ts +0 -120
  132. package/src/kernel/src/persistence/drivers.test.ts +0 -95
  133. package/src/kernel/src/persistence/drivers.ts +0 -77
  134. package/src/kernel/src/persistence/provider.test.ts +0 -58
  135. package/src/kernel/src/persistence/types.ts +0 -19
  136. package/src/kernel/src/persistence/usePersistence.ts +0 -9
  137. package/src/kernel/src/registry/mod.ts +0 -221
  138. package/src/kernel/src/registry/registry.test.ts +0 -162
  139. package/src/kernel/src/tokens/props.ts +0 -94
  140. package/src/mod.ts +0 -10
  141. package/src/runes/layout/deno.json +0 -5
  142. package/src/runes/layout/src/APP_CONFIGURATIONS.ts +0 -56
  143. package/src/runes/layout/src/connection-factory.ts +0 -95
  144. package/src/runes/layout/src/language.svelte.ts +0 -44
  145. package/src/runes/layout/src/mod.ts +0 -71
  146. package/src/runes/layout/src/store.svelte.ts +0 -142
  147. package/src/runes/layout/src/theme.svelte.ts +0 -73
  148. package/src/runes/palettes/deno.json +0 -8
  149. package/src/runes/palettes/src/commands/store.svelte.ts +0 -80
  150. package/src/runes/palettes/src/mod.ts +0 -51
  151. package/src/runes/palettes/src/notifications/bridge.ts +0 -56
  152. package/src/runes/palettes/src/notifications/store.svelte.ts +0 -58
  153. package/src/runes/palettes/src/shortcuts/store.svelte.ts +0 -85
  154. package/src/runes/palettes/src/shortcuts/useShortcuts.ts +0 -85
  155. package/src/runes/plugins/money/deno.json +0 -8
  156. package/src/runes/plugins/money/src/currency.svelte.ts +0 -95
  157. package/src/runes/plugins/money/src/currency.test.ts +0 -40
  158. package/src/runes/plugins/money/src/exchange-rate.svelte.ts +0 -176
  159. package/src/runes/plugins/money/src/exchange-rate.test.ts +0 -95
  160. package/src/runes/plugins/money/src/mod.ts +0 -79
  161. package/src/runes/plugins/money/src/money-primitive.test.ts +0 -217
  162. package/src/runes/plugins/money/src/money-primitive.ts +0 -220
  163. package/src/runes/plugins/money/src/money.test.ts +0 -183
  164. package/src/runes/plugins/money/src/money.ts +0 -382
  165. package/src/runes/plugins/money/src/strategies.test.ts +0 -143
  166. package/src/runes/plugins/money/src/types.ts +0 -27
  167. package/src/runes/plugins/money/src/useMoney.ts +0 -261
  168. package/src/runes/plugins/money/src/useMoneyFilter.ts +0 -132
  169. package/tsconfig.json +0 -41
  170. package/vite.config.ts +0 -44
  171. /package/{src → dist}/RuneProvider.svelte +0 -0
  172. /package/{src → dist}/i18n/project.inlang/settings.json +0 -0
  173. /package/{src → dist}/i18n/translations/ar.json +0 -0
  174. /package/{src → dist}/i18n/translations/de.json +0 -0
  175. /package/{src → dist}/i18n/translations/en.json +0 -0
  176. /package/{src → dist}/i18n/translations/es.json +0 -0
  177. /package/{src → dist}/i18n/translations/fr.json +0 -0
  178. /package/{src → dist}/i18n/translations/hi.json +0 -0
  179. /package/{src → dist}/i18n/translations/it.json +0 -0
  180. /package/{src → dist}/i18n/translations/ja.json +0 -0
  181. /package/{src → dist}/i18n/translations/ko.json +0 -0
  182. /package/{src → dist}/i18n/translations/pt.json +0 -0
  183. /package/{src → dist}/i18n/translations/ru.json +0 -0
  184. /package/{src → dist}/i18n/translations/vi.json +0 -0
  185. /package/{src → dist}/i18n/translations/zh.json +0 -0
  186. /package/{src/kernel/src/mod.ts → dist/kernel/src/mod.d.ts} +0 -0
  187. /package/{src → dist}/runes/layout/src/AppSettingSelector.svelte +0 -0
  188. /package/{src → dist}/runes/layout/src/ConnectedNavigationPanel.svelte +0 -0
  189. /package/{src → dist}/runes/layout/src/ConnectedWorkspaceStrip.svelte +0 -0
  190. /package/{src → dist}/runes/layout/src/ContentArea.svelte +0 -0
  191. /package/{src → dist}/runes/layout/src/DetailPanel.svelte +0 -0
  192. /package/{src → dist}/runes/layout/src/Icon.svelte +0 -0
  193. /package/{src → dist}/runes/layout/src/LanguageSelector.svelte +0 -0
  194. /package/{src → dist}/runes/layout/src/NavigationPanel.svelte +0 -0
  195. /package/{src → dist}/runes/layout/src/ResourceSelector.svelte +0 -0
  196. /package/{src → dist}/runes/layout/src/ThemeSelector.svelte +0 -0
  197. /package/{src → dist}/runes/layout/src/WorkspaceLayout.svelte +0 -0
  198. /package/{src → dist}/runes/layout/src/WorkspaceStrip.svelte +0 -0
  199. /package/{src → dist}/runes/palettes/src/commands/CommandPalette.svelte +0 -0
  200. /package/{src/runes/palettes/src/commands/mod.ts → dist/runes/palettes/src/commands/mod.d.ts} +0 -0
  201. /package/{src → dist}/runes/palettes/src/notifications/NotificationBell.svelte +0 -0
  202. /package/{src → dist}/runes/palettes/src/notifications/Toaster.svelte +0 -0
  203. /package/{src/runes/palettes/src/notifications/mod.ts → dist/runes/palettes/src/notifications/mod.d.ts} +0 -0
  204. /package/{src → dist}/runes/palettes/src/shortcuts/ShortcutPalette.svelte +0 -0
  205. /package/{src/runes/palettes/src/shortcuts/mod.ts → dist/runes/palettes/src/shortcuts/mod.d.ts} +0 -0
  206. /package/{src → dist}/runes/plugins/money/src/CurrencySelector.svelte +0 -0
  207. /package/{src → dist}/runes/plugins/money/src/MoneyDisplay.svelte +0 -0
  208. /package/{src → dist}/runes/plugins/money/src/MoneyInput.svelte +0 -0
@@ -0,0 +1,30 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ import type { PersistenceDriver } from "@rune-lab/kernel";
3
+ /**
4
+ * Namespaced configuration for Rune Lab plugins.
5
+ * Keyed by plugin.id.
6
+ */
7
+ export interface RuneLabConfig {
8
+ persistence?: PersistenceDriver;
9
+ /** Optional head management properties */
10
+ favicon?: string;
11
+ manageHead?: boolean;
12
+ icons?: "material" | "none";
13
+ /** Namespaced config for plugins */
14
+ [pluginId: string]: unknown;
15
+ }
16
+ declare const __propDef: {
17
+ props: Record<string, never>;
18
+ events: {
19
+ [evt: string]: CustomEvent<any>;
20
+ };
21
+ slots: {};
22
+ exports?: {};
23
+ bindings?: string;
24
+ };
25
+ export type RuneProviderProps = typeof __propDef.props;
26
+ export type RuneProviderEvents = typeof __propDef.events;
27
+ export type RuneProviderSlots = typeof __propDef.slots;
28
+ export default class RuneProvider extends SvelteComponentTyped<RuneProviderProps, RuneProviderEvents, RuneProviderSlots> {
29
+ }
30
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Dynamic i18n Message Resolver Pattern
3
+ *
4
+ * Enables dynamic message function calls for config selectors.
5
+ * Creates a resolver that dynamically looks up and calls message functions.
6
+ */
7
+ type MessageBundle = Record<string, (...args: unknown[]) => string>;
8
+ interface MessageResolverConfig<T> {
9
+ /**
10
+ * Function to extract the message key from an option
11
+ * @example (currency) => currency.code // "USD"
12
+ */
13
+ keyExtractor: (option: T) => string;
14
+ /**
15
+ * Optional transformer for the key before message lookup
16
+ * @example (key) => key.toLowerCase() // "USD" -> "usd"
17
+ */
18
+ keyTransformer?: (key: string) => string;
19
+ }
20
+ /**
21
+ * Creates a message resolver function for dynamic i18n lookups
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const getCurrencyLabel = createMessageResolver<Currency>(m, {
26
+ * keyExtractor: (currency) => currency.code
27
+ * });
28
+ *
29
+ * getCurrencyLabel({ code: "EUR", symbol: "€" }); // "Euro"
30
+ * ```
31
+ */
32
+ export declare function createMessageResolver<T>(messages: MessageBundle, config: MessageResolverConfig<T>): (option: T) => string;
33
+ /**
34
+ * Type guard to check if a message key exists
35
+ */
36
+ export declare function hasMessage(messages: MessageBundle, key: string): boolean;
37
+ /**
38
+ * Batch resolver for multiple options at once
39
+ */
40
+ export declare function batchResolveMessages<T>(messages: MessageBundle, options: T[], config: MessageResolverConfig<T>): Record<string, string>;
41
+ export {};
@@ -0,0 +1,47 @@
1
+ // sdk/devtools/src/patterns/message-resolver.ts
2
+ import { DEV } from "esm-env";
3
+ /**
4
+ * Creates a message resolver function for dynamic i18n lookups
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const getCurrencyLabel = createMessageResolver<Currency>(m, {
9
+ * keyExtractor: (currency) => currency.code
10
+ * });
11
+ *
12
+ * getCurrencyLabel({ code: "EUR", symbol: "€" }); // "Euro"
13
+ * ```
14
+ */
15
+ export function createMessageResolver(messages, config) {
16
+ return (option) => {
17
+ const key = config.keyExtractor(option);
18
+ const transformedKey = config.keyTransformer
19
+ ? config.keyTransformer(key)
20
+ : key;
21
+ const messageFn = messages[transformedKey];
22
+ if (!messageFn || typeof messageFn !== "function") {
23
+ if (DEV) {
24
+ console.warn(`[MessageResolver] Missing translation for key: "${transformedKey}"`);
25
+ }
26
+ return key; // Fallback to key
27
+ }
28
+ return messageFn();
29
+ };
30
+ }
31
+ /**
32
+ * Type guard to check if a message key exists
33
+ */
34
+ export function hasMessage(messages, key) {
35
+ return key in messages && typeof messages[key] === "function";
36
+ }
37
+ /**
38
+ * Batch resolver for multiple options at once
39
+ */
40
+ export function batchResolveMessages(messages, options, config) {
41
+ const resolver = createMessageResolver(messages, config);
42
+ return options.reduce((acc, option) => {
43
+ const key = config.keyExtractor(option);
44
+ acc[key] = resolver(option);
45
+ return acc;
46
+ }, {});
47
+ }
@@ -0,0 +1,77 @@
1
+ import { describe, expect, it, vi } from "vite-plus/test";
2
+ // Mock esm-env before importing the module
3
+ vi.mock("esm-env", () => ({ DEV: true }));
4
+ import { batchResolveMessages, createMessageResolver, hasMessage, } from "./message-resolver.ts";
5
+ describe("MessageResolver", () => {
6
+ const mockMessages = {
7
+ usd: () => "US Dollar",
8
+ eur: () => "Euro",
9
+ mxn: () => "Mexican Peso",
10
+ jpy: () => "Japanese Yen",
11
+ };
12
+ describe("createMessageResolver", () => {
13
+ it("should resolve a key via keyExtractor", () => {
14
+ const resolver = createMessageResolver(mockMessages, {
15
+ keyExtractor: (opt) => opt.code,
16
+ keyTransformer: (key) => key.toLowerCase(),
17
+ });
18
+ expect(resolver({ code: "USD" })).toBe("US Dollar");
19
+ expect(resolver({ code: "EUR" })).toBe("Euro");
20
+ });
21
+ it("should use untransformed key when no transformer provided", () => {
22
+ const resolver = createMessageResolver(mockMessages, {
23
+ keyExtractor: (opt) => opt.code,
24
+ });
25
+ // Without transformer, keys must match exactly
26
+ expect(resolver({ code: "usd" })).toBe("US Dollar");
27
+ });
28
+ it("should fall back to the raw key for missing translations", () => {
29
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
30
+ const resolver = createMessageResolver(mockMessages, {
31
+ keyExtractor: (opt) => opt.code,
32
+ keyTransformer: (key) => key.toLowerCase(),
33
+ });
34
+ const result = resolver({ code: "UNKNOWN" });
35
+ expect(result).toBe("UNKNOWN"); // falls back to original key
36
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("Missing translation"));
37
+ warnSpy.mockRestore();
38
+ });
39
+ });
40
+ describe("hasMessage", () => {
41
+ it("should return true for existing keys", () => {
42
+ expect(hasMessage(mockMessages, "usd")).toBe(true);
43
+ expect(hasMessage(mockMessages, "eur")).toBe(true);
44
+ });
45
+ it("should return false for missing keys", () => {
46
+ expect(hasMessage(mockMessages, "UNKNOWN")).toBe(false);
47
+ expect(hasMessage(mockMessages, "")).toBe(false);
48
+ });
49
+ });
50
+ describe("batchResolveMessages", () => {
51
+ it("should resolve all options at once", () => {
52
+ const options = [{ code: "USD" }, { code: "EUR" }, { code: "MXN" }];
53
+ const result = batchResolveMessages(mockMessages, options, {
54
+ keyExtractor: (opt) => opt.code,
55
+ keyTransformer: (key) => key.toLowerCase(),
56
+ });
57
+ expect(result).toEqual({
58
+ USD: "US Dollar",
59
+ EUR: "Euro",
60
+ MXN: "Mexican Peso",
61
+ });
62
+ });
63
+ it("should include fallback values for missing keys", () => {
64
+ vi.spyOn(console, "warn").mockImplementation(() => { });
65
+ const options = [{ code: "USD" }, { code: "XYZ" }];
66
+ const result = batchResolveMessages(mockMessages, options, {
67
+ keyExtractor: (opt) => opt.code,
68
+ keyTransformer: (key) => key.toLowerCase(),
69
+ });
70
+ expect(result).toEqual({
71
+ USD: "US Dollar",
72
+ XYZ: "XYZ", // fallback
73
+ });
74
+ vi.restoreAllMocks();
75
+ });
76
+ });
77
+ });
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Svelte action to teleport a DOM element to a different target (e.g. body)
3
+ */
4
+ export declare function portal(node: HTMLElement, target?: string | HTMLElement): {
5
+ update(newTarget: string | HTMLElement): void;
6
+ destroy(): void;
7
+ };
@@ -0,0 +1,32 @@
1
+ import { DEV } from "esm-env";
2
+ /**
3
+ * Svelte action to teleport a DOM element to a different target (e.g. body)
4
+ */
5
+ export function portal(node, target = "body") {
6
+ let targetNode;
7
+ let isTeleported = false;
8
+ function update(newTarget) {
9
+ if (typeof newTarget === "string") {
10
+ targetNode = document.querySelector(newTarget);
11
+ if (!targetNode && DEV) {
12
+ console.warn(`portal target selector "${newTarget}" not found in document.`);
13
+ }
14
+ }
15
+ else {
16
+ targetNode = newTarget;
17
+ }
18
+ if (targetNode) {
19
+ targetNode.appendChild(node);
20
+ isTeleported = true;
21
+ }
22
+ }
23
+ update(target);
24
+ return {
25
+ update,
26
+ destroy() {
27
+ if (isTeleported && node.parentNode) {
28
+ node.parentNode.removeChild(node);
29
+ }
30
+ },
31
+ };
32
+ }
@@ -0,0 +1,15 @@
1
+ export interface ShortcutStoreLike {
2
+ entries: {
3
+ enabled?: boolean;
4
+ keys: string;
5
+ when?: () => boolean;
6
+ handler: (event: KeyboardEvent) => void;
7
+ }[];
8
+ }
9
+ /**
10
+ * Svelte Action to listen for shortcuts registered in shortcutStore.
11
+ * Applied to the root element of the layout.
12
+ */
13
+ export declare function shortcutListener(_node: HTMLElement, shortcutStore: ShortcutStoreLike): {
14
+ destroy(): void;
15
+ };
@@ -0,0 +1,34 @@
1
+ import hotkeys from "hotkeys-js";
2
+ import { untrack } from "svelte";
3
+ /**
4
+ * Svelte Action to listen for shortcuts registered in shortcutStore.
5
+ * Applied to the root element of the layout.
6
+ */
7
+ export function shortcutListener(_node, shortcutStore) {
8
+ // Use $effect to reactively sync shortcuts
9
+ const cleanup = $effect.root(() => {
10
+ $effect(() => {
11
+ // Unbind everything first to ensure clean state
12
+ hotkeys.unbind();
13
+ // We read entries here, so this effect re-runs when entries change.
14
+ for (const entry of shortcutStore.entries) {
15
+ // @ts-ignore: enabled might not be on the interface but we check it anyway
16
+ if (entry.enabled === false)
17
+ continue;
18
+ hotkeys(entry.keys, "all", (event, _handler) => {
19
+ // Check "when" predicate if it exists
20
+ if (entry.when && !untrack(() => entry.when())) {
21
+ return;
22
+ }
23
+ entry.handler(event);
24
+ });
25
+ }
26
+ });
27
+ });
28
+ return {
29
+ destroy() {
30
+ cleanup();
31
+ hotkeys.unbind();
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Application metadata interface
3
+ */
4
+ export interface AppData {
5
+ name: string;
6
+ version: string;
7
+ description: string;
8
+ author: string;
9
+ repository?: string;
10
+ license?: string;
11
+ homepage?: string;
12
+ }
13
+ /**
14
+ * App Store
15
+ * Manages application metadata and identity
16
+ */
17
+ export declare class AppStore {
18
+ #private;
19
+ name: string;
20
+ version: string;
21
+ description: string;
22
+ author: string;
23
+ repository: string;
24
+ license: string;
25
+ homepage: string;
26
+ customIcons: Record<string, string>;
27
+ /**
28
+ * Initialize app store with metadata.
29
+ */
30
+ init(data: Partial<AppData>): void;
31
+ /**
32
+ * @internal Test-only. Resets initialization guard.
33
+ */
34
+ __reset(): void;
35
+ /**
36
+ * Get full app information object
37
+ */
38
+ get info(): AppData;
39
+ /**
40
+ * Registers custom SVG icons to be available globally in the Icon component
41
+ */
42
+ registerIcons(icons: Record<string, string>): void;
43
+ }
44
+ export declare function createAppStore(): AppStore;
45
+ export declare function getAppStore(): AppStore;
@@ -0,0 +1,78 @@
1
+ // src/kernel/src/context/app.svelte.ts
2
+ import { getContext } from "svelte";
3
+ import { RUNE_LAB_CONTEXT } from "./context.ts";
4
+ import { DEV } from "esm-env";
5
+ /**
6
+ * App Store
7
+ * Manages application metadata and identity
8
+ */
9
+ export class AppStore {
10
+ // State
11
+ name = $state("Rune Lab");
12
+ version = $state("0.0.1");
13
+ description = $state("Modern toolkit for Svelte 5 Runes");
14
+ author = $state("Yrrrrrf");
15
+ repository = $state("https://github.com/Yrrrrrf/rune-lab");
16
+ license = $state("MIT");
17
+ homepage = $state("https://jsr.io/@yrrrrrf/rune-lab");
18
+ customIcons = $state({});
19
+ #initialized = false;
20
+ /**
21
+ * Initialize app store with metadata.
22
+ */
23
+ init(data) {
24
+ if (this.#initialized) {
25
+ if (DEV) {
26
+ console.warn("AppStore.init() called multiple times. Ignoring subsequent calls.", "Overwritten properties would have been:", data);
27
+ }
28
+ return;
29
+ }
30
+ if (data.name)
31
+ this.name = data.name;
32
+ if (data.version)
33
+ this.version = data.version;
34
+ if (data.description)
35
+ this.description = data.description;
36
+ if (data.author)
37
+ this.author = data.author;
38
+ if (data.repository)
39
+ this.repository = data.repository;
40
+ if (data.license)
41
+ this.license = data.license;
42
+ if (data.homepage)
43
+ this.homepage = data.homepage;
44
+ this.#initialized = true;
45
+ }
46
+ /**
47
+ * @internal Test-only. Resets initialization guard.
48
+ */
49
+ __reset() {
50
+ this.#initialized = false;
51
+ }
52
+ /**
53
+ * Get full app information object
54
+ */
55
+ get info() {
56
+ return {
57
+ name: this.name,
58
+ version: this.version,
59
+ description: this.description,
60
+ author: this.author,
61
+ repository: this.repository,
62
+ license: this.license,
63
+ homepage: this.homepage,
64
+ };
65
+ }
66
+ /**
67
+ * Registers custom SVG icons to be available globally in the Icon component
68
+ */
69
+ registerIcons(icons) {
70
+ this.customIcons = { ...this.customIcons, ...icons };
71
+ }
72
+ }
73
+ export function createAppStore() {
74
+ return new AppStore();
75
+ }
76
+ export function getAppStore() {
77
+ return getContext(RUNE_LAB_CONTEXT.app);
78
+ }
@@ -0,0 +1,15 @@
1
+ export declare const RUNE_LAB_CONTEXT: {
2
+ app: symbol;
3
+ api: symbol;
4
+ toast: symbol;
5
+ theme: symbol;
6
+ language: symbol;
7
+ currency: symbol;
8
+ shortcut: symbol;
9
+ layout: symbol;
10
+ commands: symbol;
11
+ persistence: symbol;
12
+ cart: symbol;
13
+ session: symbol;
14
+ exchangeRate: symbol;
15
+ };
@@ -0,0 +1,16 @@
1
+ // src/lib/context.ts
2
+ export const RUNE_LAB_CONTEXT = {
3
+ app: Symbol("rl:app"),
4
+ api: Symbol("rl:api"),
5
+ toast: Symbol("rl:toast"),
6
+ theme: Symbol("rl:theme"),
7
+ language: Symbol("rl:language"),
8
+ currency: Symbol("rl:currency"),
9
+ shortcut: Symbol("rl:shortcut"),
10
+ layout: Symbol("rl:layout"),
11
+ commands: Symbol("rl:commands"),
12
+ persistence: Symbol("rl:persistence"),
13
+ cart: Symbol("rl:cart"),
14
+ session: Symbol("rl:session"),
15
+ exchangeRate: Symbol("rl:exchange-rate"),
16
+ };
@@ -0,0 +1,60 @@
1
+ import type { ConfigStore } from "../persistence/createConfigStore.svelte.ts";
2
+ import type { Command, Currency, Language, Theme, Toast, ToastType } from "./types.ts";
3
+ import type { LayoutStore } from "../../../runes/layout/src/store.svelte.ts";
4
+ import type { ShortcutStore } from "../../../runes/palettes/src/shortcuts/store.svelte.ts";
5
+ /**
6
+ * Common store interfaces
7
+ */
8
+ export interface ICommandStore {
9
+ commands: Command[];
10
+ register(command: Command): void;
11
+ unregister(id: string): void;
12
+ search(query: string, parentId?: string): Command[];
13
+ }
14
+ export interface IToastStore {
15
+ toasts: Toast[];
16
+ send(message: string, type?: ToastType, duration?: number): void;
17
+ success(msg: string): void;
18
+ error(msg: string): void;
19
+ warn(msg: string): void;
20
+ info(msg: string): void;
21
+ dismiss(id: string): void;
22
+ }
23
+ export interface ICurrencyStore extends ConfigStore<Currency> {
24
+ canConvert: boolean;
25
+ convertAmount(amount: number, fromCode: string, toCode?: string): number;
26
+ addCurrency(meta: Currency, dineroDef?: unknown): void;
27
+ }
28
+ /**
29
+ * Store context accessors
30
+ */
31
+ export declare function getLayoutStore(): LayoutStore;
32
+ export declare function getLanguageStore(): ConfigStore<Language>;
33
+ export declare function getThemeStore(): ConfigStore<Theme>;
34
+ export declare function getShortcutStore(): ShortcutStore;
35
+ export declare function getCommandStore(): ICommandStore;
36
+ export declare function getToastStore(): IToastStore;
37
+ export declare function getCurrencyStore(): ICurrencyStore;
38
+ /**
39
+ * Standard layout shortcuts
40
+ */
41
+ export declare const LAYOUT_SHORTCUTS: {
42
+ readonly TOGGLE_NAV: {
43
+ readonly id: "layout:toggle-nav";
44
+ readonly keys: "ctrl+b";
45
+ readonly label: "Toggle Sidebar";
46
+ readonly category: "Layout";
47
+ };
48
+ readonly TOGGLE_DETAIL: {
49
+ readonly id: "layout:toggle-detail";
50
+ readonly keys: "ctrl+alt+b";
51
+ readonly label: "Toggle Detail Panel";
52
+ readonly category: "Layout";
53
+ };
54
+ readonly OPEN_SHORTCUTS: {
55
+ readonly id: "layout:open-shortcuts";
56
+ readonly keys: "ctrl+/";
57
+ readonly label: "Show Shortcuts";
58
+ readonly category: "Layout";
59
+ };
60
+ };
@@ -0,0 +1,49 @@
1
+ import { getContext } from "svelte";
2
+ import { RUNE_LAB_CONTEXT } from "./context.ts";
3
+ /**
4
+ * Store context accessors
5
+ */
6
+ export function getLayoutStore() {
7
+ return getContext(RUNE_LAB_CONTEXT.layout);
8
+ }
9
+ export function getLanguageStore() {
10
+ return getContext(RUNE_LAB_CONTEXT.language);
11
+ }
12
+ export function getThemeStore() {
13
+ return getContext(RUNE_LAB_CONTEXT.theme);
14
+ }
15
+ export function getShortcutStore() {
16
+ return getContext(RUNE_LAB_CONTEXT.shortcut);
17
+ }
18
+ export function getCommandStore() {
19
+ return getContext(RUNE_LAB_CONTEXT.commands);
20
+ }
21
+ export function getToastStore() {
22
+ return getContext(RUNE_LAB_CONTEXT.toast);
23
+ }
24
+ export function getCurrencyStore() {
25
+ return getContext(RUNE_LAB_CONTEXT.currency);
26
+ }
27
+ /**
28
+ * Standard layout shortcuts
29
+ */
30
+ export const LAYOUT_SHORTCUTS = {
31
+ TOGGLE_NAV: {
32
+ id: "layout:toggle-nav",
33
+ keys: "ctrl+b",
34
+ label: "Toggle Sidebar",
35
+ category: "Layout",
36
+ },
37
+ TOGGLE_DETAIL: {
38
+ id: "layout:toggle-detail",
39
+ keys: "ctrl+alt+b",
40
+ label: "Toggle Detail Panel",
41
+ category: "Layout",
42
+ },
43
+ OPEN_SHORTCUTS: {
44
+ id: "layout:open-shortcuts",
45
+ keys: "ctrl+/",
46
+ label: "Show Shortcuts",
47
+ category: "Layout",
48
+ },
49
+ };
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Layout configuration
3
+ */
4
+ export interface LayoutZone {
5
+ id: string;
6
+ component?: unknown;
7
+ storeKey?: string;
8
+ width?: string;
9
+ collapsible?: boolean;
10
+ conditional?: string;
11
+ minWidth?: string;
12
+ position?: "start" | "end";
13
+ }
14
+ export type LayoutConfig = LayoutZone[];
15
+ /**
16
+ * Currency
17
+ */
18
+ export interface Currency {
19
+ code: string;
20
+ symbol: string;
21
+ decimals: number;
22
+ }
23
+ /**
24
+ * Navigation & Workspace items
25
+ */
26
+ export interface WorkspaceItem {
27
+ id: string;
28
+ icon: string;
29
+ label: string;
30
+ badge?: string | number;
31
+ href?: string;
32
+ onClick?: () => void;
33
+ }
34
+ export interface NavigationItem {
35
+ id: string;
36
+ label: string;
37
+ icon?: string;
38
+ href?: string;
39
+ badge?: string | number;
40
+ isActive?: boolean;
41
+ onClick?: () => void;
42
+ children?: NavigationItem[];
43
+ }
44
+ export interface NavigationSection {
45
+ id: string;
46
+ title: string;
47
+ items: NavigationItem[];
48
+ }
49
+ /**
50
+ * i18n
51
+ */
52
+ export interface Language {
53
+ code: string;
54
+ flag?: string;
55
+ }
56
+ /**
57
+ * Theme
58
+ */
59
+ export interface Theme {
60
+ name: string;
61
+ icon?: string;
62
+ }
63
+ /**
64
+ * Shortcuts
65
+ */
66
+ export interface ShortcutConfig {
67
+ id: string;
68
+ keys: string;
69
+ handler: (event: KeyboardEvent) => void;
70
+ when?: () => boolean;
71
+ label?: string;
72
+ category?: string;
73
+ scope?: "global" | "layout" | `panel:${string}`;
74
+ }
75
+ export interface ShortcutEntry extends ShortcutConfig {
76
+ enabled?: boolean;
77
+ }
78
+ /**
79
+ * Commands
80
+ */
81
+ export interface Command {
82
+ id: string;
83
+ label: string;
84
+ category?: string;
85
+ icon?: string;
86
+ action?: () => void;
87
+ children?: Command[];
88
+ }
89
+ /**
90
+ * Toasts
91
+ */
92
+ export type ToastType = "info" | "success" | "warning" | "error";
93
+ export interface Toast {
94
+ id: string;
95
+ message: string;
96
+ type: ToastType;
97
+ duration?: number;
98
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import { getAppStore, getCommandStore, getCurrencyStore, getLanguageStore, getLayoutStore, getShortcutStore, getThemeStore, getToastStore } from "../../../mod.ts";
2
+ export interface RuneLabContext {
3
+ app: ReturnType<typeof getAppStore>;
4
+ toast: ReturnType<typeof getToastStore>;
5
+ theme: ReturnType<typeof getThemeStore>;
6
+ language: ReturnType<typeof getLanguageStore>;
7
+ currency: ReturnType<typeof getCurrencyStore>;
8
+ shortcut: ReturnType<typeof getShortcutStore>;
9
+ layout: ReturnType<typeof getLayoutStore>;
10
+ commands: ReturnType<typeof getCommandStore>;
11
+ }
12
+ /**
13
+ * Retrieves all Rune Lab stores from the Svelte context tree.
14
+ * Must be called during component initialization (in the `<script>` block).
15
+ */
16
+ export declare function useRuneLab(): RuneLabContext;