@jc-times/business-ui 0.2.43
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 +6 -0
- package/CHANGELOG.md +267 -0
- package/README.md +55 -0
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/bin/business-ui-gate.mjs +171 -0
- package/dist/Alert.js +47 -0
- package/dist/AsyncDirectoryPicker.js +134 -0
- package/dist/AsyncSearchPicker.js +155 -0
- package/dist/AutoComplete.js +34 -0
- package/dist/Badge.js +14 -0
- package/dist/Button.js +54 -0
- package/dist/Cascader.js +141 -0
- package/dist/Combobox.js +106 -0
- package/dist/ConfirmDialog.js +48 -0
- package/dist/DataTableHorizontalScrollbar.js +38 -0
- package/dist/DataTableIcons.js +37 -0
- package/dist/DataTableMergedRows.js +45 -0
- package/dist/DataTableTheme.js +135 -0
- package/dist/DateInput.js +223 -0
- package/dist/DropdownMenu.js +130 -0
- package/dist/EmptyState.js +27 -0
- package/dist/ExplainableButton.js +68 -0
- package/dist/FileDropzone.js +70 -0
- package/dist/FilePreparationDialog.js +33 -0
- package/dist/FloatingControls.js +120 -0
- package/dist/FormField.js +143 -0
- package/dist/MetricCard.js +38 -0
- package/dist/ModalShell.js +139 -0
- package/dist/MultiSelect.js +137 -0
- package/dist/NumericInput.js +97 -0
- package/dist/OverlayContainer.js +9 -0
- package/dist/PageHeader.js +36 -0
- package/dist/Pagination.js +115 -0
- package/dist/PreparedFileDropzone.js +30 -0
- package/dist/RecoverableAsyncState.js +35 -0
- package/dist/RovingTabs.js +54 -0
- package/dist/SectionCard.js +35 -0
- package/dist/SegmentedControl.js +46 -0
- package/dist/Select.js +73 -0
- package/dist/Skeleton.js +25 -0
- package/dist/SortableList.js +55 -0
- package/dist/StructuredAddressInput.js +157 -0
- package/dist/Toast.js +100 -0
- package/dist/ToggleSwitch.js +34 -0
- package/dist/TreeSelect.js +444 -0
- package/dist/amount-format.js +20 -0
- package/dist/business-ui.js +44 -0
- package/dist/chinese-address-regions.js +15 -0
- package/dist/classNames.js +6 -0
- package/dist/data-table.js +257 -0
- package/dist/document-render-budget.js +22 -0
- package/dist/document-viewer/ContinuousPdfViewer.js +145 -0
- package/dist/document-viewer/DocumentViewer.js +123 -0
- package/dist/document-viewer/DocumentViewerViewport.js +36 -0
- package/dist/document-viewer/ImagePage.js +39 -0
- package/dist/document-viewer/PdfCanvasPage.js +26 -0
- package/dist/document-viewer/PdfThumbnailRail.js +116 -0
- package/dist/document-viewer/PdfToolbar.js +61 -0
- package/dist/document-viewer/PdfWorkspace.js +42 -0
- package/dist/document-viewer/pdf-render-budget.js +7 -0
- package/dist/document-viewer/usePdfCanvas.js +69 -0
- package/dist/document-viewer/usePdfViewport.js +48 -0
- package/dist/document-viewer-v2/DocumentViewerV2.js +171 -0
- package/dist/document-viewer-v2/HeadlessPdfViewer.js +420 -0
- package/dist/document-viewer-v2/HeadlessSearch.js +66 -0
- package/dist/document-viewer-v2.js +13 -0
- package/dist/document-viewer.js +12 -0
- package/dist/pdfium-viewer.js +18 -0
- package/dist/styles.css +2 -0
- package/dist/types/Alert.d.ts +11 -0
- package/dist/types/AmountFormat.d.ts +15 -0
- package/dist/types/AsyncDirectoryPicker.d.ts +32 -0
- package/dist/types/AsyncSearchPicker.d.ts +26 -0
- package/dist/types/AutoComplete.d.ts +9 -0
- package/dist/types/Badge.d.ts +13 -0
- package/dist/types/Button.d.ts +36 -0
- package/dist/types/Cascader.d.ts +57 -0
- package/dist/types/ChineseAddressRegions.d.ts +4 -0
- package/dist/types/Combobox.d.ts +37 -0
- package/dist/types/ConfirmDialog.d.ts +20 -0
- package/dist/types/DataTable.d.ts +68 -0
- package/dist/types/DataTableHorizontalScrollbar.d.ts +8 -0
- package/dist/types/DataTableIcons.d.ts +19 -0
- package/dist/types/DataTableMergedRows.d.ts +11 -0
- package/dist/types/DataTableTheme.d.ts +4 -0
- package/dist/types/DateInput.d.ts +25 -0
- package/dist/types/DocumentRenderBudget.d.ts +9 -0
- package/dist/types/DocumentViewer.d.ts +11 -0
- package/dist/types/DocumentViewerV2.d.ts +10 -0
- package/dist/types/DropdownMenu.d.ts +73 -0
- package/dist/types/EmptyState.d.ts +9 -0
- package/dist/types/ExplainableButton.d.ts +7 -0
- package/dist/types/FileDropzone.d.ts +20 -0
- package/dist/types/FilePreparationDialog.d.ts +12 -0
- package/dist/types/FloatingControls.d.ts +39 -0
- package/dist/types/FormField.d.ts +35 -0
- package/dist/types/MetricCard.d.ts +17 -0
- package/dist/types/ModalShell.d.ts +33 -0
- package/dist/types/MultiSelect.d.ts +12 -0
- package/dist/types/NumericInput.d.ts +54 -0
- package/dist/types/OverlayContainer.d.ts +2 -0
- package/dist/types/PageHeader.d.ts +23 -0
- package/dist/types/Pagination.d.ts +14 -0
- package/dist/types/PdfiumViewer.d.ts +5 -0
- package/dist/types/PreparedFileDropzone.d.ts +7 -0
- package/dist/types/RecoverableAsyncState.d.ts +11 -0
- package/dist/types/RovingTabs.d.ts +21 -0
- package/dist/types/SectionCard.d.ts +18 -0
- package/dist/types/SegmentedControl.d.ts +26 -0
- package/dist/types/Select.d.ts +31 -0
- package/dist/types/Skeleton.d.ts +11 -0
- package/dist/types/SortableList.d.ts +17 -0
- package/dist/types/StructuredAddressInput.d.ts +57 -0
- package/dist/types/Toast.d.ts +22 -0
- package/dist/types/ToggleSwitch.d.ts +15 -0
- package/dist/types/TreeSelect.d.ts +58 -0
- package/dist/types/classNames.d.ts +1 -0
- package/dist/types/document-viewer/ContinuousPdfViewer.d.ts +16 -0
- package/dist/types/document-viewer/DocumentViewer.d.ts +31 -0
- package/dist/types/document-viewer/DocumentViewerViewport.d.ts +23 -0
- package/dist/types/document-viewer/ImagePage.d.ts +9 -0
- package/dist/types/document-viewer/PdfCanvasPage.d.ts +7 -0
- package/dist/types/document-viewer/PdfThumbnailRail.d.ts +12 -0
- package/dist/types/document-viewer/PdfToolbar.d.ts +13 -0
- package/dist/types/document-viewer/PdfWorkspace.d.ts +5 -0
- package/dist/types/document-viewer/pdf-render-budget.d.ts +2 -0
- package/dist/types/document-viewer/usePdfCanvas.d.ts +22 -0
- package/dist/types/document-viewer/usePdfViewport.d.ts +14 -0
- package/dist/types/document-viewer-v2/DocumentViewerV2.d.ts +50 -0
- package/dist/types/document-viewer-v2/HeadlessPdfViewer.d.ts +39 -0
- package/dist/types/document-viewer-v2/HeadlessSearch.d.ts +9 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/useDebouncedValue.d.ts +2 -0
- package/dist/types/useFilePreparation.d.ts +28 -0
- package/dist/types/useModalFocusTrap.d.ts +3 -0
- package/dist/useDebouncedValue.js +16 -0
- package/dist/useFilePreparation.js +51 -0
- package/dist/useModalFocusTrap.js +71 -0
- package/docs/agent-guide.md +145 -0
- package/docs/api.md +220 -0
- package/docs/cascader.md +56 -0
- package/docs/component-strategy.md +94 -0
- package/docs/data-table.md +123 -0
- package/docs/dependencies.md +57 -0
- package/docs/document-viewer-v2.md +259 -0
- package/docs/document-viewer.md +28 -0
- package/docs/file-preparation.md +11 -0
- package/docs/maturity-migration.md +62 -0
- package/docs/modal-shell-migration.md +43 -0
- package/docs/mrt-poc.md +205 -0
- package/docs/release.md +32 -0
- package/docs/viewport-qa.md +99 -0
- package/licenses/rc-cascader-MIT.txt +21 -0
- package/package.json +163 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# 公共组件维护入口
|
|
2
|
+
|
|
3
|
+
- 开始组件使用、选型或修改前,先读 [Agent 使用指南](docs/agent-guide.md),再按需读取 API 和专题文档。
|
|
4
|
+
- 公共参数以当前源码和导出为准;消费项目以其安装版本的类型声明为准,不把本地新增能力当成已发布能力。
|
|
5
|
+
- 新增或改变公共能力时,同步指南的场景选型、对应 API/专题和 package.json 发布文件清单。README 保持入口与导航,详细用法集中维护。
|
|
6
|
+
- 通用交互、无障碍与响应式在本库实现;业务权限、接口、领域状态与文案由消费方组合。验证和发布遵循 docs/viewport-qa.md 与 docs/release.md。
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# 0.2.43
|
|
2
|
+
|
|
3
|
+
- 新增语义化 `LinkButton`,以真实链接承载导航和文件下载,并复用 Button 的变体、尺寸、图标无障碍和禁用样式。
|
|
4
|
+
- 收紧 `LinkButton` 的必填 `href` 契约;禁用链接保留可访问语义并隔离父级点击,补充下载属性、可访问名称和真实浏览器下载回归。
|
|
5
|
+
|
|
6
|
+
# 0.2.42
|
|
7
|
+
|
|
8
|
+
- DataTable 新增可选底部吸附横向滚动条,在内容溢出时显示并与 MRT 原生滚动区双向同步;支持业务化无障碍名称,默认不改变既有表格布局。
|
|
9
|
+
|
|
10
|
+
# 0.2.41
|
|
11
|
+
|
|
12
|
+
- 修复高分屏上 PDFium 左侧缩略图按设备像素尺寸显示而被裁切的问题;缩略图按插件逻辑尺寸完整缩放并保持高清渲染。
|
|
13
|
+
|
|
14
|
+
# 0.2.40
|
|
15
|
+
|
|
16
|
+
- 公共 PDF 全屏在 Escape 时退出浏览器原生全屏,由 fullscreenchange 同步状态,避免退出按钮提前消失。
|
|
17
|
+
|
|
18
|
+
# 0.2.39
|
|
19
|
+
|
|
20
|
+
- 禁用 PDFium RenderLayer 图片的浏览器原生拖放,避免正文拖选被 dragstart/pointercancel 截断。
|
|
21
|
+
|
|
22
|
+
# 0.2.38
|
|
23
|
+
|
|
24
|
+
- Headless 正文选择后 Ctrl/Cmd+C 调用官方 selection.copyToClipboard;保留 PDF CopyContents 权限检查与输入框原生复制。
|
|
25
|
+
|
|
26
|
+
# Changelog
|
|
27
|
+
|
|
28
|
+
## 0.2.37
|
|
29
|
+
|
|
30
|
+
- Headless 新增可选 initialZoom="fit-width",通过官方缩放插件适配窄屏;既有默认比例与受控 zoom 保持兼容。
|
|
31
|
+
|
|
32
|
+
## 0.2.36
|
|
33
|
+
|
|
34
|
+
- Headless 单页/连续模式搜索定位到匹配区域,缩放、旋转和视口变化后保持匹配区域可见。
|
|
35
|
+
|
|
36
|
+
## 0.2.35
|
|
37
|
+
|
|
38
|
+
- Headless 初始非零旋转等待文档打开后应用,避免恢复已保存视角时引擎抛出未加载错误。
|
|
39
|
+
## 0.2.34
|
|
40
|
+
|
|
41
|
+
- 新增 `pdfium-viewer` 专用按需加载入口,避免独立查看页面打包旧渲染器与完整外壳。
|
|
42
|
+
|
|
43
|
+
- 修复 Headless 页码切换与缩放、旋转后的滚动定位;窄屏切换时同步收起缩略图栏。
|
|
44
|
+
|
|
45
|
+
## 0.2.33
|
|
46
|
+
|
|
47
|
+
- PDFium Headless 新增可配置搜索、文本选择和双指缩放,复用官方插件;业务叠层通过 data-pdf-business-control 排除正文选择事件。
|
|
48
|
+
- 新增受控 zoom/rotation、变化回调及 showToolbar,支持消费方保留业务工具栏。
|
|
49
|
+
|
|
50
|
+
# 0.2.32
|
|
51
|
+
|
|
52
|
+
- document-viewer-v2 新增 `renderer="headless"`:URL/Buffer 使用 EmbedPDF 原生页面层,支持 React `renderPageOverlay`、受控页码、单页/连续模式、缩略图、缩放旋转和全屏;默认成品工具栏与 V1 对象兼容路径保留。
|
|
53
|
+
- document-viewer-v2 新增图片与 V1 完整调用兼容:同名 DocumentViewer、全部旧参数和底层组合导出;PDFium 仅 URL/Buffer 模式按需加载,图片与旧 PDF 对象不初始化 PDFium。原对象渲染路径仍是 PDF.js,不等同于统一引擎迁移。
|
|
54
|
+
|
|
55
|
+
- 升级直接依赖至当前最新稳定版或已验证的兼容稳定版,详见 docs/dependencies.md;开发环境使用 React 19.3,保留 React 18 兼容测试。
|
|
56
|
+
- Lucide 升级至 1.45.0,peer 范围兼容 0.x/1.x;MUI 使用 7.3.11(MRT 尚使用 MUI 9 已移除 API),MUI X 日期选择器升级至 9.13.0。
|
|
57
|
+
- PDF.js 可选 peer 升级至 6.3.289,消费方须同步升级引擎与 worker;画布渲染适配新 canvas 参数。Vite 8/Vitest 5 与 TypeScript 6 构建链升级,保留按需打包门禁。
|
|
58
|
+
|
|
59
|
+
# 0.2.31
|
|
60
|
+
|
|
61
|
+
- DataTable 使用 MRT 渲染内核并保留原参数兼容;新增完整配置 options、useDataTable/DataTableView、DataTableTheme、通用 DataTableMergedRows 以及 data-table 独立入口。MRT/MUI及配套库转为正式依赖。
|
|
62
|
+
- 构建保留组件模块边界,修复主入口带入未使用日期组件的问题;新增 Button/TextInput 不包含日期与表格实现的消费构建门禁。项目管理实际入口复验 JS 从178.51降至83.31 KiB gzip,但其80 KiB JS/14.5 KiB CSS门禁仍未全部通过,消费方预算验收仍待完成。
|
|
63
|
+
# 0.2.30
|
|
64
|
+
|
|
65
|
+
- SegmentedControl 新增 soft 浅底、block 收缩宽度、orientation 纵向、shape 胶囊和 icon/选项可访问名称;保留默认实色整行 API,补齐粗指针 44px 点击区域。
|
|
66
|
+
- 优化 SortableList 大列表渲染,将逐行线性索引改为一次性索引,避免 O(n²) 扫描。
|
|
67
|
+
- 优化 MultiSelect 大数据量与选满状态:复用选择、标签和虚拟布局引用,并用 Set 做常数时间成员查询。
|
|
68
|
+
- 新增通用 Cascader、扁平层级转换与 ID 路径索引,支持单选、多选、搜索、独立/联动选择、按需加载、表单、弹窗和窄屏底部面板;聚焦不自动展开。
|
|
69
|
+
- StructuredAddressInput 复用 Cascader,默认取消地址类型选择;海外作为顶级地区,旧模式显式启用时使用公共 Select。
|
|
70
|
+
- 新增基于 EmbedPDF/PDFium 的 `document-viewer-v2` 灰度迁移入口,支持 URL 加载模式配置和 ArrayBuffer;沿用完整响应式工具栏,并用公共令牌统一按钮、缩放组合框、选中/悬停/焦点与触屏尺寸。旧 PDF/图片复合入口作为存量兼容能力继续保留,未来仅在消费迁移和破坏性版本评估完成后考虑移除。固定版本的 PDFium 编排器仍会完整获取 URL 内容,不能将 `range-request` 配置视为已实现分段下载;完整边界见 `docs/document-viewer-v2.md`。
|
|
71
|
+
- 增加 Agent 选型指南、API/专题导航、Cascader/PDF V2 接入文档和多视口验收说明;MRT 合同台账保留为仓库内选型样例,不作为公共导出。
|
|
72
|
+
|
|
73
|
+
# 0.2.29
|
|
74
|
+
|
|
75
|
+
- 修复 SortableList 隐藏拖动手柄时卡片按内容缩宽的问题;桌面与触屏保持整行等宽。
|
|
76
|
+
|
|
77
|
+
# 0.2.27
|
|
78
|
+
|
|
79
|
+
- 新增整行分段单选 `SegmentedControl`,统一可访问的状态切换、键盘操作、禁用态和触屏尺寸。
|
|
80
|
+
|
|
81
|
+
# 0.2.26
|
|
82
|
+
|
|
83
|
+
- MultiSelect 保持空结果菜单,支持按需异步搜索的加载状态及结果展示。
|
|
84
|
+
|
|
85
|
+
# 0.2.25
|
|
86
|
+
|
|
87
|
+
- 新增基于 React Aria 的受控可访问排序列表,统一卡片的鼠标、触屏和键盘拖动排序交互。
|
|
88
|
+
|
|
89
|
+
# 0.2.24
|
|
90
|
+
|
|
91
|
+
- 新增公共上传前处理组件、取消与错误弹窗及复用 hook;支持异步解密适配、整批成功后提交、资源切换取消和处理后类型/大小复检。
|
|
92
|
+
|
|
93
|
+
# 0.2.23
|
|
94
|
+
|
|
95
|
+
- 修复旋转/缩放定位计时器覆盖用户随后跳页的问题;定位仅在原页面仍被选中时执行。补充桌面/手机连续操作回归。
|
|
96
|
+
|
|
97
|
+
# Changelog
|
|
98
|
+
|
|
99
|
+
## 0.2.21 - 2026-09-07
|
|
100
|
+
|
|
101
|
+
- Add `moneyFormat` to numeric inputs: symbol/unit/number resting displays with numeric-only drafts and commits.
|
|
102
|
+
- Export exact decimal and integer money formatting through the React-free `@jc-times/business-ui/amount-format` entry for documents and servers.
|
|
103
|
+
|
|
104
|
+
## 0.2.20 - 2026-09-06
|
|
105
|
+
|
|
106
|
+
- Adopt Radix Dialog/Toast and React Aria Calendar; share modal portal ownership and arbitrate Escape across Radix/React Aria overlays.
|
|
107
|
+
- Fix date readOnly, tree IME confirmation/native form ID submission, persistent toast eviction, and replacement toast expiry.
|
|
108
|
+
- Add date constraints/month jump/validation, search MultiSelect and independent TreeSelect multi-selection, directory TTL/refresh/reset semantics, server table sorting/selection summaries/column visibility, and detailed file size/count/type rejection.
|
|
109
|
+
- Mark CSS as a package side effect; add Chromium desktop/mobile integration tests and React 18/19 CI coverage.
|
|
110
|
+
- Migration: TreeSelect submits IDs by default (formValueMode="label" retains label submission); excess toasts queue instead of evicting existing messages. See docs/maturity-migration.md.
|
|
111
|
+
|
|
112
|
+
## 0.2.19
|
|
113
|
+
|
|
114
|
+
- Isolate async option and tree row rendering so highlight changes skip unchanged row content; preserve tree expansion and keyboard semantics.
|
|
115
|
+
- Keep TextInput callback refs stable across value updates and reuse address path/search indexes across queries.
|
|
116
|
+
- Bound AsyncDirectoryPicker queries with an LRU cache (default 50, configurable via cacheSize; zero disables caching).
|
|
117
|
+
- Add performance regression coverage for option render counts, ref lifetimes, address index invalidation and cache eviction.
|
|
118
|
+
|
|
119
|
+
## 0.2.18
|
|
120
|
+
|
|
121
|
+
- Keep the internal file input out of keyboard and accessibility navigation so each `FileDropzone` exposes one control.
|
|
122
|
+
|
|
123
|
+
## 0.2.17
|
|
124
|
+
|
|
125
|
+
- Publish maintained Chinese address regions through an independent subpath so applications can load the dataset only on address-entry routes.
|
|
126
|
+
|
|
127
|
+
## 0.2.16
|
|
128
|
+
|
|
129
|
+
- Prevent disabled `FileDropzone` surfaces from handing dropped files to the browser.
|
|
130
|
+
|
|
131
|
+
## 0.2.15
|
|
132
|
+
|
|
133
|
+
- Add `FileDropzone` as the single shared file-selection surface for click, keyboard and drag-and-drop input.
|
|
134
|
+
- Let `StructuredAddressInput` use maintained Chinese province/city/district data by default, append an `海外` top-level region, and optionally hide the legacy address-mode selector.
|
|
135
|
+
|
|
136
|
+
## 0.2.14
|
|
137
|
+
|
|
138
|
+
- Add `minimumFractionDigits` to numeric inputs for fixed currency and percentage display without padding active drafts or changing committed values. Empty values stay empty.
|
|
139
|
+
|
|
140
|
+
## 0.2.13
|
|
141
|
+
|
|
142
|
+
- Add `startAdornment` and `endAdornment` slots to `TextInput`; `NumericInput` and `ScaledNumericInput` inherit the same API.
|
|
143
|
+
- Keep the existing input-only DOM when slots are absent, and preserve the native input ref, attributes, label, help and error associations when slots are present.
|
|
144
|
+
- Keep adorned controls on the shared 40px default and 44px coarse-pointer size contract, with wrapper-level focus and invalid states.
|
|
145
|
+
|
|
146
|
+
## 0.2.12
|
|
147
|
+
|
|
148
|
+
- Keep directory inputs editable during searches; suppress focus queries for existing selections and defer IME searches until composition ends.
|
|
149
|
+
- Dismiss async results on selection, outside pointer, blur, Tab and Escape without reopening on late responses.
|
|
150
|
+
- Cancel superseded requests before cache reuse/selection and restore committed text when async selection fails.
|
|
151
|
+
|
|
152
|
+
## 0.2.11
|
|
153
|
+
|
|
154
|
+
- Hold directory searches while Backspace or Delete remains pressed, then debounce one search for the final value
|
|
155
|
+
after key release.
|
|
156
|
+
|
|
157
|
+
## 0.2.10
|
|
158
|
+
|
|
159
|
+
- Prevent `AsyncSearchPicker` from reading a stale highlighted item when an async owner clears its result list,
|
|
160
|
+
avoiding a render crash while typing a new query.
|
|
161
|
+
|
|
162
|
+
## 0.2.9
|
|
163
|
+
|
|
164
|
+
- Add `AsyncDirectoryPicker`, a generic remote directory selector with debounced search, request cancellation,
|
|
165
|
+
stale-result fencing, owner resets, selected-label synchronization, caching, and shared async states.
|
|
166
|
+
|
|
167
|
+
## 0.2.8 — 2026-09-06
|
|
168
|
+
|
|
169
|
+
- 新增 NumericInput 精确字符串数字输入与 ScaledNumericInput 安全整数缩放适配;支持自然中间态、十进制舍入、上下限、千分位、失焦/回车提交及显式全选。
|
|
170
|
+
- 复用 TextInput/FormField 的样式、ARIA、ref 与原生属性;补齐交互测试、视觉矩阵及迁移文档。
|
|
171
|
+
- 兼容既有 API;包含 0.2.6–0.2.7 尚未发布的公共能力。
|
|
172
|
+
|
|
173
|
+
## 0.2.7 - 2026-09-05
|
|
174
|
+
|
|
175
|
+
- DataTable 的 `mobileLayout="cards"` 改为按表格自身容器宽度响应;嵌入窄浮层、侧栏或分栏时无需等待整个视口缩至 600px,默认 `scroll` 模式保持不变。
|
|
176
|
+
|
|
177
|
+
## 0.2.6 - 2026-09-05
|
|
178
|
+
|
|
179
|
+
- 将 ModalShell 的 `.ui-modal-header`、`.ui-modal-content`、`.ui-modal-footer` 面板直接子节点声明为稳定兼容契约;固定底栏必须使用 `footer` / `footerClassName`,不再建议依赖 children 内原生 `<footer>` 或内部层级选择器。
|
|
180
|
+
- ModalShell 新增 `contentClassName` / `contentProps`,允许消费方对正文滚动区透传 ref、data、ARIA 和原生 div 属性,同时保留公共契约 class。
|
|
181
|
+
- 开发环境会警告“直接 footer child 且未传 footer prop”的旧式调用,但不会自动搬运节点或猜测业务结构。
|
|
182
|
+
- `business-ui-gate` 新增 `legacyModalFooter` 检测,覆盖命名别名、`Dialog`、namespace 以及条件/Fragment JSX,并提供明确迁移提示;普通业务组件 footer 不受影响。
|
|
183
|
+
- 补齐 ModalShell DOM、无 footer、自定义正文/底栏、手机全屏与短横屏的消费兼容回归。
|
|
184
|
+
- 新增业务无关的 `TreeSelect`,支持任意层级、受控/非受控状态、路径搜索、键盘树导航、无障碍语义,以及手机底部候选面板。
|
|
185
|
+
- 新增 `StructuredAddressInput`,提供可注入地区树的级联选择、整路径搜索、详细地址和非标准地址回退;区划数据、字符串解析/格式化及业务字段映射由消费方持有。
|
|
186
|
+
- TextInput、SelectInput 与 Button 的默认视觉高度改为显式统一的 border-box 40px,触屏最小操作高度继续提升至 44px,避免原生 select 在不同 WebView/系统缩放下发生同行错位。
|
|
187
|
+
|
|
188
|
+
## 0.2.5 - 2026-09-04
|
|
189
|
+
|
|
190
|
+
- 增强公共移动能力:Modal 全屏安全区与固定头尾、Select 手机底部抽屉、Dropdown/Popover 短视口滚动、AsyncSearchPicker 软键盘动态高度、320px 分页简化、DataTable 卡片长文本/选择/操作/空状态,以及 Toast/ConfirmDialog 安全区和长文案堆叠。
|
|
191
|
+
- 触屏原生 SelectInput 与其他表单控件统一使用 44px 最小点击高度;表单错误提示不再拉伸同行控件。
|
|
192
|
+
- DropdownMenu/Menu 新增类型安全的单选/多选状态,分别输出 `menuitemradio` / `menuitemcheckbox` 与 `aria-checked`;菜单项可独立声明 `aria-current`,并提供起始图标、尾部状态和选中图标槽。
|
|
193
|
+
- DropdownMenu 补齐触发器、菜单及菜单项的 ARIA/data 属性与 ref 透传,继续由 React Aria 保证方向键、Home/End、Escape、焦点归还与禁用项行为;触屏菜单项使用 44px 最小高度,短视口菜单可内部滚动。
|
|
194
|
+
- PageHeader 新增稳定的 `copyProps` / `actionsProps` 布局槽,并改善长标题与操作区在窄屏、横屏下的换行;Badge 在 flex/截断容器中保持尺寸并按文字基线对齐。
|
|
195
|
+
- DataTable 新增向后兼容的 `mobileLayout="cards"` 可选契约,以及根节点/表格属性与 ref 透传;默认仍为水平滚动,不改变 0.2.4 调用的 DOM 与布局。
|
|
196
|
+
- MetricCard、SectionCard 与既有 DataTable 调用完成真实消费审计;响应式 ActionMenu/ActionSheet 因没有第二个独立生产场景暂缓,UI 门禁保持现状。
|
|
197
|
+
|
|
198
|
+
## 0.2.4 - 2026-09-04
|
|
199
|
+
|
|
200
|
+
- 新增无业务状态映射的 Badge,提供五档语义 tone、两档 size、原生 span 属性与 ref。
|
|
201
|
+
- 新增 MetricCard,以 label、value、description、icon 和 tone 插槽承载已格式化指标,不接管业务计算或格式化。
|
|
202
|
+
- 新增页面级 PageHeader 和带可访问区域名称的 SectionCard,统一标题、说明、操作区、响应式换行与原生属性/ref。
|
|
203
|
+
- 四个展示组件均保持无状态、无 Effect、无布局测量和零新增运行时依赖,并纳入单元测试与多视口验收矩阵。
|
|
204
|
+
|
|
205
|
+
## 0.2.3 - 2026-09-04
|
|
206
|
+
|
|
207
|
+
- DataTable 单元格增加自动移动端标签,并允许通过 `mobileLabel` 覆盖复杂表头的标签文本,便于消费项目实现无业务耦合的响应式卡片表格。
|
|
208
|
+
|
|
209
|
+
## 0.2.2 - 2026-09-04
|
|
210
|
+
|
|
211
|
+
- 新增泛型 `useDebouncedValue<T>(value, delay)`,支持值/延迟变化时重置计时器和卸载清理,不接管输入或请求生命周期。
|
|
212
|
+
|
|
213
|
+
## 0.2.1 - 2026-09-04
|
|
214
|
+
|
|
215
|
+
- ModalShell 内建栈顶焦点陷阱、初始/归还焦点、背景滚动锁与可配置 Escape,关闭按钮复用 Button。
|
|
216
|
+
- Select、Combobox/AutoComplete、ToggleSwitch 和 DateInput 补齐明确的原生属性、ref 与浮层 placement/portal API。
|
|
217
|
+
- DateInput 增加方向键、Home/End、PageUp/PageDown 和按年翻页的日历焦点管理。
|
|
218
|
+
- iconOnly Button 在 TypeScript 层要求 `aria-label`。
|
|
219
|
+
- 新增无业务 DTO 的 AsyncSearchPicker、具备正确 menu 语义的 DropdownMenu/Menu,以及非锚点 ConfirmDialog。
|
|
220
|
+
- UI gate 新增手写 menu、combobox/listbox/option 回归检测,并补充公共 API 文档、示例和交互测试。
|
|
221
|
+
- 缓存 DataTable 排序值并隔离行级重渲染,降低大表排序与选择操作的重复计算。
|
|
222
|
+
- 为 AutoComplete 建立选项索引,并稳定 Combobox 集合引用,改善大列表输入响应。
|
|
223
|
+
- 合并 DateInput 高频滚动/缩放定位测量,避免同一帧内重复布局计算。
|
|
224
|
+
- 将 TypeScript 调整为开发依赖,并声明运行时代码无副作用,减少消费端安装与打包负担。
|
|
225
|
+
|
|
226
|
+
## 0.2.0 - 2026-09-04
|
|
227
|
+
|
|
228
|
+
- 新增 Alert、EmptyState、Skeleton 与 SkeletonText 公共反馈组件。
|
|
229
|
+
- 新增 Tooltip、Popover、Popconfirm、Select、Combobox、AutoComplete、ToastProvider/useToast 与 DataTable。
|
|
230
|
+
- 浮层和 Select 采用固定版本 Radix Primitives;Combobox/AutoComplete 采用 React Aria,并支持大列表虚拟化。
|
|
231
|
+
- 建立三档动效时长与缓动令牌,统一按钮忙碌、弹窗、日期浮层和禁用原因提示的状态反馈。
|
|
232
|
+
- 所有新增动画支持 `prefers-reduced-motion`,并补充手机与桌面响应式验收场景。
|
|
233
|
+
- 增加标签与包版本严格匹配、凭据临时注入的内部 registry 发布脚本。
|
|
234
|
+
- 增加 CI 验证、标签发布流水线和发布治理文档。
|
|
235
|
+
- 增加组件多视口验收页面,并完成手机、平板和桌面三档检查。
|
|
236
|
+
|
|
237
|
+
## 0.1.2 - 2026-09-04
|
|
238
|
+
|
|
239
|
+
- UI 门禁增加 `--only`,允许已有按钮/控件门禁的项目只启用公共弹层门禁。
|
|
240
|
+
|
|
241
|
+
## 0.1.1 - 2026-09-04
|
|
242
|
+
|
|
243
|
+
- ModalShell 统一处理栈顶 Escape 关闭;焦点管理支持指定初始焦点,并在挂载提交后立即建立焦点所有权。
|
|
244
|
+
- UI 门禁只把原生 DOM 弹层计为手写弹层,避免误报组件属性。
|
|
245
|
+
|
|
246
|
+
## 0.1.0 - 2026-09-04
|
|
247
|
+
|
|
248
|
+
- 首次发布 Button、ExplainableButton、ModalShell、FormField、DateInput、Pagination、RovingTabs、ToggleSwitch、RecoverableAsyncState 与 useModalFocusTrap。
|
|
249
|
+
- 建立中性语义令牌和跨项目 UI 门禁命令。
|
|
250
|
+
# 0.2.22
|
|
251
|
+
|
|
252
|
+
- 提供独立 document-viewer 子入口,统一 PDF/图片预览、连续翻页、缩略图、缩放、旋转与全屏;通过组合插槽保留消费方领域交互。
|
|
253
|
+
- 提取有界 PDF 画布渲染与取消队列,增加页级失败反馈和独立 document-render-budget 纯函数入口。
|
|
254
|
+
- PDF.js 4.10.38 为可选 peer;加载、worker、权限和打开密码由消费方管理。见 docs/document-viewer.md。
|
|
255
|
+
# 0.2.28
|
|
256
|
+
|
|
257
|
+
- PDF toolbar uses compact ghost icon controls, a single-row layout and touch-sized targets.
|
|
258
|
+
|
|
259
|
+
### 本地待发布:通用 Cascader
|
|
260
|
+
|
|
261
|
+
- 新增基于 @rc-component/cascader@1.25.0 的 Cascader、扁平层级转换与 ID 路径索引;默认独立多选,保留主题、表单和弹窗约定。
|
|
262
|
+
- StructuredAddressInput 复用级联内核,保留受控数据及详细地址;地区摘要以选择框文本显示,搜索 input.value 不再代表已选摘要。
|
|
263
|
+
- 增加部门/地址接入指南、MIT 许可与桌面/触屏回归。TreeSelect 保持兼容;未升级消费项目。
|
|
264
|
+
|
|
265
|
+
- Cascader 取消聚焦自动展开:标签点击和 Tab 只聚焦;保留点击、输入搜索与方向键展开。
|
|
266
|
+
|
|
267
|
+
- StructuredAddressInput 默认取消地址类型,海外使用顶级地区;旧模式显式启用时复用公共 Select,不再手写原生 select。
|
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# @jc-times/business-ui
|
|
2
|
+
|
|
3
|
+
精诚时代业务应用共用的 React 基础组件与交互标准。公共包负责通用 UI、无障碍与响应式;权限、接口、业务文案和合同、客户、订单、ERP 等领域状态由消费应用提供。
|
|
4
|
+
|
|
5
|
+
**Agent 从 [docs/agent-guide.md](docs/agent-guide.md) 开始阅读:按需求选组件,再查 API 和专题。** 本仓库 [AGENTS.md](AGENTS.md) 同样指向该入口。
|
|
6
|
+
|
|
7
|
+
## 安装与引入
|
|
8
|
+
|
|
9
|
+
内部 registry 为 GitHub Packages(`https://npm.pkg.github.com`)。按 [发布与消费说明](docs/release.md) 配置访问,选择已发布的精确版本并提交锁文件;受控 tarball 消费也必须固定版本和制品。不要复制源码、跨仓库引用源文件或使用目录软链接。
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { Button, ModalShell } from "@jc-times/business-ui";
|
|
13
|
+
import "@jc-times/business-ui/styles.css";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
React 等 peer dependencies 按所安装版本的 package.json 配置。应用通过 `--ui-*` 语义令牌提供主题;普通控件默认 40px,粗指针触屏最小 44px。
|
|
17
|
+
|
|
18
|
+
文档查看器、行政区划数据、纯金额格式化使用独立子入口;对应导入与依赖见专题文档。仓库工作树中的新入口不代表消费方已安装或该能力已发布。
|
|
19
|
+
|
|
20
|
+
## 文档导航
|
|
21
|
+
|
|
22
|
+
| 文档 | 用途 |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| [Agent 使用指南](docs/agent-guide.md) | 场景选型、组件组合、边界和接入检查 |
|
|
25
|
+
| [依赖维护](docs/dependencies.md) | 稳定版本核查、兼容例外、消费迁移要求 |
|
|
26
|
+
| [公共 API](docs/api.md) | 公共行为、参数说明、数字输入与装饰示例;完整签名见安装包类型声明 |
|
|
27
|
+
| [DataTable 与 MRT 迁移](docs/data-table.md) | 公共表格替代、旧参数兼容、完整配置、独立入口与合并明细;0.2.31起提供 |
|
|
28
|
+
| [表格能力与 MRT 样例](docs/mrt-poc.md) | DataTable边界、筛选/列管理、产品行合并/展开、配置及性能;包含业务样例与公共API边界 |
|
|
29
|
+
| [分段控制器](docs/api.md#分段控制器-segmentedcontrol) | 少量互斥选项、浅底/图标/纵向示例、兼容边界 |
|
|
30
|
+
| [组件设计策略](docs/component-strategy.md) | 设计依据、公共能力范围和交互内核策略 |
|
|
31
|
+
| [弹窗迁移](docs/modal-shell-migration.md) | header/content/footer 稳定插槽与历史写法迁移 |
|
|
32
|
+
| [成熟度迁移](docs/maturity-migration.md) | 日期、多选、目录缓存、表格、文件限制及 Toast 行为 |
|
|
33
|
+
| [上传前处理](docs/file-preparation.md) | 文件异步前处理、整批提交与取消 |
|
|
34
|
+
| [文档查看器](docs/document-viewer.md) | PDF.js 与图片查看入口 |
|
|
35
|
+
| [文档与图片查看器 V2](docs/document-viewer-v2.md) | PDFium/WASM、原生页面叠层、图片及 V1 兼容入口与迁移边界 |
|
|
36
|
+
| [多视口验收](docs/viewport-qa.md) | 桌面、移动与交互验证 |
|
|
37
|
+
| [发布流程](docs/release.md) | registry、版本、制品与发布检查 |
|
|
38
|
+
| [变更记录](CHANGELOG.md) | 按版本查看变化 |
|
|
39
|
+
|
|
40
|
+
详细用法集中于 API 和专题;新增公共能力时同步 Agent 选型表和发布文档清单。历史审计文档保留作证据,不作为当前 API 说明。
|
|
41
|
+
|
|
42
|
+
## 开发与消费边界
|
|
43
|
+
|
|
44
|
+
- 通用缺陷、无障碍、响应式及跨项目能力在公共包修复;单项目领域需求通过业务包装实现。
|
|
45
|
+
- 优先兼容既有 API;破坏性修改需要 major 版本及迁移说明。
|
|
46
|
+
- 消费方使用公开插槽和 props,固定弹窗底栏使用 footer;不要依赖内部 DOM 或重复实现焦点管理。
|
|
47
|
+
- 已配置 `business-ui-gate` 的消费项目继续运行门禁;首次接入需要生成并审核基线,不通过扩大 baseline 掩盖新增手写组件。
|
|
48
|
+
|
|
49
|
+
## 本地验证与发布
|
|
50
|
+
|
|
51
|
+
`pnpm dev:matrix` 打开组件验收页面;`pnpm verify` 执行类型、单元测试、库和矩阵构建;`pnpm test:browser` 验证真实浏览器交互。详细要求见多视口验收与发布流程。
|
|
52
|
+
|
|
53
|
+
仓库通过 `v<package.version>` 标签触发受控发布。公共包本地验证、正式发布、消费应用升级和生产部署是不同状态,应分别验证和记录。
|
|
54
|
+
|
|
55
|
+
- [通用级联选择与部门/地址适配](docs/cascader.md)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
`@jc-times/business-ui` 使用以下固定版本开源依赖。依赖源码未复制到本仓库;最终安装包由包管理器连同各自许可证一并解析。
|
|
4
|
+
|
|
5
|
+
| Package | Version | License | Project |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| `lucide-react` | 1.45.0(开发验证版本) | ISC | https://github.com/lucide-icons/lucide |
|
|
8
|
+
| `pdfjs-dist` | 6.3.289 | Apache-2.0 | https://github.com/mozilla/pdf.js |
|
|
9
|
+
| `material-react-table` | 3.2.1 | MIT | https://github.com/KevinVandy/material-react-table |
|
|
10
|
+
| `@mui/material`, `@mui/icons-material` | 7.3.11 | MIT | https://github.com/mui/material-ui |
|
|
11
|
+
| `@mui/x-date-pickers` | 9.13.0 | MIT | https://github.com/mui/mui-x |
|
|
12
|
+
| `@emotion/react`, `@emotion/styled` | 11.14.0 / 11.14.1 | MIT | https://github.com/emotion-js/emotion |
|
|
13
|
+
| `@embedpdf/react-pdf-viewer` | 2.15.0 | MIT | https://github.com/embedpdf/embed-pdf-viewer |
|
|
14
|
+
| `@embedpdf/core`, `@embedpdf/engines`, `@embedpdf/plugin-document-manager`, `@embedpdf/plugin-viewport`, `@embedpdf/plugin-scroll`, `@embedpdf/plugin-render`, `@embedpdf/plugin-zoom`, `@embedpdf/plugin-rotate`, `@embedpdf/plugin-thumbnail` | 2.15.0 | MIT | https://github.com/embedpdf/embed-pdf-viewer |
|
|
15
|
+
| PDFium(由 `@embedpdf/pdfium` 随查看器分发) | 2.15.0 | BSD-3-Clause / Apache-2.0 等,详见依赖内 `LICENSE.pdfium` | https://pdfium.googlesource.com/pdfium/ |
|
|
16
|
+
| `@radix-ui/react-popover` | 1.1.23 | MIT | https://github.com/radix-ui/primitives |
|
|
17
|
+
| `@radix-ui/react-dialog` | 1.1.23 | MIT | https://github.com/radix-ui/primitives |
|
|
18
|
+
| `@radix-ui/react-toast` | 1.2.23 | MIT | https://github.com/radix-ui/primitives |
|
|
19
|
+
| `@internationalized/date` | 3.12.4 | Apache-2.0 | https://github.com/adobe/react-spectrum |
|
|
20
|
+
| `@radix-ui/react-select` | 2.3.7 | MIT | https://github.com/radix-ui/primitives |
|
|
21
|
+
| `@radix-ui/react-tooltip` | 1.2.16 | MIT | https://github.com/radix-ui/primitives |
|
|
22
|
+
| `react-aria-components` | 1.21.1 | Apache-2.0 | https://github.com/adobe/react-spectrum |
|
|
23
|
+
| `cn-division` | 2026.0.1 | MIT | https://github.com/kk-418/cn-division |
|
|
24
|
+
|
|
25
|
+
完整许可证文本以各依赖包内的 `LICENSE` 文件为准。
|
|
26
|
+
|
|
27
|
+
## @rc-component/cascader 1.25.0
|
|
28
|
+
|
|
29
|
+
MIT, Copyright (c) 2019-present react-component. Source: https://github.com/react-component/cascader. Used as the external Cascader interaction dependency; license reproduced in licenses/rc-cascader-MIT.txt. Transitive dependencies retain their own notices in their installed packages.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import ts from "typescript";
|
|
5
|
+
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
const root = process.cwd();
|
|
8
|
+
const sourceRoot = path.resolve(root, value("--root") ?? "src");
|
|
9
|
+
const baselinePath = path.resolve(root, value("--baseline") ?? "scripts/business-ui-gate-baseline.json");
|
|
10
|
+
const only = new Set((value("--only") ?? "").split(",").filter(Boolean));
|
|
11
|
+
const snapshot = filterSnapshot(scan(sourceRoot));
|
|
12
|
+
|
|
13
|
+
if (args.includes("--snapshot")) {
|
|
14
|
+
process.stdout.write(`${JSON.stringify(snapshot, null, 2)}\n`);
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
if (!fs.existsSync(baselinePath)) {
|
|
18
|
+
process.stderr.write(`缺少门禁基线:${baselinePath}\n请先使用 --snapshot 生成并审核基线。\n`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const baseline = JSON.parse(fs.readFileSync(baselinePath, "utf8"));
|
|
23
|
+
const regressions = [];
|
|
24
|
+
for (const [file, current] of Object.entries(snapshot)) {
|
|
25
|
+
for (const [kind, count] of Object.entries(current)) {
|
|
26
|
+
const allowed = baseline[file]?.[kind] ?? 0;
|
|
27
|
+
if (count > allowed) regressions.push({ file, kind, count, allowed });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (regressions.length) {
|
|
31
|
+
process.stderr.write(`发现新增的未统一 UI 实现:\n${regressions.map(formatRegression).join("\n")}\n`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
process.stdout.write("Business UI gate passed.\n");
|
|
35
|
+
|
|
36
|
+
function value(flag) {
|
|
37
|
+
const index = args.indexOf(flag);
|
|
38
|
+
return index < 0 ? undefined : args[index + 1];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function filterSnapshot(input) {
|
|
42
|
+
if (!only.size) return input;
|
|
43
|
+
const output = {};
|
|
44
|
+
for (const [file, counts] of Object.entries(input)) {
|
|
45
|
+
const selected = Object.fromEntries(Object.entries(counts).filter(([kind]) => only.has(kind)));
|
|
46
|
+
if (Object.keys(selected).length) output[file] = selected;
|
|
47
|
+
}
|
|
48
|
+
return output;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function formatRegression({ file, kind, count, allowed }) {
|
|
52
|
+
const base = `- ${file}: ${kind} ${count}(基线 ${allowed})`;
|
|
53
|
+
if (kind !== "legacyModalFooter") return base;
|
|
54
|
+
return `${base}\n ModalShell 的固定底栏必须改用 footer 属性,并通过 footerClassName 定制;不要把原生 <footer> 直接放在 children 中。`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function scan(directory) {
|
|
58
|
+
const result = {};
|
|
59
|
+
for (const absolute of walk(directory)) {
|
|
60
|
+
if (!absolute.endsWith(".tsx") || absolute.endsWith(".test.tsx")) continue;
|
|
61
|
+
const source = fs.readFileSync(absolute, "utf8");
|
|
62
|
+
const sourceFile = ts.createSourceFile(absolute, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
63
|
+
const modalImports = collectModalImports(sourceFile);
|
|
64
|
+
const counts = {
|
|
65
|
+
bareButton: 0,
|
|
66
|
+
bareInput: 0,
|
|
67
|
+
bareSelect: 0,
|
|
68
|
+
bareTextarea: 0,
|
|
69
|
+
handwrittenDialog: 0,
|
|
70
|
+
handwrittenMenu: 0,
|
|
71
|
+
handwrittenCombobox: 0,
|
|
72
|
+
legacyModalFooter: 0,
|
|
73
|
+
};
|
|
74
|
+
visit(sourceFile);
|
|
75
|
+
const used = Object.fromEntries(Object.entries(counts).filter(([, count]) => count));
|
|
76
|
+
if (Object.keys(used).length) result[path.relative(root, absolute).replaceAll(path.sep, "/")] = used;
|
|
77
|
+
|
|
78
|
+
function visit(node) {
|
|
79
|
+
if (ts.isJsxElement(node) && isImportedModalTag(node.openingElement.tagName, modalImports)
|
|
80
|
+
&& !hasAttribute(node.openingElement, "footer") && node.children.some(rendersDirectFooter)) {
|
|
81
|
+
counts.legacyModalFooter += 1;
|
|
82
|
+
}
|
|
83
|
+
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
84
|
+
const tag = node.tagName.getText(sourceFile);
|
|
85
|
+
const hasClass = hasAttribute(node, "className");
|
|
86
|
+
if (tag === "button" && !hasClass) counts.bareButton += 1;
|
|
87
|
+
if (tag === "input" && !exemptInput(node)) counts.bareInput += 1;
|
|
88
|
+
if (tag === "select") counts.bareSelect += 1;
|
|
89
|
+
if (tag === "textarea") counts.bareTextarea += 1;
|
|
90
|
+
const role = stringAttribute(node, "role");
|
|
91
|
+
if (/^[a-z]/.test(tag) && (role === "dialog" || role === "alertdialog")) counts.handwrittenDialog += 1;
|
|
92
|
+
if (/^[a-z]/.test(tag) && (role === "menu" || role === "menuitem")) counts.handwrittenMenu += 1;
|
|
93
|
+
if (/^[a-z]/.test(tag) && (role === "combobox" || role === "listbox" || role === "option")) counts.handwrittenCombobox += 1;
|
|
94
|
+
}
|
|
95
|
+
ts.forEachChild(node, visit);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function exemptInput(node) {
|
|
99
|
+
const type = stringAttribute(node, "type");
|
|
100
|
+
return ["file", "hidden", "range"].includes(type ?? "");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function stringAttribute(node, name) {
|
|
104
|
+
const attribute = node.attributes.properties.find((item) => ts.isJsxAttribute(item) && item.name.getText(sourceFile) === name);
|
|
105
|
+
return attribute && ts.isJsxAttribute(attribute) && attribute.initializer && ts.isStringLiteral(attribute.initializer)
|
|
106
|
+
? attribute.initializer.text : undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function hasAttribute(node, name) {
|
|
110
|
+
return node.attributes.properties.some((item) => ts.isJsxAttribute(item) && item.name.getText(sourceFile) === name);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function rendersDirectFooter(node) {
|
|
114
|
+
if (ts.isJsxElement(node)) return node.openingElement.tagName.getText(sourceFile) === "footer";
|
|
115
|
+
if (ts.isJsxSelfClosingElement(node)) return node.tagName.getText(sourceFile) === "footer";
|
|
116
|
+
if (ts.isJsxFragment(node)) return node.children.some(rendersDirectFooter);
|
|
117
|
+
if (ts.isJsxExpression(node) && node.expression) return expressionRendersFooter(node.expression);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function expressionRendersFooter(expression) {
|
|
122
|
+
if (ts.isParenthesizedExpression(expression)) return expressionRendersFooter(expression.expression);
|
|
123
|
+
if (ts.isJsxElement(expression) || ts.isJsxSelfClosingElement(expression) || ts.isJsxFragment(expression)) {
|
|
124
|
+
return rendersDirectFooter(expression);
|
|
125
|
+
}
|
|
126
|
+
if (ts.isConditionalExpression(expression)) {
|
|
127
|
+
return expressionRendersFooter(expression.whenTrue) || expressionRendersFooter(expression.whenFalse);
|
|
128
|
+
}
|
|
129
|
+
if (ts.isBinaryExpression(expression) && [ts.SyntaxKind.AmpersandAmpersandToken, ts.SyntaxKind.BarBarToken,
|
|
130
|
+
ts.SyntaxKind.QuestionQuestionToken].includes(expression.operatorToken.kind)) {
|
|
131
|
+
return expressionRendersFooter(expression.left) || expressionRendersFooter(expression.right);
|
|
132
|
+
}
|
|
133
|
+
if (ts.isArrayLiteralExpression(expression)) return expression.elements.some(expressionRendersFooter);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return Object.fromEntries(Object.entries(result).sort(([a], [b]) => a.localeCompare(b)));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function collectModalImports(sourceFile) {
|
|
141
|
+
const names = new Set();
|
|
142
|
+
const namespaces = new Set();
|
|
143
|
+
for (const statement of sourceFile.statements) {
|
|
144
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)
|
|
145
|
+
|| statement.moduleSpecifier.text !== "@jc-times/business-ui") continue;
|
|
146
|
+
const bindings = statement.importClause?.namedBindings;
|
|
147
|
+
if (bindings && ts.isNamedImports(bindings)) {
|
|
148
|
+
for (const element of bindings.elements) {
|
|
149
|
+
const importedName = (element.propertyName ?? element.name).text;
|
|
150
|
+
if (importedName === "ModalShell" || importedName === "Dialog") names.add(element.name.text);
|
|
151
|
+
}
|
|
152
|
+
} else if (bindings && ts.isNamespaceImport(bindings)) {
|
|
153
|
+
namespaces.add(bindings.name.text);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { names, namespaces };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function isImportedModalTag(tagName, { names, namespaces }) {
|
|
160
|
+
if (ts.isIdentifier(tagName)) return names.has(tagName.text);
|
|
161
|
+
if (!ts.isPropertyAccessExpression(tagName) || !ts.isIdentifier(tagName.expression)) return false;
|
|
162
|
+
return namespaces.has(tagName.expression.text) && (tagName.name.text === "ModalShell" || tagName.name.text === "Dialog");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function* walk(directory) {
|
|
166
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
167
|
+
const absolute = path.join(directory, entry.name);
|
|
168
|
+
if (entry.isDirectory()) yield* walk(absolute);
|
|
169
|
+
else yield absolute;
|
|
170
|
+
}
|
|
171
|
+
}
|
package/dist/Alert.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { AlertCircle as e, CheckCircle2 as t, Info as n, TriangleAlert as r, X as i } from "lucide-react";
|
|
2
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
3
|
+
//#region src/Alert.tsx
|
|
4
|
+
var s = {
|
|
5
|
+
info: n,
|
|
6
|
+
success: t,
|
|
7
|
+
warning: r,
|
|
8
|
+
danger: e
|
|
9
|
+
};
|
|
10
|
+
function c({ tone: e = "info", title: t, description: n, action: r, dismissLabel: c = "关闭提示", onDismiss: l, className: u = "", ...d }) {
|
|
11
|
+
let f = s[e];
|
|
12
|
+
return /* @__PURE__ */ o("div", {
|
|
13
|
+
...d,
|
|
14
|
+
className: `ui-alert ui-alert-${e} ${u}`.trim(),
|
|
15
|
+
role: e === "danger" ? "alert" : "status",
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ a(f, {
|
|
18
|
+
className: "ui-alert-icon",
|
|
19
|
+
size: 18,
|
|
20
|
+
"aria-hidden": "true"
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ o("div", {
|
|
23
|
+
className: "ui-alert-content",
|
|
24
|
+
children: [t === void 0 ? null : /* @__PURE__ */ a("strong", { children: t }), n === void 0 ? null : /* @__PURE__ */ a("div", {
|
|
25
|
+
className: "ui-alert-description",
|
|
26
|
+
children: n
|
|
27
|
+
})]
|
|
28
|
+
}),
|
|
29
|
+
r === void 0 ? null : /* @__PURE__ */ a("div", {
|
|
30
|
+
className: "ui-alert-action",
|
|
31
|
+
children: r
|
|
32
|
+
}),
|
|
33
|
+
l && /* @__PURE__ */ a("button", {
|
|
34
|
+
type: "button",
|
|
35
|
+
className: "ui-alert-close",
|
|
36
|
+
"aria-label": c,
|
|
37
|
+
onClick: l,
|
|
38
|
+
children: /* @__PURE__ */ a(i, {
|
|
39
|
+
size: 16,
|
|
40
|
+
"aria-hidden": "true"
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { c as Alert };
|