@iris-ui-kit/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/LICENSE +21 -0
  2. package/dist/SidebarLayout-fWQRvK0a.d.cts +26 -0
  3. package/dist/SidebarLayout-fWQRvK0a.d.ts +26 -0
  4. package/dist/admin.cjs +1583 -0
  5. package/dist/admin.cjs.map +1 -0
  6. package/dist/admin.d.cts +183 -0
  7. package/dist/admin.d.ts +183 -0
  8. package/dist/admin.js +9 -0
  9. package/dist/admin.js.map +1 -0
  10. package/dist/async.cjs +97 -0
  11. package/dist/async.cjs.map +1 -0
  12. package/dist/async.d.cts +57 -0
  13. package/dist/async.d.ts +57 -0
  14. package/dist/async.js +5 -0
  15. package/dist/async.js.map +1 -0
  16. package/dist/behaviors.cjs +569 -0
  17. package/dist/behaviors.cjs.map +1 -0
  18. package/dist/behaviors.d.cts +188 -0
  19. package/dist/behaviors.d.ts +188 -0
  20. package/dist/behaviors.js +4 -0
  21. package/dist/behaviors.js.map +1 -0
  22. package/dist/chunk-2TQSTINK.js +541 -0
  23. package/dist/chunk-2TQSTINK.js.map +1 -0
  24. package/dist/chunk-53KFLVIZ.js +68 -0
  25. package/dist/chunk-53KFLVIZ.js.map +1 -0
  26. package/dist/chunk-6BMFMCMQ.js +140 -0
  27. package/dist/chunk-6BMFMCMQ.js.map +1 -0
  28. package/dist/chunk-AUA5GBT6.js +143 -0
  29. package/dist/chunk-AUA5GBT6.js.map +1 -0
  30. package/dist/chunk-DE6V6NOI.js +122 -0
  31. package/dist/chunk-DE6V6NOI.js.map +1 -0
  32. package/dist/chunk-HEJGN6UI.js +78 -0
  33. package/dist/chunk-HEJGN6UI.js.map +1 -0
  34. package/dist/chunk-IDD35UJ6.js +83 -0
  35. package/dist/chunk-IDD35UJ6.js.map +1 -0
  36. package/dist/chunk-J5FB2UB2.js +166 -0
  37. package/dist/chunk-J5FB2UB2.js.map +1 -0
  38. package/dist/chunk-OMOTUHYI.js +66 -0
  39. package/dist/chunk-OMOTUHYI.js.map +1 -0
  40. package/dist/chunk-RZNYIFV2.js +34 -0
  41. package/dist/chunk-RZNYIFV2.js.map +1 -0
  42. package/dist/chunk-SJO74IB3.js +54 -0
  43. package/dist/chunk-SJO74IB3.js.map +1 -0
  44. package/dist/chunk-SORLRLS4.js +53 -0
  45. package/dist/chunk-SORLRLS4.js.map +1 -0
  46. package/dist/chunk-TO7YVSAI.js +64 -0
  47. package/dist/chunk-TO7YVSAI.js.map +1 -0
  48. package/dist/chunk-TQ33XJIK.js +22 -0
  49. package/dist/chunk-TQ33XJIK.js.map +1 -0
  50. package/dist/chunk-UWUUEZCD.js +950 -0
  51. package/dist/chunk-UWUUEZCD.js.map +1 -0
  52. package/dist/chunk-VWCJJRSC.js +1200 -0
  53. package/dist/chunk-VWCJJRSC.js.map +1 -0
  54. package/dist/chunk-WIHBIDVJ.js +54 -0
  55. package/dist/chunk-WIHBIDVJ.js.map +1 -0
  56. package/dist/chunk-XCK4RIXB.js +66 -0
  57. package/dist/chunk-XCK4RIXB.js.map +1 -0
  58. package/dist/chunk-YAHXR2CJ.js +48 -0
  59. package/dist/chunk-YAHXR2CJ.js.map +1 -0
  60. package/dist/chunk-YXIO5THG.js +4 -0
  61. package/dist/chunk-YXIO5THG.js.map +1 -0
  62. package/dist/chunk-ZKBDUWUD.js +156 -0
  63. package/dist/chunk-ZKBDUWUD.js.map +1 -0
  64. package/dist/data.cjs +112 -0
  65. package/dist/data.cjs.map +1 -0
  66. package/dist/data.d.cts +53 -0
  67. package/dist/data.d.ts +53 -0
  68. package/dist/data.js +5 -0
  69. package/dist/data.js.map +1 -0
  70. package/dist/error-boundary.cjs +106 -0
  71. package/dist/error-boundary.cjs.map +1 -0
  72. package/dist/error-boundary.d.cts +41 -0
  73. package/dist/error-boundary.d.ts +41 -0
  74. package/dist/error-boundary.js +6 -0
  75. package/dist/error-boundary.js.map +1 -0
  76. package/dist/floating.cjs +163 -0
  77. package/dist/floating.cjs.map +1 -0
  78. package/dist/floating.d.cts +92 -0
  79. package/dist/floating.d.ts +92 -0
  80. package/dist/floating.js +5 -0
  81. package/dist/floating.js.map +1 -0
  82. package/dist/form.cjs +159 -0
  83. package/dist/form.cjs.map +1 -0
  84. package/dist/form.d.cts +120 -0
  85. package/dist/form.d.ts +120 -0
  86. package/dist/form.js +5 -0
  87. package/dist/form.js.map +1 -0
  88. package/dist/i18n.cjs +100 -0
  89. package/dist/i18n.cjs.map +1 -0
  90. package/dist/i18n.d.cts +50 -0
  91. package/dist/i18n.d.ts +50 -0
  92. package/dist/i18n.js +5 -0
  93. package/dist/i18n.js.map +1 -0
  94. package/dist/index.cjs +16635 -0
  95. package/dist/index.cjs.map +1 -0
  96. package/dist/index.d.cts +2964 -0
  97. package/dist/index.d.ts +2964 -0
  98. package/dist/index.js +12217 -0
  99. package/dist/index.js.map +1 -0
  100. package/dist/layouts.cjs +386 -0
  101. package/dist/layouts.cjs.map +1 -0
  102. package/dist/layouts.d.cts +92 -0
  103. package/dist/layouts.d.ts +92 -0
  104. package/dist/layouts.js +6 -0
  105. package/dist/layouts.js.map +1 -0
  106. package/dist/modal-utils.cjs +168 -0
  107. package/dist/modal-utils.cjs.map +1 -0
  108. package/dist/modal-utils.d.cts +43 -0
  109. package/dist/modal-utils.d.ts +43 -0
  110. package/dist/modal-utils.js +4 -0
  111. package/dist/modal-utils.js.map +1 -0
  112. package/dist/motion.cjs +104 -0
  113. package/dist/motion.cjs.map +1 -0
  114. package/dist/motion.d.cts +41 -0
  115. package/dist/motion.d.ts +41 -0
  116. package/dist/motion.js +4 -0
  117. package/dist/motion.js.map +1 -0
  118. package/dist/provider.cjs +191 -0
  119. package/dist/provider.cjs.map +1 -0
  120. package/dist/provider.d.cts +62 -0
  121. package/dist/provider.d.ts +62 -0
  122. package/dist/provider.js +8 -0
  123. package/dist/provider.js.map +1 -0
  124. package/dist/resource.cjs +61 -0
  125. package/dist/resource.cjs.map +1 -0
  126. package/dist/resource.d.cts +21 -0
  127. package/dist/resource.d.ts +21 -0
  128. package/dist/resource.js +5 -0
  129. package/dist/resource.js.map +1 -0
  130. package/dist/skeletons.cjs +1304 -0
  131. package/dist/skeletons.cjs.map +1 -0
  132. package/dist/skeletons.d.cts +70 -0
  133. package/dist/skeletons.d.ts +70 -0
  134. package/dist/skeletons.js +8 -0
  135. package/dist/skeletons.js.map +1 -0
  136. package/dist/skins.cjs +134 -0
  137. package/dist/skins.cjs.map +1 -0
  138. package/dist/skins.d.cts +45 -0
  139. package/dist/skins.d.ts +45 -0
  140. package/dist/skins.js +5 -0
  141. package/dist/skins.js.map +1 -0
  142. package/dist/theme.cjs +100 -0
  143. package/dist/theme.cjs.map +1 -0
  144. package/dist/theme.d.cts +71 -0
  145. package/dist/theme.d.ts +71 -0
  146. package/dist/theme.js +5 -0
  147. package/dist/theme.js.map +1 -0
  148. package/dist/undo.cjs +73 -0
  149. package/dist/undo.cjs.map +1 -0
  150. package/dist/undo.d.cts +47 -0
  151. package/dist/undo.d.ts +47 -0
  152. package/dist/undo.js +4 -0
  153. package/dist/undo.js.map +1 -0
  154. package/package.json +61 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/motion/usePrefersReducedMotion.ts","../src/motion/styles.ts","../src/motion/useDataState.ts"],"names":["React2"],"mappings":";;;;;AAEA,IAAM,KAAA,GAAQ,kCAAA;AAEd,SAAS,IAAA,GAAgB;AACvB,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,UAAA,KAAe,YAAY,OAAO,KAAA;AACrF,EAAA,OAAO,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA,CAAE,OAAA;AAClC;AAOO,SAAS,uBAAA,GAAmC;AACjD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAU,eAAS,IAAI,CAAA;AAEjD,EAAM,gBAAU,MAAM;AACpB,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,eAAe,UAAA,EAAY;AAC9E,IAAA,MAAM,EAAA,GAAK,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA;AAClC,IAAA,MAAM,QAAA,GAAW,MAAM,UAAA,CAAW,EAAA,CAAG,OAAO,CAAA;AAC5C,IAAA,QAAA,EAAS;AACT,IAAA,EAAA,CAAG,gBAAA,GAAmB,UAAU,QAAQ,CAAA;AACxC,IAAA,OAAO,MAAM,EAAA,CAAG,mBAAA,GAAsB,QAAA,EAAU,QAAQ,CAAA;AAAA,EAC1D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,OAAA;AACT;;;AC3BO,IAAM,qBAAA,GAAwB,wBAAA;AAG9B,IAAM,gBAAA,GAAmB;AAEhC,IAAM,GAAA,GAAM;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA,EAKT,gBAAgB,CAAA;AAAA;AAAA;AAAA;AAAA,GAAA,EAId,gBAAgB,CAAA;AAAA;AAAA,CAAA,CAEnB,IAAA,EAAK;AAEP,IAAI,SAAA,GAAY,KAAA;AAGT,SAAS,sBAAA,GAA+B;AAC7C,EAAA,IAAI,SAAA,EAAW;AACf,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACrC,EAAA,IAAI,QAAA,CAAS,cAAA,CAAe,qBAAqB,CAAA,EAAG;AAClD,IAAA,SAAA,GAAY,IAAA;AACZ,IAAA;AAAA,EACF;AACA,EAAA,MAAM,EAAA,GAAK,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACzC,EAAA,EAAA,CAAG,EAAA,GAAK,qBAAA;AACR,EAAA,EAAA,CAAG,WAAA,GAAc,GAAA;AACjB,EAAA,QAAA,CAAS,IAAA,CAAK,YAAY,EAAE,CAAA;AAC5B,EAAA,SAAA,GAAY,IAAA;AACd;AAEO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,SAAA,GAAY,KAAA;AACZ,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACnC,IAAA,QAAA,CAAS,cAAA,CAAe,qBAAqB,CAAA,EAAG,MAAA,EAAO;AAAA,EACzD;AACF;;;ACVO,SAAS,aAAa,KAAA,EAA2C;AACtE,EAAMA,KAAA,CAAA,SAAA,CAAU,sBAAA,EAAwB,EAAE,CAAA;AAC1C,EAAA,MAAM,UAAU,uBAAA,EAAwB;AACxC,EAAA,MAAM,KAAA,GAAQ,iBAAiB,KAAK,CAAA;AACpC,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAW,KAAA,KAAU,SAAA;AAAA,IACrB,QAAA,EAAU,KAAA;AAAA,IACV,UAAA,EAAY;AAAA,MACV,SAAA,EAAW,UAAU,EAAA,GAAK,gBAAA;AAAA,MAC1B,iBAAA,EAAmB;AAAA;AACrB,GACF;AACF","file":"chunk-HEJGN6UI.js","sourcesContent":["import * as React from 'react'\n\nconst QUERY = '(prefers-reduced-motion: reduce)'\n\nfunction read(): boolean {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false\n return window.matchMedia(QUERY).matches\n}\n\n/**\n * Reactive `prefers-reduced-motion` flag. Returns `false` where `matchMedia`\n * is unavailable (SSR / older jsdom) so animation is the safe default only when\n * the user has not asked to reduce it.\n */\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = React.useState(read)\n\n React.useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n const mq = window.matchMedia(QUERY)\n const onChange = () => setReduced(mq.matches)\n onChange()\n mq.addEventListener?.('change', onChange)\n return () => mq.removeEventListener?.('change', onChange)\n }, [])\n\n return reduced\n}\n","export const __DATA_STATE_STYLE_ID = 'iris-data-state-styles'\n\n/** Class applied to a state node so its entry cross-fades in. */\nexport const DATA_STATE_CLASS = 'iris-data-state-enter'\n\nconst CSS = `\n@keyframes iris-data-state-enter {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: none; }\n}\n.${DATA_STATE_CLASS} {\n animation: iris-data-state-enter var(--iris-duration-md, 200ms) ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .${DATA_STATE_CLASS} { animation: none; }\n}\n`.trim()\n\nlet installed = false\n\n/** Idempotently inject the data-state enter keyframes (SSR-safe no-op). */\nexport function installDataStateStyles(): void {\n if (installed) return\n if (typeof document === 'undefined') return\n if (document.getElementById(__DATA_STATE_STYLE_ID)) {\n installed = true\n return\n }\n const el = document.createElement('style')\n el.id = __DATA_STATE_STYLE_ID\n el.textContent = CSS\n document.head.appendChild(el)\n installed = true\n}\n\nexport function __resetDataStateStyles(): void {\n installed = false\n if (typeof document !== 'undefined') {\n document.getElementById(__DATA_STATE_STYLE_ID)?.remove()\n }\n}\n","import * as React from 'react'\nimport { resolveDataState, type DataState, type DataStateInput } from '@iris-ui-kit/core'\nimport { DATA_STATE_CLASS, installDataStateStyles } from './styles'\nimport { usePrefersReducedMotion } from './usePrefersReducedMotion'\n\nexport interface DataStateNodeProps {\n className: string\n 'data-iris-state': DataState\n}\n\nexport interface UseDataStateReturn {\n /** Resolved state (`error → loading → empty → content` precedence). */\n state: DataState\n /** `true` when the host should render its real content. */\n isContent: boolean\n /** Use as the React `key` of the state node so the enter animation replays on each transition. */\n stateKey: DataState\n /** Spread onto the rendered loading/error/empty node. */\n stateProps: DataStateNodeProps\n}\n\n/**\n * State-transition + entry-animation hook for data components. Resolves the\n * active {@link DataState} from `{ loading, error, empty }`, and returns props\n * for the state node that (a) re-key on every transition so the cross-fade\n * replays and (b) drop the animation class when the user prefers reduced motion.\n *\n * The framework-agnostic precedence lives in `@iris-ui-kit/core`'s\n * {@link resolveDataState}; this hook is the thin React animation bridge.\n */\nexport function useDataState(input: DataStateInput): UseDataStateReturn {\n React.useEffect(installDataStateStyles, [])\n const reduced = usePrefersReducedMotion()\n const state = resolveDataState(input)\n return {\n state,\n isContent: state === 'content',\n stateKey: state,\n stateProps: {\n className: reduced ? '' : DATA_STATE_CLASS,\n 'data-iris-state': state,\n },\n }\n}\n"]}
@@ -0,0 +1,83 @@
1
+ 'use client'
2
+ import { SkinProvider } from './chunk-WIHBIDVJ.js';
3
+ import { ThemeProvider } from './chunk-XCK4RIXB.js';
4
+ import { IrisI18nProvider } from './chunk-OMOTUHYI.js';
5
+ import { createContext, useMemo, useRef, useEffect, useContext } from 'react';
6
+ import { runPlugins } from '@iris-ui-kit/core';
7
+ import { applyCssVars } from '@iris-ui-kit/theme';
8
+ import { jsx } from 'react/jsx-runtime';
9
+
10
+ var PluginStoreContext = createContext(null);
11
+ function IrisProvider({
12
+ theme,
13
+ skin,
14
+ dir = "ltr",
15
+ locale,
16
+ messages,
17
+ plugins,
18
+ target = null,
19
+ children
20
+ }) {
21
+ const collected = useMemo(() => runPlugins(plugins ?? []), [plugins]);
22
+ const appliedRef = useRef(null);
23
+ useEffect(() => {
24
+ if (typeof document === "undefined") return;
25
+ const el = target ?? document.documentElement;
26
+ appliedRef.current?.revert();
27
+ appliedRef.current = applyCssVars(Object.entries(collected.tokens), el);
28
+ return () => {
29
+ appliedRef.current?.revert();
30
+ appliedRef.current = null;
31
+ };
32
+ }, [collected, target]);
33
+ useEffect(() => () => collected.teardown(), [collected]);
34
+ const value = useMemo(
35
+ () => ({ stores: collected.stores, installed: new Set((plugins ?? []).map((p) => p.name)) }),
36
+ [collected, plugins]
37
+ );
38
+ const merged = { ...collected.messages[locale ?? "en-US"], ...messages ?? {} };
39
+ let tree = /* @__PURE__ */ jsx(IrisI18nProvider, { locale, messages: merged, children: /* @__PURE__ */ jsx(PluginStoreContext.Provider, { value, children }) });
40
+ if (skin) {
41
+ tree = /* @__PURE__ */ jsx(SkinProvider, { engine: skin, target, children: tree });
42
+ }
43
+ if (theme) {
44
+ tree = /* @__PURE__ */ jsx(ThemeProvider, { store: theme, dir, target, children: tree });
45
+ }
46
+ return tree;
47
+ }
48
+ function usePlugin(name) {
49
+ return useContext(PluginStoreContext)?.installed.has(name) ?? false;
50
+ }
51
+ var warnedKeys = /* @__PURE__ */ new Map();
52
+ function usePluginStore(nsOrKey, key) {
53
+ const ctx = useContext(PluginStoreContext);
54
+ if (!ctx) {
55
+ const displayKey = key !== void 0 ? `${nsOrKey}::${key}` : nsOrKey;
56
+ throw new Error(`[iris-ui] usePluginStore("${displayKey}"): no <IrisProvider> ancestor found`);
57
+ }
58
+ const fullKey = key !== void 0 ? `${nsOrKey}::${key}` : nsOrKey;
59
+ let store = ctx.stores.get(fullKey);
60
+ if (store !== void 0) return store;
61
+ if (key === void 0) {
62
+ store = ctx.stores.get(nsOrKey);
63
+ if (store !== void 0) return store;
64
+ for (const k of ctx.stores.keys()) {
65
+ if (typeof k === "string" && k.endsWith(`::${nsOrKey}`)) {
66
+ if (!warnedKeys.has(nsOrKey)) {
67
+ warnedKeys.set(nsOrKey, true);
68
+ console.warn(
69
+ `[iris-ui] Ambiguous plugin store key "${nsOrKey}". Found "${k}". Use the namespaced form for clarity: usePluginStore("${k}").`
70
+ );
71
+ }
72
+ return ctx.stores.get(k);
73
+ }
74
+ }
75
+ }
76
+ throw new Error(
77
+ `[iris-ui] Plugin store "${fullKey}" not found. Ensure the plugin is installed in IrisProvider and the key is correct.`
78
+ );
79
+ }
80
+
81
+ export { IrisProvider, PluginStoreContext, usePlugin, usePluginStore };
82
+ //# sourceMappingURL=chunk-IDD35UJ6.js.map
83
+ //# sourceMappingURL=chunk-IDD35UJ6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/provider/context.ts","../src/provider/IrisProvider.tsx"],"names":[],"mappings":"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","file":"chunk-IDD35UJ6.js","sourcesContent":["import { createContext } from 'react'\n\n/**\n * What `<IrisProvider>` hands to descendants: the eagerly-built plugin stores\n * (keyed by registration name) plus the set of installed plugin names.\n *\n * Named `*Context` so the manifest's discover step EXCLUDES it — only\n * `Iris*`-prefixed, non-`Context` exports become manifest components.\n */\nexport interface PluginStoreContextValue {\n stores: Map<string, unknown>\n installed: Set<string>\n}\n\nexport const PluginStoreContext = createContext<PluginStoreContextValue | null>(null)\n","import { useContext, useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { runPlugins, type IrisPlugin } from '@iris-ui-kit/core'\nimport {\n applyCssVars,\n type ApplyCssVarsResult,\n type Direction,\n type ThemeStore,\n} from '@iris-ui-kit/theme'\nimport type { SkinEngine } from '@iris-ui-kit/skins'\nimport { ThemeProvider } from '../theme'\nimport { SkinProvider } from '../skins'\nimport { IrisI18nProvider } from '../i18n'\nimport { PluginStoreContext } from './context'\n\nexport interface IrisProviderProps {\n /** Active theme store. When passed, wraps children in `<ThemeProvider>`. */\n theme?: ThemeStore\n /** Active skin engine. When passed, wraps children in `<SkinProvider>`. */\n skin?: SkinEngine\n /** Writing direction; forwarded to `<ThemeProvider>`. Default `'ltr'`. */\n dir?: Direction\n /** BCP-47 locale; selects which plugin message slice is applied. */\n locale?: string\n /** User message overrides — these WIN over plugin-registered messages. */\n messages?: Record<string, string>\n /** Plugins to install. Their tokens / messages / stores are collected once. */\n plugins?: IrisPlugin[]\n /** Element to receive plugin tokens. Defaults to `document.documentElement`. */\n target?: HTMLElement | null\n children?: ReactNode\n}\n\n/**\n * The single unified entry point. Runs the plugins, applies their additive\n * token layer over the active theme, merges their messages under the user's,\n * and exposes their stores via `PluginStoreContext`. The existing\n * Theme / Skin / I18n providers are composed in around it.\n *\n * **Zero business logic** — `runPlugins` / `applyCssVars` do the work; this is a\n * thin React bridge. Client boundary (tsup prepends `'use client'`).\n */\nexport function IrisProvider({\n theme,\n skin,\n dir = 'ltr',\n locale,\n messages,\n plugins,\n target = null,\n children,\n}: IrisProviderProps) {\n const collected = useMemo(() => runPlugins(plugins ?? []), [plugins])\n const appliedRef = useRef<ApplyCssVarsResult | null>(null)\n\n useEffect(() => {\n if (typeof document === 'undefined') return\n const el = target ?? document.documentElement\n appliedRef.current?.revert()\n appliedRef.current = applyCssVars(Object.entries(collected.tokens), el)\n return () => {\n appliedRef.current?.revert()\n appliedRef.current = null\n }\n }, [collected, target])\n\n // Run plugin teardowns when the plugins set is swapped (a new `collected`) or\n // on unmount, so eager stores / subscriptions / timers don't leak.\n useEffect(() => () => collected.teardown(), [collected])\n\n const value = useMemo(\n () => ({ stores: collected.stores, installed: new Set((plugins ?? []).map((p) => p.name)) }),\n [collected, plugins],\n )\n\n // Plugin messages are the BASE; user-supplied messages win.\n const merged = { ...collected.messages[locale ?? 'en-US'], ...(messages ?? {}) }\n\n // Order (innermost-out): Theme → Skin → I18n → PluginContext → children.\n let tree: ReactNode = (\n <IrisI18nProvider locale={locale} messages={merged}>\n <PluginStoreContext.Provider value={value}>{children}</PluginStoreContext.Provider>\n </IrisI18nProvider>\n )\n if (skin) {\n tree = (\n <SkinProvider engine={skin} target={target}>\n {tree}\n </SkinProvider>\n )\n }\n if (theme) {\n tree = (\n <ThemeProvider store={theme} dir={dir} target={target}>\n {tree}\n </ThemeProvider>\n )\n }\n return tree\n}\n\n/** Whether a plugin with `name` is installed under the nearest `<IrisProvider>`. */\nexport function usePlugin(name: string): boolean {\n return useContext(PluginStoreContext)?.installed.has(name) ?? false\n}\n\n// Tracks ambiguous store key warnings to avoid spamming the console.\n// Hoisted BEFORE overload signatures (TS requires overloads immediately before implementation).\nconst warnedKeys = new Map<string, boolean>()\n\n/**\n * Read a plugin-registered store by `key` (backward-compatible single-arg form).\n * Falls back to `{namespace}::{key}` lookup if bare key not found.\n * Throws a clear error when there is no `<IrisProvider>` ancestor.\n * Plugins export typed wrappers narrowing `T`.\n */\nexport function usePluginStore<T>(key: string): T\n\n/**\n * Read a plugin-registered store by `namespace` + `key`.\n * Equivalent to `usePluginStore('{namespace}::{key}')`.\n */\nexport function usePluginStore<T>(namespace: string, key: string): T\n\nexport function usePluginStore<T>(nsOrKey: string, key?: string): T {\n const ctx = useContext(PluginStoreContext)\n if (!ctx) {\n const displayKey = key !== undefined ? `${nsOrKey}::${key}` : nsOrKey\n throw new Error(`[iris-ui] usePluginStore(\"${displayKey}\"): no <IrisProvider> ancestor found`)\n }\n\n const fullKey = key !== undefined ? `${nsOrKey}::${key}` : nsOrKey\n\n // 1. Direct lookup using the constructed key\n let store = ctx.stores.get(fullKey) as T | undefined\n if (store !== undefined) return store\n\n // 2. Single-arg: try without namespace first (backward compat for unnamespaced plugins)\n if (key === undefined) {\n // Try the key as a bare key (for plugins without namespace)\n store = ctx.stores.get(nsOrKey) as T | undefined\n if (store !== undefined) return store\n\n // Try as {namespace}::{key} where namespace may equal the key segment\n // e.g. usePluginStore('settings') → try 'default::settings', 'editor::settings', etc.\n // This handles plugins where namespace === name (the common case).\n for (const k of ctx.stores.keys()) {\n if (typeof k === 'string' && k.endsWith(`::${nsOrKey}`)) {\n // Warn at most once per ambiguous key.\n if (!warnedKeys.has(nsOrKey)) {\n warnedKeys.set(nsOrKey, true)\n console.warn(\n `[iris-ui] Ambiguous plugin store key \"${nsOrKey}\". ` +\n `Found \"${k}\". Use the namespaced form for clarity: ` +\n `usePluginStore(\"${k}\").`,\n )\n }\n return ctx.stores.get(k) as T\n }\n }\n }\n\n throw new Error(\n `[iris-ui] Plugin store \"${fullKey}\" not found. ` +\n `Ensure the plugin is installed in IrisProvider and the key is correct.`,\n )\n}\n"]}
@@ -0,0 +1,166 @@
1
+ 'use client'
2
+ import * as React from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ // src/layouts/SidebarLayout.tsx
6
+ function asLen(v) {
7
+ return typeof v === "number" ? `${v}px` : v;
8
+ }
9
+ function IrisSidebarLayout({
10
+ collapsed: collapsedProp,
11
+ defaultCollapsed = false,
12
+ onCollapsedChange,
13
+ width = 240,
14
+ collapsedWidth = 60,
15
+ side = "left",
16
+ sidebar,
17
+ style,
18
+ children,
19
+ ...rest
20
+ }) {
21
+ const isControlled = collapsedProp !== void 0;
22
+ const [internal, setInternal] = React.useState(defaultCollapsed);
23
+ const collapsed = isControlled ? Boolean(collapsedProp) : internal;
24
+ const setCollapsed = React.useCallback(
25
+ (next) => {
26
+ if (!isControlled) setInternal(next);
27
+ onCollapsedChange?.(next);
28
+ },
29
+ [isControlled, onCollapsedChange]
30
+ );
31
+ const sidebarContent = typeof sidebar === "function" ? sidebar({
32
+ collapsed,
33
+ setCollapsed
34
+ }) : sidebar;
35
+ const sidebarStyle = {
36
+ width: collapsed ? asLen(collapsedWidth) : asLen(width),
37
+ flexShrink: 0,
38
+ background: "var(--iris-surface)",
39
+ borderRight: side === "left" ? "1px solid var(--iris-border)" : "none",
40
+ borderLeft: side === "right" ? "1px solid var(--iris-border)" : "none",
41
+ transition: "width 180ms ease",
42
+ overflow: "hidden",
43
+ display: "flex",
44
+ flexDirection: "column"
45
+ };
46
+ return /* @__PURE__ */ jsxs(
47
+ "div",
48
+ {
49
+ ...rest,
50
+ "data-iris-sidebar-layout": "",
51
+ "data-collapsed": collapsed ? "" : void 0,
52
+ "data-side": side,
53
+ style: {
54
+ display: "flex",
55
+ flexDirection: side === "right" ? "row-reverse" : "row",
56
+ width: "100%",
57
+ height: "100%",
58
+ minHeight: 0,
59
+ color: "var(--iris-foreground)",
60
+ ...style
61
+ },
62
+ children: [
63
+ /* @__PURE__ */ jsx(
64
+ "aside",
65
+ {
66
+ role: "complementary",
67
+ "data-iris-sidebar": "",
68
+ "data-collapsed": collapsed ? "" : void 0,
69
+ style: sidebarStyle,
70
+ children: sidebarContent
71
+ }
72
+ ),
73
+ /* @__PURE__ */ jsx(
74
+ "div",
75
+ {
76
+ "data-iris-sidebar-main": "",
77
+ style: {
78
+ flex: 1,
79
+ minWidth: 0,
80
+ overflow: "auto",
81
+ background: "var(--iris-background)"
82
+ },
83
+ children
84
+ }
85
+ )
86
+ ]
87
+ }
88
+ );
89
+ }
90
+ function asLen2(v) {
91
+ return typeof v === "number" ? `${v}px` : v;
92
+ }
93
+ function IrisHeaderLayout({
94
+ headerHeight = "auto",
95
+ footerHeight = "auto",
96
+ sticky = true,
97
+ header,
98
+ footer,
99
+ style,
100
+ children,
101
+ ...rest
102
+ }) {
103
+ return /* @__PURE__ */ jsxs(
104
+ "div",
105
+ {
106
+ ...rest,
107
+ "data-iris-header-layout": "",
108
+ style: {
109
+ display: "flex",
110
+ flexDirection: "column",
111
+ width: "100%",
112
+ height: "100%",
113
+ minHeight: 0,
114
+ background: "var(--iris-background)",
115
+ color: "var(--iris-foreground)",
116
+ ...style
117
+ },
118
+ children: [
119
+ header ? /* @__PURE__ */ jsx(
120
+ "header",
121
+ {
122
+ role: "banner",
123
+ "data-iris-header": "",
124
+ style: {
125
+ flexShrink: 0,
126
+ height: asLen2(headerHeight),
127
+ borderBottom: "1px solid var(--iris-border)",
128
+ background: "var(--iris-surface)",
129
+ position: sticky ? "sticky" : "static",
130
+ top: 0,
131
+ zIndex: 50
132
+ },
133
+ children: header
134
+ }
135
+ ) : null,
136
+ /* @__PURE__ */ jsx(
137
+ "main",
138
+ {
139
+ role: "main",
140
+ "data-iris-header-main": "",
141
+ style: { flex: 1, minHeight: 0, overflow: "auto" },
142
+ children
143
+ }
144
+ ),
145
+ footer ? /* @__PURE__ */ jsx(
146
+ "footer",
147
+ {
148
+ role: "contentinfo",
149
+ "data-iris-footer": "",
150
+ style: {
151
+ flexShrink: 0,
152
+ height: asLen2(footerHeight),
153
+ borderTop: "1px solid var(--iris-border)",
154
+ background: "var(--iris-surface)"
155
+ },
156
+ children: footer
157
+ }
158
+ ) : null
159
+ ]
160
+ }
161
+ );
162
+ }
163
+
164
+ export { IrisHeaderLayout, IrisSidebarLayout };
165
+ //# sourceMappingURL=chunk-J5FB2UB2.js.map
166
+ //# sourceMappingURL=chunk-J5FB2UB2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/layouts/SidebarLayout.tsx","../src/layouts/HeaderLayout.tsx"],"names":["asLen","jsxs","jsx"],"mappings":"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","file":"chunk-J5FB2UB2.js","sourcesContent":["import * as React from 'react'\n\nexport interface IrisSidebarLayoutSidebarState {\n collapsed: boolean\n setCollapsed: (next: boolean) => void\n}\n\nexport interface IrisSidebarLayoutProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children'\n> {\n collapsed?: boolean\n defaultCollapsed?: boolean\n onCollapsedChange?: (next: boolean) => void\n /** Sidebar width when expanded (px or CSS length). */\n width?: number | string\n /** Sidebar width when collapsed. */\n collapsedWidth?: number | string\n side?: 'left' | 'right'\n /** Sidebar content. May be a render function that receives `{ collapsed, setCollapsed }`. */\n sidebar?: React.ReactNode | ((state: IrisSidebarLayoutSidebarState) => React.ReactNode)\n children?: React.ReactNode\n}\n\nfunction asLen(v: number | string): string {\n return typeof v === 'number' ? `${v}px` : v\n}\n\n/**\n * Two-column layout with a collapsible sidebar. The sidebar is kept mounted\n * across collapses (only its width animates) so component state survives.\n */\nexport function IrisSidebarLayout({\n collapsed: collapsedProp,\n defaultCollapsed = false,\n onCollapsedChange,\n width = 240,\n collapsedWidth = 60,\n side = 'left',\n sidebar,\n style,\n children,\n ...rest\n}: IrisSidebarLayoutProps): React.ReactElement {\n const isControlled = collapsedProp !== undefined\n const [internal, setInternal] = React.useState(defaultCollapsed)\n const collapsed = isControlled ? Boolean(collapsedProp) : internal\n\n const setCollapsed = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternal(next)\n onCollapsedChange?.(next)\n },\n [isControlled, onCollapsedChange],\n )\n\n const sidebarContent =\n typeof sidebar === 'function'\n ? (sidebar as (s: IrisSidebarLayoutSidebarState) => React.ReactNode)({\n collapsed,\n setCollapsed,\n })\n : sidebar\n\n const sidebarStyle: React.CSSProperties = {\n width: collapsed ? asLen(collapsedWidth) : asLen(width),\n flexShrink: 0,\n background: 'var(--iris-surface)',\n borderRight: side === 'left' ? '1px solid var(--iris-border)' : 'none',\n borderLeft: side === 'right' ? '1px solid var(--iris-border)' : 'none',\n transition: 'width 180ms ease',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n }\n\n return (\n <div\n {...rest}\n data-iris-sidebar-layout=\"\"\n data-collapsed={collapsed ? '' : undefined}\n data-side={side}\n style={{\n display: 'flex',\n flexDirection: side === 'right' ? 'row-reverse' : 'row',\n width: '100%',\n height: '100%',\n minHeight: 0,\n color: 'var(--iris-foreground)',\n ...style,\n }}\n >\n <aside\n role=\"complementary\"\n data-iris-sidebar=\"\"\n data-collapsed={collapsed ? '' : undefined}\n style={sidebarStyle}\n >\n {sidebarContent}\n </aside>\n <div\n data-iris-sidebar-main=\"\"\n style={{\n flex: 1,\n minWidth: 0,\n overflow: 'auto',\n background: 'var(--iris-background)',\n }}\n >\n {children}\n </div>\n </div>\n )\n}\n","import * as React from 'react'\n\nexport interface IrisHeaderLayoutProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children'\n> {\n /** Header height (px or CSS length). Default `'auto'`. */\n headerHeight?: number | string\n /** Footer height (px or CSS length). Default `'auto'`. */\n footerHeight?: number | string\n /** Header sticks via `position: sticky` instead of static. Default true. */\n sticky?: boolean\n header?: React.ReactNode\n footer?: React.ReactNode\n children?: React.ReactNode\n}\n\nfunction asLen(v: number | string): string {\n return typeof v === 'number' ? `${v}px` : v\n}\n\n/**\n * Two- (or three-) region vertical layout: a sticky header on top, a\n * scrollable main region, and an optional footer.\n */\nexport function IrisHeaderLayout({\n headerHeight = 'auto',\n footerHeight = 'auto',\n sticky = true,\n header,\n footer,\n style,\n children,\n ...rest\n}: IrisHeaderLayoutProps): React.ReactElement {\n return (\n <div\n {...rest}\n data-iris-header-layout=\"\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n height: '100%',\n minHeight: 0,\n background: 'var(--iris-background)',\n color: 'var(--iris-foreground)',\n ...style,\n }}\n >\n {header ? (\n <header\n role=\"banner\"\n data-iris-header=\"\"\n style={{\n flexShrink: 0,\n height: asLen(headerHeight),\n borderBottom: '1px solid var(--iris-border)',\n background: 'var(--iris-surface)',\n position: sticky ? 'sticky' : 'static',\n top: 0,\n zIndex: 50,\n }}\n >\n {header}\n </header>\n ) : null}\n <main\n role=\"main\"\n data-iris-header-main=\"\"\n style={{ flex: 1, minHeight: 0, overflow: 'auto' }}\n >\n {children}\n </main>\n {footer ? (\n <footer\n role=\"contentinfo\"\n data-iris-footer=\"\"\n style={{\n flexShrink: 0,\n height: asLen(footerHeight),\n borderTop: '1px solid var(--iris-border)',\n background: 'var(--iris-surface)',\n }}\n >\n {footer}\n </footer>\n ) : null}\n </div>\n )\n}\n"]}
@@ -0,0 +1,66 @@
1
+ 'use client'
2
+ import { useStore } from './chunk-RZNYIFV2.js';
3
+ import * as React2 from 'react';
4
+ import { createI18n, localeDirection } from '@iris-ui-kit/core';
5
+ import { applyDirection } from '@iris-ui-kit/theme';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ var I18nContext = React2.createContext(null);
9
+ function IrisI18nProvider({
10
+ locale,
11
+ messages,
12
+ i18n,
13
+ autoDirection,
14
+ directionTarget,
15
+ children
16
+ }) {
17
+ const ref = React2.useRef(null);
18
+ if (ref.current === null) {
19
+ ref.current = i18n ?? createI18n({ locale, messages });
20
+ }
21
+ const instance = ref.current;
22
+ React2.useEffect(() => {
23
+ if (i18n || !locale) return;
24
+ instance.setLocale(locale);
25
+ }, [locale, i18n, instance]);
26
+ React2.useEffect(() => {
27
+ if (i18n || !messages) return;
28
+ instance.setMessages(messages);
29
+ }, [messages, i18n, instance]);
30
+ React2.useEffect(() => {
31
+ if (!autoDirection || !locale || typeof document === "undefined") return;
32
+ const el = directionTarget ?? document.documentElement;
33
+ const applied = applyDirection(localeDirection(locale), el);
34
+ const prevLang = el.getAttribute("lang");
35
+ el.setAttribute("lang", locale);
36
+ return () => {
37
+ applied.revert();
38
+ if (prevLang === null) el.removeAttribute("lang");
39
+ else el.setAttribute("lang", prevLang);
40
+ };
41
+ }, [autoDirection, locale, directionTarget]);
42
+ return /* @__PURE__ */ jsx(I18nContext.Provider, { value: instance, children });
43
+ }
44
+ var fallbackI18n = null;
45
+ function getFallback() {
46
+ if (fallbackI18n === null) fallbackI18n = createI18n();
47
+ return fallbackI18n;
48
+ }
49
+ function useI18n() {
50
+ const ctx = React2.useContext(I18nContext);
51
+ const i18n = ctx ?? getFallback();
52
+ const state = useStore(i18n.store);
53
+ return {
54
+ locale: state.locale,
55
+ t: i18n.t,
56
+ formatDate: i18n.formatDate,
57
+ formatNumber: i18n.formatNumber,
58
+ formatRelativeTime: i18n.formatRelativeTime,
59
+ setLocale: i18n.setLocale,
60
+ setMessages: i18n.setMessages
61
+ };
62
+ }
63
+
64
+ export { I18nContext, IrisI18nProvider, useI18n };
65
+ //# sourceMappingURL=chunk-OMOTUHYI.js.map
66
+ //# sourceMappingURL=chunk-OMOTUHYI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/context.ts","../src/i18n/I18nProvider.tsx","../src/i18n/useI18n.ts"],"names":["React","createI18n","React3"],"mappings":";;;;;;;AAIO,IAAM,WAAA,GAAoBA,qBAA2B,IAAI;AC0BzD,SAAS,gBAAA,CAAiB;AAAA,EAC/B,MAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,GAAA,GAAY,cAAoB,IAAI,CAAA;AAC1C,EAAA,IAAI,GAAA,CAAI,YAAY,IAAA,EAAM;AACxB,IAAA,GAAA,CAAI,UAAU,IAAA,IAAQ,UAAA,CAAW,EAAE,MAAA,EAAQ,UAAU,CAAA;AAAA,EACvD;AACA,EAAA,MAAM,WAAW,GAAA,CAAI,OAAA;AAErB,EAAM,iBAAU,MAAM;AACpB,IAAA,IAAI,IAAA,IAAQ,CAAC,MAAA,EAAQ;AACrB,IAAA,QAAA,CAAS,UAAU,MAAM,CAAA;AAAA,EAC3B,CAAA,EAAG,CAAC,MAAA,EAAQ,IAAA,EAAM,QAAQ,CAAC,CAAA;AAE3B,EAAM,iBAAU,MAAM;AACpB,IAAA,IAAI,IAAA,IAAQ,CAAC,QAAA,EAAU;AACvB,IAAA,QAAA,CAAS,YAAY,QAAQ,CAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,QAAA,EAAU,IAAA,EAAM,QAAQ,CAAC,CAAA;AAG7B,EAAM,iBAAU,MAAM;AACpB,IAAA,IAAI,CAAC,aAAA,IAAiB,CAAC,MAAA,IAAU,OAAO,aAAa,WAAA,EAAa;AAClE,IAAA,MAAM,EAAA,GAAK,mBAAmB,QAAA,CAAS,eAAA;AACvC,IAAA,MAAM,OAAA,GAAU,cAAA,CAAe,eAAA,CAAgB,MAAM,GAAG,EAAE,CAAA;AAC1D,IAAA,MAAM,QAAA,GAAW,EAAA,CAAG,YAAA,CAAa,MAAM,CAAA;AACvC,IAAA,EAAA,CAAG,YAAA,CAAa,QAAQ,MAAM,CAAA;AAC9B,IAAA,OAAO,MAAM;AACX,MAAA,OAAA,CAAQ,MAAA,EAAO;AACf,MAAA,IAAI,QAAA,KAAa,IAAA,EAAM,EAAA,CAAG,eAAA,CAAgB,MAAM,CAAA;AAAA,WAC3C,EAAA,CAAG,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAA;AAAA,IACvC,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,aAAA,EAAe,MAAA,EAAQ,eAAe,CAAC,CAAA;AAE3C,EAAA,2BAAQ,WAAA,CAAY,QAAA,EAAZ,EAAqB,KAAA,EAAO,UAAW,QAAA,EAAS,CAAA;AAC1D;ACpDA,IAAI,YAAA,GAA4B,IAAA;AAChC,SAAS,WAAA,GAAoB;AAC3B,EAAA,IAAI,YAAA,KAAiB,IAAA,EAAM,YAAA,GAAeC,UAAAA,EAAW;AACrD,EAAA,OAAO,YAAA;AACT;AAOO,SAAS,OAAA,GAAyB;AACvC,EAAA,MAAM,GAAA,GAAYC,kBAAW,WAAW,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,OAAO,WAAA,EAAY;AAChC,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA;AAEjC,EAAA,OAAO;AAAA,IACL,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,GAAG,IAAA,CAAK,CAAA;AAAA,IACR,YAAY,IAAA,CAAK,UAAA;AAAA,IACjB,cAAc,IAAA,CAAK,YAAA;AAAA,IACnB,oBAAoB,IAAA,CAAK,kBAAA;AAAA,IACzB,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,aAAa,IAAA,CAAK;AAAA,GACpB;AACF","file":"chunk-OMOTUHYI.js","sourcesContent":["import * as React from 'react'\nimport type { I18n } from '@iris-ui-kit/core'\n\n/** Carries the active {@link I18n} instance to descendants via `useI18n`. */\nexport const I18nContext = React.createContext<I18n | null>(null)\n","import * as React from 'react'\nimport { createI18n, localeDirection, type I18n, type I18nMessages } from '@iris-ui-kit/core'\nimport { applyDirection } from '@iris-ui-kit/theme'\nimport { I18nContext } from './context'\n\nexport interface IrisI18nProviderProps {\n /** BCP-47 locale. Changes are synced to the live instance. */\n locale?: string\n /** Message overrides. Changes are merged into the live instance. */\n messages?: I18nMessages\n /** Provide a pre-created instance instead of `locale` / `messages`. */\n i18n?: I18n\n /**\n * When set, the locale's writing direction ({@link localeDirection}) is\n * applied to `directionTarget` (`dir` + `data-iris-dir`) and `<html lang>` is\n * set whenever `locale` changes — so \"set locale → flip direction + announce\n * language\" needs no manual wiring. Off by default so it never fights an\n * explicit `<ThemeProvider dir>`. Reverts on unmount.\n */\n autoDirection?: boolean\n /** Element to receive dir/lang when `autoDirection` is set. Defaults to `document.documentElement`. */\n directionTarget?: HTMLElement | null\n children?: React.ReactNode\n}\n\n/**\n * Makes a locale + message dictionary available to descendant components via\n * `useI18n`. Either pass `locale` / `messages` (an instance is created and\n * kept in sync) or a pre-built `i18n` instance you control externally.\n */\nexport function IrisI18nProvider({\n locale,\n messages,\n i18n,\n autoDirection,\n directionTarget,\n children,\n}: IrisI18nProviderProps) {\n const ref = React.useRef<I18n | null>(null)\n if (ref.current === null) {\n ref.current = i18n ?? createI18n({ locale, messages })\n }\n const instance = ref.current\n\n React.useEffect(() => {\n if (i18n || !locale) return\n instance.setLocale(locale)\n }, [locale, i18n, instance])\n\n React.useEffect(() => {\n if (i18n || !messages) return\n instance.setMessages(messages)\n }, [messages, i18n, instance])\n\n // Auto-apply writing direction + `lang` from the active locale (opt-in).\n React.useEffect(() => {\n if (!autoDirection || !locale || typeof document === 'undefined') return\n const el = directionTarget ?? document.documentElement\n const applied = applyDirection(localeDirection(locale), el)\n const prevLang = el.getAttribute('lang')\n el.setAttribute('lang', locale)\n return () => {\n applied.revert()\n if (prevLang === null) el.removeAttribute('lang')\n else el.setAttribute('lang', prevLang)\n }\n }, [autoDirection, locale, directionTarget])\n\n return <I18nContext.Provider value={instance}>{children}</I18nContext.Provider>\n}\n","import * as React from 'react'\nimport { createI18n, type I18n } from '@iris-ui-kit/core'\nimport { useStore } from '../useStore'\nimport { I18nContext } from './context'\n\nexport interface UseI18nReturn {\n locale: string\n t: I18n['t']\n formatDate: I18n['formatDate']\n formatNumber: I18n['formatNumber']\n formatRelativeTime: I18n['formatRelativeTime']\n setLocale: I18n['setLocale']\n setMessages: I18n['setMessages']\n}\n\n// Shared fallback so components can call `useI18n()` without an enclosing\n// provider — they get English defaults rather than throwing.\nlet fallbackI18n: I18n | null = null\nfunction getFallback(): I18n {\n if (fallbackI18n === null) fallbackI18n = createI18n()\n return fallbackI18n\n}\n\n/**\n * Reactive access to the active locale + translation/formatting helpers.\n * Re-renders the host when the locale or messages change. Works with or\n * without an `<IrisI18nProvider>` (falls back to English defaults).\n */\nexport function useI18n(): UseI18nReturn {\n const ctx = React.useContext(I18nContext)\n const i18n = ctx ?? getFallback()\n const state = useStore(i18n.store)\n\n return {\n locale: state.locale,\n t: i18n.t,\n formatDate: i18n.formatDate,\n formatNumber: i18n.formatNumber,\n formatRelativeTime: i18n.formatRelativeTime,\n setLocale: i18n.setLocale,\n setMessages: i18n.setMessages,\n }\n}\n"]}
@@ -0,0 +1,34 @@
1
+ 'use client'
2
+ import * as React from 'react';
3
+ import { useSyncExternalStore } from 'react';
4
+
5
+ // src/useStore.ts
6
+ function useStore(store) {
7
+ return useSyncExternalStore(
8
+ store.subscribe,
9
+ store.getState,
10
+ store.getState
11
+ // SSR fallback — same as client snapshot in our case.
12
+ );
13
+ }
14
+ function useStoreSelector(store, selector, isEqual) {
15
+ const [slice, setSlice] = React.useState(() => selector(store.getState()));
16
+ const selRef = React.useRef(selector);
17
+ selRef.current = selector;
18
+ const eqRef = React.useRef(isEqual);
19
+ eqRef.current = isEqual;
20
+ React.useEffect(() => {
21
+ const read = (s) => selRef.current(s);
22
+ const eq = (a, b) => (eqRef.current ?? Object.is)(a, b);
23
+ setSlice((prev) => {
24
+ const next = read(store.getState());
25
+ return eq(prev, next) ? prev : next;
26
+ });
27
+ return store.subscribeWith(read, setSlice, eq);
28
+ }, [store]);
29
+ return slice;
30
+ }
31
+
32
+ export { useStore, useStoreSelector };
33
+ //# sourceMappingURL=chunk-RZNYIFV2.js.map
34
+ //# sourceMappingURL=chunk-RZNYIFV2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/useStore.ts"],"names":[],"mappings":";;;;;AAUO,SAAS,SAAY,KAAA,EAA4B;AACtD,EAAA,OAAO,oBAAA;AAAA,IACL,KAAA,CAAM,SAAA;AAAA,IACN,KAAA,CAAM,QAAA;AAAA,IACN,KAAA,CAAM;AAAA;AAAA,GACR;AACF;AASO,SAAS,gBAAA,CACd,KAAA,EACA,QAAA,EACA,OAAA,EACG;AACH,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAU,KAAA,CAAA,QAAA,CAAS,MAAM,QAAA,CAAS,KAAA,CAAM,QAAA,EAAU,CAAC,CAAA;AACzE,EAAA,MAAM,MAAA,GAAe,aAAO,QAAQ,CAAA;AACpC,EAAA,MAAA,CAAO,OAAA,GAAU,QAAA;AACjB,EAAA,MAAM,KAAA,GAAc,aAAO,OAAO,CAAA;AAClC,EAAA,KAAA,CAAM,OAAA,GAAU,OAAA;AAChB,EAAM,gBAAU,MAAM;AACpB,IAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAY,MAAA,CAAO,QAAQ,CAAC,CAAA;AAC1C,IAAA,MAAM,EAAA,GAAK,CAAC,CAAA,EAAM,CAAA,KAAA,CAAmB,MAAM,OAAA,IAAW,MAAA,CAAO,EAAA,EAAI,CAAA,EAAG,CAAC,CAAA;AAErE,IAAA,QAAA,CAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAA,EAAU,CAAA;AAClC,MAAA,OAAO,EAAA,CAAG,IAAA,EAAM,IAAI,CAAA,GAAI,IAAA,GAAO,IAAA;AAAA,IACjC,CAAC,CAAA;AACD,IAAA,OAAO,KAAA,CAAM,aAAA,CAAc,IAAA,EAAM,QAAA,EAAU,EAAE,CAAA;AAAA,EAC/C,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACV,EAAA,OAAO,KAAA;AACT","file":"chunk-RZNYIFV2.js","sourcesContent":["import * as React from 'react'\nimport { useSyncExternalStore } from 'react'\nimport type { ReadonlyStore, Store } from '@iris-ui-kit/core'\n\n/**\n * Bridge a framework-agnostic `@iris-ui-kit/core` store into React reactivity.\n * Uses React 18's `useSyncExternalStore` — the contract is identical to the\n * one Vue uses via `ref + onMounted` and Solid uses via `createSignal`. The\n * **same** store can power Button, Popover, Dialog, etc. on any framework.\n */\nexport function useStore<T>(store: ReadonlyStore<T>): T {\n return useSyncExternalStore(\n store.subscribe,\n store.getState,\n store.getState, // SSR fallback — same as client snapshot in our case.\n )\n}\n\n/**\n * Subscribe to a DERIVED slice of a core store — the component re-renders only\n * when `selector(state)` changes per `isEqual` (default `Object.is`), not on\n * every store emission. Built on {@link Store.subscribeWith}. Inline closures\n * for `selector`/`isEqual` are fine (captured via refs; the subscription is not\n * re-created between renders).\n */\nexport function useStoreSelector<T, U>(\n store: Store<T>,\n selector: (state: T) => U,\n isEqual?: (a: U, b: U) => boolean,\n): U {\n const [slice, setSlice] = React.useState(() => selector(store.getState()))\n const selRef = React.useRef(selector)\n selRef.current = selector\n const eqRef = React.useRef(isEqual)\n eqRef.current = isEqual\n React.useEffect(() => {\n const read = (s: T): U => selRef.current(s)\n const eq = (a: U, b: U): boolean => (eqRef.current ?? Object.is)(a, b)\n // Re-sync in case the store moved between render and this effect.\n setSlice((prev) => {\n const next = read(store.getState())\n return eq(prev, next) ? prev : next\n })\n return store.subscribeWith(read, setSlice, eq)\n }, [store])\n return slice\n}\n"]}
@@ -0,0 +1,54 @@
1
+ 'use client'
2
+ import * as React from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/layouts/Grid.tsx
6
+ function resolveColumns(columns, minColWidth) {
7
+ if (typeof columns === "number") return `repeat(${columns}, minmax(0, 1fr))`;
8
+ if (columns === "auto-fit") return `repeat(auto-fit, minmax(${minColWidth}, 1fr))`;
9
+ if (columns === "auto-fill") return `repeat(auto-fill, minmax(${minColWidth}, 1fr))`;
10
+ return columns;
11
+ }
12
+ function toCssSpacing(spacing) {
13
+ if (typeof spacing === "number") return `${spacing}px`;
14
+ if (spacing === "sm" || spacing === "md" || spacing === "lg") {
15
+ return `var(--iris-gap-${spacing})`;
16
+ }
17
+ return spacing;
18
+ }
19
+ var IrisGrid = React.forwardRef(function IrisGrid2({
20
+ columns = "auto-fit",
21
+ minColWidth = "200px",
22
+ rowGap,
23
+ columnGap,
24
+ gap = "md",
25
+ inline = false,
26
+ style,
27
+ children,
28
+ ...rest
29
+ }, ref) {
30
+ const colTemplate = resolveColumns(columns, minColWidth);
31
+ const resolvedRowGap = rowGap !== void 0 ? toCssSpacing(rowGap) : toCssSpacing(gap);
32
+ const resolvedColGap = columnGap !== void 0 ? toCssSpacing(columnGap) : toCssSpacing(gap);
33
+ return /* @__PURE__ */ jsx(
34
+ "div",
35
+ {
36
+ ...rest,
37
+ ref,
38
+ "data-iris-grid": "",
39
+ "data-iris-grid-columns": String(columns),
40
+ style: {
41
+ display: inline ? "inline-grid" : "grid",
42
+ gridTemplateColumns: colTemplate,
43
+ rowGap: resolvedRowGap,
44
+ columnGap: resolvedColGap,
45
+ ...style
46
+ },
47
+ children
48
+ }
49
+ );
50
+ });
51
+
52
+ export { IrisGrid };
53
+ //# sourceMappingURL=chunk-SJO74IB3.js.map
54
+ //# sourceMappingURL=chunk-SJO74IB3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/layouts/Grid.tsx"],"names":["IrisGrid"],"mappings":";;;;;AAQA,SAAS,cAAA,CAAe,SAA0B,WAAA,EAA6B;AAC7E,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,OAAO,UAAU,OAAO,CAAA,iBAAA,CAAA;AACzD,EAAA,IAAI,OAAA,KAAY,UAAA,EAAY,OAAO,CAAA,wBAAA,EAA2B,WAAW,CAAA,OAAA,CAAA;AACzE,EAAA,IAAI,OAAA,KAAY,WAAA,EAAa,OAAO,CAAA,yBAAA,EAA4B,WAAW,CAAA,OAAA,CAAA;AAC3E,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,aAAa,OAAA,EAAkC;AACtD,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,OAAO,GAAG,OAAO,CAAA,EAAA,CAAA;AAClD,EAAA,IAAI,OAAA,KAAY,IAAA,IAAQ,OAAA,KAAY,IAAA,IAAQ,YAAY,IAAA,EAAM;AAC5D,IAAA,OAAO,kBAAkB,OAAO,CAAA,CAAA,CAAA;AAAA,EAClC;AACA,EAAA,OAAO,OAAA;AACT;AAmBO,IAAM,QAAA,GAAiB,KAAA,CAAA,UAAA,CAA0C,SAASA,SAAAA,CAC/E;AAAA,EACE,OAAA,GAAU,UAAA;AAAA,EACV,WAAA,GAAc,OAAA;AAAA,EACd,MAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAA,GAAM,IAAA;AAAA,EACN,MAAA,GAAS,KAAA;AAAA,EACT,KAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EACA,GAAA,EACA;AACA,EAAA,MAAM,WAAA,GAAc,cAAA,CAAe,OAAA,EAAS,WAAW,CAAA;AACvD,EAAA,MAAM,iBAAiB,MAAA,KAAW,MAAA,GAAY,aAAa,MAAM,CAAA,GAAI,aAAa,GAAG,CAAA;AACrF,EAAA,MAAM,iBAAiB,SAAA,KAAc,MAAA,GAAY,aAAa,SAAS,CAAA,GAAI,aAAa,GAAG,CAAA;AAE3F,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,GAAA;AAAA,MACA,gBAAA,EAAe,EAAA;AAAA,MACf,wBAAA,EAAwB,OAAO,OAAO,CAAA;AAAA,MACtC,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,SAAS,aAAA,GAAgB,MAAA;AAAA,QAClC,mBAAA,EAAqB,WAAA;AAAA,QACrB,MAAA,EAAQ,cAAA;AAAA,QACR,SAAA,EAAW,cAAA;AAAA,QACX,GAAG;AAAA,OACL;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ,CAAC","file":"chunk-SJO74IB3.js","sourcesContent":["import * as React from 'react'\n\nexport type IrisGridColumns =\n | number\n | 'auto-fit'\n | 'auto-fill'\n | string /* raw grid-template-columns value */\n\nfunction resolveColumns(columns: IrisGridColumns, minColWidth: string): string {\n if (typeof columns === 'number') return `repeat(${columns}, minmax(0, 1fr))`\n if (columns === 'auto-fit') return `repeat(auto-fit, minmax(${minColWidth}, 1fr))`\n if (columns === 'auto-fill') return `repeat(auto-fill, minmax(${minColWidth}, 1fr))`\n return columns\n}\n\nfunction toCssSpacing(spacing: string | number): string {\n if (typeof spacing === 'number') return `${spacing}px`\n if (spacing === 'sm' || spacing === 'md' || spacing === 'lg') {\n return `var(--iris-gap-${spacing})`\n }\n return spacing\n}\n\nexport interface IrisGridProps extends React.HTMLAttributes<HTMLDivElement> {\n columns?: IrisGridColumns\n /** Min width per column for `auto-fit` / `auto-fill`. */\n minColWidth?: string\n rowGap?: string | number\n columnGap?: string | number\n /** Shorthand for both row + column gap. Overridden if rowGap/columnGap given. */\n gap?: string | number\n inline?: boolean\n}\n\n/**\n * Two-dimensional grid layout primitive. Three column modes:\n * - Fixed integer (`columns={3}`)\n * - Responsive auto-fit (`columns=\"auto-fit\"` + `minColWidth`)\n * - Raw CSS (`columns=\"100px 1fr 100px\"`)\n */\nexport const IrisGrid = React.forwardRef<HTMLDivElement, IrisGridProps>(function IrisGrid(\n {\n columns = 'auto-fit',\n minColWidth = '200px',\n rowGap,\n columnGap,\n gap = 'md',\n inline = false,\n style,\n children,\n ...rest\n },\n ref,\n) {\n const colTemplate = resolveColumns(columns, minColWidth)\n const resolvedRowGap = rowGap !== undefined ? toCssSpacing(rowGap) : toCssSpacing(gap)\n const resolvedColGap = columnGap !== undefined ? toCssSpacing(columnGap) : toCssSpacing(gap)\n\n return (\n <div\n {...rest}\n ref={ref}\n data-iris-grid=\"\"\n data-iris-grid-columns={String(columns)}\n style={{\n display: inline ? 'inline-grid' : 'grid',\n gridTemplateColumns: colTemplate,\n rowGap: resolvedRowGap,\n columnGap: resolvedColGap,\n ...style,\n }}\n >\n {children}\n </div>\n )\n})\n"]}
@@ -0,0 +1,53 @@
1
+ 'use client'
2
+ import { useI18n } from './chunk-OMOTUHYI.js';
3
+ import * as React from 'react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ function DefaultErrorFallback({
7
+ error,
8
+ reset
9
+ }) {
10
+ const { t } = useI18n();
11
+ return /* @__PURE__ */ jsxs(
12
+ "div",
13
+ {
14
+ "data-iris-error-boundary": "",
15
+ role: "alert",
16
+ style: {
17
+ padding: 16,
18
+ border: "1px solid var(--iris-danger)",
19
+ borderRadius: "var(--iris-radius-md, 6px)",
20
+ color: "var(--iris-danger)"
21
+ },
22
+ children: [
23
+ /* @__PURE__ */ jsx("div", { "data-iris-error-boundary-message": "", children: error.message || t("errorBoundary.message") }),
24
+ /* @__PURE__ */ jsx("button", { type: "button", "data-iris-error-boundary-retry": "", onClick: reset, children: t("errorBoundary.retry") })
25
+ ]
26
+ }
27
+ );
28
+ }
29
+ var IrisErrorBoundary = class extends React.Component {
30
+ state = { error: null };
31
+ static getDerivedStateFromError(error) {
32
+ return { error };
33
+ }
34
+ componentDidCatch(error, info) {
35
+ this.props.onError?.(error, info);
36
+ }
37
+ reset = () => {
38
+ this.setState({ error: null });
39
+ };
40
+ render() {
41
+ const { error } = this.state;
42
+ if (error !== null) {
43
+ const { fallback } = this.props;
44
+ if (fallback) return fallback({ error, reset: this.reset });
45
+ return /* @__PURE__ */ jsx(DefaultErrorFallback, { error, reset: this.reset });
46
+ }
47
+ return this.props.children;
48
+ }
49
+ };
50
+
51
+ export { IrisErrorBoundary };
52
+ //# sourceMappingURL=chunk-SORLRLS4.js.map
53
+ //# sourceMappingURL=chunk-SORLRLS4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/error-boundary/ErrorBoundary.tsx"],"names":[],"mappings":";;;;;AA+BA,SAAS,oBAAA,CAAqB;AAAA,EAC5B,KAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,OAAA,EAAQ;AACtB,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,0BAAA,EAAyB,EAAA;AAAA,MACzB,IAAA,EAAK,OAAA;AAAA,MACL,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,EAAA;AAAA,QACT,MAAA,EAAQ,8BAAA;AAAA,QACR,YAAA,EAAc,4BAAA;AAAA,QACd,KAAA,EAAO;AAAA,OACT;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,SAAI,kCAAA,EAAiC,EAAA,EAAI,gBAAM,OAAA,IAAW,CAAA,CAAE,uBAAuB,CAAA,EAAE,CAAA;AAAA,wBACtF,GAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,gCAAA,EAA+B,IAAG,OAAA,EAAS,KAAA,EAC9D,QAAA,EAAA,CAAA,CAAE,qBAAqB,CAAA,EAC1B;AAAA;AAAA;AAAA,GACF;AAEJ;AAYO,IAAM,iBAAA,GAAN,cAAsC,KAAA,CAAA,SAAA,CAG3C;AAAA,EACS,KAAA,GAAgC,EAAE,KAAA,EAAO,IAAA,EAAK;AAAA,EAEvD,OAAO,yBAAyB,KAAA,EAAsC;AACpE,IAAA,OAAO,EAAE,KAAA,EAAM;AAAA,EACjB;AAAA,EAES,iBAAA,CAAkB,OAAc,IAAA,EAA6B;AACpE,IAAA,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,KAAA,EAAO,IAAI,CAAA;AAAA,EAClC;AAAA,EAEA,QAAQ,MAAY;AAClB,IAAA,IAAA,CAAK,QAAA,CAAS,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA;AAAA,EAC/B,CAAA;AAAA,EAES,MAAA,GAA0B;AACjC,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,IAAA,CAAK,KAAA;AACvB,IAAA,IAAI,UAAU,IAAA,EAAM;AAClB,MAAA,MAAM,EAAE,QAAA,EAAS,GAAI,IAAA,CAAK,KAAA;AAC1B,MAAA,IAAI,QAAA,SAAiB,QAAA,CAAS,EAAE,OAAO,KAAA,EAAO,IAAA,CAAK,OAAO,CAAA;AAC1D,MAAA,uBAAO,GAAA,CAAC,oBAAA,EAAA,EAAqB,KAAA,EAAc,KAAA,EAAO,KAAK,KAAA,EAAO,CAAA;AAAA,IAChE;AACA,IAAA,OAAO,KAAK,KAAA,CAAM,QAAA;AAAA,EACpB;AACF","file":"chunk-SORLRLS4.js","sourcesContent":["import * as React from 'react'\nimport { useI18n } from '../i18n'\n\nexport interface IrisErrorBoundaryFallbackProps {\n /** The caught error. */\n error: Error\n /** Clears the error and re-attempts rendering the children. */\n reset: () => void\n}\n\nexport interface IrisErrorBoundaryProps {\n /** The guarded subtree. */\n children?: React.ReactNode\n /**\n * Custom fallback UI. Receives `{ error, reset }`. When omitted, the\n * default themed, accessible fallback is rendered.\n */\n fallback?: (props: IrisErrorBoundaryFallbackProps) => React.ReactNode\n /** Invoked with the caught error (and React error info) for logging. */\n onError?: (error: Error, info: React.ErrorInfo) => void\n}\n\ninterface IrisErrorBoundaryState {\n error: Error | null\n}\n\n/**\n * Default themed, accessible fallback. A function sub-component so it can call\n * `useI18n()` — the class boundary can't use hooks. Falls back to English\n * without a provider.\n */\nfunction DefaultErrorFallback({\n error,\n reset,\n}: IrisErrorBoundaryFallbackProps): React.ReactElement {\n const { t } = useI18n()\n return (\n <div\n data-iris-error-boundary=\"\"\n role=\"alert\"\n style={{\n padding: 16,\n border: '1px solid var(--iris-danger)',\n borderRadius: 'var(--iris-radius-md, 6px)',\n color: 'var(--iris-danger)',\n }}\n >\n <div data-iris-error-boundary-message=\"\">{error.message || t('errorBoundary.message')}</div>\n <button type=\"button\" data-iris-error-boundary-retry=\"\" onClick={reset}>\n {t('errorBoundary.retry')}\n </button>\n </div>\n )\n}\n\n/**\n * Catches errors thrown while rendering its subtree and switches to a fallback\n * UI instead of crashing the whole React tree. Exposes `reset()` (passed to the\n * fallback) that clears the error and re-attempts rendering the children.\n *\n * Standalone component — it does NOT wrap `IrisProvider`'s children, so error\n * semantics for existing consumers are unchanged.\n *\n * React port of {@link import('@iris-ui-kit/vue').IrisErrorBoundary}.\n */\nexport class IrisErrorBoundary extends React.Component<\n IrisErrorBoundaryProps,\n IrisErrorBoundaryState\n> {\n override state: IrisErrorBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: Error): IrisErrorBoundaryState {\n return { error }\n }\n\n override componentDidCatch(error: Error, info: React.ErrorInfo): void {\n this.props.onError?.(error, info)\n }\n\n reset = (): void => {\n this.setState({ error: null })\n }\n\n override render(): React.ReactNode {\n const { error } = this.state\n if (error !== null) {\n const { fallback } = this.props\n if (fallback) return fallback({ error, reset: this.reset })\n return <DefaultErrorFallback error={error} reset={this.reset} />\n }\n return this.props.children\n }\n}\n"]}
@@ -0,0 +1,64 @@
1
+ 'use client'
2
+ import { useStore } from './chunk-RZNYIFV2.js';
3
+ import * as React from 'react';
4
+ import { createAsyncResource, createPaginatedResource } from '@iris-ui-kit/core';
5
+
6
+ function useAsyncResource(fetcher, options = {}) {
7
+ const latest = React.useRef(fetcher);
8
+ latest.current = fetcher;
9
+ const ref = React.useRef(null);
10
+ if (ref.current === null) {
11
+ const config = "initialData" in options ? { initialData: options.initialData } : {};
12
+ ref.current = createAsyncResource((...params) => latest.current(...params), config);
13
+ }
14
+ const resource = ref.current;
15
+ const state = useStore(resource.store);
16
+ const immediate = React.useRef(options.immediate ?? false);
17
+ React.useEffect(() => {
18
+ if (immediate.current) void resource.load(...[]);
19
+ return () => resource.cancel();
20
+ }, [resource]);
21
+ return {
22
+ ...state,
23
+ isLoading: state.status === "loading",
24
+ isError: state.status === "error",
25
+ load: resource.load,
26
+ reload: resource.reload,
27
+ mutate: resource.mutate,
28
+ cancel: resource.cancel,
29
+ reset: resource.reset
30
+ };
31
+ }
32
+ function usePaginatedResource(fetcher, options = {}) {
33
+ const latest = React.useRef(fetcher);
34
+ latest.current = fetcher;
35
+ const ref = React.useRef(null);
36
+ if (ref.current === null) {
37
+ ref.current = createPaginatedResource((query) => latest.current(query), {
38
+ pageSize: options.pageSize,
39
+ mode: options.mode
40
+ });
41
+ }
42
+ const resource = ref.current;
43
+ const state = useStore(resource.store);
44
+ const initial = React.useRef({ immediate: options.immediate ?? false, mode: options.mode });
45
+ React.useEffect(() => {
46
+ if (!initial.current.immediate) return;
47
+ void (initial.current.mode === "infinite" ? resource.loadMore() : resource.goToPage(1));
48
+ }, [resource]);
49
+ return {
50
+ ...state,
51
+ isLoading: state.status === "loading",
52
+ isError: state.status === "error",
53
+ // `state` drives the re-render; hasMore() then reads the fresh batch state.
54
+ hasMore: resource.hasMore(),
55
+ goToPage: resource.goToPage,
56
+ loadMore: resource.loadMore,
57
+ refresh: resource.refresh,
58
+ setPageSize: resource.setPageSize
59
+ };
60
+ }
61
+
62
+ export { useAsyncResource, usePaginatedResource };
63
+ //# sourceMappingURL=chunk-TO7YVSAI.js.map
64
+ //# sourceMappingURL=chunk-TO7YVSAI.js.map