rune-lab 0.4.2-beta.2 → 0.4.2-beta.3
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/package.json +29 -2
- package/src/RuneProvider.svelte.d.ts +32 -0
- package/src/{lib/i18n/message-resolver.ts → i18n/message-resolver.d.ts} +9 -47
- package/src/i18n/message-resolver.js +49 -0
- package/src/{lib/i18n/message-resolver.test.ts → i18n/message-resolver.test.js} +3 -23
- package/src/kernel/src/actions/portal.d.ts +10 -0
- package/src/{lib/kernel/src/actions/portal.ts → kernel/src/actions/portal.js} +3 -11
- package/src/kernel/src/actions/shortcut-listener.d.ts +18 -0
- package/src/{lib/kernel/src/actions/shortcut-listener.ts → kernel/src/actions/shortcut-listener.js} +5 -20
- package/src/kernel/src/context/app.svelte.d.ts +45 -0
- package/src/kernel/src/context/app.svelte.js +89 -0
- package/src/kernel/src/context/context.d.ts +15 -0
- package/src/{lib/kernel/src/context/context.ts → kernel/src/context/context.js} +2 -17
- package/src/kernel/src/context/stores.svelte.d.ts +67 -0
- package/src/kernel/src/context/stores.svelte.js +49 -0
- package/src/{lib/kernel/src/context/types.ts → kernel/src/context/types.d.ts} +0 -12
- package/src/kernel/src/context/types.js +1 -0
- package/src/{lib/kernel/src/context/useRuneLab.ts → kernel/src/context/useRuneLab.d.ts} +1 -14
- package/src/kernel/src/context/useRuneLab.js +26 -0
- package/src/kernel/src/mod.js +13 -0
- package/src/kernel/src/persistence/createConfigStore.svelte.d.ts +30 -0
- package/src/kernel/src/persistence/createConfigStore.svelte.js +76 -0
- package/src/kernel/src/persistence/drivers.d.ts +12 -0
- package/src/kernel/src/persistence/drivers.js +87 -0
- package/src/{lib/kernel/src/persistence/drivers.test.ts → kernel/src/persistence/drivers.test.js} +1 -17
- package/src/kernel/src/persistence/provider.d.ts +30 -0
- package/src/{lib/kernel/src/persistence/provider.ts → kernel/src/persistence/provider.js} +4 -17
- package/src/{lib/kernel/src/persistence/provider.test.ts → kernel/src/persistence/provider.test.js} +2 -9
- package/src/{lib/kernel/src/persistence/types.ts → kernel/src/persistence/types.d.ts} +0 -2
- package/src/kernel/src/persistence/types.js +2 -0
- package/src/kernel/src/persistence/usePersistence.d.ts +2 -0
- package/src/kernel/src/persistence/usePersistence.js +5 -0
- package/src/{lib/kernel/src/registry/mod.ts → kernel/src/registry/mod.d.ts} +14 -116
- package/src/kernel/src/registry/mod.js +140 -0
- package/src/{lib/kernel/src/registry/registry.test.ts → kernel/src/registry/registry.test.js} +17 -58
- package/src/{lib/kernel/src/tokens/props.ts → kernel/src/tokens/props.d.ts} +5 -32
- package/src/kernel/src/tokens/props.js +35 -0
- package/src/mod.d.ts +5 -0
- package/src/{lib/mod.ts → mod.js} +0 -2
- package/src/{lib/runes/layout/src/APP_CONFIGURATIONS.ts → runes/layout/src/APP_CONFIGURATIONS.d.ts} +1 -28
- package/src/runes/layout/src/APP_CONFIGURATIONS.js +38 -0
- package/src/runes/layout/src/AppSettingSelector.svelte.d.ts +18 -0
- package/src/runes/layout/src/ConnectedNavigationPanel.svelte.d.ts +18 -0
- package/src/runes/layout/src/ConnectedWorkspaceStrip.svelte.d.ts +18 -0
- package/src/runes/layout/src/ContentArea.svelte.d.ts +18 -0
- package/src/runes/layout/src/DetailPanel.svelte.d.ts +18 -0
- package/src/runes/layout/src/Icon.svelte.d.ts +15 -0
- package/src/runes/layout/src/LanguageSelector.svelte.d.ts +18 -0
- package/src/runes/layout/src/NavigationPanel.svelte.d.ts +18 -0
- package/src/runes/layout/src/ResourceSelector.svelte.d.ts +21 -0
- package/src/runes/layout/src/ThemeSelector.svelte.d.ts +18 -0
- package/src/runes/layout/src/WorkspaceLayout.svelte.d.ts +47 -0
- package/src/runes/layout/src/WorkspaceStrip.svelte.d.ts +18 -0
- package/src/{lib/runes/layout/src/connection-factory.ts → runes/layout/src/connection-factory.d.ts} +7 -41
- package/src/runes/layout/src/connection-factory.js +58 -0
- package/src/runes/layout/src/language.svelte.d.ts +50 -0
- package/src/{lib/runes/layout/src/language.svelte.ts → runes/layout/src/language.svelte.js} +9 -23
- package/src/runes/layout/src/mod.d.ts +22 -0
- package/src/{lib/runes/layout/src/mod.ts → runes/layout/src/mod.js} +14 -18
- package/src/runes/layout/src/store.svelte.d.ts +37 -0
- package/src/{lib/runes/layout/src/store.svelte.ts → runes/layout/src/store.svelte.js} +32 -57
- package/src/runes/layout/src/theme.svelte.d.ts +6 -0
- package/src/{lib/runes/layout/src/theme.svelte.ts → runes/layout/src/theme.svelte.js} +5 -15
- package/src/runes/layout/src/types.d.ts +6 -0
- package/src/{lib/runes/layout/src/types.ts → runes/layout/src/types.js} +0 -3
- package/src/runes/palettes/src/commands/CommandPalette.svelte.d.ts +18 -0
- package/src/runes/palettes/src/commands/mod.js +2 -0
- package/src/runes/palettes/src/commands/store.svelte.d.ts +33 -0
- package/src/runes/palettes/src/commands/store.svelte.js +63 -0
- package/src/runes/palettes/src/mod.d.ts +9 -0
- package/src/{lib/runes/palettes/src/mod.ts → runes/palettes/src/mod.js} +5 -9
- package/src/runes/palettes/src/notifications/NotificationBell.svelte.d.ts +26 -0
- package/src/runes/palettes/src/notifications/Toaster.svelte.d.ts +15 -0
- package/src/runes/palettes/src/notifications/bridge.d.ts +33 -0
- package/src/{lib/runes/palettes/src/notifications/bridge.ts → runes/palettes/src/notifications/bridge.js} +10 -22
- package/src/runes/palettes/src/notifications/mod.js +4 -0
- package/src/runes/palettes/src/notifications/store.svelte.d.ts +23 -0
- package/src/{lib/runes/palettes/src/notifications/store.svelte.ts → runes/palettes/src/notifications/store.svelte.js} +9 -24
- package/src/runes/palettes/src/shortcuts/ShortcutPalette.svelte.d.ts +23 -0
- package/src/runes/palettes/src/shortcuts/mod.js +4 -0
- package/src/runes/palettes/src/shortcuts/store.svelte.d.ts +37 -0
- package/src/{lib/runes/palettes/src/shortcuts/store.svelte.ts → runes/palettes/src/shortcuts/store.svelte.js} +35 -34
- package/src/runes/palettes/src/shortcuts/types.d.ts +1 -0
- package/src/{lib/runes/palettes/src/shortcuts/types.ts → runes/palettes/src/shortcuts/types.js} +1 -2
- package/src/runes/palettes/src/shortcuts/useShortcuts.d.ts +32 -0
- package/src/{lib/runes/palettes/src/shortcuts/useShortcuts.ts → runes/palettes/src/shortcuts/useShortcuts.js} +7 -16
- package/src/runes/plugins/money/src/CurrencySelector.svelte.d.ts +18 -0
- package/src/runes/plugins/money/src/MoneyDisplay.svelte.d.ts +18 -0
- package/src/runes/plugins/money/src/MoneyInput.svelte.d.ts +49 -0
- package/src/runes/plugins/money/src/currency.svelte.d.ts +29 -0
- package/src/{lib/runes/plugins/money/src/currency.svelte.ts → runes/plugins/money/src/currency.svelte.js} +19 -42
- package/src/{lib/runes/plugins/money/src/currency.test.ts → runes/plugins/money/src/currency.test.js} +2 -10
- package/src/runes/plugins/money/src/exchange-rate.svelte.d.ts +44 -0
- package/src/{lib/runes/plugins/money/src/exchange-rate.svelte.ts → runes/plugins/money/src/exchange-rate.svelte.js} +43 -49
- package/src/{lib/runes/plugins/money/src/exchange-rate.test.ts → runes/plugins/money/src/exchange-rate.test.js} +2 -23
- package/src/runes/plugins/money/src/mod.d.ts +13 -0
- package/src/{lib/runes/plugins/money/src/mod.ts → runes/plugins/money/src/mod.js} +10 -34
- package/src/runes/plugins/money/src/money-primitive.d.ts +106 -0
- package/src/{lib/runes/plugins/money/src/money-primitive.ts → runes/plugins/money/src/money-primitive.js} +26 -68
- package/src/{lib/runes/plugins/money/src/money-primitive.test.ts → runes/plugins/money/src/money-primitive.test.js} +0 -40
- package/src/runes/plugins/money/src/money.d.ts +170 -0
- package/src/{lib/runes/plugins/money/src/money.ts → runes/plugins/money/src/money.js} +32 -129
- package/src/{lib/runes/plugins/money/src/money.test.ts → runes/plugins/money/src/money.test.js} +0 -29
- package/src/runes/plugins/money/src/strategies.d.ts +55 -0
- package/src/{lib/runes/plugins/money/src/strategies.ts → runes/plugins/money/src/strategies.js} +12 -27
- package/src/{lib/runes/plugins/money/src/strategies.test.ts → runes/plugins/money/src/strategies.test.js} +2 -30
- package/src/runes/plugins/money/src/types.js +21 -0
- package/src/runes/plugins/money/src/useMoney.d.ts +69 -0
- package/src/{lib/runes/plugins/money/src/useMoney.ts → runes/plugins/money/src/useMoney.js} +12 -131
- package/src/runes/plugins/money/src/useMoneyFilter.d.ts +23 -0
- package/src/{lib/runes/plugins/money/src/useMoneyFilter.ts → runes/plugins/money/src/useMoneyFilter.js} +5 -40
- package/.gitignore +0 -12
- package/deno.json +0 -50
- package/justfile +0 -5
- package/scripts/build_pkg.ts +0 -57
- package/scripts/ci.just +0 -26
- package/scripts/deploy.just +0 -26
- package/scripts/dev.just +0 -4
- package/scripts/inject.just +0 -72
- package/src/app.d.ts +0 -13
- package/src/app.html +0 -12
- package/src/lib/kernel/src/context/app.svelte.ts +0 -98
- package/src/lib/kernel/src/context/stores.svelte.ts +0 -96
- package/src/lib/kernel/src/persistence/createConfigStore.svelte.ts +0 -120
- package/src/lib/kernel/src/persistence/drivers.ts +0 -77
- package/src/lib/kernel/src/persistence/usePersistence.ts +0 -9
- package/src/lib/runes/palettes/src/commands/store.svelte.ts +0 -80
- package/src/routes/+page.svelte +0 -3
- package/tsconfig.json +0 -41
- package/vite.config.ts +0 -22
- /package/src/{lib/RuneProvider.svelte → RuneProvider.svelte} +0 -0
- /package/src/{lib/i18n → i18n}/project.inlang/settings.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/ar.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/de.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/en.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/es.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/fr.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/hi.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/it.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/ja.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/ko.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/pt.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/ru.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/vi.json +0 -0
- /package/src/{lib/i18n → i18n}/translations/zh.json +0 -0
- /package/src/{lib/kernel → kernel}/deno.json +0 -0
- /package/src/{lib/kernel/src/mod.ts → kernel/src/mod.d.ts} +0 -0
- /package/src/{lib/runes → runes}/layout/deno.json +0 -0
- /package/src/{lib/runes → runes}/layout/src/AppSettingSelector.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/ConnectedNavigationPanel.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/ConnectedWorkspaceStrip.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/ContentArea.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/DetailPanel.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/Icon.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/LanguageSelector.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/NavigationPanel.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/ResourceSelector.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/ThemeSelector.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/WorkspaceLayout.svelte +0 -0
- /package/src/{lib/runes → runes}/layout/src/WorkspaceStrip.svelte +0 -0
- /package/src/{lib/runes → runes}/palettes/deno.json +0 -0
- /package/src/{lib/runes → runes}/palettes/src/commands/CommandPalette.svelte +0 -0
- /package/src/{lib/runes/palettes/src/commands/mod.ts → runes/palettes/src/commands/mod.d.ts} +0 -0
- /package/src/{lib/runes → runes}/palettes/src/notifications/NotificationBell.svelte +0 -0
- /package/src/{lib/runes → runes}/palettes/src/notifications/Toaster.svelte +0 -0
- /package/src/{lib/runes/palettes/src/notifications/mod.ts → runes/palettes/src/notifications/mod.d.ts} +0 -0
- /package/src/{lib/runes → runes}/palettes/src/shortcuts/ShortcutPalette.svelte +0 -0
- /package/src/{lib/runes/palettes/src/shortcuts/mod.ts → runes/palettes/src/shortcuts/mod.d.ts} +0 -0
- /package/src/{lib/runes → runes}/plugins/money/deno.json +0 -0
- /package/src/{lib/runes → runes}/plugins/money/src/CurrencySelector.svelte +0 -0
- /package/src/{lib/runes → runes}/plugins/money/src/MoneyDisplay.svelte +0 -0
- /package/src/{lib/runes → runes}/plugins/money/src/MoneyInput.svelte +0 -0
- /package/src/{lib/runes/plugins/money/src/types.ts → runes/plugins/money/src/types.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rune-lab",
|
|
3
|
-
"version": "0.4.2-beta.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.4.2-beta.3",
|
|
4
|
+
"description": "Modern toolkit for Svelte 5 Runes applications.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Yrrrrrf/rune-lab.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./src/mod.d.ts",
|
|
14
|
+
"default": "./src/mod.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"svelte": "^5.55.0",
|
|
19
|
+
"@sveltejs/kit": "^2.55.0",
|
|
20
|
+
"@inlang/paraglide-js": "^2.15.1",
|
|
21
|
+
"hotkeys-js": "^4.0.2",
|
|
22
|
+
"dinero.js": "^2.0.2",
|
|
23
|
+
"esm-env": "^1.2.2"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"svelte",
|
|
27
|
+
"svelte-5",
|
|
28
|
+
"runes",
|
|
29
|
+
"ui",
|
|
30
|
+
"components"
|
|
31
|
+
]
|
|
5
32
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
};
|
|
23
|
+
export type RuneProviderProps = typeof __propDef.props;
|
|
24
|
+
export type RuneProviderEvents = typeof __propDef.events;
|
|
25
|
+
export type RuneProviderSlots = typeof __propDef.slots;
|
|
26
|
+
export default class RuneProvider extends SvelteComponentTyped<
|
|
27
|
+
RuneProviderProps,
|
|
28
|
+
RuneProviderEvents,
|
|
29
|
+
RuneProviderSlots
|
|
30
|
+
> {
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -1,29 +1,22 @@
|
|
|
1
|
-
// sdk/devtools/src/patterns/message-resolver.ts
|
|
2
|
-
import { DEV } from "esm-env";
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* Dynamic i18n Message Resolver Pattern
|
|
6
3
|
*
|
|
7
4
|
* Enables dynamic message function calls for config selectors.
|
|
8
5
|
* Creates a resolver that dynamically looks up and calls message functions.
|
|
9
6
|
*/
|
|
10
|
-
|
|
11
7
|
type MessageBundle = Record<string, (...args: unknown[]) => string>;
|
|
12
|
-
|
|
13
8
|
interface MessageResolverConfig<T> {
|
|
14
9
|
/**
|
|
15
10
|
* Function to extract the message key from an option
|
|
16
11
|
* @example (currency) => currency.code // "USD"
|
|
17
12
|
*/
|
|
18
13
|
keyExtractor: (option: T) => string;
|
|
19
|
-
|
|
20
14
|
/**
|
|
21
15
|
* Optional transformer for the key before message lookup
|
|
22
16
|
* @example (key) => key.toLowerCase() // "USD" -> "usd"
|
|
23
17
|
*/
|
|
24
18
|
keyTransformer?: (key: string) => string;
|
|
25
19
|
}
|
|
26
|
-
|
|
27
20
|
/**
|
|
28
21
|
* Creates a message resolver function for dynamic i18n lookups
|
|
29
22
|
*
|
|
@@ -36,54 +29,23 @@ interface MessageResolverConfig<T> {
|
|
|
36
29
|
* getCurrencyLabel({ code: "EUR", symbol: "€" }); // "Euro"
|
|
37
30
|
* ```
|
|
38
31
|
*/
|
|
39
|
-
export function createMessageResolver<T>(
|
|
32
|
+
export declare function createMessageResolver<T>(
|
|
40
33
|
messages: MessageBundle,
|
|
41
34
|
config: MessageResolverConfig<T>,
|
|
42
|
-
)
|
|
43
|
-
return (option: T): string => {
|
|
44
|
-
const key = config.keyExtractor(option);
|
|
45
|
-
const transformedKey = config.keyTransformer
|
|
46
|
-
? config.keyTransformer(key)
|
|
47
|
-
: key;
|
|
48
|
-
|
|
49
|
-
const messageFn = messages[transformedKey];
|
|
50
|
-
|
|
51
|
-
if (!messageFn || typeof messageFn !== "function") {
|
|
52
|
-
if (DEV) {
|
|
53
|
-
console.warn(
|
|
54
|
-
`[MessageResolver] Missing translation for key: "${transformedKey}"`,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
return key; // Fallback to key
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return messageFn();
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
35
|
+
): (option: T) => string;
|
|
64
36
|
/**
|
|
65
37
|
* Type guard to check if a message key exists
|
|
66
38
|
*/
|
|
67
|
-
export function hasMessage(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
39
|
+
export declare function hasMessage(
|
|
40
|
+
messages: MessageBundle,
|
|
41
|
+
key: string,
|
|
42
|
+
): boolean;
|
|
71
43
|
/**
|
|
72
44
|
* Batch resolver for multiple options at once
|
|
73
45
|
*/
|
|
74
|
-
export function batchResolveMessages<T>(
|
|
46
|
+
export declare function batchResolveMessages<T>(
|
|
75
47
|
messages: MessageBundle,
|
|
76
48
|
options: T[],
|
|
77
49
|
config: MessageResolverConfig<T>,
|
|
78
|
-
): Record<string, string
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return options.reduce(
|
|
82
|
-
(acc, option) => {
|
|
83
|
-
const key = config.keyExtractor(option);
|
|
84
|
-
acc[key] = resolver(option);
|
|
85
|
-
return acc;
|
|
86
|
-
},
|
|
87
|
-
{} as Record<string, string>,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
50
|
+
): Record<string, string>;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
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(
|
|
25
|
+
`[MessageResolver] Missing translation for key: "${transformedKey}"`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return key; // Fallback to key
|
|
29
|
+
}
|
|
30
|
+
return messageFn();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Type guard to check if a message key exists
|
|
35
|
+
*/
|
|
36
|
+
export function hasMessage(messages, key) {
|
|
37
|
+
return key in messages && typeof messages[key] === "function";
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Batch resolver for multiple options at once
|
|
41
|
+
*/
|
|
42
|
+
export function batchResolveMessages(messages, options, config) {
|
|
43
|
+
const resolver = createMessageResolver(messages, config);
|
|
44
|
+
return options.reduce((acc, option) => {
|
|
45
|
+
const key = config.keyExtractor(option);
|
|
46
|
+
acc[key] = resolver(option);
|
|
47
|
+
return acc;
|
|
48
|
+
}, {});
|
|
49
|
+
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vite-plus/test";
|
|
2
|
-
|
|
3
2
|
// Mock esm-env before importing the module
|
|
4
3
|
vi.mock("esm-env", () => ({ DEV: true }));
|
|
5
|
-
|
|
6
4
|
import {
|
|
7
5
|
batchResolveMessages,
|
|
8
6
|
createMessageResolver,
|
|
9
7
|
hasMessage,
|
|
10
8
|
} from "./message-resolver.ts";
|
|
11
|
-
|
|
12
9
|
describe("MessageResolver", () => {
|
|
13
10
|
const mockMessages = {
|
|
14
11
|
usd: () => "US Dollar",
|
|
@@ -16,87 +13,70 @@ describe("MessageResolver", () => {
|
|
|
16
13
|
mxn: () => "Mexican Peso",
|
|
17
14
|
jpy: () => "Japanese Yen",
|
|
18
15
|
};
|
|
19
|
-
|
|
20
16
|
describe("createMessageResolver", () => {
|
|
21
17
|
it("should resolve a key via keyExtractor", () => {
|
|
22
|
-
const resolver = createMessageResolver
|
|
18
|
+
const resolver = createMessageResolver(mockMessages, {
|
|
23
19
|
keyExtractor: (opt) => opt.code,
|
|
24
20
|
keyTransformer: (key) => key.toLowerCase(),
|
|
25
21
|
});
|
|
26
|
-
|
|
27
22
|
expect(resolver({ code: "USD" })).toBe("US Dollar");
|
|
28
23
|
expect(resolver({ code: "EUR" })).toBe("Euro");
|
|
29
24
|
});
|
|
30
|
-
|
|
31
25
|
it("should use untransformed key when no transformer provided", () => {
|
|
32
|
-
const resolver = createMessageResolver
|
|
26
|
+
const resolver = createMessageResolver(mockMessages, {
|
|
33
27
|
keyExtractor: (opt) => opt.code,
|
|
34
28
|
});
|
|
35
|
-
|
|
36
29
|
// Without transformer, keys must match exactly
|
|
37
30
|
expect(resolver({ code: "usd" })).toBe("US Dollar");
|
|
38
31
|
});
|
|
39
|
-
|
|
40
32
|
it("should fall back to the raw key for missing translations", () => {
|
|
41
33
|
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
42
|
-
|
|
43
|
-
const resolver = createMessageResolver<{ code: string }>(mockMessages, {
|
|
34
|
+
const resolver = createMessageResolver(mockMessages, {
|
|
44
35
|
keyExtractor: (opt) => opt.code,
|
|
45
36
|
keyTransformer: (key) => key.toLowerCase(),
|
|
46
37
|
});
|
|
47
|
-
|
|
48
38
|
const result = resolver({ code: "UNKNOWN" });
|
|
49
39
|
expect(result).toBe("UNKNOWN"); // falls back to original key
|
|
50
40
|
expect(warnSpy).toHaveBeenCalledWith(
|
|
51
41
|
expect.stringContaining("Missing translation"),
|
|
52
42
|
);
|
|
53
|
-
|
|
54
43
|
warnSpy.mockRestore();
|
|
55
44
|
});
|
|
56
45
|
});
|
|
57
|
-
|
|
58
46
|
describe("hasMessage", () => {
|
|
59
47
|
it("should return true for existing keys", () => {
|
|
60
48
|
expect(hasMessage(mockMessages, "usd")).toBe(true);
|
|
61
49
|
expect(hasMessage(mockMessages, "eur")).toBe(true);
|
|
62
50
|
});
|
|
63
|
-
|
|
64
51
|
it("should return false for missing keys", () => {
|
|
65
52
|
expect(hasMessage(mockMessages, "UNKNOWN")).toBe(false);
|
|
66
53
|
expect(hasMessage(mockMessages, "")).toBe(false);
|
|
67
54
|
});
|
|
68
55
|
});
|
|
69
|
-
|
|
70
56
|
describe("batchResolveMessages", () => {
|
|
71
57
|
it("should resolve all options at once", () => {
|
|
72
58
|
const options = [{ code: "USD" }, { code: "EUR" }, { code: "MXN" }];
|
|
73
|
-
|
|
74
59
|
const result = batchResolveMessages(mockMessages, options, {
|
|
75
60
|
keyExtractor: (opt) => opt.code,
|
|
76
61
|
keyTransformer: (key) => key.toLowerCase(),
|
|
77
62
|
});
|
|
78
|
-
|
|
79
63
|
expect(result).toEqual({
|
|
80
64
|
USD: "US Dollar",
|
|
81
65
|
EUR: "Euro",
|
|
82
66
|
MXN: "Mexican Peso",
|
|
83
67
|
});
|
|
84
68
|
});
|
|
85
|
-
|
|
86
69
|
it("should include fallback values for missing keys", () => {
|
|
87
70
|
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
88
|
-
|
|
89
71
|
const options = [{ code: "USD" }, { code: "XYZ" }];
|
|
90
72
|
const result = batchResolveMessages(mockMessages, options, {
|
|
91
73
|
keyExtractor: (opt) => opt.code,
|
|
92
74
|
keyTransformer: (key) => key.toLowerCase(),
|
|
93
75
|
});
|
|
94
|
-
|
|
95
76
|
expect(result).toEqual({
|
|
96
77
|
USD: "US Dollar",
|
|
97
78
|
XYZ: "XYZ", // fallback
|
|
98
79
|
});
|
|
99
|
-
|
|
100
80
|
vi.restoreAllMocks();
|
|
101
81
|
});
|
|
102
82
|
});
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { DEV } from "esm-env";
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
3
|
* Svelte action to teleport a DOM element to a different target (e.g. body)
|
|
5
4
|
*/
|
|
6
|
-
export function portal(
|
|
7
|
-
|
|
8
|
-
target: string | HTMLElement = "body",
|
|
9
|
-
): { update(newTarget: string | HTMLElement): void; destroy(): void } {
|
|
10
|
-
let targetNode: HTMLElement | null;
|
|
5
|
+
export function portal(node, target = "body") {
|
|
6
|
+
let targetNode;
|
|
11
7
|
let isTeleported = false;
|
|
12
|
-
|
|
13
|
-
function update(newTarget: string | HTMLElement) {
|
|
8
|
+
function update(newTarget) {
|
|
14
9
|
if (typeof newTarget === "string") {
|
|
15
10
|
targetNode = document.querySelector(newTarget);
|
|
16
11
|
if (!targetNode && DEV) {
|
|
@@ -21,15 +16,12 @@ export function portal(
|
|
|
21
16
|
} else {
|
|
22
17
|
targetNode = newTarget;
|
|
23
18
|
}
|
|
24
|
-
|
|
25
19
|
if (targetNode) {
|
|
26
20
|
targetNode.appendChild(node);
|
|
27
21
|
isTeleported = true;
|
|
28
22
|
}
|
|
29
23
|
}
|
|
30
|
-
|
|
31
24
|
update(target);
|
|
32
|
-
|
|
33
25
|
return {
|
|
34
26
|
update,
|
|
35
27
|
destroy() {
|
|
@@ -0,0 +1,18 @@
|
|
|
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(
|
|
14
|
+
_node: HTMLElement,
|
|
15
|
+
shortcutStore: ShortcutStoreLike,
|
|
16
|
+
): {
|
|
17
|
+
destroy(): void;
|
|
18
|
+
};
|
package/src/{lib/kernel/src/actions/shortcut-listener.ts → kernel/src/actions/shortcut-listener.js}
RENAMED
|
@@ -1,46 +1,31 @@
|
|
|
1
1
|
import hotkeys from "hotkeys-js";
|
|
2
2
|
import { untrack } from "svelte";
|
|
3
|
-
|
|
4
|
-
export interface ShortcutStoreLike {
|
|
5
|
-
entries: {
|
|
6
|
-
enabled?: boolean;
|
|
7
|
-
keys: string;
|
|
8
|
-
when?: () => boolean;
|
|
9
|
-
handler: (event: KeyboardEvent) => void;
|
|
10
|
-
}[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
3
|
/**
|
|
14
4
|
* Svelte Action to listen for shortcuts registered in shortcutStore.
|
|
15
5
|
* Applied to the root element of the layout.
|
|
16
6
|
*/
|
|
17
|
-
export function shortcutListener(
|
|
18
|
-
_node: HTMLElement,
|
|
19
|
-
shortcutStore: ShortcutStoreLike,
|
|
20
|
-
): { destroy(): void } {
|
|
7
|
+
export function shortcutListener(_node, shortcutStore) {
|
|
21
8
|
// Use $effect to reactively sync shortcuts
|
|
22
9
|
const cleanup = $effect.root(() => {
|
|
23
10
|
$effect(() => {
|
|
24
11
|
// Unbind everything first to ensure clean state
|
|
25
12
|
hotkeys.unbind();
|
|
26
|
-
|
|
27
13
|
// We read entries here, so this effect re-runs when entries change.
|
|
28
14
|
for (const entry of shortcutStore.entries) {
|
|
29
15
|
// @ts-ignore: enabled might not be on the interface but we check it anyway
|
|
30
|
-
if (entry.enabled === false)
|
|
31
|
-
|
|
16
|
+
if (entry.enabled === false) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
32
19
|
hotkeys(entry.keys, "all", (event, _handler) => {
|
|
33
20
|
// Check "when" predicate if it exists
|
|
34
|
-
if (entry.when && !untrack(() => entry.when
|
|
21
|
+
if (entry.when && !untrack(() => entry.when())) {
|
|
35
22
|
return;
|
|
36
23
|
}
|
|
37
|
-
|
|
38
24
|
entry.handler(event);
|
|
39
25
|
});
|
|
40
26
|
}
|
|
41
27
|
});
|
|
42
28
|
});
|
|
43
|
-
|
|
44
29
|
return {
|
|
45
30
|
destroy() {
|
|
46
31
|
cleanup();
|
|
@@ -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,89 @@
|
|
|
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(
|
|
27
|
+
"AppStore.init() called multiple times. Ignoring subsequent calls.",
|
|
28
|
+
"Overwritten properties would have been:",
|
|
29
|
+
data,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (data.name) {
|
|
35
|
+
this.name = data.name;
|
|
36
|
+
}
|
|
37
|
+
if (data.version) {
|
|
38
|
+
this.version = data.version;
|
|
39
|
+
}
|
|
40
|
+
if (data.description) {
|
|
41
|
+
this.description = data.description;
|
|
42
|
+
}
|
|
43
|
+
if (data.author) {
|
|
44
|
+
this.author = data.author;
|
|
45
|
+
}
|
|
46
|
+
if (data.repository) {
|
|
47
|
+
this.repository = data.repository;
|
|
48
|
+
}
|
|
49
|
+
if (data.license) {
|
|
50
|
+
this.license = data.license;
|
|
51
|
+
}
|
|
52
|
+
if (data.homepage) {
|
|
53
|
+
this.homepage = data.homepage;
|
|
54
|
+
}
|
|
55
|
+
this.#initialized = true;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* @internal Test-only. Resets initialization guard.
|
|
59
|
+
*/
|
|
60
|
+
__reset() {
|
|
61
|
+
this.#initialized = false;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get full app information object
|
|
65
|
+
*/
|
|
66
|
+
get info() {
|
|
67
|
+
return {
|
|
68
|
+
name: this.name,
|
|
69
|
+
version: this.version,
|
|
70
|
+
description: this.description,
|
|
71
|
+
author: this.author,
|
|
72
|
+
repository: this.repository,
|
|
73
|
+
license: this.license,
|
|
74
|
+
homepage: this.homepage,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Registers custom SVG icons to be available globally in the Icon component
|
|
79
|
+
*/
|
|
80
|
+
registerIcons(icons) {
|
|
81
|
+
this.customIcons = { ...this.customIcons, ...icons };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export function createAppStore() {
|
|
85
|
+
return new AppStore();
|
|
86
|
+
}
|
|
87
|
+
export function getAppStore() {
|
|
88
|
+
return getContext(RUNE_LAB_CONTEXT.app);
|
|
89
|
+
}
|
|
@@ -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
|
+
};
|
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
// src/lib/context.ts
|
|
2
|
-
|
|
3
|
-
export const RUNE_LAB_CONTEXT: {
|
|
4
|
-
app: symbol;
|
|
5
|
-
api: symbol;
|
|
6
|
-
toast: symbol;
|
|
7
|
-
theme: symbol;
|
|
8
|
-
language: symbol;
|
|
9
|
-
currency: symbol;
|
|
10
|
-
shortcut: symbol;
|
|
11
|
-
layout: symbol;
|
|
12
|
-
commands: symbol;
|
|
13
|
-
persistence: symbol;
|
|
14
|
-
cart: symbol;
|
|
15
|
-
session: symbol;
|
|
16
|
-
exchangeRate: symbol;
|
|
17
|
-
} = {
|
|
2
|
+
export const RUNE_LAB_CONTEXT = {
|
|
18
3
|
app: Symbol("rl:app"),
|
|
19
4
|
api: Symbol("rl:api"),
|
|
20
5
|
toast: Symbol("rl:toast"),
|
|
@@ -28,4 +13,4 @@ export const RUNE_LAB_CONTEXT: {
|
|
|
28
13
|
cart: Symbol("rl:cart"),
|
|
29
14
|
session: Symbol("rl:session"),
|
|
30
15
|
exchangeRate: Symbol("rl:exchange-rate"),
|
|
31
|
-
}
|
|
16
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ConfigStore } from "../persistence/createConfigStore.svelte.ts";
|
|
2
|
+
import type {
|
|
3
|
+
Command,
|
|
4
|
+
Currency,
|
|
5
|
+
Language,
|
|
6
|
+
Theme,
|
|
7
|
+
Toast,
|
|
8
|
+
ToastType,
|
|
9
|
+
} from "./types.ts";
|
|
10
|
+
import type { LayoutStore } from "../../../runes/layout/src/store.svelte.ts";
|
|
11
|
+
import type { ShortcutStore } from "../../../runes/palettes/src/shortcuts/store.svelte.ts";
|
|
12
|
+
/**
|
|
13
|
+
* Common store interfaces
|
|
14
|
+
*/
|
|
15
|
+
export interface ICommandStore {
|
|
16
|
+
commands: Command[];
|
|
17
|
+
register(command: Command): void;
|
|
18
|
+
unregister(id: string): void;
|
|
19
|
+
search(query: string, parentId?: string): Command[];
|
|
20
|
+
}
|
|
21
|
+
export interface IToastStore {
|
|
22
|
+
toasts: Toast[];
|
|
23
|
+
send(message: string, type?: ToastType, duration?: number): void;
|
|
24
|
+
success(msg: string): void;
|
|
25
|
+
error(msg: string): void;
|
|
26
|
+
warn(msg: string): void;
|
|
27
|
+
info(msg: string): void;
|
|
28
|
+
dismiss(id: string): void;
|
|
29
|
+
}
|
|
30
|
+
export interface ICurrencyStore extends ConfigStore<Currency> {
|
|
31
|
+
canConvert: boolean;
|
|
32
|
+
convertAmount(amount: number, fromCode: string, toCode?: string): number;
|
|
33
|
+
addCurrency(meta: Currency, dineroDef?: unknown): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Store context accessors
|
|
37
|
+
*/
|
|
38
|
+
export declare function getLayoutStore(): LayoutStore;
|
|
39
|
+
export declare function getLanguageStore(): ConfigStore<Language>;
|
|
40
|
+
export declare function getThemeStore(): ConfigStore<Theme>;
|
|
41
|
+
export declare function getShortcutStore(): ShortcutStore;
|
|
42
|
+
export declare function getCommandStore(): ICommandStore;
|
|
43
|
+
export declare function getToastStore(): IToastStore;
|
|
44
|
+
export declare function getCurrencyStore(): ICurrencyStore;
|
|
45
|
+
/**
|
|
46
|
+
* Standard layout shortcuts
|
|
47
|
+
*/
|
|
48
|
+
export declare const LAYOUT_SHORTCUTS: {
|
|
49
|
+
readonly TOGGLE_NAV: {
|
|
50
|
+
readonly id: "layout:toggle-nav";
|
|
51
|
+
readonly keys: "ctrl+b";
|
|
52
|
+
readonly label: "Toggle Sidebar";
|
|
53
|
+
readonly category: "Layout";
|
|
54
|
+
};
|
|
55
|
+
readonly TOGGLE_DETAIL: {
|
|
56
|
+
readonly id: "layout:toggle-detail";
|
|
57
|
+
readonly keys: "ctrl+alt+b";
|
|
58
|
+
readonly label: "Toggle Detail Panel";
|
|
59
|
+
readonly category: "Layout";
|
|
60
|
+
};
|
|
61
|
+
readonly OPEN_SHORTCUTS: {
|
|
62
|
+
readonly id: "layout:open-shortcuts";
|
|
63
|
+
readonly keys: "ctrl+/";
|
|
64
|
+
readonly label: "Show Shortcuts";
|
|
65
|
+
readonly category: "Layout";
|
|
66
|
+
};
|
|
67
|
+
};
|