From 0a6f4b5c78f887754d383285c2083c34604ca636 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:44:35 +0800 Subject: [PATCH 01/18] feat: add CAD color mode integration helpers --- packages/renderers/cad/src/colorMode.ts | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 packages/renderers/cad/src/colorMode.ts diff --git a/packages/renderers/cad/src/colorMode.ts b/packages/renderers/cad/src/colorMode.ts new file mode 100644 index 000000000..521c93f7d --- /dev/null +++ b/packages/renderers/cad/src/colorMode.ts @@ -0,0 +1,30 @@ +import type { FileViewerCadColorMode } from '@file-viewer/core'; + +export interface CadViewerColorModeAdapter { + setColorMode?: (mode: FileViewerCadColorMode, monochromeColor?: string) => void; + getColorMode?: () => FileViewerCadColorMode; + getMonochromeColor?: () => string | undefined; +} + +export function normalizeFileViewerCadColorMode(value: unknown): FileViewerCadColorMode { + return value === 'monochrome' ? 'monochrome' : 'source'; +} + +export function resolveFileViewerCadMonochromeColor(value: unknown, fallback = '#0f172a'): string { + if (typeof value === 'string' && value.trim()) return value.trim(); + return fallback; +} + +export function supportsCadViewerColorMode(value: unknown): value is CadViewerColorModeAdapter { + return Boolean(value && typeof (value as CadViewerColorModeAdapter).setColorMode === 'function'); +} + +export function applyCadViewerColorMode( + viewer: unknown, + mode: FileViewerCadColorMode, + monochromeColor: string +): boolean { + if (!supportsCadViewerColorMode(viewer)) return false; + viewer.setColorMode?.(mode, monochromeColor); + return true; +} From d8c34ec0c974a30c56e8ddd18a03bdc37855302f Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:45:58 +0800 Subject: [PATCH 02/18] chore: apply deterministic issue 213 integration --- .github/workflows/apply-issue-213.yml | 203 ++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 .github/workflows/apply-issue-213.yml diff --git a/.github/workflows/apply-issue-213.yml b/.github/workflows/apply-issue-213.yml new file mode 100644 index 000000000..1a28f2ca5 --- /dev/null +++ b/.github/workflows/apply-issue-213.yml @@ -0,0 +1,203 @@ +name: Apply issue 213 CAD integration + +on: + push: + branches: [feature/issue-213-monochrome-cad] + +permissions: + contents: write + +jobs: + codemod: + if: ${{ !contains(github.event.head_commit.message, '[issue-213-applied]') }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: feature/issue-213-monochrome-cad + - name: Apply deterministic source changes + run: | + python <<'PY' + from pathlib import Path + + def replace_once(path: str, old: str, new: str) -> None: + file = Path(path) + text = file.read_text(encoding='utf-8') + if new in text: + return + count = text.count(old) + if count != 1: + raise RuntimeError(f'{path}: expected one match, found {count}: {old[:80]!r}') + file.write_text(text.replace(old, new, 1), encoding='utf-8') + + def append_once(path: str, marker: str, content: str) -> None: + file = Path(path) + text = file.read_text(encoding='utf-8') + if marker in text: + return + file.write_text(text.rstrip() + '\n\n' + content.strip() + '\n', encoding='utf-8') + + # Core public contracts and localized toolbar labels. + replace_once( + 'packages/core/src/contracts/types.ts', + " | 'cad.toolbar.zoomIn'\n | 'cad.layers.title'", + " | 'cad.toolbar.zoomIn'\n | 'cad.toolbar.colorSource'\n | 'cad.toolbar.monochrome'\n | 'cad.layers.title'", + ) + replace_once( + 'packages/core/src/contracts/types.ts', + "export type FileViewerCadRenderer = 'auto' | 'webgl' | 'canvas2d';\nexport type FileViewerCadDwfLineWeightMode = 'adaptive' | 'physical' | 'hairline';\nexport type FileViewerCadFitMode = 'best' | 'native';", + "export type FileViewerCadRenderer = 'auto' | 'webgl' | 'canvas2d';\nexport type FileViewerCadDwfLineWeightMode = 'adaptive' | 'physical' | 'hairline';\nexport type FileViewerCadColorMode = 'source' | 'monochrome';\nexport type FileViewerCadFitMode = 'best' | 'native';", + ) + replace_once( + 'packages/core/src/contracts/types.ts', + " renderer?: FileViewerCadRenderer;\n preferDwgWasm?: boolean;", + " renderer?: FileViewerCadRenderer;\n /** Initial CAD color policy. `monochrome` applies one plot color without mutating source data. */\n colorMode?: FileViewerCadColorMode;\n /** CSS color used by monochrome mode. Defaults to the CAD foreground color. */\n monochromeColor?: string;\n /** Shows the CAD toolbar color-mode toggle. Defaults to true. */\n showColorModeToggle?: boolean;\n preferDwgWasm?: boolean;", + ) + + replace_once( + 'packages/core/src/i18n/messages.ts', + " 'cad.toolbar.zoomOut': '缩小',\n 'cad.toolbar.zoomIn': '放大',\n 'cad.layers.title': '图层',", + " 'cad.toolbar.zoomOut': '缩小',\n 'cad.toolbar.zoomIn': '放大',\n 'cad.toolbar.colorSource': '彩色',\n 'cad.toolbar.monochrome': '黑白',\n 'cad.layers.title': '图层',", + ) + replace_once( + 'packages/core/src/i18n/messages.ts', + " 'cad.toolbar.zoomOut': 'Zoom out',\n 'cad.toolbar.zoomIn': 'Zoom in',\n 'cad.layers.title': 'Layers',", + " 'cad.toolbar.zoomOut': 'Zoom out',\n 'cad.toolbar.zoomIn': 'Zoom in',\n 'cad.toolbar.colorSource': 'Source colors',\n 'cad.toolbar.monochrome': 'Monochrome',\n 'cad.layers.title': 'Layers',", + ) + replace_once( + 'packages/core/src/i18n/messages.ja.ts', + " 'cad.toolbar.zoomOut': '縮小',\n 'cad.toolbar.zoomIn': '拡大',\n 'cad.layers.title': 'レイヤー',", + " 'cad.toolbar.zoomOut': '縮小',\n 'cad.toolbar.zoomIn': '拡大',\n 'cad.toolbar.colorSource': '元の色',\n 'cad.toolbar.monochrome': 'モノクロ',\n 'cad.layers.title': 'レイヤー',", + ) + replace_once( + 'packages/core/src/i18n/messages.de.ts', + ' "cad.toolbar.zoomOut": "Herauszoomen",\n "cad.toolbar.zoomIn": "Vergrößern",\n "cad.layers.title": "Schichten",', + ' "cad.toolbar.zoomOut": "Herauszoomen",\n "cad.toolbar.zoomIn": "Vergrößern",\n "cad.toolbar.colorSource": "Originalfarben",\n "cad.toolbar.monochrome": "Monochrom",\n "cad.layers.title": "Schichten",', + ) + + for path in [ + 'packages/core/src/index.ts', + 'packages/core/src/headless.ts', + 'packages/components/vue3/src/package/index.ts', + ]: + replace_once( + path, + ' FileViewerCadDwfLineWeightMode,\n FileViewerCadOptions,', + ' FileViewerCadColorMode,\n FileViewerCadDwfLineWeightMode,\n FileViewerCadOptions,', + ) + + replace_once( + 'packages/components/vue3/src/package/common/type.ts', + ' FileViewerCadDwfLineWeightMode as CoreFileViewerCadDwfLineWeightMode,\n FileViewerCadOptions as CoreFileViewerCadOptions,', + ' FileViewerCadColorMode as CoreFileViewerCadColorMode,\n FileViewerCadDwfLineWeightMode as CoreFileViewerCadDwfLineWeightMode,\n FileViewerCadOptions as CoreFileViewerCadOptions,', + ) + replace_once( + 'packages/components/vue3/src/package/common/type.ts', + 'export type FileViewerCadRenderer = CoreFileViewerCadRenderer;\nexport type FileViewerCadDwfLineWeightMode = CoreFileViewerCadDwfLineWeightMode;', + 'export type FileViewerCadRenderer = CoreFileViewerCadRenderer;\nexport type FileViewerCadColorMode = CoreFileViewerCadColorMode;\nexport type FileViewerCadDwfLineWeightMode = CoreFileViewerCadDwfLineWeightMode;', + ) + + cad = 'packages/renderers/cad/src/cad.ts' + replace_once( + cad, + ' type FileViewerCadOptions,\n type FileViewerFitRequest,', + ' type FileViewerCadColorMode,\n type FileViewerCadOptions,\n type FileViewerFitRequest,', + ) + replace_once( + cad, + "} from '@file-viewer/core';\n\ntype CadStatus = 'loading' | 'ready' | 'error';", + "} from '@file-viewer/core';\nimport {\n applyCadViewerColorMode,\n normalizeFileViewerCadColorMode,\n resolveFileViewerCadMonochromeColor,\n supportsCadViewerColorMode,\n} from './colorMode';\n\ntype CadStatus = 'loading' | 'ready' | 'error';", + ) + replace_once( + cad, + ".cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62}\n.cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0}", + ".cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62}\n.cad-tools button.cad-color-mode{min-width:52px;padding:0 10px;font-size:12px}\n.cad-tools button.cad-color-mode[aria-pressed='true']{background:#0f172a;color:#fff}\n.cad-tools button.cad-color-mode:disabled{cursor:not-allowed;opacity:.46}\n.cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0}", + ) + replace_once( + cad, + " const t = createFileViewerTranslator(context?.options);\n const locale = resolveFileViewerLocale(context?.options);\n let status: CadStatus = 'loading';", + " const t = createFileViewerTranslator(context?.options);\n const locale = resolveFileViewerLocale(context?.options);\n const monochromeColor = resolveFileViewerCadMonochromeColor(options.monochromeColor);\n let colorMode = normalizeFileViewerCadColorMode(options.colorMode);\n let status: CadStatus = 'loading';", + ) + replace_once( + cad, + " const zoomText = createElement('span', 'cad-zoom', '100%');\n const zoomInButton = createElement('button', undefined, '+') as HTMLButtonElement;\n const meta = createElement('div', 'cad-meta');", + " const zoomText = createElement('span', 'cad-zoom', '100%');\n const zoomInButton = createElement('button', undefined, '+') as HTMLButtonElement;\n const colorModeButton = createElement('button', 'cad-color-mode') as HTMLButtonElement;\n colorModeButton.hidden = options.showColorModeToggle === false;\n const meta = createElement('div', 'cad-meta');", + ) + replace_once( + cad, + " [fitButton, zoomOutButton, zoomInButton].forEach(button => {\n button.type = 'button';\n });\n fitButton.title = t('cad.toolbar.fit');\n zoomOutButton.title = t('cad.toolbar.zoomOut');\n zoomInButton.title = t('cad.toolbar.zoomIn');\n tools.append(fitButton, zoomOutButton, zoomText, zoomInButton);", + " [fitButton, zoomOutButton, zoomInButton, colorModeButton].forEach(button => {\n button.type = 'button';\n });\n fitButton.title = t('cad.toolbar.fit');\n zoomOutButton.title = t('cad.toolbar.zoomOut');\n zoomInButton.title = t('cad.toolbar.zoomIn');\n tools.append(fitButton, zoomOutButton, zoomText, zoomInButton, colorModeButton);", + ) + replace_once( + cad, + " backend: renderStats?.backend,\n layerCount: layers.length,", + " backend: renderStats?.backend,\n colorMode,\n monochromeColor: colorMode === 'monochrome' ? monochromeColor : undefined,\n layerCount: layers.length,", + ) + replace_once( + cad, + " const color = createElement('span', 'cad-layer-color');\n if (typeof layer.color === 'string') {\n color.style.background = layer.color;\n }", + " const color = createElement('span', 'cad-layer-color');\n if (colorMode === 'monochrome') {\n color.style.background = monochromeColor;\n } else if (typeof layer.color === 'string') {\n color.style.background = layer.color;\n }", + ) + replace_once( + cad, + " const syncState = () => {\n zoomText.textContent = `${getZoomPercent()}%`;\n backendMeta.textContent = (renderStats?.backend || 'auto').toUpperCase();", + " const syncState = () => {\n zoomText.textContent = `${getZoomPercent()}%`;\n backendMeta.textContent = (renderStats?.backend || 'auto').toUpperCase();\n const colorModeSupported = supportsCadViewerColorMode(viewer);\n colorModeButton.disabled = status !== 'ready' || !colorModeSupported;\n colorModeButton.setAttribute('aria-pressed', String(colorMode === 'monochrome'));\n colorModeButton.textContent = t(colorMode === 'monochrome'\n ? 'cad.toolbar.monochrome'\n : 'cad.toolbar.colorSource');\n colorModeButton.title = t(colorMode === 'monochrome'\n ? 'cad.toolbar.colorSource'\n : 'cad.toolbar.monochrome');", + ) + replace_once( + cad, + " fitButton.addEventListener('click', () => fitToView());\n zoomInButton.addEventListener('click', zoomIn);\n zoomOutButton.addEventListener('click', zoomOut);", + " fitButton.addEventListener('click', () => fitToView());\n zoomInButton.addEventListener('click', zoomIn);\n zoomOutButton.addEventListener('click', zoomOut);\n colorModeButton.addEventListener('click', () => {\n const previousMode = colorMode;\n colorMode = colorMode === 'monochrome' ? 'source' : 'monochrome';\n if (!applyCadViewerColorMode(viewer, colorMode, monochromeColor)) {\n colorMode = previousMode;\n syncState();\n return;\n }\n syncUi();\n emitCadViewStateChange('cad-view-change', 'user');\n });", + ) + replace_once( + cad, + " dwfMinTextCssPx: options.dwfMinTextCssPx,\n dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx,\n autoFit: true,", + " dwfMinTextCssPx: options.dwfMinTextCssPx,\n dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx,\n ...({ colorMode, monochromeColor } as Record),\n autoFit: true,", + ) + + append_once( + 'packages/renderers/cad/README.md', + '## 黑白出图模式', + ''' + ## 黑白出图模式 + + `cad.colorMode` 可设为 `source` 或 `monochrome`。黑白模式通过 CAD 引擎的实体颜色策略实现,不使用 CSS 滤镜,因此 Canvas、WebGL、文字覆盖层及原生 DWF 渲染可保持一致,同时保留透明度、线型、线宽和源文件数据。 + + ```ts + { + cad: { + colorMode: 'monochrome', + monochromeColor: '#000000', + showColorModeToggle: true, + }, + } + ``` + ''', + ) + append_once( + 'packages/renderers/cad/README.en.md', + '## Monochrome plot mode', + ''' + ## Monochrome plot mode + + Set `cad.colorMode` to `source` or `monochrome`. Monochrome rendering uses the CAD engine's entity-color policy rather than a CSS filter, keeping Canvas, WebGL, text overlays and native DWF output consistent while preserving alpha, line types, line weights and source data. + + ```ts + { + cad: { + colorMode: 'monochrome', + monochromeColor: '#000000', + showColorModeToggle: true, + }, + } + ``` + ''', + ) + PY + + rm .github/workflows/apply-issue-213.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git commit -m "feat: integrate monochrome CAD mode [issue-213-applied]" + git push origin HEAD:feature/issue-213-monochrome-cad From a16baa21197f5a7886b5212cd91a377be44174c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2026 06:46:12 +0000 Subject: [PATCH 03/18] feat: integrate monochrome CAD mode [issue-213-applied] --- .github/workflows/apply-issue-213.yml | 203 ------------------ .../vue3/src/package/common/type.ts | 2 + packages/components/vue3/src/package/index.ts | 1 + packages/core/src/contracts/types.ts | 9 + packages/core/src/headless.ts | 1 + packages/core/src/i18n/messages.de.ts | 2 + packages/core/src/i18n/messages.ja.ts | 2 + packages/core/src/i18n/messages.ts | 4 + packages/core/src/index.ts | 1 + packages/renderers/cad/README.en.md | 14 ++ packages/renderers/cad/README.md | 14 ++ packages/renderers/cad/src/cad.ts | 45 +++- 12 files changed, 92 insertions(+), 206 deletions(-) delete mode 100644 .github/workflows/apply-issue-213.yml diff --git a/.github/workflows/apply-issue-213.yml b/.github/workflows/apply-issue-213.yml deleted file mode 100644 index 1a28f2ca5..000000000 --- a/.github/workflows/apply-issue-213.yml +++ /dev/null @@ -1,203 +0,0 @@ -name: Apply issue 213 CAD integration - -on: - push: - branches: [feature/issue-213-monochrome-cad] - -permissions: - contents: write - -jobs: - codemod: - if: ${{ !contains(github.event.head_commit.message, '[issue-213-applied]') }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: feature/issue-213-monochrome-cad - - name: Apply deterministic source changes - run: | - python <<'PY' - from pathlib import Path - - def replace_once(path: str, old: str, new: str) -> None: - file = Path(path) - text = file.read_text(encoding='utf-8') - if new in text: - return - count = text.count(old) - if count != 1: - raise RuntimeError(f'{path}: expected one match, found {count}: {old[:80]!r}') - file.write_text(text.replace(old, new, 1), encoding='utf-8') - - def append_once(path: str, marker: str, content: str) -> None: - file = Path(path) - text = file.read_text(encoding='utf-8') - if marker in text: - return - file.write_text(text.rstrip() + '\n\n' + content.strip() + '\n', encoding='utf-8') - - # Core public contracts and localized toolbar labels. - replace_once( - 'packages/core/src/contracts/types.ts', - " | 'cad.toolbar.zoomIn'\n | 'cad.layers.title'", - " | 'cad.toolbar.zoomIn'\n | 'cad.toolbar.colorSource'\n | 'cad.toolbar.monochrome'\n | 'cad.layers.title'", - ) - replace_once( - 'packages/core/src/contracts/types.ts', - "export type FileViewerCadRenderer = 'auto' | 'webgl' | 'canvas2d';\nexport type FileViewerCadDwfLineWeightMode = 'adaptive' | 'physical' | 'hairline';\nexport type FileViewerCadFitMode = 'best' | 'native';", - "export type FileViewerCadRenderer = 'auto' | 'webgl' | 'canvas2d';\nexport type FileViewerCadDwfLineWeightMode = 'adaptive' | 'physical' | 'hairline';\nexport type FileViewerCadColorMode = 'source' | 'monochrome';\nexport type FileViewerCadFitMode = 'best' | 'native';", - ) - replace_once( - 'packages/core/src/contracts/types.ts', - " renderer?: FileViewerCadRenderer;\n preferDwgWasm?: boolean;", - " renderer?: FileViewerCadRenderer;\n /** Initial CAD color policy. `monochrome` applies one plot color without mutating source data. */\n colorMode?: FileViewerCadColorMode;\n /** CSS color used by monochrome mode. Defaults to the CAD foreground color. */\n monochromeColor?: string;\n /** Shows the CAD toolbar color-mode toggle. Defaults to true. */\n showColorModeToggle?: boolean;\n preferDwgWasm?: boolean;", - ) - - replace_once( - 'packages/core/src/i18n/messages.ts', - " 'cad.toolbar.zoomOut': '缩小',\n 'cad.toolbar.zoomIn': '放大',\n 'cad.layers.title': '图层',", - " 'cad.toolbar.zoomOut': '缩小',\n 'cad.toolbar.zoomIn': '放大',\n 'cad.toolbar.colorSource': '彩色',\n 'cad.toolbar.monochrome': '黑白',\n 'cad.layers.title': '图层',", - ) - replace_once( - 'packages/core/src/i18n/messages.ts', - " 'cad.toolbar.zoomOut': 'Zoom out',\n 'cad.toolbar.zoomIn': 'Zoom in',\n 'cad.layers.title': 'Layers',", - " 'cad.toolbar.zoomOut': 'Zoom out',\n 'cad.toolbar.zoomIn': 'Zoom in',\n 'cad.toolbar.colorSource': 'Source colors',\n 'cad.toolbar.monochrome': 'Monochrome',\n 'cad.layers.title': 'Layers',", - ) - replace_once( - 'packages/core/src/i18n/messages.ja.ts', - " 'cad.toolbar.zoomOut': '縮小',\n 'cad.toolbar.zoomIn': '拡大',\n 'cad.layers.title': 'レイヤー',", - " 'cad.toolbar.zoomOut': '縮小',\n 'cad.toolbar.zoomIn': '拡大',\n 'cad.toolbar.colorSource': '元の色',\n 'cad.toolbar.monochrome': 'モノクロ',\n 'cad.layers.title': 'レイヤー',", - ) - replace_once( - 'packages/core/src/i18n/messages.de.ts', - ' "cad.toolbar.zoomOut": "Herauszoomen",\n "cad.toolbar.zoomIn": "Vergrößern",\n "cad.layers.title": "Schichten",', - ' "cad.toolbar.zoomOut": "Herauszoomen",\n "cad.toolbar.zoomIn": "Vergrößern",\n "cad.toolbar.colorSource": "Originalfarben",\n "cad.toolbar.monochrome": "Monochrom",\n "cad.layers.title": "Schichten",', - ) - - for path in [ - 'packages/core/src/index.ts', - 'packages/core/src/headless.ts', - 'packages/components/vue3/src/package/index.ts', - ]: - replace_once( - path, - ' FileViewerCadDwfLineWeightMode,\n FileViewerCadOptions,', - ' FileViewerCadColorMode,\n FileViewerCadDwfLineWeightMode,\n FileViewerCadOptions,', - ) - - replace_once( - 'packages/components/vue3/src/package/common/type.ts', - ' FileViewerCadDwfLineWeightMode as CoreFileViewerCadDwfLineWeightMode,\n FileViewerCadOptions as CoreFileViewerCadOptions,', - ' FileViewerCadColorMode as CoreFileViewerCadColorMode,\n FileViewerCadDwfLineWeightMode as CoreFileViewerCadDwfLineWeightMode,\n FileViewerCadOptions as CoreFileViewerCadOptions,', - ) - replace_once( - 'packages/components/vue3/src/package/common/type.ts', - 'export type FileViewerCadRenderer = CoreFileViewerCadRenderer;\nexport type FileViewerCadDwfLineWeightMode = CoreFileViewerCadDwfLineWeightMode;', - 'export type FileViewerCadRenderer = CoreFileViewerCadRenderer;\nexport type FileViewerCadColorMode = CoreFileViewerCadColorMode;\nexport type FileViewerCadDwfLineWeightMode = CoreFileViewerCadDwfLineWeightMode;', - ) - - cad = 'packages/renderers/cad/src/cad.ts' - replace_once( - cad, - ' type FileViewerCadOptions,\n type FileViewerFitRequest,', - ' type FileViewerCadColorMode,\n type FileViewerCadOptions,\n type FileViewerFitRequest,', - ) - replace_once( - cad, - "} from '@file-viewer/core';\n\ntype CadStatus = 'loading' | 'ready' | 'error';", - "} from '@file-viewer/core';\nimport {\n applyCadViewerColorMode,\n normalizeFileViewerCadColorMode,\n resolveFileViewerCadMonochromeColor,\n supportsCadViewerColorMode,\n} from './colorMode';\n\ntype CadStatus = 'loading' | 'ready' | 'error';", - ) - replace_once( - cad, - ".cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62}\n.cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0}", - ".cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62}\n.cad-tools button.cad-color-mode{min-width:52px;padding:0 10px;font-size:12px}\n.cad-tools button.cad-color-mode[aria-pressed='true']{background:#0f172a;color:#fff}\n.cad-tools button.cad-color-mode:disabled{cursor:not-allowed;opacity:.46}\n.cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0}", - ) - replace_once( - cad, - " const t = createFileViewerTranslator(context?.options);\n const locale = resolveFileViewerLocale(context?.options);\n let status: CadStatus = 'loading';", - " const t = createFileViewerTranslator(context?.options);\n const locale = resolveFileViewerLocale(context?.options);\n const monochromeColor = resolveFileViewerCadMonochromeColor(options.monochromeColor);\n let colorMode = normalizeFileViewerCadColorMode(options.colorMode);\n let status: CadStatus = 'loading';", - ) - replace_once( - cad, - " const zoomText = createElement('span', 'cad-zoom', '100%');\n const zoomInButton = createElement('button', undefined, '+') as HTMLButtonElement;\n const meta = createElement('div', 'cad-meta');", - " const zoomText = createElement('span', 'cad-zoom', '100%');\n const zoomInButton = createElement('button', undefined, '+') as HTMLButtonElement;\n const colorModeButton = createElement('button', 'cad-color-mode') as HTMLButtonElement;\n colorModeButton.hidden = options.showColorModeToggle === false;\n const meta = createElement('div', 'cad-meta');", - ) - replace_once( - cad, - " [fitButton, zoomOutButton, zoomInButton].forEach(button => {\n button.type = 'button';\n });\n fitButton.title = t('cad.toolbar.fit');\n zoomOutButton.title = t('cad.toolbar.zoomOut');\n zoomInButton.title = t('cad.toolbar.zoomIn');\n tools.append(fitButton, zoomOutButton, zoomText, zoomInButton);", - " [fitButton, zoomOutButton, zoomInButton, colorModeButton].forEach(button => {\n button.type = 'button';\n });\n fitButton.title = t('cad.toolbar.fit');\n zoomOutButton.title = t('cad.toolbar.zoomOut');\n zoomInButton.title = t('cad.toolbar.zoomIn');\n tools.append(fitButton, zoomOutButton, zoomText, zoomInButton, colorModeButton);", - ) - replace_once( - cad, - " backend: renderStats?.backend,\n layerCount: layers.length,", - " backend: renderStats?.backend,\n colorMode,\n monochromeColor: colorMode === 'monochrome' ? monochromeColor : undefined,\n layerCount: layers.length,", - ) - replace_once( - cad, - " const color = createElement('span', 'cad-layer-color');\n if (typeof layer.color === 'string') {\n color.style.background = layer.color;\n }", - " const color = createElement('span', 'cad-layer-color');\n if (colorMode === 'monochrome') {\n color.style.background = monochromeColor;\n } else if (typeof layer.color === 'string') {\n color.style.background = layer.color;\n }", - ) - replace_once( - cad, - " const syncState = () => {\n zoomText.textContent = `${getZoomPercent()}%`;\n backendMeta.textContent = (renderStats?.backend || 'auto').toUpperCase();", - " const syncState = () => {\n zoomText.textContent = `${getZoomPercent()}%`;\n backendMeta.textContent = (renderStats?.backend || 'auto').toUpperCase();\n const colorModeSupported = supportsCadViewerColorMode(viewer);\n colorModeButton.disabled = status !== 'ready' || !colorModeSupported;\n colorModeButton.setAttribute('aria-pressed', String(colorMode === 'monochrome'));\n colorModeButton.textContent = t(colorMode === 'monochrome'\n ? 'cad.toolbar.monochrome'\n : 'cad.toolbar.colorSource');\n colorModeButton.title = t(colorMode === 'monochrome'\n ? 'cad.toolbar.colorSource'\n : 'cad.toolbar.monochrome');", - ) - replace_once( - cad, - " fitButton.addEventListener('click', () => fitToView());\n zoomInButton.addEventListener('click', zoomIn);\n zoomOutButton.addEventListener('click', zoomOut);", - " fitButton.addEventListener('click', () => fitToView());\n zoomInButton.addEventListener('click', zoomIn);\n zoomOutButton.addEventListener('click', zoomOut);\n colorModeButton.addEventListener('click', () => {\n const previousMode = colorMode;\n colorMode = colorMode === 'monochrome' ? 'source' : 'monochrome';\n if (!applyCadViewerColorMode(viewer, colorMode, monochromeColor)) {\n colorMode = previousMode;\n syncState();\n return;\n }\n syncUi();\n emitCadViewStateChange('cad-view-change', 'user');\n });", - ) - replace_once( - cad, - " dwfMinTextCssPx: options.dwfMinTextCssPx,\n dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx,\n autoFit: true,", - " dwfMinTextCssPx: options.dwfMinTextCssPx,\n dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx,\n ...({ colorMode, monochromeColor } as Record),\n autoFit: true,", - ) - - append_once( - 'packages/renderers/cad/README.md', - '## 黑白出图模式', - ''' - ## 黑白出图模式 - - `cad.colorMode` 可设为 `source` 或 `monochrome`。黑白模式通过 CAD 引擎的实体颜色策略实现,不使用 CSS 滤镜,因此 Canvas、WebGL、文字覆盖层及原生 DWF 渲染可保持一致,同时保留透明度、线型、线宽和源文件数据。 - - ```ts - { - cad: { - colorMode: 'monochrome', - monochromeColor: '#000000', - showColorModeToggle: true, - }, - } - ``` - ''', - ) - append_once( - 'packages/renderers/cad/README.en.md', - '## Monochrome plot mode', - ''' - ## Monochrome plot mode - - Set `cad.colorMode` to `source` or `monochrome`. Monochrome rendering uses the CAD engine's entity-color policy rather than a CSS filter, keeping Canvas, WebGL, text overlays and native DWF output consistent while preserving alpha, line types, line weights and source data. - - ```ts - { - cad: { - colorMode: 'monochrome', - monochromeColor: '#000000', - showColorModeToggle: true, - }, - } - ``` - ''', - ) - PY - - rm .github/workflows/apply-issue-213.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git commit -m "feat: integrate monochrome CAD mode [issue-213-applied]" - git push origin HEAD:feature/issue-213-monochrome-cad diff --git a/packages/components/vue3/src/package/common/type.ts b/packages/components/vue3/src/package/common/type.ts index e73340882..ce5b37e67 100644 --- a/packages/components/vue3/src/package/common/type.ts +++ b/packages/components/vue3/src/package/common/type.ts @@ -2,6 +2,7 @@ import type { FileViewerAiOptions as CoreFileViewerAiOptions, FileViewerArchiveOptions as CoreFileViewerArchiveOptions, FileViewerBeforeOperation as CoreFileViewerBeforeOperation, + FileViewerCadColorMode as CoreFileViewerCadColorMode, FileViewerCadDwfLineWeightMode as CoreFileViewerCadDwfLineWeightMode, FileViewerCadOptions as CoreFileViewerCadOptions, FileViewerCadRenderer as CoreFileViewerCadRenderer, @@ -110,6 +111,7 @@ export type FileViewerSpreadsheetOptions = CoreFileViewerSpreadsheetOptions; export type FileViewerTypstOptions = CoreFileViewerTypstOptions; export type FileViewerCadRenderer = CoreFileViewerCadRenderer; +export type FileViewerCadColorMode = CoreFileViewerCadColorMode; export type FileViewerCadDwfLineWeightMode = CoreFileViewerCadDwfLineWeightMode; /** diff --git a/packages/components/vue3/src/package/index.ts b/packages/components/vue3/src/package/index.ts index dca994c4b..27acc31ce 100644 --- a/packages/components/vue3/src/package/index.ts +++ b/packages/components/vue3/src/package/index.ts @@ -107,6 +107,7 @@ export type { FileViewerApplyViewStateOptions, FileViewerArchiveOptions, FileViewerBeforeOperation, + FileViewerCadColorMode, FileViewerCadDwfLineWeightMode, FileViewerCadOptions, FileViewerCadRenderer, diff --git a/packages/core/src/contracts/types.ts b/packages/core/src/contracts/types.ts index 1aae40d9e..1c105723b 100644 --- a/packages/core/src/contracts/types.ts +++ b/packages/core/src/contracts/types.ts @@ -357,6 +357,8 @@ export type FileViewerMessageKey = | 'cad.toolbar.fit' | 'cad.toolbar.zoomOut' | 'cad.toolbar.zoomIn' + | 'cad.toolbar.colorSource' + | 'cad.toolbar.monochrome' | 'cad.layers.title' | 'cad.layers.count' | 'cad.layers.merged' @@ -1108,6 +1110,7 @@ export interface FileViewerDrawingOptions { export type FileViewerCadRenderer = 'auto' | 'webgl' | 'canvas2d'; export type FileViewerCadDwfLineWeightMode = 'adaptive' | 'physical' | 'hairline'; +export type FileViewerCadColorMode = 'source' | 'monochrome'; export type FileViewerCadFitMode = 'best' | 'native'; export interface FileViewerCadOptions { @@ -1118,6 +1121,12 @@ export interface FileViewerCadOptions { useWorker?: boolean; workerTimeoutMs?: number; renderer?: FileViewerCadRenderer; + /** Initial CAD color policy. `monochrome` applies one plot color without mutating source data. */ + colorMode?: FileViewerCadColorMode; + /** CSS color used by monochrome mode. Defaults to the CAD foreground color. */ + monochromeColor?: string; + /** Shows the CAD toolbar color-mode toggle. Defaults to true. */ + showColorModeToggle?: boolean; preferDwgWasm?: boolean; includePaperSpace?: boolean; maxInsertDepth?: number; diff --git a/packages/core/src/headless.ts b/packages/core/src/headless.ts index 2e63f6e27..f26c708cd 100644 --- a/packages/core/src/headless.ts +++ b/packages/core/src/headless.ts @@ -450,6 +450,7 @@ export type { FileViewerArchiveOptions, FileViewerApplyViewStateOptions, FileViewerBeforeOperation, + FileViewerCadColorMode, FileViewerCadDwfLineWeightMode, FileViewerCadOptions, FileViewerCadRenderer, diff --git a/packages/core/src/i18n/messages.de.ts b/packages/core/src/i18n/messages.de.ts index f74a5ca1c..3baf1d27f 100644 --- a/packages/core/src/i18n/messages.de.ts +++ b/packages/core/src/i18n/messages.de.ts @@ -348,6 +348,8 @@ export const DE_DE_MESSAGES: Record = { "cad.toolbar.fit": "Fit", "cad.toolbar.zoomOut": "Herauszoomen", "cad.toolbar.zoomIn": "Vergrößern", + "cad.toolbar.colorSource": "Originalfarben", + "cad.toolbar.monochrome": "Monochrom", "cad.layers.title": "Schichten", "cad.layers.count": "{count} Artikel", "cad.layers.merged": "{name} ({count} zusammengeführte Ebenen)", diff --git a/packages/core/src/i18n/messages.ja.ts b/packages/core/src/i18n/messages.ja.ts index be9197afb..5cbf7e2d2 100644 --- a/packages/core/src/i18n/messages.ja.ts +++ b/packages/core/src/i18n/messages.ja.ts @@ -349,6 +349,8 @@ export const JA_JP_MESSAGES: Record = { 'cad.toolbar.fit': '全体表示', 'cad.toolbar.zoomOut': '縮小', 'cad.toolbar.zoomIn': '拡大', + 'cad.toolbar.colorSource': '元の色', + 'cad.toolbar.monochrome': 'モノクロ', 'cad.layers.title': 'レイヤー', 'cad.layers.count': '{count} 件', 'cad.layers.merged': '{name}(同名レイヤー {count} 件を統合)', diff --git a/packages/core/src/i18n/messages.ts b/packages/core/src/i18n/messages.ts index fccd9f0f7..01a1658d2 100644 --- a/packages/core/src/i18n/messages.ts +++ b/packages/core/src/i18n/messages.ts @@ -367,6 +367,8 @@ const ZH_CN_MESSAGES: Record = { 'cad.toolbar.fit': '适配', 'cad.toolbar.zoomOut': '缩小', 'cad.toolbar.zoomIn': '放大', + 'cad.toolbar.colorSource': '彩色', + 'cad.toolbar.monochrome': '黑白', 'cad.layers.title': '图层', 'cad.layers.count': '{count} 项', 'cad.layers.merged': '{name}(已合并 {count} 个同名图层)', @@ -822,6 +824,8 @@ const EN_US_MESSAGES: Record = { 'cad.toolbar.fit': 'Fit', 'cad.toolbar.zoomOut': 'Zoom out', 'cad.toolbar.zoomIn': 'Zoom in', + 'cad.toolbar.colorSource': 'Source colors', + 'cad.toolbar.monochrome': 'Monochrome', 'cad.layers.title': 'Layers', 'cad.layers.count': '{count} items', 'cad.layers.merged': '{name} ({count} merged layers)', diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3e294c561..c35f6f5e3 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1105,6 +1105,7 @@ export type { FileViewerArchiveOptions, FileViewerApplyViewStateOptions, FileViewerBeforeOperation, + FileViewerCadColorMode, FileViewerCadDwfLineWeightMode, FileViewerCadOptions, FileViewerCadRenderer, diff --git a/packages/renderers/cad/README.en.md b/packages/renderers/cad/README.en.md index 7a89141a8..727c6bed5 100644 --- a/packages/renderers/cad/README.en.md +++ b/packages/renderers/cad/README.en.md @@ -49,3 +49,17 @@ For private deployments, override them with `options.cad.wasmPath`, `options.cad ## Migration Note CAD preview has moved completely out of `@file-viewer/core`. Core now only keeps the asset manifest, shared types, and a compatibility error message, and it no longer installs `@flyfish-dev/cad-viewer` by default. Install this package and pass it through `renderers`, or use `@file-viewer/preset-all` for the complete CAD experience. + +## Monochrome plot mode + + Set `cad.colorMode` to `source` or `monochrome`. Monochrome rendering uses the CAD engine's entity-color policy rather than a CSS filter, keeping Canvas, WebGL, text overlays and native DWF output consistent while preserving alpha, line types, line weights and source data. + + ```ts + { + cad: { + colorMode: 'monochrome', + monochromeColor: '#000000', + showColorModeToggle: true, + }, + } + ``` diff --git a/packages/renderers/cad/README.md b/packages/renderers/cad/README.md index f60b6d100..b90cd3a72 100644 --- a/packages/renderers/cad/README.md +++ b/packages/renderers/cad/README.md @@ -49,3 +49,17 @@ const options = { ## 迁移说明 CAD 预览已经从 `@file-viewer/core` 中彻底移出,core 只保留资产 manifest、类型和兼容错误提示,不再默认安装 `@flyfish-dev/cad-viewer`。完整 CAD 能力请安装本包并传入 `renderers`,或直接使用 `@file-viewer/preset-all`。 + +## 黑白出图模式 + + `cad.colorMode` 可设为 `source` 或 `monochrome`。黑白模式通过 CAD 引擎的实体颜色策略实现,不使用 CSS 滤镜,因此 Canvas、WebGL、文字覆盖层及原生 DWF 渲染可保持一致,同时保留透明度、线型、线宽和源文件数据。 + + ```ts + { + cad: { + colorMode: 'monochrome', + monochromeColor: '#000000', + showColorModeToggle: true, + }, + } + ``` diff --git a/packages/renderers/cad/src/cad.ts b/packages/renderers/cad/src/cad.ts index 072e21c69..0b97b4e4c 100644 --- a/packages/renderers/cad/src/cad.ts +++ b/packages/renderers/cad/src/cad.ts @@ -31,6 +31,7 @@ import { unregisterFileViewerZoomProvider, type FileViewerApplyViewStateOptions, type FileRenderContext, + type FileViewerCadColorMode, type FileViewerCadOptions, type FileViewerFitRequest, type FileViewerFitResult, @@ -40,6 +41,12 @@ import { type FileViewerViewStateChangeSource, type FileViewerZoomState, } from '@file-viewer/core'; +import { + applyCadViewerColorMode, + normalizeFileViewerCadColorMode, + resolveFileViewerCadMonochromeColor, + supportsCadViewerColorMode, +} from './colorMode'; type CadStatus = 'loading' | 'ready' | 'error'; @@ -63,6 +70,9 @@ const cadStyle = ` .cad-tools,.cad-meta{display:flex;align-items:center;gap:8px} .cad-tools button{min-width:34px;min-height:30px;border:0;border-radius:8px;background:rgba(15,23,42,.06);color:#25344c;cursor:pointer;font-weight:800;letter-spacing:0;transition:background-color .18s ease,color .18s ease} .cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62} +.cad-tools button.cad-color-mode{min-width:52px;padding:0 10px;font-size:12px} +.cad-tools button.cad-color-mode[aria-pressed='true']{background:#0f172a;color:#fff} +.cad-tools button.cad-color-mode:disabled{cursor:not-allowed;opacity:.46} .cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0} .cad-meta span{border-radius:999px;padding:5px 9px;background:rgba(15,23,42,.06)} .cad-body{display:grid;min-height:0;flex:1;grid-template-columns:minmax(176px,236px) minmax(0,1fr) minmax(142px,176px);background:#eef2f7} @@ -791,6 +801,8 @@ export default async function renderCad( const options: FileViewerCadOptions = context?.options?.cad || {}; const t = createFileViewerTranslator(context?.options); const locale = resolveFileViewerLocale(context?.options); + const monochromeColor = resolveFileViewerCadMonochromeColor(options.monochromeColor); + let colorMode = normalizeFileViewerCadColorMode(options.colorMode); let status: CadStatus = 'loading'; let progressMessage = t('cad.state.loadingViewer'); let errorMessage = ''; @@ -817,16 +829,18 @@ export default async function renderCad( const zoomOutButton = createElement('button', undefined, '-') as HTMLButtonElement; const zoomText = createElement('span', 'cad-zoom', '100%'); const zoomInButton = createElement('button', undefined, '+') as HTMLButtonElement; + const colorModeButton = createElement('button', 'cad-color-mode') as HTMLButtonElement; + colorModeButton.hidden = options.showColorModeToggle === false; const meta = createElement('div', 'cad-meta'); const typeMeta = createElement('span', undefined, normalizedType.toUpperCase()); const backendMeta = createElement('span', undefined, 'AUTO'); - [fitButton, zoomOutButton, zoomInButton].forEach(button => { + [fitButton, zoomOutButton, zoomInButton, colorModeButton].forEach(button => { button.type = 'button'; }); fitButton.title = t('cad.toolbar.fit'); zoomOutButton.title = t('cad.toolbar.zoomOut'); zoomInButton.title = t('cad.toolbar.zoomIn'); - tools.append(fitButton, zoomOutButton, zoomText, zoomInButton); + tools.append(fitButton, zoomOutButton, zoomText, zoomInButton, colorModeButton); meta.append(typeMeta, backendMeta); toolbar.append(tools, meta); @@ -905,6 +919,8 @@ export default async function renderCad( status, view: viewState ? { ...viewState } : null, backend: renderStats?.backend, + colorMode, + monochromeColor: colorMode === 'monochrome' ? monochromeColor : undefined, layerCount: layers.length, visibleLayers: layers .filter(layer => layer.isVisible !== false && !layer.isFrozen) @@ -1051,7 +1067,9 @@ export default async function renderCad( : layer.name; button.setAttribute('aria-pressed', String(layerVisible)); const color = createElement('span', 'cad-layer-color'); - if (typeof layer.color === 'string') { + if (colorMode === 'monochrome') { + color.style.background = monochromeColor; + } else if (typeof layer.color === 'string') { color.style.background = layer.color; } button.append(color, createElement('span', undefined, layer.name)); @@ -1085,6 +1103,15 @@ export default async function renderCad( const syncState = () => { zoomText.textContent = `${getZoomPercent()}%`; backendMeta.textContent = (renderStats?.backend || 'auto').toUpperCase(); + const colorModeSupported = supportsCadViewerColorMode(viewer); + colorModeButton.disabled = status !== 'ready' || !colorModeSupported; + colorModeButton.setAttribute('aria-pressed', String(colorMode === 'monochrome')); + colorModeButton.textContent = t(colorMode === 'monochrome' + ? 'cad.toolbar.monochrome' + : 'cad.toolbar.colorSource'); + colorModeButton.title = t(colorMode === 'monochrome' + ? 'cad.toolbar.colorSource' + : 'cad.toolbar.monochrome'); state.hidden = status === 'ready'; state.classList.toggle('error', status === 'error'); if (status === 'loading') { @@ -1240,6 +1267,17 @@ export default async function renderCad( fitButton.addEventListener('click', () => fitToView()); zoomInButton.addEventListener('click', zoomIn); zoomOutButton.addEventListener('click', zoomOut); + colorModeButton.addEventListener('click', () => { + const previousMode = colorMode; + colorMode = colorMode === 'monochrome' ? 'source' : 'monochrome'; + if (!applyCadViewerColorMode(viewer, colorMode, monochromeColor)) { + colorMode = previousMode; + syncState(); + return; + } + syncUi(); + emitCadViewStateChange('cad-view-change', 'user'); + }); const createViewer = () => { const { wasmPath, workerUrl, dwfWasmUrl } = resolveFileViewerCadAssetUrls( @@ -1284,6 +1322,7 @@ export default async function renderCad( dwfMaxOverviewStrokeCssPx: options.dwfMaxOverviewStrokeCssPx, dwfMinTextCssPx: options.dwfMinTextCssPx, dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx, + ...({ colorMode, monochromeColor } as Record), autoFit: true, canvasOptions, onLoadProgress: updateProgress, From 29401330f719511f8bdcb35b652c15ac6401e0f4 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:50:47 +0800 Subject: [PATCH 04/18] test: verify File Viewer CAD color mode integration --- .../cad/scripts/verify-color-mode.mjs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/renderers/cad/scripts/verify-color-mode.mjs diff --git a/packages/renderers/cad/scripts/verify-color-mode.mjs b/packages/renderers/cad/scripts/verify-color-mode.mjs new file mode 100644 index 000000000..0d4a76dda --- /dev/null +++ b/packages/renderers/cad/scripts/verify-color-mode.mjs @@ -0,0 +1,28 @@ +import assert from 'node:assert/strict'; + +import { + applyCadViewerColorMode, + normalizeFileViewerCadColorMode, + resolveFileViewerCadMonochromeColor, + supportsCadViewerColorMode, +} from '../dist/colorMode.js'; + +assert.equal(normalizeFileViewerCadColorMode('monochrome'), 'monochrome'); +assert.equal(normalizeFileViewerCadColorMode('source'), 'source'); +assert.equal(normalizeFileViewerCadColorMode('unexpected'), 'source'); +assert.equal(resolveFileViewerCadMonochromeColor(' #101820 '), '#101820'); +assert.equal(resolveFileViewerCadMonochromeColor(undefined), '#0f172a'); + +const calls = []; +const viewer = { + setColorMode(mode, color) { + calls.push([mode, color]); + }, +}; + +assert.equal(supportsCadViewerColorMode(viewer), true); +assert.equal(applyCadViewerColorMode(viewer, 'monochrome', '#000000'), true); +assert.deepEqual(calls, [['monochrome', '#000000']]); +assert.equal(applyCadViewerColorMode({}, 'source', '#000000'), false); + +console.log('CAD color mode integration checks passed.'); From f1a88b86b0b1b232b46054614987a81582fedc97 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:50:59 +0800 Subject: [PATCH 05/18] feat: export CAD color mode integration helpers --- packages/renderers/cad/src/index.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/renderers/cad/src/index.ts b/packages/renderers/cad/src/index.ts index c2a292797..48783ddf4 100644 --- a/packages/renderers/cad/src/index.ts +++ b/packages/renderers/cad/src/index.ts @@ -6,6 +6,14 @@ import { type RendererDefinition, } from '@file-viewer/core'; +export { + applyCadViewerColorMode, + normalizeFileViewerCadColorMode, + resolveFileViewerCadMonochromeColor, + supportsCadViewerColorMode, +} from './colorMode'; +export type { CadViewerColorModeAdapter } from './colorMode'; + const cadDefinition = DEFAULT_RENDERER_DEFINITIONS.find( definition => definition.id === 'cad' ) as RendererDefinition | undefined; From e0e11d36d4114c838214b4cd3127a523f6c6ea52 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:51:12 +0800 Subject: [PATCH 06/18] test: expose CAD color mode verification command --- packages/renderers/cad/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/renderers/cad/package.json b/packages/renderers/cad/package.json index b90e2104f..3cf8b721a 100644 --- a/packages/renderers/cad/package.json +++ b/packages/renderers/cad/package.json @@ -19,7 +19,7 @@ ], "publishConfig": { "access": "public", - "registry": "https://registry.npmjs.org/" + "registry": "https://registry.npmjs.org" }, "author": { "name": "Yu Wang", @@ -57,7 +57,8 @@ ], "scripts": { "build": "tsc -b tsconfig.json", - "type-check": "tsc -b tsconfig.json" + "type-check": "tsc -b tsconfig.json", + "verify:color-mode": "node scripts/verify-color-mode.mjs" }, "dependencies": { "@file-viewer/core": "workspace:3.0.0", From 9501e69656f45bd1fb16e759684aa7d68f08615f Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:51:29 +0800 Subject: [PATCH 07/18] ci: verify CAD monochrome integration --- .github/workflows/public-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/public-ci.yml b/.github/workflows/public-ci.yml index c1a9ec674..c3eb87ee0 100644 --- a/.github/workflows/public-ci.yml +++ b/.github/workflows/public-ci.yml @@ -51,6 +51,9 @@ jobs: - name: Build source, components and demo run: pnpm build + - name: Verify CAD color mode integration + run: pnpm --filter @file-viewer/renderer-cad verify:color-mode + - name: Verify PPTX generated styles run: pnpm exec vitest run test/pptx-generated-style-regression.spec.ts From 13c7fd896acdc83460fbe28b84f18d40172dcf8b Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:52:41 +0800 Subject: [PATCH 08/18] docs: fix monochrome example formatting --- packages/renderers/cad/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/renderers/cad/README.md b/packages/renderers/cad/README.md index b90cd3a72..d6373bdf1 100644 --- a/packages/renderers/cad/README.md +++ b/packages/renderers/cad/README.md @@ -52,14 +52,14 @@ CAD 预览已经从 `@file-viewer/core` 中彻底移出,core 只保留资产 m ## 黑白出图模式 - `cad.colorMode` 可设为 `source` 或 `monochrome`。黑白模式通过 CAD 引擎的实体颜色策略实现,不使用 CSS 滤镜,因此 Canvas、WebGL、文字覆盖层及原生 DWF 渲染可保持一致,同时保留透明度、线型、线宽和源文件数据。 - - ```ts - { - cad: { - colorMode: 'monochrome', - monochromeColor: '#000000', - showColorModeToggle: true, - }, - } - ``` +`cad.colorMode` 可设为 `source` 或 `monochrome`。黑白模式通过 CAD 引擎的实体颜色策略实现,不使用 CSS 滤镜,因此 Canvas、WebGL、文字覆盖层及原生 DWF 渲染可保持一致,同时保留透明度、线型、线宽和源文件数据。 + +```ts +{ + cad: { + colorMode: 'monochrome', + monochromeColor: '#000000', + showColorModeToggle: true, + }, +} +``` From de69884172d8a3f8e72fb84b139fcf3281905479 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:52:55 +0800 Subject: [PATCH 09/18] docs: fix English monochrome example formatting --- packages/renderers/cad/README.en.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/renderers/cad/README.en.md b/packages/renderers/cad/README.en.md index 727c6bed5..bb7c28599 100644 --- a/packages/renderers/cad/README.en.md +++ b/packages/renderers/cad/README.en.md @@ -52,14 +52,14 @@ CAD preview has moved completely out of `@file-viewer/core`. Core now only keeps ## Monochrome plot mode - Set `cad.colorMode` to `source` or `monochrome`. Monochrome rendering uses the CAD engine's entity-color policy rather than a CSS filter, keeping Canvas, WebGL, text overlays and native DWF output consistent while preserving alpha, line types, line weights and source data. - - ```ts - { - cad: { - colorMode: 'monochrome', - monochromeColor: '#000000', - showColorModeToggle: true, - }, - } - ``` +Set `cad.colorMode` to `source` or `monochrome`. Monochrome rendering uses the CAD engine's entity-color policy rather than a CSS filter, keeping Canvas, WebGL, text overlays and native DWF output consistent while preserving alpha, line types, line weights and source data. + +```ts +{ + cad: { + colorMode: 'monochrome', + monochromeColor: '#000000', + showColorModeToggle: true, + }, +} +``` From daf630424c0ed7490ed2e398207559e7b1517fc8 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:53:09 +0800 Subject: [PATCH 10/18] chore: preserve the existing npm registry URL --- packages/renderers/cad/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderers/cad/package.json b/packages/renderers/cad/package.json index 3cf8b721a..5501ffa0d 100644 --- a/packages/renderers/cad/package.json +++ b/packages/renderers/cad/package.json @@ -19,7 +19,7 @@ ], "publishConfig": { "access": "public", - "registry": "https://registry.npmjs.org" + "registry": "https://registry.npmjs.org/" }, "author": { "name": "Yu Wang", From 733f6a934abecfe3a3dc1243ba11221a6130086f Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:58:12 +0800 Subject: [PATCH 11/18] chore: apply CAD source-document integration fix --- .../apply-issue-213-source-document-fix.yml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/workflows/apply-issue-213-source-document-fix.yml diff --git a/.github/workflows/apply-issue-213-source-document-fix.yml b/.github/workflows/apply-issue-213-source-document-fix.yml new file mode 100644 index 000000000..85167f5c6 --- /dev/null +++ b/.github/workflows/apply-issue-213-source-document-fix.yml @@ -0,0 +1,65 @@ +name: Apply issue 213 source-document fix + +on: + push: + branches: [feature/issue-213-monochrome-cad] + +permissions: + contents: write + +jobs: + patch: + if: ${{ !contains(github.event.head_commit.message, '[source-document-fix-applied]') }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: feature/issue-213-monochrome-cad + - name: Apply deterministic fix + run: | + python <<'PY' + from pathlib import Path + + helper = Path('packages/renderers/cad/src/colorMode.ts') + text = helper.read_text(encoding='utf-8') + marker = 'export function resolveCadViewerSourceDocument' + if marker not in text: + insertion = ''' + + export function resolveCadViewerSourceDocument(viewer: unknown): unknown { + const candidate = viewer as { + getSourceDocument?: () => unknown; + getDocument?: () => unknown; + } | null | undefined; + return candidate?.getSourceDocument?.() ?? candidate?.getDocument?.(); + } + ''' + anchor = '\nexport function applyCadViewerColorMode(' + if text.count(anchor) != 1: + raise RuntimeError('Unable to locate color-mode helper insertion point') + helper.write_text(text.replace(anchor, insertion + anchor, 1), encoding='utf-8') + + cad = Path('packages/renderers/cad/src/cad.ts') + text = cad.read_text(encoding='utf-8') + old_import = ' resolveFileViewerCadMonochromeColor,\n supportsCadViewerColorMode,' + new_import = ' resolveFileViewerCadMonochromeColor,\n resolveCadViewerSourceDocument,\n supportsCadViewerColorMode,' + if new_import not in text: + if text.count(old_import) != 1: + raise RuntimeError('Unable to locate CAD color-mode import list') + text = text.replace(old_import, new_import, 1) + old = ' const document = viewer?.getDocument();' + new = ' const document = resolveCadViewerSourceDocument(viewer) as CadDocument | undefined;' + if new not in text: + if text.count(old) != 1: + raise RuntimeError(f'Expected one layer source-document lookup, found {text.count(old)}') + text = text.replace(old, new, 1) + cad.write_text(text, encoding='utf-8') + PY + + rm .github/workflows/apply-issue-213-source-document-fix.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git commit -m "fix: preserve parser-owned CAD source on layer toggles [source-document-fix-applied]" + git push origin HEAD:feature/issue-213-monochrome-cad From 2c714cc3dc986ae755796ad7445222481337ba52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2026 06:58:29 +0000 Subject: [PATCH 12/18] fix: preserve parser-owned CAD source on layer toggles [source-document-fix-applied] --- .../apply-issue-213-source-document-fix.yml | 65 ------------------- packages/renderers/cad/src/cad.ts | 3 +- packages/renderers/cad/src/colorMode.ts | 9 +++ 3 files changed, 11 insertions(+), 66 deletions(-) delete mode 100644 .github/workflows/apply-issue-213-source-document-fix.yml diff --git a/.github/workflows/apply-issue-213-source-document-fix.yml b/.github/workflows/apply-issue-213-source-document-fix.yml deleted file mode 100644 index 85167f5c6..000000000 --- a/.github/workflows/apply-issue-213-source-document-fix.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Apply issue 213 source-document fix - -on: - push: - branches: [feature/issue-213-monochrome-cad] - -permissions: - contents: write - -jobs: - patch: - if: ${{ !contains(github.event.head_commit.message, '[source-document-fix-applied]') }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: feature/issue-213-monochrome-cad - - name: Apply deterministic fix - run: | - python <<'PY' - from pathlib import Path - - helper = Path('packages/renderers/cad/src/colorMode.ts') - text = helper.read_text(encoding='utf-8') - marker = 'export function resolveCadViewerSourceDocument' - if marker not in text: - insertion = ''' - - export function resolveCadViewerSourceDocument(viewer: unknown): unknown { - const candidate = viewer as { - getSourceDocument?: () => unknown; - getDocument?: () => unknown; - } | null | undefined; - return candidate?.getSourceDocument?.() ?? candidate?.getDocument?.(); - } - ''' - anchor = '\nexport function applyCadViewerColorMode(' - if text.count(anchor) != 1: - raise RuntimeError('Unable to locate color-mode helper insertion point') - helper.write_text(text.replace(anchor, insertion + anchor, 1), encoding='utf-8') - - cad = Path('packages/renderers/cad/src/cad.ts') - text = cad.read_text(encoding='utf-8') - old_import = ' resolveFileViewerCadMonochromeColor,\n supportsCadViewerColorMode,' - new_import = ' resolveFileViewerCadMonochromeColor,\n resolveCadViewerSourceDocument,\n supportsCadViewerColorMode,' - if new_import not in text: - if text.count(old_import) != 1: - raise RuntimeError('Unable to locate CAD color-mode import list') - text = text.replace(old_import, new_import, 1) - old = ' const document = viewer?.getDocument();' - new = ' const document = resolveCadViewerSourceDocument(viewer) as CadDocument | undefined;' - if new not in text: - if text.count(old) != 1: - raise RuntimeError(f'Expected one layer source-document lookup, found {text.count(old)}') - text = text.replace(old, new, 1) - cad.write_text(text, encoding='utf-8') - PY - - rm .github/workflows/apply-issue-213-source-document-fix.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git commit -m "fix: preserve parser-owned CAD source on layer toggles [source-document-fix-applied]" - git push origin HEAD:feature/issue-213-monochrome-cad diff --git a/packages/renderers/cad/src/cad.ts b/packages/renderers/cad/src/cad.ts index 0b97b4e4c..bbae4fe61 100644 --- a/packages/renderers/cad/src/cad.ts +++ b/packages/renderers/cad/src/cad.ts @@ -45,6 +45,7 @@ import { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveFileViewerCadMonochromeColor, + resolveCadViewerSourceDocument, supportsCadViewerColorMode, } from './colorMode'; @@ -1074,7 +1075,7 @@ export default async function renderCad( } button.append(color, createElement('span', undefined, layer.name)); button.addEventListener('click', () => { - const document = viewer?.getDocument(); + const document = resolveCadViewerSourceDocument(viewer) as CadDocument | undefined; if (!document) { return; } diff --git a/packages/renderers/cad/src/colorMode.ts b/packages/renderers/cad/src/colorMode.ts index 521c93f7d..1fb9bc70a 100644 --- a/packages/renderers/cad/src/colorMode.ts +++ b/packages/renderers/cad/src/colorMode.ts @@ -19,6 +19,15 @@ export function supportsCadViewerColorMode(value: unknown): value is CadViewerCo return Boolean(value && typeof (value as CadViewerColorModeAdapter).setColorMode === 'function'); } + +export function resolveCadViewerSourceDocument(viewer: unknown): unknown { + const candidate = viewer as { + getSourceDocument?: () => unknown; + getDocument?: () => unknown; + } | null | undefined; + return candidate?.getSourceDocument?.() ?? candidate?.getDocument?.(); +} + export function applyCadViewerColorMode( viewer: unknown, mode: FileViewerCadColorMode, From 0ced292a44ea6ca9e8079751df8dd3664b2b3ea3 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:59:43 +0800 Subject: [PATCH 13/18] test: preserve parser-owned CAD document during layer updates --- packages/renderers/cad/scripts/verify-color-mode.mjs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/renderers/cad/scripts/verify-color-mode.mjs b/packages/renderers/cad/scripts/verify-color-mode.mjs index 0d4a76dda..c8b00be66 100644 --- a/packages/renderers/cad/scripts/verify-color-mode.mjs +++ b/packages/renderers/cad/scripts/verify-color-mode.mjs @@ -3,6 +3,7 @@ import assert from 'node:assert/strict'; import { applyCadViewerColorMode, normalizeFileViewerCadColorMode, + resolveCadViewerSourceDocument, resolveFileViewerCadMonochromeColor, supportsCadViewerColorMode, } from '../dist/colorMode.js'; @@ -25,4 +26,15 @@ assert.equal(applyCadViewerColorMode(viewer, 'monochrome', '#000000'), true); assert.deepEqual(calls, [['monochrome', '#000000']]); assert.equal(applyCadViewerColorMode({}, 'source', '#000000'), false); +const parserDocument = { metadata: { parserOwned: true } }; +const renderDocument = { metadata: { renderOnly: true } }; +assert.equal(resolveCadViewerSourceDocument({ + getSourceDocument: () => parserDocument, + getDocument: () => renderDocument, +}), parserDocument); +assert.equal(resolveCadViewerSourceDocument({ + getDocument: () => renderDocument, +}), renderDocument); +assert.equal(resolveCadViewerSourceDocument(undefined), undefined); + console.log('CAD color mode integration checks passed.'); From aebb49ce11509cef7d0e59944402e7415ed93ffe Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:00:02 +0800 Subject: [PATCH 14/18] feat: export parser-owned CAD document resolver --- packages/renderers/cad/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/renderers/cad/src/index.ts b/packages/renderers/cad/src/index.ts index 48783ddf4..1b03e5f86 100644 --- a/packages/renderers/cad/src/index.ts +++ b/packages/renderers/cad/src/index.ts @@ -9,6 +9,7 @@ import { export { applyCadViewerColorMode, normalizeFileViewerCadColorMode, + resolveCadViewerSourceDocument, resolveFileViewerCadMonochromeColor, supportsCadViewerColorMode, } from './colorMode'; From 485d9ac6cc3462c562a851345cb246330470f938 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:02:32 +0800 Subject: [PATCH 15/18] fix: default File Viewer monochrome output to black --- packages/renderers/cad/src/colorMode.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/renderers/cad/src/colorMode.ts b/packages/renderers/cad/src/colorMode.ts index 1fb9bc70a..7511ecd56 100644 --- a/packages/renderers/cad/src/colorMode.ts +++ b/packages/renderers/cad/src/colorMode.ts @@ -10,7 +10,7 @@ export function normalizeFileViewerCadColorMode(value: unknown): FileViewerCadCo return value === 'monochrome' ? 'monochrome' : 'source'; } -export function resolveFileViewerCadMonochromeColor(value: unknown, fallback = '#0f172a'): string { +export function resolveFileViewerCadMonochromeColor(value: unknown, fallback = '#000000'): string { if (typeof value === 'string' && value.trim()) return value.trim(); return fallback; } @@ -19,7 +19,6 @@ export function supportsCadViewerColorMode(value: unknown): value is CadViewerCo return Boolean(value && typeof (value as CadViewerColorModeAdapter).setColorMode === 'function'); } - export function resolveCadViewerSourceDocument(viewer: unknown): unknown { const candidate = viewer as { getSourceDocument?: () => unknown; From 0192fa7ab20f3525db64f2e1eecd30b035dca0e4 Mon Sep 17 00:00:00 2001 From: Brownie Woom <161313394+brownie-cake@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:02:43 +0800 Subject: [PATCH 16/18] test: assert black monochrome default --- packages/renderers/cad/scripts/verify-color-mode.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderers/cad/scripts/verify-color-mode.mjs b/packages/renderers/cad/scripts/verify-color-mode.mjs index c8b00be66..9aaccd772 100644 --- a/packages/renderers/cad/scripts/verify-color-mode.mjs +++ b/packages/renderers/cad/scripts/verify-color-mode.mjs @@ -12,7 +12,7 @@ assert.equal(normalizeFileViewerCadColorMode('monochrome'), 'monochrome'); assert.equal(normalizeFileViewerCadColorMode('source'), 'source'); assert.equal(normalizeFileViewerCadColorMode('unexpected'), 'source'); assert.equal(resolveFileViewerCadMonochromeColor(' #101820 '), '#101820'); -assert.equal(resolveFileViewerCadMonochromeColor(undefined), '#0f172a'); +assert.equal(resolveFileViewerCadMonochromeColor(undefined), '#000000'); const calls = []; const viewer = { From c9df96da4944a6cae049dda3bdbb60938349fd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=88=AC=E7=9A=84=E8=80=81=E7=B2=89=E4=B8=9D?= <727842003@qq.com> Date: Sat, 5 Sep 2026 17:56:53 +0800 Subject: [PATCH 17/18] fix(security): clear audited dependency advisories --- apps/viewer-demo/package.json | 2 +- .../renderers/dicom/THIRD_PARTY_LICENSES.json | 4 +- .../renderers/dicom/THIRD_PARTY_NOTICES.md | 4 +- pnpm-lock.yaml | 40 ++++++++++--------- pnpm-workspace.yaml | 6 +++ 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/apps/viewer-demo/package.json b/apps/viewer-demo/package.json index 182c605bb..85120b9f8 100644 --- a/apps/viewer-demo/package.json +++ b/apps/viewer-demo/package.json @@ -19,7 +19,7 @@ "@file-viewer/vue3": "workspace:3.0.1", "@lucide/vue": "^1.37.0", "diff": "^9.0.0", - "qs": "^6.15.2", + "qs": "^6.16.0", "vue": "^3.5.42" }, "devDependencies": { diff --git a/packages/renderers/dicom/THIRD_PARTY_LICENSES.json b/packages/renderers/dicom/THIRD_PARTY_LICENSES.json index b130a5229..92b4cae0a 100644 --- a/packages/renderers/dicom/THIRD_PARTY_LICENSES.json +++ b/packages/renderers/dicom/THIRD_PARTY_LICENSES.json @@ -470,7 +470,7 @@ }, { "name": "browserslist", - "version": "4.28.8", + "version": "4.28.7", "license": "MIT", "direct": false, "optional": false, @@ -752,7 +752,7 @@ }, { "name": "fflate", - "version": "0.7.3", + "version": "0.7.5", "license": "MIT", "direct": false, "optional": false, diff --git a/packages/renderers/dicom/THIRD_PARTY_NOTICES.md b/packages/renderers/dicom/THIRD_PARTY_NOTICES.md index 23f9e2a52..ed6716be2 100644 --- a/packages/renderers/dicom/THIRD_PARTY_NOTICES.md +++ b/packages/renderers/dicom/THIRD_PARTY_NOTICES.md @@ -99,7 +99,7 @@ None of the Apache-2.0 dependencies in this closure publishes a top-level `NOTIC - `autoprefixer@10.5.4` — https://github.com/postcss/autoprefixer - `balanced-match@1.0.0` — https://github.com/juliangruber/balanced-match - `brace-expansion@1.1.18` — https://github.com/juliangruber/brace-expansion -- `browserslist@4.28.8` — https://github.com/browserslist/browserslist +- `browserslist@4.28.7` — https://github.com/browserslist/browserslist - `commander@9.2.0` — https://github.com/tj/commander.js - `concat-map@0.0.1` — https://github.com/substack/node-concat-map - `core-js-pure@3.50.0` — https://github.com/zloirock/core-js @@ -108,7 +108,7 @@ None of the Apache-2.0 dependencies in this closure publishes a top-level `NOTIC - `es-errors@1.3.0` — https://github.com/ljharb/es-errors - `escalade@3.2.0` — https://github.com/lukeed/escalade - `fast-deep-equal@3.1.3` — https://github.com/epoberezkin/fast-deep-equal -- `fflate@0.7.3` — https://github.com/101arrowz/fflate +- `fflate@0.7.5` — https://github.com/101arrowz/fflate - `fraction.js@5.3.4` — https://github.com/rawify/Fraction.js - `function-bind@1.1.2` — https://github.com/Raynos/function-bind - `gl-matrix@3.4.3` — https://github.com/toji/gl-matrix diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 538ff3928..ca7d50499 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,7 @@ overrides: '@ljheee/xmind-parser>@xmldom/xmldom': 0.9.12 ansi-regex@>=4.0.0 <4.1.1: 4.1.1 '@babel/core@7.29.0': 7.29.7 + browserslist: 4.28.7 brace-expansion@1.1.14: 1.1.18 brace-expansion@2.1.1: 2.1.4 brace-expansion@5.0.6: 5.0.9 @@ -19,8 +20,11 @@ overrides: mermaid: 11.17.2 nanoid: 3.3.18 postcss: 8.5.23 + postcss-selector-parser: 7.1.3 undici@6.26.0: 6.28.0 uuid@<11.1.1: 11.1.1 + fast-uri: 3.1.6 + '@kitware/vtk.js>fflate': 0.7.5 '@file-viewer/example-vanilla-vite>@file-viewer/web': workspace:3.0.1 '@file-viewer/example-vanilla-vite>@file-viewer/preset-lite': workspace:3.0.1 '@file-viewer/example-vanilla-vite>@file-viewer/vite-plugin': workspace:3.0.1 @@ -248,8 +252,8 @@ importers: specifier: ^9.0.0 version: 9.0.0 qs: - specifier: ^6.15.2 - version: 6.15.3 + specifier: ^6.16.0 + version: 6.16.0 vue: specifier: ^3.5.42 version: 3.5.42(typescript@6.0.3) @@ -4128,8 +4132,8 @@ packages: brace-expansion@1.1.18: resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} - browserslist@4.28.8: - resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==} + browserslist@4.28.7: + resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4821,8 +4825,8 @@ packages: picomatch: optional: true - fflate@0.7.3: - resolution: {integrity: sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==} + fflate@0.7.5: + resolution: {integrity: sha512-QieYf//cis6ywHNi5qW1+PXPQ4bC+XVJAtS4AXIML8P76GroEiOxm/oQtn1f02UkJY1+KsXMJcC+R2v/Eg4G3g==} fflate@0.8.3: resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} @@ -6031,8 +6035,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.15.3: - resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} + qs@6.16.0: + resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} engines: {node: '>=0.6'} quansync@0.2.11: @@ -6593,7 +6597,7 @@ packages: resolution: {integrity: sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==} hasBin: true peerDependencies: - browserslist: '>= 4.21.0' + browserslist: 4.28.7 update-check@1.5.4: resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} @@ -7037,7 +7041,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.7 '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.8 + browserslist: 4.28.7 lru-cache: 5.1.1 semver: 6.3.1 @@ -7590,7 +7594,7 @@ snapshots: commander: 9.2.0 d3-scale: 4.0.2 fast-deep-equal: 3.1.3 - fflate: 0.7.3 + fflate: 0.7.5 gl-matrix: 3.4.3 seedrandom: 3.0.5 shelljs: 0.8.5 @@ -8781,7 +8785,7 @@ snapshots: autoprefixer@10.5.4(postcss@8.5.23): dependencies: - browserslist: 4.28.8 + browserslist: 4.28.7 caniuse-lite: 1.0.30001810 fraction.js: 5.3.4 picocolors: 1.1.1 @@ -8840,13 +8844,13 @@ snapshots: balanced-match: 1.0.0 concat-map: 0.0.1 - browserslist@4.28.8: + browserslist@4.28.7: dependencies: baseline-browser-mapping: 2.11.19 caniuse-lite: 1.0.30001810 electron-to-chromium: 1.5.413 node-releases: 2.0.53 - update-browserslist-db: 1.3.1(browserslist@4.28.8) + update-browserslist-db: 1.3.1(browserslist@4.28.7) buffer-image-size@0.6.4: dependencies: @@ -9575,7 +9579,7 @@ snapshots: optionalDependencies: picomatch: 4.0.7 - fflate@0.7.3: {} + fflate@0.7.5: {} fflate@0.8.3: {} @@ -11023,7 +11027,7 @@ snapshots: punycode@2.3.1: {} - qs@6.15.3: + qs@6.16.0: dependencies: es-define-property: 1.0.1 side-channel: 1.1.1 @@ -11731,9 +11735,9 @@ snapshots: picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 - update-browserslist-db@1.3.1(browserslist@4.28.8): + update-browserslist-db@1.3.1(browserslist@4.28.7): dependencies: - browserslist: 4.28.8 + browserslist: 4.28.7 escalade: 3.2.0 picocolors: 1.1.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 6c2f61aa7..37b2f585c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -40,6 +40,7 @@ overrides: '@ljheee/xmind-parser>@xmldom/xmldom': 0.9.12 'ansi-regex@>=4.0.0 <4.1.1': 4.1.1 '@babel/core@7.29.0': 7.29.7 + browserslist: 4.28.7 'brace-expansion@1.1.14': 1.1.18 'brace-expansion@2.1.1': 2.1.4 'brace-expansion@5.0.6': 5.0.9 @@ -49,8 +50,13 @@ overrides: mermaid: 11.17.2 nanoid: 3.3.18 postcss: 8.5.23 + 'postcss-selector-parser': 7.1.3 'undici@6.26.0': 6.28.0 'uuid@<11.1.1': 11.1.1 + 'fast-uri': 3.1.6 + # @kitware/vtk.js@36.4.1 pins the vulnerable fflate 0.7.3 release. Keep + # the same API line while consuming the patched 0.7.5 security release. + '@kitware/vtk.js>fflate': 0.7.5 '@file-viewer/example-vanilla-vite>@file-viewer/web': workspace:3.0.1 '@file-viewer/example-vanilla-vite>@file-viewer/preset-lite': workspace:3.0.1 '@file-viewer/example-vanilla-vite>@file-viewer/vite-plugin': workspace:3.0.1 From 0b7b9a7775128ecd93a289458a8234330ae077ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=88=AC=E7=9A=84=E8=80=81=E7=B2=89=E4=B8=9D?= <727842003@qq.com> Date: Sat, 5 Sep 2026 18:01:26 +0800 Subject: [PATCH 18/18] fix(security): refresh public DICOM dependency ledger --- packages/renderers/dicom/THIRD_PARTY_LICENSES.json | 2 +- packages/renderers/dicom/THIRD_PARTY_NOTICES.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/renderers/dicom/THIRD_PARTY_LICENSES.json b/packages/renderers/dicom/THIRD_PARTY_LICENSES.json index 92b4cae0a..11cdeff94 100644 --- a/packages/renderers/dicom/THIRD_PARTY_LICENSES.json +++ b/packages/renderers/dicom/THIRD_PARTY_LICENSES.json @@ -680,7 +680,7 @@ }, { "name": "dompurify", - "version": "3.4.13", + "version": "3.4.14", "license": "Apache-2.0", "declaredLicense": "(MPL-2.0 OR Apache-2.0)", "direct": false, diff --git a/packages/renderers/dicom/THIRD_PARTY_NOTICES.md b/packages/renderers/dicom/THIRD_PARTY_NOTICES.md index ed6716be2..02e80260f 100644 --- a/packages/renderers/dicom/THIRD_PARTY_NOTICES.md +++ b/packages/renderers/dicom/THIRD_PARTY_NOTICES.md @@ -42,7 +42,7 @@ None of the Apache-2.0 dependencies in this closure publishes a top-level `NOTIC - `baseline-browser-mapping@2.11.19` — https://github.com/web-platform-dx/baseline-browser-mapping - `comlink@4.4.2` — https://github.com/GoogleChromeLabs/comlink -- `dompurify@3.4.13` — https://github.com/cure53/DOMPurify +- `dompurify@3.4.14` — https://github.com/cure53/DOMPurify ### BSD-3-Clause