@jc-times/business-ui 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/AGENTS.md +15 -0
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +2 -0
  4. package/THIRD_PARTY_NOTICES.md +3 -0
  5. package/bin/business-ui-gate.mjs +2 -2
  6. package/dist/AntDateWheelView.js +131 -0
  7. package/dist/AntOptionWheelView.js +76 -0
  8. package/dist/Cascader.js +56 -51
  9. package/dist/DateInput.js +84 -66
  10. package/dist/DateWheelPicker.js +58 -0
  11. package/dist/ModalShell.js +84 -72
  12. package/dist/MultiSelect.js +5 -1
  13. package/dist/OptionWheelDialog.js +99 -0
  14. package/dist/Select.js +116 -61
  15. package/dist/StructuredAddressInput.js +72 -70
  16. package/dist/TreeSelect.js +4 -1
  17. package/dist/WheelCascader.js +123 -0
  18. package/dist/WheelDateInput.js +97 -0
  19. package/dist/business-ui.js +42 -39
  20. package/dist/date-wheel-model.js +27 -0
  21. package/dist/option-wheel-model.js +49 -0
  22. package/dist/styles.css +1 -1
  23. package/dist/types/AntDateWheelView.d.ts +9 -0
  24. package/dist/types/AntOptionWheelView.d.ts +8 -0
  25. package/dist/types/Cascader.d.ts +2 -0
  26. package/dist/types/DateInput.d.ts +4 -0
  27. package/dist/types/DateWheelPicker.d.ts +13 -0
  28. package/dist/types/ModalShell.d.ts +3 -1
  29. package/dist/types/OptionWheelDialog.d.ts +18 -0
  30. package/dist/types/Select.d.ts +4 -1
  31. package/dist/types/StructuredAddressInput.d.ts +3 -1
  32. package/dist/types/WheelCascader.d.ts +6 -0
  33. package/dist/types/WheelDateInput.d.ts +11 -0
  34. package/dist/types/date-wheel-model.d.ts +8 -0
  35. package/dist/types/index.d.ts +3 -0
  36. package/dist/types/option-wheel-model.d.ts +19 -0
  37. package/dist/types/usePhoneWheel.d.ts +2 -0
  38. package/dist/types/useSheetViewport.d.ts +3 -0
  39. package/dist/usePhoneWheel.js +16 -0
  40. package/dist/useSheetViewport.js +26 -0
  41. package/docs/agent-guide.md +13 -5
  42. package/docs/api.md +14 -0
  43. package/docs/cascader.md +2 -0
  44. package/docs/component-strategy.md +3 -0
  45. package/docs/date-wheel.md +25 -0
  46. package/docs/dependencies.md +2 -0
  47. package/docs/mobile-controls.md +54 -0
  48. package/docs/modal-shell-migration.md +25 -0
  49. package/docs/release.md +7 -0
  50. package/docs/viewport-qa.md +38 -0
  51. package/licenses/antd-mobile-MIT.txt +22 -0
  52. package/package.json +11 -2
@@ -8,6 +8,8 @@ export type DateInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type"
8
8
  maxDate?: string;
9
9
  isDateUnavailable?(isoDate: string): boolean;
10
10
  onValidationError?(message: string | null): void;
11
+ /** Opt in to wheels on phones; desktops and tablets keep the calendar. */
12
+ mobileMode?: "calendar" | "wheel";
11
13
  };
12
14
  export declare const DateInput: import("react").ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "defaultValue" | "onChange" | "value"> & {
13
15
  value: string;
@@ -18,6 +20,8 @@ export declare const DateInput: import("react").ForwardRefExoticComponent<Omit<I
18
20
  maxDate?: string;
19
21
  isDateUnavailable?(isoDate: string): boolean;
20
22
  onValidationError?(message: string | null): void;
23
+ /** Opt in to wheels on phones; desktops and tablets keep the calendar. */
24
+ mobileMode?: "calendar" | "wheel";
21
25
  } & import("react").RefAttributes<HTMLInputElement>>;
22
26
  export declare function parseDate(value: string): string | null;
23
27
  export declare function calendarDays(year: number, month: number): {
@@ -0,0 +1,13 @@
1
+ export type DateWheelPickerProps = {
2
+ value: string;
3
+ onValueChange(value: string): void;
4
+ minDate?: string;
5
+ maxDate?: string;
6
+ isDateUnavailable?(date: string): boolean;
7
+ disabled?: boolean;
8
+ readOnly?: boolean;
9
+ "aria-label"?: string;
10
+ onPendingChange?(pending: boolean): void;
11
+ };
12
+ /** Independent date wheel backed by the pinned Ant Design Mobile DatePickerView. */
13
+ export declare function DateWheelPicker(props: DateWheelPickerProps): import("react").JSX.Element;
@@ -4,6 +4,8 @@ type DataAttributes = {
4
4
  [key: `data-${string}`]: string | number | boolean | undefined;
5
5
  };
6
6
  export type ModalShellProps = {
7
+ /** Compact forms can opt into a content-height bottom sheet on mobile layouts. */
8
+ mobileMode?: "fullscreen" | "bottom-sheet";
7
9
  backdropClassName?: string;
8
10
  panelClassName?: string;
9
11
  titleId: string;
@@ -28,6 +30,6 @@ export type ModalShellProps = {
28
30
  footer?: ReactNode;
29
31
  footerClassName?: string;
30
32
  };
31
- export declare function ModalShell({ backdropClassName, panelClassName, titleId, eyebrow, title, description, closeLabel, onClose, closeDisabled, showCloseButton, closeIconSize, closeOnBackdrop, rootRef, closeOnEscape, initialFocus, returnFocus, role, describedBy, children, footer, contentClassName, contentProps, footerClassName }: ModalShellProps): import("react").JSX.Element;
33
+ export declare function ModalShell({ backdropClassName, panelClassName, titleId, eyebrow, title, description, closeLabel, onClose, closeDisabled, showCloseButton, closeIconSize, closeOnBackdrop, rootRef, closeOnEscape, initialFocus, returnFocus, role, describedBy, children, footer, contentClassName, contentProps, footerClassName, mobileMode }: ModalShellProps): import("react").JSX.Element;
32
34
  export declare const Dialog: typeof ModalShell;
33
35
  export {};
@@ -0,0 +1,18 @@
1
+ import { type ReactNode } from "react";
2
+ import { type WheelOption } from "./option-wheel-model";
3
+ import type { FocusTarget } from "./useModalFocusTrap";
4
+ type Props = {
5
+ options: readonly WheelOption[];
6
+ value: readonly string[];
7
+ title?: ReactNode;
8
+ returnFocus: FocusTarget;
9
+ portalContainer?: HTMLElement | null;
10
+ allowClear?: boolean;
11
+ clearLabel?: string;
12
+ emptyText?: ReactNode;
13
+ onClose(): void;
14
+ onConfirm(value: string[]): void;
15
+ };
16
+ /** Internal shared single/cascading wheel. No business requests or implicit commits. */
17
+ export declare function OptionWheelDialog({ options, value, title, returnFocus, portalContainer, allowClear, clearLabel, emptyText, onClose, onConfirm }: Props): import("react").ReactPortal;
18
+ export {};
@@ -4,6 +4,7 @@ export type SelectOption = {
4
4
  value: string;
5
5
  label: ReactNode;
6
6
  disabled?: boolean;
7
+ textValue?: string;
7
8
  };
8
9
  type DataAttributes = {
9
10
  [key: `data-${string}`]: string | number | boolean | undefined;
@@ -21,11 +22,13 @@ export type SelectProps = {
21
22
  disabled?: boolean;
22
23
  name?: string;
23
24
  id?: string;
25
+ /** Opt-in phone wheel for short single-choice lists; desktop/tablet retain the dropdown. */
26
+ mobileMode?: "dropdown" | "wheel";
24
27
  className?: string;
25
28
  triggerRef?: Ref<HTMLButtonElement>;
26
29
  triggerProps?: Omit<RadixSelect.SelectTriggerProps, "id" | "className" | "disabled"> & DataAttributes;
27
30
  portalContainer?: HTMLElement | null;
28
31
  placement?: Pick<RadixSelect.SelectContentProps, "side" | "align" | "sideOffset" | "alignOffset" | "collisionPadding" | "avoidCollisions">;
29
32
  };
30
- export declare function Select({ value, defaultValue, onValueChange, options, label, placeholder, helpText, error, required, disabled, name, id, className, triggerRef, triggerProps, portalContainer, placement }: SelectProps): import("react").JSX.Element;
33
+ export declare function Select({ value, defaultValue, onValueChange, options, label, placeholder, helpText, error, required, disabled, name, id, className, triggerRef, triggerProps, portalContainer, placement, mobileMode }: SelectProps): import("react").JSX.Element;
31
34
  export {};
@@ -34,6 +34,8 @@ export type StructuredAddressInputProps = {
34
34
  /** Legacy opt-in. Defaults to false; use a top-level overseas region. */
35
35
  showModeSelector?: boolean;
36
36
  regionLabel?: string;
37
+ /** Opt-in linked region wheels on phones. */
38
+ mobileMode?: "dropdown" | "wheel";
37
39
  detailLabel?: string;
38
40
  freeformLabel?: string;
39
41
  searchPlaceholder?: string;
@@ -46,7 +48,7 @@ export type StructuredAddressInputProps = {
46
48
  detailInputProps?: Omit<InputHTMLAttributes<HTMLInputElement>, "children" | "className" | "disabled" | "onChange" | "value"> & DataAttributes;
47
49
  freeformInputProps?: Omit<InputHTMLAttributes<HTMLInputElement>, "children" | "className" | "disabled" | "onChange" | "value"> & DataAttributes;
48
50
  };
49
- export declare function StructuredAddressInput({ regions, value, onValueChange, label, required, disabled, annotation, dataVersion, className, structuredModeLabel, freeformModeLabel, showModeSelector, regionLabel, detailLabel, freeformLabel, searchPlaceholder, emptyText, maxLength, regionInputRef, detailInputRef, freeformInputRef, regionInputProps, detailInputProps, freeformInputProps }: StructuredAddressInputProps): import("react").JSX.Element;
51
+ export declare function StructuredAddressInput({ regions, value, onValueChange, label, required, disabled, annotation, dataVersion, className, structuredModeLabel, freeformModeLabel, showModeSelector, regionLabel, detailLabel, freeformLabel, searchPlaceholder, emptyText, maxLength, regionInputRef, detailInputRef, freeformInputRef, regionInputProps, detailInputProps, freeformInputProps, mobileMode }: StructuredAddressInputProps): import("react").JSX.Element;
50
52
  export declare function flattenAddressRegions(regions: readonly AddressRegion[]): AddressRegionPath[];
51
53
  export declare function searchAddressRegions(regions: readonly AddressRegion[], query: string, limit?: number): AddressRegionPath[];
52
54
  export declare function findAddressRegionPath(regions: readonly AddressRegion[], ids: readonly string[]): {
@@ -0,0 +1,6 @@
1
+ import type { CascaderProps } from "./Cascader";
2
+ type Props = Extract<CascaderProps, {
3
+ multiple?: false;
4
+ }>;
5
+ export declare function WheelCascader(props: Props): import("react").JSX.Element;
6
+ export {};
@@ -0,0 +1,11 @@
1
+ export declare const WheelDateInput: import("react").ForwardRefExoticComponent<Omit<import("react").InputHTMLAttributes<HTMLInputElement>, "type" | "defaultValue" | "onChange" | "value"> & {
2
+ value: string;
3
+ onValueChange(value: string): void;
4
+ inputRef?: import("react").Ref<HTMLInputElement>;
5
+ inputClassName?: string;
6
+ minDate?: string;
7
+ maxDate?: string;
8
+ isDateUnavailable?(isoDate: string): boolean;
9
+ onValidationError?(message: string | null): void;
10
+ mobileMode?: "calendar" | "wheel";
11
+ } & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,8 @@
1
+ import { CalendarDate } from "@internationalized/date";
2
+ export declare function wheelDate(value?: string): CalendarDate | null;
3
+ export declare function wheelBounds(minDate?: string, maxDate?: string): {
4
+ min: CalendarDate;
5
+ max: CalendarDate;
6
+ } | null;
7
+ export declare function clampWheelDate(value: CalendarDate, bounds: NonNullable<ReturnType<typeof wheelBounds>>): CalendarDate;
8
+ export declare function initialWheelDate(value: string, minDate?: string, maxDate?: string): CalendarDate;
@@ -6,6 +6,7 @@ export * from "./Skeleton";
6
6
  export * from "./FloatingControls";
7
7
  export * from "./UserProfilePopover";
8
8
  export * from "./Select";
9
+ export { usePhoneWheel } from "./usePhoneWheel";
9
10
  export * from "./Combobox";
10
11
  export * from "./AutoComplete";
11
12
  export * from "./Toast";
@@ -14,6 +15,8 @@ export * from "./ExplainableButton";
14
15
  export * from "./ModalShell";
15
16
  export * from "./FormField";
16
17
  export * from "./DateInput";
18
+ export * from "./DateWheelPicker";
19
+ export * from "./WheelDateInput";
17
20
  export * from "./Pagination";
18
21
  export * from "./RovingTabs";
19
22
  export * from "./ToggleSwitch";
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ export type WheelOption = {
3
+ value: string;
4
+ label: ReactNode;
5
+ textValue?: string;
6
+ disabled?: boolean;
7
+ children?: readonly WheelOption[];
8
+ isLeaf?: boolean;
9
+ };
10
+ export declare function wheelText(option: WheelOption): string;
11
+ /** Exclude disabled branches and branches with no selectable leaf. */
12
+ export declare function enabledWheelOptions(options: readonly WheelOption[]): WheelOption[];
13
+ /** Keep valid ancestors; after the first changed/missing parent reset every descendant. */
14
+ export declare function resolveWheelPath(options: readonly WheelOption[], value: readonly string[]): {
15
+ path: WheelOption[];
16
+ columns: WheelOption[][];
17
+ value: string[];
18
+ };
19
+ export declare function wheelOptionsKey(options: readonly WheelOption[]): string;
@@ -0,0 +1,2 @@
1
+ /** Match the date picker policy: phone identity AND touch-only interaction. */
2
+ export declare function usePhoneWheel(enabled: boolean): boolean;
@@ -0,0 +1,3 @@
1
+ import { type CSSProperties } from "react";
2
+ /** Keep a mobile sheet inside the visible area when a soft keyboard overlays the layout viewport. */
3
+ export declare function useSheetViewport(enabled: boolean): CSSProperties | undefined;
@@ -0,0 +1,16 @@
1
+ import { useEffect as e, useState as t } from "react";
2
+ //#region src/usePhoneWheel.ts
3
+ var n = "(hover: none) and (pointer: coarse)";
4
+ function r(r) {
5
+ let [i, a] = t(!1);
6
+ return e(() => {
7
+ if (!r || !window.matchMedia) {
8
+ a(!1);
9
+ return;
10
+ }
11
+ let e = window.matchMedia(n), t = () => a(e.matches && /iPhone|iPod|Android.+Mobile/i.test(navigator.userAgent));
12
+ return t(), e.addEventListener("change", t), () => e.removeEventListener("change", t);
13
+ }, [r]), r && i;
14
+ }
15
+ //#endregion
16
+ export { r as usePhoneWheel };
@@ -0,0 +1,26 @@
1
+ import { useEffect as e, useState as t } from "react";
2
+ //#region src/useSheetViewport.ts
3
+ var n = "(max-width: 600px), (max-width: 900px) and (max-height: 600px) and (pointer: coarse)";
4
+ function r(r) {
5
+ let [i, a] = t();
6
+ return e(() => {
7
+ if (!r || !window.visualViewport || !window.matchMedia) {
8
+ a(void 0);
9
+ return;
10
+ }
11
+ let e = window.visualViewport, t = window.matchMedia(n), i = 0;
12
+ function o() {
13
+ cancelAnimationFrame(i), i = requestAnimationFrame(() => {
14
+ a(t.matches && Math.abs(e.scale - 1) < .01 ? {
15
+ "--ui-sheet-top": `${e.offsetTop}px`,
16
+ "--ui-sheet-height": `${e.height}px`
17
+ } : void 0);
18
+ });
19
+ }
20
+ return o(), e.addEventListener("resize", o), e.addEventListener("scroll", o), t.addEventListener("change", o), () => {
21
+ cancelAnimationFrame(i), e.removeEventListener("resize", o), e.removeEventListener("scroll", o), t.removeEventListener("change", o);
22
+ };
23
+ }, [r]), r ? i : void 0;
24
+ }
25
+ //#endregion
26
+ export { r as useSheetViewport };
@@ -1,5 +1,7 @@
1
1
  # Agent 公共组件使用指南
2
2
 
3
+ 公司目录、企微/服务号客户端、按钮回调和反馈组件由同仓[统一SDK](../packages/business-sdk/README.md)维护;此文只描述UI包。不要把SDK服务端客户端导入浏览器,或把SDK变更塞入UI根入口。
4
+
3
5
  PDFium 自 0.3.2 默认按需使用同源中文/拉丁备用字体;构建器需支持包内 `?url` 静态资源导入(Vite)。不依赖外部字体 CDN;不要为禁外网而关闭整个字体回退。显式 `fontFallback: null` 仍可覆盖默认值。
4
6
 
5
7
  级联选择用于右侧窄栏时使用 0.2.48 或以上版本:浮层按可见视口避让,不需要消费方重写定位样式。
@@ -18,6 +20,10 @@ PDFium 自 0.3.2 默认按需使用同源中文/拉丁备用字体;构建器
18
20
 
19
21
  ## 按需求选择组件
20
22
 
23
+ 手机场景先看 [手机组件适配](mobile-controls.md):已有响应式行为、触控尺寸修复与后续候选分别列出;不要在消费方复制整套移动选择交互。
24
+
25
+ 需要保留电脑原生下拉并按需加载手机 Select 时,复用 `usePhoneWheel(true)` 做薄组合;不要复制设备判定。该新增导出需核对安装包版本,完整说明见手机适配文档。
26
+
21
27
  ### 页面、信息与反馈
22
28
 
23
29
  | 需求 | 使用组件 | 边界与选择依据 |
@@ -45,13 +51,14 @@ PDFium 自 0.3.2 默认按需使用同源中文/拉丁备用字体;构建器
45
51
  | 数量、精确十进制 | `NumericInput` | value 为字符串;提交用 onValueCommit,不能用草稿计算 |
46
52
  | 金额等以最小单位整数存储的数值 | `ScaledNumericInput` | value 为安全整数或 null;scale=100 表示分,不是元 |
47
53
  | 原生下拉单选 | `SelectInput` | 简单固定候选,使用浏览器原生选择体验 |
48
- | 定制单选浮层 | `Select` | 需要公共浮层、定制选项或手机抽屉体验 |
54
+ | 定制单选浮层 / 少量选项手机滚轮 | `Select` | `mobileMode="wheel"` 可选手机确认式滚轮;默认下拉,复杂标签补 textValue,详见[手机适配](mobile-controls.md) |
49
55
  | 搜索已有选项 / 允许自由文本 | `Combobox` / `AutoComplete` | 必须选已有项用前者;允许新文本用后者 |
50
56
  | 多选与已选标签 | `MultiSelect` | values/onValuesChange;异步候选之外的标签通过 selectedItems 补足 |
51
- | 部门、分类、省市区等多列级联选择 | `Cascader` | RC 内核;单选路径、多选路径数组;默认父子独立多选;扁平数据用 buildCascaderOptions 转换 |
57
+ | 部门、分类、省市区等多列级联选择 | `Cascader` | RC 内核;静态叶子单选可用 mobileMode="wheel";多选/异步/父级可选仍用列表;扁平数据用 buildCascaderOptions 转换 |
52
58
  | 部门、分类等树形单选或多选 | `TreeSelect` | 应用映射 id/label/parentId;父子独立选择,不自动级联 |
53
59
  | 远程目录搜索,需防抖、取消、缓存 | `AsyncDirectoryPicker` | 提供 loadItems(query, signal) 和 ownerKey;网络适配器必须传递 signal |
54
60
  | 页面已有查询状态和请求生命周期 | `AsyncSearchPicker` | 页面提供 query/items/status/onSearch/onSelect;组件不发请求 |
61
+ | 手机滚轮日期 / 独立年月日滚轮 | [WheelDateInput / DateWheelPicker](date-wheel.md) | DateInput mobileMode="wheel" 自动适配;业务时区、范围由调用方提供 |
55
62
  | 日期输入与日历 | `DateInput` | 用 minDate/maxDate/isDateUnavailable 约束;业务时区和日期转换由应用负责 |
56
63
  | 省市区与详细地址 | `StructuredAddressInput` | 默认无地址类型,海外作为顶级地区;内部复用 Cascader;独立行政区划入口提供数据;地址解析、拼接和字段映射由应用负责 |
57
64
 
@@ -59,7 +66,7 @@ PDFium 自 0.3.2 默认按需使用同源中文/拉丁备用字体;构建器
59
66
 
60
67
  | 需求 | 使用组件 | 边界与选择依据 |
61
68
  | --- | --- | --- |
62
- | 编辑表单、详情等模态内容 | `ModalShell`(别名 `Dialog`) | 正文用 children,固定操作区用 footer;不重复安装焦点陷阱 |
69
+ | 编辑表单、详情等模态内容 | `ModalShell`(别名 `Dialog`) | 一两个字段的小表单用 mobileMode="bottom-sheet";正文用 children,操作区用 footer;见[布局约定](modal-shell-migration.md) |
63
70
  | 独立、强层级确认 | `ConfirmDialog` | 例如删除确认;应用决定危险级别、busy 和提交逻辑 |
64
71
  | 触发器旁的轻量确认 | `Popconfirm` | 依附锚点;长表单使用 ModalShell |
65
72
  | 更多操作、分组操作、可勾选菜单 | `DropdownMenu`(别名 `Menu`) | 统一 menu 键盘行为;导航当前位置用 current,选中配置用 selectionMode |
@@ -127,8 +134,9 @@ export function EditQuantity() {
127
134
 
128
135
  1. 运行消费项目要求的类型检查、构建及相关测试,验证实际业务回调、空值、禁用、错误、重试和资源切换。
129
136
  2. 检查桌面与手机视口、长文字、弹窗嵌套下拉、键盘操作和焦点归还;需要软键盘的流程做真实手机验收。视口模拟不等于真实手机通过。
130
- 3. 已配置 `business-ui-gate` 的项目运行现有门禁;不要扩大 baseline 掩盖新增手写组件。首次接入的基线按项目规则生成并审核。
131
- 4. 修改公共实现时运行本库相关检查,并按 [多视口验收](viewport-qa.md) 和 [发布流程](release.md) 处理。区分本地验证、包已发布、消费方升级与生产部署状态。
137
+ 3. `bareButton` 统计所有原生 `<button>`,包括静态/动态/空 `className` 和属性展开;样式不构成豁免。确有整卡展开等业务语义时,在 baseline 中按文件写入精确数量并记录理由;不要对普通操作按钮批量生成放行基线。该修正为当前源码能力,已发布旧版本需升级或应用精确依赖补丁后才生效。
138
+ 4. 已配置 `business-ui-gate` 的项目运行现有门禁;不要扩大 baseline 掩盖新增手写组件。首次接入的基线按项目规则生成并审核。
139
+ 5. 修改公共实现时运行本库相关检查,并按 [多视口验收](viewport-qa.md) 和 [发布流程](release.md) 处理。区分本地验证、包已发布、消费方升级与生产部署状态。
132
140
 
133
141
  ## 文档分工与维护
134
142
 
package/docs/api.md CHANGED
@@ -251,3 +251,17 @@ PdfiumViewer 支持 defaultRailCollapsed:传 true 默认收起页面侧栏,
251
251
 
252
252
  ## MultilineAutoComplete (0.2.51)
253
253
  Controlled value/onChange, items/onSelect, label or aria-label, placeholder, disabled/loading, onFocus/onBlur, helpText and portalContainer. Composes React Aria Autocomplete, TextField/TextArea, Popover and ListBox. Async items open while focused; selection is explicit. Free text and unmatched Enter newlines are retained. Network cancellation and domain mapping belong to the consumer.
254
+
255
+ ## 滚轮日期
256
+ 独立 DateWheelPicker、WheelDateInput,以及 DateInput 的 mobileMode=wheel 适配,见[滚轮日期](date-wheel.md)。
257
+
258
+ ## 手机触控样式
259
+
260
+ `ModalShell`/`Dialog` 新增 `mobileMode?: "fullscreen" | "bottom-sheet"`,默认 fullscreen;一两个字段的小表单可使用底部面板,内容高度、固定footer、手机安全区和可见视口跟随由公共库处理。使用示例及适用范围见[小表单样式约定](modal-shell-migration.md)。0.4.0 新增能力。
261
+
262
+ `Select`、`Cascader`、`StructuredAddressInput` 新增 `mobileMode?: "dropdown" | "wheel"`(默认 dropdown);手机可选确认式单列/联动滚轮。`SelectOption.textValue?: string` 用于复杂标签的滚轮与读屏文字。级联多选、异步和父节点选择保持原模式。完整行为、回退条件与示例见[手机组件适配](mobile-controls.md),此为0.4.0 新增能力。
263
+
264
+ 选择器、勾选/开关与提示关闭按钮的手机适配见 [手机组件适配](mobile-controls.md)。粗指针最小点击尺寸复用 `--ui-touch-height`;多选长标签自动换行,公共参数及选择回调保持不变。修复自0.4.0提供。
265
+ # 按需手机控件组合
266
+
267
+ `usePhoneWheel(enabled: boolean): boolean` 复用公共手机策略(明确手机身份、无 hover 且粗指针),服务端与首次渲染返回 false,设备媒体条件变化时更新,卸载清理监听。适合消费方保留电脑 SelectInput、仅手机动态加载 Select。它不发起网络请求,也不自行创建滚轮;配合 Select 的 `mobileMode="wheel"`。公开导出自源提交 `1b56aea`,不视为旧正式包已支持。
package/docs/cascader.md CHANGED
@@ -8,6 +8,8 @@
8
8
 
9
9
  ## 单选与多选
10
10
 
11
+ 静态叶子单选可显式设置 `mobileMode="wheel"`,手机使用 antd-mobile PickerView 联动滚轮,确认后提交完整路径;多选、loadData、changeOnSelect=true 保留 RC 列表。StructuredAddressInput 也提供该参数,手机滚轮使用完整地区路径。默认和桌面行为不变;详见[手机组件适配](mobile-controls.md)。此能力自0.4.0提供。
12
+
11
13
  ```tsx
12
14
  import { Cascader } from "@jc-times/business-ui";
13
15
 
@@ -92,3 +92,6 @@
92
92
  ## 2026-09-11 Cascader 内核采用
93
93
 
94
94
  新增固定 @rc-component/cascader@1.25.0(MIT),公共包装提供业务主题、表单元信息、空值归一、最近弹窗 portal、窄屏底部面板与默认独立多选。StructuredAddressInput 复用通用组件;TreeSelect 保留兼容。无 antd 依赖;依赖外置,发行包保留 RC 许可证。当前为本地实现,消费接入与发布独立验证。
95
+
96
+ ## 2026-09-28 滚轮日期选型
97
+ 比较Ant Design Mobile DatePickerView、react-mobile-picker 1.2.0和@ncdai/react-wheel-picker 1.2.3;选择固定antd-mobile 5.43.0的日期滚轮子模块,已有日期上下限/联动/filter。另两者主要为通用滚轮,日期规则仍须组合;ncdai本次安装包未提供完整ARIA语义和有界选项DOM。删除初版自定义滚动内核,只保留公共主题、范围适配、可访问键盘语义与原ModalShell。官方:https://mobile.ant.design/components/picker-view/ 。只在手机打开选择器后动态导入,电脑/触屏电脑/平板保留React Aria日历;不引入全库主题或替换其他公共控件。
@@ -0,0 +1,25 @@
1
+ # 滚轮日期组件
2
+
3
+ 独立 `DateWheelPicker` 提供受控年/月/日滚轮,`WheelDateInput` 提供输入入口、底部弹窗、取消及确认。
4
+ `DateInput mobileMode="wheel"` 仅手机标识且为无hover粗指针时使用滚轮;电脑、触屏电脑、平板及桌面窄窗口均保留日历;默认仍是原日历,已有调用方无需修改。
5
+ 此能力为0.4.0的minor增量;消费前检查实际安装的开发包/正式包,不引用相邻源码。
6
+
7
+ ```tsx
8
+ <FormField controlId="date" label="日期" required>
9
+ <DateInput id="date" value={value} onValueChange={setValue} required
10
+ mobileMode="wheel" minDate="2026-09-28" maxDate="2027-12-31"
11
+ isDateUnavailable={iso => holidays.has(iso)} />
12
+ </FormField>
13
+ ```
14
+
15
+ - 组件没有请求、业务缓存或时区规则,调用方传ISO日期与范围。无显式限制时允许0001–9999年,不隐设业务最晚日期。
16
+ - 年月变化修正闰日/月末及上下界;自定义不可用日期禁选。年月切换遇禁用日,仅在目标月内查找最近可用日(最多31日),整月不可用则保持原值。
17
+ - `DateWheelPicker` 为即时受控值,`onPendingChange` 告知滚动尚未停止。独立使用时调用方须阻止此阶段提交。
18
+ - `WheelDateInput` 只在“确定日期”提交;取消/Escape不改值,焦点返回原输入。滚动停止前禁止确认,禁用/只读或外部value变化关闭旧草稿。动态范围和可用性在确认时重新检查。
19
+ - 内核使用固定antd-mobile@5.43.0的DatePickerView,触摸/惯性/年月日联动由上游实现,不复制其源码。年范围随选择居中移动,最多101年选项,仍能到达0001–9999;日期行44px。仅在打开手机滚轮后加载,失败可重试。
20
+ - 公共包装为每列补单焦点spinbutton,方向键、PageUp/Down、Home/End可用;读屏提供选中值、禁用状态、上下界。手写日期仅桌面日历支持,手机入口不唤起软键盘。
21
+ - 复用ModalShell与其焦点管理,浮层挂载到当前弹窗portal容器;窄屏底部面板按安全区适配,短屏正文可滚动。
22
+ - 真实iOS/微信内置浏览器的惯性滚动和读屏仍需真机验收,浏览器触屏模拟不能替代。
23
+ # 手机留白调整(2026-09-28)
24
+
25
+ 滚轮显示三行(132px),每行保留44px触摸高度。最小日期位于首项时,居中选中行上方保留一行滚动空间,避免五行窗口留下两行空白;不改变可选范围、惯性与电脑日历。
@@ -55,3 +55,5 @@ React 19 开发模式下,Cascader 的传递依赖 `@rc-component/select@1.11.0
55
55
  2026-09-12 本地验证:React 18.3.1 / 19.3.0 均通过 136 项单测、类型检查、库构建、按需打包门禁和视觉矩阵构建。React 19 的 38 项公共浏览器回归及新增 2 项日期回归、React 18 的完整 40 项浏览器回归通过;React 19 的 MRT 14 项浏览器回归和样例构建通过。日期回归 fixture 另经严格 TypeScript 检查。尚未提交、执行远端 CI 或发布,消费服务未升级。
56
56
 
57
57
  后续运行 `pnpm verify`、`pnpm test:browser`、`pnpm test:mrt`,并检查 `pnpm pack` 的声明、子入口和文档清单。最新版本可从 [npm 官方 registry](https://registry.npmjs.org/) 重新核查,具体迁移参考 [Vite 8](https://vite.dev/guide/migration) 与 [MUI X 9](https://mui.com/x/migration/migration-pickers-v8/)。
58
+
59
+ 2026-09-28:滚轮内核固定antd-mobile@5.43.0,MIT,仅动态DatePickerView子模块。antd-mobile声明支持React18/19;传递react-spring9.6.1/staged-components的peer上限仍为18,未用override强改。需分别验证公共库React19和消费项目React18的实际触摸/日期链路,不以peer声明替代实测。
@@ -0,0 +1,54 @@
1
+ # 手机组件适配
2
+
3
+ 2026-09-28 源码检查。以下区分现有实现、本次修复与后续候选;源码不代表已发布版本,消费方需核对实际安装包。
4
+
5
+ | 组件 | 当前手机行为 | 后续方向 |
6
+ | --- | --- | --- |
7
+ | DateInput / WheelDateInput | 可选滚轮日期与底部确认面板 | 真机惯性滚动、软键盘及微信容器验收 |
8
+ | Select / SelectInput | Select 可选手机滚轮;原生单选使用系统界面 | 少量有序枚举用滚轮,长列表继续用搜索 |
9
+ | Combobox / AutoComplete | 搜索输入与锚点候选;本次扩大展开按钮 | 优先候选:独立搜索面板,需要一并处理软键盘、输入焦点与虚拟列表,不能只把候选固定到底部 |
10
+ | AsyncDirectoryPicker / AsyncSearchPicker | 查询按钮窄屏整行,异步候选列表 | 与搜索面板协同设计,保留取消、缓存和业务请求边界 |
11
+ | MultiSelect | 本次修复长标签溢出,扩大移除和清空触控区域 | 优先候选:已选摘要、展开管理及可选确认式多选;默认即时回调语义应保留 |
12
+ | TreeSelect | 锚点浮层;本次扩大触发/清空按钮,修复长已选标签 | 优先候选:独立树选择面板、路径导航。旧 CSS 的窄屏 fixed 被后置 data-side 定位覆盖,不视为完整底部抽屉 |
13
+ | Cascader / StructuredAddressInput | 静态单选可选手机联动滚轮;原模式保留 | 大目录、异步与多选仍使用列表 |
14
+ | DropdownMenu / Popconfirm | 避让视口的锚点浮层,菜单触控行加高 | 可选操作面板;子菜单需统一返回路径,危险动作保持确认 |
15
+ | Checkbox / ToggleSwitch | 本次将标签点击区域提高到至少 44px | 保持原生勾选语义,避免把视觉轨道本身放大 |
16
+ | Alert / Popover / Toast | 本次关闭按钮至少 44×44px,触屏更易关闭 | 确认手机安全区、长正文与关闭焦点 |
17
+ | ModalShell / ConfirmDialog | ModalShell默认全屏;小表单可选mobileMode="bottom-sheet",内容高度贴底、固定操作栏 | 复杂表单保持全屏;ConfirmDialog原有参数保持不变,详见[小表单约定](modal-shell-migration.md) |
18
+ | Pagination / DataTable | 分页窄屏简化;表格有横向滚动及可选 cards | 消费方按列数选模式;后续可抽离筛选与列管理面板 |
19
+ | PDF / SortableList | 已有连续阅读、手势及触控拖动基础 | 真机多指/长按滚动冲突验证 |
20
+
21
+ ## 本次修复(随0.4.0交付)
22
+
23
+ - 粗指针设备自动扩大搜索候选展开、树选择清空/展开、多选移除/清空,以及 Alert、Popover、Toast 关闭按钮;最小点击尺寸使用 `--ui-touch-height`,默认 44px。
24
+ - 输入框同步预留尾部按钮空间;树选择清空与展开区域互不重叠。
25
+ - 多选和树选择已选标签允许长连续文本换行,移除按钮不收缩。
26
+ - Checkbox、ToggleSwitch 扩大整个 label 的点击高度,保留原生语义、键盘行为及桌面尺寸。
27
+ - 无新增 props 或业务回调,不改变即时选择/清空语义。与先前滚轮日期等未发布能力组成同一发布批次时,按批次最大变更级别决定正式版本。
28
+
29
+ 验证入口:`pnpm exec playwright test e2e/mobile-controls.spec.ts`;交互样例 `/e2e/mobile-controls.html`。浏览器模拟不代表真实 iOS、Android 软键盘或微信容器验收。
30
+
31
+ ## 单选与级联滚轮(0.4.0,minor)
32
+
33
+ 按需组合可使用 `usePhoneWheel(enabled)`,复用同一手机身份与粗指针判定。消费方可在电脑保留 SelectInput、仅手机动态加载 Select;不要复制设备识别或在窄桌面强制滚轮。该 hook 不请求业务数据。
34
+
35
+ ```tsx
36
+ <Select label="优先级" value={priority} onValueChange={setPriority}
37
+ options={priorities} mobileMode="wheel" />
38
+ <Cascader label="所在地区" options={regions} value={path}
39
+ onValueChange={setPath} mobileMode="wheel" />
40
+ <StructuredAddressInput regions={addressRegions} value={address}
41
+ onValueChange={setAddress} mobileMode="wheel" />
42
+ ```
43
+
44
+ - 三个组件新增 `mobileMode?: "dropdown" | "wheel"`,默认 dropdown。只在手机标识(iPhone/iPod/Android Mobile)且无 hover、粗指针时使用滚轮;平板、触屏电脑及电脑窄窗口保留原选择器。
45
+ - 使用固定 `antd-mobile@5.43.0` 的 `PickerView`,触摸/惯性/吸附由上游实现,打开面板后按需加载,加载失败可重试。日期仍使用同库的 DatePickerView。包装只处理数据、无障碍、主题、确认与弹窗管理,不自写滚动内核。
46
+ - 滚动只修改草稿;“确定选择”提交一次变化,“取消”、关闭及 Escape 不提交并返回触发器焦点。未停稳、未加载完、无可选项时不可确认。
47
+ - Select 保持 value/defaultValue、name/required、原生 FormData 和 triggerRef/triggerProps;禁用项不在滚轮中显示。复杂 ReactNode 标签应提供 `SelectOption.textValue` 作为滚轮与读屏文字;省略时使用 value。桌面仍显示原 label。
48
+ - 未选中或旧值已不可用时,面板暂选第一个可用值,打开本身不触发回调。打开后外部值、选项值/文本/禁用状态或控件禁用改变,关闭旧草稿,重新打开后再选。
49
+ - Cascader 仅对静态、叶子单选启用:multiple、loadData、changeOnSelect=true 自动保留原选择器。禁用分支、无可用叶子的分支及未加载的 isLeaf=false 节点不进入滚轮。变更上级重置所有下级为对应分支首个可用选项,确认返回完整路径及原始 options 节点;非必填且 allowClear 不为 false 时可显式清除为 []。
50
+ - StructuredAddressInput 手机滚轮选择完整地区路径,确认后返回地区入口焦点,不自动唤起详细地址软键盘;桌面原有中间级选择与详细地址聚焦保持不变。海外或直辖市等非等深数据按实际层数展示。
51
+ - 每列是一个可聚焦 spinbutton;上下方向键、PageUp/Down、Home/End 调值,左右切换列,选中路径摘要显示完整文字。面板复用 ModalShell、安全区和嵌套焦点管理。
52
+ - 适用于少量固定单选及有限层级。人员/客户大目录继续搜索,多选继续勾选列表;没有为所有组件强制滚轮或移除搜索。
53
+
54
+ 验证入口:`pnpm exec playwright test e2e/option-wheel.spec.ts`;样例 `/e2e/option-wheel.html`。真实手机惯性、VoiceOver/TalkBack及微信容器仍需验收。
@@ -1,5 +1,30 @@
1
1
  # ModalShell 0.2.6 消费迁移
2
2
 
3
+ ## 简易表单手机样式约定(0.4.0)
4
+
5
+ 一到两个字段的修改姓名、数量、备注等小表单,统一使用 `mobileMode="bottom-sheet"`:窄屏从下向上进入,按内容高度贴底,不设置固定空白高度;桌面居中。默认 `mobileMode="fullscreen"` 保持已有行为。复杂表单、多步骤、长文档继续默认模式。
6
+
7
+ ```tsx
8
+ <ModalShell titleId="edit-title" title="修改数量" closeLabel="关闭"
9
+ mobileMode="bottom-sheet" onClose={close}
10
+ footer={<>
11
+ <Button onClick={close}>取消</Button>
12
+ <Button variant="primary" type="submit" form="quantity-form">保存</Button>
13
+ </>}>
14
+ <form id="quantity-form" onSubmit={submit} style={{ display: "grid", gap: 16 }}>
15
+ <TextInput label="数量" inputMode="decimal" required />
16
+ </form>
17
+ </ModalShell>
18
+ ```
19
+
20
+ - 手机布局:宽度≤600px;短横屏同时要求≤900px、高度≤600px及粗指针。面板最大宽560px,顶部保留安全边距,底部覆盖安全区;不通过字段数量自动猜测场景。
21
+ - 字段单列排列,建议间距16px;简短标题,不放大段常驻说明。补充说明按字段问号帮助约定组合现有Popover;必填、格式、错误和操作风险直接显示。
22
+ - 将取消/保存放入 `footer`,主按钮放右侧,手机按钮等宽、至少44px高;默认不会点击遮罩就丢弃表单。未增加拖拽关闭,避免填写过程中误操作。
23
+ - 正文是唯一滚动区域,字段多或键盘压缩空间时正文滚动,头部和操作栏保留;无footer也会补底部安全区。
24
+ - 通过VisualViewport的高度和偏移适配覆盖式软键盘;无该API回退100dvh。缩放手势不触发键盘位置补偿。默认不抢输入焦点/主动唤起键盘,需要时用已有initialFocus。输入字号16px,降低iOS聚焦自动放大的干扰。
25
+ - 复用Radix焦点陷阱、Escape、返回焦点和嵌套浮层;减少动态效果偏好关闭入场动画。这里只提供布局,不代替业务提交、脏数据确认或权限规则。
26
+ - 浏览器视口和VisualViewport模拟不能代替真实iOS/Android/微信键盘验收。样例 `/e2e/mobile-sheet.html`,回归 `pnpm exec playwright test e2e/mobile-sheet.spec.ts`。
27
+
3
28
  ## 稳定 DOM 契约
4
29
 
5
30
  ModalShell 面板稳定保持以下直接子节点顺序:
package/docs/release.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # npm 公共发布流程
2
2
 
3
+ 本流程只发布根目录 `@jc-times/business-ui`。统一业务SDK为private子包,交付见[SDK版本与交付](../packages/business-sdk/docs/版本与交付.md),不得复用本流程公开发布SDK或使用递归publish。
4
+
3
5
  ## 发布位置与权限
4
6
 
5
7
  - Git 仓库:`https://github.com/jc-times/business-ui`
@@ -13,6 +15,8 @@
13
15
 
14
16
  ## 发布规则
15
17
 
18
+ 正式发布前必须盘点全部本地/远端分支和工作树:将尚未进入主线的有效改动合并,并确认各工作树没有遗漏的未提交修改。已通过 cherry-pick 或后续实现进入主线的历史分支,核对等价性并合并历史,不能用旧版本覆盖新实现。正在进行的修改先完成和验证,再进入发布;所有工作树 HEAD 应已包含在最终主线提交中。私有 SDK 即使随仓库合并,也仍按独立交付流程处理。
19
+
16
20
  1. 更新 `package.json` 版本和 `CHANGELOG.md`。
17
21
  2. 合并到 `main`,等待 CI 的类型检查、测试、构建和打包全部通过。
18
22
  3. 在已验证的提交上创建并推送注释标签 `v<package.version>`。
@@ -31,3 +35,6 @@ pnpm publish:release
31
35
  ```
32
36
 
33
37
  脚本应在发布前因缺少 `NPM_TOKEN` 或标签不匹配而退出。不要把真实令牌写入命令历史、仓库文件或文档。
38
+
39
+ ## UI私有开发制品
40
+ 提交UI源码后使用 pnpm ui:pack --target X.Y.Z。脚本验证UI门禁,按artifacts/ui唯一目录自动分配dev.N,生成带准确Git SHA和SHA256的private安装包;独立SDK工作树改动不打入UI包。所有打包者必须共用此编号目录。不公开发布、不创建正式标签;消费方固定tarball与lockfile并保存来源JSON。
@@ -1,5 +1,32 @@
1
1
  # 发布前多视口验收
2
2
 
3
+ ## 2026-09-28 — 0.4.0 布局审计
4
+
5
+ - 发布前全量浏览器145项通过、9项按设备/本地私有PDF条件跳过;SDK104单测与6项浏览器通过。新增长编号压力检查先在桌面/手机复现320px布局超宽(网格2426px),修复后五档视口和单选候选面板无水平溢出,2项专项通过。
6
+ - 修复Select长值入口省略/候选换行、勾选/开关标签不撑宽网格、Alert长编号换行。Radix Value不接受className样式,公共包装用独立具名span承载省略布局,不依赖消费方覆盖内部选择器。
7
+ - 手机搜索独立面板、树选择底部面板及复杂子菜单交互仍属后续增强;不将历史TreeSelect fixed CSS视作完整手机抽屉。现有React19 ref兼容警告、真实iOS/Android键盘/读屏与微信容器验收仍待;新增手机模式均显式启用,默认行为保留。
8
+
9
+ ## 2026-09-28 — 简易表单底部面板(minor,本地)
10
+
11
+ - ModalShell/Dialog新增可选mobileMode=bottom-sheet,原默认fullscreen保留;小表单内容高度贴底、从下方进入,固定操作栏、安全区、减少动态效果及VisualViewport高度/偏移适配。
12
+ - verify32文件173单测、类型、库/矩阵构建和tree-shaking通过;Chromium Desktop/Pixel7模拟24项通过(18既有+6新增)。覆盖五档视口、默认全屏/桌面居中、长正文独立滚动、原生必填/保存、Escape/返回焦点,以及模拟VisualViewport高度360/offsetTop40后底栏保持在可见区域。390px小表单截图已目检。
13
+ - 最初精确getByLabel匹配包含必填星号的label失败,测试改为原生textbox可访问名称后通过;没有修改组件字段语义。既有React19 ref警告仍存。非真实软键盘/iOS/微信验收;未发包、未批量改造消费页面。
14
+
15
+ ## 2026-09-28 — 单选/级联手机滚轮(minor,本地)
16
+
17
+ - Select、静态叶子单选Cascader和StructuredAddressInput可选手机滚轮;复用antd-mobile@5.43.0 PickerView,桌面/平板及默认模式保留原控件。
18
+ - 完整verify通过32文件172单测、类型、库/矩阵构建与tree-shaking;最终层级指纹改为线性序列化后4项模型专项、类型/构建复验通过(新增1项深层路径测试)。新增文档沿用已纳入发布files的mobile-controls.md,许可证清单补充PickerView。
19
+ - 既有maturity/cascader桌面与Pixel7模拟28项通过;最终滚轮专项8项通过,4项桌面不适用手势/手机用例跳过;尾部文案透传及模型调整后2项关键业务流程复验通过。
20
+ - 覆盖草稿取消/确认、禁用过滤、单次回调、原生FormData、非受控Select、级联父级重置/完整路径/清空、必填校验、地址接入、动态选项与禁用关闭、嵌套Escape与焦点、触屏停稳前禁止确认、iPad/Windows触屏回退;五档视口无溢出,390px及844px短横屏截图目检通过。
21
+ - 滚轮复用同期三行132px样式;手势按实际列高取点,不写死220px内的坐标。既有React19 element.ref警告仍存在;没有宣称iOS/Android真机、读屏或微信容器验收。未发包、未升级消费者。
22
+
23
+ ## 2026-09-28 — 手机基础触控修复(patch,本地)
24
+
25
+ - TypeScript、31文件169项单测、库构建、tree-shaking与视觉矩阵构建通过。
26
+ - Chromium Desktop / Pixel 7 模拟:18项 maturity 回归通过,最终4项 mobile-controls 专项通过。五档320×480、390×844、768×1024、1440×900、844×390无横向溢出;长标签换行、44px触控区域、树选择相邻按钮不重叠及桌面36px展开按钮验证通过。390px桌面/手机截图目检通过。
27
+ - 移除、清空、开关、提示关闭、浮层关闭与返回焦点通过。测试按React Aria实际组合名称定位移除按钮,清空后先关闭树候选,再操作下方控件;尺寸断言等待入场缩放动画结束。
28
+ - maturity样例仍输出React19 element.ref兼容警告;不是本次修复项。手机结果为浏览器模拟,iOS/Android真机及软键盘未验收,未发布。
29
+
3
30
  ## 2026-09-19 — 0.2.55 修复候选
4
31
 
5
32
  - 30 个测试文件、158 项单测、TypeScript、组件库构建、按需门禁和视觉矩阵构建通过。
@@ -133,3 +160,14 @@ Chromium桌面与Pixel 7视口,鼠标拖入目标、键盘选择目标/取消
133
160
  - 嵌套指示器可能把目标key交给祖先回调,scope仅路由至唯一当前所属列表;一次拖动只消费一次。
134
161
 
135
162
  - 首轮矩阵CI34971182111发现隐藏占位span使content不再是only-child,禁用行缩宽;占位仅在可拖动状态渲染,sortable-width回归验证。
163
+
164
+ ## 2026-09-28 — 独立滚轮日期(minor,本地)
165
+ - UI31文件169项单测、类型、构建、tree-shaking和视觉矩阵构建通过。22项日期/成熟控件桌面与Pixel7模拟回归通过;底部面板样式调整后4项滚轮专项复验通过。
166
+ - 320×480、390×844、768×1024、1440×900、844×390无横向溢出;手机底部面板、嵌套取消/确认/返回焦点、Escape只关内层、上下界与禁用日期、滚动等待和≤17项年DOM已验。
167
+ - 截图位于test-results/date-wheel-*;真实iOS/微信惯性滚动、读屏和业务生产验收仍待。
168
+ - 补充:手机CDP触摸滑动已验证,最终滚轮专项5通过、1桌面触摸用例按设计跳过;底部贴边及短横屏border-box均通过。
169
+
170
+ ## 2026-09-28 — 成熟日期滚轮内核替换(取代当日自定义滚动实现)
171
+ - 固定antd-mobile5.43.0 DatePickerView按需子模块,删除DateWheelColumn;年窗口上限101项,原17项限制仅属于已替代原型。公共31文件169测试、type/build/tree-shaking/视觉矩阵通过;日期与原成熟控件23项浏览器回归通过,1桌面触摸项跳过。
172
+ - 手机用滚轮,电脑/触屏电脑/平板保留日历。触摸滑动、上下界、禁选日、取消/确认及弹窗焦点已在React19 Chromium/Pixel7模拟验证;真机仍待,消费React18另验。
173
+ - 此批使用本地依赖实际包;ReactSpring旧peer上限警告保留,未强改传递版本。
@@ -0,0 +1,22 @@
1
+ MIT LICENSE
2
+
3
+ Copyright (c) 2016-present Alipay.com, https://www.alipay.com/
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jc-times/business-ui",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Shared accessible business UI components for JC Times applications",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,11 +21,14 @@
21
21
  "docs/mrt-poc.md",
22
22
  "docs/cascader.md",
23
23
  "licenses/rc-cascader-MIT.txt",
24
+ "licenses/antd-mobile-MIT.txt",
24
25
  "docs/component-strategy.md",
25
26
  "docs/release.md",
26
27
  "docs/viewport-qa.md",
27
28
  "docs/modal-shell-migration.md",
28
29
  "docs/maturity-migration.md",
30
+ "docs/date-wheel.md",
31
+ "docs/mobile-controls.md",
29
32
  "README.md",
30
33
  "CHANGELOG.md",
31
34
  "THIRD_PARTY_NOTICES.md",
@@ -119,6 +122,7 @@
119
122
  "@radix-ui/react-toast": "1.2.23",
120
123
  "@radix-ui/react-tooltip": "1.2.16",
121
124
  "@rc-component/cascader": "1.25.0",
125
+ "antd-mobile": "5.43.0",
122
126
  "cn-division": "2026.0.1",
123
127
  "material-react-table": "3.2.1",
124
128
  "react-aria-components": "1.21.1"
@@ -170,6 +174,11 @@
170
174
  "verify": "pnpm typecheck && pnpm test && pnpm build && pnpm test:tree-shaking && pnpm build:matrix",
171
175
  "pack:release": "pnpm verify && pnpm pack",
172
176
  "publish:release": "node scripts/publish-release.mjs",
173
- "test:tree-shaking": "node scripts/check-tree-shaking.mjs"
177
+ "test:tree-shaking": "node scripts/check-tree-shaking.mjs",
178
+ "sdk:build": "pnpm --filter @jc-times/business-sdk build",
179
+ "sdk:verify": "pnpm --filter @jc-times/business-sdk verify",
180
+ "sdk:test:browser": "playwright test --config packages/business-sdk/playwright.config.ts",
181
+ "sdk:pack": "node scripts/pack-sdk.mjs",
182
+ "ui:pack": "node scripts/pack-ui-dev.mjs"
174
183
  }
175
184
  }