@proteos/ui 0.31.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/LICENSE +105 -0
- package/dist/chunk-IKAX76MB.js +113 -0
- package/dist/chunk-IKAX76MB.js.map +1 -0
- package/dist/chunk-MWAXK66H.cjs +119 -0
- package/dist/chunk-MWAXK66H.cjs.map +1 -0
- package/dist/index.cjs +6246 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2126 -0
- package/dist/index.d.ts +2126 -0
- package/dist/index.js +6069 -0
- package/dist/index.js.map +1 -0
- package/dist/pdf-view-3ZMMS6ML.cjs +95 -0
- package/dist/pdf-view-3ZMMS6ML.cjs.map +1 -0
- package/dist/pdf-view-BV5ZD6OC.js +93 -0
- package/dist/pdf-view-BV5ZD6OC.js.map +1 -0
- package/package.json +96 -0
- package/src/components/attachment-chip/attachment-chip.tsx +129 -0
- package/src/components/attachment-chip/index.ts +2 -0
- package/src/components/attribute-type-icon/attribute-type-icon.stories.tsx +70 -0
- package/src/components/attribute-type-icon/attribute-type-icon.tsx +125 -0
- package/src/components/attribute-type-icon/index.ts +8 -0
- package/src/components/avatar/avatar.stories.tsx +42 -0
- package/src/components/avatar/avatar.tsx +48 -0
- package/src/components/avatar/index.ts +2 -0
- package/src/components/avatar-group/avatar-group.test.tsx +38 -0
- package/src/components/avatar-group/avatar-group.tsx +60 -0
- package/src/components/avatar-group/index.ts +2 -0
- package/src/components/badge/badge.stories.tsx +62 -0
- package/src/components/badge/badge.test.tsx +36 -0
- package/src/components/badge/badge.tsx +54 -0
- package/src/components/badge/index.ts +2 -0
- package/src/components/badge-multi-select/badge-multi-select.stories.tsx +177 -0
- package/src/components/badge-multi-select/badge-multi-select.test.tsx +155 -0
- package/src/components/badge-multi-select/badge-multi-select.tsx +272 -0
- package/src/components/badge-multi-select/index.ts +2 -0
- package/src/components/breadcrumbs/breadcrumbs.stories.tsx +43 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +86 -0
- package/src/components/breadcrumbs/index.ts +2 -0
- package/src/components/button/button.stories.tsx +290 -0
- package/src/components/button/button.test.tsx +59 -0
- package/src/components/button/button.tsx +86 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/card/card.stories.tsx +351 -0
- package/src/components/card/card.test.tsx +141 -0
- package/src/components/card/card.tsx +173 -0
- package/src/components/card/index.ts +13 -0
- package/src/components/checkbox/checkbox-group.tsx +52 -0
- package/src/components/checkbox/checkbox.stories.tsx +48 -0
- package/src/components/checkbox/checkbox.test.tsx +50 -0
- package/src/components/checkbox/checkbox.tsx +71 -0
- package/src/components/checkbox/index.ts +4 -0
- package/src/components/combobox/combobox.stories.tsx +97 -0
- package/src/components/combobox/combobox.test.tsx +123 -0
- package/src/components/combobox/combobox.tsx +239 -0
- package/src/components/combobox/index.ts +2 -0
- package/src/components/command/command-hint.tsx +46 -0
- package/src/components/command/command.stories.tsx +88 -0
- package/src/components/command/command.test.tsx +102 -0
- package/src/components/command/command.tsx +76 -0
- package/src/components/command/index.ts +16 -0
- package/src/components/currency-input/currency-input.tsx +192 -0
- package/src/components/currency-input/index.ts +6 -0
- package/src/components/data-table/cells.stories.tsx +120 -0
- package/src/components/data-table/cells.tsx +165 -0
- package/src/components/data-table/data-table.stories.tsx +371 -0
- package/src/components/data-table/data-table.tsx +556 -0
- package/src/components/data-table/index.ts +22 -0
- package/src/components/data-table/make-actions-column.ts +30 -0
- package/src/components/data-table/states/data-table-empty.tsx +40 -0
- package/src/components/data-table/states/data-table-error.tsx +30 -0
- package/src/components/data-table/states/data-table-skeleton.tsx +42 -0
- package/src/components/data-table/use-infinite-scroll-sentinel.ts +51 -0
- package/src/components/date-picker/calendar-internals.tsx +138 -0
- package/src/components/date-picker/date-picker.stories.tsx +78 -0
- package/src/components/date-picker/date-picker.test.tsx +71 -0
- package/src/components/date-picker/date-picker.tsx +140 -0
- package/src/components/date-picker/index.ts +2 -0
- package/src/components/date-time-picker/date-time-picker.stories.tsx +96 -0
- package/src/components/date-time-picker/date-time-picker.test.tsx +87 -0
- package/src/components/date-time-picker/date-time-picker.tsx +203 -0
- package/src/components/date-time-picker/index.ts +2 -0
- package/src/components/empty-state/empty-state.tsx +63 -0
- package/src/components/empty-state/index.ts +2 -0
- package/src/components/error-animation/error-animation.stories.tsx +50 -0
- package/src/components/error-animation/error-animation.test.tsx +22 -0
- package/src/components/error-animation/error-animation.tsx +26 -0
- package/src/components/error-animation/index.ts +2 -0
- package/src/components/field/field.tsx +142 -0
- package/src/components/field/index.ts +8 -0
- package/src/components/file-field/file-field.tsx +285 -0
- package/src/components/file-field/index.ts +2 -0
- package/src/components/file-viewer/fallback-card.tsx +68 -0
- package/src/components/file-viewer/file-viewer.stories.tsx +67 -0
- package/src/components/file-viewer/file-viewer.test.tsx +81 -0
- package/src/components/file-viewer/file-viewer.tsx +116 -0
- package/src/components/file-viewer/image-view.tsx +38 -0
- package/src/components/file-viewer/index.ts +7 -0
- package/src/components/file-viewer/pdf-view.tsx +122 -0
- package/src/components/file-viewer/video-view.tsx +16 -0
- package/src/components/image-attachment/image-attachment.stories.tsx +39 -0
- package/src/components/image-attachment/image-attachment.test.tsx +54 -0
- package/src/components/image-attachment/image-attachment.tsx +77 -0
- package/src/components/image-attachment/index.ts +3 -0
- package/src/components/image-attachment/is-previewable-image-name.ts +14 -0
- package/src/components/image-lightbox/image-lightbox.stories.tsx +38 -0
- package/src/components/image-lightbox/image-lightbox.test.tsx +72 -0
- package/src/components/image-lightbox/image-lightbox.tsx +92 -0
- package/src/components/image-lightbox/index.ts +2 -0
- package/src/components/input/index.ts +2 -0
- package/src/components/input/input.stories.tsx +71 -0
- package/src/components/input/input.test.tsx +36 -0
- package/src/components/input/input.tsx +76 -0
- package/src/components/kbd/index.ts +2 -0
- package/src/components/kbd/kbd.stories.tsx +34 -0
- package/src/components/kbd/kbd.tsx +27 -0
- package/src/components/menu/index.ts +2 -0
- package/src/components/menu/menu.tsx +121 -0
- package/src/components/modal/index.ts +10 -0
- package/src/components/modal/modal.stories.tsx +153 -0
- package/src/components/modal/modal.test.tsx +93 -0
- package/src/components/modal/modal.tsx +149 -0
- package/src/components/multi-select/index.ts +2 -0
- package/src/components/multi-select/multi-select.stories.tsx +211 -0
- package/src/components/multi-select/multi-select.test.tsx +151 -0
- package/src/components/multi-select/multi-select.tsx +339 -0
- package/src/components/nav/index.ts +7 -0
- package/src/components/nav/nav.stories.tsx +139 -0
- package/src/components/nav/nav.tsx +246 -0
- package/src/components/popover/index.ts +8 -0
- package/src/components/popover/popover.stories.tsx +92 -0
- package/src/components/popover/popover.tsx +135 -0
- package/src/components/progress-bar/index.ts +2 -0
- package/src/components/progress-bar/progress-bar.stories.tsx +75 -0
- package/src/components/progress-bar/progress-bar.test.tsx +29 -0
- package/src/components/progress-bar/progress-bar.tsx +57 -0
- package/src/components/radio-group/index.ts +2 -0
- package/src/components/radio-group/radio-group.stories.tsx +113 -0
- package/src/components/radio-group/radio-group.test.tsx +87 -0
- package/src/components/radio-group/radio-group.tsx +104 -0
- package/src/components/record-filter/attribute-picker.tsx +74 -0
- package/src/components/record-filter/chip-value.tsx +171 -0
- package/src/components/record-filter/filter-row.tsx +262 -0
- package/src/components/record-filter/filter-value-input.tsx +351 -0
- package/src/components/record-filter/group-add-controls.tsx +77 -0
- package/src/components/record-filter/group-body.tsx +173 -0
- package/src/components/record-filter/group-mutations.test.ts +104 -0
- package/src/components/record-filter/group-mutations.ts +116 -0
- package/src/components/record-filter/index.ts +58 -0
- package/src/components/record-filter/nested-group.tsx +138 -0
- package/src/components/record-filter/operator-picker.tsx +62 -0
- package/src/components/record-filter/operators.test.ts +105 -0
- package/src/components/record-filter/operators.ts +97 -0
- package/src/components/record-filter/record-filter-builder-panel.tsx +236 -0
- package/src/components/record-filter/record-filter-button.tsx +126 -0
- package/src/components/record-filter/record-filter-chips.tsx +527 -0
- package/src/components/record-filter/record-filter-editor.tsx +91 -0
- package/src/components/record-filter/record-filter.stories.tsx +196 -0
- package/src/components/record-filter/record-filter.test.tsx +437 -0
- package/src/components/record-filter/show-details-store.ts +72 -0
- package/src/components/record-filter/types.ts +150 -0
- package/src/components/segmented-control/index.ts +6 -0
- package/src/components/segmented-control/segmented-control.stories.tsx +67 -0
- package/src/components/segmented-control/segmented-control.test.tsx +47 -0
- package/src/components/segmented-control/segmented-control.tsx +105 -0
- package/src/components/select/index.ts +2 -0
- package/src/components/select/select.stories.tsx +76 -0
- package/src/components/select/select.test.tsx +56 -0
- package/src/components/select/select.tsx +159 -0
- package/src/components/separator/index.ts +2 -0
- package/src/components/separator/separator.stories.tsx +73 -0
- package/src/components/separator/separator.test.tsx +29 -0
- package/src/components/separator/separator.tsx +51 -0
- package/src/components/skeleton/index.ts +2 -0
- package/src/components/skeleton/skeleton.stories.tsx +68 -0
- package/src/components/skeleton/skeleton.test.tsx +38 -0
- package/src/components/skeleton/skeleton.tsx +43 -0
- package/src/components/success-animation/index.ts +2 -0
- package/src/components/success-animation/success-animation.stories.tsx +50 -0
- package/src/components/success-animation/success-animation.test.tsx +22 -0
- package/src/components/success-animation/success-animation.tsx +26 -0
- package/src/components/switch/index.ts +2 -0
- package/src/components/switch/switch.stories.tsx +60 -0
- package/src/components/switch/switch.test.tsx +50 -0
- package/src/components/switch/switch.tsx +49 -0
- package/src/components/table/index.ts +25 -0
- package/src/components/table/table.stories.tsx +306 -0
- package/src/components/table/table.test.tsx +115 -0
- package/src/components/table/table.tsx +543 -0
- package/src/components/tabs/index.ts +8 -0
- package/src/components/tabs/tabs.tsx +141 -0
- package/src/components/tag-input/index.ts +2 -0
- package/src/components/tag-input/tag-input.stories.tsx +73 -0
- package/src/components/tag-input/tag-input.test.tsx +80 -0
- package/src/components/tag-input/tag-input.tsx +193 -0
- package/src/components/textarea/index.ts +2 -0
- package/src/components/textarea/textarea.stories.tsx +75 -0
- package/src/components/textarea/textarea.test.tsx +41 -0
- package/src/components/textarea/textarea.tsx +86 -0
- package/src/components/time-field/index.ts +2 -0
- package/src/components/time-field/time-field.stories.tsx +76 -0
- package/src/components/time-field/time-field.test.tsx +51 -0
- package/src/components/time-field/time-field.tsx +98 -0
- package/src/components/tooltip/index.ts +2 -0
- package/src/components/tooltip/tooltip.stories.tsx +176 -0
- package/src/components/tooltip/tooltip.test.tsx +52 -0
- package/src/components/tooltip/tooltip.tsx +56 -0
- package/src/index.ts +47 -0
- package/src/lib/cn.ts +6 -0
- package/src/lib/commands/discovery-store.test.tsx +76 -0
- package/src/lib/commands/discovery-store.ts +110 -0
- package/src/lib/commands/index.ts +9 -0
- package/src/lib/commands/match-event.test.ts +99 -0
- package/src/lib/commands/match-event.ts +31 -0
- package/src/lib/commands/parse-combo.test.ts +65 -0
- package/src/lib/commands/parse-combo.ts +48 -0
- package/src/lib/commands/platform.ts +27 -0
- package/src/lib/commands/protected-combos.test.ts +18 -0
- package/src/lib/commands/protected-combos.ts +38 -0
- package/src/lib/commands/registry.test.ts +97 -0
- package/src/lib/commands/registry.ts +59 -0
- package/src/lib/commands/use-command.test.tsx +91 -0
- package/src/lib/commands/use-command.ts +32 -0
- package/src/lib/commands/use-escape-key.test.tsx +97 -0
- package/src/lib/commands/use-escape-key.ts +62 -0
- package/src/styles.css +321 -0
- package/src/test/setup.ts +9 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkMWAXK66H_cjs = require('./chunk-MWAXK66H.cjs');
|
|
4
|
+
var lucideReact = require('lucide-react');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var reactPdf = require('react-pdf');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
// url-asset:pdfjs-dist/build/pdf.worker.min.mjs?url
|
|
10
|
+
var pdf_worker_min_default = "https://unpkg.com/pdfjs-dist@5.4.296/build/pdf.worker.min.mjs";
|
|
11
|
+
if (!reactPdf.pdfjs.GlobalWorkerOptions.workerSrc) {
|
|
12
|
+
reactPdf.pdfjs.GlobalWorkerOptions.workerSrc = pdf_worker_min_default;
|
|
13
|
+
}
|
|
14
|
+
function PdfView({ name, src, onDownload }) {
|
|
15
|
+
const [pageCount, setPageCount] = react.useState(null);
|
|
16
|
+
const [pageNumber, setPageNumber] = react.useState(1);
|
|
17
|
+
const [loadError, setLoadError] = react.useState(false);
|
|
18
|
+
const scrollRef = react.useRef(null);
|
|
19
|
+
const [pageWidth, setPageWidth] = react.useState(null);
|
|
20
|
+
react.useEffect(() => {
|
|
21
|
+
const element = scrollRef.current;
|
|
22
|
+
if (!element) return;
|
|
23
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
24
|
+
if (entry) setPageWidth(Math.floor(entry.contentRect.width));
|
|
25
|
+
});
|
|
26
|
+
observer.observe(element);
|
|
27
|
+
return () => observer.disconnect();
|
|
28
|
+
}, []);
|
|
29
|
+
if (loadError) {
|
|
30
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-sans text-[13px] text-danger", children: "Could not display this PDF. Download it instead." }) });
|
|
31
|
+
}
|
|
32
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full flex-col", children: [
|
|
33
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: scrollRef, className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
34
|
+
reactPdf.Document,
|
|
35
|
+
{
|
|
36
|
+
file: src,
|
|
37
|
+
onLoadSuccess: ({ numPages }) => {
|
|
38
|
+
setPageCount(numPages);
|
|
39
|
+
setPageNumber(1);
|
|
40
|
+
},
|
|
41
|
+
onLoadError: () => setLoadError(true),
|
|
42
|
+
loading: /* @__PURE__ */ jsxRuntime.jsx(chunkMWAXK66H_cjs.Skeleton, { "aria-label": `Loading ${name}`, className: "h-full w-full rounded-none" }),
|
|
43
|
+
error: null,
|
|
44
|
+
children: pageWidth ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
45
|
+
reactPdf.Page,
|
|
46
|
+
{
|
|
47
|
+
pageNumber,
|
|
48
|
+
width: pageWidth,
|
|
49
|
+
renderTextLayer: false,
|
|
50
|
+
renderAnnotationLayer: false
|
|
51
|
+
}
|
|
52
|
+
) : null
|
|
53
|
+
}
|
|
54
|
+
) }),
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center justify-center gap-1.5 border-t border-rule bg-surface px-2 py-1", children: [
|
|
56
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
57
|
+
chunkMWAXK66H_cjs.Button,
|
|
58
|
+
{
|
|
59
|
+
variant: "ghost",
|
|
60
|
+
size: "icon-sm",
|
|
61
|
+
"aria-label": "Previous page",
|
|
62
|
+
isDisabled: pageNumber <= 1,
|
|
63
|
+
onPress: () => setPageNumber((page) => Math.max(1, page - 1)),
|
|
64
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": true })
|
|
65
|
+
}
|
|
66
|
+
),
|
|
67
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-14 text-center font-sans text-[12px] tabular-nums text-ink-3", children: pageCount ? `${pageNumber} / ${pageCount}` : "\u2013" }),
|
|
68
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
69
|
+
chunkMWAXK66H_cjs.Button,
|
|
70
|
+
{
|
|
71
|
+
variant: "ghost",
|
|
72
|
+
size: "icon-sm",
|
|
73
|
+
"aria-label": "Next page",
|
|
74
|
+
isDisabled: pageCount === null || pageNumber >= pageCount,
|
|
75
|
+
onPress: () => setPageNumber((page) => Math.min(pageCount ?? page, page + 1)),
|
|
76
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true })
|
|
77
|
+
}
|
|
78
|
+
),
|
|
79
|
+
onDownload ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
80
|
+
chunkMWAXK66H_cjs.Button,
|
|
81
|
+
{
|
|
82
|
+
variant: "ghost",
|
|
83
|
+
size: "icon-sm",
|
|
84
|
+
"aria-label": `Download ${name}`,
|
|
85
|
+
onPress: onDownload,
|
|
86
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { "aria-hidden": true })
|
|
87
|
+
}
|
|
88
|
+
) : null
|
|
89
|
+
] })
|
|
90
|
+
] });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = PdfView;
|
|
94
|
+
//# sourceMappingURL=pdf-view-3ZMMS6ML.cjs.map
|
|
95
|
+
//# sourceMappingURL=pdf-view-3ZMMS6ML.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["url-asset:pdfjs-dist/build/pdf.worker.min.mjs?url","../src/components/file-viewer/pdf-view.tsx"],"names":["pdfjs","useState","useRef","useEffect","jsx","jsxs","Document","Skeleton","Page","Button","ChevronLeft","ChevronRight","Download"],"mappings":"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","file":"pdf-view-3ZMMS6ML.cjs","sourcesContent":["export default \"https://unpkg.com/pdfjs-dist@5.4.296/build/pdf.worker.min.mjs\"","import { ChevronLeft, ChevronRight, Download } from 'lucide-react'\nimport pdfWorkerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url'\nimport { useEffect, useRef, useState } from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\n\nimport { Button } from '../button/button'\nimport { Skeleton } from '../skeleton/skeleton'\n\n/* =========================================================================\n PdfView — the FileViewer's PDF pane, backed by react-pdf (pdf.js).\n Lazy-loaded by the FileViewer (default export) so pdf.js and its worker\n stay out of the main bundle. Text/annotation layers are off: this is a\n read-only preview and the layers would need pdf.js's own stylesheets,\n which the token-based design system deliberately doesn't import.\n ========================================================================= */\n\n// The worker must come from the SAME pdfjs-dist instance react-pdf renders\n// with (API/worker version mismatch throws). `?url` lets Vite emit it as an\n// asset and hand back the served URL. In the published dist build the `?url`\n// module is rewritten to a version-pinned CDN URL (see tsup.config.ts), and\n// the guard lets consumers pre-set their own workerSrc before this lazy\n// chunk loads.\nif (!pdfjs.GlobalWorkerOptions.workerSrc) {\n pdfjs.GlobalWorkerOptions.workerSrc = pdfWorkerUrl\n}\n\nexport interface PdfViewProps {\n name: string\n /** Blob object URL of the PDF bytes. */\n src: string\n onDownload?: () => void\n}\n\nexport default function PdfView({ name, src, onDownload }: PdfViewProps) {\n const [pageCount, setPageCount] = useState<number | null>(null)\n const [pageNumber, setPageNumber] = useState(1)\n const [loadError, setLoadError] = useState(false)\n\n // Fit-width: render the page at the scroll area's current width.\n const scrollRef = useRef<HTMLDivElement | null>(null)\n const [pageWidth, setPageWidth] = useState<number | null>(null)\n useEffect(() => {\n const element = scrollRef.current\n if (!element) return\n const observer = new ResizeObserver(([entry]) => {\n if (entry) setPageWidth(Math.floor(entry.contentRect.width))\n })\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n\n if (loadError) {\n return (\n <div className=\"flex h-full w-full items-center justify-center p-4\">\n <span className=\"font-sans text-[13px] text-danger\">\n Could not display this PDF. Download it instead.\n </span>\n </div>\n )\n }\n\n return (\n <div className=\"flex h-full w-full flex-col\">\n <div ref={scrollRef} className=\"min-h-0 flex-1 overflow-auto\">\n <Document\n file={src}\n onLoadSuccess={({ numPages }) => {\n setPageCount(numPages)\n setPageNumber(1)\n }}\n onLoadError={() => setLoadError(true)}\n loading={\n <Skeleton aria-label={`Loading ${name}`} className=\"h-full w-full rounded-none\" />\n }\n error={null}\n >\n {pageWidth ? (\n <Page\n pageNumber={pageNumber}\n width={pageWidth}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n />\n ) : null}\n </Document>\n </div>\n <div className=\"flex shrink-0 items-center justify-center gap-1.5 border-t border-rule bg-surface px-2 py-1\">\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Previous page\"\n isDisabled={pageNumber <= 1}\n onPress={() => setPageNumber((page) => Math.max(1, page - 1))}\n >\n <ChevronLeft aria-hidden />\n </Button>\n <span className=\"min-w-14 text-center font-sans text-[12px] tabular-nums text-ink-3\">\n {pageCount ? `${pageNumber} / ${pageCount}` : '–'}\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Next page\"\n isDisabled={pageCount === null || pageNumber >= pageCount}\n onPress={() => setPageNumber((page) => Math.min(pageCount ?? page, page + 1))}\n >\n <ChevronRight aria-hidden />\n </Button>\n {onDownload ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={`Download ${name}`}\n onPress={onDownload}\n >\n <Download aria-hidden />\n </Button>\n ) : null}\n </div>\n </div>\n )\n}\n"]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Skeleton, Button } from './chunk-IKAX76MB.js';
|
|
2
|
+
import { ChevronLeft, ChevronRight, Download } from 'lucide-react';
|
|
3
|
+
import { useState, useRef, useEffect } from 'react';
|
|
4
|
+
import { pdfjs, Document, Page } from 'react-pdf';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
// url-asset:pdfjs-dist/build/pdf.worker.min.mjs?url
|
|
8
|
+
var pdf_worker_min_default = "https://unpkg.com/pdfjs-dist@5.4.296/build/pdf.worker.min.mjs";
|
|
9
|
+
if (!pdfjs.GlobalWorkerOptions.workerSrc) {
|
|
10
|
+
pdfjs.GlobalWorkerOptions.workerSrc = pdf_worker_min_default;
|
|
11
|
+
}
|
|
12
|
+
function PdfView({ name, src, onDownload }) {
|
|
13
|
+
const [pageCount, setPageCount] = useState(null);
|
|
14
|
+
const [pageNumber, setPageNumber] = useState(1);
|
|
15
|
+
const [loadError, setLoadError] = useState(false);
|
|
16
|
+
const scrollRef = useRef(null);
|
|
17
|
+
const [pageWidth, setPageWidth] = useState(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const element = scrollRef.current;
|
|
20
|
+
if (!element) return;
|
|
21
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
22
|
+
if (entry) setPageWidth(Math.floor(entry.contentRect.width));
|
|
23
|
+
});
|
|
24
|
+
observer.observe(element);
|
|
25
|
+
return () => observer.disconnect();
|
|
26
|
+
}, []);
|
|
27
|
+
if (loadError) {
|
|
28
|
+
return /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ jsx("span", { className: "font-sans text-[13px] text-danger", children: "Could not display this PDF. Download it instead." }) });
|
|
29
|
+
}
|
|
30
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-full w-full flex-col", children: [
|
|
31
|
+
/* @__PURE__ */ jsx("div", { ref: scrollRef, className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx(
|
|
32
|
+
Document,
|
|
33
|
+
{
|
|
34
|
+
file: src,
|
|
35
|
+
onLoadSuccess: ({ numPages }) => {
|
|
36
|
+
setPageCount(numPages);
|
|
37
|
+
setPageNumber(1);
|
|
38
|
+
},
|
|
39
|
+
onLoadError: () => setLoadError(true),
|
|
40
|
+
loading: /* @__PURE__ */ jsx(Skeleton, { "aria-label": `Loading ${name}`, className: "h-full w-full rounded-none" }),
|
|
41
|
+
error: null,
|
|
42
|
+
children: pageWidth ? /* @__PURE__ */ jsx(
|
|
43
|
+
Page,
|
|
44
|
+
{
|
|
45
|
+
pageNumber,
|
|
46
|
+
width: pageWidth,
|
|
47
|
+
renderTextLayer: false,
|
|
48
|
+
renderAnnotationLayer: false
|
|
49
|
+
}
|
|
50
|
+
) : null
|
|
51
|
+
}
|
|
52
|
+
) }),
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-center gap-1.5 border-t border-rule bg-surface px-2 py-1", children: [
|
|
54
|
+
/* @__PURE__ */ jsx(
|
|
55
|
+
Button,
|
|
56
|
+
{
|
|
57
|
+
variant: "ghost",
|
|
58
|
+
size: "icon-sm",
|
|
59
|
+
"aria-label": "Previous page",
|
|
60
|
+
isDisabled: pageNumber <= 1,
|
|
61
|
+
onPress: () => setPageNumber((page) => Math.max(1, page - 1)),
|
|
62
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": true })
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-14 text-center font-sans text-[12px] tabular-nums text-ink-3", children: pageCount ? `${pageNumber} / ${pageCount}` : "\u2013" }),
|
|
66
|
+
/* @__PURE__ */ jsx(
|
|
67
|
+
Button,
|
|
68
|
+
{
|
|
69
|
+
variant: "ghost",
|
|
70
|
+
size: "icon-sm",
|
|
71
|
+
"aria-label": "Next page",
|
|
72
|
+
isDisabled: pageCount === null || pageNumber >= pageCount,
|
|
73
|
+
onPress: () => setPageNumber((page) => Math.min(pageCount ?? page, page + 1)),
|
|
74
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true })
|
|
75
|
+
}
|
|
76
|
+
),
|
|
77
|
+
onDownload ? /* @__PURE__ */ jsx(
|
|
78
|
+
Button,
|
|
79
|
+
{
|
|
80
|
+
variant: "ghost",
|
|
81
|
+
size: "icon-sm",
|
|
82
|
+
"aria-label": `Download ${name}`,
|
|
83
|
+
onPress: onDownload,
|
|
84
|
+
children: /* @__PURE__ */ jsx(Download, { "aria-hidden": true })
|
|
85
|
+
}
|
|
86
|
+
) : null
|
|
87
|
+
] })
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { PdfView as default };
|
|
92
|
+
//# sourceMappingURL=pdf-view-BV5ZD6OC.js.map
|
|
93
|
+
//# sourceMappingURL=pdf-view-BV5ZD6OC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["url-asset:pdfjs-dist/build/pdf.worker.min.mjs?url","../src/components/file-viewer/pdf-view.tsx"],"names":[],"mappings":"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","file":"pdf-view-BV5ZD6OC.js","sourcesContent":["export default \"https://unpkg.com/pdfjs-dist@5.4.296/build/pdf.worker.min.mjs\"","import { ChevronLeft, ChevronRight, Download } from 'lucide-react'\nimport pdfWorkerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url'\nimport { useEffect, useRef, useState } from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\n\nimport { Button } from '../button/button'\nimport { Skeleton } from '../skeleton/skeleton'\n\n/* =========================================================================\n PdfView — the FileViewer's PDF pane, backed by react-pdf (pdf.js).\n Lazy-loaded by the FileViewer (default export) so pdf.js and its worker\n stay out of the main bundle. Text/annotation layers are off: this is a\n read-only preview and the layers would need pdf.js's own stylesheets,\n which the token-based design system deliberately doesn't import.\n ========================================================================= */\n\n// The worker must come from the SAME pdfjs-dist instance react-pdf renders\n// with (API/worker version mismatch throws). `?url` lets Vite emit it as an\n// asset and hand back the served URL. In the published dist build the `?url`\n// module is rewritten to a version-pinned CDN URL (see tsup.config.ts), and\n// the guard lets consumers pre-set their own workerSrc before this lazy\n// chunk loads.\nif (!pdfjs.GlobalWorkerOptions.workerSrc) {\n pdfjs.GlobalWorkerOptions.workerSrc = pdfWorkerUrl\n}\n\nexport interface PdfViewProps {\n name: string\n /** Blob object URL of the PDF bytes. */\n src: string\n onDownload?: () => void\n}\n\nexport default function PdfView({ name, src, onDownload }: PdfViewProps) {\n const [pageCount, setPageCount] = useState<number | null>(null)\n const [pageNumber, setPageNumber] = useState(1)\n const [loadError, setLoadError] = useState(false)\n\n // Fit-width: render the page at the scroll area's current width.\n const scrollRef = useRef<HTMLDivElement | null>(null)\n const [pageWidth, setPageWidth] = useState<number | null>(null)\n useEffect(() => {\n const element = scrollRef.current\n if (!element) return\n const observer = new ResizeObserver(([entry]) => {\n if (entry) setPageWidth(Math.floor(entry.contentRect.width))\n })\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n\n if (loadError) {\n return (\n <div className=\"flex h-full w-full items-center justify-center p-4\">\n <span className=\"font-sans text-[13px] text-danger\">\n Could not display this PDF. Download it instead.\n </span>\n </div>\n )\n }\n\n return (\n <div className=\"flex h-full w-full flex-col\">\n <div ref={scrollRef} className=\"min-h-0 flex-1 overflow-auto\">\n <Document\n file={src}\n onLoadSuccess={({ numPages }) => {\n setPageCount(numPages)\n setPageNumber(1)\n }}\n onLoadError={() => setLoadError(true)}\n loading={\n <Skeleton aria-label={`Loading ${name}`} className=\"h-full w-full rounded-none\" />\n }\n error={null}\n >\n {pageWidth ? (\n <Page\n pageNumber={pageNumber}\n width={pageWidth}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n />\n ) : null}\n </Document>\n </div>\n <div className=\"flex shrink-0 items-center justify-center gap-1.5 border-t border-rule bg-surface px-2 py-1\">\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Previous page\"\n isDisabled={pageNumber <= 1}\n onPress={() => setPageNumber((page) => Math.max(1, page - 1))}\n >\n <ChevronLeft aria-hidden />\n </Button>\n <span className=\"min-w-14 text-center font-sans text-[12px] tabular-nums text-ink-3\">\n {pageCount ? `${pageNumber} / ${pageCount}` : '–'}\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Next page\"\n isDisabled={pageCount === null || pageNumber >= pageCount}\n onPress={() => setPageNumber((page) => Math.min(pageCount ?? page, page + 1))}\n >\n <ChevronRight aria-hidden />\n </Button>\n {onDownload ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={`Download ${name}`}\n onPress={onDownload}\n >\n <Download aria-hidden />\n </Button>\n ) : null}\n </div>\n </div>\n )\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@proteos/ui",
|
|
3
|
+
"version": "0.31.0",
|
|
4
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
5
|
+
"description": "Proteos React component library (React Aria Components + Tailwind v4).",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/proteos-ai/ui.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/proteos-ai/ui",
|
|
11
|
+
"bugs": "https://github.com/proteos-ai/ui/issues",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"**/*.css"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"default": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./styles.css": "./src/styles.css"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public",
|
|
31
|
+
"provenance": false
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"src"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=20.0.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"react": ">=19.0.0",
|
|
42
|
+
"react-dom": ">=19.0.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@atlaskit/pragmatic-drag-and-drop": "^1.8.1",
|
|
46
|
+
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
|
|
47
|
+
"@internationalized/date": "^3.10.0",
|
|
48
|
+
"@tanstack/react-table": "^8.21.3",
|
|
49
|
+
"@tanstack/react-virtual": "^3.13.24",
|
|
50
|
+
"clsx": "^2.1.1",
|
|
51
|
+
"lucide-react": "^0.473.0",
|
|
52
|
+
"pdfjs-dist": "5.4.296",
|
|
53
|
+
"react-aria-components": "^1.17.0",
|
|
54
|
+
"react-pdf": "^10.4.1",
|
|
55
|
+
"tailwind-merge": "^3.5.0",
|
|
56
|
+
"tailwind-variants": "^3.2.2",
|
|
57
|
+
"tailwindcss": "^4.2.4",
|
|
58
|
+
"@proteos/sdk": "0.31.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@biomejs/biome": "^2.4.13",
|
|
62
|
+
"@storybook/addon-a11y": "^10.3.5",
|
|
63
|
+
"@storybook/addon-docs": "^10.3.5",
|
|
64
|
+
"@storybook/react-vite": "^10.3.5",
|
|
65
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
66
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
67
|
+
"@testing-library/react": "^16.3.2",
|
|
68
|
+
"@testing-library/user-event": "^14.6.1",
|
|
69
|
+
"@types/react": "^19.2.14",
|
|
70
|
+
"@types/react-dom": "^19.2.3",
|
|
71
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
72
|
+
"jsdom": "^29.0.2",
|
|
73
|
+
"react": "^19.2.5",
|
|
74
|
+
"react-dom": "^19.2.5",
|
|
75
|
+
"storybook": "^10.3.5",
|
|
76
|
+
"tsup": "^8.3.0",
|
|
77
|
+
"typescript": "^6.0.3",
|
|
78
|
+
"vite": "^8.0.10",
|
|
79
|
+
"vitest": "^3.2.4",
|
|
80
|
+
"@proteos/biome-config": "0.0.0",
|
|
81
|
+
"@proteos/tsconfig": "0.0.0"
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"lint": "biome check .",
|
|
85
|
+
"format": "biome format --write .",
|
|
86
|
+
"typecheck": "tsc -b",
|
|
87
|
+
"test": "vitest run",
|
|
88
|
+
"test:watch": "vitest",
|
|
89
|
+
"storybook": "storybook dev -p 6006",
|
|
90
|
+
"build": "tsc --noEmit && storybook build -o dist-storybook",
|
|
91
|
+
"build:lib": "tsup"
|
|
92
|
+
},
|
|
93
|
+
"main": "./dist/index.cjs",
|
|
94
|
+
"module": "./dist/index.js",
|
|
95
|
+
"types": "./dist/index.d.ts"
|
|
96
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Loader2 } from 'lucide-react'
|
|
2
|
+
import type { ReactNode } from 'react'
|
|
3
|
+
import { tv, type VariantProps } from 'tailwind-variants'
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/cn'
|
|
6
|
+
import { formatFileSize, iconForContentType } from '../file-field'
|
|
7
|
+
|
|
8
|
+
/* =========================================================================
|
|
9
|
+
AttachmentChip — a small file token for chat composers and message
|
|
10
|
+
bubbles. A file-type icon (or a spinner while uploading), a truncated
|
|
11
|
+
name, the size (or upload state), and an optional (x) to remove. Pure
|
|
12
|
+
presentation: the consumer owns upload / remove / download.
|
|
13
|
+
========================================================================= */
|
|
14
|
+
|
|
15
|
+
export const attachmentChipStyles = tv({
|
|
16
|
+
base: [
|
|
17
|
+
'inline-flex items-center gap-1.5 max-w-[220px]',
|
|
18
|
+
'pl-2 pr-1 py-1 rounded-[6px] border',
|
|
19
|
+
'font-sans text-[12.5px] leading-none',
|
|
20
|
+
],
|
|
21
|
+
variants: {
|
|
22
|
+
status: {
|
|
23
|
+
uploading: 'bg-surface-2 border-rule text-ink-3',
|
|
24
|
+
ready: 'bg-surface-2 border-rule text-ink',
|
|
25
|
+
error: 'bg-surface-2 border-danger text-danger',
|
|
26
|
+
},
|
|
27
|
+
isInteractive: {
|
|
28
|
+
true: 'cursor-pointer hover:bg-surface-3',
|
|
29
|
+
false: '',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
defaultVariants: { status: 'ready', isInteractive: false },
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export type AttachmentChipVariants = VariantProps<typeof attachmentChipStyles>
|
|
36
|
+
|
|
37
|
+
export interface AttachmentChipProps {
|
|
38
|
+
/** File name shown (truncated). */
|
|
39
|
+
name: string
|
|
40
|
+
/** Size in bytes — rendered when known and the chip is in the `ready` state. */
|
|
41
|
+
sizeInBytes?: number
|
|
42
|
+
/** MIME type — picks the leading file-type icon. */
|
|
43
|
+
contentType?: string
|
|
44
|
+
/** Upload lifecycle: spinner while `uploading`, danger styling on `error`. */
|
|
45
|
+
status?: 'uploading' | 'ready' | 'error'
|
|
46
|
+
/** Tooltip text and the meta line shown in the `error` state (the failure reason). */
|
|
47
|
+
errorMessage?: string
|
|
48
|
+
/** When set, an (x) button is shown that calls this. */
|
|
49
|
+
onRemove?: () => void
|
|
50
|
+
/** When set, the chip body is pressable (e.g. to download an agent file). */
|
|
51
|
+
onPress?: () => void
|
|
52
|
+
className?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function AttachmentChip({
|
|
56
|
+
name,
|
|
57
|
+
sizeInBytes,
|
|
58
|
+
contentType,
|
|
59
|
+
status = 'ready',
|
|
60
|
+
errorMessage,
|
|
61
|
+
onRemove,
|
|
62
|
+
onPress,
|
|
63
|
+
className,
|
|
64
|
+
}: AttachmentChipProps) {
|
|
65
|
+
const Icon = status === 'uploading' ? Loader2 : iconForContentType(contentType)
|
|
66
|
+
const meta =
|
|
67
|
+
status === 'error'
|
|
68
|
+
? (errorMessage ?? 'Failed')
|
|
69
|
+
: status === 'uploading'
|
|
70
|
+
? 'Uploading…'
|
|
71
|
+
: formatFileSize(sizeInBytes)
|
|
72
|
+
|
|
73
|
+
const body: ReactNode = (
|
|
74
|
+
<>
|
|
75
|
+
<Icon
|
|
76
|
+
className={cn('size-3.5 shrink-0 text-ink-3', status === 'uploading' && 'animate-spin')}
|
|
77
|
+
aria-hidden
|
|
78
|
+
/>
|
|
79
|
+
<span className="min-w-0 truncate">{name}</span>
|
|
80
|
+
{meta ? (
|
|
81
|
+
<span className={cn('shrink-0', status !== 'error' && 'text-ink-4')}>{meta}</span>
|
|
82
|
+
) : null}
|
|
83
|
+
</>
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<span
|
|
88
|
+
className={cn(attachmentChipStyles({ status, isInteractive: Boolean(onPress) }), className)}
|
|
89
|
+
title={errorMessage ?? name}
|
|
90
|
+
>
|
|
91
|
+
{onPress ? (
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
onClick={onPress}
|
|
95
|
+
className="inline-flex min-w-0 cursor-pointer items-center gap-1.5 outline-none focus-visible:shadow-[var(--shadow-focus)]"
|
|
96
|
+
>
|
|
97
|
+
{body}
|
|
98
|
+
</button>
|
|
99
|
+
) : (
|
|
100
|
+
<span className="inline-flex min-w-0 items-center gap-1.5">{body}</span>
|
|
101
|
+
)}
|
|
102
|
+
{onRemove ? (
|
|
103
|
+
<button
|
|
104
|
+
type="button"
|
|
105
|
+
aria-label={`Remove ${name}`}
|
|
106
|
+
onClick={(event) => {
|
|
107
|
+
event.stopPropagation()
|
|
108
|
+
onRemove()
|
|
109
|
+
}}
|
|
110
|
+
className={cn(
|
|
111
|
+
'inline-flex shrink-0 items-center justify-center',
|
|
112
|
+
'size-4 rounded-[3px]',
|
|
113
|
+
'cursor-pointer text-ink-3 hover:bg-surface-3 hover:text-ink',
|
|
114
|
+
'outline-none focus-visible:shadow-[var(--shadow-focus)]',
|
|
115
|
+
)}
|
|
116
|
+
>
|
|
117
|
+
<svg aria-hidden viewBox="0 0 10 10" className="size-2.5" fill="none">
|
|
118
|
+
<path
|
|
119
|
+
d="M2 2l6 6M8 2l-6 6"
|
|
120
|
+
stroke="currentColor"
|
|
121
|
+
strokeWidth="1.4"
|
|
122
|
+
strokeLinecap="round"
|
|
123
|
+
/>
|
|
124
|
+
</svg>
|
|
125
|
+
</button>
|
|
126
|
+
) : null}
|
|
127
|
+
</span>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
|
|
3
|
+
import { type AttributeType, AttributeTypeIcon } from './attribute-type-icon'
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof AttributeTypeIcon> = {
|
|
6
|
+
title: 'Components/AttributeTypeIcon',
|
|
7
|
+
component: AttributeTypeIcon,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
args: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
},
|
|
12
|
+
argTypes: {
|
|
13
|
+
type: {
|
|
14
|
+
control: { type: 'inline-radio' },
|
|
15
|
+
options: ['string', 'number', 'integer', 'datetime', 'enum', 'boolean', 'array', 'object'],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default meta
|
|
21
|
+
type Story = StoryObj<typeof AttributeTypeIcon>
|
|
22
|
+
|
|
23
|
+
export const Playground: Story = {}
|
|
24
|
+
|
|
25
|
+
const ALL_TYPES: AttributeType[] = [
|
|
26
|
+
'string',
|
|
27
|
+
'number',
|
|
28
|
+
'integer',
|
|
29
|
+
'datetime',
|
|
30
|
+
'enum',
|
|
31
|
+
'boolean',
|
|
32
|
+
'array',
|
|
33
|
+
'object',
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
export const AllTypes: Story = {
|
|
37
|
+
parameters: { controls: { hideNoControlsWarning: true } },
|
|
38
|
+
render: () => (
|
|
39
|
+
<div className="grid grid-cols-4 gap-3">
|
|
40
|
+
{ALL_TYPES.map((t) => (
|
|
41
|
+
<div
|
|
42
|
+
key={t}
|
|
43
|
+
className="flex items-center gap-2 px-3 py-2 rounded-md border border-rule bg-surface"
|
|
44
|
+
>
|
|
45
|
+
<AttributeTypeIcon type={t} className="size-4 text-ink-3" />
|
|
46
|
+
<span className="font-mono text-[12px] text-ink-2">{t}</span>
|
|
47
|
+
</div>
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const InChipContext: Story = {
|
|
54
|
+
parameters: { controls: { hideNoControlsWarning: true } },
|
|
55
|
+
render: () => (
|
|
56
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
57
|
+
{ALL_TYPES.map((t) => (
|
|
58
|
+
<span
|
|
59
|
+
key={t}
|
|
60
|
+
className="inline-flex items-center gap-1.5 pl-2 pr-2.5 py-1 rounded-sm border border-rule bg-surface font-sans text-[12.5px] text-ink"
|
|
61
|
+
>
|
|
62
|
+
<span className="text-ink-3">
|
|
63
|
+
<AttributeTypeIcon type={t} />
|
|
64
|
+
</span>
|
|
65
|
+
{t === 'datetime' ? 'created at' : t === 'enum' ? 'status' : t}
|
|
66
|
+
</span>
|
|
67
|
+
))}
|
|
68
|
+
</div>
|
|
69
|
+
),
|
|
70
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Banknote,
|
|
3
|
+
BookText,
|
|
4
|
+
Braces,
|
|
5
|
+
Brackets,
|
|
6
|
+
Calendar,
|
|
7
|
+
CircleDot,
|
|
8
|
+
Hash,
|
|
9
|
+
Link2,
|
|
10
|
+
type LucideIcon,
|
|
11
|
+
type LucideProps,
|
|
12
|
+
Paperclip,
|
|
13
|
+
ToggleLeft,
|
|
14
|
+
Type,
|
|
15
|
+
User,
|
|
16
|
+
} from 'lucide-react'
|
|
17
|
+
import { cn } from '../../lib/cn'
|
|
18
|
+
|
|
19
|
+
/* =========================================================================
|
|
20
|
+
AttributeTypeIcon — one lucide-react glyph per attribute type. Generic
|
|
21
|
+
over the lib so any attribute-aware UI (filter chips, attribute pickers,
|
|
22
|
+
schema editors, table headers, etc.) can render a consistent icon for
|
|
23
|
+
the same type without re-inventing the mapping.
|
|
24
|
+
|
|
25
|
+
Four exports:
|
|
26
|
+
|
|
27
|
+
- `AttributeType` — the canonical union of attribute-type
|
|
28
|
+
literals.
|
|
29
|
+
- `ATTRIBUTE_TYPE_ICONS` — `Record<AttributeType, LucideIcon>` for
|
|
30
|
+
direct lookups (e.g. when a consumer wants
|
|
31
|
+
the icon component itself, not a rendered
|
|
32
|
+
element).
|
|
33
|
+
- `useAttributeTypeIcon` — hook returning the matching `LucideIcon`.
|
|
34
|
+
Useful when you need to compose the icon
|
|
35
|
+
into a different layout (sized via
|
|
36
|
+
parent's prop, wrapped in a button, etc.).
|
|
37
|
+
- `AttributeTypeIcon` — convenience component with sane defaults
|
|
38
|
+
(`size-3.5`, `aria-hidden`,
|
|
39
|
+
`currentColor`).
|
|
40
|
+
|
|
41
|
+
Mapping
|
|
42
|
+
string → Type ("Aa" lowercase/uppercase glyph)
|
|
43
|
+
number → Hash ("#")
|
|
44
|
+
integer → Hash (same — they're conceptually one bucket)
|
|
45
|
+
datetime → Calendar
|
|
46
|
+
enum → CircleDot (filled-center radio metaphor)
|
|
47
|
+
boolean → ToggleLeft (toggle switch)
|
|
48
|
+
array → Brackets ("[ ]")
|
|
49
|
+
object → Braces ("{ }")
|
|
50
|
+
relation → Link2 (chain link — foreign-key reference)
|
|
51
|
+
user → User (person glyph — platform-user reference)
|
|
52
|
+
currency → Banknote (money — amount + currency_code)
|
|
53
|
+
knowledge-text → BookText (long text stored as a knowledge node)
|
|
54
|
+
file → Paperclip (attachment — stored-file reference)
|
|
55
|
+
========================================================================= */
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Attribute-type values the design system knows how to render. Exported as a
|
|
59
|
+
* value (an enum-like const object) so consumers can both reference a single
|
|
60
|
+
* member by name (`AttributeType.String`) and iterate the full set
|
|
61
|
+
* (`Object.values(AttributeType)`) without re-declaring the list. The
|
|
62
|
+
* matching type — derived from this same object — keeps the union and the
|
|
63
|
+
* runtime list in lockstep: adding a member here surfaces it in every
|
|
64
|
+
* consumer (icon mapping, type picker, designer config) automatically.
|
|
65
|
+
*/
|
|
66
|
+
export const AttributeType = {
|
|
67
|
+
String: 'string',
|
|
68
|
+
Number: 'number',
|
|
69
|
+
Integer: 'integer',
|
|
70
|
+
Datetime: 'datetime',
|
|
71
|
+
Enum: 'enum',
|
|
72
|
+
Boolean: 'boolean',
|
|
73
|
+
Array: 'array',
|
|
74
|
+
Object: 'object',
|
|
75
|
+
Relation: 'relation',
|
|
76
|
+
User: 'user',
|
|
77
|
+
Currency: 'currency',
|
|
78
|
+
KnowledgeText: 'knowledge-text',
|
|
79
|
+
File: 'file',
|
|
80
|
+
} as const
|
|
81
|
+
export type AttributeType = (typeof AttributeType)[keyof typeof AttributeType]
|
|
82
|
+
|
|
83
|
+
/** Iteration order for type pickers, dropdowns, etc. */
|
|
84
|
+
export const ATTRIBUTE_TYPES: ReadonlyArray<AttributeType> = Object.values(AttributeType)
|
|
85
|
+
|
|
86
|
+
export const ATTRIBUTE_TYPE_ICONS: Record<AttributeType, LucideIcon> = {
|
|
87
|
+
[AttributeType.String]: Type,
|
|
88
|
+
[AttributeType.Number]: Hash,
|
|
89
|
+
[AttributeType.Integer]: Hash,
|
|
90
|
+
[AttributeType.Datetime]: Calendar,
|
|
91
|
+
[AttributeType.Enum]: CircleDot,
|
|
92
|
+
[AttributeType.Boolean]: ToggleLeft,
|
|
93
|
+
[AttributeType.Array]: Brackets,
|
|
94
|
+
[AttributeType.Object]: Braces,
|
|
95
|
+
[AttributeType.Relation]: Link2,
|
|
96
|
+
[AttributeType.User]: User,
|
|
97
|
+
[AttributeType.Currency]: Banknote,
|
|
98
|
+
[AttributeType.KnowledgeText]: BookText,
|
|
99
|
+
[AttributeType.File]: Paperclip,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function useAttributeTypeIcon(type: AttributeType): LucideIcon {
|
|
103
|
+
return ATTRIBUTE_TYPE_ICONS[type]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type AttributeTypeIconProps = Omit<LucideProps, 'ref'> & {
|
|
107
|
+
type: AttributeType
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function AttributeTypeIcon({
|
|
111
|
+
type,
|
|
112
|
+
className,
|
|
113
|
+
strokeWidth,
|
|
114
|
+
...props
|
|
115
|
+
}: AttributeTypeIconProps) {
|
|
116
|
+
const Icon = useAttributeTypeIcon(type)
|
|
117
|
+
return (
|
|
118
|
+
<Icon
|
|
119
|
+
aria-hidden
|
|
120
|
+
strokeWidth={strokeWidth ?? 1.6}
|
|
121
|
+
className={cn('size-3.5', className)}
|
|
122
|
+
{...props}
|
|
123
|
+
/>
|
|
124
|
+
)
|
|
125
|
+
}
|