@iris-ui-kit/react 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/admin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- export { IrisAdminBreadcrumb, IrisAdminLayout, IrisAdminTabs, IrisNavMenu, createAdminPreferences, createTabsNav, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, isBranch, isClosable, localStorageAdminPreferencesStorage, nodeAllowsRoles, useAdminPreferences, useAdminShell, useTabsNav, visibleNav } from './chunk-KRFZ5KL4.js';
2
+ export { IrisAdminBreadcrumb, IrisAdminLayout, IrisAdminTabs, IrisNavMenu, createAdminPreferences, createTabsNav, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, isBranch, isClosable, localStorageAdminPreferencesStorage, nodeAllowsRoles, useAdminPreferences, useAdminShell, useTabsNav, visibleNav } from './chunk-TDVRIHE6.js';
3
3
  import './chunk-XCK4RIXB.js';
4
4
  import './chunk-J5FB2UB2.js';
5
5
  import './chunk-K2F7SC2T.js';
package/dist/async.cjs CHANGED
@@ -66,17 +66,25 @@ function usePaginatedResource(fetcher, options = {}) {
66
66
  latest.current = fetcher;
67
67
  const ref = React2__namespace.useRef(null);
68
68
  if (ref.current === null) {
69
- ref.current = core.createPaginatedResource((query) => latest.current(query), {
70
- pageSize: options.pageSize,
71
- mode: options.mode
72
- });
69
+ ref.current = core.createPaginatedResource(
70
+ (query, signal) => {
71
+ const current = latest.current;
72
+ return signal === void 0 ? current(query) : current(query, signal);
73
+ },
74
+ {
75
+ pageSize: options.pageSize,
76
+ mode: options.mode
77
+ }
78
+ );
73
79
  }
74
80
  const resource = ref.current;
75
81
  const state = useStore(resource.store);
76
82
  const initial = React2__namespace.useRef({ immediate: options.immediate ?? false, mode: options.mode });
77
83
  React2__namespace.useEffect(() => {
78
- if (!initial.current.immediate) return;
79
- void (initial.current.mode === "infinite" ? resource.loadMore() : resource.goToPage(1));
84
+ if (initial.current.immediate) {
85
+ void (initial.current.mode === "infinite" ? resource.loadMore() : resource.goToPage(1));
86
+ }
87
+ return () => resource.cancel();
80
88
  }, [resource]);
81
89
  return {
82
90
  ...state,
@@ -87,7 +95,8 @@ function usePaginatedResource(fetcher, options = {}) {
87
95
  goToPage: resource.goToPage,
88
96
  loadMore: resource.loadMore,
89
97
  refresh: resource.refresh,
90
- setPageSize: resource.setPageSize
98
+ setPageSize: resource.setPageSize,
99
+ cancel: resource.cancel
91
100
  };
92
101
  }
93
102
 
@@ -1 +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"]}
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 AdvancedPaginatedResource,\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: AdvancedPaginatedResource<T>['goToPage']\n loadMore: AdvancedPaginatedResource<T>['loadMore']\n refresh: AdvancedPaginatedResource<T>['refresh']\n setPageSize: AdvancedPaginatedResource<T>['setPageSize']\n cancel: AdvancedPaginatedResource<T>['cancel']\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, signal?: AbortSignal) => 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<AdvancedPaginatedResource<T> | null>(null)\n if (ref.current === null) {\n ref.current = createPaginatedResource<T>(\n (query, signal) => {\n const current = latest.current\n return signal === undefined ? current(query) : current(query, signal)\n },\n {\n pageSize: options.pageSize,\n mode: options.mode,\n },\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) {\n void (initial.current.mode === 'infinite' ? resource.loadMore() : resource.goToPage(1))\n }\n return () => resource.cancel()\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 cancel: resource.cancel,\n }\n}\n"]}
package/dist/async.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { AsyncResourceConfig, AsyncState, AsyncResource, PaginationMode, PaginatedState, PaginatedResource, PageQuery, PageResult } from '@iris-ui-kit/core';
1
+ import { AsyncResourceConfig, AsyncState, AsyncResource, PaginationMode, PaginatedState, AdvancedPaginatedResource, PageQuery, PageResult } from '@iris-ui-kit/core';
2
2
 
3
3
  interface UseAsyncResourceOptions<T> extends AsyncResourceConfig<T> {
4
4
  /** Run `load()` (no params) once on mount. Default `false`. */
@@ -36,10 +36,11 @@ interface UsePaginatedResourceReturn<T> extends PaginatedState<T> {
36
36
  isLoading: boolean;
37
37
  isError: boolean;
38
38
  hasMore: boolean;
39
- goToPage: PaginatedResource<T>['goToPage'];
40
- loadMore: PaginatedResource<T>['loadMore'];
41
- refresh: PaginatedResource<T>['refresh'];
42
- setPageSize: PaginatedResource<T>['setPageSize'];
39
+ goToPage: AdvancedPaginatedResource<T>['goToPage'];
40
+ loadMore: AdvancedPaginatedResource<T>['loadMore'];
41
+ refresh: AdvancedPaginatedResource<T>['refresh'];
42
+ setPageSize: AdvancedPaginatedResource<T>['setPageSize'];
43
+ cancel: AdvancedPaginatedResource<T>['cancel'];
43
44
  }
44
45
  /**
45
46
  * React binding for the server-side pagination resource. Instantiates once and
@@ -52,6 +53,6 @@ interface UsePaginatedResourceReturn<T> extends PaginatedState<T> {
52
53
  * <IrisPagination total={p.total ?? 0} value={p.page} onValueChange={p.goToPage} />
53
54
  * ```
54
55
  */
55
- declare function usePaginatedResource<T>(fetcher: (query: PageQuery) => Promise<PageResult<T>>, options?: UsePaginatedResourceOptions): UsePaginatedResourceReturn<T>;
56
+ declare function usePaginatedResource<T>(fetcher: (query: PageQuery, signal?: AbortSignal) => Promise<PageResult<T>>, options?: UsePaginatedResourceOptions): UsePaginatedResourceReturn<T>;
56
57
 
57
58
  export { type UseAsyncResourceOptions, type UseAsyncResourceReturn, type UsePaginatedResourceOptions, type UsePaginatedResourceReturn, useAsyncResource, usePaginatedResource };
package/dist/async.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AsyncResourceConfig, AsyncState, AsyncResource, PaginationMode, PaginatedState, PaginatedResource, PageQuery, PageResult } from '@iris-ui-kit/core';
1
+ import { AsyncResourceConfig, AsyncState, AsyncResource, PaginationMode, PaginatedState, AdvancedPaginatedResource, PageQuery, PageResult } from '@iris-ui-kit/core';
2
2
 
3
3
  interface UseAsyncResourceOptions<T> extends AsyncResourceConfig<T> {
4
4
  /** Run `load()` (no params) once on mount. Default `false`. */
@@ -36,10 +36,11 @@ interface UsePaginatedResourceReturn<T> extends PaginatedState<T> {
36
36
  isLoading: boolean;
37
37
  isError: boolean;
38
38
  hasMore: boolean;
39
- goToPage: PaginatedResource<T>['goToPage'];
40
- loadMore: PaginatedResource<T>['loadMore'];
41
- refresh: PaginatedResource<T>['refresh'];
42
- setPageSize: PaginatedResource<T>['setPageSize'];
39
+ goToPage: AdvancedPaginatedResource<T>['goToPage'];
40
+ loadMore: AdvancedPaginatedResource<T>['loadMore'];
41
+ refresh: AdvancedPaginatedResource<T>['refresh'];
42
+ setPageSize: AdvancedPaginatedResource<T>['setPageSize'];
43
+ cancel: AdvancedPaginatedResource<T>['cancel'];
43
44
  }
44
45
  /**
45
46
  * React binding for the server-side pagination resource. Instantiates once and
@@ -52,6 +53,6 @@ interface UsePaginatedResourceReturn<T> extends PaginatedState<T> {
52
53
  * <IrisPagination total={p.total ?? 0} value={p.page} onValueChange={p.goToPage} />
53
54
  * ```
54
55
  */
55
- declare function usePaginatedResource<T>(fetcher: (query: PageQuery) => Promise<PageResult<T>>, options?: UsePaginatedResourceOptions): UsePaginatedResourceReturn<T>;
56
+ declare function usePaginatedResource<T>(fetcher: (query: PageQuery, signal?: AbortSignal) => Promise<PageResult<T>>, options?: UsePaginatedResourceOptions): UsePaginatedResourceReturn<T>;
56
57
 
57
58
  export { type UseAsyncResourceOptions, type UseAsyncResourceReturn, type UsePaginatedResourceOptions, type UsePaginatedResourceReturn, useAsyncResource, usePaginatedResource };
package/dist/async.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- export { useAsyncResource, usePaginatedResource } from './chunk-TO7YVSAI.js';
2
+ export { useAsyncResource, usePaginatedResource } from './chunk-3KYNBLRY.js';
3
3
  import './chunk-RZNYIFV2.js';
4
4
  //# sourceMappingURL=async.js.map
5
5
  //# sourceMappingURL=async.js.map