@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.
Files changed (184) hide show
  1. package/README.md +3 -1
  2. package/dist/audio-player.js +1 -1
  3. package/dist/{chunk-EUPTXKH7.js → chunk-BRKMQ6JV.js} +2 -1
  4. package/dist/chunk-FDCMBWUU.js +168 -0
  5. package/dist/chunk-FDCMBWUU.js.map +1 -0
  6. package/dist/chunk-HCNOOPZE.js +210 -0
  7. package/dist/chunk-HCNOOPZE.js.map +1 -0
  8. package/dist/{chunk-X6TW3X6Y.js → chunk-LCZXS6AK.js} +2 -2
  9. package/dist/chunk-OGJI5X4W.js +157 -0
  10. package/dist/chunk-OGJI5X4W.js.map +1 -0
  11. package/dist/combobox.js +2 -2
  12. package/dist/data-table.d.ts +284 -24
  13. package/dist/data-table.js +914 -121
  14. package/dist/data-table.js.map +1 -1
  15. package/dist/date-picker.js +1 -1
  16. package/dist/filter-bar.d.ts +12 -12
  17. package/dist/filter-bar.js +9 -145
  18. package/dist/filter-bar.js.map +1 -1
  19. package/dist/image-cropper.js +1 -1
  20. package/dist/media-capture.js +1 -1
  21. package/dist/native/list.d.ts +95 -0
  22. package/dist/native/list.js +135 -0
  23. package/dist/native/list.js.map +1 -0
  24. package/dist/search-field.js +6 -160
  25. package/dist/search-field.js.map +1 -1
  26. package/dist/tag-input.js +2 -2
  27. package/dist/video-player.js +1 -1
  28. package/dist/video-trimmer.js +1 -1
  29. package/dist/virtual.d.ts +140 -0
  30. package/dist/virtual.js +19 -0
  31. package/dist/virtual.js.map +1 -0
  32. package/package.json +66 -6
  33. package/registry/achievement.json +1 -1
  34. package/registry/action-bar.json +1 -1
  35. package/registry/alert.json +1 -1
  36. package/registry/app-shell.json +1 -1
  37. package/registry/argument-card.json +1 -1
  38. package/registry/audio-player.json +1 -1
  39. package/registry/auth-layout.json +1 -1
  40. package/registry/avatar.json +1 -1
  41. package/registry/badge.json +1 -1
  42. package/registry/button.json +1 -1
  43. package/registry/card-grid.json +1 -1
  44. package/registry/card.json +1 -1
  45. package/registry/catalogue-page.json +1 -1
  46. package/registry/changelog-page.json +1 -1
  47. package/registry/checkbox.json +1 -1
  48. package/registry/chip-link.json +1 -1
  49. package/registry/chip.json +1 -1
  50. package/registry/choice-grid.json +1 -1
  51. package/registry/code-block.json +1 -1
  52. package/registry/combobox.json +1 -1
  53. package/registry/command.json +1 -1
  54. package/registry/component-page.json +1 -1
  55. package/registry/confirm-button.json +1 -1
  56. package/registry/contact-page.json +1 -1
  57. package/registry/continue-prompt.json +1 -1
  58. package/registry/countdown.json +1 -1
  59. package/registry/cta-panel.json +1 -1
  60. package/registry/dashboard-layout.json +1 -1
  61. package/registry/data-table.json +643 -49
  62. package/registry/date-picker.json +1 -1
  63. package/registry/decision-list.json +1 -1
  64. package/registry/detail-layout.json +1 -1
  65. package/registry/dialog.json +1 -1
  66. package/registry/docs-article-page.json +1 -1
  67. package/registry/docs-hub-page.json +1 -1
  68. package/registry/docs-layout.json +1 -1
  69. package/registry/dropdown-menu.json +1 -1
  70. package/registry/empty-state.json +1 -1
  71. package/registry/error-page.json +1 -1
  72. package/registry/examples/data-table/details.d.ts +4 -0
  73. package/registry/examples/data-table/details.js +33 -0
  74. package/registry/examples/data-table/details.tsx +31 -0
  75. package/registry/examples/data-table/filters.d.ts +4 -0
  76. package/registry/examples/data-table/filters.js +40 -0
  77. package/registry/examples/data-table/filters.tsx +40 -0
  78. package/registry/examples/data-table/grouped.d.ts +4 -0
  79. package/registry/examples/data-table/grouped.js +24 -0
  80. package/registry/examples/data-table/grouped.tsx +23 -0
  81. package/registry/examples/data-table/paginated.d.ts +4 -0
  82. package/registry/examples/data-table/paginated.js +23 -0
  83. package/registry/examples/data-table/paginated.tsx +22 -0
  84. package/registry/examples/data-table/pinned.d.ts +4 -0
  85. package/registry/examples/data-table/pinned.js +26 -0
  86. package/registry/examples/data-table/pinned.tsx +25 -0
  87. package/registry/examples/data-table/server.d.ts +4 -0
  88. package/registry/examples/data-table/server.js +40 -0
  89. package/registry/examples/data-table/server.tsx +40 -0
  90. package/registry/examples/data-table/virtualized.js +2 -2
  91. package/registry/examples/data-table/virtualized.tsx +3 -3
  92. package/registry/examples/list/native/default.d.ts +4 -0
  93. package/registry/examples/list/native/default.dark.png +0 -0
  94. package/registry/examples/list/native/default.js +33 -0
  95. package/registry/examples/list/native/default.light.png +0 -0
  96. package/registry/examples/list/native/default.tsx +31 -0
  97. package/registry/examples/list/native/infinite.d.ts +4 -0
  98. package/registry/examples/list/native/infinite.dark.png +0 -0
  99. package/registry/examples/list/native/infinite.js +30 -0
  100. package/registry/examples/list/native/infinite.light.png +0 -0
  101. package/registry/examples/list/native/infinite.tsx +35 -0
  102. package/registry/examples/list/native/states.d.ts +4 -0
  103. package/registry/examples/list/native/states.dark.png +0 -0
  104. package/registry/examples/list/native/states.js +26 -0
  105. package/registry/examples/list/native/states.light.png +0 -0
  106. package/registry/examples/list/native/states.tsx +21 -0
  107. package/registry/examples/virtual/feed.d.ts +4 -0
  108. package/registry/examples/virtual/feed.js +26 -0
  109. package/registry/examples/virtual/feed.tsx +24 -0
  110. package/registry/examples/virtual/gallery.d.ts +4 -0
  111. package/registry/examples/virtual/gallery.js +31 -0
  112. package/registry/examples/virtual/gallery.tsx +28 -0
  113. package/registry/examples/virtual/messages.d.ts +4 -0
  114. package/registry/examples/virtual/messages.js +28 -0
  115. package/registry/examples/virtual/messages.tsx +28 -0
  116. package/registry/field.json +1 -1
  117. package/registry/file-upload.json +1 -1
  118. package/registry/filter-bar.json +1 -1
  119. package/registry/gallery-page.json +1 -1
  120. package/registry/glow-card.json +1 -1
  121. package/registry/goal-gauge.json +1 -1
  122. package/registry/how-it-works-page.json +1 -1
  123. package/registry/image-cropper.json +1 -1
  124. package/registry/index.json +48 -5
  125. package/registry/iso.json +1 -1
  126. package/registry/kbd.json +1 -1
  127. package/registry/landing-page.json +1 -1
  128. package/registry/landscape.json +1 -1
  129. package/registry/legal-page.json +1 -1
  130. package/registry/link-card.json +1 -1
  131. package/registry/list.json +249 -0
  132. package/registry/loader.json +1 -1
  133. package/registry/longform-page.json +1 -1
  134. package/registry/marketing-layout.json +1 -1
  135. package/registry/marquee.json +1 -1
  136. package/registry/mascot-quote.json +1 -1
  137. package/registry/mascot-state.json +1 -1
  138. package/registry/mascots.json +1 -1
  139. package/registry/media-capture.json +1 -1
  140. package/registry/meter.json +1 -1
  141. package/registry/nav-bar.json +1 -1
  142. package/registry/number-ticker.json +1 -1
  143. package/registry/page-header.json +1 -1
  144. package/registry/page-hero.json +1 -1
  145. package/registry/page.json +1 -1
  146. package/registry/pagination.json +1 -1
  147. package/registry/pointer-light.json +1 -1
  148. package/registry/popover.json +1 -1
  149. package/registry/pricing-page.json +1 -1
  150. package/registry/product-page.json +1 -1
  151. package/registry/profile-card.json +1 -1
  152. package/registry/progress.json +1 -1
  153. package/registry/promise-card.json +1 -1
  154. package/registry/radio-group.json +1 -1
  155. package/registry/scroll-stage.json +1 -1
  156. package/registry/search-field.json +1 -1
  157. package/registry/section-backdrop.json +1 -1
  158. package/registry/separator.json +1 -1
  159. package/registry/settings-layout.json +1 -1
  160. package/registry/skeleton.json +1 -1
  161. package/registry/slider.json +1 -1
  162. package/registry/slot.json +1 -1
  163. package/registry/spinner.json +1 -1
  164. package/registry/split-view.json +1 -1
  165. package/registry/stage-banner.json +1 -1
  166. package/registry/stat.json +1 -1
  167. package/registry/status-page.json +1 -1
  168. package/registry/stepper.json +1 -1
  169. package/registry/switch.json +1 -1
  170. package/registry/tabs.json +1 -1
  171. package/registry/tag-input.json +1 -1
  172. package/registry/terminal-replay.json +1 -1
  173. package/registry/theme.json +1 -1
  174. package/registry/toast.json +1 -1
  175. package/registry/toc.json +1 -1
  176. package/registry/tooltip.json +1 -1
  177. package/registry/video-player.json +1 -1
  178. package/registry/video-trimmer.json +1 -1
  179. package/registry/virtual.json +569 -0
  180. package/skills/data-table/SKILL.md +56 -0
  181. package/skills/native-list/SKILL.md +39 -0
  182. package/skills/virtual/SKILL.md +35 -0
  183. /package/dist/{chunk-EUPTXKH7.js.map → chunk-BRKMQ6JV.js.map} +0 -0
  184. /package/dist/{chunk-X6TW3X6Y.js.map → chunk-LCZXS6AK.js.map} +0 -0
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ // registry/examples/data-table/filters.tsx
4
+ import { DataTable, DataTableColumnsMenu, DataTableExport, DataTableFilters } from "@krizaka/ui/data-table";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var videos = Array.from({ length: 36 }, (_, i) => ({
7
+ id: `v${i + 1}`,
8
+ title: ["Sunset over Montr\xE9al", "Behind the scenes", "Studio tour", "Live Q&A replay"][i % 4] + ` #${i + 1}`,
9
+ creator: ["Elena Varga", "Noah Petit", "Maya Chen"][i % 3],
10
+ status: ["Public", "Followers", "Draft"][i % 3 === 2 ? 2 : i % 2],
11
+ views: i * 7919 % 2e4
12
+ }));
13
+ var columns = [
14
+ { id: "title", header: "Title", sortable: true, card: "title", filter: "text" },
15
+ { id: "creator", header: "Creator", filter: "facet" },
16
+ { id: "status", header: "Visibility", filter: "facet" },
17
+ { id: "views", header: "Views", sortable: true, align: "end", filter: "range", cell: (v) => v.views.toLocaleString("en") }
18
+ ];
19
+ function DataTableFiltersExample() {
20
+ return /* @__PURE__ */ jsx(
21
+ DataTable,
22
+ {
23
+ caption: "Videos",
24
+ rows: videos,
25
+ columns,
26
+ getRowId: (v) => v.id,
27
+ defaultPageSize: 8,
28
+ toolbar: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
29
+ /* @__PURE__ */ jsx(DataTableFilters, {}),
30
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
31
+ /* @__PURE__ */ jsx(DataTableColumnsMenu, {}),
32
+ /* @__PURE__ */ jsx(DataTableExport, { filename: "videos.csv" })
33
+ ] })
34
+ ] })
35
+ }
36
+ );
37
+ }
38
+ export {
39
+ DataTableFiltersExample as default
40
+ };
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ import { DataTable, type DataTableColumn, DataTableColumnsMenu, DataTableExport, DataTableFilters } from "@krizaka/ui/data-table";
4
+
5
+ type Video = { id: string; title: string; creator: string; status: string; views: number };
6
+ const videos: Video[] = Array.from({ length: 36 }, (_, i) => ({
7
+ id: `v${i + 1}`,
8
+ title: ["Sunset over Montréal", "Behind the scenes", "Studio tour", "Live Q&A replay"][i % 4]! + ` #${i + 1}`,
9
+ creator: ["Elena Varga", "Noah Petit", "Maya Chen"][i % 3]!,
10
+ status: ["Public", "Followers", "Draft"][i % 3 === 2 ? 2 : i % 2]!,
11
+ views: (i * 7919) % 20_000,
12
+ }));
13
+ const columns: DataTableColumn<Video>[] = [
14
+ { id: "title", header: "Title", sortable: true, card: "title", filter: "text" },
15
+ { id: "creator", header: "Creator", filter: "facet" },
16
+ { id: "status", header: "Visibility", filter: "facet" },
17
+ { id: "views", header: "Views", sortable: true, align: "end", filter: "range", cell: (v) => v.views.toLocaleString("en") },
18
+ ];
19
+
20
+ // A search, facets with their counts, a range, the filters as chips; hide columns, export what is shown.
21
+ export default function DataTableFiltersExample() {
22
+ return (
23
+ <DataTable
24
+ caption="Videos"
25
+ rows={videos}
26
+ columns={columns}
27
+ getRowId={(v) => v.id}
28
+ defaultPageSize={8}
29
+ toolbar={
30
+ <div className="flex flex-col gap-3">
31
+ <DataTableFilters />
32
+ <div className="flex justify-end gap-2">
33
+ <DataTableColumnsMenu />
34
+ <DataTableExport filename="videos.csv" />
35
+ </div>
36
+ </div>
37
+ }
38
+ />
39
+ );
40
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+
3
+ // registry/examples/data-table/grouped.tsx
4
+ import { DataTable } from "@krizaka/ui/data-table";
5
+ import { jsx } from "react/jsx-runtime";
6
+ var tips = [
7
+ { id: "t1", creator: "Elena Varga", fan: "marco_v", cents: 500 },
8
+ { id: "t2", creator: "Elena Varga", fan: "ana.lu", cents: 1500 },
9
+ { id: "t3", creator: "Noah Petit", fan: "kenji", cents: 300 },
10
+ { id: "t4", creator: "Maya Chen", fan: "marco_v", cents: 2e3 },
11
+ { id: "t5", creator: "Noah Petit", fan: "zoe", cents: 700 }
12
+ ];
13
+ var money = (cents) => (cents / 100).toLocaleString("en", { style: "currency", currency: "USD" });
14
+ var columns = [
15
+ { id: "creator", header: "Creator", groupable: true, card: "title" },
16
+ { id: "fan", header: "From" },
17
+ { id: "cents", header: "Amount", align: "end", cell: (t) => money(t.cents), aggregate: (rows) => money(rows.reduce((sum, t) => sum + t.cents, 0)) }
18
+ ];
19
+ function DataTableGrouped() {
20
+ return /* @__PURE__ */ jsx(DataTable, { caption: "Tips this week", rows: tips, columns, getRowId: (t) => t.id, defaultGroupBy: ["creator"], defaultExpanded: { "creator:Elena Varga": true } });
21
+ }
22
+ export {
23
+ DataTableGrouped as default
24
+ };
@@ -0,0 +1,23 @@
1
+ "use client";
2
+
3
+ import { DataTable, type DataTableColumn } from "@krizaka/ui/data-table";
4
+
5
+ type Tip = { id: string; creator: string; fan: string; cents: number };
6
+ const tips: Tip[] = [
7
+ { id: "t1", creator: "Elena Varga", fan: "marco_v", cents: 500 },
8
+ { id: "t2", creator: "Elena Varga", fan: "ana.lu", cents: 1500 },
9
+ { id: "t3", creator: "Noah Petit", fan: "kenji", cents: 300 },
10
+ { id: "t4", creator: "Maya Chen", fan: "marco_v", cents: 2000 },
11
+ { id: "t5", creator: "Noah Petit", fan: "zoe", cents: 700 },
12
+ ];
13
+ const money = (cents: number) => (cents / 100).toLocaleString("en", { style: "currency", currency: "USD" });
14
+ const columns: DataTableColumn<Tip>[] = [
15
+ { id: "creator", header: "Creator", groupable: true, card: "title" },
16
+ { id: "fan", header: "From" },
17
+ { id: "cents", header: "Amount", align: "end", cell: (t) => money(t.cents), aggregate: (rows) => money(rows.reduce((sum, t) => sum + t.cents, 0)) },
18
+ ];
19
+
20
+ // Grouped by creator: a row per group with its count and its total, opened to see the tips.
21
+ export default function DataTableGrouped() {
22
+ return <DataTable caption="Tips this week" rows={tips} columns={columns} getRowId={(t) => t.id} defaultGroupBy={["creator"]} defaultExpanded={{ "creator:Elena Varga": true }} />;
23
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,23 @@
1
+ "use client";
2
+
3
+ // registry/examples/data-table/paginated.tsx
4
+ import { DataTable } from "@krizaka/ui/data-table";
5
+ import { jsx } from "react/jsx-runtime";
6
+ var invoices = Array.from({ length: 87 }, (_, i) => ({
7
+ id: `INV-2026-${String(i + 1).padStart(4, "0")}`,
8
+ customer: ["Atelier Lumen", "Northwind Studio", "Caf\xE9 Br\xFBl\xE9", "Kite & Co"][i % 4],
9
+ issued: `2026-${String(1 + i % 9).padStart(2, "0")}-${String(1 + i % 27).padStart(2, "0")}`,
10
+ total: i * 4111 % 12e4 / 100
11
+ }));
12
+ var columns = [
13
+ { id: "id", header: "Invoice", sortable: true, card: "title" },
14
+ { id: "customer", header: "Customer", sortable: true },
15
+ { id: "issued", header: "Issued", sortable: true },
16
+ { id: "total", header: "Total", sortable: true, align: "end", cell: (r) => `\u20AC${r.total.toFixed(2)}` }
17
+ ];
18
+ function DataTablePaginated() {
19
+ return /* @__PURE__ */ jsx(DataTable, { caption: "Invoices", rows: invoices, columns, getRowId: (r) => r.id, defaultPageSize: 10, pageSizeOptions: [10, 25, 50] });
20
+ }
21
+ export {
22
+ DataTablePaginated as default
23
+ };
@@ -0,0 +1,22 @@
1
+ "use client";
2
+
3
+ import { DataTable, type DataTableColumn } from "@krizaka/ui/data-table";
4
+
5
+ type Invoice = { id: string; customer: string; issued: string; total: number };
6
+ const invoices: Invoice[] = Array.from({ length: 87 }, (_, i) => ({
7
+ id: `INV-2026-${String(i + 1).padStart(4, "0")}`,
8
+ customer: ["Atelier Lumen", "Northwind Studio", "Café Brûlé", "Kite & Co"][i % 4]!,
9
+ issued: `2026-${String(1 + (i % 9)).padStart(2, "0")}-${String(1 + (i % 27)).padStart(2, "0")}`,
10
+ total: ((i * 4111) % 120_000) / 100,
11
+ }));
12
+ const columns: DataTableColumn<Invoice>[] = [
13
+ { id: "id", header: "Invoice", sortable: true, card: "title" },
14
+ { id: "customer", header: "Customer", sortable: true },
15
+ { id: "issued", header: "Issued", sortable: true },
16
+ { id: "total", header: "Total", sortable: true, align: "end", cell: (r) => `€${r.total.toFixed(2)}` },
17
+ ];
18
+
19
+ // Pages in the browser: the pagination under the table, the rows per page to choose; a sort goes back to page 1.
20
+ export default function DataTablePaginated() {
21
+ return <DataTable caption="Invoices" rows={invoices} columns={columns} getRowId={(r) => r.id} defaultPageSize={10} pageSizeOptions={[10, 25, 50]} />;
22
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,26 @@
1
+ "use client";
2
+
3
+ // registry/examples/data-table/pinned.tsx
4
+ import { DataTable } from "@krizaka/ui/data-table";
5
+ import { jsx } from "react/jsx-runtime";
6
+ var models = [
7
+ { id: "m1", name: "Llama 3.3 70B", provider: "Self-hosted", input: 0.23, output: 0.4, context: 128, latency: 420, region: "eu-west" },
8
+ { id: "m2", name: "Mistral Large", provider: "Mistral", input: 2, output: 6, context: 128, latency: 380, region: "eu-west" },
9
+ { id: "m3", name: "Qwen 2.5 Coder", provider: "Self-hosted", input: 0.12, output: 0.2, context: 32, latency: 210, region: "eu-central" }
10
+ ];
11
+ var usd = (n) => `$${n.toFixed(2)}`;
12
+ var columns = [
13
+ { id: "name", header: "Model", width: 180, card: "title" },
14
+ { id: "provider", header: "Provider", width: 140 },
15
+ { id: "input", header: "Input / 1M", width: 130, align: "end", cell: (m) => usd(m.input) },
16
+ { id: "output", header: "Output / 1M", width: 130, align: "end", cell: (m) => usd(m.output) },
17
+ { id: "context", header: "Context", width: 110, align: "end", cell: (m) => `${m.context}k` },
18
+ { id: "latency", header: "Latency", width: 110, align: "end", cell: (m) => `${m.latency} ms` },
19
+ { id: "region", header: "Region", width: 130 }
20
+ ];
21
+ function DataTablePinned() {
22
+ return /* @__PURE__ */ jsx(DataTable, { caption: "Model pricing", rows: models, columns, getRowId: (m) => m.id, pinning: { start: ["name"] }, resizing: true, layout: "table" });
23
+ }
24
+ export {
25
+ DataTablePinned as default
26
+ };
@@ -0,0 +1,25 @@
1
+ "use client";
2
+
3
+ import { DataTable, type DataTableColumn } from "@krizaka/ui/data-table";
4
+
5
+ type Model = { id: string; name: string; provider: string; input: number; output: number; context: number; latency: number; region: string };
6
+ const models: Model[] = [
7
+ { id: "m1", name: "Llama 3.3 70B", provider: "Self-hosted", input: 0.23, output: 0.4, context: 128, latency: 420, region: "eu-west" },
8
+ { id: "m2", name: "Mistral Large", provider: "Mistral", input: 2, output: 6, context: 128, latency: 380, region: "eu-west" },
9
+ { id: "m3", name: "Qwen 2.5 Coder", provider: "Self-hosted", input: 0.12, output: 0.2, context: 32, latency: 210, region: "eu-central" },
10
+ ];
11
+ const usd = (n: number) => `$${n.toFixed(2)}`;
12
+ const columns: DataTableColumn<Model>[] = [
13
+ { id: "name", header: "Model", width: 180, card: "title" },
14
+ { id: "provider", header: "Provider", width: 140 },
15
+ { id: "input", header: "Input / 1M", width: 130, align: "end", cell: (m) => usd(m.input) },
16
+ { id: "output", header: "Output / 1M", width: 130, align: "end", cell: (m) => usd(m.output) },
17
+ { id: "context", header: "Context", width: 110, align: "end", cell: (m) => `${m.context}k` },
18
+ { id: "latency", header: "Latency", width: 110, align: "end", cell: (m) => `${m.latency} ms` },
19
+ { id: "region", header: "Region", width: 130 },
20
+ ];
21
+
22
+ // A wide table: the name stays at the start while it scrolls sideways; drag (or ← →) a header's edge to resize.
23
+ export default function DataTablePinned() {
24
+ return <DataTable caption="Model pricing" rows={models} columns={columns} getRowId={(m) => m.id} pinning={{ start: ["name"] }} resizing layout="table" />;
25
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ // registry/examples/data-table/server.tsx
4
+ import { configureKrizakaFetch, defineKeys, keepPreviousData, krizakaFetch, KrizakaQueryProvider, useQuery } from "@krizaka/query";
5
+ import { DataTable, DataTableFilters } from "@krizaka/ui/data-table";
6
+ import { useState } from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var ALL = Array.from({ length: 240 }, (_, i) => ({ id: `po-${1e3 + i}`, creator: ["Elena Varga", "Noah Petit", "Maya Chen"][i % 3], status: ["paid", "pending", "failed"][i % 4 % 3], amount: i * 7919 % 9e4 / 100 }));
9
+ async function fakeApi(input) {
10
+ const q = new URL(String(input), "https://api.example").searchParams;
11
+ const [by, dir] = (q.get("sort") ?? "id:ascending").split(":");
12
+ const rows = ALL.filter((p) => !q.get("status") || q.get("status").split(",").includes(p.status)).sort((a, b) => (a[by] > b[by] ? 1 : -1) * (dir === "descending" ? -1 : 1));
13
+ const [page, size] = [Number(q.get("page")), Number(q.get("size"))];
14
+ return Response.json({ rows: rows.slice((page - 1) * size, page * size), total: rows.length });
15
+ }
16
+ var payoutKeys = defineKeys("payouts", { list: (query) => [query] });
17
+ var columns = [
18
+ { id: "id", header: "Payout", sortable: true, card: "title" },
19
+ { id: "creator", header: "Creator", sortable: true },
20
+ { id: "status", header: "Status", filter: "facet", options: [{ value: "paid", label: "Paid" }, { value: "pending", label: "Pending" }, { value: "failed", label: "Failed" }] },
21
+ { id: "amount", header: "Amount", sortable: true, align: "end", cell: (p) => `$${p.amount.toFixed(2)}` }
22
+ ];
23
+ var NONE = [];
24
+ function Payouts() {
25
+ const [query, setQuery] = useState({ sort: null, filters: {}, page: 1, pageSize: 10 });
26
+ const { data, isPending, error } = useQuery({
27
+ queryKey: payoutKeys.list(query),
28
+ queryFn: ({ signal }) => krizakaFetch("/api/payouts", { signal, query: { sort: query.sort && `${query.sort.column}:${query.sort.direction}`, status: query.filters.status, page: query.page, size: query.pageSize } }),
29
+ placeholderData: keepPreviousData,
30
+ meta: { list: true }
31
+ });
32
+ return /* @__PURE__ */ jsx(DataTable, { caption: "Payouts", rows: data?.rows ?? NONE, columns, getRowId: (p) => p.id, manual: { sorting: true, filtering: true, pagination: true }, rowCount: data?.total, defaultPageSize: 10, onStateChange: setQuery, loading: isPending, error: error?.message, toolbar: /* @__PURE__ */ jsx(DataTableFilters, {}) });
33
+ }
34
+ function DataTableServer() {
35
+ useState(() => configureKrizakaFetch({ fetch: fakeApi }));
36
+ return /* @__PURE__ */ jsx(KrizakaQueryProvider, { children: /* @__PURE__ */ jsx(Payouts, {}) });
37
+ }
38
+ export {
39
+ DataTableServer as default
40
+ };
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ import { configureKrizakaFetch, defineKeys, keepPreviousData, krizakaFetch, KrizakaQueryProvider, useQuery } from "@krizaka/query";
4
+ import { DataTable, type DataTableColumn, DataTableFilters, type DataTableQuery } from "@krizaka/ui/data-table";
5
+ import { useState } from "react";
6
+
7
+ type Payout = { id: string; creator: string; status: string; amount: number };
8
+ const ALL: Payout[] = Array.from({ length: 240 }, (_, i) => ({ id: `po-${1000 + i}`, creator: ["Elena Varga", "Noah Petit", "Maya Chen"][i % 3]!, status: ["paid", "pending", "failed"][i % 4 % 3]!, amount: ((i * 7919) % 90_000) / 100 }));
9
+ // The API, faked in the page: it sorts, filters and pages — the table shows what it answers.
10
+ async function fakeApi(input: RequestInfo | URL) {
11
+ const q = new URL(String(input), "https://api.example").searchParams;
12
+ const [by, dir] = (q.get("sort") ?? "id:ascending").split(":") as [keyof Payout, string];
13
+ const rows = ALL.filter((p) => !q.get("status") || q.get("status")!.split(",").includes(p.status)).sort((a, b) => (a[by] > b[by] ? 1 : -1) * (dir === "descending" ? -1 : 1));
14
+ const [page, size] = [Number(q.get("page")), Number(q.get("size"))];
15
+ return Response.json({ rows: rows.slice((page - 1) * size, page * size), total: rows.length });
16
+ }
17
+ const payoutKeys = defineKeys("payouts", { list: (query: DataTableQuery) => [query] });
18
+ const columns: DataTableColumn<Payout>[] = [
19
+ { id: "id", header: "Payout", sortable: true, card: "title" },
20
+ { id: "creator", header: "Creator", sortable: true },
21
+ { id: "status", header: "Status", filter: "facet", options: [{ value: "paid", label: "Paid" }, { value: "pending", label: "Pending" }, { value: "failed", label: "Failed" }] },
22
+ { id: "amount", header: "Amount", sortable: true, align: "end", cell: (p) => `$${p.amount.toFixed(2)}` },
23
+ ];
24
+ const NONE: Payout[] = [];
25
+ function Payouts() {
26
+ const [query, setQuery] = useState<DataTableQuery>({ sort: null, filters: {}, page: 1, pageSize: 10 });
27
+ const { data, isPending, error } = useQuery({
28
+ queryKey: payoutKeys.list(query),
29
+ queryFn: ({ signal }) => krizakaFetch("/api/payouts", { signal, query: { sort: query.sort && `${query.sort.column}:${query.sort.direction}`, status: query.filters.status as string[] | undefined, page: query.page, size: query.pageSize } }) as Promise<{ rows: Payout[]; total: number }>,
30
+ placeholderData: keepPreviousData,
31
+ meta: { list: true },
32
+ });
33
+ return <DataTable caption="Payouts" rows={data?.rows ?? NONE} columns={columns} getRowId={(p) => p.id} manual={{ sorting: true, filtering: true, pagination: true }} rowCount={data?.total} defaultPageSize={10} onStateChange={setQuery} loading={isPending} error={error?.message} toolbar={<DataTableFilters />} />;
34
+ }
35
+
36
+ // Server mode: sort, filters and page go to the API (krizakaFetch, keys from defineKeys); the previous page stays while the next loads.
37
+ export default function DataTableServer() {
38
+ useState(() => configureKrizakaFetch({ fetch: fakeApi as typeof fetch }));
39
+ return <KrizakaQueryProvider><Payouts /></KrizakaQueryProvider>;
40
+ }
@@ -3,7 +3,7 @@
3
3
  // registry/examples/data-table/virtualized.tsx
4
4
  import { DataTable } from "@krizaka/ui/data-table";
5
5
  import { jsx } from "react/jsx-runtime";
6
- var events = Array.from({ length: 5e3 }, (_, i) => ({
6
+ var events = Array.from({ length: 5e4 }, (_, i) => ({
7
7
  id: `evt-${i + 1}`,
8
8
  kind: ["view", "tip", "follow", "comment"][i % 4],
9
9
  at: `2026-10-${String(1 + i % 11).padStart(2, "0")} ${String(i % 24).padStart(2, "0")}:00`
@@ -14,7 +14,7 @@ var columns = [
14
14
  { id: "at", header: "At", align: "end" }
15
15
  ];
16
16
  function DataTableVirtualized() {
17
- return /* @__PURE__ */ jsx(DataTable, { caption: "Events", rows: events, columns, getRowId: (e) => e.id, virtualize: { rowHeight: 44, height: 320 }, density: "compact" });
17
+ return /* @__PURE__ */ jsx(DataTable, { caption: "Events", rows: events, columns, getRowId: (e) => e.id, virtualized: { height: 320, estimateRowHeight: 37 }, density: "compact" });
18
18
  }
19
19
  export {
20
20
  DataTableVirtualized as default
@@ -3,7 +3,7 @@
3
3
  import { DataTable, type DataTableColumn } from "@krizaka/ui/data-table";
4
4
 
5
5
  type Event = { id: string; kind: string; at: string };
6
- const events: Event[] = Array.from({ length: 5000 }, (_, i) => ({
6
+ const events: Event[] = Array.from({ length: 50_000 }, (_, i) => ({
7
7
  id: `evt-${i + 1}`,
8
8
  kind: ["view", "tip", "follow", "comment"][i % 4]!,
9
9
  at: `2026-10-${String(1 + (i % 11)).padStart(2, "0")} ${String(i % 24).padStart(2, "0")}:00`,
@@ -14,7 +14,7 @@ const columns: DataTableColumn<Event>[] = [
14
14
  { id: "at", header: "At", align: "end" },
15
15
  ];
16
16
 
17
- // 5,000 rows, ~20 rendered: the body scrolls, the header stays.
17
+ // 50,000 rows, ~20 rendered: the body scrolls, the header stays, the sort runs on all of them.
18
18
  export default function DataTableVirtualized() {
19
- return <DataTable caption="Events" rows={events} columns={columns} getRowId={(e) => e.id} virtualize={{ rowHeight: 44, height: 320 }} density="compact" />;
19
+ return <DataTable caption="Events" rows={events} columns={columns} getRowId={(e) => e.id} virtualized={{ height: 320, estimateRowHeight: 37 }} density="compact" />;
20
20
  }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,33 @@
1
+ "use client";
2
+
3
+ // registry/examples/list/native/default.tsx
4
+ import { Avatar, Txt } from "@krizaka/ui/native";
5
+ import { List } from "@krizaka/ui/native/list";
6
+ import { View } from "react-native";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var notifications = [
9
+ { id: "n1", who: "Elena Varga", what: "tipped your video \u201CSunset over Montr\xE9al\u201D", when: "2 min" },
10
+ { id: "n2", who: "Noah Petit", what: "started following you", when: "1 h" },
11
+ { id: "n3", who: "Maya Chen", what: "commented: \u201CThe drone shot!\u201D", when: "3 h" }
12
+ ];
13
+ function NativeListDefault() {
14
+ return /* @__PURE__ */ jsx(
15
+ List,
16
+ {
17
+ label: "Notifications",
18
+ data: notifications,
19
+ keyExtractor: (n) => n.id,
20
+ separator: "inset",
21
+ renderItem: (n) => /* @__PURE__ */ jsxs(View, { style: { flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 16, paddingVertical: 12 }, children: [
22
+ /* @__PURE__ */ jsx(Avatar, { alt: n.who, size: "md" }),
23
+ /* @__PURE__ */ jsxs(View, { style: { flex: 1 }, children: [
24
+ /* @__PURE__ */ jsx(Txt, { children: `${n.who} ${n.what}` }),
25
+ /* @__PURE__ */ jsx(Txt, { variant: "caption", tone: "secondary", children: n.when })
26
+ ] })
27
+ ] })
28
+ }
29
+ );
30
+ }
31
+ export {
32
+ NativeListDefault as default
33
+ };
@@ -0,0 +1,31 @@
1
+ import { Avatar, Txt } from "@krizaka/ui/native";
2
+ import { List } from "@krizaka/ui/native/list";
3
+ import { View } from "react-native";
4
+
5
+ type Notification = { id: string; who: string; what: string; when: string };
6
+ const notifications: Notification[] = [
7
+ { id: "n1", who: "Elena Varga", what: "tipped your video “Sunset over Montréal”", when: "2 min" },
8
+ { id: "n2", who: "Noah Petit", what: "started following you", when: "1 h" },
9
+ { id: "n3", who: "Maya Chen", what: "commented: “The drone shot!”", when: "3 h" },
10
+ ];
11
+
12
+ // A FlashList v2 with the theme's separators, inset after the avatar.
13
+ export default function NativeListDefault() {
14
+ return (
15
+ <List
16
+ label="Notifications"
17
+ data={notifications}
18
+ keyExtractor={(n) => n.id}
19
+ separator="inset"
20
+ renderItem={(n) => (
21
+ <View style={{ flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 16, paddingVertical: 12 }}>
22
+ <Avatar alt={n.who} size="md" />
23
+ <View style={{ flex: 1 }}>
24
+ <Txt>{`${n.who} ${n.what}`}</Txt>
25
+ <Txt variant="caption" tone="secondary">{n.when}</Txt>
26
+ </View>
27
+ </View>
28
+ )}
29
+ />
30
+ );
31
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+
3
+ // registry/examples/list/native/infinite.tsx
4
+ import { configureKrizakaFetch, krizakaFetch, KrizakaQueryProvider } from "@krizaka/query";
5
+ import { Txt } from "@krizaka/ui/native";
6
+ import { List, useInfiniteList } from "@krizaka/ui/native/list";
7
+ import { useState } from "react";
8
+ import { jsx } from "react/jsx-runtime";
9
+ async function fakeApi(input) {
10
+ const cursor = Number(new URL(String(input), "https://api.example").searchParams.get("cursor"));
11
+ const items = Array.from({ length: 20 }, (_, i) => ({ id: `v${cursor + i}`, title: `Video ${cursor + i + 1}` }));
12
+ return Response.json({ items, next: cursor + 20 < 100 ? cursor + 20 : null });
13
+ }
14
+ function Videos() {
15
+ const { listProps, error } = useInfiniteList({
16
+ queryKey: ["videos", "feed"],
17
+ queryFn: ({ pageParam, signal }) => krizakaFetch("/api/videos", { query: { cursor: pageParam }, signal }),
18
+ initialPageParam: 0,
19
+ getNextPageParam: (last) => last.next,
20
+ getItems: (page) => page.items
21
+ });
22
+ return /* @__PURE__ */ jsx(List, { label: "Videos", ...listProps, error: error ? /* @__PURE__ */ jsx(Txt, { children: "Could not load the videos." }) : void 0, keyExtractor: (v) => v.id, renderItem: (v) => /* @__PURE__ */ jsx(Txt, { style: { padding: 16 }, children: v.title }) });
23
+ }
24
+ function NativeListInfinite() {
25
+ useState(() => configureKrizakaFetch({ fetch: fakeApi }));
26
+ return /* @__PURE__ */ jsx(KrizakaQueryProvider, { children: /* @__PURE__ */ jsx(Videos, {}) });
27
+ }
28
+ export {
29
+ NativeListInfinite as default
30
+ };
@@ -0,0 +1,35 @@
1
+ import { configureKrizakaFetch, krizakaFetch, KrizakaQueryProvider } from "@krizaka/query";
2
+ import { Txt } from "@krizaka/ui/native";
3
+ import { List, useInfiniteList } from "@krizaka/ui/native/list";
4
+ import { useState } from "react";
5
+
6
+ type Page = { items: { id: string; title: string }[]; next: number | null };
7
+ // The API, faked in the screen: 20 videos per page, 5 pages.
8
+ async function fakeApi(input: RequestInfo | URL) {
9
+ const cursor = Number(new URL(String(input), "https://api.example").searchParams.get("cursor"));
10
+ const items = Array.from({ length: 20 }, (_, i) => ({ id: `v${cursor + i}`, title: `Video ${cursor + i + 1}` }));
11
+ return Response.json({ items, next: cursor + 20 < 100 ? cursor + 20 : null } satisfies Page);
12
+ }
13
+
14
+ function Videos() {
15
+ const { listProps, error } = useInfiniteList({
16
+ queryKey: ["videos", "feed"],
17
+ queryFn: ({ pageParam, signal }) => krizakaFetch("/api/videos", { query: { cursor: pageParam }, signal }) as Promise<Page>,
18
+ initialPageParam: 0,
19
+ getNextPageParam: (last) => last.next,
20
+ getItems: (page) => page.items,
21
+ });
22
+ return (
23
+ <List label="Videos" {...listProps} error={error ? <Txt>Could not load the videos.</Txt> : undefined} keyExtractor={(v) => v.id} renderItem={(v) => <Txt style={{ padding: 16 }}>{v.title}</Txt>} />
24
+ );
25
+ }
26
+
27
+ // A paginated API as a list: the next page near the end, pull to refresh, the query of @krizaka/query.
28
+ export default function NativeListInfinite() {
29
+ useState(() => configureKrizakaFetch({ fetch: fakeApi as typeof fetch }));
30
+ return (
31
+ <KrizakaQueryProvider>
32
+ <Videos />
33
+ </KrizakaQueryProvider>
34
+ );
35
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,26 @@
1
+ "use client";
2
+
3
+ // registry/examples/list/native/states.tsx
4
+ import { Button } from "@krizaka/ui/native";
5
+ import { List } from "@krizaka/ui/native/list";
6
+ import { View } from "react-native";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var NONE = [];
9
+ function NativeListStates() {
10
+ return /* @__PURE__ */ jsxs(View, { style: { gap: 24, width: "100%" }, children: [
11
+ /* @__PURE__ */ jsx(List, { label: "Messages", data: NONE, keyExtractor: (m) => m.id, renderItem: () => null, loading: true, loadingRows: 3 }),
12
+ /* @__PURE__ */ jsx(
13
+ List,
14
+ {
15
+ label: "Messages",
16
+ data: NONE,
17
+ keyExtractor: (m) => m.id,
18
+ renderItem: () => null,
19
+ empty: { title: "No message yet", description: "Say hello to a creator you follow.", action: /* @__PURE__ */ jsx(Button, { label: "Find creators", size: "sm" }) }
20
+ }
21
+ )
22
+ ] });
23
+ }
24
+ export {
25
+ NativeListStates as default
26
+ };
@@ -0,0 +1,21 @@
1
+ import { Button } from "@krizaka/ui/native";
2
+ import { List } from "@krizaka/ui/native/list";
3
+ import { View } from "react-native";
4
+
5
+ const NONE: { id: string }[] = [];
6
+
7
+ // While the first page loads: skeleton rows. Nothing yet: the empty state and what to do next.
8
+ export default function NativeListStates() {
9
+ return (
10
+ <View style={{ gap: 24, width: "100%" }}>
11
+ <List label="Messages" data={NONE} keyExtractor={(m) => m.id} renderItem={() => null} loading loadingRows={3} />
12
+ <List
13
+ label="Messages"
14
+ data={NONE}
15
+ keyExtractor={(m) => m.id}
16
+ renderItem={() => null}
17
+ empty={{ title: "No message yet", description: "Say hello to a creator you follow.", action: <Button label="Find creators" size="sm" /> }}
18
+ />
19
+ </View>
20
+ );
21
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,26 @@
1
+ "use client";
2
+
3
+ // registry/examples/virtual/feed.tsx
4
+ import { VirtualList } from "@krizaka/ui/virtual";
5
+ import { useState } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ var page = (from) => Array.from({ length: 20 }, (_, i) => ({ id: `p${from + i}`, text: `Post ${from + i + 1}` }));
8
+ function VirtualFeed() {
9
+ const [posts, setPosts] = useState(() => page(0));
10
+ return /* @__PURE__ */ jsx(
11
+ VirtualList,
12
+ {
13
+ items: posts,
14
+ getKey: (p) => p.id,
15
+ estimateSize: 72,
16
+ gap: 8,
17
+ scroll: "window",
18
+ label: "Feed",
19
+ onEndReached: () => setPosts((all) => [...all, ...page(all.length)]),
20
+ renderItem: (p) => /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-border-default bg-surface-1 p-4 text-sm text-fg", children: p.text })
21
+ }
22
+ );
23
+ }
24
+ export {
25
+ VirtualFeed as default
26
+ };