@keboola/design 13.2.0 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -1
- package/CHANGELOG.md +161 -0
- package/COMPONENT-API.md +52 -42
- package/dist/{AIKit-C5FbKjwa.js → AIKit-BRSZ3nY7.js} +2216 -302
- package/dist/AIKit-BRSZ3nY7.js.map +1 -0
- package/dist/{Alert-DuAGeYyM.js → Alert-CZ0dDsuk.js} +2 -2
- package/dist/{Alert-DuAGeYyM.js.map → Alert-CZ0dDsuk.js.map} +1 -1
- package/dist/{BrandEditor-Dq168RJc.js → BrandEditor-CN2HJ_12.js} +5 -5
- package/dist/{BrandEditor-Dq168RJc.js.map → BrandEditor-CN2HJ_12.js.map} +1 -1
- package/dist/{Breadcrumb-CUyYu5Bi.js → Breadcrumb-BnIlsoIH.js} +54 -12
- package/dist/Breadcrumb-BnIlsoIH.js.map +1 -0
- package/dist/{Checkbox-D9rafoKh.js → Checkbox-uFE8XLT_.js} +2 -2
- package/dist/{Checkbox-D9rafoKh.js.map → Checkbox-uFE8XLT_.js.map} +1 -1
- package/dist/{Clipboard-BHWUodAx.js → Clipboard-D-9XOqy4.js} +2 -2
- package/dist/{Clipboard-BHWUodAx.js.map → Clipboard-D-9XOqy4.js.map} +1 -1
- package/dist/{ClipboardButton-Urg-kZbh.js → ClipboardButton-DxvZG_H0.js} +2 -2
- package/dist/{ClipboardButton-Urg-kZbh.js.map → ClipboardButton-DxvZG_H0.js.map} +1 -1
- package/dist/{CodeEditor-Y0iE-SwV.js → CodeEditor-BfRSCKEs.js} +5 -5
- package/dist/{CodeEditor-Y0iE-SwV.js.map → CodeEditor-BfRSCKEs.js.map} +1 -1
- package/dist/{ColorInput-D1nC0X6i.js → ColorInput-CDKH8q_f.js} +2 -2
- package/dist/{ColorInput-D1nC0X6i.js.map → ColorInput-CDKH8q_f.js.map} +1 -1
- package/dist/{ColorModeSwitch-Cxee8jnB.js → ColorModeSwitch-DR6J2U6M.js} +2 -2
- package/dist/{ColorModeSwitch-Cxee8jnB.js.map → ColorModeSwitch-DR6J2U6M.js.map} +1 -1
- package/dist/{Combobox-B1Kjoy5J.js → Combobox-CEesMe2M.js} +240 -38
- package/dist/Combobox-CEesMe2M.js.map +1 -0
- package/dist/{Command-BuOA3V18.js → Command-T3MLRaen.js} +8 -4
- package/dist/Command-T3MLRaen.js.map +1 -0
- package/dist/{CopyField-DsOVtV2Q.js → CopyField-CNbCHw9a.js} +2 -2
- package/dist/{CopyField-DsOVtV2Q.js.map → CopyField-CNbCHw9a.js.map} +1 -1
- package/dist/{DateInput-BlKkequE.js → DateInput-ClK1lCxz.js} +2 -2
- package/dist/{DateInput-BlKkequE.js.map → DateInput-ClK1lCxz.js.map} +1 -1
- package/dist/{DateRangeInput-DOxJHw8V.js → DateRangeInput-DtlAffS1.js} +2 -2
- package/dist/{DateRangeInput-DOxJHw8V.js.map → DateRangeInput-DtlAffS1.js.map} +1 -1
- package/dist/{DropdownMenu-DtRYcKEx.js → DropdownMenu-B1gGvZoh.js} +2 -2
- package/dist/{DropdownMenu-DtRYcKEx.js.map → DropdownMenu-B1gGvZoh.js.map} +1 -1
- package/dist/{FieldItem-Cf1E3rfQ.js → FieldItem-CYvJyjiI.js} +3 -3
- package/dist/{FieldItem-Cf1E3rfQ.js.map → FieldItem-CYvJyjiI.js.map} +1 -1
- package/dist/{Form-CuaAn-lR.js → Form-CD55zJiy.js} +5 -5
- package/dist/{Form-CuaAn-lR.js.map → Form-CD55zJiy.js.map} +1 -1
- package/dist/{FormGroup-D4O96YPm.js → FormGroup-DiYFdEhH.js} +3 -3
- package/dist/{FormGroup-D4O96YPm.js.map → FormGroup-DiYFdEhH.js.map} +1 -1
- package/dist/{HoverCard-Cy6nhg4u.js → HoverCard-BBdPYqEf.js} +2 -2
- package/dist/HoverCard-BBdPYqEf.js.map +1 -0
- package/dist/{InlineEdit-DSMIEUUa.js → InlineEdit-D5RdunZo.js} +3 -3
- package/dist/{InlineEdit-DSMIEUUa.js.map → InlineEdit-D5RdunZo.js.map} +1 -1
- package/dist/{Kbd-Du93F3o4.js → Kbd-3YM7NQO4.js} +2 -2
- package/dist/{Kbd-Du93F3o4.js.map → Kbd-3YM7NQO4.js.map} +1 -1
- package/dist/MermaidDiagram-CeiOkI60.js +199 -0
- package/dist/MermaidDiagram-CeiOkI60.js.map +1 -0
- package/dist/{Modal-DQIauzar.js → Modal-DMZRswk4.js} +4 -3
- package/dist/Modal-DMZRswk4.js.map +1 -0
- package/dist/{MultiActionButtonGroup-xKqiucAN.js → MultiActionButtonGroup-CEv_txvz.js} +2 -2
- package/dist/{MultiActionButtonGroup-xKqiucAN.js.map → MultiActionButtonGroup-CEv_txvz.js.map} +1 -1
- package/dist/{RadioGroup-C2vk5acr.js → RadioGroup-C8EC3fqO.js} +2 -2
- package/dist/{RadioGroup-C2vk5acr.js.map → RadioGroup-C8EC3fqO.js.map} +1 -1
- package/dist/{Search-CVrv3hqf.js → Search-aaUMI4ix.js} +2 -2
- package/dist/{Search-CVrv3hqf.js.map → Search-aaUMI4ix.js.map} +1 -1
- package/dist/{SearchInput-BnU6YHgT.js → SearchInput-Dxi2GK4n.js} +2 -2
- package/dist/{SearchInput-BnU6YHgT.js.map → SearchInput-Dxi2GK4n.js.map} +1 -1
- package/dist/{SectionNav-XlhvXXdF.js → SectionNav-BnHOMLtE.js} +3 -3
- package/dist/{SectionNav-XlhvXXdF.js.map → SectionNav-BnHOMLtE.js.map} +1 -1
- package/dist/Sheet-utw4_rUa.js.map +1 -1
- package/dist/{Sidebar-CKaxOPwY.js → Sidebar-BAmux2Uj.js} +5 -5
- package/dist/{Sidebar-CKaxOPwY.js.map → Sidebar-BAmux2Uj.js.map} +1 -1
- package/dist/{Slider-Rcc2qVct.js → Slider-DbzzSDRV.js} +2 -2
- package/dist/{Slider-Rcc2qVct.js.map → Slider-DbzzSDRV.js.map} +1 -1
- package/dist/{Table-CgSC-fSo.js → Table-CilEvpMq.js} +62 -3
- package/dist/Table-CilEvpMq.js.map +1 -0
- package/dist/{TextInput-B5TDDOty.js → TextInput-K2DSDs5O.js} +2 -2
- package/dist/{TextInput-B5TDDOty.js.map → TextInput-K2DSDs5O.js.map} +1 -1
- package/dist/{ThemeProvider-Dt9b67sW.js → ThemeProvider-C8yaKlM1.js} +2 -2
- package/dist/{ThemeProvider-Dt9b67sW.js.map → ThemeProvider-C8yaKlM1.js.map} +1 -1
- package/dist/ToggleAllTooltip-Dlmq-yqS.js +37 -0
- package/dist/ToggleAllTooltip-Dlmq-yqS.js.map +1 -0
- package/dist/{ZoomableSvg-D8sXKpoV.js → ZoomableSvg-Dh1OstPN.js} +84 -80
- package/dist/ZoomableSvg-Dh1OstPN.js.map +1 -0
- package/dist/editors.js +3 -3
- package/dist/flint.js +10 -45
- package/dist/flint.js.map +1 -1
- package/dist/highlightCode-D354tCXO.js +81 -0
- package/dist/highlightCode-D354tCXO.js.map +1 -0
- package/dist/index.d.ts +792 -346
- package/dist/index.js +35 -35
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ChipEditor.js +1 -1
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.js +1 -1
- package/dist/internal/blocks/ColorModeSwitch.js +1 -1
- package/dist/internal/blocks/Command.js +1 -1
- package/dist/internal/blocks/CopyField.js +1 -1
- package/dist/internal/blocks/DateInput.js +1 -1
- package/dist/internal/blocks/DateRangeInput.js +1 -1
- package/dist/internal/blocks/DiagramShared/DiagramSkeleton.js.map +1 -1
- package/dist/internal/blocks/ExportMenu.js +2 -2
- package/dist/internal/blocks/Form/connectors/ComboboxField.js +2 -2
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
- package/dist/internal/blocks/Form.js +1 -1
- package/dist/internal/blocks/FormGroup.js +1 -1
- package/dist/internal/blocks/InlineEdit.js +1 -1
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
- package/dist/internal/blocks/MultiCombobox.js +204 -68
- package/dist/internal/blocks/MultiCombobox.js.map +1 -1
- package/dist/internal/blocks/PasswordInput.js +1 -1
- package/dist/internal/blocks/SearchInput.js +1 -1
- package/dist/internal/blocks/SearchInputWithNavigation.js +2 -2
- package/dist/internal/blocks/SectionNav.js +1 -1
- package/dist/internal/blocks/SplitButton.js +1 -1
- package/dist/internal/blocks/TextInput.js +1 -1
- package/dist/internal/blocks/TimeInput.js +1 -1
- package/dist/internal/components/Alert.js +1 -1
- package/dist/internal/components/Avatar.js +1 -1
- package/dist/internal/components/Breadcrumb.js +1 -1
- package/dist/internal/components/Checkbox.js +1 -1
- package/dist/internal/components/Clipboard.js +1 -1
- package/dist/internal/components/CollapsiblePanel.js +1 -1
- package/dist/internal/components/Combobox.js +1 -1
- package/dist/internal/components/DropdownMenu.js +1 -1
- package/dist/internal/components/HoverCard.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/Modal.js +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Skeleton/Skeleton.js +1 -1
- package/dist/internal/components/Skeleton/Skeleton.js.map +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/Table.js +1 -1
- package/dist/internal/components/ThemeProvider.js +1 -1
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/utils.js +1 -1
- package/dist/markdown-editor.js +6 -6
- package/dist/mermaid.d.ts +1 -2
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +98 -11
- package/dist/rjsf.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/svgCache-Dhmbe-7i.js +26 -0
- package/dist/svgCache-Dhmbe-7i.js.map +1 -0
- package/dist/svgTransforms-Hnvev3Vs.js +38 -0
- package/dist/svgTransforms-Hnvev3Vs.js.map +1 -0
- package/dist/testing.js +1 -1
- package/dist/{themeTokens-7DEab0kp.js → themeTokens-l2Fsfcs7.js} +3 -12
- package/dist/themeTokens-l2Fsfcs7.js.map +1 -0
- package/dist/{utils-p6tjltbX.js → utils-LQ4jJA-9.js} +18 -2
- package/dist/utils-LQ4jJA-9.js.map +1 -0
- package/dist/vega.js +1 -1
- package/dist/vegaTheme-BrmVoPEz.js +49 -0
- package/dist/vegaTheme-BrmVoPEz.js.map +1 -0
- package/dist/{vegaTheme-VQMWTlBw.js → vegaTokens-Ce07C0DH.js} +36 -44
- package/dist/vegaTokens-Ce07C0DH.js.map +1 -0
- package/package.json +3 -4
- package/src/styles.css +4 -4
- package/dist/AIKit-C5FbKjwa.js.map +0 -1
- package/dist/Breadcrumb-CUyYu5Bi.js.map +0 -1
- package/dist/Combobox-B1Kjoy5J.js.map +0 -1
- package/dist/Command-BuOA3V18.js.map +0 -1
- package/dist/DiagramSource-jTwmmi9g.js +0 -11
- package/dist/DiagramSource-jTwmmi9g.js.map +0 -1
- package/dist/HoverCard-Cy6nhg4u.js.map +0 -1
- package/dist/MermaidDiagram-D2ThT8Q-.js +0 -302
- package/dist/MermaidDiagram-D2ThT8Q-.js.map +0 -1
- package/dist/Modal-DQIauzar.js.map +0 -1
- package/dist/Table-CgSC-fSo.js.map +0 -1
- package/dist/ZoomableSvg-D8sXKpoV.js.map +0 -1
- package/dist/svgTransforms-Dw2hRA-i.js +0 -51
- package/dist/svgTransforms-Dw2hRA-i.js.map +0 -1
- package/dist/themeTokens-7DEab0kp.js.map +0 -1
- package/dist/utils-p6tjltbX.js.map +0 -1
- package/dist/vegaTheme-VQMWTlBw.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MermaidDiagram-D2ThT8Q-.js","names":[],"sources":["../src/blocks/MermaidDiagram/mermaidTheme.ts","../src/blocks/MermaidDiagram/MermaidDiagram.tsx"],"sourcesContent":["import type { RenderOptions } from 'beautiful-mermaid';\nimport type { MermaidConfig } from 'mermaid';\n\nimport type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { createTokenResolver } from '../../utils/themeTokens';\n\nconst DIAGRAM_FONT = 'Inter, system-ui, sans-serif';\n\n/**\n * Token fallbacks; keep in sync with the `:root` / `[data-theme='dark']` blocks of `styles.css`.\n *\n * - Used only when the live custom property is missing (SSR, tests without CSS).\n */\nconst FALLBACK_CHANNELS = {\n card: { light: '255 255 255', dark: '34 34 40' },\n 'card-foreground': { light: '30 41 59', dark: '229 230 236' },\n foreground: { light: '30 41 59', dark: '229 230 236' },\n muted: { light: '241 245 249', dark: '38 38 45' },\n 'muted-foreground': { light: '100 116 139', dark: '141 144 153' },\n border: { light: '229 231 235', dark: '52 53 62' },\n primary: { light: '37 99 235', dark: '31 143 255' },\n accent: { light: '224 242 254', dark: '30 58 95' },\n 'accent-foreground': { light: '13 65 127', dark: '147 197 253' },\n warning: { light: '138 82 16', dark: '255 190 92' },\n success: { light: '24 122 76', dark: '62 207 127' },\n destructive: { light: '220 38 38', dark: '229 72 77' },\n} as const;\n\ntype TokenName = keyof typeof FALLBACK_CHANNELS;\n\n/** One `getComputedStyle` snapshot per palette; never hoist — values follow scheme and brand. */\nconst tokenReader = (scheme: ResolvedColorScheme, from?: Element | null) => {\n const resolve = createTokenResolver(from);\n return (name: TokenName, alpha?: number): string =>\n resolve(name, FALLBACK_CHANNELS[name][scheme], alpha);\n};\n\n/**\n * Palette for `beautiful-mermaid`'s synchronous renderer.\n *\n * - It derives the rest from `bg` + `fg` via `color-mix()`, so both must be set.\n * - With `transparent`, `bg` only feeds those derivations; `surface` pins the node fill.\n */\nexport const fastRenderOptions = (\n scheme: ResolvedColorScheme,\n from?: Element | null,\n): RenderOptions => {\n const token = tokenReader(scheme, from);\n\n return {\n bg: token('card'),\n fg: token('foreground'),\n line: token('border'),\n accent: token('primary'),\n muted: token('muted-foreground'),\n surface: token('muted'),\n border: token('border'),\n transparent: true,\n font: DIAGRAM_FONT,\n };\n};\n\n/**\n * Config for the async `mermaid` renderer (unparseable dialects and icon diagrams).\n *\n * - `base` theme, so every colour comes from `themeVariables`.\n * - Status tokens are text colours, so fills use a low-alpha tint (brand-neutrality contract).\n */\nexport const mermaidConfig = (\n scheme: ResolvedColorScheme,\n from?: Element | null,\n): MermaidConfig => {\n const token = tokenReader(scheme, from);\n\n const surface = token('accent');\n const onSurface = token('accent-foreground');\n const container = token('card');\n const onContainer = token('card-foreground');\n const line = token('border');\n const stroke = token('primary');\n const text = token('foreground');\n\n return {\n startOnLoad: false,\n securityLevel: 'strict',\n theme: 'base',\n themeVariables: {\n darkMode: scheme === 'dark',\n background: container,\n primaryColor: surface,\n primaryTextColor: onSurface,\n primaryBorderColor: stroke,\n secondaryColor: container,\n secondaryTextColor: onContainer,\n secondaryBorderColor: line,\n tertiaryColor: token('warning', 0.15),\n tertiaryTextColor: token('warning'),\n tertiaryBorderColor: token('warning'),\n lineColor: line,\n textColor: text,\n mainBkg: surface,\n nodeBorder: stroke,\n clusterBkg: container,\n clusterBorder: line,\n titleColor: text,\n edgeLabelBackground: container,\n nodeTextColor: onSurface,\n actorBorder: stroke,\n actorBkg: surface,\n actorTextColor: onSurface,\n actorLineColor: line,\n signalColor: text,\n signalTextColor: text,\n labelBoxBkgColor: surface,\n labelBoxBorderColor: stroke,\n labelTextColor: onSurface,\n loopTextColor: text,\n noteBorderColor: token('warning'),\n noteBkgColor: token('warning', 0.15),\n noteTextColor: text,\n sectionBkgColor: surface,\n altSectionBkgColor: container,\n sectionBkgColor2: token('muted'),\n taskBorderColor: stroke,\n taskBkgColor: surface,\n taskTextColor: onSurface,\n taskTextDarkColor: text,\n taskTextLightColor: text,\n activeTaskBorderColor: stroke,\n activeTaskBkgColor: token('primary', 0.25),\n doneTaskBorderColor: token('success'),\n doneTaskBkgColor: token('success', 0.15),\n critBorderColor: token('destructive'),\n critBkgColor: token('destructive', 0.15),\n fontFamily: DIAGRAM_FONT,\n fontSize: '14px',\n },\n };\n};\n","import { useEffect, useId, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { renderMermaidSVG } from 'beautiful-mermaid';\nimport type mermaid from 'mermaid';\n\nimport type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { useThemeAttributes } from '../../components/ThemeProvider/useThemeAttributes';\nimport { ZoomableSvg } from '../../components/ZoomableSvg';\nimport { DiagramSkeleton } from '../DiagramShared/DiagramSkeleton';\nimport { DiagramSource } from '../DiagramShared/DiagramSource';\nimport {\n flattenForeignObjectLabels,\n hasDrawnContent,\n makeResponsive,\n} from '../DiagramShared/svgTransforms';\n\nimport { fastRenderOptions, mermaidConfig } from './mermaidTheme';\n\ntype MermaidModule = { default: typeof mermaid };\n\nlet mermaidPromise: Promise<MermaidModule> | null = null;\n\n// Makes `lucide:name` icon refs render; the pack is a lazy local chunk, so no CDN fetch and it works under strict CSP.\nconst registerLucideIconPack = (m: typeof mermaid): void => {\n m.registerIconPacks([\n {\n name: 'lucide',\n loader: () => import('@iconify-json/lucide/icons.json').then((mod) => mod.default),\n },\n ]);\n};\n\nconst getMermaid = (): Promise<MermaidModule> => {\n if (!mermaidPromise) {\n mermaidPromise = import('mermaid')\n .then((m) => {\n registerLucideIconPack(m.default);\n return m;\n })\n .catch((err) => {\n mermaidPromise = null;\n throw err;\n });\n }\n return mermaidPromise;\n};\n\nconst stripFontImports = (svg: string): string =>\n svg.replace(/@import\\s+url\\([^)]*fonts\\.googleapis\\.com[^)]*\\);?\\s*/g, '');\n\n// The fast renderer has no icon packs, so icon syntax takes the async path. Matches:\n// - `@{ icon: \"pack:name\" }`\n// - `icon|service|group <id>(pack:name)`, id optional\n// - FontAwesome `fa:fa-*` / `fab:` in node text\nconst hasIconSyntax = (code: string): boolean =>\n /@\\{[^}]*\\bicon\\s*:/.test(code) ||\n /\\b(?:icon|service|group)\\b[^\\n(]*\\(\\s*[\\w-]+:/.test(code) ||\n /\\bfa[bslr]?:fa-/.test(code);\n\nconst tryFastRender = (\n code: string,\n scheme: ResolvedColorScheme,\n from: Element | null,\n): string | null => {\n if (hasIconSyntax(code)) return null;\n try {\n const svg = stripFontImports(renderMermaidSVG(code, fastRenderOptions(scheme, from)));\n // A zero-sized result is a silent layout failure — fall back instead of caching it.\n return hasDrawnContent(svg) ? svg : null;\n } catch (err) {\n // Unsupported dialects are expected here; debug level keeps the console quiet.\n console.debug('[MermaidDiagram] fast render unavailable, using async fallback:', err);\n return null;\n }\n};\n\n/**\n * Whether a mermaid parse error means \"ran out of input\" rather than \"bad syntax\".\n *\n * - Jison parsers report end of input as token `1`, as in every streaming frame.\n * - Lower bound only: some truncations hit a real token and show as `<pre>` for one frame.\n */\nconst isTruncatedDiagram = (err: unknown): boolean =>\n typeof err === 'object' && err !== null && 'hash' in err\n ? (err as { hash?: { token?: unknown } }).hash?.token === 1\n : false;\n\nconst RENDER_DEBOUNCE_MS = 300;\n\n// Longer than the gap between streamed chunks, short enough for an abandoned stream.\nconst TRUNCATION_GRACE_MS = 2_000;\n\n// Survives remounts. Colours are baked into the SVG, so the key includes the theme key.\nconst svgCache = new Map<string, string>();\n\nconst diagramCacheKey = (code: string, themeKey: string): string => `${themeKey}\\n${code}`;\n\n// Cache hit or fast render; null means the caller takes the async render.\nconst resolveSyncSvg = (\n code: string,\n cacheKey: string,\n scheme: ResolvedColorScheme,\n from: Element | null,\n): string | null => {\n const cached = svgCache.get(cacheKey);\n if (cached) return cached;\n const fast = tryFastRender(code, scheme, from);\n if (fast) svgCache.set(cacheKey, fast);\n return fast;\n};\n\ntype Props = {\n /** Mermaid source. Gantt time-only `dateFormat HH:mm` is unsupported — use\n * `dateFormat YYYY-MM-DD HH:mm` with `axisFormat %H:%M`. */\n code: string;\n /** Extra toolbar controls forwarded to `ZoomableSvg`; receives the sanitized SVG. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const MermaidDiagram = ({ code, renderActions }: Props) => {\n const id = useId();\n // - Scheme and key come from one read, so a palette is never cached under the wrong scheme.\n // - `scope` is the element tokens are read off (`null` = `<html>`) and is part of `themeKey`.\n const { scheme, cacheKey: themeKey, scope } = useThemeAttributes();\n const cacheKey = diagramCacheKey(code, themeKey);\n\n const [svg, setSvg] = useState<string | null>(() =>\n resolveSyncSvg(code, cacheKey, scheme, scope),\n );\n const [renderFailed, setRenderFailed] = useState(false);\n const [truncated, setTruncated] = useState(false);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const renderIdRef = useRef(0);\n\n // Render-phase reset avoids a one-frame flash of the previous diagram.\n const [prevKey, setPrevKey] = useState(cacheKey);\n if (cacheKey !== prevKey) {\n setPrevKey(cacheKey);\n setSvg(resolveSyncSvg(code, cacheKey, scheme, scope));\n setRenderFailed(false);\n setTruncated(false);\n }\n\n useEffect(() => {\n // Sync results are already applied by the initializer and the render-phase reset.\n if (svgCache.has(cacheKey)) return;\n\n const currentRenderId = ++renderIdRef.current;\n\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n\n debounceRef.current = setTimeout(() => {\n getMermaid()\n .then(async (mermaidModule) => {\n if (renderIdRef.current !== currentRenderId) return;\n const rendererId = `mermaid-${id.replaceAll(':', '')}`;\n const container = document.createElement('div');\n container.style.visibility = 'hidden';\n container.style.position = 'absolute';\n container.style.top = '-9999px';\n container.style.width = '900px';\n document.body.appendChild(container);\n // Per render: `initialize` is the only way to change mermaid's palette.\n mermaidModule.default.initialize(mermaidConfig(scheme, scope));\n try {\n const result = await mermaidModule.default.render(rendererId, code, container);\n if (renderIdRef.current === currentRenderId && result) {\n const svgOutput = flattenForeignObjectLabels(result.svg);\n svgCache.set(cacheKey, svgOutput);\n setSvg(svgOutput);\n setRenderFailed(false);\n setTruncated(false);\n }\n } finally {\n container.remove();\n }\n })\n .catch((err: unknown) => {\n if (renderIdRef.current !== currentRenderId) return;\n setSvg(null);\n // A streaming diagram is truncated at almost every frame — keep the skeleton, not `<pre>`.\n if (isTruncatedDiagram(err)) {\n console.debug('[MermaidDiagram] incomplete diagram, awaiting more input:', err);\n setTruncated(true);\n return;\n }\n console.error('[MermaidDiagram] fallback failed:', err);\n setRenderFailed(true);\n });\n }, RENDER_DEBOUNCE_MS);\n\n const timer = debounceRef.current;\n const renderId = renderIdRef;\n return () => {\n renderId.current++;\n if (timer) {\n clearTimeout(timer);\n }\n };\n }, [cacheKey, code, id, scheme, scope]);\n\n // A truncated diagram may never get another chunk, so fall back to source after a grace period.\n // A new chunk resets `truncated` and clears the timer.\n useEffect(() => {\n if (!truncated) return;\n const timer = setTimeout(() => setRenderFailed(true), TRUNCATION_GRACE_MS);\n return () => clearTimeout(timer);\n }, [truncated, cacheKey]);\n\n const processedSvg = svg ? makeResponsive(svg) : null;\n\n if (renderFailed) {\n return <DiagramSource code={code} />;\n }\n\n if (processedSvg) {\n return (\n <ZoomableSvg\n key={code}\n html={processedSvg}\n copyText={`\\`\\`\\`mermaid\\n${code}\\n\\`\\`\\``}\n className=\"tw:my-3\"\n allowForeignObject\n renderActions={renderActions}\n />\n );\n }\n\n return <DiagramSkeleton />;\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Modal-DQIauzar.js","names":[],"sources":["../src/components/Modal/ModalBody.tsx","../src/components/Modal/ModalContent.tsx","../src/components/Modal/ModalFooter.tsx","../src/components/Modal/ModalActions.tsx","../src/components/Modal/ModalHeader.tsx","../src/components/Modal/ModalIcon.tsx","../src/components/Modal/ModalImage.tsx","../src/components/Modal/Modal.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\n/** Props for `Modal.Body`. Accepts all `<div>` attributes; `as=\"form\"` is reserved for future use. */\ntype Props = ComponentProps<'div'> & {\n as?: 'form';\n};\n\n/**\n * Scrollable body slot for `Modal`. Place form fields, content blocks, or detail panels here.\n * Takes available height inside `Modal.Content` and scrolls when content overflows.\n */\nexport const ModalBody = ({ className, ...props }: Props) => (\n <div\n data-slot=\"modal-body\"\n className={cn(\n // scrollable body - takes available space and scrolls when content overflows\n 'tw:flex-1',\n 'tw:overflow-y-auto',\n\n // argo: soft top/bottom edge fade in place of header/footer separators (pure-CSS utility)\n 'tw:group-data-[argo=true]/modal:scroll-fade-y',\n\n // Own horizontal padding, matching Header/Footer so content edges align (ModalContent adds none)\n 'tw:group-data-[argo=false]/modal:px-7',\n 'tw:group-data-[argo=true]/modal:px-4',\n 'tw:py-1',\n\n // normalize nested Lucide icon sizing, matching Popover/HoverCard/Alert content surfaces\n \"tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4\",\n 'tw:[&_svg]:shrink-0',\n className,\n )}\n {...props}\n />\n);\n","import type { ComponentProps } from 'react';\nimport { Content, Portal } from '@radix-ui/react-dialog';\n\nimport { cn } from '../../utils';\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nimport { ModalOverlay } from './ModalOverlay';\n\ntype Props = ComponentProps<typeof Content> & {\n size?: 'small' | 'medium' | 'large';\n};\n\nexport const ModalContent = ({\n size = 'medium',\n className,\n children,\n onEscapeKeyDown,\n ...props\n}: Props) => {\n const renderArgo = useArgoDesign();\n\n const handleEscapeKeyDown: typeof onEscapeKeyDown = (event) => {\n // Keeps parent modals (e.g. FullScreenModal) open\n event.stopPropagation();\n onEscapeKeyDown?.(event);\n };\n\n return (\n <Portal>\n <ModalOverlay>\n <Content\n // props first so callers can't override the computed data-argo / data-size\n {...props}\n data-argo={renderArgo}\n data-size={size}\n className={cn(\n 'tailwindcss-preflight',\n 'tw:group/modal',\n\n 'tw:fixed',\n 'tw:left-1/2',\n 'tw:-translate-x-1/2',\n 'tw:z-[1051]',\n\n 'tw:data-[argo=false]:top-20',\n 'tw:data-[argo=true]:top-1/2',\n 'tw:data-[argo=true]:-translate-y-1/2',\n\n 'tw:w-full',\n 'tw:max-w-2xl',\n 'tw:max-h-[calc(100vh-2*theme(spacing.20))]',\n\n 'tw:flex',\n 'tw:flex-col',\n 'tw:gap-4',\n 'tw:data-[argo=false]:rounded-lg',\n 'tw:data-[argo=true]:rounded-modal',\n 'tw:bg-card',\n 'tw:text-card-foreground',\n\n // Vertical padding here survives an omitted Header/Footer; horizontal is theirs, so the\n // Body scrollbar sits at the modal edge.\n 'tw:data-[argo=false]:py-8',\n 'tw:data-[argo=true]:py-4',\n\n 'tw:duration-200',\n 'tw:data-[state=open]:animate-in',\n 'tw:data-[state=open]:fade-in-0',\n 'tw:data-[state=closed]:animate-out',\n 'tw:data-[state=closed]:fade-out-0',\n\n // No -1/2 slide classes: centring uses `translate`, the animation `transform`; they\n // compose, so a -50% slide would stack to -100% and fly in from the top-left.\n\n // legacy is top-anchored, so its slide has no centring translate to double\n 'tw:data-[argo=false]:data-[state=open]:zoom-in-80',\n 'tw:data-[argo=false]:data-[state=open]:slide-in-from-top-[48%]',\n 'tw:data-[argo=false]:data-[state=closed]:zoom-out-80',\n 'tw:data-[argo=false]:data-[state=closed]:slide-out-to-top-[48%]',\n\n 'tw:data-[argo=true]:data-[state=open]:zoom-in-95',\n 'tw:data-[argo=true]:data-[state=closed]:zoom-out-95',\n\n {\n 'tw:max-w-[480px]': size === 'small',\n 'tw:max-w-4xl': size === 'large',\n },\n\n className,\n )}\n onEscapeKeyDown={handleEscapeKeyDown}\n >\n {children}\n </Content>\n </ModalOverlay>\n </Portal>\n );\n};\n","import type { ComponentPropsWithRef } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentPropsWithRef<'div'>;\n\n/**\n * The modal's action row.\n *\n * - A child that should fill the row carries `tw:w-full` itself; the footer is already full width.\n * - tailwind-merge replaces only within a group: `tw:flex-col` keeps `items-center`, so add `tw:items-stretch`.\n */\nexport const ModalFooter = ({ className, ...props }: Props) => (\n <div\n {...props}\n className={cn(\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-end',\n 'tw:gap-2',\n\n 'tw:group-data-[argo=false]/modal:px-7',\n 'tw:group-data-[argo=true]/modal:px-4',\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'>;\n\n/**\n * Container for the header's top-right controls — any `actions` passed to `Modal.Header` plus the\n * close icon. Sits in the header grid's last column, top-aligned. Mirrors `Alert`'s action slot.\n */\nexport const ModalActions = ({ className, ...props }: Props) => (\n <div\n className={cn(\n 'tw:col-start-3',\n 'tw:row-start-1',\n 'tw:self-start',\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-1',\n // argo: gutter separating the actions/close from the title (carried here so the grid needs no\n // column gap — see ModalHeader)\n 'tw:group-data-[argo=true]/modal:ml-3',\n className,\n )}\n {...props}\n />\n);\n","import type { ComponentProps, ReactNode } from 'react';\nimport { Close } from '@radix-ui/react-dialog';\n\nimport { X } from '../../icons';\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\nimport { Separator } from '../Separator';\n\nimport { ModalActions } from './ModalActions';\nimport { ModalDescription } from './ModalDescription';\nimport { ModalTitle } from './ModalTitle';\n\ntype Props = {\n /** Status icon slot — `<Modal.Icon />` or `<Modal.Image />`. */\n icon?: ReactNode;\n /** Visible subtitle below the title (also fills `aria-describedby`). */\n description?: ReactNode;\n /** Screen-reader-only description; fills `aria-describedby` without rendering visibly. */\n 'aria-description'?: string;\n /** Controls rendered top-right, before the close icon. */\n actions?: ReactNode;\n /** Hide the top-right close icon. */\n hideCloseIcon?: boolean;\n} & ComponentProps<'div'>;\n\n/** Modal header: `[icon] | title (children) | actions + close` on row 1, `description` on row 2. */\nexport const ModalHeader = ({\n className,\n icon,\n description,\n 'aria-description': ariaDescription,\n actions,\n hideCloseIcon = false,\n children,\n ...props\n}: Props) => (\n <div\n {...props}\n data-slot=\"modal-header\"\n className={cn(\n 'tw:grid',\n 'tw:grid-cols-[auto_1fr_auto]',\n 'tw:items-center',\n 'tw:group-data-[argo=false]/modal:px-7',\n 'tw:group-data-[argo=true]/modal:px-4',\n className,\n )}\n >\n {icon}\n\n {children && <ModalTitle className=\"tw:col-start-2 tw:row-start-1\">{children}</ModalTitle>}\n {(actions || !hideCloseIcon) && (\n <ModalActions>\n {actions}\n {!hideCloseIcon && (\n <Close asChild>\n <Button variant=\"invisible\" size=\"icon-sm\">\n <X />\n <span className=\"tw:sr-only\">Close</span>\n </Button>\n </Close>\n )}\n </ModalActions>\n )}\n {(description || ariaDescription) && (\n <ModalDescription\n className={cn(\n 'tw:col-start-1',\n 'tw:col-end-4',\n 'tw:row-start-2',\n description ? 'tw:mt-1' : 'tw:sr-only',\n )}\n >\n {description ?? ariaDescription}\n </ModalDescription>\n )}\n\n {/* Legacy-only separator; shown when a Body follows, hidden when that body hosts Tabs. */}\n <div\n className={cn(\n 'tw:col-start-1',\n 'tw:col-end-4',\n 'tw:mt-5',\n 'tw:hidden',\n 'tw:group-data-[argo=false]/modal:[[data-slot=modal-header]:has(~[data-slot=modal-body])_&]:block',\n 'tw:group-data-[argo=false]/modal:[[data-slot=modal-header]:has(~[data-slot=modal-body]_[data-slot=tabs-root])_&]:!hidden',\n )}\n >\n <Separator orientation=\"horizontal\" />\n </div>\n </div>\n);\n","import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils';\n\ntype NamedColor = 'orange' | 'blue' | 'red' | 'green' | 'gray' | 'violet';\n\ntype Props = {\n color: NamedColor | (string & {});\n icon: ReactNode;\n};\n\nconst NAMED_COLORS = new Set<string>(['orange', 'blue', 'red', 'green', 'gray', 'violet']);\n\n/**\n * Status-coloured icon for `Modal`, authored inside `Modal.Header`; remote images use `Modal.Image`.\n *\n * - Legacy: solid circular badge, absolutely docked to `Modal.Content`'s top-left.\n * - Argo (`data-argo` on `Modal.Content`): soft-tinted inline badge next to the title.\n * - CSS (`group-data-[argo=true]/modal:`) toggles the two, no context.\n * - `color` is categorical (`red` destructive … `violet` agent), fixed across brand themes.\n */\nexport const ModalIcon = ({ color, icon }: Props) => {\n const customColor = color && !NAMED_COLORS.has(color) ? color : undefined;\n\n return (\n <span\n data-slot=\"modal-icon\"\n className={cn(\n 'tw:flex',\n 'tw:shrink-0',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:[&_svg]:aspect-square',\n\n // legacy\n 'tw:group-data-[argo=false]/modal:absolute',\n 'tw:group-data-[argo=false]/modal:top-0',\n 'tw:group-data-[argo=false]/modal:left-8',\n 'tw:group-data-[argo=false]/modal:-translate-y-1/2',\n 'tw:group-data-[argo=false]/modal:size-12',\n 'tw:group-data-[argo=false]/modal:rounded-full',\n 'tw:group-data-[argo=false]/modal:[&_svg:not([class*=\"tw:size-\"])]:size-6',\n\n // argo\n 'tw:group-data-[argo=true]/modal:col-start-1',\n 'tw:group-data-[argo=true]/modal:row-start-1',\n 'tw:group-data-[argo=true]/modal:self-start',\n 'tw:group-data-[argo=true]/modal:mr-3',\n 'tw:group-data-[argo=true]/modal:size-8',\n 'tw:group-data-[argo=true]/modal:rounded',\n 'tw:group-data-[argo=true]/modal:overflow-hidden',\n 'tw:group-data-[argo=true]/modal:[&_svg:not([class*=\"tw:size-\"])]:size-5',\n\n // legacy palette\n {\n 'tw:group-data-[argo=false]/modal:bg-warning-500': color === 'orange',\n 'tw:group-data-[argo=false]/modal:bg-blue-500': color === 'blue',\n 'tw:group-data-[argo=false]/modal:bg-green-500': color === 'green',\n 'tw:group-data-[argo=false]/modal:bg-error-500': color === 'red',\n 'tw:group-data-[argo=false]/modal:bg-neutral-150': color === 'gray',\n 'tw:group-data-[argo=false]/modal:bg-purple-100': color === 'violet',\n 'tw:group-data-[argo=false]/modal:text-white': color !== 'violet',\n 'tw:group-data-[argo=false]/modal:text-purple-500': color === 'violet',\n },\n\n // argo palette\n {\n 'tw:group-data-[argo=true]/modal:bg-warning-100 tw:group-data-[argo=true]/modal:text-warning-500':\n color === 'orange',\n 'tw:group-data-[argo=true]/modal:bg-blue-100 tw:group-data-[argo=true]/modal:text-blue-600':\n color === 'blue',\n 'tw:group-data-[argo=true]/modal:bg-green-100 tw:group-data-[argo=true]/modal:text-green-900':\n color === 'green',\n 'tw:group-data-[argo=true]/modal:bg-error-100 tw:group-data-[argo=true]/modal:text-error-500':\n color === 'red',\n 'tw:group-data-[argo=true]/modal:bg-neutral-100 tw:group-data-[argo=true]/modal:text-neutral-500':\n color === 'gray',\n 'tw:group-data-[argo=true]/modal:bg-purple-100 tw:group-data-[argo=true]/modal:text-purple-500':\n color === 'violet',\n },\n\n // custom (non-named) colour\n { 'tw:text-white': !!customColor },\n )}\n style={customColor ? { backgroundColor: customColor } : undefined}\n >\n {icon}\n </span>\n );\n};\n","import { useEffect, useState } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = {\n src: string;\n /** Accessible alt text. Defaults to `\"\"` (decorative) — provide it when the image carries meaning. */\n alt?: string;\n};\n\nexport const ModalImage = ({ src, alt = '' }: Props) => {\n const [hasImageError, setHasImageError] = useState(false);\n\n // Reset the error state when the source changes, so a reused badge (new logo, or a retry after a\n // transient failure) isn't permanently hidden by an earlier onError.\n useEffect(() => setHasImageError(false), [src]);\n\n if (hasImageError) return null;\n\n return (\n <span\n data-slot=\"modal-image\"\n className={cn(\n 'tw:shrink-0',\n 'tw:overflow-hidden',\n\n // legacy: circular badge floating at the top-left of the modal\n 'tw:group-data-[argo=false]/modal:absolute',\n 'tw:group-data-[argo=false]/modal:top-0',\n 'tw:group-data-[argo=false]/modal:left-8',\n 'tw:group-data-[argo=false]/modal:-translate-y-1/2',\n 'tw:group-data-[argo=false]/modal:size-12',\n 'tw:group-data-[argo=false]/modal:rounded-full',\n\n // argo: inline badge in the header grid's first column\n 'tw:group-data-[argo=true]/modal:flex',\n 'tw:group-data-[argo=true]/modal:col-start-1',\n 'tw:group-data-[argo=true]/modal:row-start-1',\n 'tw:group-data-[argo=true]/modal:self-start',\n 'tw:group-data-[argo=true]/modal:mr-3',\n 'tw:group-data-[argo=true]/modal:items-center',\n 'tw:group-data-[argo=true]/modal:justify-center',\n 'tw:group-data-[argo=true]/modal:rounded',\n 'tw:group-data-[argo=true]/modal:size-8',\n )}\n >\n <img\n src={src}\n alt={alt}\n className=\"tw:size-full tw:object-contain\"\n onError={() => setHasImageError(true)}\n />\n </span>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Close, Root, Trigger } from '@radix-ui/react-dialog';\n\nimport { ModalBody } from './ModalBody';\nimport { ModalContent } from './ModalContent';\nimport { ModalFooter } from './ModalFooter';\nimport { ModalHeader } from './ModalHeader';\nimport { ModalIcon } from './ModalIcon';\nimport { ModalImage } from './ModalImage';\nimport { ModalOverlay } from './ModalOverlay';\n\ntype Props = ComponentProps<typeof Root>;\n\n/**\n * Blocking dialog the user must act on before continuing. Built on Radix Dialog.\n *\n * - Not for side editing (`Sheet`), anchored confirms (`Popconfirm`) or hover previews (`HoverCard`).\n * - `Modal.Content` wraps Header + Body + Footer; a form's `FormBody` goes in Body, its buttons in Footer.\n *\n * @see RECIPES.md#modal-form\n * @see RECIPES.md#confirm-dialog\n */\nexport const Modal = (props: Props) => <Root {...props} />;\n\nModal.Close = Close;\nModal.Trigger = Trigger;\n\nModal.Content = ModalContent;\nModal.Body = ModalBody;\nModal.Icon = ModalIcon;\nModal.Image = ModalImage;\nModal.Footer = ModalFooter;\nModal.Header = ModalHeader;\nModal.Overlay = ModalOverlay;\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAa,aAAa,EAAE,WAAW,GAAG,YACxC,oBAAC,OAAD;CACE,aAAU;CACV,WAAW,GAET,aACA,sBAGA,iDAGA,yCACA,wCACA,WAGA,qDACA,uBACA,SACF;CACA,GAAI;AACL,CAAA;;;ACvBH,MAAa,gBAAgB,EAC3B,OAAO,UACP,WACA,UACA,iBACA,GAAG,YACQ;CACX,MAAM,aAAa,cAAc;CAEjC,MAAM,uBAA+C,UAAU;EAE7D,MAAM,gBAAgB;EACtB,kBAAkB,KAAK;CACzB;CAEA,OACE,oBAAC,QAAD,EAAA,UACE,oBAAC,cAAD,EAAA,UACE,oBAAC,SAAD;EAEE,GAAI;EACJ,aAAW;EACX,aAAW;EACX,WAAW,GACT,yBACA,kBAEA,YACA,eACA,uBACA,eAEA,+BACA,+BACA,wCAEA,aACA,gBACA,8CAEA,WACA,eACA,YACA,mCACA,qCACA,cACA,2BAIA,6BACA,4BAEA,mBACA,mCACA,kCACA,sCACA,qCAMA,qDACA,kEACA,wDACA,mEAEA,oDACA,uDAEA;GACE,oBAAoB,SAAS;GAC7B,gBAAgB,SAAS;EAC3B,GAEA,SACF;EACA,iBAAiB;EAEhB;CACM,CAAA,EACG,CAAA,EACR,CAAA;AAEZ;;;;;;;;;ACrFA,MAAa,eAAe,EAAE,WAAW,GAAG,YAC1C,oBAAC,OAAD;CACE,GAAI;CACJ,WAAW,GACT,WACA,mBACA,kBACA,YAEA,yCACA,wCACA,SACF;AACD,CAAA;;;;;;;ACfH,MAAa,gBAAgB,EAAE,WAAW,GAAG,YAC3C,oBAAC,OAAD;CACE,WAAW,GACT,kBACA,kBACA,iBACA,WACA,mBACA,YAGA,wCACA,SACF;CACA,GAAI;AACL,CAAA;;;;ACCH,MAAa,eAAe,EAC1B,WACA,MACA,aACA,oBAAoB,iBACpB,SACA,gBAAgB,OAChB,UACA,GAAG,YAEH,qBAAC,OAAD;CACE,GAAI;CACJ,aAAU;CACV,WAAW,GACT,WACA,gCACA,mBACA,yCACA,wCACA,SACF;CAVF,UAAA;EAYG;EAEA,YAAY,oBAAC,YAAD;GAAY,WAAU;GAAiC;EAAqB,CAAA;GACvF,WAAW,CAAC,kBACZ,qBAAC,cAAD,EAAA,UAAA,CACG,SACA,CAAC,iBACA,oBAAC,OAAD;GAAO,SAAA;GACL,UAAA,qBAAC,QAAD;IAAQ,SAAQ;IAAY,MAAK;IAAjC,UAAA,CACE,oBAAC,GAAD,CAAI,CAAA,GACJ,oBAAC,QAAD;KAAM,WAAU;KAAa,UAAA;IAAW,CAAA,CAClC;;EACH,CAAA,CAEG,EAAA,CAAA;GAEd,eAAe,oBACf,oBAAC,kBAAD;GACE,WAAW,GACT,kBACA,gBACA,kBACA,cAAc,YAAY,YAC5B;GAEC,UAAA,eAAe;EACA,CAAA;EAIpB,oBAAC,OAAD;GACE,WAAW,GACT,kBACA,gBACA,WACA,aACA,oGACA,0HACF;GAEA,UAAA,oBAAC,WAAD,EAAW,aAAY,aAAc,CAAA;EAClC,CAAA;CACF;;;;AC/EP,MAAM,+BAAe,IAAI,IAAY;CAAC;CAAU;CAAQ;CAAO;CAAS;CAAQ;AAAQ,CAAC;;;;;;;;;AAUzF,MAAa,aAAa,EAAE,OAAO,WAAkB;CACnD,MAAM,cAAc,SAAS,CAAC,aAAa,IAAI,KAAK,IAAI,QAAQ,KAAA;CAEhE,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,WACA,eACA,mBACA,qBACA,4BAGA,6CACA,0CACA,2CACA,qDACA,4CACA,iDACA,8EAGA,+CACA,+CACA,8CACA,wCACA,0CACA,2CACA,mDACA,6EAGA;GACE,mDAAmD,UAAU;GAC7D,gDAAgD,UAAU;GAC1D,iDAAiD,UAAU;GAC3D,iDAAiD,UAAU;GAC3D,mDAAmD,UAAU;GAC7D,kDAAkD,UAAU;GAC5D,+CAA+C,UAAU;GACzD,oDAAoD,UAAU;EAChE,GAGA;GACE,mGACE,UAAU;GACZ,6FACE,UAAU;GACZ,+FACE,UAAU;GACZ,+FACE,UAAU;GACZ,mGACE,UAAU;GACZ,iGACE,UAAU;EACd,GAGA,EAAE,iBAAiB,CAAC,CAAC,YAAY,CACnC;EACA,OAAO,cAAc,EAAE,iBAAiB,YAAY,IAAI,KAAA;EAEvD,UAAA;CACG,CAAA;AAEV;;;AC/EA,MAAa,cAAc,EAAE,KAAK,MAAM,SAAgB;CACtD,MAAM,CAAC,eAAe,oBAAoB,SAAS,KAAK;CAIxD,gBAAgB,iBAAiB,KAAK,GAAG,CAAC,GAAG,CAAC;CAE9C,IAAI,eAAe,OAAO;CAE1B,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,eACA,sBAGA,6CACA,0CACA,2CACA,qDACA,4CACA,iDAGA,wCACA,+CACA,+CACA,8CACA,wCACA,gDACA,kDACA,2CACA,wCACF;EAEA,UAAA,oBAAC,OAAD;GACO;GACA;GACL,WAAU;GACV,eAAe,iBAAiB,IAAI;EACrC,CAAA;CACG,CAAA;AAEV;;;;;;;;;;;;AChCA,MAAa,SAAS,UAAiB,oBAAC,MAAD,EAAM,GAAI,MAAQ,CAAA;AAEzD,MAAM,QAAQ;AACd,MAAM,UAAU;AAEhB,MAAM,UAAU;AAChB,MAAM,OAAO;AACb,MAAM,OAAO;AACb,MAAM,QAAQ;AACd,MAAM,SAAS;AACf,MAAM,SAAS;AACf,MAAM,UAAU"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Table-CgSC-fSo.js","names":[],"sources":["../src/components/Table/TableBody.tsx","../src/components/Table/TableCell.tsx","../src/components/Table/TableFooter.tsx","../src/components/Table/TableHead.tsx","../src/components/Table/TableHeader.tsx","../src/components/Table/TableRow.tsx","../src/components/Table/TableSortHeader.tsx","../src/components/Table/Table.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nexport const TableBody = ({\n withBorderSeparator = true,\n className,\n ...props\n}: { withBorderSeparator?: boolean } & ComponentProps<'tbody'>) => {\n return (\n <tbody\n className={cn(\n {\n 'tw:[&_tr]:border-0 tw:[&_tr]:border-b-border tw:[&_tr]:border-b tw:[&_tr]:border-solid tw:[&_tr:last-child]:border-0':\n withBorderSeparator,\n },\n className,\n )}\n {...props}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nexport const TableCell = ({ className, ...props }: ComponentProps<'td'>) => {\n return <td className={cn('tw:px-3 tw:py-2', className)} {...props} />;\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nexport const TableFooter = ({ className, ...props }: ComponentProps<'tfoot'>) => {\n return (\n <tfoot\n className={cn(\n 'tw:bg-muted/50 tw:border-t tw:border-border tw:font-medium tw:[&>tr]:last:border-b-0',\n className,\n )}\n {...props}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nexport const TableHead = ({ className, ...props }: ComponentProps<'th'>) => {\n return (\n <th\n className={cn(\n 'tw:px-3 tw:py-2 tw:text-left tw:font-medium tw:whitespace-nowrap tw:[&:has([role=checkbox])]:pr-0 tw:[&>[role=checkbox]]:translate-y-[2px] tw:focus-within:ring-2 tw:focus-within:ring-ring/50',\n className,\n )}\n {...props}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nexport const TableHeader = ({\n withShadow = false,\n className,\n ...props\n}: { withShadow?: boolean } & ComponentProps<'thead'>) => {\n return (\n <thead\n className={cn(\n // `[&_tr]:hover:` (0,2,1) outranks `TableRow`'s own `hover:bg-muted/50` (0,2,0), so the\n // header row keeps its background instead of flashing muted — a header is not hoverable.\n 'tw:sticky tw:top-0 tw:z-10 tw:[&_tr]:bg-table-header tw:[&_tr]:hover:bg-table-header tw:[&_tr]:border-b tw:[&_tr]:border-border',\n { 'tw:shadow-table': withShadow },\n className,\n )}\n {...props}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nexport const TableRow = ({ ref, className, ...props }: ComponentProps<'tr'>) => (\n <tr\n ref={ref}\n className={cn(\n 'tw:hover:bg-[var(--hover,color-mix(in_oklab,rgb(var(--muted))_50%,transparent))] tw:aria-selected:bg-selected tw:aria-selected:hover:bg-selected tw:aria-selected:text-[var(--selected-foreground,currentColor)]',\n className,\n )}\n {...props}\n />\n);\n","import type { ComponentProps, ReactNode } from 'react';\n\nimport { ChevronDown, ChevronsUpDown, ChevronUp } from '../../icons';\nimport { cn } from '../../utils';\n\nexport type TableSortDirection = 'asc' | 'desc' | false;\n\n/** Maps a sort direction to the `aria-sort` value for the enclosing `Table.Head`. */\nexport const tableAriaSort = (sorted: TableSortDirection): ComponentProps<'th'>['aria-sort'] =>\n sorted === 'asc' ? 'ascending' : sorted === 'desc' ? 'descending' : 'none';\n\ntype Props = {\n /** Current sort state for this column: `'asc'`, `'desc'`, or `false` when unsorted. */\n sorted: TableSortDirection;\n children: ReactNode;\n} & Omit<ComponentProps<'button'>, 'children' | 'type'>;\n\n/**\n * Clickable column-header label with a sort-direction chevron, for use inside `Table.Head`.\n *\n * Presentational only — it owns no sort state. Pair it with your sort model (a `useState`\n * key/direction pair, or `@tanstack/react-table`'s `getToggleSortingHandler()` / `getIsSorted()`)\n * and set `aria-sort` on the enclosing `Table.Head` via {@link tableAriaSort}.\n */\nexport const TableSortHeader = ({ sorted, children, className, ...props }: Props) => {\n const Icon = sorted === false ? ChevronsUpDown : sorted === 'asc' ? ChevronUp : ChevronDown;\n return (\n <button\n className={cn(\n 'tw:group tw:flex tw:cursor-pointer tw:items-center tw:gap-1 tw:border-0 tw:bg-transparent tw:p-0 tw:font-medium tw:text-inherit',\n className,\n )}\n {...props}\n type=\"button\"\n >\n {children}\n <Icon className=\"tw:size-3 tw:text-muted-foreground\" />\n </button>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nimport { TableBody } from './TableBody';\nimport { TableCell } from './TableCell';\nimport { TableFooter } from './TableFooter';\nimport { TableHead } from './TableHead';\nimport { TableHeader } from './TableHeader';\nimport { TableRow } from './TableRow';\nimport { TableSortHeader } from './TableSortHeader';\n\n/**\n * - `borderCollapsed`: collapsed borders vs separate row spacing.\n * - `bordered`: rounded bordered container with overflow scrolling.\n */\ntype Props = {\n borderCollapsed?: boolean;\n bordered?: boolean;\n containerClassName?: string;\n} & ComponentProps<'table'>;\n\n/**\n * Presentational table for rows sharing one schema; sort/filter state is the consumer's.\n *\n * - Not for rows of differing shape — use a `Card` list.\n * - Wrap in `PageLayout.Content`.\n *\n * @see RECIPES.md#list-detail\n */\nexport const Table = ({\n borderCollapsed = true,\n bordered = false,\n containerClassName,\n className,\n ...props\n}: Props) => {\n return (\n <div\n className={cn(\n 'tw:relative tw:w-full',\n bordered && 'tw:overflow-auto tw:rounded-[10px] tw:border tw:border-solid tw:border-border',\n containerClassName,\n )}\n >\n <table\n className={cn(\n // Semantic token so text flips under `[data-theme='dark']`.\n 'tw:w-full tw:caption-bottom tw:text-sm tw:text-foreground',\n borderCollapsed ? 'tw:border-collapse' : 'tw:border-separate tw:border-spacing-y-1',\n className,\n )}\n {...props}\n />\n </div>\n );\n};\n\nTable.Header = TableHeader;\nTable.Head = TableHead;\nTable.Body = TableBody;\nTable.Row = TableRow;\nTable.Cell = TableCell;\nTable.Footer = TableFooter;\nTable.SortHeader = TableSortHeader;\n"],"mappings":";;;;AAIA,MAAa,aAAa,EACxB,sBAAsB,MACtB,WACA,GAAG,YAC8D;CACjE,OACE,oBAAC,SAAD;EACE,WAAW,GACT,EACE,wHACE,oBACJ,GACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;;;ACjBA,MAAa,aAAa,EAAE,WAAW,GAAG,YAAkC;CAC1E,OAAO,oBAAC,MAAD;EAAI,WAAW,GAAG,mBAAmB,SAAS;EAAG,GAAI;CAAQ,CAAA;AACtE;;;ACFA,MAAa,eAAe,EAAE,WAAW,GAAG,YAAqC;CAC/E,OACE,oBAAC,SAAD;EACE,WAAW,GACT,wFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;;;ACVA,MAAa,aAAa,EAAE,WAAW,GAAG,YAAkC;CAC1E,OACE,oBAAC,MAAD;EACE,WAAW,GACT,kMACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;;;ACVA,MAAa,eAAe,EAC1B,aAAa,OACb,WACA,GAAG,YACqD;CACxD,OACE,oBAAC,SAAD;EACE,WAAW,GAGT,mIACA,EAAE,mBAAmB,WAAW,GAChC,SACF;EACA,GAAI;CACL,CAAA;AAEL;;;ACjBA,MAAa,YAAY,EAAE,KAAK,WAAW,GAAG,YAC5C,oBAAC,MAAD;CACO;CACL,WAAW,GACT,oNACA,SACF;CACA,GAAI;AACL,CAAA;;;;ACJH,MAAa,iBAAiB,WAC5B,WAAW,QAAQ,cAAc,WAAW,SAAS,eAAe;;;;;;;;AAetE,MAAa,mBAAmB,EAAE,QAAQ,UAAU,WAAW,GAAG,YAAmB;CACnF,MAAM,OAAO,WAAW,QAAQ,iBAAiB,WAAW,QAAQ,YAAY;CAChF,OACE,qBAAC,UAAD;EACE,WAAW,GACT,mIACA,SACF;EACA,GAAI;EACJ,MAAK;EANP,UAAA,CAQG,UACD,oBAAC,MAAD,EAAM,WAAU,qCAAsC,CAAA,CAChD;;AAEZ;;;;;;;;;;;ACTA,MAAa,SAAS,EACpB,kBAAkB,MAClB,WAAW,OACX,oBACA,WACA,GAAG,YACQ;CACX,OACE,oBAAC,OAAD;EACE,WAAW,GACT,yBACA,YAAY,iFACZ,kBACF;EAEA,UAAA,oBAAC,SAAD;GACE,WAAW,GAET,6DACA,kBAAkB,uBAAuB,4CACzC,SACF;GACA,GAAI;EACL,CAAA;CACE,CAAA;AAET;AAEA,MAAM,SAAS;AACf,MAAM,OAAO;AACb,MAAM,OAAO;AACb,MAAM,MAAM;AACZ,MAAM,OAAO;AACb,MAAM,SAAS;AACf,MAAM,aAAa"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ZoomableSvg-D8sXKpoV.js","names":[],"sources":["../src/components/ZoomableSvg/ZoomableSvg.tsx","../src/components/ZoomableSvg/exportSvg.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport DOMPurify from 'dompurify';\n\nimport { ClipboardButton } from '../../blocks/ClipboardButton';\nimport { Maximize2, Minimize2 } from '../../icons';\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\nimport { Tooltip } from '../Tooltip';\n\nconst MIN_SCALE = 0.5;\nconst MAX_SCALE = 3;\nconst ZOOM_STEP = 0.1;\n\ntype Props = {\n /** Raw SVG markup; DOMPurify-sanitized (SVG profile), so user/LLM content is safe. */\n html: string;\n copyText?: string;\n className?: string;\n /** Keep `<foreignObject>` through sanitization; its HTML children are still stripped.\n * Enable only when each one is pre-flattened to bare text. */\n allowForeignObject?: boolean;\n /** Extra toolbar controls (e.g. `ExportMenu`) between copy and fullscreen; receives the\n * sanitized SVG. Injected so this lazy chunk carries no export dependencies. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const ZoomableSvg = ({\n html,\n copyText,\n className,\n allowForeignObject,\n renderActions,\n}: Props) => {\n const safeHtml = useMemo(\n () =>\n DOMPurify.sanitize(html, {\n USE_PROFILES: { svg: true, svgFilters: true },\n ...(allowForeignObject ? { ADD_TAGS: ['foreignObject'] } : {}),\n }),\n [html, allowForeignObject],\n );\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [scale, setScale] = useState(1);\n const [translate, setTranslate] = useState({ x: 0, y: 0 });\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n useEffect(() => {\n if (!isFullscreen) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n setIsFullscreen(false);\n }\n };\n document.addEventListener('keydown', onKeyDown, { capture: true });\n return () => document.removeEventListener('keydown', onKeyDown, { capture: true });\n }, [isFullscreen]);\n\n const dragRef = useRef<{\n startX: number;\n startY: number;\n startTx: number;\n startTy: number;\n } | null>(null);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n const delta = e.deltaY > 0 ? -ZOOM_STEP : ZOOM_STEP;\n setScale((s) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, s + delta)));\n };\n\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n // Re-bind when toggling fullscreen: the portal/inline switch remounts the\n // container element, so the listener must attach to the new node.\n }, [isFullscreen]);\n\n const didDragRef = useRef(false);\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n didDragRef.current = false;\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startTx: translate.x,\n startTy: translate.y,\n };\n },\n [translate],\n );\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!dragRef.current) return;\n didDragRef.current = true;\n setTranslate({\n x: dragRef.current.startTx + e.clientX - dragRef.current.startX,\n y: dragRef.current.startTy + e.clientY - dragRef.current.startY,\n });\n }, []);\n\n const handleMouseUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n const handleReset = useCallback(() => {\n setScale(1);\n setTranslate({ x: 0, y: 0 });\n }, []);\n\n const isZoomed = Math.abs(scale - 1) > 0.001 || translate.x !== 0 || translate.y !== 0;\n\n const handleClick = useCallback((e: React.MouseEvent) => {\n if (didDragRef.current) {\n e.stopPropagation();\n }\n }, []);\n\n const stopPropagation = useCallback((e: React.SyntheticEvent) => {\n e.stopPropagation();\n }, []);\n\n const diagramContent = (\n <div\n role=\"presentation\"\n className={cn('tw:group/zoom tw:relative', isFullscreen && 'tw:h-full')}\n onClick={handleClick}\n >\n <div\n role=\"presentation\"\n ref={containerRef}\n className={cn(\n 'tw:overflow-hidden tw:cursor-grab tw:active:cursor-grabbing tw:p-3',\n isFullscreen && 'tw:h-full',\n )}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n >\n <div\n className={cn(\n 'tw:flex tw:justify-center tw:origin-center',\n isFullscreen && 'tw:h-full tw:[&>svg]:h-full',\n )}\n style={{ transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})` }}\n dangerouslySetInnerHTML={{ __html: safeHtml }}\n />\n </div>\n <div\n role=\"presentation\"\n // `focus-within` too: the opacity-0 toolbar is still in the tab order.\n className=\"tw:absolute tw:right-1 tw:top-1 tw:flex tw:gap-1 tw:opacity-0 tw:transition-opacity tw:focus-within:opacity-100 tw:group-hover/zoom:opacity-100\"\n onClick={stopPropagation}\n >\n {isZoomed && (\n <Tooltip tooltip=\"Reset zoom\" placement=\"top\" triggerAsChild>\n <Button size=\"small\" variant=\"outline\" onClick={handleReset}>\n Reset\n </Button>\n </Tooltip>\n )}\n {copyText && (\n <ClipboardButton text={copyText} tooltip=\"Copy code\" size=\"icon-sm\" variant=\"outline\" />\n )}\n {renderActions?.(safeHtml)}\n <Tooltip\n tooltip={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n placement=\"top\"\n triggerAsChild\n >\n <Button\n size=\"icon-sm\"\n variant=\"outline\"\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n onClick={() => setIsFullscreen((f) => !f)}\n >\n {isFullscreen ? (\n <Minimize2 className=\"tw:size-4\" />\n ) : (\n <Maximize2 className=\"tw:size-4\" />\n )}\n </Button>\n </Tooltip>\n </div>\n </div>\n );\n\n if (isFullscreen) {\n return createPortal(\n <div\n role=\"presentation\"\n data-testid=\"zoomable-svg-fullscreen\"\n // z-1051 (Modal band): must stay below floating panels (z-1055) or toolbar menus hide.\n // Tooltip (z-1060) and SpotlightBackdrop (z-1056) sit above it by design.\n className=\"tw:fixed tw:inset-0 tw:z-[1051] tw:bg-muted tw:p-4 tailwindcss-preflight\"\n onClick={stopPropagation}\n >\n {diagramContent}\n </div>,\n document.body,\n );\n }\n\n return (\n <div\n className={cn(\n 'tw:overflow-hidden tw:rounded-md tw:border tw:border-border tw:bg-muted',\n className,\n )}\n >\n {diagramContent}\n </div>\n );\n};\n","const PNG_SCALE = 2;\n\n// The root `<svg …>` tag, so the namespace check looks only at its attributes.\n// A plain `includes('xmlns=')` would also match a nested element or body text,\n// and would miss `xmlns = \"…\"` — adding a second declaration, which parsers\n// reject outright with \"Attribute xmlns redefined\".\nconst ROOT_SVG_TAG = /^<svg\\b[^>]*>/i;\nconst HAS_DEFAULT_NAMESPACE = /\\bxmlns\\s*=/i;\n\n// A standalone SVG file needs the namespace declaration; mermaid's inline output\n// omits it because an inline <svg> inherits it from the host document.\n// Trim before matching: the anchored `^<svg` misses markup that arrives with a\n// leading newline or indentation, which would emit a standalone file with no\n// namespace — unopenable in an image viewer.\nconst withSvgNamespace = (svg: string) => {\n const trimmed = svg.trim();\n const rootTag = trimmed.match(ROOT_SVG_TAG)?.[0];\n\n if (!rootTag || HAS_DEFAULT_NAMESPACE.test(rootTag)) return trimmed;\n\n return trimmed.replace(/^<svg\\b/i, '<svg xmlns=\"http://www.w3.org/2000/svg\"');\n};\n\nexport const toSvgFileContent = (svg: string) =>\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${withSvgNamespace(svg).trim()}\\n`;\n\n// A single decimal number: `12`, `12.5`, `.5`. Deliberately stricter than\n// `[\\d.]+`, which also matches `1.2.3` — and `parseFloat` truncates that to\n// `1.2` rather than rejecting it, so a malformed value would pass as a plausible\n// one.\nconst NUMBER = String.raw`\\d+(?:\\.\\d+)?|\\.\\d+`;\n\n// `parseFloat` happily reads a relative length as a number — `\"100%\"` becomes\n// `100`, `\"2em\"` becomes `2` — and `makeResponsive` sets `width=\"100%\"` on every\n// mermaid root, so an SVG with no usable viewBox would rasterize 100px wide with\n// no error. Accept only a unitless number or an explicit `px`.\nconst PIXEL_LENGTH = new RegExp(String.raw`^\\s*(?:${NUMBER})(?:px)?\\s*$`, 'i');\n\nconst parsePixelLength = (value: string | null): number | null => {\n if (!PIXEL_LENGTH.test(value ?? '')) return null;\n\n const parsed = Number.parseFloat(value ?? '');\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n};\n\nexport const parseSvgSize = (svg: string) => {\n const doc = new DOMParser().parseFromString(withSvgNamespace(svg), 'image/svg+xml');\n const element = doc.documentElement;\n\n const viewBox = element\n .getAttribute('viewBox')\n ?.split(/[\\s,]+/)\n .map(Number);\n // `> 0`, not truthiness: a negative extent is accepted by a truthy check, and\n // negative canvas dimensions silently fall back to the 300x150 default — an\n // export at the wrong size with no error. Falling through to width/height is\n // the better answer, since those are usually still valid.\n if (viewBox?.length === 4 && viewBox.every((value) => Number.isFinite(value))) {\n const [, , width, height] = viewBox;\n if (width !== undefined && height !== undefined && width > 0 && height > 0) {\n return { width, height };\n }\n }\n\n const width = parsePixelLength(element.getAttribute('width'));\n const height = parsePixelLength(element.getAttribute('height'));\n\n return width !== null && height !== null ? { width, height } : null;\n};\n\n// Resolve the themed page background so the exported PNG follows the active\n// brand and color scheme instead of a frozen literal. Falls back to `white`\n// (a CSS keyword, not a brand-locked hex) when the token is unset.\n//\n// The token holds Tailwind's bare channel triplet (\"249 250 251\") so utilities\n// can add an alpha. Canvas `fillStyle` rejects that form *silently* and keeps\n// its previous value (black), so wrap it back into rgb() before use.\nconst CHANNEL_TRIPLET = new RegExp(String.raw`^(?:${NUMBER})\\s+(?:${NUMBER})\\s+(?:${NUMBER})$`);\n\nexport const toCanvasColor = (token: string) => {\n const trimmed = token.trim();\n if (!trimmed) return 'white';\n\n // Only wrap a well-formed triplet. A malformed one (`1.2.3 4 5`) would produce\n // an invalid `rgb()` that `fillStyle` rejects silently, painting the PNG on\n // whatever colour was set before — passing it through unwrapped at least lets\n // a genuine CSS color value work.\n return CHANNEL_TRIPLET.test(trimmed) ? `rgb(${trimmed})` : trimmed;\n};\n\nconst resolveBackground = () =>\n toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue('--color-background'));\n\n/**\n * Rasterize SVG markup to a PNG blob at 2x for legible text.\n *\n * The SVG is loaded as a data URL rather than a blob URL: an <img> loading SVG\n * is treated as a foreign resource, so a blob URL would taint the canvas and\n * make toBlob throw a SecurityError. A background is painted first because a\n * transparent PNG reads as unusable when pasted into a slide deck.\n */\nexport const svgToPngBlob = async (svg: string, background?: string): Promise<Blob> => {\n const size = parseSvgSize(svg);\n if (!size) throw new Error('Cannot determine diagram dimensions.');\n\n const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(toSvgFileContent(svg))}`;\n\n const image = new Image();\n image.decoding = 'sync';\n await new Promise<void>((resolve, reject) => {\n image.onload = () => resolve();\n image.onerror = () => reject(new Error('Failed to load the diagram for export.'));\n image.src = encoded;\n });\n\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(size.width * PNG_SCALE);\n canvas.height = Math.round(size.height * PNG_SCALE);\n\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Canvas is unavailable in this browser.');\n\n context.fillStyle = background ?? resolveBackground();\n context.fillRect(0, 0, canvas.width, canvas.height);\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n\n return new Promise<Blob>((resolve, reject) => {\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error('Failed to encode the PNG.'))),\n 'image/png',\n );\n });\n};\n"],"mappings":"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"}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
//#region src/blocks/DiagramShared/svgTransforms.ts
|
|
2
|
-
const HTML_TAG = /<[^>]+>/g;
|
|
3
|
-
const FOREIGN_OBJECT = /(<foreignObject\b[^>]*>)([\s\S]*?)(<\/foreignObject>)/g;
|
|
4
|
-
const ROOT_SVG_TAG = /^(\s*<svg\b)([^>]*)(>)/i;
|
|
5
|
-
/**
|
|
6
|
-
* Collapses each `<foreignObject>`'s HTML to its text content.
|
|
7
|
-
*
|
|
8
|
-
* - DOMPurify's SVG profile strips XHTML elements (mermaid labels vanish) but keeps bare text.
|
|
9
|
-
* - Mermaid already sanitized the text (`securityLevel: 'strict'`).
|
|
10
|
-
* - Entities stay encoded: decoding could turn `<`/`>` into real markup.
|
|
11
|
-
*/
|
|
12
|
-
const flattenForeignObjectLabels = (svg) => svg.replace(FOREIGN_OBJECT, (_match, open, inner, close) => {
|
|
13
|
-
return `${open}${inner.replace(HTML_TAG, " ").replace(/\s+/g, " ").trim()}${close}`;
|
|
14
|
-
});
|
|
15
|
-
/**
|
|
16
|
-
* Makes the root `<svg>` fluid: `width="100%"`, `max-width` from the viewBox, no fixed height.
|
|
17
|
-
*
|
|
18
|
-
* - Only the root tag: inner icon `<svg>`s keep their fixed size.
|
|
19
|
-
* - Keeps `style` (minus `max-width`): beautiful-mermaid's `--bg`/`--fg` theme vars live there.
|
|
20
|
-
*/
|
|
21
|
-
const STYLE_ATTR = /\s+style="([^"]*)"/i;
|
|
22
|
-
const makeResponsive = (svgString) => {
|
|
23
|
-
const viewBoxMatch = svgString.match(/viewBox="[^"]*\s([\d.]+)\s[\d.]+"/);
|
|
24
|
-
const vbWidth = viewBoxMatch ? Math.round(Number(viewBoxMatch[1])) : void 0;
|
|
25
|
-
return svgString.replace(ROOT_SVG_TAG, (_match, open, attrs, close) => {
|
|
26
|
-
const styleDecls = (attrs.match(STYLE_ATTR)?.[1] ?? "").replace(/max-width:\s*[^;"]*;?\s*/gi, "").replace(/\s+/g, " ").trim().replace(/;$/, "");
|
|
27
|
-
let nextAttrs = attrs.replace(/\s+width="[^"]*"/i, "").replace(/\s+height="[^"]*"/i, "").replace(STYLE_ATTR, "");
|
|
28
|
-
nextAttrs += " width=\"100%\"";
|
|
29
|
-
const styleParts = [styleDecls, vbWidth ? `max-width: ${vbWidth}px` : ""].filter(Boolean).join("; ");
|
|
30
|
-
if (styleParts) nextAttrs += ` style="${styleParts}"`;
|
|
31
|
-
return `${open}${nextAttrs}${close}`;
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Whether an SVG has drawn content, i.e. a non-degenerate viewBox.
|
|
36
|
-
*
|
|
37
|
-
* - beautiful-mermaid may return `viewBox="0 0 0 0"` instead of throwing; mermaid must then run.
|
|
38
|
-
* - A missing viewBox counts as drawn: some mermaid types size via width/height.
|
|
39
|
-
* - Only the root `<svg>` is read; nested icon `<svg>`s carry their own viewBox.
|
|
40
|
-
* - Any quote style and spaces around `=` match; a miss would count as drawn.
|
|
41
|
-
*/
|
|
42
|
-
const ROOT_VIEWBOX = /^\s*<svg\b[^>]*\sviewBox\s*=\s*(["'])\s*[\d.eE+-]+\s+[\d.eE+-]+\s+([\d.eE+-]+)\s+([\d.eE+-]+)\s*\1/i;
|
|
43
|
-
const hasDrawnContent = (svg) => {
|
|
44
|
-
const viewBox = svg.match(ROOT_VIEWBOX);
|
|
45
|
-
if (!viewBox) return true;
|
|
46
|
-
return Number(viewBox[2]) > 0 && Number(viewBox[3]) > 0;
|
|
47
|
-
};
|
|
48
|
-
//#endregion
|
|
49
|
-
export { flattenForeignObjectLabels, hasDrawnContent, makeResponsive };
|
|
50
|
-
|
|
51
|
-
//# sourceMappingURL=svgTransforms-Dw2hRA-i.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"svgTransforms-Dw2hRA-i.js","names":[],"sources":["../src/blocks/DiagramShared/svgTransforms.ts"],"sourcesContent":["// Post-processing of diagram SVG output (mermaid, vega) before ZoomableSvg's DOMPurify pass.\n\nconst HTML_TAG = /<[^>]+>/g;\nconst FOREIGN_OBJECT = /(<foreignObject\\b[^>]*>)([\\s\\S]*?)(<\\/foreignObject>)/g;\n// Root <svg> open tag only; nested icon <svg>s must not match.\nconst ROOT_SVG_TAG = /^(\\s*<svg\\b)([^>]*)(>)/i;\n\n/**\n * Collapses each `<foreignObject>`'s HTML to its text content.\n *\n * - DOMPurify's SVG profile strips XHTML elements (mermaid labels vanish) but keeps bare text.\n * - Mermaid already sanitized the text (`securityLevel: 'strict'`).\n * - Entities stay encoded: decoding could turn `<`/`>` into real markup.\n */\nexport const flattenForeignObjectLabels = (svg: string): string =>\n svg.replace(FOREIGN_OBJECT, (_match, open: string, inner: string, close: string) => {\n const text = inner.replace(HTML_TAG, ' ').replace(/\\s+/g, ' ').trim();\n return `${open}${text}${close}`;\n });\n\n/**\n * Makes the root `<svg>` fluid: `width=\"100%\"`, `max-width` from the viewBox, no fixed height.\n *\n * - Only the root tag: inner icon `<svg>`s keep their fixed size.\n * - Keeps `style` (minus `max-width`): beautiful-mermaid's `--bg`/`--fg` theme vars live there.\n */\nconst STYLE_ATTR = /\\s+style=\"([^\"]*)\"/i;\n\nexport const makeResponsive = (svgString: string): string => {\n const viewBoxMatch = svgString.match(/viewBox=\"[^\"]*\\s([\\d.]+)\\s[\\d.]+\"/);\n const vbWidth = viewBoxMatch ? Math.round(Number(viewBoxMatch[1])) : undefined;\n\n return svgString.replace(ROOT_SVG_TAG, (_match, open: string, attrs: string, close: string) => {\n const existingStyle = attrs.match(STYLE_ATTR)?.[1] ?? '';\n const styleDecls = existingStyle\n .replace(/max-width:\\s*[^;\"]*;?\\s*/gi, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/;$/, '');\n\n let nextAttrs = attrs\n .replace(/\\s+width=\"[^\"]*\"/i, '')\n .replace(/\\s+height=\"[^\"]*\"/i, '')\n .replace(STYLE_ATTR, '');\n\n nextAttrs += ' width=\"100%\"';\n\n const styleParts = [styleDecls, vbWidth ? `max-width: ${vbWidth}px` : '']\n .filter(Boolean)\n .join('; ');\n if (styleParts) nextAttrs += ` style=\"${styleParts}\"`;\n\n return `${open}${nextAttrs}${close}`;\n });\n};\n\n/**\n * Whether an SVG has drawn content, i.e. a non-degenerate viewBox.\n *\n * - beautiful-mermaid may return `viewBox=\"0 0 0 0\"` instead of throwing; mermaid must then run.\n * - A missing viewBox counts as drawn: some mermaid types size via width/height.\n * - Only the root `<svg>` is read; nested icon `<svg>`s carry their own viewBox.\n * - Any quote style and spaces around `=` match; a miss would count as drawn.\n */\nconst ROOT_VIEWBOX =\n /^\\s*<svg\\b[^>]*\\sviewBox\\s*=\\s*([\"'])\\s*[\\d.eE+-]+\\s+[\\d.eE+-]+\\s+([\\d.eE+-]+)\\s+([\\d.eE+-]+)\\s*\\1/i;\n\nexport const hasDrawnContent = (svg: string): boolean => {\n const viewBox = svg.match(ROOT_VIEWBOX);\n if (!viewBox) return true;\n return Number(viewBox[2]) > 0 && Number(viewBox[3]) > 0;\n};\n"],"mappings":";AAEA,MAAM,WAAW;AACjB,MAAM,iBAAiB;AAEvB,MAAM,eAAe;;;;;;;;AASrB,MAAa,8BAA8B,QACzC,IAAI,QAAQ,iBAAiB,QAAQ,MAAc,OAAe,UAAkB;CAElF,OAAO,GAAG,OADG,MAAM,QAAQ,UAAU,GAAG,CAAC,CAAC,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAC3C,IAAI;AAC1B,CAAC;;;;;;;AAQH,MAAM,aAAa;AAEnB,MAAa,kBAAkB,cAA8B;CAC3D,MAAM,eAAe,UAAU,MAAM,mCAAmC;CACxE,MAAM,UAAU,eAAe,KAAK,MAAM,OAAO,aAAa,EAAE,CAAC,IAAI,KAAA;CAErE,OAAO,UAAU,QAAQ,eAAe,QAAQ,MAAc,OAAe,UAAkB;EAE7F,MAAM,cADgB,MAAM,MAAM,UAAU,CAAC,GAAG,MAAM,GAAA,CAEnD,QAAQ,8BAA8B,EAAE,CAAC,CACzC,QAAQ,QAAQ,GAAG,CAAC,CACpB,KAAK,CAAC,CACN,QAAQ,MAAM,EAAE;EAEnB,IAAI,YAAY,MACb,QAAQ,qBAAqB,EAAE,CAAC,CAChC,QAAQ,sBAAsB,EAAE,CAAC,CACjC,QAAQ,YAAY,EAAE;EAEzB,aAAa;EAEb,MAAM,aAAa,CAAC,YAAY,UAAU,cAAc,QAAQ,MAAM,EAAE,CAAC,CACtE,OAAO,OAAO,CAAC,CACf,KAAK,IAAI;EACZ,IAAI,YAAY,aAAa,WAAW,WAAW;EAEnD,OAAO,GAAG,OAAO,YAAY;CAC/B,CAAC;AACH;;;;;;;;;AAUA,MAAM,eACJ;AAEF,MAAa,mBAAmB,QAAyB;CACvD,MAAM,UAAU,IAAI,MAAM,YAAY;CACtC,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,OAAO,QAAQ,EAAE,IAAI,KAAK,OAAO,QAAQ,EAAE,IAAI;AACxD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"themeTokens-7DEab0kp.js","names":[],"sources":["../src/utils/themeTokens.ts"],"sourcesContent":["const format = (channels: string, alpha?: number): string =>\n alpha === undefined ? `rgb(${channels})` : `rgb(${channels} / ${alpha})`;\n\n/**\n * A semantic `--*` token as the `rgb(...)` the browser currently computes on `<html>`.\n *\n * - For consumers that need a concrete colour string, not a Tailwind class.\n * - Falls back to `fallbackChannels` with no document or undefined token (tests load no CSS).\n */\nexport const resolveToken = (token: string, fallbackChannels: string, alpha?: number): string => {\n const channels =\n typeof document === 'undefined'\n ? fallbackChannels\n : getComputedStyle(document.documentElement).getPropertyValue(`--${token}`).trim() ||\n fallbackChannels;\n return format(channels, alpha);\n};\n\n/** {@link createTokenResolver}, answering the raw `\"R G B\"` channels. */\nexport const createChannelResolver = (from?: Element | null) => {\n // `from`: a node inside a `ThemeScope`, whose tokens differ from `<html>`'s.\n const element = from ?? (typeof document === 'undefined' ? null : document.documentElement);\n const computed = element === null ? null : getComputedStyle(element);\n\n return (token: string, fallbackChannels: string): string =>\n computed?.getPropertyValue(`--${token}`).trim() || fallbackChannels;\n};\n\n/**\n * A {@link resolveToken} bound to one `getComputedStyle` snapshot, for building a whole palette.\n *\n * - Create one per palette build, never at module level — tokens change with scheme and brand.\n */\nexport const createTokenResolver = (from?: Element | null) => {\n const resolve = createChannelResolver(from);\n\n return (token: string, fallbackChannels: string, alpha?: number): string =>\n format(resolve(token, fallbackChannels), alpha);\n};\n"],"mappings":";AAAA,MAAM,UAAU,UAAkB,UAChC,UAAU,KAAA,IAAY,OAAO,SAAS,KAAK,OAAO,SAAS,KAAK,MAAM;;;;;;;AAQxE,MAAa,gBAAgB,OAAe,kBAA0B,UAA2B;CAC/F,MAAM,WACJ,OAAO,aAAa,cAChB,mBACA,iBAAiB,SAAS,eAAe,CAAC,CAAC,iBAAiB,KAAK,OAAO,CAAC,CAAC,KAAK,KAC/E;CACN,OAAO,OAAO,UAAU,KAAK;AAC/B;;AAGA,MAAa,yBAAyB,SAA0B;CAE9D,MAAM,UAAU,SAAS,OAAO,aAAa,cAAc,OAAO,SAAS;CAC3E,MAAM,WAAW,YAAY,OAAO,OAAO,iBAAiB,OAAO;CAEnE,QAAQ,OAAe,qBACrB,UAAU,iBAAiB,KAAK,OAAO,CAAC,CAAC,KAAK,KAAK;AACvD;;;;;;AAOA,MAAa,uBAAuB,SAA0B;CAC5D,MAAM,UAAU,sBAAsB,IAAI;CAE1C,QAAQ,OAAe,kBAA0B,UAC/C,OAAO,QAAQ,OAAO,gBAAgB,GAAG,KAAK;AAClD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils-p6tjltbX.js","names":["Root"],"sources":["../src/utils/copyToClipboard.ts","../src/utils/createChangeInputEvent.ts","../src/constants/keyCodes.ts","../src/components/Tooltip/TooltipContent.tsx","../src/components/Tooltip/TooltipRoot.tsx","../src/components/Tooltip/TooltipTrigger.tsx","../src/components/Tooltip/Tooltip.tsx","../src/utils/decorators.tsx","../src/utils/createPrefixedString.ts","../src/utils/noop.ts","../src/utils/debounce.ts","../src/utils/isMac.ts","../src/utils/useSHA256.ts","../src/utils/splitEntry.ts"],"sourcesContent":["/**\n * The async Clipboard API requires the document to be focused and rejects with\n * `NotAllowedError: Document is not focused` otherwise — which is the normal state\n * for a page inside an iframe that has not taken focus, such as Storybook's canvas\n * or an embedded preview. `execCommand` has no such requirement because it copies\n * the selection of a node we focus ourselves, so it covers that gap.\n */\nconst copyViaSelection = (text: string) => {\n const node = document.createElement('textarea');\n node.value = text;\n node.setAttribute('readonly', '');\n node.style.cssText = 'position:fixed;top:0;left:0;opacity:0';\n document.body.append(node);\n node.select();\n\n try {\n return document.execCommand('copy');\n } finally {\n node.remove();\n }\n};\n\nexport const copyToClipboard = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n } catch (error) {\n if (!copyViaSelection(text)) throw error;\n }\n};\n","import type { ChangeEvent } from 'react';\n\nexport const createChangeInputEvent = (input: HTMLInputElement) => {\n const changeEvent: ChangeEvent<HTMLInputElement> = {\n target: input,\n currentTarget: input,\n type: 'change',\n nativeEvent: new Event('change', { bubbles: true }),\n bubbles: true,\n cancelable: false,\n defaultPrevented: false,\n eventPhase: 2, // AT_TARGET\n isTrusted: false,\n preventDefault: () => {},\n isDefaultPrevented: () => false,\n stopPropagation: () => {},\n isPropagationStopped: () => false,\n persist: () => {},\n timeStamp: Date.now(),\n };\n\n Object.defineProperty(changeEvent, 'target', {\n value: input,\n writable: false,\n });\n\n return changeEvent;\n};\n","export const keyCodes = {\n ENTER: 'Enter',\n ESCAPE: 'Escape',\n SPACE: ' ',\n};\n","import type { ComponentProps } from 'react';\nimport { Content, Portal } from '@radix-ui/react-tooltip';\nimport type { VariantProps } from 'class-variance-authority';\nimport { cva } from 'class-variance-authority';\n\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nconst tooltipVariants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:inline-block',\n 'tw:wrap-anywhere',\n 'tw:max-h-96',\n 'tw:overflow-y-auto',\n 'tw:z-[1060]',\n\n // legacy (dark) chrome — default\n 'tw:rounded',\n 'tw:bg-neutral-800',\n 'tw:text-white',\n\n // argo chrome overrides\n 'tw:data-[argo=true]:rounded-popover',\n 'tw:data-[argo=true]:border',\n 'tw:data-[argo=true]:border-solid',\n 'tw:data-[argo=true]:border-border',\n 'tw:data-[argo=true]:bg-popover',\n 'tw:data-[argo=true]:text-popover-foreground',\n 'tw:data-[argo=true]:shadow-md',\n\n // argo open animation\n 'tw:data-[argo=true]:data-[state=delayed-open]:animate-in',\n 'tw:data-[argo=true]:data-[state=instant-open]:animate-in',\n 'tw:data-[argo=true]:data-[state=delayed-open]:fade-in-0',\n 'tw:data-[argo=true]:data-[state=instant-open]:fade-in-0',\n 'tw:data-[argo=true]:data-[state=delayed-open]:zoom-in-95',\n 'tw:data-[argo=true]:data-[state=instant-open]:zoom-in-95',\n\n // argo closed animation\n 'tw:data-[argo=true]:data-[state=closed]:animate-out',\n 'tw:data-[argo=true]:data-[state=closed]:fade-out-0',\n 'tw:data-[argo=true]:data-[state=closed]:zoom-out-95',\n\n // argo position animation\n 'tw:data-[argo=true]:data-[side=bottom]:slide-in-from-top-2',\n 'tw:data-[argo=true]:data-[side=left]:slide-in-from-right-2',\n 'tw:data-[argo=true]:data-[side=right]:slide-in-from-left-2',\n 'tw:data-[argo=true]:data-[side=top]:slide-in-from-bottom-2',\n ],\n {\n defaultVariants: {\n variant: 'action',\n },\n variants: {\n variant: {\n action: [\n 'tw:max-w-fit',\n 'tw:px-3',\n 'tw:py-2',\n\n 'tw:text-center',\n 'tw:text-xs',\n 'tw:font-medium',\n // Uppercase on legacy chrome only; argo reads standard case.\n 'tw:data-[tooltip-content=true]:uppercase',\n 'tw:data-[tooltip-content=true]:tracking-wider',\n ],\n explanatory: [\n 'tw:max-w-80',\n 'tw:px-4',\n 'tw:py-3',\n 'tw:text-left',\n\n 'tw:text-sm',\n 'tw:font-normal',\n ],\n },\n },\n },\n);\n\ntype Props = {\n keepOpenOnPointerDownOutside?: boolean;\n /** Force argo (`true`) or legacy (`false`) chrome; `undefined` follows the brand. */\n argo?: boolean;\n placement?: ComponentProps<typeof Content>['side'];\n} & Omit<ComponentProps<typeof Content>, 'side'> &\n VariantProps<typeof tooltipVariants>;\n\nexport const TooltipContent = ({\n className,\n variant,\n keepOpenOnPointerDownOutside = false,\n argo,\n children,\n onPointerDownOutside,\n sideOffset = 8,\n collisionPadding = 8,\n hideWhenDetached = true,\n placement = 'right',\n ...rest\n}: Props) => {\n const brandIsArgo = useArgoDesign();\n const renderArgo = argo ?? brandIsArgo;\n\n const handlePointerDownOutside: ComponentProps<typeof Content>['onPointerDownOutside'] = (\n event,\n ) => {\n if (keepOpenOnPointerDownOutside) event.preventDefault();\n onPointerDownOutside?.(event);\n };\n\n return (\n <Portal>\n <Content\n {...rest}\n // styles.css inverts nested `.tw\\:prose` on the dark chrome.\n data-tooltip-content={renderArgo ? undefined : true}\n data-argo={renderArgo}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n onPointerDownOutside={handlePointerDownOutside}\n className={tooltipVariants({ className, variant })}\n hideWhenDetached={hideWhenDetached}\n side={placement}\n >\n {children}\n </Content>\n </Portal>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Root } from '@radix-ui/react-tooltip';\n\ntype Props = ComponentProps<typeof Root>;\n\nconst DELAY_SHOW_TOOLTIP = 300;\n\nexport const TooltipRoot = ({ children, delayDuration = DELAY_SHOW_TOOLTIP, ...rest }: Props) => (\n <Root {...rest} delayDuration={delayDuration}>\n {children}\n </Root>\n);\n","import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { Trigger } from '@radix-ui/react-tooltip';\n\nimport { cn } from '../../utils';\n\n/**\n * Radix stamps the tooltip's own open/closed `data-state` onto the trigger. Merged onto an\n * `asChild` child that keeps a `data-state` of its own — `ToggleGroup.Item`, `Switch`, a `Tabs`\n * trigger — it wins, because those primitives spread incoming props *after* their own attribute.\n * The child then silently loses every `data-[state=…]` style it has, which is usually the only\n * thing marking it as selected.\n *\n * The tooltip's trigger state is styled nowhere, so it is dropped before it reaches the child.\n */\nconst WithoutTooltipState = ({\n children,\n ...props\n // `Slot`'s own props, plus the one attribute this exists to remove: React's types declare no\n // `data-*`, so it has to be named to be destructured away.\n}: ComponentProps<typeof Slot> & { 'data-state'?: string }) => {\n const { 'data-state': _tooltipState, ...rest } = props;\n\n return <Slot {...rest}>{children}</Slot>;\n};\n\ntype Props = {\n keepOpenOnClick?: boolean;\n} & ComponentProps<typeof Trigger>;\n\nexport const TooltipTrigger = ({\n ref,\n children,\n className,\n keepOpenOnClick = false,\n onClick,\n onPointerDown,\n asChild,\n ...rest\n}: Props) => {\n const handleClick: ComponentProps<typeof Trigger>['onClick'] = (event) => {\n if (keepOpenOnClick) event.preventDefault();\n onClick?.(event);\n };\n\n const handlePointerDown: ComponentProps<typeof Trigger>['onPointerDown'] = (event) => {\n if (keepOpenOnClick) event.preventDefault();\n onPointerDown?.(event);\n };\n\n return (\n <Trigger\n {...rest}\n asChild\n ref={ref}\n className={cn('tailwindcss-preflight', className)}\n onClick={handleClick}\n onPointerDown={handlePointerDown}\n >\n {asChild ? (\n <WithoutTooltipState>{children}</WithoutTooltipState>\n ) : (\n // Default-mode trigger wraps children in a span so Radix has a\n // single DOM element to attach handlers to. `tailwindcss-preflight`\n // (merged in via Slot) activates Tailwind's preflight inside the\n // span, which sets `svg { display: block }` — without an inline-flex\n // container that would stack any bare Lucide icon onto its own\n // line. `tw:inline-flex tw:items-center` keeps icon + text aligned.\n <span className=\"tw:inline-flex tw:items-center\">{children}</span>\n )}\n </Trigger>\n );\n};\n","import { useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type { Content, Trigger } from '@radix-ui/react-tooltip';\nimport { Provider } from '@radix-ui/react-tooltip';\n\nimport { keyCodes } from '../../constants/keyCodes';\n\nimport { TooltipContent } from './TooltipContent';\nimport { TooltipRoot } from './TooltipRoot';\nimport { TooltipTrigger } from './TooltipTrigger';\n\nconst ACTION_TOOLTIP_LIMIT = 30;\n\n/**\n * New-design-only DOM; a trigger inside it gets the argo tooltip whatever the brand.\n *\n * - Matched on DOM ancestry, not React context, so overlays portaled to `document.body` follow the brand.\n */\nconst NEW_DESIGN_CHROME_SELECTOR = '[data-slot=\"navbar\"], [data-slot=\"sidebar\"]';\n\nexport const HINT_UNDERLINE_CLASS_NAME =\n 'tw:cursor-help tw:underline tw:decoration-dashed tw:decoration-neutral-300 tw:underline-offset-2';\n\ntype TriggerProps = {\n triggerAsChild?: boolean;\n};\n\nexport type Props = {\n /** Stays open on trigger click (click-to-copy feedback). */\n keepOpenOnTriggerClick?: boolean;\n /** Plain text only — interactive content belongs in `HoverCard` / `Popover`. */\n tooltip: ReactNode;\n children: ReactNode;\n placement?: ComponentProps<typeof Content>['side'];\n /** Hides it regardless of hover. */\n forceHide?: boolean;\n /** Shows it regardless of hover (e.g. guided tours). */\n forceShow?: boolean;\n /** In ms; defaults to the shared 300ms. */\n delayDuration?: number;\n /** Dashed-underline hover hint on the trigger. */\n hintUnderline?: boolean;\n /** Force one chrome. Default: argo inside `Navbar` / `Sidebar` DOM, else the brand's. */\n chrome?: 'argo' | 'legacy';\n className?: string;\n} & TriggerProps &\n Pick<ComponentProps<typeof TooltipContent>, 'variant' | 'className'>;\n\n/** Mount once at the app root so tooltips share delay state. */\nexport const TooltipProvider = Provider;\n\n/**\n * Short plain-text label on hover or focus.\n *\n * - Use for icon-only buttons, disabled controls, truncated values.\n * - Rich content → `HoverCard`; links or buttons → `Popover` (they break a11y here).\n * - `variant` defaults to `\"explanatory\"` for strings over 30 chars, else `\"action\"`.\n *\n * @see RECIPES.md#disabled-button-tooltip\n */\nexport const Tooltip = ({\n tooltip,\n children,\n className,\n keepOpenOnTriggerClick = false,\n variant,\n placement = 'right',\n forceHide = false,\n forceShow = false,\n delayDuration,\n chrome,\n triggerAsChild = false,\n hintUnderline = false,\n}: Props) => {\n const [open, setOpen] = useState(false);\n const [triggerElement, setTriggerElement] = useState<HTMLElement | null>(null);\n\n const argo = (() => {\n if (chrome) return chrome === 'argo';\n if (triggerElement?.closest(NEW_DESIGN_CHROME_SELECTOR)) return true;\n return undefined;\n })();\n\n const resolvedVariant = (() => {\n if (!!variant) return variant;\n if (typeof tooltip === 'string' && tooltip.length > ACTION_TOOLTIP_LIMIT) return 'explanatory';\n\n return 'action';\n })();\n\n const isActionVariant = resolvedVariant === 'action';\n\n const handleKeyUp: ComponentProps<typeof Trigger>['onKeyUp'] = (event) => {\n if (![keyCodes.ENTER, keyCodes.SPACE].includes(event.key)) return;\n event.stopPropagation();\n };\n\n return (\n <TooltipRoot\n open={!!tooltip && (open || forceShow) && !forceHide}\n onOpenChange={setOpen}\n delayDuration={delayDuration}\n disableHoverableContent={isActionVariant}\n >\n <TooltipTrigger\n ref={setTriggerElement}\n asChild={triggerAsChild}\n keepOpenOnClick={keepOpenOnTriggerClick}\n onKeyUp={handleKeyUp}\n className={hintUnderline ? HINT_UNDERLINE_CLASS_NAME : undefined}\n >\n {children}\n </TooltipTrigger>\n\n <TooltipContent\n className={className}\n variant={resolvedVariant}\n placement={placement}\n argo={argo}\n keepOpenOnPointerDownOutside={keepOpenOnTriggerClick}\n >\n {tooltip}\n </TooltipContent>\n </TooltipRoot>\n );\n};\n\nTooltip.Root = TooltipRoot;\nTooltip.Content = TooltipContent;\nTooltip.Trigger = TooltipTrigger;\n","import type { ComponentType } from 'react';\n\nimport { TooltipProvider } from '../components/Tooltip';\n\nexport const withTooltipProvider = (Story: ComponentType) => (\n <TooltipProvider>\n <Story />\n </TooltipProvider>\n);\n\n// Marks a story whose final render arrives asynchronously (lazy chunk, debounced\n// parse). The visual suite waits for every `[data-skeleton]` inside this box to\n// unmount before capturing, so the baseline is the settled content, never the\n// placeholder it briefly shows.\nexport const withVisualSettle = (Story: ComponentType) => (\n <div data-visual-settle>\n <Story />\n </div>\n);\n\n// position:fixed only fills the Storybook iframe, not the browser window.\nexport const withHiddenFullscreen = (Story: ComponentType) => (\n <div className=\"tw:[&_[aria-label=Fullscreen]]:hidden\">\n <Story />\n </div>\n);\n","export const createPrefixedString = (prefix: string) => (literals: TemplateStringsArray) =>\n literals.reduce((acc, literal) => acc + literal, `${prefix}-`);\n","export const noop = () => void 0;\n","type DebouncedFn<T extends (...args: any[]) => void> = {\n (...args: Parameters<T>): void;\n cancel: () => void;\n};\n\nexport const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n delay: number,\n): DebouncedFn<T> => {\n let timeoutId: ReturnType<typeof setTimeout>;\n const debounced = (...args: Parameters<T>) => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), delay);\n };\n debounced.cancel = () => clearTimeout(timeoutId);\n return debounced;\n};\n","// Platform detection\ntype NavigatorUAData = {\n platform: string;\n brands: { brand: string; version: string }[];\n mobile: boolean;\n};\n\nconst getIsMac = (): boolean => {\n // Modern approach using navigator.userAgentData\n if (typeof navigator !== 'undefined' && 'userAgentData' in navigator) {\n const platform = (navigator.userAgentData as NavigatorUAData).platform;\n\n if (typeof platform === 'string') {\n return platform.toLowerCase() === 'macos';\n }\n }\n\n if (typeof navigator !== 'undefined' && typeof navigator.platform === 'string') {\n return navigator.platform.toUpperCase().indexOf('MAC') >= 0;\n }\n\n // Server-side rendering fallback\n return false;\n};\n\nexport const isMac = getIsMac();\n","import { useEffect, useState } from 'react';\n\n// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\nconst sha256 = async (text: string) => {\n const msgUint8 = new TextEncoder().encode(text);\n const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n};\n\nexport const useSHA256 = (text?: string) => {\n const [hash, setHash] = useState('');\n\n useEffect(() => {\n if (!text) return;\n let cancelled = false;\n sha256(text).then((h) => {\n if (!cancelled) setHash(h);\n });\n return () => {\n cancelled = true;\n };\n }, [text]);\n\n // Empty input has no hash — derive it during render instead of syncing state\n // in the effect (avoids the extra render and a stale-value frame).\n return text ? hash : '';\n};\n","/** The separator a typed entry is split on when the caller names none. */\nexport const DEFAULT_ENTRY_SEPARATOR = ',';\n\n/**\n * The strings one typed entry stands for.\n *\n * - Parts are trimmed; blanks dropped.\n * - Repeats collapse case-insensitively, matching the combobox's display-string matching.\n * - A `null` separator returns the entry verbatim, untrimmed — the caller must reject blank text.\n */\nexport const splitEntry = (entry: string, separator: string | RegExp | null): string[] => {\n if (separator === null) return [entry];\n\n const seen = new Set<string>();\n return entry\n .split(separator)\n .map((part) => part.trim())\n .filter((part) => {\n if (part === '') return false;\n const key = part.toLowerCase();\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vegaTheme-VQMWTlBw.js","names":[],"sources":["../src/vega/vegaTokens.ts","../src/vega/vegaTheme.ts"],"sourcesContent":["import type { ResolvedColorScheme } from '../components/ThemeProvider/types';\nimport { createChannelResolver } from '../utils/themeTokens';\n\n/**\n * Serializes `\"R G B\"` channels comma-separated, the only form vega parses.\n *\n * - vega reads colours through d3-color 3.1, which answers `null` for the\n * space-separated CSS Color 4 form the rest of the package emits.\n * - A flat fill survives that anyway — the string reaches the SVG attribute and\n * the browser parses it. An interpolated one does not: both endpoints of a\n * sequential ramp collapse, and a quantitative scale paints solid black.\n */\nexport const vegaRgb = (channels: string, alpha?: number): string => {\n const c = channels.split(/\\s+/).join(', ');\n return alpha === undefined ? `rgb(${c})` : `rgba(${c}, ${alpha})`;\n};\n\n/** The `--chart-*` slots, in series order. */\nexport const SERIES_TOKENS = ['chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5'] as const;\n\n/**\n * Fallback channels for the tokens a vega chart reads, mirroring the `:root` /\n * `[data-theme='dark']` blocks of `styles.css`. The resolver reaches these only\n * when the live custom property is missing — SSR, or a unit test that loads no\n * CSS.\n */\nconst FALLBACK_CHANNELS = {\n foreground: { light: '30 41 59', dark: '229 230 236' },\n 'muted-foreground': { light: '100 116 139', dark: '141 144 153' },\n border: { light: '229 231 235', dark: '52 53 62' },\n 'chart-1': { light: '31 143 255', dark: '92 173 255' },\n 'chart-2': { light: '0 194 135', dark: '0 230 161' },\n 'chart-3': { light: '146 92 255', dark: '173 133 255' },\n 'chart-4': { light: '245 147 0', dark: '255 190 92' },\n 'chart-5': { light: '237 94 223', dark: '242 140 232' },\n // The sequential ramp's low end and the surface it must stay legible against.\n accent: { light: '224 242 254', dark: '30 58 95' },\n card: { light: '255 255 255', dark: '34 34 40' },\n} as const;\n\nexport type VegaTokenName = keyof typeof FALLBACK_CHANNELS;\n\n/**\n * A vega-serializing token resolver bound to one `getComputedStyle` snapshot.\n *\n * - Answers `rgb(R, G, B)` / `rgba(R, G, B, a)` — see {@link vegaRgb}.\n * - Falls back per scheme when the custom property is not painted.\n * - Build one per palette, never at module level: the values change whenever\n * the scheme or the brand does.\n */\nexport const createVegaColorResolver = (scheme: ResolvedColorScheme, from?: Element | null) => {\n const resolve = createChannelResolver(from);\n\n return (token: VegaTokenName, alpha?: number): string =>\n vegaRgb(resolve(token, FALLBACK_CHANNELS[token][scheme]), alpha);\n};\n","import type { Config } from 'vega-lite';\n\nimport type { ResolvedColorScheme } from '../components/ThemeProvider/types';\n\nimport { createVegaColorResolver, SERIES_TOKENS } from './vegaTokens';\n\nconst CHART_FONT = 'Inter, system-ui, sans-serif';\n\n/**\n * The design system's Vega-Lite chart look, following scheme and brand.\n *\n * - `range.category` is `--chart-1..5`, the same palette as `@keboola/design/charts`.\n * - A range set on the spec's own scale still wins (Flint charts rely on it).\n * - Colours are concrete `rgb()` strings — vega never reads the stylesheet — so rebuild on a\n * scheme or brand change; `useVegaTheme` does.\n */\nexport const vegaTheme = (scheme: ResolvedColorScheme, from?: Element | null): Config => {\n const token = createVegaColorResolver(scheme, from);\n\n const label = token('muted-foreground');\n const heading = token('foreground');\n const line = token('border');\n\n return {\n background: 'transparent',\n font: CHART_FONT,\n axis: {\n labelColor: label,\n titleColor: heading,\n gridColor: token('border', 0.6),\n domainColor: line,\n tickColor: line,\n },\n legend: { labelColor: label, titleColor: heading },\n header: { labelColor: label, titleColor: heading },\n title: { color: heading, subtitleColor: label },\n text: { color: heading },\n range: {\n category: SERIES_TOKENS.map((name) => token(name)),\n ramp: [token('accent'), token('chart-1')],\n },\n };\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,WAAW,UAAkB,UAA2B;CACnE,MAAM,IAAI,SAAS,MAAM,KAAK,CAAC,CAAC,KAAK,IAAI;CACzC,OAAO,UAAU,KAAA,IAAY,OAAO,EAAE,KAAK,QAAQ,EAAE,IAAI,MAAM;AACjE;;AAGA,MAAa,gBAAgB;CAAC;CAAW;CAAW;CAAW;CAAW;AAAS;;;;;;;AAQnF,MAAM,oBAAoB;CACxB,YAAY;EAAE,OAAO;EAAY,MAAM;CAAc;CACrD,oBAAoB;EAAE,OAAO;EAAe,MAAM;CAAc;CAChE,QAAQ;EAAE,OAAO;EAAe,MAAM;CAAW;CACjD,WAAW;EAAE,OAAO;EAAc,MAAM;CAAa;CACrD,WAAW;EAAE,OAAO;EAAa,MAAM;CAAY;CACnD,WAAW;EAAE,OAAO;EAAc,MAAM;CAAc;CACtD,WAAW;EAAE,OAAO;EAAa,MAAM;CAAa;CACpD,WAAW;EAAE,OAAO;EAAc,MAAM;CAAc;CAEtD,QAAQ;EAAE,OAAO;EAAe,MAAM;CAAW;CACjD,MAAM;EAAE,OAAO;EAAe,MAAM;CAAW;AACjD;;;;;;;;;AAYA,MAAa,2BAA2B,QAA6B,SAA0B;CAC7F,MAAM,UAAU,sBAAsB,IAAI;CAE1C,QAAQ,OAAsB,UAC5B,QAAQ,QAAQ,OAAO,kBAAkB,MAAM,CAAC,OAAO,GAAG,KAAK;AACnE;;;ACjDA,MAAM,aAAa;;;;;;;;;AAUnB,MAAa,aAAa,QAA6B,SAAkC;CACvF,MAAM,QAAQ,wBAAwB,QAAQ,IAAI;CAElD,MAAM,QAAQ,MAAM,kBAAkB;CACtC,MAAM,UAAU,MAAM,YAAY;CAClC,MAAM,OAAO,MAAM,QAAQ;CAE3B,OAAO;EACL,YAAY;EACZ,MAAM;EACN,MAAM;GACJ,YAAY;GACZ,YAAY;GACZ,WAAW,MAAM,UAAU,EAAG;GAC9B,aAAa;GACb,WAAW;EACb;EACA,QAAQ;GAAE,YAAY;GAAO,YAAY;EAAQ;EACjD,QAAQ;GAAE,YAAY;GAAO,YAAY;EAAQ;EACjD,OAAO;GAAE,OAAO;GAAS,eAAe;EAAM;EAC9C,MAAM,EAAE,OAAO,QAAQ;EACvB,OAAO;GACL,UAAU,cAAc,KAAK,SAAS,MAAM,IAAI,CAAC;GACjD,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC;EAC1C;CACF;AACF"}
|