@upbound/monarch-blocks 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/cel-filter-bar.js +10 -4
- package/dist/cel-filter-bar.js.map +1 -1
- package/dist/chart.js.map +1 -1
- package/dist/chat-interface.js +1 -1
- package/dist/chat-interface.js.map +1 -1
- package/dist/code-block.d.ts +20 -5
- package/dist/code-block.js +70 -12
- package/dist/code-block.js.map +1 -1
- package/dist/data-table.d.ts +4 -176
- package/dist/data-table.js +62 -19
- package/dist/data-table.js.map +1 -1
- package/dist/empty-view-DO36LNvk.d.ts +179 -0
- package/dist/filter-bar.js +13 -4
- package/dist/filter-bar.js.map +1 -1
- package/dist/floating-widget.js.map +1 -1
- package/dist/graph.css +73 -0
- package/dist/graph.d.ts +182 -0
- package/dist/graph.js +1787 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1089 -51
- package/dist/index.js.map +1 -1
- package/dist/page-header.js.map +1 -1
- package/dist/relative-time.js.map +1 -1
- package/dist/section-header.js.map +1 -1
- package/dist/section-nav.js.map +1 -1
- package/dist/timeline.js.map +1 -1
- package/package.json +9 -4
package/dist/code-block.js
CHANGED
|
@@ -32,7 +32,7 @@ var __objRest = (source, exclude) => {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
// src/code-block.tsx
|
|
35
|
-
import { useState } from "react";
|
|
35
|
+
import { useEffect, useState } from "react";
|
|
36
36
|
import { Icon } from "@upbound/monarch-core";
|
|
37
37
|
|
|
38
38
|
// src/lib/utils.ts
|
|
@@ -78,6 +78,36 @@ import {
|
|
|
78
78
|
TooltipContent,
|
|
79
79
|
TooltipTrigger
|
|
80
80
|
} from "@upbound/monarch-core";
|
|
81
|
+
|
|
82
|
+
// src/lib/highlight.ts
|
|
83
|
+
import { createHighlighter } from "shiki";
|
|
84
|
+
var CODE_BLOCK_LANGUAGES = ["tsx", "typescript", "bash", "shell", "json", "css", "yaml"];
|
|
85
|
+
var HIGHLIGHTER_KEY = "__monarch_shiki_highlighter__";
|
|
86
|
+
function getHighlighter() {
|
|
87
|
+
const g = globalThis;
|
|
88
|
+
if (!g[HIGHLIGHTER_KEY]) {
|
|
89
|
+
g[HIGHLIGHTER_KEY] = createHighlighter({
|
|
90
|
+
themes: ["github-light-high-contrast", "github-dark-dimmed"],
|
|
91
|
+
langs: [...CODE_BLOCK_LANGUAGES]
|
|
92
|
+
}).catch((error) => {
|
|
93
|
+
delete g[HIGHLIGHTER_KEY];
|
|
94
|
+
throw error;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return g[HIGHLIGHTER_KEY];
|
|
98
|
+
}
|
|
99
|
+
async function highlightCode(code, lang) {
|
|
100
|
+
const hl = await getHighlighter();
|
|
101
|
+
return hl.codeToHtml(code, {
|
|
102
|
+
lang,
|
|
103
|
+
themes: {
|
|
104
|
+
light: "github-light-high-contrast",
|
|
105
|
+
dark: "github-dark-dimmed"
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/code-block.tsx
|
|
81
111
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
82
112
|
function CodeBlock(_a) {
|
|
83
113
|
var _b = _a, {
|
|
@@ -118,24 +148,48 @@ function CodeBlockHeader(_a) {
|
|
|
118
148
|
}, props)
|
|
119
149
|
);
|
|
120
150
|
}
|
|
151
|
+
var LINE_NUMBER_GUTTER = cn(
|
|
152
|
+
"[&_code]:[counter-reset:line]",
|
|
153
|
+
"[&_.line]:before:[counter-increment:line]",
|
|
154
|
+
"[&_.line]:before:content-[counter(line)]",
|
|
155
|
+
"[&_.line]:before:inline-block",
|
|
156
|
+
"[&_.line]:before:w-6",
|
|
157
|
+
"[&_.line]:before:mr-3",
|
|
158
|
+
"[&_.line]:before:text-right",
|
|
159
|
+
"[&_.line]:before:text-muted-foreground",
|
|
160
|
+
"[&_.line]:before:text-[0.75rem]",
|
|
161
|
+
"[&_.line]:before:select-none"
|
|
162
|
+
);
|
|
121
163
|
function CodeBlockBody(_a) {
|
|
122
164
|
var _b = _a, {
|
|
123
165
|
className,
|
|
124
166
|
code,
|
|
125
|
-
html,
|
|
126
|
-
lineNumbers,
|
|
127
167
|
maxHeight,
|
|
128
168
|
copyButton,
|
|
129
169
|
downloadButton
|
|
130
170
|
} = _b, props = __objRest(_b, [
|
|
131
171
|
"className",
|
|
132
172
|
"code",
|
|
133
|
-
"html",
|
|
134
|
-
"lineNumbers",
|
|
135
173
|
"maxHeight",
|
|
136
174
|
"copyButton",
|
|
137
175
|
"downloadButton"
|
|
138
176
|
]);
|
|
177
|
+
const { content, lineNumbers } = code;
|
|
178
|
+
const [html, setHtml] = useState(null);
|
|
179
|
+
const language = code.type === "parsed" ? code.language : null;
|
|
180
|
+
useEffect(() => {
|
|
181
|
+
if (!language) {
|
|
182
|
+
setHtml(null);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
let cancelled = false;
|
|
186
|
+
highlightCode(content, language).then((result) => {
|
|
187
|
+
if (!cancelled) setHtml(result);
|
|
188
|
+
});
|
|
189
|
+
return () => {
|
|
190
|
+
cancelled = true;
|
|
191
|
+
};
|
|
192
|
+
}, [content, language]);
|
|
139
193
|
return /* @__PURE__ */ jsxs(CardContent, __spreadProps(__spreadValues({ "data-line-numbers": lineNumbers || void 0, className: cn("relative p-0!", className) }, props), { children: [
|
|
140
194
|
(copyButton || downloadButton) && /* @__PURE__ */ jsxs("div", { className: "absolute top-2 right-2 z-10 flex items-center gap-1 opacity-0 transition-opacity group-hover/code-block:opacity-100", children: [
|
|
141
195
|
copyButton,
|
|
@@ -146,16 +200,20 @@ function CodeBlockBody(_a) {
|
|
|
146
200
|
{
|
|
147
201
|
className: cn("overflow-x-auto", maxHeight && "overflow-y-auto"),
|
|
148
202
|
style: maxHeight ? { maxHeight } : void 0,
|
|
149
|
-
children:
|
|
203
|
+
children: /* @__PURE__ */ jsx(
|
|
150
204
|
"div",
|
|
151
205
|
{
|
|
152
|
-
className:
|
|
153
|
-
|
|
206
|
+
className: cn(
|
|
207
|
+
"[&_code]:font-mono [&_pre]:m-0 [&_pre]:p-4 group-data-[size=sm]/code-block:[&_pre]:p-3",
|
|
208
|
+
html && "[&_pre]:bg-transparent!",
|
|
209
|
+
lineNumbers && LINE_NUMBER_GUTTER
|
|
210
|
+
),
|
|
211
|
+
children: html ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { className: lineNumbers ? void 0 : "whitespace-pre", children: lineNumbers ? content.split("\n").map((line, i) => /* @__PURE__ */ jsxs("span", { className: "line", children: [
|
|
212
|
+
line,
|
|
213
|
+
"\n"
|
|
214
|
+
] }, i)) : content }) })
|
|
154
215
|
}
|
|
155
|
-
)
|
|
156
|
-
line,
|
|
157
|
-
"\n"
|
|
158
|
-
] }, i)) }) }) : /* @__PURE__ */ jsx("pre", { className: "p-4 group-data-[size=sm]/code-block:p-3", children: /* @__PURE__ */ jsx("code", { className: "font-mono whitespace-pre", children: code }) })
|
|
216
|
+
)
|
|
159
217
|
}
|
|
160
218
|
)
|
|
161
219
|
] }));
|
package/dist/code-block.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/code-block.tsx","../src/lib/utils.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useState } from 'react';\nimport { Icon } from '@upbound/monarch-core';\n\nimport { cn } from '@/lib/utils';\nimport {\n Card,\n CardContent,\n CardFooter,\n CardHeader,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@upbound/monarch-core';\n\nfunction CodeBlock({\n className,\n variant = 'default',\n size = 'default',\n ...props\n}: React.ComponentProps<'div'> & {\n variant?: 'default' | 'terminal';\n size?: 'default' | 'sm';\n}) {\n return (\n <Card\n data-slot=\"code-block\"\n data-variant={variant}\n data-size={size}\n role=\"region\"\n className={cn(\n 'group/code-block gap-0 overflow-hidden py-0',\n size === 'default' && 'text-[13px]',\n size === 'sm' && 'text-body-sm',\n variant === 'terminal' && 'border-terminal-border bg-terminal-bg text-terminal-fg ring-0',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CodeBlockHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <CardHeader\n className={cn(\n 'group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted flex flex-row items-center gap-2 border-b bg-[color-mix(in_oklch,var(--muted)_50%,var(--card))] py-4',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CodeBlockBody({\n className,\n code,\n html,\n lineNumbers,\n maxHeight,\n copyButton,\n downloadButton,\n ...props\n}: React.ComponentProps<'div'> & {\n code: string;\n html?: string;\n lineNumbers?: boolean;\n maxHeight?: string;\n copyButton?: React.ReactNode;\n downloadButton?: React.ReactNode;\n}) {\n // Layout note: the copy/download buttons must stay anchored to the\n // top-right of the visible code area when the content scrolls\n // horizontally. To make that work the relative containing block\n // (CardContent) must NOT be the scrollable element — otherwise\n // `right`-positioning is computed against the scrolled content edge and\n // the buttons move with the scroll. So the overflow lives on an inner\n // wrapper and the absolute button group is its sibling under CardContent.\n return (\n <CardContent data-line-numbers={lineNumbers || undefined} className={cn('relative p-0!', className)} {...props}>\n {(copyButton || downloadButton) && (\n <div className=\"absolute top-2 right-2 z-10 flex items-center gap-1 opacity-0 transition-opacity group-hover/code-block:opacity-100\">\n {copyButton}\n {downloadButton}\n </div>\n )}\n <div\n className={cn('overflow-x-auto', maxHeight && 'overflow-y-auto')}\n style={maxHeight ? { maxHeight } : undefined}\n >\n {html ? (\n <div\n className=\"[&_code]:font-mono [&_pre]:m-0 [&_pre]:bg-transparent! [&_pre]:p-4 group-data-[size=sm]/code-block:[&_pre]:p-3\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n ) : lineNumbers ? (\n <pre className=\"p-4 group-data-[size=sm]/code-block:p-3\">\n <code className=\"font-mono\">\n {code.split('\\n').map((line, i) => (\n <span key={i} className=\"line\">\n {line}\n {'\\n'}\n </span>\n ))}\n </code>\n </pre>\n ) : (\n <pre className=\"p-4 group-data-[size=sm]/code-block:p-3\">\n <code className=\"font-mono whitespace-pre\">{code}</code>\n </pre>\n )}\n </div>\n </CardContent>\n );\n}\n\nfunction CodeBlockFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <CardFooter\n className={cn(\n 'text-body-sm group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-footer-bg group-data-[variant=terminal]/code-block:text-terminal-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CodeBlockCopyButton({\n code,\n className,\n ...props\n}: Omit<React.ComponentProps<'button'>, 'children'> & {\n code: string;\n}) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n data-slot=\"code-block-copy-button\"\n onClick={handleCopy}\n className={cn(\n 'border-border bg-background inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border motion-safe:transition-colors',\n 'text-muted-foreground hover:bg-accent hover:text-foreground',\n 'focus-visible:ring-ring/30 focus-visible:ring-2 focus-visible:outline-none',\n 'group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted group-data-[variant=terminal]/code-block:hover:bg-terminal-muted-hover-bg group-data-[variant=terminal]/code-block:hover:text-terminal-muted-hover-fg',\n className,\n )}\n aria-label={copied ? 'Copied' : 'Copy code'}\n {...props}\n >\n {copied ? <Icon name=\"check\" size=\"sm\" className=\"text-green-500\" /> : <Icon name=\"copy\" size=\"sm\" />}\n </button>\n </TooltipTrigger>\n <TooltipContent>{copied ? 'Copied' : 'Copy'}</TooltipContent>\n </Tooltip>\n );\n}\n\nfunction CodeBlockDownloadButton({\n code,\n fileName,\n mimeType = 'text/plain',\n className,\n ...props\n}: Omit<React.ComponentProps<'button'>, 'children'> & {\n code: string;\n fileName: string;\n mimeType?: string;\n}) {\n const [downloaded, setDownloaded] = useState(false);\n\n const handleDownload = () => {\n const blob = new Blob([code], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = fileName;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n setDownloaded(true);\n setTimeout(() => setDownloaded(false), 2000);\n };\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n data-slot=\"code-block-download-button\"\n onClick={handleDownload}\n className={cn(\n 'border-border bg-background inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border motion-safe:transition-colors',\n 'text-muted-foreground hover:bg-accent hover:text-foreground',\n 'focus-visible:ring-ring/30 focus-visible:ring-2 focus-visible:outline-none',\n 'group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted group-data-[variant=terminal]/code-block:hover:bg-terminal-muted-hover-bg group-data-[variant=terminal]/code-block:hover:text-terminal-muted-hover-fg',\n className,\n )}\n aria-label={downloaded ? 'Downloaded' : 'Download code'}\n {...props}\n >\n {downloaded ? <Icon name=\"check\" size=\"sm\" className=\"text-green-500\" /> : <Icon name=\"download\" size=\"sm\" />}\n </button>\n </TooltipTrigger>\n <TooltipContent>{downloaded ? 'Downloaded' : 'Download'}</TooltipContent>\n </Tooltip>\n );\n}\n\nexport { CodeBlock, CodeBlockHeader, CodeBlockBody, CodeBlockFooter, CodeBlockCopyButton, CodeBlockDownloadButton };\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/code-block.tsx","../src/lib/utils.ts","../src/lib/highlight.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { Icon } from '@upbound/monarch-core';\n\nimport { cn } from '@/lib/utils';\nimport {\n Card,\n CardContent,\n CardFooter,\n CardHeader,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@upbound/monarch-core';\nimport { highlightCode, type CodeBlockLanguage } from './lib/highlight';\n\nexport type { CodeBlockLanguage } from './lib/highlight';\n\ntype CodeBlockCodeBase = {\n /** Raw code string — used for clipboard copy, download, and as the rendered text. */\n content: string;\n /** Numbers each line in the gutter. */\n lineNumbers?: boolean;\n};\n\nexport type CodeBlockCode =\n | (CodeBlockCodeBase & {\n /** Syntax-highlighted with Shiki inside CodeBlockBody — no highlighting step needed on your end. */\n type: 'parsed';\n language: CodeBlockLanguage;\n })\n | (CodeBlockCodeBase & {\n /** Rendered as plain, unhighlighted text. */\n type: 'raw';\n });\n\nfunction CodeBlock({\n className,\n variant = 'default',\n size = 'default',\n ...props\n}: React.ComponentProps<'div'> & {\n variant?: 'default' | 'terminal';\n size?: 'default' | 'sm';\n}) {\n return (\n <Card\n data-slot=\"code-block\"\n data-variant={variant}\n data-size={size}\n role=\"region\"\n className={cn(\n 'group/code-block gap-0 overflow-hidden py-0',\n size === 'default' && 'text-[13px]',\n size === 'sm' && 'text-body-sm',\n variant === 'terminal' && 'border-terminal-border bg-terminal-bg text-terminal-fg ring-0',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CodeBlockHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <CardHeader\n className={cn(\n 'group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted flex flex-row items-center gap-2 border-b bg-[color-mix(in_oklch,var(--muted)_50%,var(--card))] py-4',\n className,\n )}\n {...props}\n />\n );\n}\n\nconst LINE_NUMBER_GUTTER = cn(\n '[&_code]:[counter-reset:line]',\n '[&_.line]:before:[counter-increment:line]',\n '[&_.line]:before:content-[counter(line)]',\n '[&_.line]:before:inline-block',\n '[&_.line]:before:w-6',\n '[&_.line]:before:mr-3',\n '[&_.line]:before:text-right',\n '[&_.line]:before:text-muted-foreground',\n '[&_.line]:before:text-[0.75rem]',\n '[&_.line]:before:select-none',\n);\n\nfunction CodeBlockBody({\n className,\n code,\n maxHeight,\n copyButton,\n downloadButton,\n ...props\n}: Omit<React.ComponentProps<'div'>, 'children'> & {\n code: CodeBlockCode;\n maxHeight?: string;\n copyButton?: React.ReactNode;\n downloadButton?: React.ReactNode;\n}) {\n const { content, lineNumbers } = code;\n const [html, setHtml] = useState<string | null>(null);\n const language = code.type === 'parsed' ? code.language : null;\n\n useEffect(() => {\n if (!language) {\n setHtml(null);\n return;\n }\n\n let cancelled = false;\n highlightCode(content, language).then(result => {\n if (!cancelled) setHtml(result);\n });\n\n return () => {\n cancelled = true;\n };\n }, [content, language]);\n\n // Layout note: the copy/download buttons must stay anchored to the\n // top-right of the visible code area when the content scrolls\n // horizontally. To make that work the relative containing block\n // (CardContent) must NOT be the scrollable element — otherwise\n // `right`-positioning is computed against the scrolled content edge and\n // the buttons move with the scroll. So the overflow lives on an inner\n // wrapper and the absolute button group is its sibling under CardContent.\n return (\n <CardContent data-line-numbers={lineNumbers || undefined} className={cn('relative p-0!', className)} {...props}>\n {(copyButton || downloadButton) && (\n <div className=\"absolute top-2 right-2 z-10 flex items-center gap-1 opacity-0 transition-opacity group-hover/code-block:opacity-100\">\n {copyButton}\n {downloadButton}\n </div>\n )}\n <div\n className={cn('overflow-x-auto', maxHeight && 'overflow-y-auto')}\n style={maxHeight ? { maxHeight } : undefined}\n >\n <div\n className={cn(\n '[&_code]:font-mono [&_pre]:m-0 [&_pre]:p-4 group-data-[size=sm]/code-block:[&_pre]:p-3',\n html && '[&_pre]:bg-transparent!',\n lineNumbers && LINE_NUMBER_GUTTER,\n )}\n >\n {html ? (\n <div dangerouslySetInnerHTML={{ __html: html }} />\n ) : (\n <pre>\n <code className={lineNumbers ? undefined : 'whitespace-pre'}>\n {lineNumbers\n ? content.split('\\n').map((line, i) => (\n <span key={i} className=\"line\">\n {line}\n {'\\n'}\n </span>\n ))\n : content}\n </code>\n </pre>\n )}\n </div>\n </div>\n </CardContent>\n );\n}\n\nfunction CodeBlockFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <CardFooter\n className={cn(\n 'text-body-sm group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-footer-bg group-data-[variant=terminal]/code-block:text-terminal-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CodeBlockCopyButton({\n code,\n className,\n ...props\n}: Omit<React.ComponentProps<'button'>, 'children'> & {\n code: string;\n}) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n data-slot=\"code-block-copy-button\"\n onClick={handleCopy}\n className={cn(\n 'border-border bg-background inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border motion-safe:transition-colors',\n 'text-muted-foreground hover:bg-accent hover:text-foreground',\n 'focus-visible:ring-ring/30 focus-visible:ring-2 focus-visible:outline-none',\n 'group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted group-data-[variant=terminal]/code-block:hover:bg-terminal-muted-hover-bg group-data-[variant=terminal]/code-block:hover:text-terminal-muted-hover-fg',\n className,\n )}\n aria-label={copied ? 'Copied' : 'Copy code'}\n {...props}\n >\n {copied ? <Icon name=\"check\" size=\"sm\" className=\"text-green-500\" /> : <Icon name=\"copy\" size=\"sm\" />}\n </button>\n </TooltipTrigger>\n <TooltipContent>{copied ? 'Copied' : 'Copy'}</TooltipContent>\n </Tooltip>\n );\n}\n\nfunction CodeBlockDownloadButton({\n code,\n fileName,\n mimeType = 'text/plain',\n className,\n ...props\n}: Omit<React.ComponentProps<'button'>, 'children'> & {\n code: string;\n fileName: string;\n mimeType?: string;\n}) {\n const [downloaded, setDownloaded] = useState(false);\n\n const handleDownload = () => {\n const blob = new Blob([code], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = fileName;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n setDownloaded(true);\n setTimeout(() => setDownloaded(false), 2000);\n };\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n data-slot=\"code-block-download-button\"\n onClick={handleDownload}\n className={cn(\n 'border-border bg-background inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border motion-safe:transition-colors',\n 'text-muted-foreground hover:bg-accent hover:text-foreground',\n 'focus-visible:ring-ring/30 focus-visible:ring-2 focus-visible:outline-none',\n 'group-data-[variant=terminal]/code-block:border-terminal-border group-data-[variant=terminal]/code-block:bg-terminal-bg group-data-[variant=terminal]/code-block:text-terminal-muted group-data-[variant=terminal]/code-block:hover:bg-terminal-muted-hover-bg group-data-[variant=terminal]/code-block:hover:text-terminal-muted-hover-fg',\n className,\n )}\n aria-label={downloaded ? 'Downloaded' : 'Download code'}\n {...props}\n >\n {downloaded ? <Icon name=\"check\" size=\"sm\" className=\"text-green-500\" /> : <Icon name=\"download\" size=\"sm\" />}\n </button>\n </TooltipTrigger>\n <TooltipContent>{downloaded ? 'Downloaded' : 'Download'}</TooltipContent>\n </Tooltip>\n );\n}\n\nexport { CodeBlock, CodeBlockHeader, CodeBlockBody, CodeBlockFooter, CodeBlockCopyButton, CodeBlockDownloadButton };\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport function sortBy<T>(items: T[], getKey: (item: T) => string): T[] {\n return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));\n}\n","import { createHighlighter, type Highlighter } from 'shiki';\n\nexport const CODE_BLOCK_LANGUAGES = ['tsx', 'typescript', 'bash', 'shell', 'json', 'css', 'yaml'] as const;\n\nexport type CodeBlockLanguage = (typeof CODE_BLOCK_LANGUAGES)[number];\n\nconst HIGHLIGHTER_KEY = '__monarch_shiki_highlighter__';\n\ntype HighlighterGlobal = typeof globalThis & {\n [HIGHLIGHTER_KEY]?: Promise<Highlighter>;\n};\n\n/**\n * Cache the in-flight Promise, not the resolved instance. `createHighlighter`\n * is async — storing only after `await` lets every concurrent CodeBlockBody\n * start a new highlighter (Shiki warns at 10/20/30 instances). `globalThis`\n * keeps the same promise across HMR module re-evals in the same realm.\n */\nfunction getHighlighter(): Promise<Highlighter> {\n const g = globalThis as HighlighterGlobal;\n if (!g[HIGHLIGHTER_KEY]) {\n g[HIGHLIGHTER_KEY] = createHighlighter({\n themes: ['github-light-high-contrast', 'github-dark-dimmed'],\n langs: [...CODE_BLOCK_LANGUAGES],\n }).catch(error => {\n delete g[HIGHLIGHTER_KEY];\n throw error;\n });\n }\n return g[HIGHLIGHTER_KEY];\n}\n\n/**\n * Highlight a code string with Shiki dual themes. Returns raw HTML safe to\n * render via dangerouslySetInnerHTML.\n *\n * Light theme renders as inline `color:` / `background-color:`.\n * Dark theme renders as CSS variables `--shiki-dark` / `--shiki-dark-bg`.\n */\nexport async function highlightCode(code: string, lang: CodeBlockLanguage): Promise<string> {\n const hl = await getHighlighter();\n return hl.codeToHtml(code, {\n lang,\n themes: {\n light: 'github-light-high-contrast',\n dark: 'github-dark-dimmed',\n },\n });\n}\n"],"mappings":"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","names":[]}
|
package/dist/data-table.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import { ReactNode, Dispatch, SetStateAction, ComponentType } from 'react';
|
|
3
3
|
import { RowData, ColumnFilter, Cell, Column, ColumnOrderState, Row, ColumnDef, CellContext, HeaderGroup, TableOptions, TableState, InitialTableState, SortingFn, FilterFn, ExpandedState, ColumnFiltersState, PaginationState, SortingState, VisibilityState, ColumnPinningState, GroupingState, OnChangeFn, ColumnSizingState } from '@tanstack/react-table';
|
|
4
|
-
import { DropdownMenuItem
|
|
4
|
+
import { DropdownMenuItem } from '@upbound/monarch-core';
|
|
5
5
|
import { f as CelFilterSchema, g as CelFilterTree, k as CompileResult, i as CelRestrictedOptionSelectPayload } from './types-BULiU2qC.js';
|
|
6
|
+
import { T as TableDataState, a as DataTableEmptyView } from './empty-view-DO36LNvk.js';
|
|
7
|
+
export { D as DataTableEmptyConfig, d as defaultEmptyConfig, b as defaultErrorConfig, c as defaultNoFilterFoundConfig } from './empty-view-DO36LNvk.js';
|
|
6
8
|
|
|
7
9
|
/** A single entry (or nested submenu) in a cell's contextual right-click menu, alongside the built-in "Filter by this value" item. */
|
|
8
10
|
type ContextualMenuAction<TData extends RowData = RowData, TValue = unknown> = {
|
|
@@ -86,180 +88,6 @@ declare function TimestampCell({ timestamp }: {
|
|
|
86
88
|
timestamp?: Date | string | number;
|
|
87
89
|
}): React$1.JSX.Element;
|
|
88
90
|
|
|
89
|
-
/**
|
|
90
|
-
* Non-CEL column filter definitions — the `meta.filter` vocabulary consumed by
|
|
91
|
-
* contextual (right-click cell) filtering and by the plain filter bar.
|
|
92
|
-
* Mirrors TableWrapper's `Filters/types.ts` shapes; `id` is omitted here since
|
|
93
|
-
* it comes from the owning `ColumnDef.id`, not the filter definition itself.
|
|
94
|
-
*/
|
|
95
|
-
type ColumnFilterType = 'checkbox' | 'radio' | 'dateRange' | 'text' | 'multiText';
|
|
96
|
-
type ColumnFilterOption = {
|
|
97
|
-
label: string;
|
|
98
|
-
value: string;
|
|
99
|
-
disabled?: boolean;
|
|
100
|
-
children?: ColumnFilterOption[];
|
|
101
|
-
};
|
|
102
|
-
type FetchColumnFilterOptionsArgs = {
|
|
103
|
-
query: string;
|
|
104
|
-
page: number;
|
|
105
|
-
signal: AbortSignal;
|
|
106
|
-
};
|
|
107
|
-
type FetchColumnFilterOptionsResult = {
|
|
108
|
-
items: ColumnFilterOption[];
|
|
109
|
-
hasMore: boolean;
|
|
110
|
-
};
|
|
111
|
-
type FetchColumnFilterOptions = (args: FetchColumnFilterOptionsArgs) => Promise<FetchColumnFilterOptionsResult>;
|
|
112
|
-
type ColumnFilterBase = {
|
|
113
|
-
title: string;
|
|
114
|
-
type: ColumnFilterType;
|
|
115
|
-
order?: number;
|
|
116
|
-
};
|
|
117
|
-
type StaticCheckboxColumnFilter = ColumnFilterBase & {
|
|
118
|
-
type: 'checkbox';
|
|
119
|
-
options: string[] | ColumnFilterOption[];
|
|
120
|
-
fetchFilterOptions?: never;
|
|
121
|
-
/** Whether the chip's value popup is a searchable Combobox. Defaults to `true`. */
|
|
122
|
-
searchable?: boolean;
|
|
123
|
-
};
|
|
124
|
-
type AsyncCheckboxColumnFilter = ColumnFilterBase & {
|
|
125
|
-
type: 'checkbox';
|
|
126
|
-
fetchFilterOptions: FetchColumnFilterOptions;
|
|
127
|
-
options?: never;
|
|
128
|
-
/** Whether the chip's value popup is a searchable Combobox. Defaults to `true`. */
|
|
129
|
-
searchable?: boolean;
|
|
130
|
-
};
|
|
131
|
-
type CheckboxColumnFilter = StaticCheckboxColumnFilter | AsyncCheckboxColumnFilter;
|
|
132
|
-
type RadioColumnFilter = ColumnFilterBase & {
|
|
133
|
-
type: 'radio';
|
|
134
|
-
options: string[] | ColumnFilterOption[];
|
|
135
|
-
/** Whether the chip's value popup is a searchable Combobox. Defaults to `true`. */
|
|
136
|
-
searchable?: boolean;
|
|
137
|
-
};
|
|
138
|
-
type DateRangeColumnFilter = ColumnFilterBase & {
|
|
139
|
-
type: 'dateRange';
|
|
140
|
-
/** When true, always show time inputs. When false, never show them. When omitted, auto-detect from value. */
|
|
141
|
-
includeTime?: boolean;
|
|
142
|
-
};
|
|
143
|
-
type TextColumnFilter = ColumnFilterBase & {
|
|
144
|
-
type: 'text';
|
|
145
|
-
placeholder?: string;
|
|
146
|
-
};
|
|
147
|
-
type MultiTextColumnFilter = ColumnFilterBase & {
|
|
148
|
-
type: 'multiText';
|
|
149
|
-
/** Defaults to comma (`,`) when omitted. */
|
|
150
|
-
delimiter?: string;
|
|
151
|
-
description?: string;
|
|
152
|
-
placeholder?: string;
|
|
153
|
-
};
|
|
154
|
-
type ColumnFilterDefinition = CheckboxColumnFilter | DateRangeColumnFilter | RadioColumnFilter | TextColumnFilter | MultiTextColumnFilter;
|
|
155
|
-
type CheckboxColumnFilterValue = string[] | undefined;
|
|
156
|
-
type RadioColumnFilterValue = string | undefined;
|
|
157
|
-
type DateRangeColumnFilterValue = {
|
|
158
|
-
startDate: Date | null;
|
|
159
|
-
endDate: Date | null;
|
|
160
|
-
} | undefined;
|
|
161
|
-
type TextColumnFilterValue = string | undefined;
|
|
162
|
-
type MultiTextColumnFilterValue = string[] | undefined;
|
|
163
|
-
type ColumnFilterValue = CheckboxColumnFilterValue | RadioColumnFilterValue | DateRangeColumnFilterValue | TextColumnFilterValue | MultiTextColumnFilterValue;
|
|
164
|
-
|
|
165
|
-
/** Derives a contextual (right-click cell) column-filter value from a cell. */
|
|
166
|
-
type ContextualFilterValueParser<TData extends RowData, TValue> = (cell: Cell<TData, TValue>) => ColumnFilterValue | undefined;
|
|
167
|
-
/** Derives a contextual (right-click cell) global-search term from a cell. */
|
|
168
|
-
type ContextualGlobalSearchValueParser<TData extends RowData, TValue> = (cell: Cell<TData, TValue>) => string | undefined;
|
|
169
|
-
/** A fixed-width grid track: sizes to content or an explicit CSS length. */
|
|
170
|
-
type GridColumnFixed = {
|
|
171
|
-
fixed: string;
|
|
172
|
-
flex?: never;
|
|
173
|
-
};
|
|
174
|
-
type GridColumnFlexContentMin = {
|
|
175
|
-
min: 'max-content' | 'min-content';
|
|
176
|
-
minCap?: string;
|
|
177
|
-
};
|
|
178
|
-
type GridColumnFlexFixedMin = {
|
|
179
|
-
min?: string;
|
|
180
|
-
minCap?: never;
|
|
181
|
-
};
|
|
182
|
-
/** A proportional grid track: shares space by weight, with optional min/max. */
|
|
183
|
-
type GridColumnFlex = {
|
|
184
|
-
flex: number;
|
|
185
|
-
max?: string;
|
|
186
|
-
fixed?: never;
|
|
187
|
-
} & (GridColumnFlexContentMin | GridColumnFlexFixedMin);
|
|
188
|
-
/**
|
|
189
|
-
* Column sizing for grid layout mode.
|
|
190
|
-
*
|
|
191
|
-
* Fixed column (sizes to content or explicit value):
|
|
192
|
-
* { fixed: 'max-content' }
|
|
193
|
-
* { fixed: '200px' }
|
|
194
|
-
*
|
|
195
|
-
* Proportional column (shares space by weight, with optional min/max):
|
|
196
|
-
* { flex: 2, min: '100px' }
|
|
197
|
-
* { flex: 0.5, min: 'max-content' }
|
|
198
|
-
* { flex: 0.5, min: 'max-content', minCap: '200px' }
|
|
199
|
-
* { flex: 1, min: '80px', max: '500px' }
|
|
200
|
-
*/
|
|
201
|
-
type GridColumnSizing = GridColumnFixed | GridColumnFlex;
|
|
202
|
-
/**
|
|
203
|
-
* Column-def metadata `DataTable` reads — a straight port of TableWrapper's
|
|
204
|
-
* `ColumnMeta` module augmentation. Import this file for its side effect
|
|
205
|
-
* (`import '@/lib/data-table/table-meta'`) wherever a `ColumnDef` is authored
|
|
206
|
-
* with any of these fields.
|
|
207
|
-
*/
|
|
208
|
-
declare module '@tanstack/react-table' {
|
|
209
|
-
interface ColumnMeta<TData extends RowData, TValue> {
|
|
210
|
-
/** Pins the column left or right. Pinned columns are excluded from column reordering. */
|
|
211
|
-
pinning?: 'left' | 'right';
|
|
212
|
-
/** Marks an actions column — hides its header label and excludes it from contextual filtering. */
|
|
213
|
-
actions?: boolean;
|
|
214
|
-
/** The column's non-CEL filter definition, read by the plain filter bar and contextual filtering. */
|
|
215
|
-
filter?: ColumnFilterDefinition;
|
|
216
|
-
/** Parses a cell into a filter value for contextual (right-click) cell filtering. */
|
|
217
|
-
contextualFilterValue?: ContextualFilterValueParser<TData, TValue>;
|
|
218
|
-
/** Parses a cell into a search term for contextual (right-click) global search. */
|
|
219
|
-
contextualGlobalSearchValue?: ContextualGlobalSearchValueParser<TData, TValue>;
|
|
220
|
-
/** When true, the column is used only for filtering and is never rendered in the table. */
|
|
221
|
-
filterOnly?: boolean;
|
|
222
|
-
/** Column sizing for `layout="grid"` mode — see `GridColumnSizing`. */
|
|
223
|
-
grid?: GridColumnSizing;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
type TableDataState = 'empty' | 'loading' | 'error' | 'success';
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Monarch-native equivalent of TableWrapper's `EmptyConfig` — same four
|
|
231
|
-
* states (error / empty / filtered-empty), rebuilt on Monarch's `Empty`
|
|
232
|
-
* compound API instead of a single props-driven component. Two deliberate
|
|
233
|
-
* adaptations: `icon` takes a Monarch `IconName` (no FontAwesome dependency),
|
|
234
|
-
* and `action` is a rendered node rather than a `ComponentType` reference.
|
|
235
|
-
* `details` has no native `Empty` slot — it composes `Alert` instead.
|
|
236
|
-
*/
|
|
237
|
-
type DataTableEmptyConfig = {
|
|
238
|
-
icon?: IconName;
|
|
239
|
-
header?: React$1.ReactNode;
|
|
240
|
-
subheader?: React$1.ReactNode;
|
|
241
|
-
details?: React$1.ReactNode;
|
|
242
|
-
action?: React$1.ReactNode;
|
|
243
|
-
className?: string;
|
|
244
|
-
wrapperClassName?: string;
|
|
245
|
-
};
|
|
246
|
-
declare const defaultErrorConfig: DataTableEmptyConfig;
|
|
247
|
-
declare const defaultEmptyConfig: DataTableEmptyConfig;
|
|
248
|
-
declare const defaultNoFilterFoundConfig: DataTableEmptyConfig;
|
|
249
|
-
type DataTableEmptyView = {
|
|
250
|
-
empty?: DataTableEmptyConfig;
|
|
251
|
-
error?: DataTableEmptyConfig;
|
|
252
|
-
filter?: DataTableEmptyConfig;
|
|
253
|
-
};
|
|
254
|
-
declare function DataTableEmptyView({ emptyView, tableState, filterCount, resetFilters, className, }: {
|
|
255
|
-
emptyView?: DataTableEmptyView;
|
|
256
|
-
/** `'success'`/`'loading'` render nothing here — the table body handles those. */
|
|
257
|
-
tableState: TableDataState;
|
|
258
|
-
filterCount: number;
|
|
259
|
-
resetFilters: () => void;
|
|
260
|
-
className?: string;
|
|
261
|
-
}): React$1.JSX.Element;
|
|
262
|
-
|
|
263
91
|
type RowCountRelation = 'eq' | 'gt';
|
|
264
92
|
/** Pass `true` for defaults, `false` to disable the footer entirely (handled by the caller, not this component), or an object to toggle individual parts. */
|
|
265
93
|
type DataTablePaginationConfig = boolean | {
|
|
@@ -533,4 +361,4 @@ type ViewFilterProps<TData extends RowData> = {
|
|
|
533
361
|
*/
|
|
534
362
|
declare function ViewFilter<TData extends RowData>({ columns, columnFilters, onColumnFiltersChange, className, }: ViewFilterProps<TData>): React$1.JSX.Element;
|
|
535
363
|
|
|
536
|
-
export { CellContextualFilter, type CellContextualFilterProps, ColumnOptions, type ColumnOptionsProps, type ContextualMenuAction, DataTable, DataTableBody, type DataTableCelFilterConfig, DataTableCell,
|
|
364
|
+
export { CellContextualFilter, type CellContextualFilterProps, ColumnOptions, type ColumnOptionsProps, type ContextualMenuAction, DataTable, DataTableBody, type DataTableCelFilterConfig, DataTableCell, DataTableEmptyView, DataTableExpandedRow, type DataTableFilterVisibilityConfig, DataTableGroupRow, DataTableHeader, DataTablePagination, type DataTablePaginationConfig, type DataTablePaginationProps, type DataTableProps, DataTableRow, type DataTableRowProps, DataTableSkeletonBody, DataTableValueCell, type DataTableValueCellProps, ExpandButton, RowActionItem, RowActions, type RowCountRelation, type StickyHeaderConfig, type TableHookOptions, type TableLayout, TimestampCell, ViewFilter, type ViewFilterProps, getActionsColumnDefinition, getExpandColumnDefinition, normalizePageSizeOptions };
|
package/dist/data-table.js
CHANGED
|
@@ -99,7 +99,15 @@ function CellContextualFilter({
|
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
return /* @__PURE__ */ jsxs(ContextMenuContent, { children: [
|
|
102
|
-
/* @__PURE__ */ jsx(
|
|
102
|
+
/* @__PURE__ */ jsx(
|
|
103
|
+
ContextMenuItem,
|
|
104
|
+
{
|
|
105
|
+
disabled,
|
|
106
|
+
onClick: (event) => event.stopPropagation(),
|
|
107
|
+
onSelect: handleSelect,
|
|
108
|
+
children: "Filter by this value"
|
|
109
|
+
}
|
|
110
|
+
),
|
|
103
111
|
contextualMenuActions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
104
112
|
/* @__PURE__ */ jsx(ContextMenuSeparator, {}),
|
|
105
113
|
contextualMenuActions.map(renderAction)
|
|
@@ -152,6 +160,9 @@ var twMerge = extendTailwindMerge({
|
|
|
152
160
|
function cn(...inputs) {
|
|
153
161
|
return twMerge(clsx(inputs));
|
|
154
162
|
}
|
|
163
|
+
function sortBy(items, getKey) {
|
|
164
|
+
return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));
|
|
165
|
+
}
|
|
155
166
|
|
|
156
167
|
// src/lib/data-table/utils.ts
|
|
157
168
|
var TO_EACH_SIDE = 2;
|
|
@@ -601,8 +612,25 @@ function RowActions({
|
|
|
601
612
|
contentClassName
|
|
602
613
|
}) {
|
|
603
614
|
return /* @__PURE__ */ jsxs3(DropdownMenu2, { children: [
|
|
604
|
-
/* @__PURE__ */ jsx4(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx4(
|
|
605
|
-
|
|
615
|
+
/* @__PURE__ */ jsx4(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx4(
|
|
616
|
+
Button2,
|
|
617
|
+
{
|
|
618
|
+
variant: "ghost",
|
|
619
|
+
size: "icon-xs",
|
|
620
|
+
"aria-label": "Row actions",
|
|
621
|
+
onClick: (e) => e.stopPropagation(),
|
|
622
|
+
children: /* @__PURE__ */ jsx4(Icon2, { name: "ellipsis-vertical", size: "sm" })
|
|
623
|
+
}
|
|
624
|
+
) }),
|
|
625
|
+
/* @__PURE__ */ jsx4(
|
|
626
|
+
DropdownMenuContent2,
|
|
627
|
+
{
|
|
628
|
+
align,
|
|
629
|
+
className: contentClassName,
|
|
630
|
+
onClick: (event) => event.stopPropagation(),
|
|
631
|
+
children
|
|
632
|
+
}
|
|
633
|
+
)
|
|
606
634
|
] });
|
|
607
635
|
}
|
|
608
636
|
function RowActionItem({
|
|
@@ -1787,7 +1815,10 @@ function CelAddFilterButton({
|
|
|
1787
1815
|
list.push(column);
|
|
1788
1816
|
groupMap.set(key, list);
|
|
1789
1817
|
}
|
|
1790
|
-
const groups =
|
|
1818
|
+
const groups = sortBy(
|
|
1819
|
+
Array.from(groupMap.entries()).map(([value, items]) => ({ value, items: sortBy(items, (item) => item.title) })),
|
|
1820
|
+
(group) => group.value
|
|
1821
|
+
);
|
|
1791
1822
|
return /* @__PURE__ */ jsxs4(
|
|
1792
1823
|
Combobox,
|
|
1793
1824
|
{
|
|
@@ -1798,7 +1829,7 @@ function CelAddFilterButton({
|
|
|
1798
1829
|
if (column) onSelect(column.id);
|
|
1799
1830
|
},
|
|
1800
1831
|
children: [
|
|
1801
|
-
/* @__PURE__ */ jsxs4(ComboboxTrigger, { "aria-label": "Add filter", render: /* @__PURE__ */ jsx5(Button3, { variant: "outline" }), children: [
|
|
1832
|
+
/* @__PURE__ */ jsxs4(ComboboxTrigger, { "aria-label": "Add filter", showIndicator: false, render: /* @__PURE__ */ jsx5(Button3, { variant: "outline" }), children: [
|
|
1802
1833
|
/* @__PURE__ */ jsx5(Icon3, { name: "plus", "data-icon": "inline-start" }),
|
|
1803
1834
|
"Add filter"
|
|
1804
1835
|
] }),
|
|
@@ -2015,7 +2046,7 @@ function CelCheckboxComboboxPill({
|
|
|
2015
2046
|
container
|
|
2016
2047
|
}) {
|
|
2017
2048
|
var _a;
|
|
2018
|
-
const options = (_a = columnDef.options) != null ? _a : [];
|
|
2049
|
+
const options = sortBy((_a = columnDef.options) != null ? _a : [], (o) => o.label);
|
|
2019
2050
|
const value = isCheckboxCelValue(condition.value) ? condition.value : [];
|
|
2020
2051
|
const selected = options.filter((option) => value.includes(option.value));
|
|
2021
2052
|
const allowedOperators = getAllowedOperators(columnDef);
|
|
@@ -2104,7 +2135,7 @@ function CelRadioComboboxPill({
|
|
|
2104
2135
|
container
|
|
2105
2136
|
}) {
|
|
2106
2137
|
var _a, _b;
|
|
2107
|
-
const options = (_a = columnDef.options) != null ? _a : [];
|
|
2138
|
+
const options = sortBy((_a = columnDef.options) != null ? _a : [], (o) => o.label);
|
|
2108
2139
|
const value = typeof condition.value === "string" ? condition.value : "";
|
|
2109
2140
|
const selected = (_b = options.find((option) => option.value === value)) != null ? _b : null;
|
|
2110
2141
|
const allowedOperators = getAllowedOperators(columnDef);
|
|
@@ -3153,6 +3184,7 @@ function DataTablePagination({
|
|
|
3153
3184
|
PaginationLink,
|
|
3154
3185
|
{
|
|
3155
3186
|
href: "#",
|
|
3187
|
+
size: "icon",
|
|
3156
3188
|
isActive: page === currentPage,
|
|
3157
3189
|
onClick: (e) => {
|
|
3158
3190
|
e.preventDefault();
|
|
@@ -3264,9 +3296,9 @@ function DataTableSortIcon({ sortOrder }) {
|
|
|
3264
3296
|
return /* @__PURE__ */ jsx9(
|
|
3265
3297
|
Icon7,
|
|
3266
3298
|
{
|
|
3267
|
-
name: sortOrder === "asc" ? "arrow-up" : "arrow-down",
|
|
3268
3299
|
size: "xs",
|
|
3269
|
-
|
|
3300
|
+
name: sortOrder === "asc" ? "arrow-up" : "arrow-down",
|
|
3301
|
+
className: "text-foreground group-hover/col-actions:text-foreground group-data-[state=open]/col-actions:text-foreground mr-0.5 shrink-0"
|
|
3270
3302
|
}
|
|
3271
3303
|
);
|
|
3272
3304
|
}
|
|
@@ -3358,7 +3390,7 @@ function HeaderCellContent({
|
|
|
3358
3390
|
"aria-label": shouldShowActionsMenu ? headerTitle ? `${headerTitle} column actions` : "Column actions" : void 0,
|
|
3359
3391
|
className: cn(
|
|
3360
3392
|
"group/col-actions text-muted-foreground -mx-2 -my-1 flex min-w-0 items-center gap-1 truncate rounded-md px-2 py-1 text-left font-medium motion-safe:transition-colors",
|
|
3361
|
-
sorted && "text-
|
|
3393
|
+
sorted && "text-foreground",
|
|
3362
3394
|
shouldShowActionsMenu ? "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50 cursor-pointer" : "cursor-default"
|
|
3363
3395
|
),
|
|
3364
3396
|
children: [
|
|
@@ -3794,6 +3826,9 @@ function composeRefs(...refs) {
|
|
|
3794
3826
|
}
|
|
3795
3827
|
};
|
|
3796
3828
|
}
|
|
3829
|
+
function hasOrder(filter) {
|
|
3830
|
+
return typeof filter.order === "number";
|
|
3831
|
+
}
|
|
3797
3832
|
function FilterBar(_a) {
|
|
3798
3833
|
var _b = _a, {
|
|
3799
3834
|
filters,
|
|
@@ -3815,7 +3850,8 @@ function FilterBar(_a) {
|
|
|
3815
3850
|
"ref"
|
|
3816
3851
|
]);
|
|
3817
3852
|
const usedKeys = new Set(activeFilters.map((f) => f.key));
|
|
3818
|
-
const
|
|
3853
|
+
const remainingFilters = filters.filter((f) => !usedKeys.has(f.key));
|
|
3854
|
+
const availableFilters = filters.some(hasOrder) ? remainingFilters : sortBy(remainingFilters, (f) => f.label);
|
|
3819
3855
|
const shouldShowFilters = availableFilters.length > 0 || activeFilters.length > 0;
|
|
3820
3856
|
const [pendingOpenKey, setPendingOpenKey] = React7.useState(null);
|
|
3821
3857
|
function handleAddFilter(key) {
|
|
@@ -3842,7 +3878,7 @@ function FilterBar(_a) {
|
|
|
3842
3878
|
if (filter) handleAddFilter(filter.key);
|
|
3843
3879
|
},
|
|
3844
3880
|
children: [
|
|
3845
|
-
/* @__PURE__ */ jsxs9(ComboboxTrigger2, { "aria-label": "Add filter", render: /* @__PURE__ */ jsx10(Button6, { variant: "outline" }), children: [
|
|
3881
|
+
/* @__PURE__ */ jsxs9(ComboboxTrigger2, { "aria-label": "Add filter", showIndicator: false, render: /* @__PURE__ */ jsx10(Button6, { variant: "outline" }), children: [
|
|
3846
3882
|
/* @__PURE__ */ jsx10(Icon8, { name: "plus", "data-icon": "inline-start" }),
|
|
3847
3883
|
"Add filter"
|
|
3848
3884
|
] }),
|
|
@@ -3950,7 +3986,8 @@ function CheckboxFilterChip({
|
|
|
3950
3986
|
onRemove
|
|
3951
3987
|
}) {
|
|
3952
3988
|
var _a, _b;
|
|
3953
|
-
const { label,
|
|
3989
|
+
const { label, searchable = false } = definition;
|
|
3990
|
+
const options = sortBy(definition.options, (o) => o.label);
|
|
3954
3991
|
const values = asCheckboxValue(value);
|
|
3955
3992
|
const displayLabel = values.length === 0 ? "Any" : values.length === 1 ? (_b = (_a = options.find((o) => o.value === values[0])) == null ? void 0 : _a.label) != null ? _b : values[0] : `${values.length} selected`;
|
|
3956
3993
|
function toggle(optionValue) {
|
|
@@ -4035,7 +4072,8 @@ function RadioFilterChip({
|
|
|
4035
4072
|
onRemove
|
|
4036
4073
|
}) {
|
|
4037
4074
|
var _a, _b, _c;
|
|
4038
|
-
const { label,
|
|
4075
|
+
const { label, searchable = false } = definition;
|
|
4076
|
+
const options = sortBy(definition.options, (o) => o.label);
|
|
4039
4077
|
const selectedValue = asRadioValue(value);
|
|
4040
4078
|
const displayLabel = selectedValue ? (_b = (_a = options.find((o) => o.value === selectedValue)) == null ? void 0 : _a.label) != null ? _b : selectedValue : "Any";
|
|
4041
4079
|
const selected = (_c = options.find((o) => o.value === selectedValue)) != null ? _c : null;
|
|
@@ -4290,21 +4328,21 @@ function toFilterOption(opt) {
|
|
|
4290
4328
|
return typeof opt === "string" ? { value: opt, label: opt } : { value: opt.value, label: opt.label };
|
|
4291
4329
|
}
|
|
4292
4330
|
function toFilterBarDefinition(key, filter) {
|
|
4293
|
-
var _a, _b
|
|
4294
|
-
const base = { key, label: filter.title, order:
|
|
4331
|
+
var _a, _b;
|
|
4332
|
+
const base = { key, label: filter.title, order: filter.order };
|
|
4295
4333
|
if (isCheckboxColumnFilter(filter)) {
|
|
4296
4334
|
const options = "options" in filter && filter.options ? filter.options : [];
|
|
4297
4335
|
return __spreadProps(__spreadValues({}, base), {
|
|
4298
4336
|
type: "checkbox",
|
|
4299
4337
|
options: options.map(toFilterOption),
|
|
4300
|
-
searchable: (
|
|
4338
|
+
searchable: (_a = filter.searchable) != null ? _a : true
|
|
4301
4339
|
});
|
|
4302
4340
|
}
|
|
4303
4341
|
if (isRadioColumnFilter(filter)) {
|
|
4304
4342
|
return __spreadProps(__spreadValues({}, base), {
|
|
4305
4343
|
type: "radio",
|
|
4306
4344
|
options: filter.options.map(toFilterOption),
|
|
4307
|
-
searchable: (
|
|
4345
|
+
searchable: (_b = filter.searchable) != null ? _b : true
|
|
4308
4346
|
});
|
|
4309
4347
|
}
|
|
4310
4348
|
if (isDateRangeColumnFilter(filter)) {
|
|
@@ -4337,7 +4375,12 @@ function ViewFilter({
|
|
|
4337
4375
|
[columns]
|
|
4338
4376
|
);
|
|
4339
4377
|
const filterDefinitions = React8.useMemo(
|
|
4340
|
-
() => filterableColumns.map(({ key, filter }) => toFilterBarDefinition(key, filter)).sort((a, b) =>
|
|
4378
|
+
() => filterableColumns.map(({ key, filter }) => toFilterBarDefinition(key, filter)).sort((a, b) => {
|
|
4379
|
+
if (a.order == null && b.order == null) return 0;
|
|
4380
|
+
if (a.order == null) return 1;
|
|
4381
|
+
if (b.order == null) return -1;
|
|
4382
|
+
return a.order - b.order;
|
|
4383
|
+
}),
|
|
4341
4384
|
[filterableColumns]
|
|
4342
4385
|
);
|
|
4343
4386
|
const emptyValueByKey = React8.useMemo(
|