@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,183 @@
1
+ import * as React from 'react';
2
+ import { NavNode, TabsNav, TabItem } from '@iris-ui-kit/core';
3
+ export { NavNode, TabItem, TabsNav, TabsNavConfig, TabsNavState, createTabsNav, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, isBranch, isClosable, nodeAllowsRoles, visibleNav } from '@iris-ui-kit/core';
4
+
5
+ type IrisAdminLayoutMode = 'sidebar' | 'full-content';
6
+ type LogoRenderer = React.ReactNode | ((state: {
7
+ collapsed: boolean;
8
+ }) => React.ReactNode);
9
+ type ContentRenderer = React.ReactNode | ((state: {
10
+ activeKey: string;
11
+ }) => React.ReactNode);
12
+ interface IrisAdminLayoutProps {
13
+ /** Normalized nav tree driving menu + breadcrumb. */
14
+ menus: NavNode[];
15
+ /** Active page key (controlled). */
16
+ activeKey?: string;
17
+ defaultActiveKey?: string;
18
+ onActiveKeyChange?: (key: string) => void;
19
+ /** Sidebar collapsed (controlled); undefined = uncontrolled. */
20
+ collapsed?: boolean;
21
+ defaultCollapsed?: boolean;
22
+ onCollapsedChange?: (next: boolean) => void;
23
+ mode?: IrisAdminLayoutMode;
24
+ appTitle?: string;
25
+ /** Optional shared tabs store; when present the tab bar is rendered. */
26
+ tabs?: TabsNav;
27
+ showBreadcrumb?: boolean;
28
+ sidebarWidth?: number | string;
29
+ collapsedWidth?: number | string;
30
+ /** Brand region; render-prop receives `{ collapsed }`. */
31
+ logo?: LogoRenderer;
32
+ /** Header end region (theme switch, user menu, …). */
33
+ toolbar?: React.ReactNode;
34
+ footer?: React.ReactNode;
35
+ onSelect?: (key: string, node: NavNode) => void;
36
+ /** Page content; render-prop receives `{ activeKey }`. */
37
+ children?: ContentRenderer;
38
+ }
39
+ /**
40
+ * The CMS / admin shell — a Vben-style, router-agnostic, data-driven layout that
41
+ * composes IrisSidebarLayout + IrisHeaderLayout with the admin nav pieces. One
42
+ * `menus` tree drives the collapsible sidebar nav, the header breadcrumb, and
43
+ * (when a `tabs` store is passed) the multi-tab bar; `activeKey` is the current
44
+ * page. The host owns routing: react to `onSelect` / `onActiveKeyChange` and
45
+ * render the page via the children render-prop (wrap it in keep-alive keyed by
46
+ * `tabs.cacheKey` for Vben-style tab caching).
47
+ *
48
+ * Modes: `sidebar` (default) and `full-content` (chrome hidden). React port of
49
+ * the Vue `IrisAdminLayout`.
50
+ */
51
+ declare function IrisAdminLayout({ menus, activeKey, defaultActiveKey, onActiveKeyChange, collapsed, defaultCollapsed, onCollapsedChange, mode, appTitle, tabs, showBreadcrumb, sidebarWidth, collapsedWidth, logo, toolbar, footer, onSelect, children, }: IrisAdminLayoutProps): React.ReactElement;
52
+
53
+ interface IrisNavMenuProps {
54
+ /** Normalized nav tree. */
55
+ items: NavNode[];
56
+ /** Key of the active leaf. */
57
+ activeKey?: string;
58
+ /** Controlled expanded branch keys. */
59
+ expandedKeys?: string[];
60
+ /** Initial expanded keys when uncontrolled (else the active trail expands). */
61
+ defaultExpandedKeys?: string[];
62
+ /** Icon-only rail (top-level items only). */
63
+ collapsed?: boolean;
64
+ ariaLabel?: string;
65
+ onSelect?: (key: string, node: NavNode) => void;
66
+ onExpandedKeysChange?: (keys: string[]) => void;
67
+ }
68
+ /**
69
+ * Data-driven nested navigation menu — the sidebar nav of the admin shell.
70
+ * Renders a normalized `NavNode[]` tree as an accordion of expandable branches
71
+ * and selectable leaves; the active leaf and its ancestor branches are
72
+ * highlighted, and the active branch trail auto-expands. Router-agnostic: takes
73
+ * `activeKey`, calls `onSelect(key, node)`; the host owns navigation.
74
+ *
75
+ * `collapsed` switches to an icon-only rail (top-level only); a branch click
76
+ * then jumps to its first leaf. React port of the Vue `IrisNavMenu`.
77
+ */
78
+ declare function IrisNavMenu({ items, activeKey, expandedKeys, defaultExpandedKeys, collapsed, ariaLabel, onSelect, onExpandedKeysChange, }: IrisNavMenuProps): React.ReactElement;
79
+
80
+ interface IrisAdminBreadcrumbProps {
81
+ /** Root→current ancestor chain (typically `findNavPath(menus, activeKey)`). */
82
+ trail: NavNode[];
83
+ /** Show each node's icon before its title. */
84
+ showIcon?: boolean;
85
+ /** Hide the breadcrumb when the trail has a single crumb. */
86
+ hideSingle?: boolean;
87
+ separator?: string;
88
+ onSelect?: (key: string, node: NavNode) => void;
89
+ }
90
+ /**
91
+ * Breadcrumb trail for the admin header, driven by a `NavNode[]` ancestor chain.
92
+ * The last crumb is the current page (auto-marked `aria-current` by
93
+ * IrisBreadcrumb); earlier crumbs are clickable and call `onSelect(key, node)`.
94
+ * React port of the Vue `IrisAdminBreadcrumb`.
95
+ */
96
+ declare function IrisAdminBreadcrumb({ trail, showIcon, hideSingle, separator, onSelect, }: IrisAdminBreadcrumbProps): React.ReactElement | null;
97
+
98
+ interface IrisAdminTabsProps {
99
+ /** Shared tabs store (from `createTabsNav`). */
100
+ nav: TabsNav;
101
+ onChange?: (key: string) => void;
102
+ onClose?: (key: string) => void;
103
+ onRefresh?: (key: string) => void;
104
+ }
105
+ /**
106
+ * Vben-style multi-tab bar over a shared {@link TabsNav} store. Each open page is
107
+ * a closable chip; clicking activates (`onChange`), the × closes, and a trailing
108
+ * actions dropdown runs Refresh / Close / Close-others / Close-all on the active
109
+ * tab. The store owns the tab list + active key; the host watches it to sync
110
+ * routing + keep-alive.
111
+ *
112
+ * Keyboard (WAI-ARIA tablist, automatic activation): ←/→ move + activate, Home/
113
+ * End jump, Delete/Backspace closes the focused tab. Roving tabindex keeps a
114
+ * single tab stop. React port of the Vue `IrisAdminTabs`.
115
+ */
116
+ declare function IrisAdminTabs({ nav, onChange, onClose, onRefresh, }: IrisAdminTabsProps): React.ReactElement;
117
+
118
+ interface UseTabsNavReturn {
119
+ tabs: TabItem[];
120
+ activeKey: string | undefined;
121
+ /** Keep-alive include-set (composite cache keys of all open tabs). */
122
+ cacheKeys: string[];
123
+ open: TabsNav['open'];
124
+ activate: TabsNav['activate'];
125
+ close: TabsNav['close'];
126
+ closeOthers: TabsNav['closeOthers'];
127
+ closeAll: TabsNav['closeAll'];
128
+ closeLeft: TabsNav['closeLeft'];
129
+ closeRight: TabsNav['closeRight'];
130
+ refresh: TabsNav['refresh'];
131
+ setPinned: TabsNav['setPinned'];
132
+ cacheKey: TabsNav['cacheKey'];
133
+ }
134
+ /**
135
+ * React binding for a framework-agnostic {@link TabsNav} store. Pass a shared
136
+ * `createTabsNav()` instance (the host owns it so the tab bar and the keep-alive
137
+ * content read the same state) and get the reactive `tabs` / `activeKey` /
138
+ * `cacheKeys` plus the store's mutators — bridged via `useStore`
139
+ * (`useSyncExternalStore`), mirroring the Vue adapter.
140
+ *
141
+ * ```tsx
142
+ * const nav = createTabsNav({ tabs: [{ key: 'home', title: 'Home', pinned: true }] })
143
+ * const { tabs, activeKey, open, close } = useTabsNav(nav)
144
+ * ```
145
+ */
146
+ declare function useTabsNav(nav: TabsNav): UseTabsNavReturn;
147
+
148
+ interface UseAdminShellConfig {
149
+ /** Normalized nav tree driving menu + breadcrumb. */
150
+ menus: NavNode[];
151
+ /** Active page key (controlled); undefined = uncontrolled. */
152
+ activeKey?: string;
153
+ defaultActiveKey?: string;
154
+ onActiveKeyChange?: (key: string) => void;
155
+ /** Fired whenever a nav node / tab becomes active, with the resolved leaf node. */
156
+ onSelect?: (key: string, node: NavNode) => void;
157
+ /** Optional shared tabs store; the shell opens/reconciles tabs through it. */
158
+ tabs?: TabsNav;
159
+ }
160
+ interface UseAdminShellReturn {
161
+ /** Current active leaf key ('' when none). */
162
+ activeKey: string;
163
+ /** Select a nav node: a branch redirects to its first leaf, opens its tab. */
164
+ navigate: (node: NavNode) => void;
165
+ /** Reconcile when the active TAB changed (e.g. a close picked a neighbor). */
166
+ syncFromTab: (key: string) => void;
167
+ /** Ancestor→node breadcrumb trail of the active key. */
168
+ breadcrumb: NavNode[];
169
+ }
170
+ /**
171
+ * React binding for the framework-agnostic {@link createAdminShell} controller —
172
+ * the menu→tab→active-key wiring that every AdminLayout used to re-implement
173
+ * byte-for-byte. The hook owns the controlled/uncontrolled `activeKey`
174
+ * reconciliation (idiomatic to React) and delegates navigate / syncFromTab /
175
+ * branch-resolution / breadcrumb to the shared core shell.
176
+ *
177
+ * Controlled mode renders from the prop directly (no flicker); an effect keeps
178
+ * the shell's guard-base synced to the prop so the active-change callback fires
179
+ * with the same semantics as before.
180
+ */
181
+ declare function useAdminShell(config: UseAdminShellConfig): UseAdminShellReturn;
182
+
183
+ export { IrisAdminBreadcrumb, type IrisAdminBreadcrumbProps, IrisAdminLayout, type IrisAdminLayoutMode, type IrisAdminLayoutProps, IrisAdminTabs, type IrisAdminTabsProps, IrisNavMenu, type IrisNavMenuProps, type UseAdminShellConfig, type UseAdminShellReturn, type UseTabsNavReturn, useAdminShell, useTabsNav };
package/dist/admin.js ADDED
@@ -0,0 +1,9 @@
1
+ 'use client'
2
+ export { IrisAdminBreadcrumb, IrisAdminLayout, IrisAdminTabs, IrisNavMenu, createTabsNav, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, isBranch, isClosable, nodeAllowsRoles, useAdminShell, useTabsNav, visibleNav } from './chunk-VWCJJRSC.js';
3
+ import './chunk-XCK4RIXB.js';
4
+ import './chunk-J5FB2UB2.js';
5
+ import './chunk-OMOTUHYI.js';
6
+ import './chunk-6BMFMCMQ.js';
7
+ import './chunk-RZNYIFV2.js';
8
+ //# sourceMappingURL=admin.js.map
9
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":";","file":"admin.js"}
package/dist/async.cjs ADDED
@@ -0,0 +1,97 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ var React2 = require('react');
5
+ var core = require('@iris-ui-kit/core');
6
+
7
+ function _interopNamespace(e) {
8
+ if (e && e.__esModule) return e;
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
26
+
27
+ // src/async/useAsyncResource.ts
28
+ function useStore(store) {
29
+ return React2.useSyncExternalStore(
30
+ store.subscribe,
31
+ store.getState,
32
+ store.getState
33
+ // SSR fallback — same as client snapshot in our case.
34
+ );
35
+ }
36
+
37
+ // src/async/useAsyncResource.ts
38
+ function useAsyncResource(fetcher, options = {}) {
39
+ const latest = React2__namespace.useRef(fetcher);
40
+ latest.current = fetcher;
41
+ const ref = React2__namespace.useRef(null);
42
+ if (ref.current === null) {
43
+ const config = "initialData" in options ? { initialData: options.initialData } : {};
44
+ ref.current = core.createAsyncResource((...params) => latest.current(...params), config);
45
+ }
46
+ const resource = ref.current;
47
+ const state = useStore(resource.store);
48
+ const immediate = React2__namespace.useRef(options.immediate ?? false);
49
+ React2__namespace.useEffect(() => {
50
+ if (immediate.current) void resource.load(...[]);
51
+ return () => resource.cancel();
52
+ }, [resource]);
53
+ return {
54
+ ...state,
55
+ isLoading: state.status === "loading",
56
+ isError: state.status === "error",
57
+ load: resource.load,
58
+ reload: resource.reload,
59
+ mutate: resource.mutate,
60
+ cancel: resource.cancel,
61
+ reset: resource.reset
62
+ };
63
+ }
64
+ function usePaginatedResource(fetcher, options = {}) {
65
+ const latest = React2__namespace.useRef(fetcher);
66
+ latest.current = fetcher;
67
+ const ref = React2__namespace.useRef(null);
68
+ if (ref.current === null) {
69
+ ref.current = core.createPaginatedResource((query) => latest.current(query), {
70
+ pageSize: options.pageSize,
71
+ mode: options.mode
72
+ });
73
+ }
74
+ const resource = ref.current;
75
+ const state = useStore(resource.store);
76
+ const initial = React2__namespace.useRef({ immediate: options.immediate ?? false, mode: options.mode });
77
+ React2__namespace.useEffect(() => {
78
+ if (!initial.current.immediate) return;
79
+ void (initial.current.mode === "infinite" ? resource.loadMore() : resource.goToPage(1));
80
+ }, [resource]);
81
+ return {
82
+ ...state,
83
+ isLoading: state.status === "loading",
84
+ isError: state.status === "error",
85
+ // `state` drives the re-render; hasMore() then reads the fresh batch state.
86
+ hasMore: resource.hasMore(),
87
+ goToPage: resource.goToPage,
88
+ loadMore: resource.loadMore,
89
+ refresh: resource.refresh,
90
+ setPageSize: resource.setPageSize
91
+ };
92
+ }
93
+
94
+ exports.useAsyncResource = useAsyncResource;
95
+ exports.usePaginatedResource = usePaginatedResource;
96
+ //# sourceMappingURL=async.cjs.map
97
+ //# sourceMappingURL=async.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/useStore.ts","../src/async/useAsyncResource.ts","../src/async/usePaginatedResource.ts"],"names":["useSyncExternalStore","React2","createAsyncResource","React3","createPaginatedResource"],"mappings":"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","file":"async.cjs","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","import * as React from 'react'\nimport {\n createAsyncResource,\n type AsyncResource,\n type AsyncResourceConfig,\n type AsyncState,\n} from '@iris-ui-kit/core'\nimport { useStore } from '../useStore'\n\nexport interface UseAsyncResourceOptions<T> extends AsyncResourceConfig<T> {\n /** Run `load()` (no params) once on mount. Default `false`. */\n immediate?: boolean\n}\n\nexport interface UseAsyncResourceReturn<T, P extends unknown[]> extends AsyncState<T> {\n isLoading: boolean\n isError: boolean\n load: AsyncResource<T, P>['load']\n reload: AsyncResource<T, P>['reload']\n mutate: AsyncResource<T, P>['mutate']\n cancel: AsyncResource<T, P>['cancel']\n reset: AsyncResource<T, P>['reset']\n}\n\n/**\n * React binding for the framework-agnostic async resource. Instantiates the\n * resource once and bridges it via `useSyncExternalStore`. The fetcher is read\n * through a ref each render so it never goes stale, while seeding/immediacy are\n * captured on first render.\n *\n * ```tsx\n * const users = useAsyncResource(() => api.listUsers(), { immediate: true })\n * <IrisTable data={users.data ?? []} loading={users.isLoading} error={users.isError} />\n * ```\n */\nexport function useAsyncResource<T, P extends unknown[] = []>(\n fetcher: (...params: P) => Promise<T>,\n options: UseAsyncResourceOptions<T> = {},\n): UseAsyncResourceReturn<T, P> {\n const latest = React.useRef(fetcher)\n latest.current = fetcher\n\n const ref = React.useRef<AsyncResource<T, P> | null>(null)\n if (ref.current === null) {\n const config: AsyncResourceConfig<T> =\n 'initialData' in options ? { initialData: options.initialData } : {}\n ref.current = createAsyncResource<T, P>((...params) => latest.current(...params), config)\n }\n const resource = ref.current\n const state = useStore(resource.store)\n\n const immediate = React.useRef(options.immediate ?? false)\n React.useEffect(() => {\n if (immediate.current) void resource.load(...([] as unknown as P))\n // Abort any in-flight request on unmount so it can't write back into an\n // unmounted component (the token guard already prevents the state write;\n // this also cancels the underlying request when the fetcher honors signal).\n return () => resource.cancel()\n }, [resource])\n\n return {\n ...state,\n isLoading: state.status === 'loading',\n isError: state.status === 'error',\n load: resource.load,\n reload: resource.reload,\n mutate: resource.mutate,\n cancel: resource.cancel,\n reset: resource.reset,\n }\n}\n","import * as React from 'react'\nimport {\n createPaginatedResource,\n type PageQuery,\n type PageResult,\n type PaginatedResource,\n type PaginatedState,\n type PaginationMode,\n} from '@iris-ui-kit/core'\nimport { useStore } from '../useStore'\n\nexport interface UsePaginatedResourceOptions {\n pageSize?: number\n mode?: PaginationMode\n /** Load the first page on mount (page 1, or `loadMore` in infinite mode). */\n immediate?: boolean\n}\n\nexport interface UsePaginatedResourceReturn<T> extends PaginatedState<T> {\n isLoading: boolean\n isError: boolean\n hasMore: boolean\n goToPage: PaginatedResource<T>['goToPage']\n loadMore: PaginatedResource<T>['loadMore']\n refresh: PaginatedResource<T>['refresh']\n setPageSize: PaginatedResource<T>['setPageSize']\n}\n\n/**\n * React binding for the server-side pagination resource. Instantiates once and\n * bridges via `useSyncExternalStore`; the fetcher is read through a ref so it\n * never goes stale.\n *\n * ```tsx\n * const p = usePaginatedResource((q) => api.rows(q), { pageSize: 25, immediate: true })\n * <IrisTable data={p.items} loading={p.isLoading} error={p.isError} />\n * <IrisPagination total={p.total ?? 0} value={p.page} onValueChange={p.goToPage} />\n * ```\n */\nexport function usePaginatedResource<T>(\n fetcher: (query: PageQuery) => Promise<PageResult<T>>,\n options: UsePaginatedResourceOptions = {},\n): UsePaginatedResourceReturn<T> {\n const latest = React.useRef(fetcher)\n latest.current = fetcher\n\n const ref = React.useRef<PaginatedResource<T> | null>(null)\n if (ref.current === null) {\n ref.current = createPaginatedResource<T>((query) => latest.current(query), {\n pageSize: options.pageSize,\n mode: options.mode,\n })\n }\n const resource = ref.current\n const state = useStore(resource.store)\n\n const initial = React.useRef({ immediate: options.immediate ?? false, mode: options.mode })\n React.useEffect(() => {\n if (!initial.current.immediate) return\n void (initial.current.mode === 'infinite' ? resource.loadMore() : resource.goToPage(1))\n }, [resource])\n\n return {\n ...state,\n isLoading: state.status === 'loading',\n isError: state.status === 'error',\n // `state` drives the re-render; hasMore() then reads the fresh batch state.\n hasMore: resource.hasMore(),\n goToPage: resource.goToPage,\n loadMore: resource.loadMore,\n refresh: resource.refresh,\n setPageSize: resource.setPageSize,\n }\n}\n"]}
@@ -0,0 +1,57 @@
1
+ import { AsyncResourceConfig, AsyncState, AsyncResource, PaginationMode, PaginatedState, PaginatedResource, PageQuery, PageResult } from '@iris-ui-kit/core';
2
+
3
+ interface UseAsyncResourceOptions<T> extends AsyncResourceConfig<T> {
4
+ /** Run `load()` (no params) once on mount. Default `false`. */
5
+ immediate?: boolean;
6
+ }
7
+ interface UseAsyncResourceReturn<T, P extends unknown[]> extends AsyncState<T> {
8
+ isLoading: boolean;
9
+ isError: boolean;
10
+ load: AsyncResource<T, P>['load'];
11
+ reload: AsyncResource<T, P>['reload'];
12
+ mutate: AsyncResource<T, P>['mutate'];
13
+ cancel: AsyncResource<T, P>['cancel'];
14
+ reset: AsyncResource<T, P>['reset'];
15
+ }
16
+ /**
17
+ * React binding for the framework-agnostic async resource. Instantiates the
18
+ * resource once and bridges it via `useSyncExternalStore`. The fetcher is read
19
+ * through a ref each render so it never goes stale, while seeding/immediacy are
20
+ * captured on first render.
21
+ *
22
+ * ```tsx
23
+ * const users = useAsyncResource(() => api.listUsers(), { immediate: true })
24
+ * <IrisTable data={users.data ?? []} loading={users.isLoading} error={users.isError} />
25
+ * ```
26
+ */
27
+ declare function useAsyncResource<T, P extends unknown[] = []>(fetcher: (...params: P) => Promise<T>, options?: UseAsyncResourceOptions<T>): UseAsyncResourceReturn<T, P>;
28
+
29
+ interface UsePaginatedResourceOptions {
30
+ pageSize?: number;
31
+ mode?: PaginationMode;
32
+ /** Load the first page on mount (page 1, or `loadMore` in infinite mode). */
33
+ immediate?: boolean;
34
+ }
35
+ interface UsePaginatedResourceReturn<T> extends PaginatedState<T> {
36
+ isLoading: boolean;
37
+ isError: boolean;
38
+ hasMore: boolean;
39
+ goToPage: PaginatedResource<T>['goToPage'];
40
+ loadMore: PaginatedResource<T>['loadMore'];
41
+ refresh: PaginatedResource<T>['refresh'];
42
+ setPageSize: PaginatedResource<T>['setPageSize'];
43
+ }
44
+ /**
45
+ * React binding for the server-side pagination resource. Instantiates once and
46
+ * bridges via `useSyncExternalStore`; the fetcher is read through a ref so it
47
+ * never goes stale.
48
+ *
49
+ * ```tsx
50
+ * const p = usePaginatedResource((q) => api.rows(q), { pageSize: 25, immediate: true })
51
+ * <IrisTable data={p.items} loading={p.isLoading} error={p.isError} />
52
+ * <IrisPagination total={p.total ?? 0} value={p.page} onValueChange={p.goToPage} />
53
+ * ```
54
+ */
55
+ declare function usePaginatedResource<T>(fetcher: (query: PageQuery) => Promise<PageResult<T>>, options?: UsePaginatedResourceOptions): UsePaginatedResourceReturn<T>;
56
+
57
+ export { type UseAsyncResourceOptions, type UseAsyncResourceReturn, type UsePaginatedResourceOptions, type UsePaginatedResourceReturn, useAsyncResource, usePaginatedResource };
@@ -0,0 +1,57 @@
1
+ import { AsyncResourceConfig, AsyncState, AsyncResource, PaginationMode, PaginatedState, PaginatedResource, PageQuery, PageResult } from '@iris-ui-kit/core';
2
+
3
+ interface UseAsyncResourceOptions<T> extends AsyncResourceConfig<T> {
4
+ /** Run `load()` (no params) once on mount. Default `false`. */
5
+ immediate?: boolean;
6
+ }
7
+ interface UseAsyncResourceReturn<T, P extends unknown[]> extends AsyncState<T> {
8
+ isLoading: boolean;
9
+ isError: boolean;
10
+ load: AsyncResource<T, P>['load'];
11
+ reload: AsyncResource<T, P>['reload'];
12
+ mutate: AsyncResource<T, P>['mutate'];
13
+ cancel: AsyncResource<T, P>['cancel'];
14
+ reset: AsyncResource<T, P>['reset'];
15
+ }
16
+ /**
17
+ * React binding for the framework-agnostic async resource. Instantiates the
18
+ * resource once and bridges it via `useSyncExternalStore`. The fetcher is read
19
+ * through a ref each render so it never goes stale, while seeding/immediacy are
20
+ * captured on first render.
21
+ *
22
+ * ```tsx
23
+ * const users = useAsyncResource(() => api.listUsers(), { immediate: true })
24
+ * <IrisTable data={users.data ?? []} loading={users.isLoading} error={users.isError} />
25
+ * ```
26
+ */
27
+ declare function useAsyncResource<T, P extends unknown[] = []>(fetcher: (...params: P) => Promise<T>, options?: UseAsyncResourceOptions<T>): UseAsyncResourceReturn<T, P>;
28
+
29
+ interface UsePaginatedResourceOptions {
30
+ pageSize?: number;
31
+ mode?: PaginationMode;
32
+ /** Load the first page on mount (page 1, or `loadMore` in infinite mode). */
33
+ immediate?: boolean;
34
+ }
35
+ interface UsePaginatedResourceReturn<T> extends PaginatedState<T> {
36
+ isLoading: boolean;
37
+ isError: boolean;
38
+ hasMore: boolean;
39
+ goToPage: PaginatedResource<T>['goToPage'];
40
+ loadMore: PaginatedResource<T>['loadMore'];
41
+ refresh: PaginatedResource<T>['refresh'];
42
+ setPageSize: PaginatedResource<T>['setPageSize'];
43
+ }
44
+ /**
45
+ * React binding for the server-side pagination resource. Instantiates once and
46
+ * bridges via `useSyncExternalStore`; the fetcher is read through a ref so it
47
+ * never goes stale.
48
+ *
49
+ * ```tsx
50
+ * const p = usePaginatedResource((q) => api.rows(q), { pageSize: 25, immediate: true })
51
+ * <IrisTable data={p.items} loading={p.isLoading} error={p.isError} />
52
+ * <IrisPagination total={p.total ?? 0} value={p.page} onValueChange={p.goToPage} />
53
+ * ```
54
+ */
55
+ declare function usePaginatedResource<T>(fetcher: (query: PageQuery) => Promise<PageResult<T>>, options?: UsePaginatedResourceOptions): UsePaginatedResourceReturn<T>;
56
+
57
+ export { type UseAsyncResourceOptions, type UseAsyncResourceReturn, type UsePaginatedResourceOptions, type UsePaginatedResourceReturn, useAsyncResource, usePaginatedResource };
package/dist/async.js ADDED
@@ -0,0 +1,5 @@
1
+ 'use client'
2
+ export { useAsyncResource, usePaginatedResource } from './chunk-TO7YVSAI.js';
3
+ import './chunk-RZNYIFV2.js';
4
+ //# sourceMappingURL=async.js.map
5
+ //# sourceMappingURL=async.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":";","file":"async.js"}