@zerodep-dev/vue-tsx-pro-mobile 0.0.0-stage → 0.4.1

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 (209) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -2
  3. package/dist/area/data.d.ts +10 -0
  4. package/dist/area/data.js +3899 -0
  5. package/dist/area/data.js.map +1 -0
  6. package/dist/area/index.d.ts +22 -0
  7. package/dist/area/index.js +41 -0
  8. package/dist/area/index.js.map +1 -0
  9. package/dist/base/Button.d.ts +170 -0
  10. package/dist/base/Button.js +537 -0
  11. package/dist/base/Button.js.map +1 -0
  12. package/dist/base/Icon.d.ts +38 -0
  13. package/dist/base/Icon.js +65 -0
  14. package/dist/base/Icon.js.map +1 -0
  15. package/dist/capability/PrivacyPrompt.d.ts +1 -0
  16. package/dist/capability/PrivacyPrompt.js +73 -0
  17. package/dist/capability/PrivacyPrompt.js.map +1 -0
  18. package/dist/capability/types.d.ts +92 -0
  19. package/dist/capability/usePermission.d.ts +23 -0
  20. package/dist/capability/usePermission.js +52 -0
  21. package/dist/capability/usePermission.js.map +1 -0
  22. package/dist/capability/useStorage.d.ts +8 -0
  23. package/dist/capability/useStorage.js +19 -0
  24. package/dist/capability/useStorage.js.map +1 -0
  25. package/dist/capability/web.d.ts +18 -0
  26. package/dist/capability/web.js +109 -0
  27. package/dist/capability/web.js.map +1 -0
  28. package/dist/capacitor/index.d.ts +9 -0
  29. package/dist/capacitor/index.js +143 -0
  30. package/dist/capacitor/index.js.map +1 -0
  31. package/dist/config/ConfigProvider.d.ts +37 -0
  32. package/dist/config/ConfigProvider.js +64 -0
  33. package/dist/config/ConfigProvider.js.map +1 -0
  34. package/dist/config/context.d.ts +16 -0
  35. package/dist/config/context.js +20 -0
  36. package/dist/config/context.js.map +1 -0
  37. package/dist/config/lang.d.ts +85 -0
  38. package/dist/config/lang.js +138 -0
  39. package/dist/config/lang.js.map +1 -0
  40. package/dist/display/Badge.d.ts +39 -0
  41. package/dist/display/Badge.js +108 -0
  42. package/dist/display/Badge.js.map +1 -0
  43. package/dist/display/Cell.d.ts +92 -0
  44. package/dist/display/Cell.js +204 -0
  45. package/dist/display/Cell.js.map +1 -0
  46. package/dist/display/Collapse.d.ts +47 -0
  47. package/dist/display/Collapse.js +173 -0
  48. package/dist/display/Collapse.js.map +1 -0
  49. package/dist/display/Empty.d.ts +42 -0
  50. package/dist/display/Empty.js +79 -0
  51. package/dist/display/Empty.js.map +1 -0
  52. package/dist/display/Grid.d.ts +49 -0
  53. package/dist/display/Grid.js +136 -0
  54. package/dist/display/Grid.js.map +1 -0
  55. package/dist/display/Image.d.ts +70 -0
  56. package/dist/display/Image.js +138 -0
  57. package/dist/display/Image.js.map +1 -0
  58. package/dist/display/IndexBar.d.ts +34 -0
  59. package/dist/display/IndexBar.js +158 -0
  60. package/dist/display/IndexBar.js.map +1 -0
  61. package/dist/display/List.d.ts +34 -0
  62. package/dist/display/List.js +105 -0
  63. package/dist/display/List.js.map +1 -0
  64. package/dist/display/NoticeBar.d.ts +57 -0
  65. package/dist/display/NoticeBar.js +172 -0
  66. package/dist/display/NoticeBar.js.map +1 -0
  67. package/dist/display/Steps.d.ts +59 -0
  68. package/dist/display/Steps.js +158 -0
  69. package/dist/display/Steps.js.map +1 -0
  70. package/dist/display/SwipeCell.d.ts +37 -0
  71. package/dist/display/SwipeCell.js +147 -0
  72. package/dist/display/SwipeCell.js.map +1 -0
  73. package/dist/display/Swiper.d.ts +47 -0
  74. package/dist/display/Swiper.js +173 -0
  75. package/dist/display/Swiper.js.map +1 -0
  76. package/dist/display/Tag.d.ts +99 -0
  77. package/dist/display/Tag.js +320 -0
  78. package/dist/display/Tag.js.map +1 -0
  79. package/dist/feedback/Dialog.d.ts +79 -0
  80. package/dist/feedback/Dialog.js +186 -0
  81. package/dist/feedback/Dialog.js.map +1 -0
  82. package/dist/feedback/FeedbackOutlet.d.ts +2 -0
  83. package/dist/feedback/FeedbackOutlet.js +31 -0
  84. package/dist/feedback/FeedbackOutlet.js.map +1 -0
  85. package/dist/feedback/Loading.d.ts +26 -0
  86. package/dist/feedback/Loading.js +68 -0
  87. package/dist/feedback/Loading.js.map +1 -0
  88. package/dist/feedback/Notify.d.ts +48 -0
  89. package/dist/feedback/Notify.js +116 -0
  90. package/dist/feedback/Notify.js.map +1 -0
  91. package/dist/feedback/PullRefresh.d.ts +58 -0
  92. package/dist/feedback/PullRefresh.js +178 -0
  93. package/dist/feedback/PullRefresh.js.map +1 -0
  94. package/dist/feedback/Skeleton.d.ts +56 -0
  95. package/dist/feedback/Skeleton.js +99 -0
  96. package/dist/feedback/Skeleton.js.map +1 -0
  97. package/dist/feedback/Toast.d.ts +89 -0
  98. package/dist/feedback/Toast.js +186 -0
  99. package/dist/feedback/Toast.js.map +1 -0
  100. package/dist/form/Checkbox.d.ts +52 -0
  101. package/dist/form/Checkbox.js +107 -0
  102. package/dist/form/Checkbox.js.map +1 -0
  103. package/dist/form/Field.d.ts +91 -0
  104. package/dist/form/Field.js +296 -0
  105. package/dist/form/Field.js.map +1 -0
  106. package/dist/form/Form.d.ts +50 -0
  107. package/dist/form/Form.js +96 -0
  108. package/dist/form/Form.js.map +1 -0
  109. package/dist/form/FormItem.d.ts +57 -0
  110. package/dist/form/FormItem.js +142 -0
  111. package/dist/form/FormItem.js.map +1 -0
  112. package/dist/form/Radio.d.ts +41 -0
  113. package/dist/form/Radio.js +85 -0
  114. package/dist/form/Radio.js.map +1 -0
  115. package/dist/form/Rate.d.ts +45 -0
  116. package/dist/form/Rate.js +162 -0
  117. package/dist/form/Rate.js.map +1 -0
  118. package/dist/form/Search.d.ts +50 -0
  119. package/dist/form/Search.js +152 -0
  120. package/dist/form/Search.js.map +1 -0
  121. package/dist/form/Slider.d.ts +43 -0
  122. package/dist/form/Slider.js +213 -0
  123. package/dist/form/Slider.js.map +1 -0
  124. package/dist/form/Stepper.d.ts +61 -0
  125. package/dist/form/Stepper.js +222 -0
  126. package/dist/form/Stepper.js.map +1 -0
  127. package/dist/form/Switch.d.ts +33 -0
  128. package/dist/form/Switch.js +116 -0
  129. package/dist/form/Switch.js.map +1 -0
  130. package/dist/form/Uploader.d.ts +67 -0
  131. package/dist/form/Uploader.js +207 -0
  132. package/dist/form/Uploader.js.map +1 -0
  133. package/dist/form/choice.d.ts +42 -0
  134. package/dist/form/choice.js +109 -0
  135. package/dist/form/choice.js.map +1 -0
  136. package/dist/form/context.d.ts +83 -0
  137. package/dist/form/context.js +89 -0
  138. package/dist/form/context.js.map +1 -0
  139. package/dist/index.d.ts +66 -0
  140. package/dist/index.js +59 -0
  141. package/dist/layout/Divider.d.ts +34 -0
  142. package/dist/layout/Divider.js +55 -0
  143. package/dist/layout/Divider.js.map +1 -0
  144. package/dist/layout/Space.d.ts +66 -0
  145. package/dist/layout/Space.js +65 -0
  146. package/dist/layout/Space.js.map +1 -0
  147. package/dist/navigation/BackTop.d.ts +29 -0
  148. package/dist/navigation/BackTop.js +89 -0
  149. package/dist/navigation/BackTop.js.map +1 -0
  150. package/dist/navigation/NavBar.d.ts +46 -0
  151. package/dist/navigation/NavBar.js +141 -0
  152. package/dist/navigation/NavBar.js.map +1 -0
  153. package/dist/navigation/Sticky.d.ts +19 -0
  154. package/dist/navigation/Sticky.js +28 -0
  155. package/dist/navigation/Sticky.js.map +1 -0
  156. package/dist/navigation/TabBar.d.ts +54 -0
  157. package/dist/navigation/TabBar.js +138 -0
  158. package/dist/navigation/TabBar.js.map +1 -0
  159. package/dist/navigation/Tabs.d.ts +45 -0
  160. package/dist/navigation/Tabs.js +206 -0
  161. package/dist/navigation/Tabs.js.map +1 -0
  162. package/dist/overlay/ActionSheet.d.ts +80 -0
  163. package/dist/overlay/ActionSheet.js +164 -0
  164. package/dist/overlay/ActionSheet.js.map +1 -0
  165. package/dist/overlay/Overlay.d.ts +35 -0
  166. package/dist/overlay/Overlay.js +85 -0
  167. package/dist/overlay/Overlay.js.map +1 -0
  168. package/dist/overlay/Popup.d.ts +76 -0
  169. package/dist/overlay/Popup.js +191 -0
  170. package/dist/overlay/Popup.js.map +1 -0
  171. package/dist/picker/Calendar.d.ts +69 -0
  172. package/dist/picker/Calendar.js +213 -0
  173. package/dist/picker/Calendar.js.map +1 -0
  174. package/dist/picker/Cascader.d.ts +50 -0
  175. package/dist/picker/Cascader.js +199 -0
  176. package/dist/picker/Cascader.js.map +1 -0
  177. package/dist/picker/DatePicker.d.ts +52 -0
  178. package/dist/picker/DatePicker.js +135 -0
  179. package/dist/picker/DatePicker.js.map +1 -0
  180. package/dist/picker/DropdownMenu.d.ts +39 -0
  181. package/dist/picker/DropdownMenu.js +242 -0
  182. package/dist/picker/DropdownMenu.js.map +1 -0
  183. package/dist/picker/Picker.d.ts +67 -0
  184. package/dist/picker/Picker.js +185 -0
  185. package/dist/picker/Picker.js.map +1 -0
  186. package/dist/picker/PickerColumn.d.ts +36 -0
  187. package/dist/picker/PickerColumn.js +175 -0
  188. package/dist/picker/PickerColumn.js.map +1 -0
  189. package/dist/theme/dark.d.ts +121 -0
  190. package/dist/theme/dark.js +77 -0
  191. package/dist/theme/dark.js.map +1 -0
  192. package/dist/theme/divider.d.ts +6 -0
  193. package/dist/theme/divider.js +18 -0
  194. package/dist/theme/divider.js.map +1 -0
  195. package/dist/theme/token-names.d.ts +1389 -0
  196. package/dist/theme/tokens.d.ts +549 -0
  197. package/dist/theme/tokens.js +312 -0
  198. package/dist/theme/tokens.js.map +1 -0
  199. package/dist/utils/host.d.ts +97 -0
  200. package/dist/utils/host.js +98 -0
  201. package/dist/utils/host.js.map +1 -0
  202. package/dist/utils/presence.d.ts +11 -0
  203. package/dist/utils/presence.js +34 -0
  204. package/dist/utils/presence.js.map +1 -0
  205. package/dist/utils/props.d.ts +38 -0
  206. package/dist/utils/props.js +115 -0
  207. package/dist/utils/props.js.map +1 -0
  208. package/dist/utils/scales.d.ts +48 -0
  209. package/package.json +106 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Slider.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/form/Slider.tsx"],"sourcesContent":["/**\n * 滑块:在一段范围里拖动选一个数(音量、价格上限),给两个数时是区间(价格区间)。点轨道直接跳过去。\n *\n * <Slider _value={volume} />\n * <Slider _value={price} min={0} max={1000} step={50} /> price 是 [200, 600] 时两个滑块\n *\n * 拖动时值跟着变,松手时 onChange;横滑才接管手势,竖滑照常滚动页面。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { useHost, type HostRect } from '../utils/host';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\nimport { useForm } from './context';\n\n/** 一个数,或区间的两端 */\nexport type SliderValue = number | [number, number];\n\n/** 未声明的属性落到根元素(div)上 */\nexport interface SliderProps extends Omit<PartProps<'div'>, 'onChange'> {\n /** 当前的值;双向绑定写 `_value={x}`。数组时是区间 */\n _value?: SliderValue;\n /**\n * 最小值\n * @default 0\n */\n min?: number;\n /**\n * 最大值\n * @default 100\n */\n max?: number;\n /**\n * 步长\n * @default 1\n */\n step?: number;\n /** 禁用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 松手(或点了轨道、按了方向键)之后 */\n onChange?: (value: SliderValue) => void;\n /** 轨道的部件属性 */\n propsTrack?: PartProps<'div'>;\n /** 滑块(两个时都用)的部件属性 */\n propsThumb?: PartProps<'div'>;\n}\n\n/** Slider 的样式:root、track、fill、thumb */\nexport const sliderStyles = css.create({\n root: {\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n height: '2em',\n // 两端留出半个滑块,滑块不出界\n paddingInline: '0.75em',\n touchAction: 'pan-y',\n userSelect: 'none',\n opacity: { default: 1, '[data-disabled]': '_disabled' },\n },\n track: {\n position: 'relative',\n flex: '1 1 auto',\n height: '0.25em',\n borderRadius: '_full',\n backgroundColor: '_fillActive',\n },\n fill: { position: 'absolute', insetBlock: 0, borderRadius: '_full', backgroundColor: '_accent' },\n thumb: {\n boxSizing: 'border-box',\n position: 'absolute',\n insetBlockStart: '50%',\n width: '1.5em',\n height: '1.5em',\n borderRadius: '_full',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n // 滑块在亮暗两套主题里都是白的(同 Switch 的圆点)\n backgroundColor: '#fff',\n boxShadow: '_sm',\n transform: 'translate(-50%, -50%)',\n cursor: { default: 'grab', '[data-disabled]': 'not-allowed' },\n },\n});\n\n// 判定横竖的移动距离(px)\nconst LOCK_DISTANCE = 6;\n\n/** 滑块(div > 轨道:已选的一段 + 滑块) */\nexport const Slider = _component(\n ({\n _value: value = _bindable<SliderValue>(0),\n min = 0,\n max = 100,\n step = 1,\n disabled,\n readonly = false,\n onChange,\n propsTrack,\n propsThumb,\n ...rest\n }: SliderProps) => {\n const host = useHost();\n const form = useForm();\n let track: unknown = null;\n let rect: HostRect | null = null;\n let horizontal = _state(false);\n let start = { x: 0, y: 0 };\n let direction: 'h' | 'v' | null = null;\n // 拖的是区间的哪一端\n let active = 0;\n\n const interactive = () => !(disabled ?? form?.disabled) && !readonly && !form?.readonly;\n const ends = (): [number, number] => (Array.isArray(value) ? value : [min, value]);\n const percent = (number: number) => ((number - min) / (max - min || 1)) * 100;\n const snap = (number: number) => {\n const stepped = Math.round((number - min) / step) * step + min;\n return Number(Math.min(max, Math.max(min, stepped)).toFixed(10));\n };\n const valueAt = (x: number) =>\n rect ? snap(min + ((x - rect.left) / (rect.width || 1)) * (max - min)) : null;\n /** 把一端改成 next:区间两端交叉时换成拖另一端 */\n const setEnd = (index: number, next: number) => {\n if (!Array.isArray(value)) return void (value = next);\n const pair: [number, number] = [...value];\n pair[index] = next;\n if (pair[0] > pair[1]) {\n pair.reverse();\n active = 1 - index;\n }\n value = pair;\n };\n const nearest = (number: number) => {\n if (!Array.isArray(value)) return 0;\n return Math.abs(number - value[0]) <= Math.abs(number - value[1]) ? 0 : 1;\n };\n const pointX = (event: Event) =>\n (event as TouchEvent).changedTouches?.[0]?.clientX ?? (event as MouseEvent).clientX;\n\n const onTouchstart = (event: TouchEvent) => {\n if (!interactive()) return;\n const touch = event.touches[0]!;\n start = { x: touch.clientX, y: touch.clientY };\n direction = null;\n void host.measure(track).then((measured) => (rect = measured));\n };\n const onTouchmove = (event: TouchEvent) => {\n if (!interactive() || !rect) return;\n const touch = event.touches[0]!;\n if (!direction) {\n const dx = touch.clientX - start.x;\n const dy = touch.clientY - start.y;\n if (Math.abs(dx) < LOCK_DISTANCE && Math.abs(dy) < LOCK_DISTANCE) return;\n direction = Math.abs(dx) > Math.abs(dy) ? 'h' : 'v';\n horizontal = direction === 'h';\n if (horizontal) active = nearest(valueAt(start.x) ?? min);\n }\n if (direction !== 'h') return;\n const next = valueAt(touch.clientX);\n if (next !== null) setEnd(active, next);\n };\n const onTouchend = () => {\n if (horizontal) onChange?.(value);\n horizontal = false;\n };\n // 点轨道:跳到点的位置(滑动不触发点击)\n const onClick = (event: Event) => {\n if (!interactive()) return;\n const x = pointX(event);\n void host.measure(track).then((measured) => {\n rect = measured;\n const next = valueAt(x);\n if (next === null) return;\n active = nearest(next);\n setEnd(active, next);\n onChange?.(value);\n });\n };\n const onKeydown = (index: number, event: KeyboardEvent) => {\n if (!interactive()) return;\n const delta = { ArrowRight: step, ArrowUp: step, ArrowLeft: -step, ArrowDown: -step }[\n event.key\n ];\n if (delta === undefined) return;\n event.preventDefault();\n setEnd(index, snap(ends()[index]! + delta));\n onChange?.(value);\n };\n\n return () => {\n const off = !interactive();\n const [low, high] = ends();\n const range = Array.isArray(value);\n const thumbs = range ? [low, high] : [high];\n return (\n <div\n {...mergeAttrs<'div'>({ sx: sliderStyles.root }, rest, {\n onTouchstart,\n onTouchmove,\n onTouchend,\n onTouchcancel: onTouchend,\n onClick,\n ...dataAttrs({\n // 小程序:收 touchmove;横滑期间 catch,页面不跟着滚\n 'data-touch-move': horizontal ? 'catch' : true,\n 'data-disabled': disabled ?? form?.disabled,\n }),\n })}\n >\n <div\n {...mergeAttrs<'div'>({ sx: sliderStyles.track }, propsTrack)}\n ref={(node: unknown) => (track = node)}\n >\n <div\n {...mergeAttrs<'div'>({\n sx: sliderStyles.fill,\n style: {\n insetInlineStart: `${range ? percent(low) : 0}%`,\n width: `${percent(high) - (range ? percent(low) : 0)}%`,\n },\n })}\n />\n {thumbs.map((number, index) => (\n <div\n {...mergeAttrs<'div'>(\n { sx: sliderStyles.thumb, style: { insetInlineStart: `${percent(number)}%` } },\n propsThumb,\n {\n role: 'slider',\n tabindex: off ? undefined : 0,\n 'aria-valuemin': min,\n 'aria-valuemax': max,\n 'aria-valuenow': number,\n 'aria-disabled': off ? 'true' : undefined,\n onKeydown: (event: KeyboardEvent) => onKeydown(range ? index : 1, event),\n ...dataAttrs({ 'data-disabled': off }),\n },\n )}\n />\n ))}\n </div>\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
+ import { type PartProps } from '../utils/props';
3
+ /** 外观 */
4
+ export interface StepperThemes {
5
+ /** 方块按钮,浅灰底(默认) */
6
+ default: unknown;
7
+ /** 圆按钮:减号描边、加号实底 */
8
+ round: unknown;
9
+ }
10
+ /** 未声明的属性落到根元素(div)上 */
11
+ export interface StepperProps extends Omit<PartProps<'div', 'role'>, 'onChange'> {
12
+ /** 当前的数;双向绑定写 `_value={x}` */
13
+ _value?: number;
14
+ /**
15
+ * 最小值
16
+ * @default 1
17
+ */
18
+ min?: number;
19
+ /** 最大值 */
20
+ max?: number;
21
+ /**
22
+ * 每次加减多少
23
+ * @default 1
24
+ */
25
+ step?: number;
26
+ /** 保留几位小数;不给时按 step 的小数位 */
27
+ decimalLength?: number;
28
+ /**
29
+ * 外观
30
+ * @default 'default'
31
+ */
32
+ theme?: keyof StepperThemes;
33
+ /** 禁用 */
34
+ disabled?: boolean;
35
+ /** 中间的数不能直接输入(只能点加减) */
36
+ disableInput?: boolean;
37
+ /**
38
+ * 按住加减号时连续变化
39
+ * @default true
40
+ */
41
+ longPress?: boolean;
42
+ /** 数变了 */
43
+ onChange?: (value: number) => void;
44
+ /** 减号按钮的部件属性 */
45
+ propsMinus?: PartProps<'button'>;
46
+ /** 加号按钮的部件属性 */
47
+ propsPlus?: PartProps<'button'>;
48
+ /** 输入框的部件属性 */
49
+ propsInput?: PartProps<'input', 'value' | 'disabled' | 'readonly' | 'inputmode'>;
50
+ }
51
+ /** Stepper 的样式:root、button、round、plusRound、input */
52
+ export declare const stepperStyles: Readonly<{
53
+ button: css.CompiledStyles;
54
+ input: css.CompiledStyles;
55
+ inputRound: css.CompiledStyles;
56
+ plusRound: css.CompiledStyles;
57
+ root: css.CompiledStyles;
58
+ round: css.CompiledStyles;
59
+ }>;
60
+ /** 步进器(div > 减号 + 输入框 + 加号) */
61
+ export declare const Stepper: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<StepperProps>;
@@ -0,0 +1,222 @@
1
+ import { useConfig } from "../config/context.js";
2
+ import { dataAttrs, mergeAttrs } from "../utils/props.js";
3
+ import { Icon } from "../base/Icon.js";
4
+ import { useForm } from "./context.js";
5
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
6
+ import { _component, bindable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
7
+ import { createVNode, onBeforeUnmount, ref } from "vue";
8
+ import { Minus, Plus } from "@lucide/icons";
9
+ //#region src/form/Stepper.tsx
10
+ /**
11
+ * 步进器:减号、数字、加号,调整数量(购物车的件数、人数)。按住加减号连续变化;中间的数字也可以直接输入,失焦时按范围修正。
12
+ *
13
+ * <Stepper _value={count} min={1} max={99} />
14
+ * <Stepper _value={weight} step={0.5} decimalLength={1} theme="round" />
15
+ */
16
+ /** 外观 */
17
+ /** 未声明的属性落到根元素(div)上 */
18
+ /** Stepper 的样式:root、button、round、plusRound、input */
19
+ var stepperStyles = css.create({
20
+ root: {
21
+ display: "inline-flex",
22
+ alignItems: "center",
23
+ gap: "0.15em",
24
+ verticalAlign: "middle"
25
+ },
26
+ button: {
27
+ boxSizing: "border-box",
28
+ display: "inline-flex",
29
+ alignItems: "center",
30
+ justifyContent: "center",
31
+ width: "2em",
32
+ height: "2em",
33
+ margin: 0,
34
+ padding: 0,
35
+ borderWidth: 0,
36
+ borderRadius: "_sm",
37
+ backgroundColor: {
38
+ default: "_fill",
39
+ ":active:not([disabled])": "_fillActive"
40
+ },
41
+ color: {
42
+ default: "_text",
43
+ "[disabled]": "_textDisabled"
44
+ },
45
+ fontSize: "1em",
46
+ cursor: {
47
+ default: "pointer",
48
+ "[disabled]": "not-allowed"
49
+ },
50
+ userSelect: "none"
51
+ },
52
+ round: {
53
+ borderRadius: "_full",
54
+ borderWidth: "_xs",
55
+ borderStyle: "solid",
56
+ borderColor: {
57
+ default: "_accent",
58
+ "[disabled]": "_border"
59
+ },
60
+ backgroundColor: {
61
+ default: "_surface",
62
+ ":active:not([disabled])": "_accentSoft"
63
+ },
64
+ color: {
65
+ default: "_accentText",
66
+ "[disabled]": "_textDisabled"
67
+ }
68
+ },
69
+ plusRound: {
70
+ backgroundColor: {
71
+ default: "_accent",
72
+ ":active:not([disabled])": "_accentActive",
73
+ "[disabled]": "_fill"
74
+ },
75
+ color: {
76
+ default: "_accentContrast",
77
+ "[disabled]": "_textDisabled"
78
+ }
79
+ },
80
+ input: {
81
+ boxSizing: "border-box",
82
+ width: "2.6em",
83
+ height: "2em",
84
+ margin: 0,
85
+ padding: 0,
86
+ borderWidth: 0,
87
+ borderRadius: "_sm",
88
+ backgroundColor: "_fill",
89
+ color: {
90
+ default: "_text",
91
+ "[disabled]": "_textDisabled"
92
+ },
93
+ fontFamily: "inherit",
94
+ fontSize: "inherit",
95
+ textAlign: "center",
96
+ outlineStyle: "none"
97
+ },
98
+ inputRound: { backgroundColor: "transparent" }
99
+ });
100
+ /** 按住多久开始连续变化、之后每隔多久变一次(ms) */
101
+ var HOLD_DELAY = 500;
102
+ var REPEAT_INTERVAL = 150;
103
+ /** 小数位:step 是 0.5 时是 1 */
104
+ var decimalsOf = (step) => (String(step).split(".")[1] ?? "").length;
105
+ /** 步进器(div > 减号 + 输入框 + 加号) */
106
+ var Stepper = /*#__PURE__*/ _component((_props, _ctx) => {
107
+ const value = bindable(_props, "_value", () => 1, _ctx.emit);
108
+ const min = readonlyProp(_props, "min", 1);
109
+ const max = readonlyProp(_props, "max", () => Number.POSITIVE_INFINITY);
110
+ const step = readonlyProp(_props, "step", 1);
111
+ const decimalLength = readonlyProp(_props, "decimalLength");
112
+ const theme = readonlyProp(_props, "theme", "default");
113
+ const disabled = readonlyProp(_props, "disabled");
114
+ const disableInput = readonlyProp(_props, "disableInput", false);
115
+ const longPress = readonlyProp(_props, "longPress", true);
116
+ const onChange = readonlyProp(_props, "onChange");
117
+ const propsMinus = readonlyProp(_props, "propsMinus");
118
+ const propsPlus = readonlyProp(_props, "propsPlus");
119
+ const propsInput = readonlyProp(_props, "propsInput");
120
+ const rest = restProps(_props, _ctx, true);
121
+ const config = useConfig();
122
+ const form = useForm();
123
+ let draft = ref(null);
124
+ const digits = () => decimalLength.value ?? decimalsOf(step.value);
125
+ const clamp = (next) => {
126
+ const bounded = Math.min(max.value, Math.max(min.value, next));
127
+ return Number(bounded.toFixed(digits()));
128
+ };
129
+ const set = (next) => {
130
+ const fixed = clamp(next);
131
+ if (fixed === value.value) return;
132
+ value.value = fixed;
133
+ onChange.value?.(fixed);
134
+ };
135
+ const isDisabled = () => disabled.value ?? form?.disabled ?? false;
136
+ let holdTimer;
137
+ let repeatTimer;
138
+ let held = false;
139
+ const stopHold = () => {
140
+ clearTimeout(holdTimer);
141
+ clearInterval(repeatTimer);
142
+ };
143
+ onBeforeUnmount(stopHold);
144
+ const startHold = (direction) => {
145
+ held = false;
146
+ if (!longPress.value) return;
147
+ stopHold();
148
+ holdTimer = setTimeout(() => {
149
+ held = true;
150
+ repeatTimer = setInterval(() => set(value.value + direction * step.value), REPEAT_INTERVAL);
151
+ }, HOLD_DELAY);
152
+ };
153
+ const button = (direction) => {
154
+ const off = isDisabled() || form?.readonly || (direction < 0 ? value.value <= min.value : value.value >= max.value) || false;
155
+ return createVNode("button", mergeAttrs({ sx: [
156
+ stepperStyles.button,
157
+ theme.value === "round" && stepperStyles.round,
158
+ theme.value === "round" && direction > 0 && stepperStyles.plusRound
159
+ ] }, direction > 0 ? propsPlus.value : propsMinus.value, {
160
+ type: "button",
161
+ disabled: off,
162
+ "aria-label": direction > 0 ? config.lang.increase : config.lang.decrease,
163
+ onTouchstart: () => startHold(direction),
164
+ onTouchend: stopHold,
165
+ onTouchcancel: stopHold,
166
+ onClick: () => {
167
+ if (held) return void (held = false);
168
+ set(value.value + direction * step.value);
169
+ }
170
+ }), [createVNode(Icon, { "icon": direction > 0 ? Plus : Minus }, null)]);
171
+ };
172
+ return () => {
173
+ const off = isDisabled();
174
+ return createVNode("div", mergeAttrs({ sx: stepperStyles.root }, rest, {
175
+ role: "group",
176
+ ...dataAttrs({ "data-disabled": off })
177
+ }), [
178
+ button(-1),
179
+ createVNode("input", mergeAttrs({ sx: [stepperStyles.input, theme.value === "round" && stepperStyles.inputRound] }, propsInput.value, {
180
+ value: draft.value ?? value.value.toFixed(digits()),
181
+ type: "text",
182
+ inputmode: digits() > 0 || min.value < 0 ? "decimal" : "numeric",
183
+ disabled: off,
184
+ readonly: disableInput.value || form?.readonly,
185
+ "aria-valuemin": min.value,
186
+ "aria-valuemax": Number.isFinite(max.value) ? max.value : void 0,
187
+ "aria-valuenow": value.value,
188
+ role: "spinbutton",
189
+ onInput: (event) => draft.value = event.target.value,
190
+ onBlur: () => {
191
+ if (draft.value === null) return;
192
+ const parsed = Number.parseFloat(draft.value);
193
+ draft.value = null;
194
+ if (!Number.isNaN(parsed)) set(parsed);
195
+ }
196
+ }), null),
197
+ button(1)
198
+ ]);
199
+ };
200
+ }, {
201
+ name: "Stepper",
202
+ props: [
203
+ "_value",
204
+ "onUpdate:_value",
205
+ "min",
206
+ "max",
207
+ "step",
208
+ "decimalLength",
209
+ "theme",
210
+ "disabled",
211
+ "disableInput",
212
+ "longPress",
213
+ "onChange",
214
+ "propsMinus",
215
+ "propsPlus",
216
+ "propsInput"
217
+ ]
218
+ });
219
+ //#endregion
220
+ export { Stepper, stepperStyles };
221
+
222
+ //# sourceMappingURL=Stepper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Stepper.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_ref","_createVNode"],"sources":["../../src/form/Stepper.tsx"],"sourcesContent":["/**\n * 步进器:减号、数字、加号,调整数量(购物车的件数、人数)。按住加减号连续变化;中间的数字也可以直接输入,失焦时按范围修正。\n *\n * <Stepper _value={count} min={1} max={99} />\n * <Stepper _value={weight} step={0.5} decimalLength={1} theme=\"round\" />\n */\nimport { Minus, Plus } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { onBeforeUnmount } from 'vue';\nimport { Icon } from '../base/Icon';\nimport { useConfig } from '../config/context';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\nimport { useForm } from './context';\n\n/** 外观 */\nexport interface StepperThemes {\n /** 方块按钮,浅灰底(默认) */\n default: unknown;\n /** 圆按钮:减号描边、加号实底 */\n round: unknown;\n}\n\n/** 未声明的属性落到根元素(div)上 */\nexport interface StepperProps extends Omit<PartProps<'div', 'role'>, 'onChange'> {\n /** 当前的数;双向绑定写 `_value={x}` */\n _value?: number;\n /**\n * 最小值\n * @default 1\n */\n min?: number;\n /** 最大值 */\n max?: number;\n /**\n * 每次加减多少\n * @default 1\n */\n step?: number;\n /** 保留几位小数;不给时按 step 的小数位 */\n decimalLength?: number;\n /**\n * 外观\n * @default 'default'\n */\n theme?: keyof StepperThemes;\n /** 禁用 */\n disabled?: boolean;\n /** 中间的数不能直接输入(只能点加减) */\n disableInput?: boolean;\n /**\n * 按住加减号时连续变化\n * @default true\n */\n longPress?: boolean;\n /** 数变了 */\n onChange?: (value: number) => void;\n /** 减号按钮的部件属性 */\n propsMinus?: PartProps<'button'>;\n /** 加号按钮的部件属性 */\n propsPlus?: PartProps<'button'>;\n /** 输入框的部件属性 */\n propsInput?: PartProps<'input', 'value' | 'disabled' | 'readonly' | 'inputmode'>;\n}\n\n/** Stepper 的样式:root、button、round、plusRound、input */\nexport const stepperStyles = css.create({\n root: { display: 'inline-flex', alignItems: 'center', gap: '0.15em', verticalAlign: 'middle' },\n button: {\n boxSizing: 'border-box',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '2em',\n height: '2em',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n borderRadius: '_sm',\n backgroundColor: { default: '_fill', ':active:not([disabled])': '_fillActive' },\n color: { default: '_text', '[disabled]': '_textDisabled' },\n fontSize: '1em',\n cursor: { default: 'pointer', '[disabled]': 'not-allowed' },\n userSelect: 'none',\n },\n round: {\n borderRadius: '_full',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: { default: '_accent', '[disabled]': '_border' },\n backgroundColor: { default: '_surface', ':active:not([disabled])': '_accentSoft' },\n color: { default: '_accentText', '[disabled]': '_textDisabled' },\n },\n plusRound: {\n backgroundColor: {\n default: '_accent',\n ':active:not([disabled])': '_accentActive',\n '[disabled]': '_fill',\n },\n color: { default: '_accentContrast', '[disabled]': '_textDisabled' },\n },\n input: {\n boxSizing: 'border-box',\n width: '2.6em',\n height: '2em',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n borderRadius: '_sm',\n backgroundColor: '_fill',\n color: { default: '_text', '[disabled]': '_textDisabled' },\n fontFamily: 'inherit',\n fontSize: 'inherit',\n textAlign: 'center',\n outlineStyle: 'none',\n },\n inputRound: { backgroundColor: 'transparent' },\n});\n\n/** 按住多久开始连续变化、之后每隔多久变一次(ms) */\nconst HOLD_DELAY = 500;\nconst REPEAT_INTERVAL = 150;\n\n/** 小数位:step 是 0.5 时是 1 */\nconst decimalsOf = (step: number) => (String(step).split('.')[1] ?? '').length;\n\n/** 步进器(div > 减号 + 输入框 + 加号) */\nexport const Stepper = _component(\n ({\n _value: value = _bindable(1),\n min = 1,\n max = Number.POSITIVE_INFINITY,\n step = 1,\n decimalLength,\n theme = 'default',\n disabled,\n disableInput = false,\n longPress = true,\n onChange,\n propsMinus,\n propsPlus,\n propsInput,\n ...rest\n }: StepperProps) => {\n const config = useConfig();\n const form = useForm();\n // 正在输入的文字:失焦时才换成数\n let draft = _state<string | null>(null);\n const digits = () => decimalLength ?? decimalsOf(step);\n const clamp = (next: number) => {\n const bounded = Math.min(max, Math.max(min, next));\n return Number(bounded.toFixed(digits()));\n };\n const set = (next: number) => {\n const fixed = clamp(next);\n if (fixed === value) return;\n value = fixed;\n onChange?.(fixed);\n };\n const isDisabled = () => disabled ?? form?.disabled ?? false;\n\n // 按住连续加减;连续变化过之后松手,那一次点击不再算\n let holdTimer: ReturnType<typeof setTimeout> | undefined;\n let repeatTimer: ReturnType<typeof setInterval> | undefined;\n let held = false;\n const stopHold = () => {\n clearTimeout(holdTimer);\n clearInterval(repeatTimer);\n };\n onBeforeUnmount(stopHold);\n const startHold = (direction: 1 | -1) => {\n held = false;\n if (!longPress) return;\n stopHold();\n holdTimer = setTimeout(() => {\n held = true;\n repeatTimer = setInterval(() => set(value + direction * step), REPEAT_INTERVAL);\n }, HOLD_DELAY);\n };\n\n const button = (direction: 1 | -1) => {\n const off =\n isDisabled() || form?.readonly || (direction < 0 ? value <= min : value >= max) || false;\n return (\n <button\n {...mergeAttrs<'button'>(\n {\n sx: [\n stepperStyles.button,\n theme === 'round' && stepperStyles.round,\n theme === 'round' && direction > 0 && stepperStyles.plusRound,\n ],\n },\n direction > 0 ? propsPlus : propsMinus,\n {\n type: 'button',\n disabled: off,\n 'aria-label': direction > 0 ? config.lang.increase : config.lang.decrease,\n onTouchstart: () => startHold(direction),\n onTouchend: stopHold,\n onTouchcancel: stopHold,\n onClick: () => {\n if (held) return void (held = false);\n set(value + direction * step);\n },\n },\n )}\n >\n <Icon icon={direction > 0 ? Plus : Minus} />\n </button>\n );\n };\n\n return () => {\n const off = isDisabled();\n return (\n <div\n {...mergeAttrs<'div'>({ sx: stepperStyles.root }, rest, {\n role: 'group',\n ...dataAttrs({ 'data-disabled': off }),\n })}\n >\n {button(-1)}\n <input\n {...mergeAttrs<'input'>(\n { sx: [stepperStyles.input, theme === 'round' && stepperStyles.inputRound] },\n propsInput,\n {\n value: draft ?? value.toFixed(digits()),\n type: 'text',\n inputmode: digits() > 0 || min < 0 ? 'decimal' : 'numeric',\n disabled: off,\n readonly: disableInput || form?.readonly,\n 'aria-valuemin': min,\n 'aria-valuemax': Number.isFinite(max) ? max : undefined,\n 'aria-valuenow': value,\n role: 'spinbutton',\n onInput: (event: Event) => (draft = (event.target as HTMLInputElement).value),\n onBlur: () => {\n if (draft === null) return;\n const parsed = Number.parseFloat(draft);\n draft = null;\n if (!Number.isNaN(parsed)) set(parsed);\n },\n },\n )}\n />\n {button(1)}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
+ import { type PartProps } from '../utils/props';
3
+ /** 角色与状态由组件管理 */
4
+ export type SwitchManaged = 'role' | 'aria-checked' | 'type' | 'disabled';
5
+ /** 未声明的属性落到按钮上 */
6
+ export interface SwitchProps extends Omit<PartProps<'button', SwitchManaged>, 'onChange'> {
7
+ /** 是否打开;双向绑定写 `_checked={x}` */
8
+ _checked?: boolean;
9
+ /**
10
+ * 打开时的色调
11
+ * @default 'accent'
12
+ */
13
+ tone?: 'accent' | 'success' | 'warning' | 'danger';
14
+ /** 加载中:圆点里转圈,不能切换 */
15
+ loading?: boolean;
16
+ /** 禁用;在 Form 里时随 Form */
17
+ disabled?: boolean;
18
+ /** 切换了 */
19
+ onChange?: (checked: boolean) => void;
20
+ /** 圆点的部件属性 */
21
+ propsThumb?: PartProps<'span'>;
22
+ }
23
+ /** Switch 的样式:root、各色调、thumb、spinner */
24
+ export declare const switchStyles: Readonly<{
25
+ accent: css.CompiledStyles;
26
+ danger: css.CompiledStyles;
27
+ root: css.CompiledStyles;
28
+ success: css.CompiledStyles;
29
+ thumb: css.CompiledStyles;
30
+ warning: css.CompiledStyles;
31
+ }>;
32
+ /** 开关(button[role=switch] > 圆点) */
33
+ export declare const Switch: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<SwitchProps>;
@@ -0,0 +1,116 @@
1
+ import { dataAttrs, mergeAttrs } from "../utils/props.js";
2
+ import { Loading } from "../feedback/Loading.js";
3
+ import { useForm } from "./context.js";
4
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
5
+ import { _component, bindable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
6
+ import { createVNode } from "vue";
7
+ //#region src/form/Switch.tsx
8
+ /** 角色与状态由组件管理 */
9
+ /** 未声明的属性落到按钮上 */
10
+ /** Switch 的样式:root、各色调、thumb、spinner */
11
+ var switchStyles = css.create({
12
+ root: {
13
+ boxSizing: "border-box",
14
+ position: "relative",
15
+ display: "inline-block",
16
+ flex: "none",
17
+ width: "3.1em",
18
+ height: "1.85em",
19
+ margin: 0,
20
+ padding: 0,
21
+ borderWidth: 0,
22
+ borderRadius: "_full",
23
+ verticalAlign: "middle",
24
+ cursor: {
25
+ default: "pointer",
26
+ "[data-disabled]": "not-allowed"
27
+ },
28
+ opacity: {
29
+ default: 1,
30
+ "[data-disabled]": "_disabled"
31
+ },
32
+ transitionProperty: "background-color",
33
+ transitionDuration: "_md"
34
+ },
35
+ accent: { backgroundColor: {
36
+ default: "_fillActive",
37
+ "[aria-checked=\"true\"]": "_accent"
38
+ } },
39
+ success: { backgroundColor: {
40
+ default: "_fillActive",
41
+ "[aria-checked=\"true\"]": "_success"
42
+ } },
43
+ warning: { backgroundColor: {
44
+ default: "_fillActive",
45
+ "[aria-checked=\"true\"]": "_warning"
46
+ } },
47
+ danger: { backgroundColor: {
48
+ default: "_fillActive",
49
+ "[aria-checked=\"true\"]": "_danger"
50
+ } },
51
+ thumb: {
52
+ boxSizing: "border-box",
53
+ position: "absolute",
54
+ insetBlockStart: "0.15em",
55
+ insetInlineStart: "0.15em",
56
+ display: "flex",
57
+ alignItems: "center",
58
+ justifyContent: "center",
59
+ width: "1.55em",
60
+ height: "1.55em",
61
+ borderRadius: "_full",
62
+ backgroundColor: "#fff",
63
+ boxShadow: "_sm",
64
+ color: "_accent",
65
+ fontSize: "1em",
66
+ transform: {
67
+ default: "none",
68
+ "[data-checked]": "translateX(1.25em)"
69
+ },
70
+ transitionProperty: "transform",
71
+ transitionDuration: "_md",
72
+ transitionTimingFunction: "_standard"
73
+ }
74
+ });
75
+ /** 开关(button[role=switch] > 圆点) */
76
+ var Switch = /*#__PURE__*/ _component((_props, _ctx) => {
77
+ const checked = bindable(_props, "_checked", () => false, _ctx.emit);
78
+ const tone = readonlyProp(_props, "tone", "accent");
79
+ const loading = readonlyProp(_props, "loading", false);
80
+ const disabled = readonlyProp(_props, "disabled");
81
+ const onChange = readonlyProp(_props, "onChange");
82
+ const propsThumb = readonlyProp(_props, "propsThumb");
83
+ const rest = restProps(_props, _ctx, true);
84
+ const form = useForm();
85
+ return () => {
86
+ const off = disabled.value ?? form?.disabled ?? false;
87
+ return createVNode("button", mergeAttrs({ sx: [switchStyles.root, switchStyles[tone.value]] }, rest, {
88
+ type: "button",
89
+ role: "switch",
90
+ "aria-checked": checked.value ? "true" : "false",
91
+ "aria-busy": loading.value ? "true" : void 0,
92
+ disabled: off,
93
+ onClick: () => {
94
+ if (loading.value || form?.readonly) return;
95
+ checked.value = !checked.value;
96
+ onChange.value?.(checked.value);
97
+ },
98
+ ...dataAttrs({ "data-disabled": off })
99
+ }), [createVNode("span", mergeAttrs({ sx: switchStyles.thumb }, propsThumb.value, dataAttrs({ "data-checked": checked.value })), [loading.value && createVNode(Loading, { "size": 14 }, null)])]);
100
+ };
101
+ }, {
102
+ name: "Switch",
103
+ props: [
104
+ "_checked",
105
+ "onUpdate:_checked",
106
+ "tone",
107
+ "loading",
108
+ "disabled",
109
+ "onChange",
110
+ "propsThumb"
111
+ ]
112
+ });
113
+ //#endregion
114
+ export { Switch, switchStyles };
115
+
116
+ //# sourceMappingURL=Switch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Switch.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_createVNode"],"sources":["../../src/form/Switch.tsx"],"sourcesContent":["/**\n * 开关:两种状态之间切换,立刻生效(消息通知、深色模式)。要提交了才生效的选项用 Checkbox。\n *\n * <Switch _checked={notify} aria-label=\"消息通知\" />\n * <Switch _checked={autoRenew} loading={saving} onChange={(on) => save(on)} />\n *\n * 大小随所在文字(em),整体缩放写 sx 的 fontSize。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Loading } from '../feedback/Loading';\nimport { useForm } from './context';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\n\n/** 角色与状态由组件管理 */\nexport type SwitchManaged = 'role' | 'aria-checked' | 'type' | 'disabled';\n\n/** 未声明的属性落到按钮上 */\nexport interface SwitchProps extends Omit<PartProps<'button', SwitchManaged>, 'onChange'> {\n /** 是否打开;双向绑定写 `_checked={x}` */\n _checked?: boolean;\n /**\n * 打开时的色调\n * @default 'accent'\n */\n tone?: 'accent' | 'success' | 'warning' | 'danger';\n /** 加载中:圆点里转圈,不能切换 */\n loading?: boolean;\n /** 禁用;在 Form 里时随 Form */\n disabled?: boolean;\n /** 切换了 */\n onChange?: (checked: boolean) => void;\n /** 圆点的部件属性 */\n propsThumb?: PartProps<'span'>;\n}\n\n/** Switch 的样式:root、各色调、thumb、spinner */\nexport const switchStyles = css.create({\n root: {\n boxSizing: 'border-box',\n position: 'relative',\n display: 'inline-block',\n flex: 'none',\n width: '3.1em',\n height: '1.85em',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n borderRadius: '_full',\n verticalAlign: 'middle',\n cursor: { default: 'pointer', '[data-disabled]': 'not-allowed' },\n opacity: { default: 1, '[data-disabled]': '_disabled' },\n transitionProperty: 'background-color',\n transitionDuration: '_md',\n },\n accent: { backgroundColor: { default: '_fillActive', '[aria-checked=\"true\"]': '_accent' } },\n success: { backgroundColor: { default: '_fillActive', '[aria-checked=\"true\"]': '_success' } },\n warning: { backgroundColor: { default: '_fillActive', '[aria-checked=\"true\"]': '_warning' } },\n danger: { backgroundColor: { default: '_fillActive', '[aria-checked=\"true\"]': '_danger' } },\n thumb: {\n boxSizing: 'border-box',\n position: 'absolute',\n insetBlockStart: '0.15em',\n insetInlineStart: '0.15em',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '1.55em',\n height: '1.55em',\n borderRadius: '_full',\n // 圆点在亮暗两套主题里都是白的(同系统的开关)\n backgroundColor: '#fff',\n boxShadow: '_sm',\n color: '_accent',\n fontSize: '1em',\n transform: { default: 'none', '[data-checked]': 'translateX(1.25em)' },\n transitionProperty: 'transform',\n transitionDuration: '_md',\n transitionTimingFunction: '_standard',\n },\n});\n\n/** 开关(button[role=switch] > 圆点) */\nexport const Switch = _component(\n ({\n _checked: checked = _bindable(false),\n tone = 'accent',\n loading = false,\n disabled,\n onChange,\n propsThumb,\n ...rest\n }: SwitchProps) => {\n const form = useForm();\n return () => {\n const off = disabled ?? form?.disabled ?? false;\n return (\n <button\n {...mergeAttrs<'button'>({ sx: [switchStyles.root, switchStyles[tone]] }, rest, {\n type: 'button',\n role: 'switch',\n 'aria-checked': checked ? 'true' : 'false',\n 'aria-busy': loading ? 'true' : undefined,\n disabled: off,\n onClick: () => {\n if (loading || form?.readonly) return;\n checked = !checked;\n onChange?.(checked);\n },\n ...dataAttrs({ 'data-disabled': off }),\n })}\n >\n <span\n {...mergeAttrs<'span'>(\n { sx: switchStyles.thumb },\n propsThumb,\n dataAttrs({ 'data-checked': checked }),\n )}\n >\n {loading && <Loading size={14} />}\n </span>\n </button>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;AAqCA,IAAa,eAAe,IAAI,OAAO;CACrC,MAAM;EACJ,WAAW;EACX,UAAU;EACV,SAAS;EACT,MAAM;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,aAAa;EACb,cAAc;EACd,eAAe;EACf,QAAQ;GAAE,SAAS;GAAW,mBAAmB;EAAc;EAC/D,SAAS;GAAE,SAAS;GAAG,mBAAmB;EAAY;EACtD,oBAAoB;EACpB,oBAAoB;CACtB;CACA,QAAQ,EAAE,iBAAiB;EAAE,SAAS;EAAe,2BAAyB;CAAU,EAAE;CAC1F,SAAS,EAAE,iBAAiB;EAAE,SAAS;EAAe,2BAAyB;CAAW,EAAE;CAC5F,SAAS,EAAE,iBAAiB;EAAE,SAAS;EAAe,2BAAyB;CAAW,EAAE;CAC5F,QAAQ,EAAE,iBAAiB;EAAE,SAAS;EAAe,2BAAyB;CAAU,EAAE;CAC1F,OAAO;EACL,WAAW;EACX,UAAU;EACV,iBAAiB;EACjB,kBAAkB;EAClB,SAAS;EACT,YAAY;EACZ,gBAAgB;EAChB,OAAO;EACP,QAAQ;EACR,cAAc;EAEd,iBAAiB;EACjB,WAAW;EACX,OAAO;EACP,UAAU;EACV,WAAW;GAAE,SAAS;GAAQ,kBAAkB;EAAqB;EACrE,oBAAoB;EACpB,oBAAoB;EACpB,0BAA0B;CAC5B;AACF,CAAC;;AAGD,IAAa,SAAS,0BACpB,QAAA,SAQmB;CAAA,MAAA,UAAAA,SAAA,QAAA,kBAPa,OAAK,KAAA,IAAA;CAAA,MAAA,OAAAC,aAAA,QAAA,QAC5B,QAAQ;CAAA,MAAA,UAAAA,aAAA,QAAA,WACL,KAAK;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAIZ,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,OAAO,QAAQ;CACrB,aAAa;EACX,MAAM,MAAM,SAAA,SAAY,MAAM,YAAY;EAC1C,OAAAC,YAAA,UAEQ,WAAqB,EAAE,IAAI,CAAC,aAAa,MAAM,aAAY,KAAA,MAAM,EAAE,GAAG,MAAM;GAC9E,MAAM;GACN,MAAM;GACN,gBAAgB,QAAA,QAAU,SAAS;GACnC,aAAa,QAAA,QAAU,SAAS,KAAA;GAChC,UAAU;GACV,eAAe;IACb,IAAI,QAAA,SAAW,MAAM,UAAU;IAC/B,QAAA,QAAU,CAAA,QAAA;IACV,SAAA,QAAA,QAAA,KAAkB;GACpB;GACA,GAAG,UAAU,EAAE,iBAAiB,IAAI,CAAC;EACvC,CAAC,GAAC,CAAAA,YAAA,QAGI,WACF,EAAE,IAAI,aAAa,MAAM,GAAC,WAAA,OAE1B,UAAU,EAAE,gBAAc,QAAA,MAAU,CAAC,CACvC,GAAC,CAEA,QAAA,SAAAA,YAAA,SAAA,EAAA,QAA0B,GAAE,GAAA,IAAA,CAAI,CAAA,CAAA,CAAA;CAIzC;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -0,0 +1,67 @@
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
+ import { type VNodeChild } from 'vue';
3
+ import { type PartProps } from '../utils/props';
4
+ /** 一个文件 */
5
+ export interface UploaderFile {
6
+ /** 预览(及上传完)的地址 */
7
+ url: string;
8
+ /** H5 里选到的 File,上传时用;小程序里没有(用 url 这个临时路径上传) */
9
+ file?: File;
10
+ /** 字节数 */
11
+ size?: number;
12
+ /** 上传的状态;不给时是已完成 */
13
+ status?: 'uploading' | 'failed' | 'done';
14
+ /** 状态下面的文字(“上传中”“上传失败”) */
15
+ message?: string;
16
+ }
17
+ /** 未声明的属性落到根元素(div)上 */
18
+ export interface UploaderProps extends Omit<PartProps<'div'>, 'onChange'> {
19
+ /** 已选的文件;双向绑定写 `_value={x}` */
20
+ _value?: UploaderFile[];
21
+ /** 最多几张 */
22
+ maxCount?: number;
23
+ /** 单张最大字节数;超过的不加进来,交给 onOversize */
24
+ maxSize?: number;
25
+ /**
26
+ * 一次可以选多张
27
+ * @default true
28
+ */
29
+ multiple?: boolean;
30
+ /**
31
+ * 能删除
32
+ * @default true
33
+ */
34
+ deletable?: boolean;
35
+ /** 禁用 */
36
+ disabled?: boolean;
37
+ /**
38
+ * 方格的边长(CSS 长度)
39
+ * @default '5em'
40
+ */
41
+ previewSize?: string;
42
+ /** 选图那一格的文字;不给时用语言包的“上传图片” */
43
+ uploadText?: VNodeChild;
44
+ /** 选好了:新加的文件(已经在 _value 里,是响应式的,改 status 会刷新) */
45
+ onRead?: (files: UploaderFile[]) => void;
46
+ /** 有文件超过 maxSize */
47
+ onOversize?: (files: UploaderFile[]) => void;
48
+ /** 删除了一张 */
49
+ onDelete?: (file: UploaderFile, index: number) => void;
50
+ /** 点了一张预览 */
51
+ onPreview?: (file: UploaderFile, index: number) => void;
52
+ /** 每一格预览的部件属性 */
53
+ propsItem?: PartProps<'div'>;
54
+ /** 选图那一格的部件属性 */
55
+ propsUpload?: PartProps<'button'>;
56
+ }
57
+ /** Uploader 的样式:root、item、mask、remove、upload */
58
+ export declare const uploaderStyles: Readonly<{
59
+ item: css.CompiledStyles;
60
+ mask: css.CompiledStyles;
61
+ remove: css.CompiledStyles;
62
+ root: css.CompiledStyles;
63
+ upload: css.CompiledStyles;
64
+ uploadIcon: css.CompiledStyles;
65
+ }>;
66
+ /** 图片上传(div > 预览的方格 + 选图的一格) */
67
+ export declare const Uploader: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<UploaderProps>;