@simplysm/solid 13.0.0-beta.28 → 13.0.0-beta.29

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 (32) hide show
  1. package/README.md +18 -12
  2. package/dist/hooks/{useLocalConfig.d.ts → useLocalStorage.d.ts} +6 -4
  3. package/dist/hooks/useLocalStorage.d.ts.map +1 -0
  4. package/dist/hooks/{useLocalConfig.js → useLocalStorage.js} +9 -6
  5. package/dist/hooks/useLocalStorage.js.map +7 -0
  6. package/dist/hooks/useLogger.d.ts.map +1 -1
  7. package/dist/hooks/useLogger.js +6 -25
  8. package/dist/hooks/useLogger.js.map +2 -2
  9. package/dist/hooks/useSyncConfig.d.ts.map +1 -1
  10. package/dist/hooks/useSyncConfig.js +7 -6
  11. package/dist/hooks/useSyncConfig.js.map +2 -2
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/providers/ConfigContext.d.ts +4 -3
  17. package/dist/providers/ConfigContext.d.ts.map +1 -1
  18. package/dist/providers/ConfigContext.js.map +2 -2
  19. package/dist/providers/InitializeProvider.d.ts +1 -0
  20. package/dist/providers/InitializeProvider.d.ts.map +1 -1
  21. package/dist/providers/InitializeProvider.js +19 -1
  22. package/dist/providers/InitializeProvider.js.map +2 -2
  23. package/dist/providers/shared-data/SharedDataProvider.d.ts.map +1 -1
  24. package/dist/providers/shared-data/SharedDataProvider.js +3 -0
  25. package/dist/providers/shared-data/SharedDataProvider.js.map +2 -2
  26. package/package.json +3 -3
  27. package/dist/configs/LogConfig.d.ts +0 -9
  28. package/dist/configs/LogConfig.d.ts.map +0 -1
  29. package/dist/configs/LogConfig.js +0 -5
  30. package/dist/configs/LogConfig.js.map +0 -7
  31. package/dist/hooks/useLocalConfig.d.ts.map +0 -1
  32. package/dist/hooks/useLocalConfig.js.map +0 -7
package/README.md CHANGED
@@ -37,7 +37,7 @@ export default {
37
37
 
38
38
  ### Provider Setup
39
39
 
40
- Wrap your app root with `InitializeProvider`. It automatically sets up all required providers internally: configuration context, theme (dark/light/system), notification system with banner, loading overlay, and programmatic dialog support.
40
+ Wrap your app root with `InitializeProvider`. It automatically sets up all required providers internally: configuration context, theme (dark/light/system), notification system with banner, global error capturing (window.onerror, unhandledrejection), loading overlay, and programmatic dialog support.
41
41
 
42
42
  ```tsx
43
43
  import { InitializeProvider } from "@simplysm/solid";
@@ -74,7 +74,7 @@ interface StorageAdapter {
74
74
 
75
75
  ```typescript
76
76
  interface LogAdapter {
77
- write(severity: "error" | "warn" | "log", ...data: any[]): Promise<void> | void;
77
+ write(severity: "error" | "warn" | "info" | "log", ...data: any[]): Promise<void> | void;
78
78
  }
79
79
  ```
80
80
 
@@ -1780,14 +1780,14 @@ theme.cycleMode(); // light -> system -> dark -> light
1780
1780
 
1781
1781
  ---
1782
1782
 
1783
- ### useLocalConfig
1783
+ ### useLocalStorage
1784
1784
 
1785
- Local-only persistent config hook. Always uses `localStorage` regardless of `syncStorage` setting. Keys are automatically stored as `{clientName}.{key}`. Use for data that should never leave the device (auth tokens, device-specific state).
1785
+ Local-only persistent storage hook. Always uses `localStorage` regardless of `syncStorage` setting. Keys are automatically prefixed as `{clientName}.{key}`. Use for data that should never leave the device (auth tokens, device-specific state).
1786
1786
 
1787
1787
  ```tsx
1788
- import { useLocalConfig } from "@simplysm/solid";
1788
+ import { useLocalStorage } from "@simplysm/solid";
1789
1789
 
1790
- const [token, setToken] = useLocalConfig<string | undefined>("auth-token", undefined);
1790
+ const [token, setToken] = useLocalStorage<string | undefined>("auth-token", undefined);
1791
1791
  ```
1792
1792
 
1793
1793
  | Return value | Type | Description |
@@ -1799,7 +1799,7 @@ const [token, setToken] = useLocalConfig<string | undefined>("auth-token", undef
1799
1799
 
1800
1800
  ### useSyncConfig
1801
1801
 
1802
- Syncable config hook. Uses `syncStorage` if configured, falls back to `localStorage` otherwise. Keys are automatically stored as `{clientName}.{key}`. Use for user preferences that should sync across devices (theme, DataSheet column configs, filter presets).
1802
+ Syncable config hook. Uses `syncStorage` if configured, falls back to `localStorage` otherwise. Keys are automatically prefixed as `{clientName}.{key}`. Use for user preferences that should sync across devices (theme, DataSheet column configs, filter presets).
1803
1803
 
1804
1804
  ```tsx
1805
1805
  import { useSyncConfig } from "@simplysm/solid";
@@ -1820,20 +1820,26 @@ const [theme, setTheme, loading] = useSyncConfig("theme", "light");
1820
1820
 
1821
1821
  ### useLogger
1822
1822
 
1823
- Logging hook. Always logs to `consola`. Additionally calls `LogAdapter.write()` if `logger` is configured in `AppConfig`. Errors from `LogAdapter.write()` are caught and logged to `consola.error`.
1823
+ Logging hook. If `logger` adapter is configured in `AppConfig`, logs are sent to the adapter only. Otherwise, logs fall back to `consola`. Must be used inside `InitializeProvider`.
1824
1824
 
1825
1825
  ```tsx
1826
1826
  import { useLogger } from "@simplysm/solid";
1827
1827
 
1828
1828
  const logger = useLogger();
1829
- logger.write("log", "user action", { userId: 123 });
1830
- logger.write("error", "something failed", errorObj);
1831
- logger.write("warn", "deprecation notice");
1829
+ logger.log("user action", { userId: 123 });
1830
+ logger.info("app started");
1831
+ logger.error("something failed", errorObj);
1832
+ logger.warn("deprecation notice");
1832
1833
  ```
1833
1834
 
1834
1835
  | Method | Signature | Description |
1835
1836
  |--------|-----------|-------------|
1836
- | `write` | `(severity: "error" \| "warn" \| "log", ...data: any[]) => void` | Log with severity level |
1837
+ | `log` | `(...args: unknown[]) => void` | Log message (general) |
1838
+ | `info` | `(...args: unknown[]) => void` | Log message (informational) |
1839
+ | `warn` | `(...args: unknown[]) => void` | Log message (warning) |
1840
+ | `error` | `(...args: unknown[]) => void` | Log message (error) |
1841
+
1842
+ **Global error capturing:** `InitializeProvider` automatically captures uncaught errors (`window.onerror`) and unhandled promise rejections (`unhandledrejection`) and logs them via `useLogger`. No additional setup required.
1837
1843
 
1838
1844
  ---
1839
1845
 
@@ -1,9 +1,11 @@
1
1
  import { type Accessor, type Setter } from "solid-js";
2
2
  /**
3
- * localStorage 기반 설정 관리 훅.
3
+ * localStorage 기반 저장소 훅.
4
4
  * syncStorage 설정과 무관하게 항상 localStorage를 사용한다.
5
5
  * 기기별로 독립적으로 유지되어야 하는 데이터(인증 토큰, 기기별 상태 등)에 사용한다.
6
6
  *
7
+ * 키는 ConfigContext의 `clientName`으로 자동 prefix된다. (`${clientName}.${key}`)
8
+ *
7
9
  * @template T - 저장할 값의 타입
8
10
  * @param key - localStorage 키
9
11
  * @param initialValue - 초기값 (옵셔널)
@@ -11,7 +13,7 @@ import { type Accessor, type Setter } from "solid-js";
11
13
  *
12
14
  * @example
13
15
  * ```tsx
14
- * const [token, setToken] = useLocalConfig<string>("auth-token");
16
+ * const [token, setToken] = useLocalStorage<string>("auth-token");
15
17
  *
16
18
  * // 값 설정
17
19
  * setToken("abc123");
@@ -23,5 +25,5 @@ import { type Accessor, type Setter } from "solid-js";
23
25
  * setToken(undefined);
24
26
  * ```
25
27
  */
26
- export declare function useLocalConfig<T>(key: string, initialValue?: T): [Accessor<T | undefined>, Setter<T | undefined>];
27
- //# sourceMappingURL=useLocalConfig.d.ts.map
28
+ export declare function useLocalStorage<T>(key: string, initialValue?: T): [Accessor<T | undefined>, Setter<T | undefined>];
29
+ //# sourceMappingURL=useLocalStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLocalStorage.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAgB,MAAM,UAAU,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAsClH"}
@@ -1,8 +1,11 @@
1
1
  import { createSignal } from "solid-js";
2
- function useLocalConfig(key, initialValue) {
2
+ import { useConfig } from "../providers/ConfigContext.js";
3
+ function useLocalStorage(key, initialValue) {
4
+ const config = useConfig();
5
+ const prefixedKey = `${config.clientName}.${key}`;
3
6
  let storedValue = initialValue;
4
7
  try {
5
- const item = localStorage.getItem(key);
8
+ const item = localStorage.getItem(prefixedKey);
6
9
  if (item !== null) {
7
10
  storedValue = JSON.parse(item);
8
11
  }
@@ -19,15 +22,15 @@ function useLocalConfig(key, initialValue) {
19
22
  setValue(() => newValue);
20
23
  }
21
24
  if (resolved === void 0) {
22
- localStorage.removeItem(key);
25
+ localStorage.removeItem(prefixedKey);
23
26
  } else {
24
- localStorage.setItem(key, JSON.stringify(resolved));
27
+ localStorage.setItem(prefixedKey, JSON.stringify(resolved));
25
28
  }
26
29
  return resolved;
27
30
  };
28
31
  return [value, setAndStore];
29
32
  }
30
33
  export {
31
- useLocalConfig
34
+ useLocalStorage
32
35
  };
33
- //# sourceMappingURL=useLocalConfig.js.map
36
+ //# sourceMappingURL=useLocalStorage.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useLocalStorage.ts"],
4
+ "sourcesContent": ["import { type Accessor, type Setter, createSignal } from \"solid-js\";\nimport { useConfig } from \"../providers/ConfigContext\";\n\n/**\n * localStorage \uAE30\uBC18 \uC800\uC7A5\uC18C \uD6C5.\n * syncStorage \uC124\uC815\uACFC \uBB34\uAD00\uD558\uAC8C \uD56D\uC0C1 localStorage\uB97C \uC0AC\uC6A9\uD55C\uB2E4.\n * \uAE30\uAE30\uBCC4\uB85C \uB3C5\uB9BD\uC801\uC73C\uB85C \uC720\uC9C0\uB418\uC5B4\uC57C \uD558\uB294 \uB370\uC774\uD130(\uC778\uC99D \uD1A0\uD070, \uAE30\uAE30\uBCC4 \uC0C1\uD0DC \uB4F1)\uC5D0 \uC0AC\uC6A9\uD55C\uB2E4.\n *\n * \uD0A4\uB294 ConfigContext\uC758 `clientName`\uC73C\uB85C \uC790\uB3D9 prefix\uB41C\uB2E4. (`${clientName}.${key}`)\n *\n * @template T - \uC800\uC7A5\uD560 \uAC12\uC758 \uD0C0\uC785\n * @param key - localStorage \uD0A4\n * @param initialValue - \uCD08\uAE30\uAC12 (\uC635\uC154\uB110)\n * @returns [Accessor<T | undefined>, Setter<T | undefined>] \uD29C\uD50C\n *\n * @example\n * ```tsx\n * const [token, setToken] = useLocalStorage<string>(\"auth-token\");\n *\n * // \uAC12 \uC124\uC815\n * setToken(\"abc123\");\n *\n * // \uAC12 \uC77D\uAE30\n * console.log(token()); // \"abc123\"\n *\n * // \uAC12 \uC81C\uAC70\n * setToken(undefined);\n * ```\n */\nexport function useLocalStorage<T>(key: string, initialValue?: T): [Accessor<T | undefined>, Setter<T | undefined>] {\n const config = useConfig();\n const prefixedKey = `${config.clientName}.${key}`;\n\n // localStorage\uC5D0\uC11C \uCD08\uAE30\uAC12 \uC77D\uAE30\n let storedValue: T | undefined = initialValue;\n try {\n const item = localStorage.getItem(prefixedKey);\n if (item !== null) {\n storedValue = JSON.parse(item) as T;\n }\n } catch {\n // JSON \uD30C\uC2F1 \uC2E4\uD328 \uC2DC \uCD08\uAE30\uAC12 \uC0AC\uC6A9\n }\n\n const [value, setValue] = createSignal<T | undefined>(storedValue);\n\n const setAndStore = (newValue: T | undefined | ((prev: T | undefined) => T | undefined)) => {\n let resolved: T | undefined;\n\n if (typeof newValue === \"function\") {\n resolved = (newValue as (prev: T | undefined) => T | undefined)(value());\n setValue(() => resolved);\n } else {\n resolved = newValue;\n setValue(() => newValue);\n }\n\n if (resolved === undefined) {\n localStorage.removeItem(prefixedKey);\n } else {\n localStorage.setItem(prefixedKey, JSON.stringify(resolved));\n }\n\n return resolved;\n };\n\n return [value, setAndStore as Setter<T | undefined>];\n}\n"],
5
+ "mappings": "AAAA,SAAqC,oBAAoB;AACzD,SAAS,iBAAiB;AA4BnB,SAAS,gBAAmB,KAAa,cAAoE;AAClH,QAAM,SAAS,UAAU;AACzB,QAAM,cAAc,GAAG,OAAO,UAAU,IAAI,GAAG;AAG/C,MAAI,cAA6B;AACjC,MAAI;AACF,UAAM,OAAO,aAAa,QAAQ,WAAW;AAC7C,QAAI,SAAS,MAAM;AACjB,oBAAc,KAAK,MAAM,IAAI;AAAA,IAC/B;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,QAAM,CAAC,OAAO,QAAQ,IAAI,aAA4B,WAAW;AAEjE,QAAM,cAAc,CAAC,aAAuE;AAC1F,QAAI;AAEJ,QAAI,OAAO,aAAa,YAAY;AAClC,iBAAY,SAAoD,MAAM,CAAC;AACvE,eAAS,MAAM,QAAQ;AAAA,IACzB,OAAO;AACL,iBAAW;AACX,eAAS,MAAM,QAAQ;AAAA,IACzB;AAEA,QAAI,aAAa,QAAW;AAC1B,mBAAa,WAAW,WAAW;AAAA,IACrC,OAAO;AACL,mBAAa,QAAQ,aAAa,KAAK,UAAU,QAAQ,CAAC;AAAA,IAC5D;AAEA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,OAAO,WAAoC;AACrD;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"useLogger.d.ts","sourceRoot":"","sources":["../../src/hooks/useLogger.ts"],"names":[],"mappings":"AAGA,UAAU,MAAM;IACd,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACnC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,SAAS,IAAI,MAAM,CA2ClC"}
1
+ {"version":3,"file":"useLogger.d.ts","sourceRoot":"","sources":["../../src/hooks/useLogger.ts"],"names":[],"mappings":"AAKA,UAAU,MAAM;IACd,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACnC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAmBlC"}
@@ -1,32 +1,13 @@
1
1
  import { consola } from "consola";
2
- import { LogAdapter } from "../configs/LogConfig.js";
2
+ import { useConfig } from "../providers/ConfigContext.js";
3
3
  function useLogger() {
4
+ const config = useConfig();
4
5
  const createLogFunction = (level) => {
5
6
  return (...args) => {
6
- consola[level](...args);
7
- if (LogAdapter.write != null) {
8
- try {
9
- const message = args.map((arg) => {
10
- if (typeof arg === "string") {
11
- return arg;
12
- }
13
- if (arg == null) {
14
- return String(arg);
15
- }
16
- try {
17
- return JSON.stringify(arg);
18
- } catch {
19
- return String(arg);
20
- }
21
- }).join(" ");
22
- LogAdapter.write({
23
- level,
24
- message,
25
- timestamp: Date.now()
26
- });
27
- } catch (err) {
28
- consola.error("Failed to write log to adapter:", err);
29
- }
7
+ if (config.logger) {
8
+ void config.logger.write(level, ...args);
9
+ } else {
10
+ consola[level](...args);
30
11
  }
31
12
  };
32
13
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/useLogger.ts"],
4
- "sourcesContent": ["import { consola } from \"consola\";\nimport { LogAdapter, type LogEntry } from \"../configs/LogConfig\";\n\ninterface Logger {\n log: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\nexport function useLogger(): Logger {\n const createLogFunction = (level: LogEntry[\"level\"]) => {\n return (...args: unknown[]) => {\n // Always log to consola\n (consola as any)[level](...args);\n\n // Optionally write to adapter\n if (LogAdapter.write != null) {\n try {\n const message = args\n .map((arg) => {\n if (typeof arg === \"string\") {\n return arg;\n }\n if (arg == null) {\n return String(arg);\n }\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n })\n .join(\" \");\n\n LogAdapter.write({\n level,\n message,\n timestamp: Date.now(),\n });\n } catch (err) {\n consola.error(\"Failed to write log to adapter:\", err);\n }\n }\n };\n };\n\n return {\n log: createLogFunction(\"log\"),\n info: createLogFunction(\"info\"),\n warn: createLogFunction(\"warn\"),\n error: createLogFunction(\"error\"),\n };\n}\n"],
5
- "mappings": "AAAA,SAAS,eAAe;AACxB,SAAS,kBAAiC;AASnC,SAAS,YAAoB;AAClC,QAAM,oBAAoB,CAAC,UAA6B;AACtD,WAAO,IAAI,SAAoB;AAE7B,MAAC,QAAgB,KAAK,EAAE,GAAG,IAAI;AAG/B,UAAI,WAAW,SAAS,MAAM;AAC5B,YAAI;AACF,gBAAM,UAAU,KACb,IAAI,CAAC,QAAQ;AACZ,gBAAI,OAAO,QAAQ,UAAU;AAC3B,qBAAO;AAAA,YACT;AACA,gBAAI,OAAO,MAAM;AACf,qBAAO,OAAO,GAAG;AAAA,YACnB;AACA,gBAAI;AACF,qBAAO,KAAK,UAAU,GAAG;AAAA,YAC3B,QAAQ;AACN,qBAAO,OAAO,GAAG;AAAA,YACnB;AAAA,UACF,CAAC,EACA,KAAK,GAAG;AAEX,qBAAW,MAAM;AAAA,YACf;AAAA,YACA;AAAA,YACA,WAAW,KAAK,IAAI;AAAA,UACtB,CAAC;AAAA,QACH,SAAS,KAAK;AACZ,kBAAQ,MAAM,mCAAmC,GAAG;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,KAAK,kBAAkB,KAAK;AAAA,IAC5B,MAAM,kBAAkB,MAAM;AAAA,IAC9B,MAAM,kBAAkB,MAAM;AAAA,IAC9B,OAAO,kBAAkB,OAAO;AAAA,EAClC;AACF;",
4
+ "sourcesContent": ["import { consola } from \"consola\";\nimport { useConfig, type LogAdapter } from \"../providers/ConfigContext\";\n\ntype LogLevel = Parameters<LogAdapter[\"write\"]>[0];\n\ninterface Logger {\n log: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\nexport function useLogger(): Logger {\n const config = useConfig();\n\n const createLogFunction = (level: LogLevel) => {\n return (...args: unknown[]) => {\n if (config.logger) {\n void config.logger.write(level, ...args);\n } else {\n (consola as any)[level](...args);\n }\n };\n };\n\n return {\n log: createLogFunction(\"log\"),\n info: createLogFunction(\"info\"),\n warn: createLogFunction(\"warn\"),\n error: createLogFunction(\"error\"),\n };\n}\n"],
5
+ "mappings": "AAAA,SAAS,eAAe;AACxB,SAAS,iBAAkC;AAWpC,SAAS,YAAoB;AAClC,QAAM,SAAS,UAAU;AAEzB,QAAM,oBAAoB,CAAC,UAAoB;AAC7C,WAAO,IAAI,SAAoB;AAC7B,UAAI,OAAO,QAAQ;AACjB,aAAK,OAAO,OAAO,MAAM,OAAO,GAAG,IAAI;AAAA,MACzC,OAAO;AACL,QAAC,QAAgB,KAAK,EAAE,GAAG,IAAI;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,KAAK,kBAAkB,KAAK;AAAA,IAC5B,MAAM,kBAAkB,MAAM;AAAA,IAC9B,MAAM,kBAAkB,MAAM;AAAA,IAC9B,OAAO,kBAAkB,OAAO;AAAA,EAClC;AACF;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useSyncConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/useSyncConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAyC,MAAM,UAAU,CAAC;AAG7F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAyE1G"}
1
+ {"version":3,"file":"useSyncConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/useSyncConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAyC,MAAM,UAAU,CAAC;AAG7F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CA0E1G"}
@@ -2,12 +2,13 @@ import { createEffect, createSignal, onCleanup } from "solid-js";
2
2
  import { useConfig } from "../providers/ConfigContext.js";
3
3
  function useSyncConfig(key, defaultValue) {
4
4
  const config = useConfig();
5
+ const prefixedKey = `${config.clientName}.${key}`;
5
6
  const [value, setValue] = createSignal(defaultValue);
6
7
  const [loading, setLoading] = createSignal(false);
7
8
  const initializeFromStorage = async () => {
8
9
  if (!config.syncStorage) {
9
10
  try {
10
- const stored = localStorage.getItem(key);
11
+ const stored = localStorage.getItem(prefixedKey);
11
12
  if (stored !== null) {
12
13
  setValue(() => JSON.parse(stored));
13
14
  }
@@ -17,13 +18,13 @@ function useSyncConfig(key, defaultValue) {
17
18
  }
18
19
  setLoading(true);
19
20
  try {
20
- const stored = await config.syncStorage.getItem(key);
21
+ const stored = await config.syncStorage.getItem(prefixedKey);
21
22
  if (stored !== null) {
22
23
  setValue(() => JSON.parse(stored));
23
24
  }
24
25
  } catch {
25
26
  try {
26
- const stored = localStorage.getItem(key);
27
+ const stored = localStorage.getItem(prefixedKey);
27
28
  if (stored !== null) {
28
29
  setValue(() => JSON.parse(stored));
29
30
  }
@@ -38,14 +39,14 @@ function useSyncConfig(key, defaultValue) {
38
39
  const currentValue = value();
39
40
  const serialized = JSON.stringify(currentValue);
40
41
  if (!config.syncStorage) {
41
- localStorage.setItem(key, serialized);
42
+ localStorage.setItem(prefixedKey, serialized);
42
43
  return;
43
44
  }
44
45
  void (async () => {
45
46
  try {
46
- await config.syncStorage.setItem(key, serialized);
47
+ await config.syncStorage.setItem(prefixedKey, serialized);
47
48
  } catch {
48
- localStorage.setItem(key, serialized);
49
+ localStorage.setItem(prefixedKey, serialized);
49
50
  }
50
51
  })();
51
52
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/useSyncConfig.ts"],
4
- "sourcesContent": ["import { type Accessor, type Setter, createEffect, createSignal, onCleanup } from \"solid-js\";\nimport { useConfig } from \"../providers/ConfigContext\";\n\n/**\n * Creates a reactive signal that syncs configuration data to storage.\n *\n * Uses `syncStorage` from ConfigProvider if available, otherwise falls back to `localStorage`.\n * Designed for data that should persist and sync across devices (e.g., theme, user preferences, DataSheet configs).\n *\n * @param key - Storage key for the config value\n * @param defaultValue - Default value if no stored value exists\n * @returns Tuple of [value accessor, value setter, loading state accessor]\n *\n * @example\n * ```tsx\n * const [theme, setTheme, loading] = useSyncConfig(\"user-theme\", \"light\");\n *\n * <Show when={!loading()}>\n * <button onClick={() => setTheme(theme() === \"light\" ? \"dark\" : \"light\")}>\n * Toggle theme\n * </button>\n * </Show>\n * ```\n */\nexport function useSyncConfig<T>(key: string, defaultValue: T): [Accessor<T>, Setter<T>, Accessor<boolean>] {\n const config = useConfig();\n const [value, setValue] = createSignal<T>(defaultValue);\n const [loading, setLoading] = createSignal(false);\n\n // Initialize from storage\n const initializeFromStorage = async () => {\n if (!config.syncStorage) {\n // Use localStorage synchronously\n try {\n const stored = localStorage.getItem(key);\n if (stored !== null) {\n setValue(() => JSON.parse(stored) as T);\n }\n } catch {\n // Ignore parse errors, keep default value\n }\n return;\n }\n\n // Use syncStorage asynchronously\n setLoading(true);\n try {\n const stored = await config.syncStorage.getItem(key);\n if (stored !== null) {\n setValue(() => JSON.parse(stored) as T);\n }\n } catch {\n // Fall back to localStorage on error\n try {\n const stored = localStorage.getItem(key);\n if (stored !== null) {\n setValue(() => JSON.parse(stored) as T);\n }\n } catch {\n // Ignore parse errors\n }\n } finally {\n setLoading(false);\n }\n };\n\n // Initialize on mount\n void initializeFromStorage();\n\n // Save to storage whenever value changes\n createEffect(() => {\n const currentValue = value();\n const serialized = JSON.stringify(currentValue);\n\n if (!config.syncStorage) {\n // Use localStorage synchronously\n localStorage.setItem(key, serialized);\n return;\n }\n\n // Use syncStorage asynchronously\n void (async () => {\n try {\n await config.syncStorage!.setItem(key, serialized);\n } catch {\n // Fall back to localStorage on error\n localStorage.setItem(key, serialized);\n }\n })();\n });\n\n // Clean up (optional, for consistency)\n onCleanup(() => {\n // No cleanup needed for storage operations\n });\n\n return [value, setValue, loading];\n}\n"],
5
- "mappings": "AAAA,SAAqC,cAAc,cAAc,iBAAiB;AAClF,SAAS,iBAAiB;AAuBnB,SAAS,cAAiB,KAAa,cAA8D;AAC1G,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,OAAO,QAAQ,IAAI,aAAgB,YAAY;AACtD,QAAM,CAAC,SAAS,UAAU,IAAI,aAAa,KAAK;AAGhD,QAAM,wBAAwB,YAAY;AACxC,QAAI,CAAC,OAAO,aAAa;AAEvB,UAAI;AACF,cAAM,SAAS,aAAa,QAAQ,GAAG;AACvC,YAAI,WAAW,MAAM;AACnB,mBAAS,MAAM,KAAK,MAAM,MAAM,CAAM;AAAA,QACxC;AAAA,MACF,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAGA,eAAW,IAAI;AACf,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,YAAY,QAAQ,GAAG;AACnD,UAAI,WAAW,MAAM;AACnB,iBAAS,MAAM,KAAK,MAAM,MAAM,CAAM;AAAA,MACxC;AAAA,IACF,QAAQ;AAEN,UAAI;AACF,cAAM,SAAS,aAAa,QAAQ,GAAG;AACvC,YAAI,WAAW,MAAM;AACnB,mBAAS,MAAM,KAAK,MAAM,MAAM,CAAM;AAAA,QACxC;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAGA,OAAK,sBAAsB;AAG3B,eAAa,MAAM;AACjB,UAAM,eAAe,MAAM;AAC3B,UAAM,aAAa,KAAK,UAAU,YAAY;AAE9C,QAAI,CAAC,OAAO,aAAa;AAEvB,mBAAa,QAAQ,KAAK,UAAU;AACpC;AAAA,IACF;AAGA,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,OAAO,YAAa,QAAQ,KAAK,UAAU;AAAA,MACnD,QAAQ;AAEN,qBAAa,QAAQ,KAAK,UAAU;AAAA,MACtC;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AAGD,YAAU,MAAM;AAAA,EAEhB,CAAC;AAED,SAAO,CAAC,OAAO,UAAU,OAAO;AAClC;",
4
+ "sourcesContent": ["import { type Accessor, type Setter, createEffect, createSignal, onCleanup } from \"solid-js\";\nimport { useConfig } from \"../providers/ConfigContext\";\n\n/**\n * Creates a reactive signal that syncs configuration data to storage.\n *\n * Uses `syncStorage` from ConfigProvider if available, otherwise falls back to `localStorage`.\n * Designed for data that should persist and sync across devices (e.g., theme, user preferences, DataSheet configs).\n *\n * @param key - Storage key for the config value\n * @param defaultValue - Default value if no stored value exists\n * @returns Tuple of [value accessor, value setter, loading state accessor]\n *\n * @example\n * ```tsx\n * const [theme, setTheme, loading] = useSyncConfig(\"user-theme\", \"light\");\n *\n * <Show when={!loading()}>\n * <button onClick={() => setTheme(theme() === \"light\" ? \"dark\" : \"light\")}>\n * Toggle theme\n * </button>\n * </Show>\n * ```\n */\nexport function useSyncConfig<T>(key: string, defaultValue: T): [Accessor<T>, Setter<T>, Accessor<boolean>] {\n const config = useConfig();\n const prefixedKey = `${config.clientName}.${key}`;\n const [value, setValue] = createSignal<T>(defaultValue);\n const [loading, setLoading] = createSignal(false);\n\n // Initialize from storage\n const initializeFromStorage = async () => {\n if (!config.syncStorage) {\n // Use localStorage synchronously\n try {\n const stored = localStorage.getItem(prefixedKey);\n if (stored !== null) {\n setValue(() => JSON.parse(stored) as T);\n }\n } catch {\n // Ignore parse errors, keep default value\n }\n return;\n }\n\n // Use syncStorage asynchronously\n setLoading(true);\n try {\n const stored = await config.syncStorage.getItem(prefixedKey);\n if (stored !== null) {\n setValue(() => JSON.parse(stored) as T);\n }\n } catch {\n // Fall back to localStorage on error\n try {\n const stored = localStorage.getItem(prefixedKey);\n if (stored !== null) {\n setValue(() => JSON.parse(stored) as T);\n }\n } catch {\n // Ignore parse errors\n }\n } finally {\n setLoading(false);\n }\n };\n\n // Initialize on mount\n void initializeFromStorage();\n\n // Save to storage whenever value changes\n createEffect(() => {\n const currentValue = value();\n const serialized = JSON.stringify(currentValue);\n\n if (!config.syncStorage) {\n // Use localStorage synchronously\n localStorage.setItem(prefixedKey, serialized);\n return;\n }\n\n // Use syncStorage asynchronously\n void (async () => {\n try {\n await config.syncStorage!.setItem(prefixedKey, serialized);\n } catch {\n // Fall back to localStorage on error\n localStorage.setItem(prefixedKey, serialized);\n }\n })();\n });\n\n // Clean up (optional, for consistency)\n onCleanup(() => {\n // No cleanup needed for storage operations\n });\n\n return [value, setValue, loading];\n}\n"],
5
+ "mappings": "AAAA,SAAqC,cAAc,cAAc,iBAAiB;AAClF,SAAS,iBAAiB;AAuBnB,SAAS,cAAiB,KAAa,cAA8D;AAC1G,QAAM,SAAS,UAAU;AACzB,QAAM,cAAc,GAAG,OAAO,UAAU,IAAI,GAAG;AAC/C,QAAM,CAAC,OAAO,QAAQ,IAAI,aAAgB,YAAY;AACtD,QAAM,CAAC,SAAS,UAAU,IAAI,aAAa,KAAK;AAGhD,QAAM,wBAAwB,YAAY;AACxC,QAAI,CAAC,OAAO,aAAa;AAEvB,UAAI;AACF,cAAM,SAAS,aAAa,QAAQ,WAAW;AAC/C,YAAI,WAAW,MAAM;AACnB,mBAAS,MAAM,KAAK,MAAM,MAAM,CAAM;AAAA,QACxC;AAAA,MACF,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAGA,eAAW,IAAI;AACf,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,YAAY,QAAQ,WAAW;AAC3D,UAAI,WAAW,MAAM;AACnB,iBAAS,MAAM,KAAK,MAAM,MAAM,CAAM;AAAA,MACxC;AAAA,IACF,QAAQ;AAEN,UAAI;AACF,cAAM,SAAS,aAAa,QAAQ,WAAW;AAC/C,YAAI,WAAW,MAAM;AACnB,mBAAS,MAAM,KAAK,MAAM,MAAM,CAAM;AAAA,QACxC;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAGA,OAAK,sBAAsB;AAG3B,eAAa,MAAM;AACjB,UAAM,eAAe,MAAM;AAC3B,UAAM,aAAa,KAAK,UAAU,YAAY;AAE9C,QAAI,CAAC,OAAO,aAAa;AAEvB,mBAAa,QAAQ,aAAa,UAAU;AAC5C;AAAA,IACF;AAGA,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,OAAO,YAAa,QAAQ,aAAa,UAAU;AAAA,MAC3D,QAAQ;AAEN,qBAAa,QAAQ,aAAa,UAAU;AAAA,MAC9C;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AAGD,YAAU,MAAM;AAAA,EAEhB,CAAC;AAED,SAAO,CAAC,OAAO,UAAU,OAAO;AAClC;",
6
6
  "names": []
7
7
  }
package/dist/index.d.ts CHANGED
@@ -70,7 +70,7 @@ export * from "./providers/ServiceClientProvider";
70
70
  export * from "./providers/shared-data/SharedDataContext";
71
71
  export * from "./providers/shared-data/SharedDataProvider";
72
72
  export * from "./providers/shared-data/SharedDataChangeEvent";
73
- export * from "./hooks/useLocalConfig";
73
+ export * from "./hooks/useLocalStorage";
74
74
  export * from "./hooks/useSyncConfig";
75
75
  export * from "./hooks/useLogger";
76
76
  export * from "./hooks/usePrint";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ export * from "./providers/ServiceClientProvider.js";
69
69
  export * from "./providers/shared-data/SharedDataContext.js";
70
70
  export * from "./providers/shared-data/SharedDataProvider.js";
71
71
  export * from "./providers/shared-data/SharedDataChangeEvent.js";
72
- export * from "./hooks/useLocalConfig.js";
72
+ export * from "./hooks/useLocalStorage.js";
73
73
  export * from "./hooks/useSyncConfig.js";
74
74
  export * from "./hooks/useLogger.js";
75
75
  export * from "./hooks/usePrint.js";
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["// form-control\nexport * from \"./components/form-control/Button\";\nexport * from \"./components/form-control/select/Select\";\nexport * from \"./components/form-control/select/SelectContext\";\nexport * from \"./components/form-control/combobox/Combobox\";\nexport * from \"./components/form-control/combobox/ComboboxContext\";\nexport * from \"./components/form-control/field/TextInput\";\nexport * from \"./components/form-control/field/NumberInput\";\nexport * from \"./components/form-control/field/DatePicker\";\nexport * from \"./components/form-control/field/DateTimePicker\";\nexport * from \"./components/form-control/field/TimePicker\";\nexport * from \"./components/form-control/field/Textarea\";\nexport * from \"./components/form-control/field/Field.styles\";\nexport * from \"./components/form-control/checkbox/Checkbox\";\nexport * from \"./components/form-control/checkbox/Checkbox.styles\";\nexport * from \"./components/form-control/checkbox/Radio\";\nexport * from \"./components/form-control/checkbox/CheckboxGroup\";\nexport * from \"./components/form-control/checkbox/RadioGroup\";\nexport * from \"./components/form-control/color-picker/ColorPicker\";\nexport * from \"./components/form-control/date-range-picker/DateRangePicker\";\nexport * from \"./components/form-control/editor/RichTextEditor\";\nexport * from \"./components/form-control/numpad/Numpad\";\nexport * from \"./components/form-control/state-preset/StatePreset\";\nexport * from \"./components/form-control/ThemeToggle\";\n\n// layout\nexport * from \"./components/layout/FormGroup\";\nexport * from \"./components/layout/FormTable\";\nexport * from \"./components/layout/sidebar/Sidebar\";\nexport * from \"./components/layout/sidebar/SidebarContext\";\nexport * from \"./components/layout/topbar/Topbar\";\n\n// data\nexport * from \"./components/data/Table\";\nexport * from \"./components/data/list/List\";\nexport * from \"./components/data/list/ListContext\";\nexport * from \"./components/data/list/ListItem.styles\";\nexport * from \"./components/data/Pagination\";\nexport * from \"./components/data/sheet/DataSheet\";\nexport * from \"./components/data/sheet/DataSheet.styles\";\nexport * from \"./components/data/sheet/types\";\nexport * from \"./components/data/calendar/Calendar\";\nexport * from \"./components/data/permission-table/PermissionTable\";\nexport * from \"./components/data/kanban/Kanban\";\nexport * from \"./components/data/kanban/KanbanContext\";\n\n// display\nexport * from \"./components/display/Barcode\";\nexport * from \"./components/display/Card\";\nexport * from \"./components/display/Echarts\";\nexport * from \"./components/display/Icon\";\nexport * from \"./components/display/Tag\";\nexport * from \"./components/display/Alert\";\n\n// disclosure\nexport * from \"./components/disclosure/Collapse\";\nexport * from \"./components/disclosure/Dropdown\";\nexport * from \"./components/disclosure/Dialog\";\nexport * from \"./components/disclosure/DialogContext\";\nexport * from \"./components/disclosure/DialogInstanceContext\";\nexport * from \"./components/disclosure/DialogProvider\";\nexport * from \"./components/disclosure/Tabs\";\n\n// feedback\nexport * from \"./components/feedback/notification/NotificationContext\";\nexport * from \"./components/feedback/notification/NotificationBell\";\nexport * from \"./components/feedback/notification/NotificationProvider\";\nexport * from \"./components/feedback/notification/NotificationBanner\";\n\n// feedback - loading\nexport * from \"./components/feedback/loading/LoadingContext\";\nexport * from \"./components/feedback/loading/LoadingContainer\";\nexport * from \"./components/feedback/loading/LoadingProvider\";\n\n// feedback - print\nexport * from \"./components/feedback/print/Print\";\nexport * from \"./components/feedback/print/PrintInstanceContext\";\nexport * from \"./components/feedback/Progress\";\n\n// providers\nexport * from \"./providers/ConfigContext\";\nexport * from \"./providers/InitializeProvider\";\nexport { useTheme } from \"./providers/ThemeContext\";\nexport type { ThemeMode, ResolvedTheme } from \"./providers/ThemeContext\";\nexport * from \"./providers/ServiceClientContext\";\nexport * from \"./providers/ServiceClientProvider\";\nexport * from \"./providers/shared-data/SharedDataContext\";\nexport * from \"./providers/shared-data/SharedDataProvider\";\nexport * from \"./providers/shared-data/SharedDataChangeEvent\";\n\n// hooks\nexport * from \"./hooks/useLocalConfig\";\nexport * from \"./hooks/useSyncConfig\";\nexport * from \"./hooks/useLogger\";\nexport * from \"./hooks/usePrint\";\nexport { createControllableSignal } from \"./hooks/createControllableSignal\";\nexport { createIMEHandler } from \"./hooks/createIMEHandler\";\nexport { createMountTransition } from \"./hooks/createMountTransition\";\nexport { createPwaUpdate } from \"./hooks/createPwaUpdate\";\nexport { useRouterLink } from \"./hooks/useRouterLink\";\n\n// styles\nexport * from \"./styles/tokens.styles\";\nexport * from \"./styles/patterns.styles\";\n\n// directives\nexport { ripple } from \"./directives/ripple\";\n\n// helpers\nexport { mergeStyles } from \"./helpers/mergeStyles\";\nexport { splitSlots } from \"./helpers/splitSlots\";\nexport { createAppStructure } from \"./helpers/createAppStructure\";\nexport type {\n AppStructureItem,\n AppStructureGroupItem,\n AppStructureLeafItem,\n AppStructureSubPerm,\n AppRoute,\n AppFlatMenu,\n AppStructure,\n} from \"./helpers/createAppStructure\";\n"],
4
+ "sourcesContent": ["// form-control\nexport * from \"./components/form-control/Button\";\nexport * from \"./components/form-control/select/Select\";\nexport * from \"./components/form-control/select/SelectContext\";\nexport * from \"./components/form-control/combobox/Combobox\";\nexport * from \"./components/form-control/combobox/ComboboxContext\";\nexport * from \"./components/form-control/field/TextInput\";\nexport * from \"./components/form-control/field/NumberInput\";\nexport * from \"./components/form-control/field/DatePicker\";\nexport * from \"./components/form-control/field/DateTimePicker\";\nexport * from \"./components/form-control/field/TimePicker\";\nexport * from \"./components/form-control/field/Textarea\";\nexport * from \"./components/form-control/field/Field.styles\";\nexport * from \"./components/form-control/checkbox/Checkbox\";\nexport * from \"./components/form-control/checkbox/Checkbox.styles\";\nexport * from \"./components/form-control/checkbox/Radio\";\nexport * from \"./components/form-control/checkbox/CheckboxGroup\";\nexport * from \"./components/form-control/checkbox/RadioGroup\";\nexport * from \"./components/form-control/color-picker/ColorPicker\";\nexport * from \"./components/form-control/date-range-picker/DateRangePicker\";\nexport * from \"./components/form-control/editor/RichTextEditor\";\nexport * from \"./components/form-control/numpad/Numpad\";\nexport * from \"./components/form-control/state-preset/StatePreset\";\nexport * from \"./components/form-control/ThemeToggle\";\n\n// layout\nexport * from \"./components/layout/FormGroup\";\nexport * from \"./components/layout/FormTable\";\nexport * from \"./components/layout/sidebar/Sidebar\";\nexport * from \"./components/layout/sidebar/SidebarContext\";\nexport * from \"./components/layout/topbar/Topbar\";\n\n// data\nexport * from \"./components/data/Table\";\nexport * from \"./components/data/list/List\";\nexport * from \"./components/data/list/ListContext\";\nexport * from \"./components/data/list/ListItem.styles\";\nexport * from \"./components/data/Pagination\";\nexport * from \"./components/data/sheet/DataSheet\";\nexport * from \"./components/data/sheet/DataSheet.styles\";\nexport * from \"./components/data/sheet/types\";\nexport * from \"./components/data/calendar/Calendar\";\nexport * from \"./components/data/permission-table/PermissionTable\";\nexport * from \"./components/data/kanban/Kanban\";\nexport * from \"./components/data/kanban/KanbanContext\";\n\n// display\nexport * from \"./components/display/Barcode\";\nexport * from \"./components/display/Card\";\nexport * from \"./components/display/Echarts\";\nexport * from \"./components/display/Icon\";\nexport * from \"./components/display/Tag\";\nexport * from \"./components/display/Alert\";\n\n// disclosure\nexport * from \"./components/disclosure/Collapse\";\nexport * from \"./components/disclosure/Dropdown\";\nexport * from \"./components/disclosure/Dialog\";\nexport * from \"./components/disclosure/DialogContext\";\nexport * from \"./components/disclosure/DialogInstanceContext\";\nexport * from \"./components/disclosure/DialogProvider\";\nexport * from \"./components/disclosure/Tabs\";\n\n// feedback\nexport * from \"./components/feedback/notification/NotificationContext\";\nexport * from \"./components/feedback/notification/NotificationBell\";\nexport * from \"./components/feedback/notification/NotificationProvider\";\nexport * from \"./components/feedback/notification/NotificationBanner\";\n\n// feedback - loading\nexport * from \"./components/feedback/loading/LoadingContext\";\nexport * from \"./components/feedback/loading/LoadingContainer\";\nexport * from \"./components/feedback/loading/LoadingProvider\";\n\n// feedback - print\nexport * from \"./components/feedback/print/Print\";\nexport * from \"./components/feedback/print/PrintInstanceContext\";\nexport * from \"./components/feedback/Progress\";\n\n// providers\nexport * from \"./providers/ConfigContext\";\nexport * from \"./providers/InitializeProvider\";\nexport { useTheme } from \"./providers/ThemeContext\";\nexport type { ThemeMode, ResolvedTheme } from \"./providers/ThemeContext\";\nexport * from \"./providers/ServiceClientContext\";\nexport * from \"./providers/ServiceClientProvider\";\nexport * from \"./providers/shared-data/SharedDataContext\";\nexport * from \"./providers/shared-data/SharedDataProvider\";\nexport * from \"./providers/shared-data/SharedDataChangeEvent\";\n\n// hooks\nexport * from \"./hooks/useLocalStorage\";\nexport * from \"./hooks/useSyncConfig\";\nexport * from \"./hooks/useLogger\";\nexport * from \"./hooks/usePrint\";\nexport { createControllableSignal } from \"./hooks/createControllableSignal\";\nexport { createIMEHandler } from \"./hooks/createIMEHandler\";\nexport { createMountTransition } from \"./hooks/createMountTransition\";\nexport { createPwaUpdate } from \"./hooks/createPwaUpdate\";\nexport { useRouterLink } from \"./hooks/useRouterLink\";\n\n// styles\nexport * from \"./styles/tokens.styles\";\nexport * from \"./styles/patterns.styles\";\n\n// directives\nexport { ripple } from \"./directives/ripple\";\n\n// helpers\nexport { mergeStyles } from \"./helpers/mergeStyles\";\nexport { splitSlots } from \"./helpers/splitSlots\";\nexport { createAppStructure } from \"./helpers/createAppStructure\";\nexport type {\n AppStructureItem,\n AppStructureGroupItem,\n AppStructureLeafItem,\n AppStructureSubPerm,\n AppRoute,\n AppFlatMenu,\n AppStructure,\n} from \"./helpers/createAppStructure\";\n"],
5
5
  "mappings": "AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,SAAS,gBAAgB;AAEzB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,gCAAgC;AACzC,SAAS,wBAAwB;AACjC,SAAS,6BAA6B;AACtC,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAG9B,cAAc;AACd,cAAc;AAGd,SAAS,cAAc;AAGvB,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;",
6
6
  "names": []
7
7
  }
@@ -14,10 +14,11 @@ export interface StorageAdapter {
14
14
  * 로그 어댑터 인터페이스
15
15
  *
16
16
  * @remarks
17
- * - `useLogger`에서 consola 출력 외에 추가 로그 전송(DB, 서버 등)에 사용
17
+ * - `useLogger`에서 사용하는 로그 전송 어댑터 (DB, 서버 등)
18
+ * - adapter가 설정되면 consola 대신 adapter만 사용됨
18
19
  */
19
20
  export interface LogAdapter {
20
- write(severity: "error" | "warn" | "log", ...data: any[]): Promise<void> | void;
21
+ write(severity: "error" | "warn" | "info" | "log", ...data: any[]): Promise<void> | void;
21
22
  }
22
23
  /**
23
24
  * 앱 전역 설정
@@ -28,7 +29,7 @@ export interface AppConfig {
28
29
  */
29
30
  clientName: string;
30
31
  /**
31
- * 동기화 가능 저장소 (useSyncConfig에서 사용, 기본값: localStorage)
32
+ * 동기화 가능 저장소 (useSyncConfig에서 사용, 없으면 localStorage로 fallback)
32
33
  */
33
34
  syncStorage?: StorageAdapter;
34
35
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigContext.d.ts","sourceRoot":"","sources":["../../src/providers/ConfigContext.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACjF;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;CACpC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,mDAA6B,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAMrC"}
1
+ {"version":3,"file":"ConfigContext.d.ts","sourceRoot":"","sources":["../../src/providers/ConfigContext.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1F;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;CACpC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,mDAA6B,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAMrC"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/providers/ConfigContext.ts"],
4
- "sourcesContent": ["import { createContext, useContext } from \"solid-js\";\n\n/**\n * \uCEE4\uC2A4\uD140 \uC800\uC7A5\uC18C \uC5B4\uB311\uD130 \uC778\uD130\uD398\uC774\uC2A4\n *\n * @remarks\n * - \uB3D9\uAE30 \uC800\uC7A5\uC18C: `localStorage`, `sessionStorage` \uB4F1 \uADF8\uB300\uB85C \uC804\uB2EC \uAC00\uB2A5\n * - \uBE44\uB3D9\uAE30 \uC800\uC7A5\uC18C: `getItem`\uC774 `Promise`\uB97C \uBC18\uD658\uD558\uB294 \uAD6C\uD604\uCCB4 \uC804\uB2EC\n */\nexport interface StorageAdapter {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<unknown>;\n removeItem(key: string): void | Promise<void>;\n}\n\n/**\n * \uB85C\uADF8 \uC5B4\uB311\uD130 \uC778\uD130\uD398\uC774\uC2A4\n *\n * @remarks\n * - `useLogger`\uC5D0\uC11C consola \uCD9C\uB825 \uC678\uC5D0 \uCD94\uAC00 \uB85C\uADF8 \uC804\uC1A1(DB, \uC11C\uBC84 \uB4F1)\uC5D0 \uC0AC\uC6A9\n */\nexport interface LogAdapter {\n write(severity: \"error\" | \"warn\" | \"log\", ...data: any[]): Promise<void> | void;\n}\n\n/**\n * \uC571 \uC804\uC5ED \uC124\uC815\n */\nexport interface AppConfig {\n /**\n * \uD074\uB77C\uC774\uC5B8\uD2B8 \uC2DD\uBCC4\uC790 (\uC800\uC7A5\uC18C key prefix\uB85C \uC0AC\uC6A9)\n */\n clientName: string;\n\n /**\n * \uB3D9\uAE30\uD654 \uAC00\uB2A5 \uC800\uC7A5\uC18C (useSyncConfig\uC5D0\uC11C \uC0AC\uC6A9, \uAE30\uBCF8\uAC12: localStorage)\n */\n syncStorage?: StorageAdapter;\n\n /**\n * \uB85C\uADF8 \uC5B4\uB311\uD130 (useLogger\uC5D0\uC11C consola \uC678 \uCD94\uAC00 \uC804\uC1A1\uC5D0 \uC0AC\uC6A9)\n */\n logger?: LogAdapter;\n\n /**\n * \uB8E8\uD2B8 \uB85C\uB529 \uC624\uBC84\uB808\uC774 \uBCC0\uD615 (\uAE30\uBCF8\uAC12: \"spinner\")\n */\n loadingVariant?: \"spinner\" | \"bar\";\n}\n\n/**\n * \uC571 \uC804\uC5ED \uC124\uC815 Context\n *\n * @example\n * ```tsx\n * // \uC571 \uB8E8\uD2B8\uC5D0\uC11C Provider \uC124\uC815\n * <ConfigContext.Provider value={{ clientName: \"myApp\" }}>\n * <App />\n * </ConfigContext.Provider>\n *\n * // \uCEF4\uD3EC\uB10C\uD2B8\uC5D0\uC11C \uC0AC\uC6A9\n * const config = useConfig();\n * console.log(config.clientName); // \"myApp\"\n * ```\n */\nexport const ConfigContext = createContext<AppConfig>();\n\n/**\n * \uC571 \uC804\uC5ED \uC124\uC815\uC5D0 \uC811\uADFC\uD558\uB294 \uD6C5\n *\n * @throws ConfigContext.Provider\uAC00 \uC5C6\uC73C\uBA74 \uC5D0\uB7EC \uBC1C\uC0DD\n */\nexport function useConfig(): AppConfig {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error(\"useConfig\uB294 ConfigContext.Provider \uB0B4\uBD80\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4\");\n }\n return context;\n}\n"],
5
- "mappings": "AAAA,SAAS,eAAe,kBAAkB;AAiEnC,MAAM,gBAAgB,cAAyB;AAO/C,SAAS,YAAuB;AACrC,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,0HAAoD;AAAA,EACtE;AACA,SAAO;AACT;",
4
+ "sourcesContent": ["import { createContext, useContext } from \"solid-js\";\n\n/**\n * \uCEE4\uC2A4\uD140 \uC800\uC7A5\uC18C \uC5B4\uB311\uD130 \uC778\uD130\uD398\uC774\uC2A4\n *\n * @remarks\n * - \uB3D9\uAE30 \uC800\uC7A5\uC18C: `localStorage`, `sessionStorage` \uB4F1 \uADF8\uB300\uB85C \uC804\uB2EC \uAC00\uB2A5\n * - \uBE44\uB3D9\uAE30 \uC800\uC7A5\uC18C: `getItem`\uC774 `Promise`\uB97C \uBC18\uD658\uD558\uB294 \uAD6C\uD604\uCCB4 \uC804\uB2EC\n */\nexport interface StorageAdapter {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<unknown>;\n removeItem(key: string): void | Promise<void>;\n}\n\n/**\n * \uB85C\uADF8 \uC5B4\uB311\uD130 \uC778\uD130\uD398\uC774\uC2A4\n *\n * @remarks\n * - `useLogger`\uC5D0\uC11C \uC0AC\uC6A9\uD558\uB294 \uB85C\uADF8 \uC804\uC1A1 \uC5B4\uB311\uD130 (DB, \uC11C\uBC84 \uB4F1)\n * - adapter\uAC00 \uC124\uC815\uB418\uBA74 consola \uB300\uC2E0 adapter\uB9CC \uC0AC\uC6A9\uB428\n */\nexport interface LogAdapter {\n write(severity: \"error\" | \"warn\" | \"info\" | \"log\", ...data: any[]): Promise<void> | void;\n}\n\n/**\n * \uC571 \uC804\uC5ED \uC124\uC815\n */\nexport interface AppConfig {\n /**\n * \uD074\uB77C\uC774\uC5B8\uD2B8 \uC2DD\uBCC4\uC790 (\uC800\uC7A5\uC18C key prefix\uB85C \uC0AC\uC6A9)\n */\n clientName: string;\n\n /**\n * \uB3D9\uAE30\uD654 \uAC00\uB2A5 \uC800\uC7A5\uC18C (useSyncConfig\uC5D0\uC11C \uC0AC\uC6A9, \uC5C6\uC73C\uBA74 localStorage\uB85C fallback)\n */\n syncStorage?: StorageAdapter;\n\n /**\n * \uB85C\uADF8 \uC5B4\uB311\uD130 (useLogger\uC5D0\uC11C consola \uC678 \uCD94\uAC00 \uC804\uC1A1\uC5D0 \uC0AC\uC6A9)\n */\n logger?: LogAdapter;\n\n /**\n * \uB8E8\uD2B8 \uB85C\uB529 \uC624\uBC84\uB808\uC774 \uBCC0\uD615 (\uAE30\uBCF8\uAC12: \"spinner\")\n */\n loadingVariant?: \"spinner\" | \"bar\";\n}\n\n/**\n * \uC571 \uC804\uC5ED \uC124\uC815 Context\n *\n * @example\n * ```tsx\n * // \uC571 \uB8E8\uD2B8\uC5D0\uC11C Provider \uC124\uC815\n * <ConfigContext.Provider value={{ clientName: \"myApp\" }}>\n * <App />\n * </ConfigContext.Provider>\n *\n * // \uCEF4\uD3EC\uB10C\uD2B8\uC5D0\uC11C \uC0AC\uC6A9\n * const config = useConfig();\n * console.log(config.clientName); // \"myApp\"\n * ```\n */\nexport const ConfigContext = createContext<AppConfig>();\n\n/**\n * \uC571 \uC804\uC5ED \uC124\uC815\uC5D0 \uC811\uADFC\uD558\uB294 \uD6C5\n *\n * @throws ConfigContext.Provider\uAC00 \uC5C6\uC73C\uBA74 \uC5D0\uB7EC \uBC1C\uC0DD\n */\nexport function useConfig(): AppConfig {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error(\"useConfig\uB294 ConfigContext.Provider \uB0B4\uBD80\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4\");\n }\n return context;\n}\n"],
5
+ "mappings": "AAAA,SAAS,eAAe,kBAAkB;AAkEnC,MAAM,gBAAgB,cAAyB;AAO/C,SAAS,YAAuB;AACrC,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,0HAAoD;AAAA,EACtE;AACA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -9,6 +9,7 @@ import { type AppConfig } from "./ConfigContext";
9
9
  * - 폼 컨트롤 value 클립보드 복사 지원
10
10
  * - 테마 (라이트/다크/시스템)
11
11
  * - 알림 시스템 + 배너
12
+ * - 전역 에러 캡처 (window.onerror, unhandledrejection)
12
13
  * - 루트 로딩 오버레이
13
14
  * - 프로그래매틱 다이얼로그
14
15
  *
@@ -1 +1 @@
1
- {"version":3,"file":"InitializeProvider.d.ts","sourceRoot":"","sources":["../../src/providers/InitializeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,iBAAiB,CAAC;AAehE;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,kBAAkB,EAAE,eAAe,CAAC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAmBrE,CAAC"}
1
+ {"version":3,"file":"InitializeProvider.d.ts","sourceRoot":"","sources":["../../src/providers/InitializeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,iBAAiB,CAAC;AAuChE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,kBAAkB,EAAE,eAAe,CAAC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAoBrE,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { onCleanup } from "solid-js";
1
2
  import { ConfigContext } from "./ConfigContext.js";
2
3
  import { useClipboardValueCopy } from "../hooks/useClipboardValueCopy.js";
3
4
  import { ThemeProvider } from "./ThemeContext.js";
@@ -6,13 +7,30 @@ import { NotificationBanner } from "../components/feedback/notification/Notifica
6
7
  import { LoadingProvider } from "../components/feedback/loading/LoadingProvider.js";
7
8
  import { DialogProvider } from "../components/disclosure/DialogProvider.js";
8
9
  import { createPwaUpdate } from "../hooks/createPwaUpdate.js";
10
+ import { useLogger } from "../hooks/useLogger.js";
9
11
  function PwaUpdater() {
10
12
  createPwaUpdate();
11
13
  return null;
12
14
  }
15
+ function GlobalErrorLogger() {
16
+ const logger = useLogger();
17
+ const onError = (event) => {
18
+ logger.error("Uncaught error:", event.error ?? event.message);
19
+ };
20
+ const onUnhandledRejection = (event) => {
21
+ logger.error("Unhandled rejection:", event.reason);
22
+ };
23
+ window.addEventListener("error", onError);
24
+ window.addEventListener("unhandledrejection", onUnhandledRejection);
25
+ onCleanup(() => {
26
+ window.removeEventListener("error", onError);
27
+ window.removeEventListener("unhandledrejection", onUnhandledRejection);
28
+ });
29
+ return null;
30
+ }
13
31
  const InitializeProvider = (props) => {
14
32
  useClipboardValueCopy();
15
- return /* @__PURE__ */ React.createElement(ConfigContext.Provider, { value: props.config }, /* @__PURE__ */ React.createElement(ThemeProvider, null, /* @__PURE__ */ React.createElement(NotificationProvider, null, /* @__PURE__ */ React.createElement(NotificationBanner, null), /* @__PURE__ */ React.createElement(PwaUpdater, null), /* @__PURE__ */ React.createElement(LoadingProvider, { variant: props.config.loadingVariant }, /* @__PURE__ */ React.createElement(DialogProvider, null, props.children)))));
33
+ return /* @__PURE__ */ React.createElement(ConfigContext.Provider, { value: props.config }, /* @__PURE__ */ React.createElement(ThemeProvider, null, /* @__PURE__ */ React.createElement(NotificationProvider, null, /* @__PURE__ */ React.createElement(NotificationBanner, null), /* @__PURE__ */ React.createElement(GlobalErrorLogger, null), /* @__PURE__ */ React.createElement(PwaUpdater, null), /* @__PURE__ */ React.createElement(LoadingProvider, { variant: props.config.loadingVariant }, /* @__PURE__ */ React.createElement(DialogProvider, null, props.children)))));
16
34
  };
17
35
  export {
18
36
  InitializeProvider
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/providers/InitializeProvider.tsx"],
4
- "sourcesContent": ["import type { ParentComponent } from \"solid-js\";\nimport { type AppConfig, ConfigContext } from \"./ConfigContext\";\nimport { useClipboardValueCopy } from \"../hooks/useClipboardValueCopy\";\nimport { ThemeProvider } from \"./ThemeContext\";\nimport { NotificationProvider } from \"../components/feedback/notification/NotificationProvider\";\nimport { NotificationBanner } from \"../components/feedback/notification/NotificationBanner\";\nimport { LoadingProvider } from \"../components/feedback/loading/LoadingProvider\";\nimport { DialogProvider } from \"../components/disclosure/DialogProvider\";\nimport { createPwaUpdate } from \"../hooks/createPwaUpdate\";\n\n/** Runs PWA update detection inside NotificationProvider context */\nfunction PwaUpdater() {\n createPwaUpdate();\n return null;\n}\n\n/**\n * @simplysm/solid \uCD08\uAE30\uD654 Provider\n *\n * @remarks\n * \uC571 \uB8E8\uD2B8\uC5D0\uC11C \uD55C \uBC88 \uAC10\uC2F8\uBA70, \uB2E4\uC74C\uC744 \uCD08\uAE30\uD654\uD55C\uB2E4:\n * - \uC571 \uC804\uC5ED \uC124\uC815 (config) Context \uC81C\uACF5\n * - \uD3FC \uCEE8\uD2B8\uB864 value \uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC \uC9C0\uC6D0\n * - \uD14C\uB9C8 (\uB77C\uC774\uD2B8/\uB2E4\uD06C/\uC2DC\uC2A4\uD15C)\n * - \uC54C\uB9BC \uC2DC\uC2A4\uD15C + \uBC30\uB108\n * - \uB8E8\uD2B8 \uB85C\uB529 \uC624\uBC84\uB808\uC774\n * - \uD504\uB85C\uADF8\uB798\uB9E4\uD2F1 \uB2E4\uC774\uC5BC\uB85C\uADF8\n *\n * @example\n * ```tsx\n * <InitializeProvider config={{ clientName: \"myApp\" }}>\n * <App />\n * </InitializeProvider>\n * ```\n */\nexport const InitializeProvider: ParentComponent<{ config: AppConfig }> = (props) => {\n // \uD3FC \uCEE8\uD2B8\uB864 value \uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC\n useClipboardValueCopy();\n\n /* eslint-disable solid/reactivity -- config\uB294 \uCD08\uAE30 \uC124\uC815\uAC12\uC73C\uB85C \uBCC0\uACBD\uB418\uC9C0 \uC54A\uC74C */\n return (\n <ConfigContext.Provider value={props.config}>\n <ThemeProvider>\n <NotificationProvider>\n <NotificationBanner />\n <PwaUpdater />\n <LoadingProvider variant={props.config.loadingVariant}>\n <DialogProvider>{props.children}</DialogProvider>\n </LoadingProvider>\n </NotificationProvider>\n </ThemeProvider>\n </ConfigContext.Provider>\n );\n /* eslint-enable solid/reactivity */\n};\n"],
5
- "mappings": "AACA,SAAyB,qBAAqB;AAC9C,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAGhC,SAAS,aAAa;AACpB,kBAAgB;AAChB,SAAO;AACT;AAqBO,MAAM,qBAA6D,CAAC,UAAU;AAEnF,wBAAsB;AAGtB,SACE,oCAAC,cAAc,UAAd,EAAuB,OAAO,MAAM,UACnC,oCAAC,qBACC,oCAAC,4BACC,oCAAC,wBAAmB,GACpB,oCAAC,gBAAW,GACZ,oCAAC,mBAAgB,SAAS,MAAM,OAAO,kBACrC,oCAAC,sBAAgB,MAAM,QAAS,CAClC,CACF,CACF,CACF;AAGJ;",
4
+ "sourcesContent": ["import type { ParentComponent } from \"solid-js\";\nimport { onCleanup } from \"solid-js\";\nimport { type AppConfig, ConfigContext } from \"./ConfigContext\";\nimport { useClipboardValueCopy } from \"../hooks/useClipboardValueCopy\";\nimport { ThemeProvider } from \"./ThemeContext\";\nimport { NotificationProvider } from \"../components/feedback/notification/NotificationProvider\";\nimport { NotificationBanner } from \"../components/feedback/notification/NotificationBanner\";\nimport { LoadingProvider } from \"../components/feedback/loading/LoadingProvider\";\nimport { DialogProvider } from \"../components/disclosure/DialogProvider\";\nimport { createPwaUpdate } from \"../hooks/createPwaUpdate\";\nimport { useLogger } from \"../hooks/useLogger\";\n\n/** Runs PWA update detection inside NotificationProvider context */\nfunction PwaUpdater() {\n createPwaUpdate();\n return null;\n}\n\n/** Captures uncaught errors and unhandled rejections via useLogger */\nfunction GlobalErrorLogger() {\n const logger = useLogger();\n\n const onError = (event: ErrorEvent) => {\n logger.error(\"Uncaught error:\", event.error ?? event.message);\n };\n\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n logger.error(\"Unhandled rejection:\", event.reason);\n };\n\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onUnhandledRejection);\n\n onCleanup(() => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onUnhandledRejection);\n });\n\n return null;\n}\n\n/**\n * @simplysm/solid \uCD08\uAE30\uD654 Provider\n *\n * @remarks\n * \uC571 \uB8E8\uD2B8\uC5D0\uC11C \uD55C \uBC88 \uAC10\uC2F8\uBA70, \uB2E4\uC74C\uC744 \uCD08\uAE30\uD654\uD55C\uB2E4:\n * - \uC571 \uC804\uC5ED \uC124\uC815 (config) Context \uC81C\uACF5\n * - \uD3FC \uCEE8\uD2B8\uB864 value \uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC \uC9C0\uC6D0\n * - \uD14C\uB9C8 (\uB77C\uC774\uD2B8/\uB2E4\uD06C/\uC2DC\uC2A4\uD15C)\n * - \uC54C\uB9BC \uC2DC\uC2A4\uD15C + \uBC30\uB108\n * - \uC804\uC5ED \uC5D0\uB7EC \uCEA1\uCC98 (window.onerror, unhandledrejection)\n * - \uB8E8\uD2B8 \uB85C\uB529 \uC624\uBC84\uB808\uC774\n * - \uD504\uB85C\uADF8\uB798\uB9E4\uD2F1 \uB2E4\uC774\uC5BC\uB85C\uADF8\n *\n * @example\n * ```tsx\n * <InitializeProvider config={{ clientName: \"myApp\" }}>\n * <App />\n * </InitializeProvider>\n * ```\n */\nexport const InitializeProvider: ParentComponent<{ config: AppConfig }> = (props) => {\n // \uD3FC \uCEE8\uD2B8\uB864 value \uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC\n useClipboardValueCopy();\n\n /* eslint-disable solid/reactivity -- config\uB294 \uCD08\uAE30 \uC124\uC815\uAC12\uC73C\uB85C \uBCC0\uACBD\uB418\uC9C0 \uC54A\uC74C */\n return (\n <ConfigContext.Provider value={props.config}>\n <ThemeProvider>\n <NotificationProvider>\n <NotificationBanner />\n <GlobalErrorLogger />\n <PwaUpdater />\n <LoadingProvider variant={props.config.loadingVariant}>\n <DialogProvider>{props.children}</DialogProvider>\n </LoadingProvider>\n </NotificationProvider>\n </ThemeProvider>\n </ConfigContext.Provider>\n );\n /* eslint-enable solid/reactivity */\n};\n"],
5
+ "mappings": "AACA,SAAS,iBAAiB;AAC1B,SAAyB,qBAAqB;AAC9C,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAG1B,SAAS,aAAa;AACpB,kBAAgB;AAChB,SAAO;AACT;AAGA,SAAS,oBAAoB;AAC3B,QAAM,SAAS,UAAU;AAEzB,QAAM,UAAU,CAAC,UAAsB;AACrC,WAAO,MAAM,mBAAmB,MAAM,SAAS,MAAM,OAAO;AAAA,EAC9D;AAEA,QAAM,uBAAuB,CAAC,UAAiC;AAC7D,WAAO,MAAM,wBAAwB,MAAM,MAAM;AAAA,EACnD;AAEA,SAAO,iBAAiB,SAAS,OAAO;AACxC,SAAO,iBAAiB,sBAAsB,oBAAoB;AAElE,YAAU,MAAM;AACd,WAAO,oBAAoB,SAAS,OAAO;AAC3C,WAAO,oBAAoB,sBAAsB,oBAAoB;AAAA,EACvE,CAAC;AAED,SAAO;AACT;AAsBO,MAAM,qBAA6D,CAAC,UAAU;AAEnF,wBAAsB;AAGtB,SACE,oCAAC,cAAc,UAAd,EAAuB,OAAO,MAAM,UACnC,oCAAC,qBACC,oCAAC,4BACC,oCAAC,wBAAmB,GACpB,oCAAC,uBAAkB,GACnB,oCAAC,gBAAW,GACZ,oCAAC,mBAAgB,SAAS,MAAM,OAAO,kBACrC,oCAAC,sBAAgB,MAAM,QAAS,CAClC,CACF,CACF,CACF;AAGJ;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SharedDataProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/shared-data/SharedDataProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,GAAG,EAAuC,MAAM,UAAU,CAAC;AAExF,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,qBAAqB,CAAC;AAK7B,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE;IAC3E,WAAW,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAAE,CAAC;IAC5D,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB,GAAG,GAAG,CAAC,OAAO,CAqId"}
1
+ {"version":3,"file":"SharedDataProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/shared-data/SharedDataProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,GAAG,EAAuC,MAAM,UAAU,CAAC;AAExF,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,qBAAqB,CAAC;AAM7B,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE;IAC3E,WAAW,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAAE,CAAC;IAC5D,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB,GAAG,GAAG,CAAC,OAAO,CAuId"}
@@ -6,9 +6,11 @@ import {
6
6
  import { SharedDataChangeEvent } from "./SharedDataChangeEvent.js";
7
7
  import { useServiceClient } from "../ServiceClientContext.js";
8
8
  import { useNotification } from "../../components/feedback/notification/NotificationContext.js";
9
+ import { useLogger } from "../../hooks/useLogger.js";
9
10
  function SharedDataProvider(props) {
10
11
  const serviceClient = useServiceClient();
11
12
  const notification = useNotification();
13
+ const logger = useLogger();
12
14
  const [loadingCount, setLoadingCount] = createSignal(0);
13
15
  const loading = () => loadingCount() > 0;
14
16
  const signalMap = /* @__PURE__ */ new Map();
@@ -47,6 +49,7 @@ function SharedDataProvider(props) {
47
49
  });
48
50
  }
49
51
  } catch (err) {
52
+ logger.error(`SharedData '${name}' fetch failed:`, err);
50
53
  notification.danger(
51
54
  "\uACF5\uC720 \uB370\uC774\uD130 \uB85C\uB4DC \uC2E4\uD328",
52
55
  err instanceof Error ? err.message : `'${name}' \uB370\uC774\uD130\uB97C \uBD88\uB7EC\uC624\uB294 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.`
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/providers/shared-data/SharedDataProvider.tsx"],
4
- "sourcesContent": ["import { type Accessor, type JSX, createMemo, createSignal, onCleanup } from \"solid-js\";\nimport { objEqual, waitUntil } from \"@simplysm/core-common\";\nimport {\n SharedDataContext,\n type SharedDataAccessor,\n type SharedDataDefinition,\n type SharedDataValue,\n} from \"./SharedDataContext\";\nimport { SharedDataChangeEvent } from \"./SharedDataChangeEvent\";\nimport { useServiceClient } from \"../ServiceClientContext\";\nimport { useNotification } from \"../../components/feedback/notification/NotificationContext\";\n\nexport function SharedDataProvider<T extends Record<string, unknown>>(props: {\n definitions: { [K in keyof T]: SharedDataDefinition<T[K]> };\n children: JSX.Element;\n}): JSX.Element {\n const serviceClient = useServiceClient();\n const notification = useNotification();\n\n const [loadingCount, setLoadingCount] = createSignal(0);\n const loading: Accessor<boolean> = () => loadingCount() > 0;\n\n const signalMap = new Map<string, ReturnType<typeof createSignal<unknown[]>>>();\n const memoMap = new Map<string, Accessor<Map<string | number, unknown>>>();\n const listenerKeyMap = new Map<string, string>();\n const versionMap = new Map<string, number>();\n\n function ordering<TT>(data: TT[], orderByList: [(item: TT) => unknown, \"asc\" | \"desc\"][]): TT[] {\n let result = [...data];\n for (const orderBy of [...orderByList].reverse()) {\n const selector = (item: TT) => orderBy[0](item) as string | number | undefined;\n if (orderBy[1] === \"desc\") {\n result = result.orderByDesc(selector);\n } else {\n result = result.orderBy(selector);\n }\n }\n return result;\n }\n\n async function loadData(\n name: string,\n def: SharedDataDefinition<unknown>,\n changeKeys?: Array<string | number>,\n ): Promise<void> {\n // CR-1: version counter\uB85C \uB3D9\uC2DC \uD638\uCD9C \uC2DC \uB370\uC774\uD130 \uC5ED\uC804 \uBC29\uC9C0\n const currentVersion = (versionMap.get(name) ?? 0) + 1;\n versionMap.set(name, currentVersion);\n\n setLoadingCount((c) => c + 1);\n try {\n const signal = signalMap.get(name);\n if (!signal) throw new Error(`'${name}'\uC5D0 \uB300\uD55C \uACF5\uC720\uB370\uC774\uD130 \uC800\uC7A5\uC18C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`);\n\n const [, setItems] = signal;\n const resData = await def.fetch(changeKeys);\n\n // CR-1: \uC624\uB798\uB41C \uC751\uB2F5\uC740 \uBB34\uC2DC\n if (versionMap.get(name) !== currentVersion) return;\n\n if (!changeKeys) {\n setItems(ordering(resData, def.orderBy));\n } else {\n setItems((prev) => {\n const filtered = prev.filter((item) => !changeKeys.includes(def.getKey(item as never)));\n filtered.push(...resData);\n return ordering(filtered, def.orderBy);\n });\n }\n } catch (err) {\n // CR-2: fetch \uC2E4\uD328 \uC2DC \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9BC\n notification.danger(\n \"\uACF5\uC720 \uB370\uC774\uD130 \uB85C\uB4DC \uC2E4\uD328\",\n err instanceof Error ? err.message : `'${name}' \uB370\uC774\uD130\uB97C \uBD88\uB7EC\uC624\uB294 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.`,\n );\n } finally {\n setLoadingCount((c) => c - 1);\n }\n }\n\n async function wait(): Promise<void> {\n // eslint-disable-next-line solid/reactivity -- waitUntil\uC740 \uD3F4\uB9C1 \uAE30\uBC18\uC774\uBBC0\uB85C tracked scope \uBD88\uD544\uC694\n await waitUntil(() => loadingCount() <= 0);\n }\n\n const accessors: Record<string, SharedDataAccessor<unknown>> = {};\n\n // eslint-disable-next-line solid/reactivity -- definitions\uB294 \uCD08\uAE30 \uC124\uC815\uC6A9\uC73C\uB85C \uB9C8\uC6B4\uD2B8 \uC2DC 1\uD68C\uB9CC \uC77D\uC74C\n for (const [name, def] of Object.entries(props.definitions) as [string, SharedDataDefinition<unknown>][]) {\n const [items, setItems] = createSignal<unknown[]>([]);\n // eslint-disable-next-line solid/reactivity -- signal \uCC38\uC870\uB97C Map\uC5D0 \uC800\uC7A5\uD558\uB294 \uAC83\uC740 \uBC18\uC751\uC131 \uC811\uADFC\uC774 \uC544\uB2D8\n signalMap.set(name, [items, setItems]);\n\n const itemMap = createMemo(() => {\n const map = new Map<string | number, unknown>();\n for (const item of items()) {\n map.set(def.getKey(item as never), item);\n }\n return map;\n });\n // eslint-disable-next-line solid/reactivity -- memo \uCC38\uC870\uB97C Map\uC5D0 \uC800\uC7A5\uD558\uB294 \uAC83\uC740 \uBC18\uC751\uC131 \uC811\uADFC\uC774 \uC544\uB2D8\n memoMap.set(name, itemMap);\n\n const client = serviceClient.get(def.serviceKey);\n void client\n .addEventListener(SharedDataChangeEvent, { name, filter: def.filter }, async (changeKeys) => {\n await loadData(name, def, changeKeys);\n })\n .then((key) => {\n listenerKeyMap.set(name, key);\n });\n\n void loadData(name, def);\n\n accessors[name] = {\n items,\n get: (key: string | number | undefined) => {\n if (key === undefined) return undefined;\n return itemMap().get(key);\n },\n emit: async (changeKeys?: Array<string | number>) => {\n await client.emitToServer(\n SharedDataChangeEvent,\n (info) => info.name === name && objEqual(info.filter, def.filter),\n changeKeys,\n );\n },\n };\n }\n\n onCleanup(() => {\n for (const [name] of Object.entries(props.definitions)) {\n const listenerKey = listenerKeyMap.get(name);\n if (listenerKey != null) {\n const def = (props.definitions as Record<string, SharedDataDefinition<unknown>>)[name];\n const client = serviceClient.get(def.serviceKey);\n void client.removeEventListener(listenerKey);\n }\n }\n });\n\n const contextValue = {\n ...accessors,\n wait,\n loading,\n } as SharedDataValue<Record<string, unknown>>;\n\n return <SharedDataContext.Provider value={contextValue}>{props.children}</SharedDataContext.Provider>;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { type Accessor, type JSX, createMemo, createSignal, onCleanup } from \"solid-js\";\nimport { objEqual, waitUntil } from \"@simplysm/core-common\";\nimport {\n SharedDataContext,\n type SharedDataAccessor,\n type SharedDataDefinition,\n type SharedDataValue,\n} from \"./SharedDataContext\";\nimport { SharedDataChangeEvent } from \"./SharedDataChangeEvent\";\nimport { useServiceClient } from \"../ServiceClientContext\";\nimport { useNotification } from \"../../components/feedback/notification/NotificationContext\";\nimport { useLogger } from \"../../hooks/useLogger\";\n\nexport function SharedDataProvider<T extends Record<string, unknown>>(props: {\n definitions: { [K in keyof T]: SharedDataDefinition<T[K]> };\n children: JSX.Element;\n}): JSX.Element {\n const serviceClient = useServiceClient();\n const notification = useNotification();\n const logger = useLogger();\n\n const [loadingCount, setLoadingCount] = createSignal(0);\n const loading: Accessor<boolean> = () => loadingCount() > 0;\n\n const signalMap = new Map<string, ReturnType<typeof createSignal<unknown[]>>>();\n const memoMap = new Map<string, Accessor<Map<string | number, unknown>>>();\n const listenerKeyMap = new Map<string, string>();\n const versionMap = new Map<string, number>();\n\n function ordering<TT>(data: TT[], orderByList: [(item: TT) => unknown, \"asc\" | \"desc\"][]): TT[] {\n let result = [...data];\n for (const orderBy of [...orderByList].reverse()) {\n const selector = (item: TT) => orderBy[0](item) as string | number | undefined;\n if (orderBy[1] === \"desc\") {\n result = result.orderByDesc(selector);\n } else {\n result = result.orderBy(selector);\n }\n }\n return result;\n }\n\n async function loadData(\n name: string,\n def: SharedDataDefinition<unknown>,\n changeKeys?: Array<string | number>,\n ): Promise<void> {\n // CR-1: version counter\uB85C \uB3D9\uC2DC \uD638\uCD9C \uC2DC \uB370\uC774\uD130 \uC5ED\uC804 \uBC29\uC9C0\n const currentVersion = (versionMap.get(name) ?? 0) + 1;\n versionMap.set(name, currentVersion);\n\n setLoadingCount((c) => c + 1);\n try {\n const signal = signalMap.get(name);\n if (!signal) throw new Error(`'${name}'\uC5D0 \uB300\uD55C \uACF5\uC720\uB370\uC774\uD130 \uC800\uC7A5\uC18C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`);\n\n const [, setItems] = signal;\n const resData = await def.fetch(changeKeys);\n\n // CR-1: \uC624\uB798\uB41C \uC751\uB2F5\uC740 \uBB34\uC2DC\n if (versionMap.get(name) !== currentVersion) return;\n\n if (!changeKeys) {\n setItems(ordering(resData, def.orderBy));\n } else {\n setItems((prev) => {\n const filtered = prev.filter((item) => !changeKeys.includes(def.getKey(item as never)));\n filtered.push(...resData);\n return ordering(filtered, def.orderBy);\n });\n }\n } catch (err) {\n // CR-2: fetch \uC2E4\uD328 \uC2DC \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9BC\n logger.error(`SharedData '${name}' fetch failed:`, err);\n notification.danger(\n \"\uACF5\uC720 \uB370\uC774\uD130 \uB85C\uB4DC \uC2E4\uD328\",\n err instanceof Error ? err.message : `'${name}' \uB370\uC774\uD130\uB97C \uBD88\uB7EC\uC624\uB294 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.`,\n );\n } finally {\n setLoadingCount((c) => c - 1);\n }\n }\n\n async function wait(): Promise<void> {\n // eslint-disable-next-line solid/reactivity -- waitUntil\uC740 \uD3F4\uB9C1 \uAE30\uBC18\uC774\uBBC0\uB85C tracked scope \uBD88\uD544\uC694\n await waitUntil(() => loadingCount() <= 0);\n }\n\n const accessors: Record<string, SharedDataAccessor<unknown>> = {};\n\n // eslint-disable-next-line solid/reactivity -- definitions\uB294 \uCD08\uAE30 \uC124\uC815\uC6A9\uC73C\uB85C \uB9C8\uC6B4\uD2B8 \uC2DC 1\uD68C\uB9CC \uC77D\uC74C\n for (const [name, def] of Object.entries(props.definitions) as [string, SharedDataDefinition<unknown>][]) {\n const [items, setItems] = createSignal<unknown[]>([]);\n // eslint-disable-next-line solid/reactivity -- signal \uCC38\uC870\uB97C Map\uC5D0 \uC800\uC7A5\uD558\uB294 \uAC83\uC740 \uBC18\uC751\uC131 \uC811\uADFC\uC774 \uC544\uB2D8\n signalMap.set(name, [items, setItems]);\n\n const itemMap = createMemo(() => {\n const map = new Map<string | number, unknown>();\n for (const item of items()) {\n map.set(def.getKey(item as never), item);\n }\n return map;\n });\n // eslint-disable-next-line solid/reactivity -- memo \uCC38\uC870\uB97C Map\uC5D0 \uC800\uC7A5\uD558\uB294 \uAC83\uC740 \uBC18\uC751\uC131 \uC811\uADFC\uC774 \uC544\uB2D8\n memoMap.set(name, itemMap);\n\n const client = serviceClient.get(def.serviceKey);\n void client\n .addEventListener(SharedDataChangeEvent, { name, filter: def.filter }, async (changeKeys) => {\n await loadData(name, def, changeKeys);\n })\n .then((key) => {\n listenerKeyMap.set(name, key);\n });\n\n void loadData(name, def);\n\n accessors[name] = {\n items,\n get: (key: string | number | undefined) => {\n if (key === undefined) return undefined;\n return itemMap().get(key);\n },\n emit: async (changeKeys?: Array<string | number>) => {\n await client.emitToServer(\n SharedDataChangeEvent,\n (info) => info.name === name && objEqual(info.filter, def.filter),\n changeKeys,\n );\n },\n };\n }\n\n onCleanup(() => {\n for (const [name] of Object.entries(props.definitions)) {\n const listenerKey = listenerKeyMap.get(name);\n if (listenerKey != null) {\n const def = (props.definitions as Record<string, SharedDataDefinition<unknown>>)[name];\n const client = serviceClient.get(def.serviceKey);\n void client.removeEventListener(listenerKey);\n }\n }\n });\n\n const contextValue = {\n ...accessors,\n wait,\n loading,\n } as SharedDataValue<Record<string, unknown>>;\n\n return <SharedDataContext.Provider value={contextValue}>{props.children}</SharedDataContext.Provider>;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/solid",
3
- "version": "13.0.0-beta.28",
3
+ "version": "13.0.0-beta.29",
4
4
  "description": "심플리즘 패키지 - SolidJS 라이브러리",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,8 +44,8 @@
44
44
  "solid-tiptap": "^0.8.0",
45
45
  "tailwind-merge": "^3.4.0",
46
46
  "tailwindcss": "^3.4.19",
47
- "@simplysm/core-browser": "13.0.0-beta.28",
48
- "@simplysm/core-common": "13.0.0-beta.28"
47
+ "@simplysm/core-browser": "13.0.0-beta.29",
48
+ "@simplysm/core-common": "13.0.0-beta.29"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@solidjs/testing-library": "^0.8.10"
@@ -1,9 +0,0 @@
1
- export interface LogEntry {
2
- level: "log" | "info" | "warn" | "error";
3
- message: string;
4
- timestamp: number;
5
- }
6
- export declare const LogAdapter: {
7
- write?: (entry: LogEntry) => void;
8
- };
9
- //# sourceMappingURL=LogConfig.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LogConfig.d.ts","sourceRoot":"","sources":["../../src/configs/LogConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,UAAU,EAAE;IACvB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC9B,CAAC"}
@@ -1,5 +0,0 @@
1
- const LogAdapter = {};
2
- export {
3
- LogAdapter
4
- };
5
- //# sourceMappingURL=LogConfig.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/configs/LogConfig.ts"],
4
- "sourcesContent": ["export interface LogEntry {\n level: \"log\" | \"info\" | \"warn\" | \"error\";\n message: string;\n timestamp: number;\n}\n\nexport const LogAdapter: {\n write?: (entry: LogEntry) => void;\n} = {};\n"],
5
- "mappings": "AAMO,MAAM,aAET,CAAC;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"useLocalConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAgB,MAAM,UAAU,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAmCjH"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/hooks/useLocalConfig.ts"],
4
- "sourcesContent": ["import { type Accessor, type Setter, createSignal } from \"solid-js\";\n\n/**\n * localStorage \uAE30\uBC18 \uC124\uC815 \uAD00\uB9AC \uD6C5.\n * syncStorage \uC124\uC815\uACFC \uBB34\uAD00\uD558\uAC8C \uD56D\uC0C1 localStorage\uB97C \uC0AC\uC6A9\uD55C\uB2E4.\n * \uAE30\uAE30\uBCC4\uB85C \uB3C5\uB9BD\uC801\uC73C\uB85C \uC720\uC9C0\uB418\uC5B4\uC57C \uD558\uB294 \uB370\uC774\uD130(\uC778\uC99D \uD1A0\uD070, \uAE30\uAE30\uBCC4 \uC0C1\uD0DC \uB4F1)\uC5D0 \uC0AC\uC6A9\uD55C\uB2E4.\n *\n * @template T - \uC800\uC7A5\uD560 \uAC12\uC758 \uD0C0\uC785\n * @param key - localStorage \uD0A4\n * @param initialValue - \uCD08\uAE30\uAC12 (\uC635\uC154\uB110)\n * @returns [Accessor<T | undefined>, Setter<T | undefined>] \uD29C\uD50C\n *\n * @example\n * ```tsx\n * const [token, setToken] = useLocalConfig<string>(\"auth-token\");\n *\n * // \uAC12 \uC124\uC815\n * setToken(\"abc123\");\n *\n * // \uAC12 \uC77D\uAE30\n * console.log(token()); // \"abc123\"\n *\n * // \uAC12 \uC81C\uAC70\n * setToken(undefined);\n * ```\n */\nexport function useLocalConfig<T>(key: string, initialValue?: T): [Accessor<T | undefined>, Setter<T | undefined>] {\n // localStorage\uC5D0\uC11C \uCD08\uAE30\uAC12 \uC77D\uAE30\n let storedValue: T | undefined = initialValue;\n try {\n const item = localStorage.getItem(key);\n if (item !== null) {\n storedValue = JSON.parse(item) as T;\n }\n } catch {\n // JSON \uD30C\uC2F1 \uC2E4\uD328 \uC2DC \uCD08\uAE30\uAC12 \uC0AC\uC6A9\n }\n\n const [value, setValue] = createSignal<T | undefined>(storedValue);\n\n const setAndStore = (newValue: T | undefined | ((prev: T | undefined) => T | undefined)) => {\n let resolved: T | undefined;\n\n if (typeof newValue === \"function\") {\n resolved = (newValue as (prev: T | undefined) => T | undefined)(value());\n setValue(() => resolved);\n } else {\n resolved = newValue;\n setValue(() => newValue);\n }\n\n if (resolved === undefined) {\n localStorage.removeItem(key);\n } else {\n localStorage.setItem(key, JSON.stringify(resolved));\n }\n\n return resolved;\n };\n\n return [value, setAndStore as Setter<T | undefined>];\n}\n"],
5
- "mappings": "AAAA,SAAqC,oBAAoB;AA0BlD,SAAS,eAAkB,KAAa,cAAoE;AAEjH,MAAI,cAA6B;AACjC,MAAI;AACF,UAAM,OAAO,aAAa,QAAQ,GAAG;AACrC,QAAI,SAAS,MAAM;AACjB,oBAAc,KAAK,MAAM,IAAI;AAAA,IAC/B;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,QAAM,CAAC,OAAO,QAAQ,IAAI,aAA4B,WAAW;AAEjE,QAAM,cAAc,CAAC,aAAuE;AAC1F,QAAI;AAEJ,QAAI,OAAO,aAAa,YAAY;AAClC,iBAAY,SAAoD,MAAM,CAAC;AACvE,eAAS,MAAM,QAAQ;AAAA,IACzB,OAAO;AACL,iBAAW;AACX,eAAS,MAAM,QAAQ;AAAA,IACzB;AAEA,QAAI,aAAa,QAAW;AAC1B,mBAAa,WAAW,GAAG;AAAA,IAC7B,OAAO;AACL,mBAAa,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,IACpD;AAEA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,OAAO,WAAoC;AACrD;",
6
- "names": []
7
- }