@krizaka/ui 2.10.0 → 3.0.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.
- package/README.md +3 -1
- package/dist/audio-player.js +1 -1
- package/dist/{chunk-EUPTXKH7.js → chunk-BRKMQ6JV.js} +2 -1
- package/dist/chunk-FDCMBWUU.js +168 -0
- package/dist/chunk-FDCMBWUU.js.map +1 -0
- package/dist/chunk-HCNOOPZE.js +210 -0
- package/dist/chunk-HCNOOPZE.js.map +1 -0
- package/dist/{chunk-X6TW3X6Y.js → chunk-LCZXS6AK.js} +2 -2
- package/dist/chunk-OGJI5X4W.js +157 -0
- package/dist/chunk-OGJI5X4W.js.map +1 -0
- package/dist/combobox.js +2 -2
- package/dist/data-table.d.ts +284 -24
- package/dist/data-table.js +914 -121
- package/dist/data-table.js.map +1 -1
- package/dist/date-picker.js +1 -1
- package/dist/filter-bar.d.ts +12 -12
- package/dist/filter-bar.js +9 -145
- package/dist/filter-bar.js.map +1 -1
- package/dist/image-cropper.js +1 -1
- package/dist/media-capture.js +1 -1
- package/dist/native/list.d.ts +95 -0
- package/dist/native/list.js +135 -0
- package/dist/native/list.js.map +1 -0
- package/dist/search-field.js +6 -160
- package/dist/search-field.js.map +1 -1
- package/dist/tag-input.js +2 -2
- package/dist/video-player.js +1 -1
- package/dist/video-trimmer.js +1 -1
- package/dist/virtual.d.ts +140 -0
- package/dist/virtual.js +19 -0
- package/dist/virtual.js.map +1 -0
- package/package.json +66 -6
- package/registry/achievement.json +1 -1
- package/registry/action-bar.json +1 -1
- package/registry/alert.json +1 -1
- package/registry/app-shell.json +1 -1
- package/registry/argument-card.json +1 -1
- package/registry/audio-player.json +1 -1
- package/registry/auth-layout.json +1 -1
- package/registry/avatar.json +1 -1
- package/registry/badge.json +1 -1
- package/registry/button.json +1 -1
- package/registry/card-grid.json +1 -1
- package/registry/card.json +1 -1
- package/registry/catalogue-page.json +1 -1
- package/registry/changelog-page.json +1 -1
- package/registry/checkbox.json +1 -1
- package/registry/chip-link.json +1 -1
- package/registry/chip.json +1 -1
- package/registry/choice-grid.json +1 -1
- package/registry/code-block.json +1 -1
- package/registry/combobox.json +1 -1
- package/registry/command.json +1 -1
- package/registry/component-page.json +1 -1
- package/registry/confirm-button.json +1 -1
- package/registry/contact-page.json +1 -1
- package/registry/continue-prompt.json +1 -1
- package/registry/countdown.json +1 -1
- package/registry/cta-panel.json +1 -1
- package/registry/dashboard-layout.json +1 -1
- package/registry/data-table.json +643 -49
- package/registry/date-picker.json +1 -1
- package/registry/decision-list.json +1 -1
- package/registry/detail-layout.json +1 -1
- package/registry/dialog.json +1 -1
- package/registry/docs-article-page.json +1 -1
- package/registry/docs-hub-page.json +1 -1
- package/registry/docs-layout.json +1 -1
- package/registry/dropdown-menu.json +1 -1
- package/registry/empty-state.json +1 -1
- package/registry/error-page.json +1 -1
- package/registry/examples/data-table/details.d.ts +4 -0
- package/registry/examples/data-table/details.js +33 -0
- package/registry/examples/data-table/details.tsx +31 -0
- package/registry/examples/data-table/filters.d.ts +4 -0
- package/registry/examples/data-table/filters.js +40 -0
- package/registry/examples/data-table/filters.tsx +40 -0
- package/registry/examples/data-table/grouped.d.ts +4 -0
- package/registry/examples/data-table/grouped.js +24 -0
- package/registry/examples/data-table/grouped.tsx +23 -0
- package/registry/examples/data-table/paginated.d.ts +4 -0
- package/registry/examples/data-table/paginated.js +23 -0
- package/registry/examples/data-table/paginated.tsx +22 -0
- package/registry/examples/data-table/pinned.d.ts +4 -0
- package/registry/examples/data-table/pinned.js +26 -0
- package/registry/examples/data-table/pinned.tsx +25 -0
- package/registry/examples/data-table/server.d.ts +4 -0
- package/registry/examples/data-table/server.js +40 -0
- package/registry/examples/data-table/server.tsx +40 -0
- package/registry/examples/data-table/virtualized.js +2 -2
- package/registry/examples/data-table/virtualized.tsx +3 -3
- package/registry/examples/list/native/default.d.ts +4 -0
- package/registry/examples/list/native/default.dark.png +0 -0
- package/registry/examples/list/native/default.js +33 -0
- package/registry/examples/list/native/default.light.png +0 -0
- package/registry/examples/list/native/default.tsx +31 -0
- package/registry/examples/list/native/infinite.d.ts +4 -0
- package/registry/examples/list/native/infinite.dark.png +0 -0
- package/registry/examples/list/native/infinite.js +30 -0
- package/registry/examples/list/native/infinite.light.png +0 -0
- package/registry/examples/list/native/infinite.tsx +35 -0
- package/registry/examples/list/native/states.d.ts +4 -0
- package/registry/examples/list/native/states.dark.png +0 -0
- package/registry/examples/list/native/states.js +26 -0
- package/registry/examples/list/native/states.light.png +0 -0
- package/registry/examples/list/native/states.tsx +21 -0
- package/registry/examples/virtual/feed.d.ts +4 -0
- package/registry/examples/virtual/feed.js +26 -0
- package/registry/examples/virtual/feed.tsx +24 -0
- package/registry/examples/virtual/gallery.d.ts +4 -0
- package/registry/examples/virtual/gallery.js +31 -0
- package/registry/examples/virtual/gallery.tsx +28 -0
- package/registry/examples/virtual/messages.d.ts +4 -0
- package/registry/examples/virtual/messages.js +28 -0
- package/registry/examples/virtual/messages.tsx +28 -0
- package/registry/field.json +1 -1
- package/registry/file-upload.json +1 -1
- package/registry/filter-bar.json +1 -1
- package/registry/gallery-page.json +1 -1
- package/registry/glow-card.json +1 -1
- package/registry/goal-gauge.json +1 -1
- package/registry/how-it-works-page.json +1 -1
- package/registry/image-cropper.json +1 -1
- package/registry/index.json +48 -5
- package/registry/iso.json +1 -1
- package/registry/kbd.json +1 -1
- package/registry/landing-page.json +1 -1
- package/registry/landscape.json +1 -1
- package/registry/legal-page.json +1 -1
- package/registry/link-card.json +1 -1
- package/registry/list.json +249 -0
- package/registry/loader.json +1 -1
- package/registry/longform-page.json +1 -1
- package/registry/marketing-layout.json +1 -1
- package/registry/marquee.json +1 -1
- package/registry/mascot-quote.json +1 -1
- package/registry/mascot-state.json +1 -1
- package/registry/mascots.json +1 -1
- package/registry/media-capture.json +1 -1
- package/registry/meter.json +1 -1
- package/registry/nav-bar.json +1 -1
- package/registry/number-ticker.json +1 -1
- package/registry/page-header.json +1 -1
- package/registry/page-hero.json +1 -1
- package/registry/page.json +1 -1
- package/registry/pagination.json +1 -1
- package/registry/pointer-light.json +1 -1
- package/registry/popover.json +1 -1
- package/registry/pricing-page.json +1 -1
- package/registry/product-page.json +1 -1
- package/registry/profile-card.json +1 -1
- package/registry/progress.json +1 -1
- package/registry/promise-card.json +1 -1
- package/registry/radio-group.json +1 -1
- package/registry/scroll-stage.json +1 -1
- package/registry/search-field.json +1 -1
- package/registry/section-backdrop.json +1 -1
- package/registry/separator.json +1 -1
- package/registry/settings-layout.json +1 -1
- package/registry/skeleton.json +1 -1
- package/registry/slider.json +1 -1
- package/registry/slot.json +1 -1
- package/registry/spinner.json +1 -1
- package/registry/split-view.json +1 -1
- package/registry/stage-banner.json +1 -1
- package/registry/stat.json +1 -1
- package/registry/status-page.json +1 -1
- package/registry/stepper.json +1 -1
- package/registry/switch.json +1 -1
- package/registry/tabs.json +1 -1
- package/registry/tag-input.json +1 -1
- package/registry/terminal-replay.json +1 -1
- package/registry/theme.json +1 -1
- package/registry/toast.json +1 -1
- package/registry/toc.json +1 -1
- package/registry/tooltip.json +1 -1
- package/registry/video-player.json +1 -1
- package/registry/video-trimmer.json +1 -1
- package/registry/virtual.json +569 -0
- package/skills/data-table/SKILL.md +56 -0
- package/skills/native-list/SKILL.md +39 -0
- package/skills/virtual/SKILL.md +35 -0
- /package/dist/{chunk-EUPTXKH7.js.map → chunk-BRKMQ6JV.js.map} +0 -0
- /package/dist/{chunk-X6TW3X6Y.js.map → chunk-LCZXS6AK.js.map} +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: krizaka-data-table
|
|
3
|
+
description: Tables of records in a Krizaka web app with @krizaka/ui/data-table v2 (TanStack Table v9 behind the Krizaka facade) — sorting, text/facet/range filters, grouping, detail panels and trees, pagination, selection, column visibility, pinning, resizing, CSV export, server mode with @krizaka/query, windowing of long lists, cards on a phone. Use it before writing any table, list of records, admin grid or <table> in a Krizaka product.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @krizaka/ui/data-table (v2)
|
|
7
|
+
|
|
8
|
+
## Rules
|
|
9
|
+
|
|
10
|
+
1. Import from `@krizaka/ui/data-table` — **never `@tanstack/react-table`** (ESLint `krizaka/no-direct-tanstack-import`,
|
|
11
|
+
dependency-cruiser). The escape hatch is `useDataTable().table` (the TanStack instance), inside the table's `toolbar`.
|
|
12
|
+
2. **No `<table>` written by hand** in an app for records (ratchet `krizaka/no-local-table-or-form`).
|
|
13
|
+
3. `rows` and `columns` are **stable**: module scope, state, a query's `data`, or `useMemo`. Never `rows={data ?? []}` —
|
|
14
|
+
use a module constant (`const NONE: Row[] = []`).
|
|
15
|
+
4. Words are props, passed translated: `header` of each column, `caption`, `labels` (`dataTableLabels` lists them).
|
|
16
|
+
5. A server list: `manual={{ sorting: true, filtering: true, pagination: true }}`, `rowCount`, `onStateChange` → the
|
|
17
|
+
`DataTableQuery` in state (or the URL) → the query key (`defineKeys`) → `krizakaFetch`. `placeholderData:
|
|
18
|
+
keepPreviousData` keeps the page while the next loads; `meta: { list: true }` keeps errors in the table.
|
|
19
|
+
|
|
20
|
+
## Columns
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
const columns: DataTableColumn<Job>[] = [
|
|
24
|
+
{ id: "name", header: t.jobs.name, sortable: true, card: "title", filter: "text" },
|
|
25
|
+
{ id: "status", header: t.jobs.status, filter: "facet", groupable: true, options: statusOptions, cell: (j) => <Badge>…</Badge> },
|
|
26
|
+
{ id: "cost", header: t.jobs.cost, align: "end", filter: "range", value: (j) => j.cents, aggregate: (rows) => sum(rows) },
|
|
27
|
+
];
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`value` is what sorts, filters, groups and exports (default `row[id]`); `cell` is what shows.
|
|
31
|
+
|
|
32
|
+
## Recipes
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// Client table with filters, columns menu, export and pages
|
|
36
|
+
<DataTable caption={t.jobs.title} rows={jobs} columns={columns} getRowId={(j) => j.id} rowLabel={(j) => j.name}
|
|
37
|
+
selectable onSelectedChange={setSelected} defaultPageSize={25} pageSizeOptions={[25, 50, 100]}
|
|
38
|
+
toolbar={<><DataTableFilters /><DataTableColumnsMenu /><DataTableExport filename="jobs.csv" /></>}
|
|
39
|
+
labels={t.dataTable} />
|
|
40
|
+
|
|
41
|
+
// Server table
|
|
42
|
+
const [query, setQuery] = useState<DataTableQuery>({ sort: null, filters: {}, page: 1, pageSize: 25 });
|
|
43
|
+
const { data, isPending, error } = useQuery({ ...jobsQuery(query), placeholderData: keepPreviousData });
|
|
44
|
+
<DataTable rows={data?.rows ?? NONE} rowCount={data?.total} manual={{ sorting: true, filtering: true, pagination: true }}
|
|
45
|
+
defaultPageSize={25} onStateChange={setQuery} loading={isPending} error={error && <ErrorState … />} … />
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Also: `groupBy` / `defaultGroupBy`, `renderDetail` (a panel under a row), `getSubRows` (a tree), `pinning={{ start:
|
|
49
|
+
["name"], end: ["actions"] }}`, `resizing`, `columnVisibility`, `virtualized={{ height: 480 }}` (thousands of rows
|
|
50
|
+
loaded at once), `layout="cards"` / `auto` (cards below 36rem), `density="compact"`, `loading` / `empty` / `error`.
|
|
51
|
+
|
|
52
|
+
## Accessibility (built in)
|
|
53
|
+
|
|
54
|
+
Caption, `scope="col"`, `aria-sort`, `aria-expanded` on expand buttons, focusable resize separators (← →), a named
|
|
55
|
+
filters group with an announced count, `aria-busy` while loading, `role="alert"` on errors, `aria-rowcount` /
|
|
56
|
+
`aria-rowindex` when windowed. Give `caption` and `rowLabel` real words.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: krizaka-native-list
|
|
3
|
+
description: Lists in a Krizaka React Native / Expo app with @krizaka/ui/native/list — List on FlashList v2 (separators, skeleton rows, empty/error states, pull to refresh, spinner for the next page) and useInfiniteList (useInfiniteQuery of @krizaka/query wired to onEndReached). Use it instead of FlatList, ScrollView+map or a direct @shopify/flash-list import.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @krizaka/ui/native/list
|
|
7
|
+
|
|
8
|
+
## Rules
|
|
9
|
+
|
|
10
|
+
1. Import `List` and `useInfiniteList` from `@krizaka/ui/native/list` — not `FlatList`, not `@shopify/flash-list`
|
|
11
|
+
directly. The app installs the optional peers: `@shopify/flash-list` (v2) and `@krizaka/query`.
|
|
12
|
+
2. Server data goes through `@krizaka/query` (never `@tanstack/react-query`): one `KrizakaQueryProvider` at the root.
|
|
13
|
+
3. `keyExtractor` returns an id; `renderItem` stays light (views are recycled); words are passed translated.
|
|
14
|
+
|
|
15
|
+
## Recipes
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
// A paginated API
|
|
19
|
+
const { listProps, error } = useInfiniteList({
|
|
20
|
+
queryKey: notificationKeys.list(),
|
|
21
|
+
queryFn: ({ pageParam, signal }) => krizakaFetch("/api/notifications", { schema: NotificationPage, query: { cursor: pageParam }, signal }),
|
|
22
|
+
initialPageParam: null as string | null,
|
|
23
|
+
getNextPageParam: (last) => last.nextCursor,
|
|
24
|
+
getItems: (page) => page.items,
|
|
25
|
+
});
|
|
26
|
+
return (
|
|
27
|
+
<List label={t.notifications.title} {...listProps} keyExtractor={(n) => n.id} separator="inset"
|
|
28
|
+
renderItem={(n) => <NotificationRow notification={n} />}
|
|
29
|
+
error={error ? <ErrorState title={t.errors.load} action={…} /> : undefined}
|
|
30
|
+
empty={{ title: t.notifications.empty, description: t.notifications.emptyHint }}
|
|
31
|
+
loadingMoreLabel={t.common.loadingMore} />
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Static data
|
|
35
|
+
<List label={t.settings.devices} data={devices} keyExtractor={(d) => d.id} renderItem={(d) => <DeviceRow device={d} />} />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`listProps` = `{ data, loading, refreshing, onRefresh, onEndReached, loadingMore }`: the next page is asked once at a
|
|
39
|
+
time and never past the last; pull to refresh refetches every loaded page.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: krizaka-virtual
|
|
3
|
+
description: Long lists, feeds and galleries in a Krizaka web app with @krizaka/ui/virtual (TanStack Virtual v3 behind the Krizaka facade) — VirtualList (own region or window scroll, measured items), VirtualGrid (responsive columns), infinite loading with @krizaka/query. Use it before rendering more than ~100 items, an infinite feed or a gallery.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @krizaka/ui/virtual
|
|
7
|
+
|
|
8
|
+
## Rules
|
|
9
|
+
|
|
10
|
+
1. Import from `@krizaka/ui/virtual` — **never `@tanstack/react-virtual`**, `react-window` or `react-virtualized`.
|
|
11
|
+
The raw hooks come through the facade: `useVirtualizer`, `useWindowVirtualizer`.
|
|
12
|
+
2. Records compared on columns → `@krizaka/ui/data-table` (`virtualized`), not a list. React Native → `@krizaka/ui/native/list`.
|
|
13
|
+
3. Always `getKey` (an id) and a `label` (translated): it names the focusable scrolling region.
|
|
14
|
+
|
|
15
|
+
## Recipes
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
// Messages of different heights, in their own region
|
|
19
|
+
<VirtualList items={messages} getKey={(m) => m.id} estimateSize={64} gap={8} height={480} label={t.chat.messages}
|
|
20
|
+
renderItem={(m) => <MessageBubble message={m} />} />
|
|
21
|
+
|
|
22
|
+
// A feed that scrolls the page, infinite with @krizaka/query
|
|
23
|
+
const feed = useInfiniteQuery({ ...feedQuery(), meta: { list: true } });
|
|
24
|
+
const posts = useMemo(() => feed.data?.pages.flatMap((p) => p.items) ?? NONE, [feed.data]);
|
|
25
|
+
<VirtualList scroll="window" items={posts} getKey={(p) => p.id} estimateSize={320} label={t.feed.title}
|
|
26
|
+
onEndReached={() => feed.hasNextPage && !feed.isFetchingNextPage && feed.fetchNextPage()}
|
|
27
|
+
footer={feed.isFetchingNextPage ? <Spinner label={t.common.loadingMore} /> : null} renderItem={(p) => <Post post={p} />} />
|
|
28
|
+
|
|
29
|
+
// A gallery: as many columns as fit (or `columns={4}`)
|
|
30
|
+
<VirtualGrid items={videos} getKey={(v) => v.id} estimateRowHeight={260} minItemWidth={220} label={t.explore.videos}
|
|
31
|
+
renderItem={(v) => <VideoCard video={v} />} />
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`ref` gives `scrollToIndex(i, align)` — smooth, or instant under reduced motion. Items are `listitem`s with
|
|
35
|
+
`aria-setsize` / `aria-posinset`.
|
|
File without changes
|
|
File without changes
|