cortena-ui 1.4.2 → 1.5.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 (133) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +149 -1
  3. package/dist/a2ui/views.js +2 -2
  4. package/dist/agent-chat/a2ui-block.d.ts +60 -0
  5. package/dist/agent-chat/a2ui-block.js +69 -0
  6. package/dist/agent-chat/a2ui-block.js.map +1 -0
  7. package/dist/agent-chat/agui-client.d.ts +40 -0
  8. package/dist/agent-chat/agui-client.js +251 -0
  9. package/dist/agent-chat/agui-client.js.map +1 -0
  10. package/dist/agent-chat/bridge.d.ts +109 -0
  11. package/dist/agent-chat/bridge.js +349 -0
  12. package/dist/agent-chat/bridge.js.map +1 -0
  13. package/dist/agent-chat/session.d.ts +58 -0
  14. package/dist/agent-chat/session.js +249 -0
  15. package/dist/agent-chat/session.js.map +1 -0
  16. package/dist/agent-chat/store.d.ts +67 -0
  17. package/dist/agent-chat/store.js +548 -0
  18. package/dist/agent-chat/store.js.map +1 -0
  19. package/dist/agent-chat/types.d.ts +187 -0
  20. package/dist/agent-chat/types.js +17 -0
  21. package/dist/agent-chat/types.js.map +1 -0
  22. package/dist/agent-chat.d.ts +10 -0
  23. package/dist/agent-chat.js +10 -0
  24. package/dist/components/admin-permissions/admin-permissions.d.ts +66 -0
  25. package/dist/components/admin-permissions/admin-permissions.js +101 -0
  26. package/dist/components/admin-permissions/admin-permissions.js.map +1 -0
  27. package/dist/components/admin-permissions/context.d.ts +70 -0
  28. package/dist/components/admin-permissions/context.js +258 -0
  29. package/dist/components/admin-permissions/context.js.map +1 -0
  30. package/dist/components/admin-permissions/index.d.ts +10 -0
  31. package/dist/components/admin-permissions/licence.d.ts +15 -0
  32. package/dist/components/admin-permissions/licence.js +78 -0
  33. package/dist/components/admin-permissions/licence.js.map +1 -0
  34. package/dist/components/admin-permissions/matrix.d.ts +20 -0
  35. package/dist/components/admin-permissions/matrix.js +191 -0
  36. package/dist/components/admin-permissions/matrix.js.map +1 -0
  37. package/dist/components/admin-permissions/members.d.ts +18 -0
  38. package/dist/components/admin-permissions/members.js +185 -0
  39. package/dist/components/admin-permissions/members.js.map +1 -0
  40. package/dist/components/admin-permissions/role-assignment.d.ts +35 -0
  41. package/dist/components/admin-permissions/role-assignment.js +174 -0
  42. package/dist/components/admin-permissions/role-assignment.js.map +1 -0
  43. package/dist/components/admin-permissions/roles.d.ts +25 -0
  44. package/dist/components/admin-permissions/roles.js +168 -0
  45. package/dist/components/admin-permissions/roles.js.map +1 -0
  46. package/dist/components/admin-permissions/types.d.ts +152 -0
  47. package/dist/components/admin-permissions/types.js +63 -0
  48. package/dist/components/admin-permissions/types.js.map +1 -0
  49. package/dist/components/agent-chat-popup.d.ts +29 -0
  50. package/dist/components/agent-chat-popup.js +188 -0
  51. package/dist/components/agent-chat-popup.js.map +1 -0
  52. package/dist/components/agent-chat.d.ts +143 -0
  53. package/dist/components/agent-chat.js +578 -0
  54. package/dist/components/agent-chat.js.map +1 -0
  55. package/dist/components/app-shell.d.ts +126 -0
  56. package/dist/components/app-shell.js +297 -0
  57. package/dist/components/app-shell.js.map +1 -0
  58. package/dist/components/badge.d.ts +1 -1
  59. package/dist/components/button-link.js +1 -1
  60. package/dist/components/button.d.ts +2 -2
  61. package/dist/components/checkbox.d.ts +1 -1
  62. package/dist/components/combobox.d.ts +1 -1
  63. package/dist/components/combobox.js +1 -1
  64. package/dist/components/consent-screen.d.ts +65 -0
  65. package/dist/components/consent-screen.js +123 -0
  66. package/dist/components/consent-screen.js.map +1 -0
  67. package/dist/components/data-table/data-table.d.ts +15 -1
  68. package/dist/components/data-table/data-table.js +18 -4
  69. package/dist/components/data-table/data-table.js.map +1 -1
  70. package/dist/components/data-table/index.d.ts +4 -4
  71. package/dist/components/data-table/parts.d.ts +27 -3
  72. package/dist/components/data-table/parts.js +175 -55
  73. package/dist/components/data-table/parts.js.map +1 -1
  74. package/dist/components/data-table/types.d.ts +61 -0
  75. package/dist/components/data-table/use-data-table.js +91 -6
  76. package/dist/components/data-table/use-data-table.js.map +1 -1
  77. package/dist/components/data-table/use-server-source.js +119 -28
  78. package/dist/components/data-table/use-server-source.js.map +1 -1
  79. package/dist/components/help-panel.d.ts +131 -0
  80. package/dist/components/help-panel.js +545 -0
  81. package/dist/components/help-panel.js.map +1 -0
  82. package/dist/components/login-screen.d.ts +127 -0
  83. package/dist/components/login-screen.js +339 -0
  84. package/dist/components/login-screen.js.map +1 -0
  85. package/dist/components/session-guard.d.ts +268 -0
  86. package/dist/components/session-guard.js +632 -0
  87. package/dist/components/session-guard.js.map +1 -0
  88. package/dist/components/toast.d.ts +1 -1
  89. package/dist/core.d.ts +5 -1
  90. package/dist/core.js +11 -7
  91. package/dist/data-table.d.ts +13 -4
  92. package/dist/data-table.js +10 -2
  93. package/dist/hooks/use-cortena-theme.js +49 -3
  94. package/dist/hooks/use-cortena-theme.js.map +1 -1
  95. package/dist/index.d.ts +17 -4
  96. package/dist/index.js +21 -8
  97. package/dist/markdown.d.ts +2 -1
  98. package/dist/markdown.js +2 -1
  99. package/package.json +16 -4
  100. package/src/agent-chat/a2ui-block.ts +118 -0
  101. package/src/agent-chat/agui-client.ts +405 -0
  102. package/src/agent-chat/bridge.ts +433 -0
  103. package/src/agent-chat/session.ts +392 -0
  104. package/src/agent-chat/store.ts +738 -0
  105. package/src/agent-chat/types.ts +213 -0
  106. package/src/components/admin-permissions/admin-permissions.tsx +130 -0
  107. package/src/components/admin-permissions/context.tsx +376 -0
  108. package/src/components/admin-permissions/index.tsx +32 -0
  109. package/src/components/admin-permissions/licence.tsx +84 -0
  110. package/src/components/admin-permissions/matrix.tsx +257 -0
  111. package/src/components/admin-permissions/members.tsx +204 -0
  112. package/src/components/admin-permissions/role-assignment.tsx +239 -0
  113. package/src/components/admin-permissions/roles.tsx +169 -0
  114. package/src/components/admin-permissions/types.ts +231 -0
  115. package/src/components/agent-chat-popup.tsx +289 -0
  116. package/src/components/agent-chat.tsx +843 -0
  117. package/src/components/app-shell.tsx +502 -0
  118. package/src/components/consent-screen.tsx +239 -0
  119. package/src/components/data-table/data-table.tsx +36 -0
  120. package/src/components/data-table/index.tsx +6 -1
  121. package/src/components/data-table/parts.tsx +223 -47
  122. package/src/components/data-table/types.ts +68 -0
  123. package/src/components/data-table/use-data-table.ts +152 -4
  124. package/src/components/data-table/use-server-source.ts +150 -12
  125. package/src/components/help-panel.tsx +765 -0
  126. package/src/components/login-screen.tsx +479 -0
  127. package/src/components/session-guard.tsx +1071 -0
  128. package/src/entries/agent-chat.ts +113 -0
  129. package/src/entries/core.ts +8 -0
  130. package/src/entries/data-table.ts +41 -0
  131. package/src/entries/markdown.ts +25 -0
  132. package/src/hooks/use-cortena-theme.ts +63 -4
  133. package/src/index.ts +6 -0
@@ -4,8 +4,8 @@ import { cn } from "../lib/cn.js";
4
4
  import { inputClassName } from "./input.js";
5
5
  import { Check, ChevronDown, X } from "lucide-react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
- import { Combobox } from "@base-ui/react/combobox";
8
7
  import { createContext, useContext } from "react";
8
+ import { Combobox } from "@base-ui/react/combobox";
9
9
  //#region src/components/combobox.tsx
10
10
  /**
11
11
  * Combobox: a filterable text input with a listbox popup, on Base UI.
@@ -0,0 +1,65 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ //#region src/components/consent-screen.d.ts
4
+ /**
5
+ * ConsentScreen — the OAuth authorize page an MCP client lands on
6
+ * (how-to-create-a-cortena-extension §7.4, audit rule P-08, decision DESIGN-D1).
7
+ *
8
+ * It is the consent *variant* of the login screen rather than a screen of its
9
+ * own: same frame, same card, same tokens, same brand row. That is the whole
10
+ * requirement. An MCP client opens a browser onto a page nobody chose to visit,
11
+ * and if that page looks like a different product the only honest reading is
12
+ * that something has gone wrong. Sharing `AuthScreen` with `LoginScreen` is
13
+ * what makes the two impossible to drift apart.
14
+ *
15
+ * It replaces the hand-written HTML cortena-auth serves today
16
+ * (`src/routes/oauth-login.ts`, `renderConsent`), and the props are that page's
17
+ * contents: the client asking, the scopes it wants in plain language, who the
18
+ * user is signed in as, and Allow / Deny. Props-only — the flow id, the CSRF
19
+ * binding cookie, the double-submit guard and the redirect all stay on the
20
+ * server, where they already work.
21
+ */
22
+ export interface ConsentClient {
23
+ /** The registered client name — "Claude Code". Never the raw client id. */
24
+ name: string;
25
+ /**
26
+ * The client's own logo, when it registered one. **https only** — the value
27
+ * is a third party's, and this is the screen on which a user decides whether
28
+ * to give that third party access, so `AuthScreen` drops a `data:`, `blob:`
29
+ * or `http:` URL and draws the mark instead (`httpsLogoUrl`).
30
+ */
31
+ logoUrl?: string;
32
+ }
33
+ export interface ConsentScope {
34
+ /** The raw scope string, `task:read`. Shown, small, under the label. */
35
+ id: string;
36
+ /** The plain-language gloss — cortena-auth's `glossFor(scope)`. */
37
+ label: string;
38
+ /** One sentence on what granting it actually allows. */
39
+ description?: string;
40
+ }
41
+ export interface ConsentUser {
42
+ name: string;
43
+ email: string;
44
+ }
45
+ export interface ConsentScreenProps extends Omit<React.ComponentProps<"div">, "onSubmit"> {
46
+ client: ConsentClient;
47
+ /**
48
+ * The requested scopes, already glossed. Rendered in the order given, which
49
+ * is the order cortena-auth resolved them in — not re-sorted here, so the
50
+ * screen and the granted token read the same way.
51
+ */
52
+ scopes: readonly ConsentScope[];
53
+ /** Who is about to grant this. Shown, because consent is personal. */
54
+ user: ConsentUser;
55
+ onAllow?: () => void;
56
+ onDeny?: () => void;
57
+ /** Disables both decisions and marks Allow busy. One decision per page. */
58
+ loading?: boolean;
59
+ /** A failed decision, in the user's words. */
60
+ error?: string;
61
+ }
62
+ declare function ConsentScreen({ className, client, scopes, user, onAllow, onDeny, loading, error, ...props }: ConsentScreenProps): React.JSX.Element;
63
+ //#endregion
64
+ export { ConsentScreen };
65
+ //# sourceMappingURL=consent-screen.d.ts.map
@@ -0,0 +1,123 @@
1
+ "use client";
2
+ "use client";
3
+ import { cn } from "../lib/cn.js";
4
+ import { Alert, AlertDescription } from "./alert.js";
5
+ import { Button } from "./button.js";
6
+ import { Spinner } from "./spinner.js";
7
+ import { AuthScreen } from "./login-screen.js";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/components/consent-screen.tsx
10
+ function ConsentScreen({ className, client, scopes, user, onAllow, onDeny, loading, error, ...props }) {
11
+ return /* @__PURE__ */ jsxs(AuthScreen, {
12
+ "data-slot": "consent-screen",
13
+ "data-loading": loading ? "" : void 0,
14
+ className,
15
+ brand: {
16
+ name: client.name,
17
+ logoUrl: client.logoUrl
18
+ },
19
+ title: `${client.name} wants access`,
20
+ subtitle: "Review what it is asking for before you allow it.",
21
+ notices: error ? /* @__PURE__ */ jsx(Alert, {
22
+ variant: "destructive",
23
+ "data-slot": "consent-screen-error",
24
+ children: /* @__PURE__ */ jsx(AlertDescription, {
25
+ className: "text-[color:var(--ds-foreground)]",
26
+ children: error
27
+ })
28
+ }) : null,
29
+ footer: /* @__PURE__ */ jsx("span", {
30
+ "data-slot": "consent-screen-footer",
31
+ children: "You can revoke this access at any time from your Cortena settings."
32
+ }),
33
+ ...props,
34
+ children: [
35
+ /* @__PURE__ */ jsxs("div", {
36
+ "data-slot": "consent-screen-user",
37
+ className: cn("flex flex-col gap-0.5 rounded-[var(--ds-radius-md)] bg-[var(--ds-muted)] px-3.5 py-3", "text-[length:var(--ds-text-caption-lg)]", "leading-[var(--ds-text-caption-lg--line-height)]"),
38
+ children: [/* @__PURE__ */ jsxs("span", {
39
+ className: "font-medium text-[color:var(--ds-foreground)]",
40
+ children: ["Signed in as ", user.name]
41
+ }), /* @__PURE__ */ jsx("span", {
42
+ className: "text-[color:var(--ds-muted-foreground)]",
43
+ children: user.email
44
+ })]
45
+ }),
46
+ /* @__PURE__ */ jsxs("div", {
47
+ "data-slot": "consent-screen-scopes",
48
+ className: "flex flex-col gap-2",
49
+ children: [/* @__PURE__ */ jsxs("p", {
50
+ className: cn("text-[length:var(--ds-text-caption)]", "leading-[var(--ds-text-caption--line-height)]", "text-[color:var(--ds-muted-foreground)]"),
51
+ children: [client.name, " will be able to:"]
52
+ }), scopes.length === 0 ? /* @__PURE__ */ jsx("p", {
53
+ "data-slot": "consent-screen-no-scopes",
54
+ className: cn("text-[length:var(--ds-text-caption-lg)]", "leading-[var(--ds-text-caption-lg--line-height)]", "text-[color:var(--ds-muted-foreground)]"),
55
+ children: "Nothing beyond confirming who you are."
56
+ }) : /* @__PURE__ */ jsx("ul", {
57
+ className: "flex list-none flex-col gap-2.5 p-0",
58
+ children: scopes.map((scope) => /* @__PURE__ */ jsxs("li", {
59
+ "data-slot": "consent-scope",
60
+ "data-scope": scope.id,
61
+ className: "flex gap-2.5",
62
+ children: [/* @__PURE__ */ jsx(CheckGlyph, {}), /* @__PURE__ */ jsxs("span", {
63
+ className: "flex min-w-0 flex-col gap-0.5",
64
+ children: [
65
+ /* @__PURE__ */ jsx("span", {
66
+ className: cn("font-medium text-[length:var(--ds-text-caption-lg)]", "leading-[var(--ds-text-caption-lg--line-height)]", "text-[color:var(--ds-foreground)]"),
67
+ children: scope.label
68
+ }),
69
+ scope.description ? /* @__PURE__ */ jsx("span", {
70
+ className: cn("text-[length:var(--ds-text-caption)]", "leading-[var(--ds-text-caption--line-height)]", "text-[color:var(--ds-muted-foreground)]"),
71
+ children: scope.description
72
+ }) : null,
73
+ /* @__PURE__ */ jsx("span", {
74
+ className: cn("font-mono text-[length:var(--ds-text-caption-sm)]", "text-[color:var(--ds-text-tertiary)]"),
75
+ children: scope.id
76
+ })
77
+ ]
78
+ })]
79
+ }, scope.id))
80
+ })]
81
+ }),
82
+ /* @__PURE__ */ jsxs("div", {
83
+ "data-slot": "consent-screen-actions",
84
+ className: "flex flex-col gap-2.5",
85
+ children: [/* @__PURE__ */ jsxs(Button, {
86
+ type: "button",
87
+ size: "lg",
88
+ disabled: loading,
89
+ "data-decision": "allow",
90
+ onClick: onAllow,
91
+ children: [loading ? /* @__PURE__ */ jsx(Spinner, { tone: "inverse" }) : null, loading ? "Allowing…" : "Allow"]
92
+ }), /* @__PURE__ */ jsx(Button, {
93
+ type: "button",
94
+ variant: "secondary",
95
+ size: "lg",
96
+ disabled: loading,
97
+ "data-decision": "deny",
98
+ onClick: onDeny,
99
+ children: "Deny"
100
+ })]
101
+ })
102
+ ]
103
+ });
104
+ }
105
+ /** The scope bullet. Inline rather than a lucide import: one icon, one size. */
106
+ function CheckGlyph() {
107
+ return /* @__PURE__ */ jsx("svg", {
108
+ viewBox: "0 0 24 24",
109
+ fill: "none",
110
+ stroke: "currentColor",
111
+ strokeWidth: "2",
112
+ strokeLinecap: "round",
113
+ strokeLinejoin: "round",
114
+ "aria-hidden": true,
115
+ focusable: "false",
116
+ className: "mt-0.5 size-4 shrink-0 text-[color:var(--ds-primary)]",
117
+ children: /* @__PURE__ */ jsx("path", { d: "m4 12.5 5 5L20 6.5" })
118
+ });
119
+ }
120
+ //#endregion
121
+ export { ConsentScreen };
122
+
123
+ //# sourceMappingURL=consent-screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-screen.js","names":[],"sources":["../../src/components/consent-screen.tsx"],"sourcesContent":["\"use client\";\n\nimport type * as React from \"react\";\nimport { Alert, AlertDescription } from \"@/components/alert\";\nimport { Button } from \"@/components/button\";\nimport { AuthScreen } from \"@/components/login-screen\";\nimport { Spinner } from \"@/components/spinner\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * ConsentScreen — the OAuth authorize page an MCP client lands on\n * (how-to-create-a-cortena-extension §7.4, audit rule P-08, decision DESIGN-D1).\n *\n * It is the consent *variant* of the login screen rather than a screen of its\n * own: same frame, same card, same tokens, same brand row. That is the whole\n * requirement. An MCP client opens a browser onto a page nobody chose to visit,\n * and if that page looks like a different product the only honest reading is\n * that something has gone wrong. Sharing `AuthScreen` with `LoginScreen` is\n * what makes the two impossible to drift apart.\n *\n * It replaces the hand-written HTML cortena-auth serves today\n * (`src/routes/oauth-login.ts`, `renderConsent`), and the props are that page's\n * contents: the client asking, the scopes it wants in plain language, who the\n * user is signed in as, and Allow / Deny. Props-only — the flow id, the CSRF\n * binding cookie, the double-submit guard and the redirect all stay on the\n * server, where they already work.\n */\n\nexport interface ConsentClient {\n /** The registered client name — \"Claude Code\". Never the raw client id. */\n name: string;\n /**\n * The client's own logo, when it registered one. **https only** — the value\n * is a third party's, and this is the screen on which a user decides whether\n * to give that third party access, so `AuthScreen` drops a `data:`, `blob:`\n * or `http:` URL and draws the mark instead (`httpsLogoUrl`).\n */\n logoUrl?: string;\n}\n\nexport interface ConsentScope {\n /** The raw scope string, `task:read`. Shown, small, under the label. */\n id: string;\n /** The plain-language gloss — cortena-auth's `glossFor(scope)`. */\n label: string;\n /** One sentence on what granting it actually allows. */\n description?: string;\n}\n\nexport interface ConsentUser {\n name: string;\n email: string;\n}\n\nexport interface ConsentScreenProps extends Omit<React.ComponentProps<\"div\">, \"onSubmit\"> {\n client: ConsentClient;\n /**\n * The requested scopes, already glossed. Rendered in the order given, which\n * is the order cortena-auth resolved them in — not re-sorted here, so the\n * screen and the granted token read the same way.\n */\n scopes: readonly ConsentScope[];\n /** Who is about to grant this. Shown, because consent is personal. */\n user: ConsentUser;\n onAllow?: () => void;\n onDeny?: () => void;\n /** Disables both decisions and marks Allow busy. One decision per page. */\n loading?: boolean;\n /** A failed decision, in the user's words. */\n error?: string;\n}\n\nfunction ConsentScreen({\n className,\n client,\n scopes,\n user,\n onAllow,\n onDeny,\n loading,\n error,\n ...props\n}: ConsentScreenProps) {\n return (\n <AuthScreen\n data-slot=\"consent-screen\"\n data-loading={loading ? \"\" : undefined}\n className={className}\n brand={{ name: client.name, logoUrl: client.logoUrl }}\n title={`${client.name} wants access`}\n subtitle=\"Review what it is asking for before you allow it.\"\n notices={\n error ? (\n <Alert variant=\"destructive\" data-slot=\"consent-screen-error\">\n <AlertDescription className=\"text-[color:var(--ds-foreground)]\">\n {error}\n </AlertDescription>\n </Alert>\n ) : null\n }\n footer={\n <span data-slot=\"consent-screen-footer\">\n You can revoke this access at any time from your Cortena settings.\n </span>\n }\n {...props}\n >\n <div\n data-slot=\"consent-screen-user\"\n className={cn(\n \"flex flex-col gap-0.5 rounded-[var(--ds-radius-md)] bg-[var(--ds-muted)] px-3.5 py-3\",\n \"text-[length:var(--ds-text-caption-lg)]\",\n \"leading-[var(--ds-text-caption-lg--line-height)]\",\n )}\n >\n <span className=\"font-medium text-[color:var(--ds-foreground)]\">\n Signed in as {user.name}\n </span>\n <span className=\"text-[color:var(--ds-muted-foreground)]\">{user.email}</span>\n </div>\n\n <div data-slot=\"consent-screen-scopes\" className=\"flex flex-col gap-2\">\n <p\n className={cn(\n \"text-[length:var(--ds-text-caption)]\",\n \"leading-[var(--ds-text-caption--line-height)]\",\n \"text-[color:var(--ds-muted-foreground)]\",\n )}\n >\n {client.name} will be able to:\n </p>\n {/* An empty list is a real state: a client can ask for no scopes at\n all, and saying so is better than an empty box the user has to\n interpret. */}\n {scopes.length === 0 ? (\n <p\n data-slot=\"consent-screen-no-scopes\"\n className={cn(\n \"text-[length:var(--ds-text-caption-lg)]\",\n \"leading-[var(--ds-text-caption-lg--line-height)]\",\n \"text-[color:var(--ds-muted-foreground)]\",\n )}\n >\n Nothing beyond confirming who you are.\n </p>\n ) : (\n <ul className=\"flex list-none flex-col gap-2.5 p-0\">\n {scopes.map((scope) => (\n <li\n key={scope.id}\n data-slot=\"consent-scope\"\n data-scope={scope.id}\n className=\"flex gap-2.5\"\n >\n <CheckGlyph />\n <span className=\"flex min-w-0 flex-col gap-0.5\">\n <span\n className={cn(\n \"font-medium text-[length:var(--ds-text-caption-lg)]\",\n \"leading-[var(--ds-text-caption-lg--line-height)]\",\n \"text-[color:var(--ds-foreground)]\",\n )}\n >\n {scope.label}\n </span>\n {scope.description ? (\n <span\n className={cn(\n \"text-[length:var(--ds-text-caption)]\",\n \"leading-[var(--ds-text-caption--line-height)]\",\n \"text-[color:var(--ds-muted-foreground)]\",\n )}\n >\n {scope.description}\n </span>\n ) : null}\n <span\n className={cn(\n \"font-mono text-[length:var(--ds-text-caption-sm)]\",\n \"text-[color:var(--ds-text-tertiary)]\",\n )}\n >\n {scope.id}\n </span>\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {/* Allow first and filled, Deny second and quiet — but both are real\n buttons of the same size, so declining is never the harder click. */}\n <div data-slot=\"consent-screen-actions\" className=\"flex flex-col gap-2.5\">\n <Button\n type=\"button\"\n size=\"lg\"\n disabled={loading}\n data-decision=\"allow\"\n onClick={onAllow}\n >\n {loading ? <Spinner tone=\"inverse\" /> : null}\n {loading ? \"Allowing…\" : \"Allow\"}\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"lg\"\n disabled={loading}\n data-decision=\"deny\"\n onClick={onDeny}\n >\n Deny\n </Button>\n </div>\n </AuthScreen>\n );\n}\n\n/** The scope bullet. Inline rather than a lucide import: one icon, one size. */\nfunction CheckGlyph() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n focusable=\"false\"\n className=\"mt-0.5 size-4 shrink-0 text-[color:var(--ds-primary)]\"\n >\n <path d=\"m4 12.5 5 5L20 6.5\" />\n </svg>\n );\n}\n\nexport { ConsentScreen };\n"],"mappings":";;;;;;;;;AAwEA,SAAS,cAAc,EACrB,WACA,QACA,QACA,MACA,SACA,QACA,SACA,OACA,GAAG,SACkB;CACrB,OACE,qBAAC,YAAD;EACE,aAAU;EACV,gBAAc,UAAU,KAAK,KAAA;EAClB;EACX,OAAO;GAAE,MAAM,OAAO;GAAM,SAAS,OAAO;EAAQ;EACpD,OAAO,GAAG,OAAO,KAAK;EACtB,UAAS;EACT,SACE,QACE,oBAAC,OAAD;GAAO,SAAQ;GAAc,aAAU;GACrC,UAAA,oBAAC,kBAAD;IAAkB,WAAU;IACzB,UAAA;GACe,CAAA;EACb,CAAA,IACL;EAEN,QACE,oBAAC,QAAD;GAAM,aAAU;GAAwB,UAAA;EAElC,CAAA;EAER,GAAI;EArBN,UAAA;GAuBE,qBAAC,OAAD;IACE,aAAU;IACV,WAAW,GACT,wFACA,2CACA,kDACF;IANF,UAAA,CAQE,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CAAgE,iBAChD,KAAK,IACf;IACN,CAAA,GAAA,oBAAC,QAAD;KAAM,WAAU;KAA2C,UAAA,KAAK;IAAY,CAAA,CACzE;;GAEL,qBAAC,OAAD;IAAK,aAAU;IAAwB,WAAU;IAAjD,UAAA,CACE,qBAAC,KAAD;KACE,WAAW,GACT,wCACA,iDACA,yCACF;KALF,UAAA,CAOG,OAAO,MAAK,mBACZ;IAIF,CAAA,GAAA,OAAO,WAAW,IACjB,oBAAC,KAAD;KACE,aAAU;KACV,WAAW,GACT,2CACA,oDACA,yCACF;KACD,UAAA;IAEE,CAAA,IAEH,oBAAC,MAAD;KAAI,WAAU;KACX,UAAA,OAAO,KAAK,UACX,qBAAC,MAAD;MAEE,aAAU;MACV,cAAY,MAAM;MAClB,WAAU;MAJZ,UAAA,CAME,oBAAC,YAAD,CAAa,CAAA,GACb,qBAAC,QAAD;OAAM,WAAU;OAAhB,UAAA;QACE,oBAAC,QAAD;SACE,WAAW,GACT,uDACA,oDACA,mCACF;SAEC,UAAA,MAAM;QACH,CAAA;QACL,MAAM,cACL,oBAAC,QAAD;SACE,WAAW,GACT,wCACA,iDACA,yCACF;SAEC,UAAA,MAAM;QACH,CAAA,IACJ;QACJ,oBAAC,QAAD;SACE,WAAW,GACT,qDACA,sCACF;SAEC,UAAA,MAAM;QACH,CAAA;OACF;MACJ,CAAA,CAAA;KApCG,GAAA,MAAM,EAoCT,CACL;IACC,CAAA,CAEH;;GAIL,qBAAC,OAAD;IAAK,aAAU;IAAyB,WAAU;IAAlD,UAAA,CACE,qBAAC,QAAD;KACE,MAAK;KACL,MAAK;KACL,UAAU;KACV,iBAAc;KACd,SAAS;KALX,UAAA,CAOG,UAAU,oBAAC,SAAD,EAAS,MAAK,UAAW,CAAA,IAAI,MACvC,UAAU,cAAc,OACnB;IACR,CAAA,GAAA,oBAAC,QAAD;KACE,MAAK;KACL,SAAQ;KACR,MAAK;KACL,UAAU;KACV,iBAAc;KACd,SAAS;KACV,UAAA;IAEO,CAAA,CACL;;EACK;;AAEhB;;AAGA,SAAS,aAAa;CACpB,OACE,oBAAC,OAAD;EACE,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAY;EACZ,eAAc;EACd,gBAAe;EACf,eAAA;EACA,WAAU;EACV,WAAU;EAEV,UAAA,oBAAC,QAAD,EAAM,GAAE,qBAAsB,CAAA;CAC3B,CAAA;AAET"}
@@ -3,8 +3,22 @@ import { DataTableInstance, DataTableRow, DataTableTable, UseDataTableOptions }
3
3
  import * as React from "react";
4
4
  import { RowData } from "@tanstack/react-table";
5
5
  //#region src/components/data-table/data-table.d.ts
6
+ /** What a `ref` on `DataTable` hands back. */
7
+ export interface DataTableHandle<Row extends RowData> {
8
+ /**
9
+ * Refetch the page on screen through the same query the auto-refresh
10
+ * interval drives — never a second fetch path. A table subscribed to a
11
+ * notification stream calls this from the stream and leaves the interval as
12
+ * the fallback for when the stream is unavailable.
13
+ */
14
+ refresh: () => void;
15
+ /** Everything else the table knows, for a caller that needs more than a refresh. */
16
+ instance: DataTableInstance<Row>;
17
+ }
6
18
  export interface DataTableViewProps<Row extends RowData> {
7
19
  className?: string;
20
+ /** Imperative handle: `ref.current.refresh()`. */
21
+ ref?: React.Ref<DataTableHandle<Row>>;
8
22
  /** Height of the scrolling body. Required for virtualisation to mean anything; defaults to 600px when virtualised. */
9
23
  maxHeight?: number | string;
10
24
  /** Force virtualisation on or off; undefined virtualises above 100 rows. */
@@ -57,7 +71,7 @@ export type DataTableProps<Row extends RowData> = DataTableViewProps<Row> & ({
57
71
  instance: DataTableInstance<Row>;
58
72
  } | UseDataTableOptions<Row>);
59
73
  declare function DataTable<Row extends RowData>(props: DataTableProps<Row>): React.JSX.Element;
60
- declare function DataTableView<Row extends RowData>({ instance, className, maxHeight, virtualize, rowHeight, stickyHeader, density, renderSubComponent, toolbar, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage, pageSizeOptions, enableExport, exportFileName, loading, error, onRowClick, activeRowId, rowClassName }: DataTableViewProps<Row> & {
74
+ declare function DataTableView<Row extends RowData>({ instance, className, maxHeight, virtualize, rowHeight, stickyHeader, density, renderSubComponent, toolbar, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage, pageSizeOptions, enableExport, exportFileName, loading, error, onRowClick, activeRowId, rowClassName, ref }: DataTableViewProps<Row> & {
61
75
  instance: DataTableInstance<Row>;
62
76
  }): React.JSX.Element;
63
77
  //#endregion
@@ -2,9 +2,9 @@
2
2
  "use client";
3
3
  import { cn } from "../../lib/cn.js";
4
4
  import { Input } from "../input.js";
5
+ import { Spinner } from "../spinner.js";
5
6
  import { ErrorBanner } from "../error-banner.js";
6
7
  import { Skeleton } from "../skeleton.js";
7
- import { Spinner } from "../spinner.js";
8
8
  import { DataTableColumnHeader, DataTablePagination, DataTableToolbar } from "./parts.js";
9
9
  import { useDataTable } from "./use-data-table.js";
10
10
  import { Inbox } from "lucide-react";
@@ -45,7 +45,7 @@ function DataTable(props) {
45
45
  return /* @__PURE__ */ jsx(DataTableOwned, { ...props });
46
46
  }
47
47
  function DataTableOwned(props) {
48
- const { className, maxHeight, virtualize, rowHeight, stickyHeader, density, renderSubComponent, toolbar, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage, pageSizeOptions, enableExport, exportFileName, loading, error, onRowClick, activeRowId, rowClassName, ...options } = props;
48
+ const { className, maxHeight, virtualize, rowHeight, stickyHeader, density, renderSubComponent, toolbar, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage, pageSizeOptions, enableExport, exportFileName, loading, error, onRowClick, activeRowId, rowClassName, ref, ...options } = props;
49
49
  const instance = useDataTable({
50
50
  ...options,
51
51
  enableExpanding: options.enableExpanding ?? Boolean(renderSubComponent)
@@ -72,7 +72,8 @@ function DataTableOwned(props) {
72
72
  error,
73
73
  onRowClick,
74
74
  activeRowId,
75
- rowClassName
75
+ rowClassName,
76
+ ref
76
77
  });
77
78
  }
78
79
  function pinAttrs(column, table) {
@@ -150,7 +151,7 @@ function EditableCell({ cell, instance, onDone }) {
150
151
  className: "h-7 px-2 py-0 text-[length:var(--ds-text-body-sm)]"
151
152
  });
152
153
  }
153
- function DataTableView({ instance, className, maxHeight, virtualize, rowHeight = 40, stickyHeader = true, density = "default", renderSubComponent, toolbar = true, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage = "No results", pageSizeOptions, enableExport = true, exportFileName = "export", loading, error, onRowClick, activeRowId, rowClassName }) {
154
+ function DataTableView({ instance, className, maxHeight, virtualize, rowHeight = 40, stickyHeader = true, density = "default", renderSubComponent, toolbar = true, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage = "No results", pageSizeOptions, enableExport = true, exportFileName = "export", loading, error, onRowClick, activeRowId, rowClassName, ref }) {
154
155
  const { table, paginationMode } = instance;
155
156
  const rows = table.getRowModel().rows;
156
157
  const leafColumns = table.getVisibleLeafColumns();
@@ -164,6 +165,18 @@ function DataTableView({ instance, className, maxHeight, virtualize, rowHeight =
164
165
  const errorMessage = error instanceof Error ? error.message : error ?? instance.error?.message ?? "";
165
166
  const scrollRef = React.useRef(null);
166
167
  const tableRef = React.useRef(null);
168
+ const refresh = instance.refetch;
169
+ React.useImperativeHandle(ref, () => ({
170
+ refresh,
171
+ instance
172
+ }), [refresh, instance]);
173
+ const refreshProps = instance.dataSource.kind === "server" ? {
174
+ onRefresh: refresh,
175
+ isFetching: instance.isFetching,
176
+ lastUpdatedAt: instance.lastUpdatedAt,
177
+ lastErrorAt: instance.lastErrorAt,
178
+ autoRefresh: instance.autoRefresh
179
+ } : void 0;
167
180
  const virtualizer = useVirtualizer({
168
181
  count: rows.length,
169
182
  enabled: isVirtual,
@@ -437,6 +450,7 @@ function DataTableView({ instance, className, maxHeight, virtualize, rowHeight =
437
450
  searchPlaceholder,
438
451
  enableExport,
439
452
  exportFileName,
453
+ refresh: refreshProps,
440
454
  children: toolbarActions
441
455
  }),
442
456
  /* @__PURE__ */ jsxs("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.js","names":[],"sources":["../../../src/components/data-table/data-table.tsx"],"sourcesContent":["\"use client\";\n\nimport type { RowData } from \"@tanstack/react-table\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport { Inbox } from \"lucide-react\";\nimport * as React from \"react\";\nimport { ErrorBanner } from \"@/components/error-banner\";\nimport { Input } from \"@/components/input\";\nimport { Skeleton } from \"@/components/skeleton\";\nimport { Spinner } from \"@/components/spinner\";\nimport { cn } from \"@/lib/cn\";\nimport { DataTableColumnHeader, DataTablePagination, DataTableToolbar } from \"./parts\";\nimport type {\n DataTableCell,\n DataTableColumn,\n DataTableInstance,\n DataTableRow,\n DataTableTable,\n UseDataTableOptions,\n} from \"./types\";\nimport { useDataTable } from \"./use-data-table\";\n\n/**\n * DataTable — the composite from cortenaUI&Design/04-data-tables.md.\n *\n * `<DataTable columns={columns} dataSource={{ kind: \"client\", rows }} />`\n * renders a complete table: toolbar with search, faceted filters, view and\n * export menus; sortable, pinnable, hideable, resizable columns; sticky\n * header; pager; and, past 100 rows, virtualised rows. A server source\n * changes nothing in the markup and everything in the data flow.\n *\n * Markup is a real `<table>` with `role=\"grid\"` so screen readers get rows\n * and columns, and keyboard users get one tab stop with arrow-key movement\n * between cells (roving tabindex), Enter to edit an editable cell, Escape to\n * cancel, Space to toggle selection.\n *\n * Virtualised bodies keep the table element: rows outside the viewport are\n * replaced by two spacer rows sized from the virtualizer, which keeps column\n * widths, sticky headers and pinned columns working without absolute\n * positioning.\n */\n\nconst VIRTUALIZE_ABOVE = 100;\nconst DEFAULT_VIRTUAL_HEIGHT = 600;\nconst INFINITE_THRESHOLD_PX = 240;\n\nexport interface DataTableViewProps<Row extends RowData> {\n className?: string;\n /** Height of the scrolling body. Required for virtualisation to mean anything; defaults to 600px when virtualised. */\n maxHeight?: number | string;\n /** Force virtualisation on or off; undefined virtualises above 100 rows. */\n virtualize?: boolean;\n /** Estimated row height in px for the virtualizer. @default 40 */\n rowHeight?: number;\n /** @default true */\n stickyHeader?: boolean;\n /** @default \"default\" */\n density?: \"default\" | \"compact\";\n /** Detail panel under an expanded row; enables the expander column. */\n renderSubComponent?: (row: DataTableRow<Row>) => React.ReactNode;\n /** `false` hides the toolbar; a function replaces it. */\n toolbar?: boolean | ((ctx: { instance: DataTableInstance<Row> }) => React.ReactNode);\n /** Rendered in the toolbar while rows are selected. */\n bulkActions?: (ctx: { rows: Row[]; table: DataTableTable<Row> }) => React.ReactNode;\n /** Extra toolbar controls (right side). */\n toolbarActions?: React.ReactNode;\n searchPlaceholder?: string;\n emptyState?: React.ReactNode;\n /** @default \"No results\" */\n emptyMessage?: string;\n pageSizeOptions?: number[];\n /** @default true */\n enableExport?: boolean;\n /** @default \"export\" */\n exportFileName?: string;\n /** Show the loading skeleton regardless of the source's own state. */\n loading?: boolean;\n /** Error to show above the table, in addition to the server source's. */\n error?: string | Error | null;\n onRowClick?: (row: Row, event: React.MouseEvent<HTMLTableRowElement>) => void;\n /**\n * The row a detail pane is currently showing, matched against the row id\n * (`getRowId`, the row index when that is not set). It gets `data-active`\n * and the `--ds-primary-soft` tint, independent of checkbox selection — a\n * master/detail list highlights one row without selecting it, and a table\n * with both can show a selected set and one open row at once.\n */\n activeRowId?: string | null;\n /** Extra classes per row, e.g. to dim rows the app considers stale. */\n rowClassName?: (row: Row) => string | undefined;\n}\n\nexport type DataTableProps<Row extends RowData> = DataTableViewProps<Row> &\n ({ instance: DataTableInstance<Row> } | UseDataTableOptions<Row>);\n\nfunction DataTable<Row extends RowData>(props: DataTableProps<Row>) {\n if (\"instance\" in props) {\n const { instance, ...view } = props;\n return <DataTableView instance={instance} {...view} />;\n }\n return <DataTableOwned {...props} />;\n}\n\nfunction DataTableOwned<Row extends RowData>(props: DataTableViewProps<Row> & UseDataTableOptions<Row>) {\n const {\n className,\n maxHeight,\n virtualize,\n rowHeight,\n stickyHeader,\n density,\n renderSubComponent,\n toolbar,\n bulkActions,\n toolbarActions,\n searchPlaceholder,\n emptyState,\n emptyMessage,\n pageSizeOptions,\n enableExport,\n exportFileName,\n loading,\n error,\n onRowClick,\n activeRowId,\n rowClassName,\n ...options\n } = props;\n const instance = useDataTable<Row>({\n ...options,\n enableExpanding: options.enableExpanding ?? Boolean(renderSubComponent),\n });\n return (\n <DataTableView\n instance={instance}\n className={className}\n maxHeight={maxHeight}\n virtualize={virtualize}\n rowHeight={rowHeight}\n stickyHeader={stickyHeader}\n density={density}\n renderSubComponent={renderSubComponent}\n toolbar={toolbar}\n bulkActions={bulkActions}\n toolbarActions={toolbarActions}\n searchPlaceholder={searchPlaceholder}\n emptyState={emptyState}\n emptyMessage={emptyMessage}\n pageSizeOptions={pageSizeOptions}\n enableExport={enableExport}\n exportFileName={exportFileName}\n loading={loading}\n error={error}\n onRowClick={onRowClick}\n activeRowId={activeRowId}\n rowClassName={rowClassName}\n />\n );\n}\n\n/* ------------------------------------------------------------------------ */\n/* Pinning */\n/* ------------------------------------------------------------------------ */\n\nfunction pinAttrs<Row extends RowData>(\n column: DataTableColumn<Row, any>,\n table: DataTableTable<Row>,\n): { style: React.CSSProperties; pinned: \"start\" | \"end\" | undefined; edge: boolean } {\n const pinned = column.getIsPinned();\n if (!pinned) return { style: {}, pinned: undefined, edge: false };\n if (pinned === \"start\") {\n const last = table.getStartVisibleLeafColumns().at(-1);\n return {\n style: { position: \"sticky\", left: column.getStart(\"start\") },\n pinned,\n edge: last?.id === column.id,\n };\n }\n const first = table.getEndVisibleLeafColumns()[0];\n return {\n style: { position: \"sticky\", right: column.getAfter(\"end\") },\n pinned,\n edge: first?.id === column.id,\n };\n}\n\nconst alignClass = { start: \"text-left\", center: \"text-center\", end: \"text-right\" } as const;\n\n/* ------------------------------------------------------------------------ */\n/* Editable cell */\n/* ------------------------------------------------------------------------ */\n\nfunction EditableCell<Row extends RowData>({\n cell,\n instance,\n onDone,\n}: {\n cell: DataTableCell<Row, any>;\n instance: DataTableInstance<Row>;\n onDone: () => void;\n}) {\n const editable = cell.column.columnDef.meta?.editable;\n const config = typeof editable === \"object\" ? editable : {};\n const initial = cell.getValue();\n const [draft, setDraft] = React.useState(initial == null ? \"\" : String(initial));\n const done = React.useRef(false);\n\n const finish = () => {\n done.current = true;\n instance.editing.stop();\n onDone();\n };\n const commit = () => {\n if (done.current) return;\n const value = config.parse ? config.parse(draft) : config.type === \"number\" ? Number(draft) : draft;\n void instance.editing.commit(cell.row, cell.column.id, value);\n finish();\n };\n const cancel = () => {\n if (done.current) return;\n finish();\n };\n\n return (\n <Input\n data-slot=\"data-table-editor\"\n autoFocus\n type={config.type === \"number\" ? \"number\" : \"text\"}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onFocus={(e) => e.target.select()}\n onBlur={commit}\n onKeyDown={(e) => {\n // The editor owns its keys; the grid must not move the focus cell.\n e.stopPropagation();\n if (e.key === \"Enter\") {\n e.preventDefault();\n commit();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n cancel();\n }\n }}\n className=\"h-7 px-2 py-0 text-[length:var(--ds-text-body-sm)]\"\n />\n );\n}\n\n/* ------------------------------------------------------------------------ */\n/* View */\n/* ------------------------------------------------------------------------ */\n\ntype CellCoord = { r: number; c: number };\n\nfunction DataTableView<Row extends RowData>({\n instance,\n className,\n maxHeight,\n virtualize,\n rowHeight = 40,\n stickyHeader = true,\n density = \"default\",\n renderSubComponent,\n toolbar = true,\n bulkActions,\n toolbarActions,\n searchPlaceholder,\n emptyState,\n emptyMessage = \"No results\",\n pageSizeOptions,\n enableExport = true,\n exportFileName = \"export\",\n loading,\n error,\n onRowClick,\n activeRowId,\n rowClassName,\n}: DataTableViewProps<Row> & { instance: DataTableInstance<Row> }) {\n const { table, paginationMode } = instance;\n const rows = table.getRowModel().rows;\n const leafColumns = table.getVisibleLeafColumns();\n const colCount = leafColumns.length;\n const headerGroups = table.getHeaderGroups();\n const isVirtual = virtualize ?? rows.length > VIRTUALIZE_ABOVE;\n const isLoading = loading || instance.isLoading;\n const showSkeleton = isLoading && rows.length === 0;\n const showEmpty = !isLoading && rows.length === 0;\n const resolvedHeight = maxHeight ?? (isVirtual ? DEFAULT_VIRTUAL_HEIGHT : undefined);\n const errorMessage = error instanceof Error ? error.message : (error ?? instance.error?.message ?? \"\");\n\n const scrollRef = React.useRef<HTMLDivElement>(null);\n const tableRef = React.useRef<HTMLTableElement>(null);\n\n /* Virtualisation ------------------------------------------------------ */\n\n const virtualizer = useVirtualizer<HTMLDivElement, HTMLTableRowElement>({\n count: rows.length,\n enabled: isVirtual,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => rowHeight,\n overscan: 8,\n getItemKey: (index) => rows[index]?.id ?? index,\n // An expanded row and its detail row are one virtual item.\n measureElement: (element) => {\n let height = element.getBoundingClientRect().height;\n const next = element.nextElementSibling as HTMLElement | null;\n if (next?.dataset.slot === \"data-table-subrow\") height += next.getBoundingClientRect().height;\n return height;\n },\n });\n const virtualItems = isVirtual ? virtualizer.getVirtualItems() : null;\n const paddingTop = virtualItems?.length ? virtualItems[0]!.start : 0;\n const paddingBottom = virtualItems?.length\n ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1]!.end\n : 0;\n\n /* Infinite scroll ----------------------------------------------------- */\n\n const onScroll = React.useCallback(\n (event: React.UIEvent<HTMLDivElement>) => {\n if (paginationMode !== \"infinite\" || !instance.hasNextPage || instance.isFetching) return;\n const el = event.currentTarget;\n if (el.scrollHeight - el.scrollTop - el.clientHeight < INFINITE_THRESHOLD_PX) instance.fetchNextPage();\n },\n [paginationMode, instance],\n );\n\n /* Keyboard navigation ------------------------------------------------- */\n\n const [focused, setFocused] = React.useState<CellCoord>({ r: -1, c: 0 });\n const pendingFocus = React.useRef<CellCoord | null>(null);\n\n const cellElement = (coord: CellCoord) =>\n tableRef.current?.querySelector<HTMLElement>(\n `[data-row-index=\"${coord.r}\"][data-col-index=\"${coord.c}\"]`,\n ) ?? null;\n\n const focusCell = React.useCallback(\n (coord: CellCoord) => {\n const el = cellElement(coord);\n if (el) {\n setFocused(coord);\n el.focus();\n return;\n }\n if (isVirtual && coord.r >= 0) {\n pendingFocus.current = coord;\n setFocused(coord);\n virtualizer.scrollToIndex(coord.r, { align: \"auto\" });\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [isVirtual, virtualizer],\n );\n\n React.useEffect(() => {\n const coord = pendingFocus.current;\n if (!coord) return;\n const el = cellElement(coord);\n if (el) {\n pendingFocus.current = null;\n el.focus();\n }\n });\n\n const onKeyDown = (event: React.KeyboardEvent<HTMLTableElement>) => {\n const target = event.target as HTMLElement;\n // Portaled menus bubble through React but live outside the table element.\n if (!tableRef.current?.contains(target)) return;\n if (instance.editing.cell) return;\n const cell = target.closest<HTMLElement>(\"[data-row-index][data-col-index]\");\n if (!cell) return;\n const r = Number(cell.dataset.rowIndex);\n const c = Number(cell.dataset.colIndex);\n const lastRow = rows.length - 1;\n const lastCol = colCount - 1;\n const onCellItself = target === cell;\n\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n focusCell({ r: Math.min(lastRow, r + 1), c });\n return;\n case \"ArrowUp\":\n event.preventDefault();\n focusCell({ r: Math.max(-1, r - 1), c });\n return;\n case \"ArrowRight\":\n event.preventDefault();\n focusCell({ r, c: Math.min(lastCol, c + 1) });\n return;\n case \"ArrowLeft\":\n event.preventDefault();\n focusCell({ r, c: Math.max(0, c - 1) });\n return;\n case \"Home\":\n event.preventDefault();\n focusCell(event.ctrlKey ? { r: -1, c: 0 } : { r, c: 0 });\n return;\n case \"End\":\n event.preventDefault();\n focusCell(event.ctrlKey ? { r: lastRow, c: lastCol } : { r, c: lastCol });\n return;\n case \"PageDown\":\n event.preventDefault();\n focusCell({ r: Math.min(lastRow, r + 10), c });\n return;\n case \"PageUp\":\n event.preventDefault();\n focusCell({ r: Math.max(-1, r - 10), c });\n return;\n case \"Enter\": {\n if (!onCellItself) return;\n if (r === -1) {\n const column = leafColumns[c];\n if (column?.getCanSort()) {\n event.preventDefault();\n column.toggleSorting(undefined, event.shiftKey);\n }\n return;\n }\n const row = rows[r];\n const column = leafColumns[c];\n if (row && column && column.columnDef.meta?.editable) {\n event.preventDefault();\n instance.editing.start({ rowId: row.id, columnId: column.id });\n }\n return;\n }\n case \" \": {\n if (!onCellItself || r === -1) return;\n const row = rows[r];\n if (row?.getCanSelect()) {\n event.preventDefault();\n row.toggleSelected();\n }\n return;\n }\n default:\n return;\n }\n };\n\n const onFocus = (event: React.FocusEvent<HTMLTableElement>) => {\n const cell = (event.target as HTMLElement).closest<HTMLElement>(\"[data-row-index][data-col-index]\");\n if (!cell || !tableRef.current?.contains(cell)) return;\n const r = Number(cell.dataset.rowIndex);\n const c = Number(cell.dataset.colIndex);\n setFocused((f) => (f.r === r && f.c === c ? f : { r, c }));\n };\n\n const tabIndexFor = (r: number, c: number) => (focused.r === r && focused.c === c ? 0 : -1);\n\n /* Rendering ----------------------------------------------------------- */\n\n const cellPadding = density === \"compact\" ? \"px-3 py-1.5\" : \"px-3 py-2.5\";\n const headPadding = density === \"compact\" ? \"px-3 py-1.5\" : \"px-3 py-2\";\n const editingCell = instance.editing.cell;\n\n const renderRow = (row: DataTableRow<Row>, index: number, virtualIndex?: number) => {\n const cells = row.getVisibleCells();\n const endStart = cells.findIndex((cell) => cell.column.getIsPinned() === \"end\");\n const splitAt = endStart === -1 ? cells.length : endStart;\n const selected = row.getIsSelected();\n const active = activeRowId != null && row.id === activeRowId;\n const expanded = renderSubComponent && row.getIsExpanded();\n\n const renderCell = (cell: DataTableCell<Row, any>, c: number) => {\n const column = cell.column;\n const meta = column.columnDef.meta;\n const pin = pinAttrs(column, table);\n const isEditing = editingCell?.rowId === row.id && editingCell.columnId === column.id;\n const canEdit = Boolean(meta?.editable);\n return (\n <td\n key={cell.id}\n role=\"gridcell\"\n data-slot=\"data-table-cell\"\n data-row-index={index}\n data-col-index={c}\n data-pinned={pin.pinned}\n data-pinned-edge={pin.edge ? \"\" : undefined}\n data-editable={canEdit ? \"\" : undefined}\n data-editing={isEditing ? \"\" : undefined}\n aria-colindex={c + 1}\n tabIndex={tabIndexFor(index, c)}\n style={{ width: column.getSize(), ...pin.style }}\n onDoubleClick={\n canEdit && !isEditing\n ? () => instance.editing.start({ rowId: row.id, columnId: column.id })\n : undefined\n }\n className={cn(\n \"relative align-middle outline-none\",\n isEditing ? \"px-1.5 py-1\" : cellPadding,\n alignClass[meta?.align ?? \"start\"],\n \"focus-visible:ring-[2px] focus-visible:ring-inset focus-visible:ring-[var(--ds-ring)]\",\n // Pinned cells cover what scrolls under them, so their background is\n // opaque card with the translucent hover / selected tint layered on.\n pin.pinned &&\n \"z-[1] bg-[var(--ds-card)] group-hover/row:bg-[linear-gradient(var(--ds-hover),var(--ds-hover))] group-data-[selected]/row:bg-[linear-gradient(var(--ds-primary-soft),var(--ds-primary-soft))] group-data-[active]/row:bg-[linear-gradient(var(--ds-primary-soft),var(--ds-primary-soft))]\",\n pin.pinned === \"start\" && pin.edge && \"shadow-[inset_-1px_0_0_var(--ds-border)]\",\n pin.pinned === \"end\" && pin.edge && \"shadow-[inset_1px_0_0_var(--ds-border)]\",\n !isEditing && \"truncate\",\n meta?.cellClassName,\n )}\n >\n {isEditing ? (\n <EditableCell\n cell={cell}\n instance={instance}\n onDone={() => {\n pendingFocus.current = { r: index, c };\n }}\n />\n ) : (\n <table.FlexRender cell={cell} />\n )}\n </td>\n );\n };\n\n return (\n <React.Fragment key={row.id}>\n <tr\n role=\"row\"\n data-slot=\"data-table-row\"\n data-index={virtualIndex}\n data-selected={selected ? \"\" : undefined}\n data-active={active ? \"\" : undefined}\n data-expanded={expanded ? \"\" : undefined}\n aria-rowindex={index + 2}\n aria-selected={table.options.enableRowSelection ? selected : undefined}\n ref={isVirtual ? virtualizer.measureElement : undefined}\n onClick={onRowClick ? (e) => onRowClick(row.original, e) : undefined}\n className={cn(\n \"group/row border-b border-[var(--ds-border-subtle)] transition-colors duration-[var(--ds-duration-fast)]\",\n \"hover:bg-[var(--ds-hover)] data-[selected]:bg-[var(--ds-primary-soft)]\",\n // Independent of selection: a detail pane highlights one row\n // without ticking its checkbox.\n \"data-[active]:bg-[var(--ds-primary-soft)]\",\n onRowClick && \"cursor-pointer\",\n rowClassName?.(row.original),\n )}\n >\n {cells.slice(0, splitAt).map((cell, c) => renderCell(cell, c))}\n <td aria-hidden data-slot=\"data-table-filler\" className=\"p-0\" />\n {cells.slice(splitAt).map((cell, i) => renderCell(cell, splitAt + i))}\n </tr>\n {expanded ? (\n <tr role=\"row\" data-slot=\"data-table-subrow\" className=\"border-b border-[var(--ds-border-subtle)]\">\n <td\n role=\"gridcell\"\n colSpan={colCount + 1}\n className=\"bg-[var(--ds-muted)] px-4 py-3 text-[length:var(--ds-text-body-sm)]\"\n >\n {renderSubComponent(row)}\n </td>\n </tr>\n ) : null}\n </React.Fragment>\n );\n };\n\n const skeletonRows = Array.from({ length: Math.min(8, table.state.pagination.pageSize) }, (_, i) => (\n <tr key={`skeleton-${i}`} aria-hidden data-slot=\"data-table-skeleton-row\" className=\"border-b border-[var(--ds-border-subtle)]\">\n {leafColumns.map((column) => (\n <td key={column.id} className={cellPadding} style={{ width: column.getSize() }}>\n <Skeleton className=\"h-3.5 w-3/4\" />\n </td>\n ))}\n <td className=\"p-0\" />\n </tr>\n ));\n\n return (\n <div data-slot=\"data-table\" className={cn(\"flex min-w-0 flex-col gap-3\", className)}>\n {errorMessage ? (\n <ErrorBanner message={errorMessage} onRetry={instance.error ? instance.refetch : undefined} />\n ) : null}\n {toolbar === false ? null : typeof toolbar === \"function\" ? (\n toolbar({ instance })\n ) : (\n <DataTableToolbar\n table={table}\n bulkActions={bulkActions}\n searchPlaceholder={searchPlaceholder}\n enableExport={enableExport}\n exportFileName={exportFileName}\n >\n {toolbarActions}\n </DataTableToolbar>\n )}\n <div\n ref={scrollRef}\n data-slot=\"data-table-container\"\n onScroll={onScroll}\n style={{ maxHeight: resolvedHeight }}\n className={cn(\n \"relative w-full overflow-auto rounded-[var(--ds-radius-md)] border border-[var(--ds-border)] bg-[var(--ds-card)]\",\n )}\n >\n <table\n ref={tableRef}\n role=\"grid\"\n data-slot=\"data-table-grid\"\n data-virtualized={isVirtual ? \"\" : undefined}\n aria-rowcount={rows.length + 1}\n aria-colcount={colCount}\n aria-busy={instance.isFetching || undefined}\n aria-multiselectable={table.options.enableRowSelection ? true : undefined}\n onKeyDown={onKeyDown}\n onFocus={onFocus}\n style={{ minWidth: table.getTotalSize() }}\n className={cn(\n \"w-full table-fixed border-collapse caption-bottom\",\n \"text-[length:var(--ds-text-body-sm)] leading-[var(--ds-text-body-sm--line-height)] text-[color:var(--ds-foreground)]\",\n )}\n >\n <thead data-slot=\"data-table-header\" className={cn(stickyHeader && \"sticky top-0 z-[2]\")}>\n {headerGroups.map((group) => {\n const endStart = group.headers.findIndex((h) => h.column.getIsPinned() === \"end\");\n const splitAt = endStart === -1 ? group.headers.length : endStart;\n const renderHead = (header: (typeof group.headers)[number], c: number) => {\n const column = header.column;\n const meta = column.columnDef.meta;\n const pin = pinAttrs(column, table);\n const sorted = column.getIsSorted();\n const def = column.columnDef;\n return (\n <th\n key={header.id}\n role=\"columnheader\"\n scope=\"col\"\n data-slot=\"data-table-head\"\n data-row-index={-1}\n data-col-index={c}\n data-pinned={pin.pinned}\n data-pinned-edge={pin.edge ? \"\" : undefined}\n aria-colindex={c + 1}\n aria-sort={\n sorted === \"asc\"\n ? \"ascending\"\n : sorted === \"desc\"\n ? \"descending\"\n : column.getCanSort()\n ? \"none\"\n : undefined\n }\n colSpan={header.colSpan}\n tabIndex={tabIndexFor(-1, c)}\n style={{ width: header.getSize(), ...pin.style }}\n className={cn(\n \"group/head relative h-10 align-middle font-medium outline-none\",\n headPadding,\n \"bg-[var(--ds-muted)] text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]\",\n \"border-b border-[var(--ds-border)]\",\n alignClass[meta?.align ?? \"start\"],\n \"focus-visible:ring-[2px] focus-visible:ring-inset focus-visible:ring-[var(--ds-ring)]\",\n pin.pinned && \"z-[3]\",\n pin.pinned === \"start\" && pin.edge && \"shadow-[inset_-1px_0_0_var(--ds-border)]\",\n pin.pinned === \"end\" && pin.edge && \"shadow-[inset_1px_0_0_var(--ds-border)]\",\n meta?.headerClassName,\n )}\n >\n {header.isPlaceholder ? null : typeof def.header === \"string\" ? (\n <DataTableColumnHeader column={column} title={def.header} />\n ) : (\n <table.FlexRender header={header} />\n )}\n {column.getCanResize() ? (\n <div\n data-slot=\"data-table-resizer\"\n data-resizing={column.getIsResizing() ? \"\" : undefined}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onDoubleClick={() => column.resetSize()}\n className={cn(\n \"absolute right-0 top-0 h-full w-1 cursor-col-resize touch-none select-none\",\n \"opacity-0 transition-opacity duration-[var(--ds-duration-fast)] hover:opacity-100 data-[resizing]:opacity-100\",\n \"bg-[var(--ds-ring)]\",\n )}\n />\n ) : null}\n </th>\n );\n };\n return (\n <tr key={group.id} role=\"row\" aria-rowindex={1}>\n {group.headers.slice(0, splitAt).map((header, c) => renderHead(header, c))}\n <th aria-hidden className=\"border-b border-[var(--ds-border)] bg-[var(--ds-muted)] p-0\" />\n {group.headers.slice(splitAt).map((header, i) => renderHead(header, splitAt + i))}\n </tr>\n );\n })}\n </thead>\n <tbody data-slot=\"data-table-body\">\n {showSkeleton ? skeletonRows : null}\n {showEmpty ? (\n <tr role=\"row\" data-slot=\"data-table-empty\">\n <td role=\"gridcell\" colSpan={colCount + 1} className=\"p-0\">\n {emptyState ?? (\n <div className=\"flex flex-col items-center justify-center gap-2 px-4 py-12 text-center text-[color:var(--ds-muted-foreground)]\">\n <Inbox aria-hidden className=\"size-6 text-[color:var(--ds-text-tertiary)]\" />\n <p className=\"text-[length:var(--ds-text-body-sm)]\">{emptyMessage}</p>\n </div>\n )}\n </td>\n </tr>\n ) : null}\n {virtualItems ? (\n <>\n {paddingTop > 0 ? (\n <tr aria-hidden data-slot=\"data-table-spacer\" style={{ height: paddingTop }}>\n <td colSpan={colCount + 1} className=\"p-0\" />\n </tr>\n ) : null}\n {virtualItems.map((item) => {\n const row = rows[item.index];\n return row ? renderRow(row, item.index, item.index) : null;\n })}\n {paddingBottom > 0 ? (\n <tr aria-hidden data-slot=\"data-table-spacer\" style={{ height: paddingBottom }}>\n <td colSpan={colCount + 1} className=\"p-0\" />\n </tr>\n ) : null}\n </>\n ) : (\n rows.map((row, index) => renderRow(row, index))\n )}\n </tbody>\n </table>\n {paginationMode === \"infinite\" && instance.isFetching && rows.length > 0 ? (\n <div\n data-slot=\"data-table-loading-more\"\n className=\"flex items-center justify-center gap-2 border-t border-[var(--ds-border-subtle)] py-2 text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]\"\n >\n <Spinner size={14} /> Loading more\n </div>\n ) : null}\n </div>\n {paginationMode === \"pages\" ? (\n <DataTablePagination table={table} pageSizeOptions={pageSizeOptions} />\n ) : paginationMode === \"infinite\" ? (\n <div className=\"text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]\">\n {rows.length} of {instance.total}\n </div>\n ) : null}\n </div>\n );\n}\n\nexport { DataTable, DataTableView };\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-table.js","names":[],"sources":["../../../src/components/data-table/data-table.tsx"],"sourcesContent":["\"use client\";\n\nimport type { RowData } from \"@tanstack/react-table\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport { Inbox } from \"lucide-react\";\nimport * as React from \"react\";\nimport { ErrorBanner } from \"@/components/error-banner\";\nimport { Input } from \"@/components/input\";\nimport { Skeleton } from \"@/components/skeleton\";\nimport { Spinner } from \"@/components/spinner\";\nimport { cn } from \"@/lib/cn\";\nimport { DataTableColumnHeader, DataTablePagination, DataTableToolbar } from \"./parts\";\nimport type {\n DataTableCell,\n DataTableColumn,\n DataTableInstance,\n DataTableRow,\n DataTableTable,\n UseDataTableOptions,\n} from \"./types\";\nimport { useDataTable } from \"./use-data-table\";\n\n/**\n * DataTable — the composite from cortenaUI&Design/04-data-tables.md.\n *\n * `<DataTable columns={columns} dataSource={{ kind: \"client\", rows }} />`\n * renders a complete table: toolbar with search, faceted filters, view and\n * export menus; sortable, pinnable, hideable, resizable columns; sticky\n * header; pager; and, past 100 rows, virtualised rows. A server source\n * changes nothing in the markup and everything in the data flow.\n *\n * Markup is a real `<table>` with `role=\"grid\"` so screen readers get rows\n * and columns, and keyboard users get one tab stop with arrow-key movement\n * between cells (roving tabindex), Enter to edit an editable cell, Escape to\n * cancel, Space to toggle selection.\n *\n * Virtualised bodies keep the table element: rows outside the viewport are\n * replaced by two spacer rows sized from the virtualizer, which keeps column\n * widths, sticky headers and pinned columns working without absolute\n * positioning.\n */\n\nconst VIRTUALIZE_ABOVE = 100;\nconst DEFAULT_VIRTUAL_HEIGHT = 600;\nconst INFINITE_THRESHOLD_PX = 240;\n\n/** What a `ref` on `DataTable` hands back. */\nexport interface DataTableHandle<Row extends RowData> {\n /**\n * Refetch the page on screen through the same query the auto-refresh\n * interval drives — never a second fetch path. A table subscribed to a\n * notification stream calls this from the stream and leaves the interval as\n * the fallback for when the stream is unavailable.\n */\n refresh: () => void;\n /** Everything else the table knows, for a caller that needs more than a refresh. */\n instance: DataTableInstance<Row>;\n}\n\nexport interface DataTableViewProps<Row extends RowData> {\n className?: string;\n /** Imperative handle: `ref.current.refresh()`. */\n ref?: React.Ref<DataTableHandle<Row>>;\n /** Height of the scrolling body. Required for virtualisation to mean anything; defaults to 600px when virtualised. */\n maxHeight?: number | string;\n /** Force virtualisation on or off; undefined virtualises above 100 rows. */\n virtualize?: boolean;\n /** Estimated row height in px for the virtualizer. @default 40 */\n rowHeight?: number;\n /** @default true */\n stickyHeader?: boolean;\n /** @default \"default\" */\n density?: \"default\" | \"compact\";\n /** Detail panel under an expanded row; enables the expander column. */\n renderSubComponent?: (row: DataTableRow<Row>) => React.ReactNode;\n /** `false` hides the toolbar; a function replaces it. */\n toolbar?: boolean | ((ctx: { instance: DataTableInstance<Row> }) => React.ReactNode);\n /** Rendered in the toolbar while rows are selected. */\n bulkActions?: (ctx: { rows: Row[]; table: DataTableTable<Row> }) => React.ReactNode;\n /** Extra toolbar controls (right side). */\n toolbarActions?: React.ReactNode;\n searchPlaceholder?: string;\n emptyState?: React.ReactNode;\n /** @default \"No results\" */\n emptyMessage?: string;\n pageSizeOptions?: number[];\n /** @default true */\n enableExport?: boolean;\n /** @default \"export\" */\n exportFileName?: string;\n /** Show the loading skeleton regardless of the source's own state. */\n loading?: boolean;\n /** Error to show above the table, in addition to the server source's. */\n error?: string | Error | null;\n onRowClick?: (row: Row, event: React.MouseEvent<HTMLTableRowElement>) => void;\n /**\n * The row a detail pane is currently showing, matched against the row id\n * (`getRowId`, the row index when that is not set). It gets `data-active`\n * and the `--ds-primary-soft` tint, independent of checkbox selection — a\n * master/detail list highlights one row without selecting it, and a table\n * with both can show a selected set and one open row at once.\n */\n activeRowId?: string | null;\n /** Extra classes per row, e.g. to dim rows the app considers stale. */\n rowClassName?: (row: Row) => string | undefined;\n}\n\nexport type DataTableProps<Row extends RowData> = DataTableViewProps<Row> &\n ({ instance: DataTableInstance<Row> } | UseDataTableOptions<Row>);\n\nfunction DataTable<Row extends RowData>(props: DataTableProps<Row>) {\n if (\"instance\" in props) {\n const { instance, ...view } = props;\n return <DataTableView instance={instance} {...view} />;\n }\n return <DataTableOwned {...props} />;\n}\n\nfunction DataTableOwned<Row extends RowData>(props: DataTableViewProps<Row> & UseDataTableOptions<Row>) {\n const {\n className,\n maxHeight,\n virtualize,\n rowHeight,\n stickyHeader,\n density,\n renderSubComponent,\n toolbar,\n bulkActions,\n toolbarActions,\n searchPlaceholder,\n emptyState,\n emptyMessage,\n pageSizeOptions,\n enableExport,\n exportFileName,\n loading,\n error,\n onRowClick,\n activeRowId,\n rowClassName,\n ref,\n ...options\n } = props;\n const instance = useDataTable<Row>({\n ...options,\n enableExpanding: options.enableExpanding ?? Boolean(renderSubComponent),\n });\n return (\n <DataTableView\n instance={instance}\n className={className}\n maxHeight={maxHeight}\n virtualize={virtualize}\n rowHeight={rowHeight}\n stickyHeader={stickyHeader}\n density={density}\n renderSubComponent={renderSubComponent}\n toolbar={toolbar}\n bulkActions={bulkActions}\n toolbarActions={toolbarActions}\n searchPlaceholder={searchPlaceholder}\n emptyState={emptyState}\n emptyMessage={emptyMessage}\n pageSizeOptions={pageSizeOptions}\n enableExport={enableExport}\n exportFileName={exportFileName}\n loading={loading}\n error={error}\n onRowClick={onRowClick}\n activeRowId={activeRowId}\n rowClassName={rowClassName}\n ref={ref}\n />\n );\n}\n\n/* ------------------------------------------------------------------------ */\n/* Pinning */\n/* ------------------------------------------------------------------------ */\n\nfunction pinAttrs<Row extends RowData>(\n column: DataTableColumn<Row, any>,\n table: DataTableTable<Row>,\n): { style: React.CSSProperties; pinned: \"start\" | \"end\" | undefined; edge: boolean } {\n const pinned = column.getIsPinned();\n if (!pinned) return { style: {}, pinned: undefined, edge: false };\n if (pinned === \"start\") {\n const last = table.getStartVisibleLeafColumns().at(-1);\n return {\n style: { position: \"sticky\", left: column.getStart(\"start\") },\n pinned,\n edge: last?.id === column.id,\n };\n }\n const first = table.getEndVisibleLeafColumns()[0];\n return {\n style: { position: \"sticky\", right: column.getAfter(\"end\") },\n pinned,\n edge: first?.id === column.id,\n };\n}\n\nconst alignClass = { start: \"text-left\", center: \"text-center\", end: \"text-right\" } as const;\n\n/* ------------------------------------------------------------------------ */\n/* Editable cell */\n/* ------------------------------------------------------------------------ */\n\nfunction EditableCell<Row extends RowData>({\n cell,\n instance,\n onDone,\n}: {\n cell: DataTableCell<Row, any>;\n instance: DataTableInstance<Row>;\n onDone: () => void;\n}) {\n const editable = cell.column.columnDef.meta?.editable;\n const config = typeof editable === \"object\" ? editable : {};\n const initial = cell.getValue();\n const [draft, setDraft] = React.useState(initial == null ? \"\" : String(initial));\n const done = React.useRef(false);\n\n const finish = () => {\n done.current = true;\n instance.editing.stop();\n onDone();\n };\n const commit = () => {\n if (done.current) return;\n const value = config.parse ? config.parse(draft) : config.type === \"number\" ? Number(draft) : draft;\n void instance.editing.commit(cell.row, cell.column.id, value);\n finish();\n };\n const cancel = () => {\n if (done.current) return;\n finish();\n };\n\n return (\n <Input\n data-slot=\"data-table-editor\"\n autoFocus\n type={config.type === \"number\" ? \"number\" : \"text\"}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onFocus={(e) => e.target.select()}\n onBlur={commit}\n onKeyDown={(e) => {\n // The editor owns its keys; the grid must not move the focus cell.\n e.stopPropagation();\n if (e.key === \"Enter\") {\n e.preventDefault();\n commit();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n cancel();\n }\n }}\n className=\"h-7 px-2 py-0 text-[length:var(--ds-text-body-sm)]\"\n />\n );\n}\n\n/* ------------------------------------------------------------------------ */\n/* View */\n/* ------------------------------------------------------------------------ */\n\ntype CellCoord = { r: number; c: number };\n\nfunction DataTableView<Row extends RowData>({\n instance,\n className,\n maxHeight,\n virtualize,\n rowHeight = 40,\n stickyHeader = true,\n density = \"default\",\n renderSubComponent,\n toolbar = true,\n bulkActions,\n toolbarActions,\n searchPlaceholder,\n emptyState,\n emptyMessage = \"No results\",\n pageSizeOptions,\n enableExport = true,\n exportFileName = \"export\",\n loading,\n error,\n onRowClick,\n activeRowId,\n rowClassName,\n ref,\n}: DataTableViewProps<Row> & { instance: DataTableInstance<Row> }) {\n const { table, paginationMode } = instance;\n const rows = table.getRowModel().rows;\n const leafColumns = table.getVisibleLeafColumns();\n const colCount = leafColumns.length;\n const headerGroups = table.getHeaderGroups();\n const isVirtual = virtualize ?? rows.length > VIRTUALIZE_ABOVE;\n const isLoading = loading || instance.isLoading;\n const showSkeleton = isLoading && rows.length === 0;\n const showEmpty = !isLoading && rows.length === 0;\n const resolvedHeight = maxHeight ?? (isVirtual ? DEFAULT_VIRTUAL_HEIGHT : undefined);\n const errorMessage = error instanceof Error ? error.message : (error ?? instance.error?.message ?? \"\");\n\n const scrollRef = React.useRef<HTMLDivElement>(null);\n const tableRef = React.useRef<HTMLTableElement>(null);\n\n const refresh = instance.refetch;\n React.useImperativeHandle(ref, () => ({ refresh, instance }), [refresh, instance]);\n\n // Mandatory on every server-backed table (P-39): a Refresh button beside the\n // search box and a stamp saying which moment these rows are. The switch only\n // appears where the table asked for `autoRefresh`.\n const refreshProps =\n instance.dataSource.kind === \"server\"\n ? {\n onRefresh: refresh,\n isFetching: instance.isFetching,\n lastUpdatedAt: instance.lastUpdatedAt,\n lastErrorAt: instance.lastErrorAt,\n autoRefresh: instance.autoRefresh,\n }\n : undefined;\n\n /* Virtualisation ------------------------------------------------------ */\n\n const virtualizer = useVirtualizer<HTMLDivElement, HTMLTableRowElement>({\n count: rows.length,\n enabled: isVirtual,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => rowHeight,\n overscan: 8,\n getItemKey: (index) => rows[index]?.id ?? index,\n // An expanded row and its detail row are one virtual item.\n measureElement: (element) => {\n let height = element.getBoundingClientRect().height;\n const next = element.nextElementSibling as HTMLElement | null;\n if (next?.dataset.slot === \"data-table-subrow\") height += next.getBoundingClientRect().height;\n return height;\n },\n });\n const virtualItems = isVirtual ? virtualizer.getVirtualItems() : null;\n const paddingTop = virtualItems?.length ? virtualItems[0]!.start : 0;\n const paddingBottom = virtualItems?.length\n ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1]!.end\n : 0;\n\n /* Infinite scroll ----------------------------------------------------- */\n\n const onScroll = React.useCallback(\n (event: React.UIEvent<HTMLDivElement>) => {\n if (paginationMode !== \"infinite\" || !instance.hasNextPage || instance.isFetching) return;\n const el = event.currentTarget;\n if (el.scrollHeight - el.scrollTop - el.clientHeight < INFINITE_THRESHOLD_PX) instance.fetchNextPage();\n },\n [paginationMode, instance],\n );\n\n /* Keyboard navigation ------------------------------------------------- */\n\n const [focused, setFocused] = React.useState<CellCoord>({ r: -1, c: 0 });\n const pendingFocus = React.useRef<CellCoord | null>(null);\n\n const cellElement = (coord: CellCoord) =>\n tableRef.current?.querySelector<HTMLElement>(\n `[data-row-index=\"${coord.r}\"][data-col-index=\"${coord.c}\"]`,\n ) ?? null;\n\n const focusCell = React.useCallback(\n (coord: CellCoord) => {\n const el = cellElement(coord);\n if (el) {\n setFocused(coord);\n el.focus();\n return;\n }\n if (isVirtual && coord.r >= 0) {\n pendingFocus.current = coord;\n setFocused(coord);\n virtualizer.scrollToIndex(coord.r, { align: \"auto\" });\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [isVirtual, virtualizer],\n );\n\n React.useEffect(() => {\n const coord = pendingFocus.current;\n if (!coord) return;\n const el = cellElement(coord);\n if (el) {\n pendingFocus.current = null;\n el.focus();\n }\n });\n\n const onKeyDown = (event: React.KeyboardEvent<HTMLTableElement>) => {\n const target = event.target as HTMLElement;\n // Portaled menus bubble through React but live outside the table element.\n if (!tableRef.current?.contains(target)) return;\n if (instance.editing.cell) return;\n const cell = target.closest<HTMLElement>(\"[data-row-index][data-col-index]\");\n if (!cell) return;\n const r = Number(cell.dataset.rowIndex);\n const c = Number(cell.dataset.colIndex);\n const lastRow = rows.length - 1;\n const lastCol = colCount - 1;\n const onCellItself = target === cell;\n\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n focusCell({ r: Math.min(lastRow, r + 1), c });\n return;\n case \"ArrowUp\":\n event.preventDefault();\n focusCell({ r: Math.max(-1, r - 1), c });\n return;\n case \"ArrowRight\":\n event.preventDefault();\n focusCell({ r, c: Math.min(lastCol, c + 1) });\n return;\n case \"ArrowLeft\":\n event.preventDefault();\n focusCell({ r, c: Math.max(0, c - 1) });\n return;\n case \"Home\":\n event.preventDefault();\n focusCell(event.ctrlKey ? { r: -1, c: 0 } : { r, c: 0 });\n return;\n case \"End\":\n event.preventDefault();\n focusCell(event.ctrlKey ? { r: lastRow, c: lastCol } : { r, c: lastCol });\n return;\n case \"PageDown\":\n event.preventDefault();\n focusCell({ r: Math.min(lastRow, r + 10), c });\n return;\n case \"PageUp\":\n event.preventDefault();\n focusCell({ r: Math.max(-1, r - 10), c });\n return;\n case \"Enter\": {\n if (!onCellItself) return;\n if (r === -1) {\n const column = leafColumns[c];\n if (column?.getCanSort()) {\n event.preventDefault();\n column.toggleSorting(undefined, event.shiftKey);\n }\n return;\n }\n const row = rows[r];\n const column = leafColumns[c];\n if (row && column && column.columnDef.meta?.editable) {\n event.preventDefault();\n instance.editing.start({ rowId: row.id, columnId: column.id });\n }\n return;\n }\n case \" \": {\n if (!onCellItself || r === -1) return;\n const row = rows[r];\n if (row?.getCanSelect()) {\n event.preventDefault();\n row.toggleSelected();\n }\n return;\n }\n default:\n return;\n }\n };\n\n const onFocus = (event: React.FocusEvent<HTMLTableElement>) => {\n const cell = (event.target as HTMLElement).closest<HTMLElement>(\"[data-row-index][data-col-index]\");\n if (!cell || !tableRef.current?.contains(cell)) return;\n const r = Number(cell.dataset.rowIndex);\n const c = Number(cell.dataset.colIndex);\n setFocused((f) => (f.r === r && f.c === c ? f : { r, c }));\n };\n\n const tabIndexFor = (r: number, c: number) => (focused.r === r && focused.c === c ? 0 : -1);\n\n /* Rendering ----------------------------------------------------------- */\n\n const cellPadding = density === \"compact\" ? \"px-3 py-1.5\" : \"px-3 py-2.5\";\n const headPadding = density === \"compact\" ? \"px-3 py-1.5\" : \"px-3 py-2\";\n const editingCell = instance.editing.cell;\n\n const renderRow = (row: DataTableRow<Row>, index: number, virtualIndex?: number) => {\n const cells = row.getVisibleCells();\n const endStart = cells.findIndex((cell) => cell.column.getIsPinned() === \"end\");\n const splitAt = endStart === -1 ? cells.length : endStart;\n const selected = row.getIsSelected();\n const active = activeRowId != null && row.id === activeRowId;\n const expanded = renderSubComponent && row.getIsExpanded();\n\n const renderCell = (cell: DataTableCell<Row, any>, c: number) => {\n const column = cell.column;\n const meta = column.columnDef.meta;\n const pin = pinAttrs(column, table);\n const isEditing = editingCell?.rowId === row.id && editingCell.columnId === column.id;\n const canEdit = Boolean(meta?.editable);\n return (\n <td\n key={cell.id}\n role=\"gridcell\"\n data-slot=\"data-table-cell\"\n data-row-index={index}\n data-col-index={c}\n data-pinned={pin.pinned}\n data-pinned-edge={pin.edge ? \"\" : undefined}\n data-editable={canEdit ? \"\" : undefined}\n data-editing={isEditing ? \"\" : undefined}\n aria-colindex={c + 1}\n tabIndex={tabIndexFor(index, c)}\n style={{ width: column.getSize(), ...pin.style }}\n onDoubleClick={\n canEdit && !isEditing\n ? () => instance.editing.start({ rowId: row.id, columnId: column.id })\n : undefined\n }\n className={cn(\n \"relative align-middle outline-none\",\n isEditing ? \"px-1.5 py-1\" : cellPadding,\n alignClass[meta?.align ?? \"start\"],\n \"focus-visible:ring-[2px] focus-visible:ring-inset focus-visible:ring-[var(--ds-ring)]\",\n // Pinned cells cover what scrolls under them, so their background is\n // opaque card with the translucent hover / selected tint layered on.\n pin.pinned &&\n \"z-[1] bg-[var(--ds-card)] group-hover/row:bg-[linear-gradient(var(--ds-hover),var(--ds-hover))] group-data-[selected]/row:bg-[linear-gradient(var(--ds-primary-soft),var(--ds-primary-soft))] group-data-[active]/row:bg-[linear-gradient(var(--ds-primary-soft),var(--ds-primary-soft))]\",\n pin.pinned === \"start\" && pin.edge && \"shadow-[inset_-1px_0_0_var(--ds-border)]\",\n pin.pinned === \"end\" && pin.edge && \"shadow-[inset_1px_0_0_var(--ds-border)]\",\n !isEditing && \"truncate\",\n meta?.cellClassName,\n )}\n >\n {isEditing ? (\n <EditableCell\n cell={cell}\n instance={instance}\n onDone={() => {\n pendingFocus.current = { r: index, c };\n }}\n />\n ) : (\n <table.FlexRender cell={cell} />\n )}\n </td>\n );\n };\n\n return (\n <React.Fragment key={row.id}>\n <tr\n role=\"row\"\n data-slot=\"data-table-row\"\n data-index={virtualIndex}\n data-selected={selected ? \"\" : undefined}\n data-active={active ? \"\" : undefined}\n data-expanded={expanded ? \"\" : undefined}\n aria-rowindex={index + 2}\n aria-selected={table.options.enableRowSelection ? selected : undefined}\n ref={isVirtual ? virtualizer.measureElement : undefined}\n onClick={onRowClick ? (e) => onRowClick(row.original, e) : undefined}\n className={cn(\n \"group/row border-b border-[var(--ds-border-subtle)] transition-colors duration-[var(--ds-duration-fast)]\",\n \"hover:bg-[var(--ds-hover)] data-[selected]:bg-[var(--ds-primary-soft)]\",\n // Independent of selection: a detail pane highlights one row\n // without ticking its checkbox.\n \"data-[active]:bg-[var(--ds-primary-soft)]\",\n onRowClick && \"cursor-pointer\",\n rowClassName?.(row.original),\n )}\n >\n {cells.slice(0, splitAt).map((cell, c) => renderCell(cell, c))}\n <td aria-hidden data-slot=\"data-table-filler\" className=\"p-0\" />\n {cells.slice(splitAt).map((cell, i) => renderCell(cell, splitAt + i))}\n </tr>\n {expanded ? (\n <tr role=\"row\" data-slot=\"data-table-subrow\" className=\"border-b border-[var(--ds-border-subtle)]\">\n <td\n role=\"gridcell\"\n colSpan={colCount + 1}\n className=\"bg-[var(--ds-muted)] px-4 py-3 text-[length:var(--ds-text-body-sm)]\"\n >\n {renderSubComponent(row)}\n </td>\n </tr>\n ) : null}\n </React.Fragment>\n );\n };\n\n const skeletonRows = Array.from({ length: Math.min(8, table.state.pagination.pageSize) }, (_, i) => (\n <tr key={`skeleton-${i}`} aria-hidden data-slot=\"data-table-skeleton-row\" className=\"border-b border-[var(--ds-border-subtle)]\">\n {leafColumns.map((column) => (\n <td key={column.id} className={cellPadding} style={{ width: column.getSize() }}>\n <Skeleton className=\"h-3.5 w-3/4\" />\n </td>\n ))}\n <td className=\"p-0\" />\n </tr>\n ));\n\n return (\n <div data-slot=\"data-table\" className={cn(\"flex min-w-0 flex-col gap-3\", className)}>\n {errorMessage ? (\n <ErrorBanner message={errorMessage} onRetry={instance.error ? instance.refetch : undefined} />\n ) : null}\n {toolbar === false ? null : typeof toolbar === \"function\" ? (\n toolbar({ instance })\n ) : (\n <DataTableToolbar\n table={table}\n bulkActions={bulkActions}\n searchPlaceholder={searchPlaceholder}\n enableExport={enableExport}\n exportFileName={exportFileName}\n refresh={refreshProps}\n >\n {toolbarActions}\n </DataTableToolbar>\n )}\n <div\n ref={scrollRef}\n data-slot=\"data-table-container\"\n onScroll={onScroll}\n style={{ maxHeight: resolvedHeight }}\n className={cn(\n \"relative w-full overflow-auto rounded-[var(--ds-radius-md)] border border-[var(--ds-border)] bg-[var(--ds-card)]\",\n )}\n >\n <table\n ref={tableRef}\n role=\"grid\"\n data-slot=\"data-table-grid\"\n data-virtualized={isVirtual ? \"\" : undefined}\n aria-rowcount={rows.length + 1}\n aria-colcount={colCount}\n aria-busy={instance.isFetching || undefined}\n aria-multiselectable={table.options.enableRowSelection ? true : undefined}\n onKeyDown={onKeyDown}\n onFocus={onFocus}\n style={{ minWidth: table.getTotalSize() }}\n className={cn(\n \"w-full table-fixed border-collapse caption-bottom\",\n \"text-[length:var(--ds-text-body-sm)] leading-[var(--ds-text-body-sm--line-height)] text-[color:var(--ds-foreground)]\",\n )}\n >\n <thead data-slot=\"data-table-header\" className={cn(stickyHeader && \"sticky top-0 z-[2]\")}>\n {headerGroups.map((group) => {\n const endStart = group.headers.findIndex((h) => h.column.getIsPinned() === \"end\");\n const splitAt = endStart === -1 ? group.headers.length : endStart;\n const renderHead = (header: (typeof group.headers)[number], c: number) => {\n const column = header.column;\n const meta = column.columnDef.meta;\n const pin = pinAttrs(column, table);\n const sorted = column.getIsSorted();\n const def = column.columnDef;\n return (\n <th\n key={header.id}\n role=\"columnheader\"\n scope=\"col\"\n data-slot=\"data-table-head\"\n data-row-index={-1}\n data-col-index={c}\n data-pinned={pin.pinned}\n data-pinned-edge={pin.edge ? \"\" : undefined}\n aria-colindex={c + 1}\n aria-sort={\n sorted === \"asc\"\n ? \"ascending\"\n : sorted === \"desc\"\n ? \"descending\"\n : column.getCanSort()\n ? \"none\"\n : undefined\n }\n colSpan={header.colSpan}\n tabIndex={tabIndexFor(-1, c)}\n style={{ width: header.getSize(), ...pin.style }}\n className={cn(\n \"group/head relative h-10 align-middle font-medium outline-none\",\n headPadding,\n \"bg-[var(--ds-muted)] text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]\",\n \"border-b border-[var(--ds-border)]\",\n alignClass[meta?.align ?? \"start\"],\n \"focus-visible:ring-[2px] focus-visible:ring-inset focus-visible:ring-[var(--ds-ring)]\",\n pin.pinned && \"z-[3]\",\n pin.pinned === \"start\" && pin.edge && \"shadow-[inset_-1px_0_0_var(--ds-border)]\",\n pin.pinned === \"end\" && pin.edge && \"shadow-[inset_1px_0_0_var(--ds-border)]\",\n meta?.headerClassName,\n )}\n >\n {header.isPlaceholder ? null : typeof def.header === \"string\" ? (\n <DataTableColumnHeader column={column} title={def.header} />\n ) : (\n <table.FlexRender header={header} />\n )}\n {column.getCanResize() ? (\n <div\n data-slot=\"data-table-resizer\"\n data-resizing={column.getIsResizing() ? \"\" : undefined}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onDoubleClick={() => column.resetSize()}\n className={cn(\n \"absolute right-0 top-0 h-full w-1 cursor-col-resize touch-none select-none\",\n \"opacity-0 transition-opacity duration-[var(--ds-duration-fast)] hover:opacity-100 data-[resizing]:opacity-100\",\n \"bg-[var(--ds-ring)]\",\n )}\n />\n ) : null}\n </th>\n );\n };\n return (\n <tr key={group.id} role=\"row\" aria-rowindex={1}>\n {group.headers.slice(0, splitAt).map((header, c) => renderHead(header, c))}\n <th aria-hidden className=\"border-b border-[var(--ds-border)] bg-[var(--ds-muted)] p-0\" />\n {group.headers.slice(splitAt).map((header, i) => renderHead(header, splitAt + i))}\n </tr>\n );\n })}\n </thead>\n <tbody data-slot=\"data-table-body\">\n {showSkeleton ? skeletonRows : null}\n {showEmpty ? (\n <tr role=\"row\" data-slot=\"data-table-empty\">\n <td role=\"gridcell\" colSpan={colCount + 1} className=\"p-0\">\n {emptyState ?? (\n <div className=\"flex flex-col items-center justify-center gap-2 px-4 py-12 text-center text-[color:var(--ds-muted-foreground)]\">\n <Inbox aria-hidden className=\"size-6 text-[color:var(--ds-text-tertiary)]\" />\n <p className=\"text-[length:var(--ds-text-body-sm)]\">{emptyMessage}</p>\n </div>\n )}\n </td>\n </tr>\n ) : null}\n {virtualItems ? (\n <>\n {paddingTop > 0 ? (\n <tr aria-hidden data-slot=\"data-table-spacer\" style={{ height: paddingTop }}>\n <td colSpan={colCount + 1} className=\"p-0\" />\n </tr>\n ) : null}\n {virtualItems.map((item) => {\n const row = rows[item.index];\n return row ? renderRow(row, item.index, item.index) : null;\n })}\n {paddingBottom > 0 ? (\n <tr aria-hidden data-slot=\"data-table-spacer\" style={{ height: paddingBottom }}>\n <td colSpan={colCount + 1} className=\"p-0\" />\n </tr>\n ) : null}\n </>\n ) : (\n rows.map((row, index) => renderRow(row, index))\n )}\n </tbody>\n </table>\n {paginationMode === \"infinite\" && instance.isFetching && rows.length > 0 ? (\n <div\n data-slot=\"data-table-loading-more\"\n className=\"flex items-center justify-center gap-2 border-t border-[var(--ds-border-subtle)] py-2 text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]\"\n >\n <Spinner size={14} /> Loading more\n </div>\n ) : null}\n </div>\n {paginationMode === \"pages\" ? (\n <DataTablePagination table={table} pageSizeOptions={pageSizeOptions} />\n ) : paginationMode === \"infinite\" ? (\n <div className=\"text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]\">\n {rows.length} of {instance.total}\n </div>\n ) : null}\n </div>\n );\n}\n\nexport { DataTable, DataTableView };\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { DataTableFeatures, createColumnHelper, dataTableFeatures } from "./features.js";
3
- import { ClientSource, DataSource, DataTableCell, DataTableColumn, DataTableColumnDef, DataTableColumnMeta, DataTableEditable, DataTableEditingCell, DataTableInstance, DataTablePaginationMode, DataTableRow, DataTableState, DataTableTable, ServerSource, TableQuery, TableResult, UseDataTableOptions } from "./types.js";
4
- import { DataTable, DataTableProps, DataTableView, DataTableViewProps } from "./data-table.js";
5
- import { DataTableColumnHeader, DataTableColumnHeaderProps, DataTableExportMenu, DataTableExportMenuProps, DataTableFacetedFilter, DataTableFacetedFilterOption, DataTableFacetedFilterProps, DataTablePagination, DataTablePaginationProps, DataTableToolbar, DataTableToolbarProps, DataTableViewOptions, DataTableViewOptionsProps } from "./parts.js";
3
+ import { ClientSource, DataSource, DataTableAutoRefresh, DataTableAutoRefreshState, DataTableCell, DataTableColumn, DataTableColumnDef, DataTableColumnMeta, DataTableEditable, DataTableEditingCell, DataTableInstance, DataTablePaginationMode, DataTableRefreshPause, DataTableRow, DataTableState, DataTableTable, ServerSource, TableQuery, TableResult, UseDataTableOptions } from "./types.js";
4
+ import { DataTable, DataTableHandle, DataTableProps, DataTableView, DataTableViewProps } from "./data-table.js";
5
+ import { DataTableColumnHeader, DataTableColumnHeaderProps, DataTableExportMenu, DataTableExportMenuProps, DataTableFacetedFilter, DataTableFacetedFilterOption, DataTableFacetedFilterProps, DataTablePagination, DataTablePaginationProps, DataTableRefresh, DataTableRefreshProps, DataTableToolbar, DataTableToolbarProps, DataTableViewOptions, DataTableViewOptionsProps } from "./parts.js";
6
6
  import { useDataTable } from "./use-data-table.js";
7
7
  import { ExportCell, ExportSheet, downloadCsv, downloadExcel, toCsv, toSheet } from "./export.js";
8
- export { type ClientSource, type DataSource, DataTable, type DataTableCell, type DataTableColumn, type DataTableColumnDef, DataTableColumnHeader, type DataTableColumnHeaderProps, type DataTableColumnMeta, type DataTableEditable, type DataTableEditingCell, DataTableExportMenu, type DataTableExportMenuProps, DataTableFacetedFilter, type DataTableFacetedFilterOption, type DataTableFacetedFilterProps, type DataTableFeatures, type DataTableInstance, DataTablePagination, type DataTablePaginationMode, type DataTablePaginationProps, type DataTableProps, type DataTableRow, type DataTableState, type DataTableTable, DataTableToolbar, type DataTableToolbarProps, DataTableView, DataTableViewOptions, type DataTableViewOptionsProps, type DataTableViewProps, type ExportCell, type ExportSheet, type ServerSource, type TableQuery, type TableResult, type UseDataTableOptions, createColumnHelper, dataTableFeatures, downloadCsv, downloadExcel, toCsv, toSheet, useDataTable };
8
+ export { type ClientSource, type DataSource, DataTable, type DataTableAutoRefresh, type DataTableAutoRefreshState, type DataTableCell, type DataTableColumn, type DataTableColumnDef, DataTableColumnHeader, type DataTableColumnHeaderProps, type DataTableColumnMeta, type DataTableEditable, type DataTableEditingCell, DataTableExportMenu, type DataTableExportMenuProps, DataTableFacetedFilter, type DataTableFacetedFilterOption, type DataTableFacetedFilterProps, type DataTableFeatures, type DataTableHandle, type DataTableInstance, DataTablePagination, type DataTablePaginationMode, type DataTablePaginationProps, type DataTableProps, DataTableRefresh, type DataTableRefreshPause, type DataTableRefreshProps, type DataTableRow, type DataTableState, type DataTableTable, DataTableToolbar, type DataTableToolbarProps, DataTableView, DataTableViewOptions, type DataTableViewOptionsProps, type DataTableViewProps, type ExportCell, type ExportSheet, type ServerSource, type TableQuery, type TableResult, type UseDataTableOptions, createColumnHelper, dataTableFeatures, downloadCsv, downloadExcel, toCsv, toSheet, useDataTable };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { DataTableColumn, DataTableTable } from "./types.js";
2
+ import { DataTableAutoRefreshState, DataTableColumn, DataTableTable } from "./types.js";
3
3
  import * as React from "react";
4
4
  import { RowData } from "@tanstack/react-table";
5
5
  //#region src/components/data-table/parts.d.ts
@@ -61,13 +61,37 @@ export interface DataTableToolbarProps<Row extends RowData> extends Omit<React.C
61
61
  /** @default true */
62
62
  enableExport?: boolean;
63
63
  exportFileName?: string;
64
+ /**
65
+ * Freshness controls beside the search box. `DataTable` fills this in for
66
+ * every server source; a hand-built toolbar must pass it too (P-39).
67
+ */
68
+ refresh?: DataTableRefreshProps;
64
69
  }
65
70
  /**
66
71
  * Search box, one faceted filter per `meta.filter: "faceted"` column, a reset
67
72
  * when anything is filtered, and the view / export menus. While rows are
68
73
  * selected the left side becomes the selection summary and `bulkActions`.
69
74
  */
70
- declare function DataTableToolbar<Row extends RowData>({ table, searchPlaceholder, bulkActions, children, enableExport, exportFileName, className, ...props }: DataTableToolbarProps<Row>): React.JSX.Element;
75
+ declare function DataTableToolbar<Row extends RowData>({ table, searchPlaceholder, bulkActions, children, enableExport, exportFileName, refresh, className, ...props }: DataTableToolbarProps<Row>): React.JSX.Element;
76
+ export interface DataTableRefreshProps extends Omit<React.ComponentProps<"div">, "children"> {
77
+ /** Refetch the page on screen. The same query the interval drives. */
78
+ onRefresh: () => void;
79
+ /** Spins the icon and holds the button while a request is in flight. */
80
+ isFetching?: boolean;
81
+ /** `Date.now()` of the last successful response. */
82
+ lastUpdatedAt?: number | null;
83
+ /** `Date.now()` of the last failure; shown for ten seconds, then dropped. */
84
+ lastErrorAt?: number | null;
85
+ /** Renders the on/off switch and the live indicator. Omit for a table without `autoRefresh`. */
86
+ autoRefresh?: DataTableAutoRefreshState | null;
87
+ }
88
+ /**
89
+ * The freshness controls: Refresh, the last-updated stamp, and — only where a
90
+ * table opted in — the auto-refresh switch with its live indicator. Mandatory
91
+ * on every server-backed table (P-39); `DataTable` renders it beside the
92
+ * search box on its own.
93
+ */
94
+ declare function DataTableRefresh({ onRefresh, isFetching, lastUpdatedAt, lastErrorAt, autoRefresh, className, ...props }: DataTableRefreshProps): React.JSX.Element;
71
95
  export interface DataTablePaginationProps<Row extends RowData> extends React.ComponentProps<"div"> {
72
96
  table: DataTableTable<Row>;
73
97
  /** @default [10, 25, 50, 100] */
@@ -75,5 +99,5 @@ export interface DataTablePaginationProps<Row extends RowData> extends React.Com
75
99
  }
76
100
  declare function DataTablePagination<Row extends RowData>({ table, pageSizeOptions, className, ...props }: DataTablePaginationProps<Row>): React.JSX.Element;
77
101
  //#endregion
78
- export { DataTableColumnHeader, DataTableExportMenu, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableViewOptions };
102
+ export { DataTableColumnHeader, DataTableExportMenu, DataTableFacetedFilter, DataTablePagination, DataTableRefresh, DataTableToolbar, DataTableViewOptions };
79
103
  //# sourceMappingURL=parts.d.ts.map