@zerodep-dev/vue-tsx-pro-ui 0.3.0 → 0.3.2

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 (616) hide show
  1. package/dist/base/Blockquote.d.ts +1 -1
  2. package/dist/base/Blockquote.js +1 -1
  3. package/dist/base/Blockquote.js.map +1 -1
  4. package/dist/base/ButtonGroup.d.ts +1 -1
  5. package/dist/base/ButtonGroup.js +1 -1
  6. package/dist/base/ButtonGroup.js.map +1 -1
  7. package/dist/base/Code.d.ts +1 -1
  8. package/dist/base/Code.js +1 -1
  9. package/dist/base/Code.js.map +1 -1
  10. package/dist/base/CodeBlock.d.ts +1 -1
  11. package/dist/base/CodeBlock.js +1 -1
  12. package/dist/base/CodeBlock.js.map +1 -1
  13. package/dist/base/CopyButton.d.ts +1 -1
  14. package/dist/base/CopyButton.js +1 -1
  15. package/dist/base/CopyButton.js.map +1 -1
  16. package/dist/base/Heading.d.ts +1 -1
  17. package/dist/base/Heading.js +1 -1
  18. package/dist/base/Heading.js.map +1 -1
  19. package/dist/base/Icon.d.ts +1 -1
  20. package/dist/base/Icon.js +1 -1
  21. package/dist/base/Icon.js.map +1 -1
  22. package/dist/base/Indicator.d.ts +1 -1
  23. package/dist/base/Indicator.js +1 -1
  24. package/dist/base/Indicator.js.map +1 -1
  25. package/dist/base/Kbd.d.ts +1 -1
  26. package/dist/base/Kbd.js +1 -1
  27. package/dist/base/Kbd.js.map +1 -1
  28. package/dist/base/Link.d.ts +1 -1
  29. package/dist/base/Link.js +1 -1
  30. package/dist/base/Link.js.map +1 -1
  31. package/dist/base/List.d.ts +1 -1
  32. package/dist/base/List.js +1 -1
  33. package/dist/base/List.js.map +1 -1
  34. package/dist/base/Mark.d.ts +1 -1
  35. package/dist/base/Mark.js +1 -1
  36. package/dist/base/Mark.js.map +1 -1
  37. package/dist/base/Spinner.d.ts +1 -1
  38. package/dist/base/Spinner.js +1 -1
  39. package/dist/base/Spinner.js.map +1 -1
  40. package/dist/base/StatusDot.d.ts +1 -1
  41. package/dist/base/StatusDot.js +1 -1
  42. package/dist/base/StatusDot.js.map +1 -1
  43. package/dist/base/Tag.d.ts +1 -1
  44. package/dist/base/Tag.js +1 -1
  45. package/dist/base/Tag.js.map +1 -1
  46. package/dist/base/Text.d.ts +1 -1
  47. package/dist/base/Text.js +1 -1
  48. package/dist/base/Text.js.map +1 -1
  49. package/dist/base/VisuallyHidden.d.ts +1 -1
  50. package/dist/base/VisuallyHidden.js +1 -1
  51. package/dist/base/VisuallyHidden.js.map +1 -1
  52. package/dist/base/badge-styles.d.ts +1 -1
  53. package/dist/base/badge-styles.js +1 -1
  54. package/dist/base/badge-styles.js.map +1 -1
  55. package/dist/base/button-core.d.ts +1 -1
  56. package/dist/base/button-core.js +1 -1
  57. package/dist/base/button-core.js.map +1 -1
  58. package/dist/charts/ChordChart.d.ts +1 -1
  59. package/dist/charts/ChordChart.js +1 -1
  60. package/dist/charts/ChordChart.js.map +1 -1
  61. package/dist/charts/DonutChart.d.ts +1 -1
  62. package/dist/charts/DonutChart.js +1 -1
  63. package/dist/charts/DonutChart.js.map +1 -1
  64. package/dist/charts/FunnelChart.d.ts +1 -1
  65. package/dist/charts/FunnelChart.js +1 -1
  66. package/dist/charts/FunnelChart.js.map +1 -1
  67. package/dist/charts/GraphChart.d.ts +1 -1
  68. package/dist/charts/GraphChart.js +1 -1
  69. package/dist/charts/GraphChart.js.map +1 -1
  70. package/dist/charts/MapChart.d.ts +1 -1
  71. package/dist/charts/MapChart.js +1 -1
  72. package/dist/charts/MapChart.js.map +1 -1
  73. package/dist/charts/RadarChart.d.ts +1 -1
  74. package/dist/charts/RadarChart.js +1 -1
  75. package/dist/charts/RadarChart.js.map +1 -1
  76. package/dist/charts/SankeyChart.d.ts +1 -1
  77. package/dist/charts/SankeyChart.js +1 -1
  78. package/dist/charts/SankeyChart.js.map +1 -1
  79. package/dist/charts/TreemapChart.d.ts +1 -1
  80. package/dist/charts/TreemapChart.js +1 -1
  81. package/dist/charts/TreemapChart.js.map +1 -1
  82. package/dist/charts/XYChart.d.ts +1 -1
  83. package/dist/charts/XYChart.js +1 -1
  84. package/dist/charts/XYChart.js.map +1 -1
  85. package/dist/charts/frame.d.ts +1 -1
  86. package/dist/charts/frame.js +1 -1
  87. package/dist/charts/frame.js.map +1 -1
  88. package/dist/code-editor/CodeEditor.js +1 -1
  89. package/dist/code-editor/CodeEditor.js.map +1 -1
  90. package/dist/config/Provider.d.ts +1 -1
  91. package/dist/config/Provider.js +1 -1
  92. package/dist/config/Provider.js.map +1 -1
  93. package/dist/config/createUi.d.ts +1 -1
  94. package/dist/config/createUi.js +1 -1
  95. package/dist/config/createUi.js.map +1 -1
  96. package/dist/config/theme/coffee.d.ts +1 -1
  97. package/dist/config/theme/coffee.js +1 -1
  98. package/dist/config/theme/coffee.js.map +1 -1
  99. package/dist/config/theme/cyberpunk.d.ts +1 -1
  100. package/dist/config/theme/cyberpunk.js +1 -1
  101. package/dist/config/theme/cyberpunk.js.map +1 -1
  102. package/dist/config/theme/dark.d.ts +1 -1
  103. package/dist/config/theme/dark.js +1 -1
  104. package/dist/config/theme/dark.js.map +1 -1
  105. package/dist/config/theme/festive.d.ts +1 -1
  106. package/dist/config/theme/festive.js +1 -1
  107. package/dist/config/theme/festive.js.map +1 -1
  108. package/dist/config/theme/forest.d.ts +1 -1
  109. package/dist/config/theme/forest.js +1 -1
  110. package/dist/config/theme/forest.js.map +1 -1
  111. package/dist/config/theme/high-contrast.d.ts +1 -1
  112. package/dist/config/theme/high-contrast.js +1 -1
  113. package/dist/config/theme/high-contrast.js.map +1 -1
  114. package/dist/config/theme/lemon.d.ts +1 -1
  115. package/dist/config/theme/lemon.js +1 -1
  116. package/dist/config/theme/lemon.js.map +1 -1
  117. package/dist/config/theme/light.d.ts +1 -1
  118. package/dist/config/theme/light.js +1 -1
  119. package/dist/config/theme/light.js.map +1 -1
  120. package/dist/config/theme/midnight.d.ts +1 -1
  121. package/dist/config/theme/midnight.js +1 -1
  122. package/dist/config/theme/midnight.js.map +1 -1
  123. package/dist/config/theme/ocean.d.ts +1 -1
  124. package/dist/config/theme/ocean.js +1 -1
  125. package/dist/config/theme/ocean.js.map +1 -1
  126. package/dist/config/theme/paper.d.ts +1 -1
  127. package/dist/config/theme/paper.js +1 -1
  128. package/dist/config/theme/paper.js.map +1 -1
  129. package/dist/config/theme/sakura.d.ts +1 -1
  130. package/dist/config/theme/sakura.js +1 -1
  131. package/dist/config/theme/sakura.js.map +1 -1
  132. package/dist/config/theme/theme.js +1 -1
  133. package/dist/config/theme/theme.js.map +1 -1
  134. package/dist/config/theme/tokens.d.ts +1 -1
  135. package/dist/config/theme/tokens.js +1 -1
  136. package/dist/config/theme/tokens.js.map +1 -1
  137. package/dist/date/CalendarBoard.d.ts +1 -1
  138. package/dist/date/CalendarBoard.js +1 -1
  139. package/dist/date/CalendarBoard.js.map +1 -1
  140. package/dist/date/CalendarView.d.ts +1 -1
  141. package/dist/date/CalendarView.js +1 -1
  142. package/dist/date/CalendarView.js.map +1 -1
  143. package/dist/date/Countdown.d.ts +1 -1
  144. package/dist/date/Countdown.js +1 -1
  145. package/dist/date/Countdown.js.map +1 -1
  146. package/dist/date/DatePicker.d.ts +1 -1
  147. package/dist/date/DatePicker.js +1 -1
  148. package/dist/date/DatePicker.js.map +1 -1
  149. package/dist/date/DateRangePicker.d.ts +1 -1
  150. package/dist/date/DateRangePicker.js +1 -1
  151. package/dist/date/DateRangePicker.js.map +1 -1
  152. package/dist/date/DateSegmentGroup.d.ts +1 -1
  153. package/dist/date/DateSegmentGroup.js +1 -1
  154. package/dist/date/DateSegmentGroup.js.map +1 -1
  155. package/dist/date/QuarterCalendar.js +1 -1
  156. package/dist/date/QuarterCalendar.js.map +1 -1
  157. package/dist/date/SegmentedField.d.ts +1 -1
  158. package/dist/date/SegmentedField.js +1 -1
  159. package/dist/date/SegmentedField.js.map +1 -1
  160. package/dist/date/TimePicker.d.ts +1 -1
  161. package/dist/date/TimePicker.js +1 -1
  162. package/dist/date/TimePicker.js.map +1 -1
  163. package/dist/date/picker-popover.d.ts +1 -1
  164. package/dist/date/picker-popover.js +1 -1
  165. package/dist/date/picker-popover.js.map +1 -1
  166. package/dist/diagram/Diagram.d.ts +1 -1
  167. package/dist/diagram/Diagram.js +1 -1
  168. package/dist/diagram/Diagram.js.map +1 -1
  169. package/dist/diagram/DiagramControls.d.ts +1 -1
  170. package/dist/diagram/DiagramControls.js +1 -1
  171. package/dist/diagram/DiagramControls.js.map +1 -1
  172. package/dist/diagram/DiagramLanes.d.ts +1 -1
  173. package/dist/diagram/DiagramLanes.js +1 -1
  174. package/dist/diagram/DiagramLanes.js.map +1 -1
  175. package/dist/diagram/DiagramMinimap.d.ts +1 -1
  176. package/dist/diagram/DiagramMinimap.js +1 -1
  177. package/dist/diagram/DiagramMinimap.js.map +1 -1
  178. package/dist/diagram/DiagramNode.d.ts +1 -1
  179. package/dist/diagram/DiagramNode.js +1 -1
  180. package/dist/diagram/DiagramNode.js.map +1 -1
  181. package/dist/display/Accordion.d.ts +1 -1
  182. package/dist/display/Accordion.js +1 -1
  183. package/dist/display/Accordion.js.map +1 -1
  184. package/dist/display/AnimatedNumber.d.ts +1 -1
  185. package/dist/display/AnimatedNumber.js +1 -1
  186. package/dist/display/AnimatedNumber.js.map +1 -1
  187. package/dist/display/Avatar.d.ts +1 -1
  188. package/dist/display/Avatar.js +1 -1
  189. package/dist/display/Avatar.js.map +1 -1
  190. package/dist/display/AvatarGroup.d.ts +1 -1
  191. package/dist/display/AvatarGroup.js +1 -1
  192. package/dist/display/AvatarGroup.js.map +1 -1
  193. package/dist/display/Card.d.ts +1 -1
  194. package/dist/display/Card.js +1 -1
  195. package/dist/display/Card.js.map +1 -1
  196. package/dist/display/Checklist.d.ts +1 -1
  197. package/dist/display/Checklist.js +1 -1
  198. package/dist/display/Checklist.js.map +1 -1
  199. package/dist/display/Collapse.d.ts +1 -1
  200. package/dist/display/Collapse.js +1 -1
  201. package/dist/display/Collapse.js.map +1 -1
  202. package/dist/display/Descriptions.d.ts +1 -1
  203. package/dist/display/Descriptions.js +1 -1
  204. package/dist/display/Descriptions.js.map +1 -1
  205. package/dist/display/Ellipsis.d.ts +1 -1
  206. package/dist/display/Ellipsis.js +1 -1
  207. package/dist/display/Ellipsis.js.map +1 -1
  208. package/dist/display/FieldCompare.d.ts +1 -1
  209. package/dist/display/FieldCompare.js +1 -1
  210. package/dist/display/FieldCompare.js.map +1 -1
  211. package/dist/display/Gauge.d.ts +1 -1
  212. package/dist/display/Gauge.js +1 -1
  213. package/dist/display/Gauge.js.map +1 -1
  214. package/dist/display/Image.d.ts +1 -1
  215. package/dist/display/Image.js +1 -1
  216. package/dist/display/Image.js.map +1 -1
  217. package/dist/display/ItemList.d.ts +1 -1
  218. package/dist/display/ItemList.js +1 -1
  219. package/dist/display/ItemList.js.map +1 -1
  220. package/dist/display/Marquee.d.ts +1 -1
  221. package/dist/display/Marquee.js +1 -1
  222. package/dist/display/Marquee.js.map +1 -1
  223. package/dist/display/ProportionBar.d.ts +1 -1
  224. package/dist/display/ProportionBar.js +1 -1
  225. package/dist/display/ProportionBar.js.map +1 -1
  226. package/dist/display/Sortable.d.ts +1 -1
  227. package/dist/display/Sortable.js +1 -1
  228. package/dist/display/Sortable.js.map +1 -1
  229. package/dist/display/Sparkline.d.ts +1 -1
  230. package/dist/display/Sparkline.js +1 -1
  231. package/dist/display/Sparkline.js.map +1 -1
  232. package/dist/display/Stat.d.ts +1 -1
  233. package/dist/display/Stat.js +1 -1
  234. package/dist/display/Stat.js.map +1 -1
  235. package/dist/display/Timeline.d.ts +1 -1
  236. package/dist/display/Timeline.js +1 -1
  237. package/dist/display/Timeline.js.map +1 -1
  238. package/dist/display/Tree.d.ts +1 -1
  239. package/dist/display/Tree.js +1 -1
  240. package/dist/display/Tree.js.map +1 -1
  241. package/dist/display/VirtualList.d.ts +1 -1
  242. package/dist/display/VirtualList.js +1 -1
  243. package/dist/display/VirtualList.js.map +1 -1
  244. package/dist/display/Watermark.d.ts +1 -1
  245. package/dist/display/Watermark.js +1 -1
  246. package/dist/display/Watermark.js.map +1 -1
  247. package/dist/docs-kit/CodeGroup.d.ts +1 -1
  248. package/dist/docs-kit/CodeGroup.js +1 -1
  249. package/dist/docs-kit/CodeGroup.js.map +1 -1
  250. package/dist/docs-kit/CodePreview.d.ts +1 -1
  251. package/dist/docs-kit/CodePreview.js +1 -1
  252. package/dist/docs-kit/CodePreview.js.map +1 -1
  253. package/dist/docs-kit/ColorSwatch.d.ts +1 -1
  254. package/dist/docs-kit/ColorSwatch.js +1 -1
  255. package/dist/docs-kit/ColorSwatch.js.map +1 -1
  256. package/dist/docs-kit/PropsTable.d.ts +1 -1
  257. package/dist/docs-kit/PropsTable.js +1 -1
  258. package/dist/docs-kit/PropsTable.js.map +1 -1
  259. package/dist/feedback/Alert.d.ts +1 -1
  260. package/dist/feedback/Alert.js +1 -1
  261. package/dist/feedback/Alert.js.map +1 -1
  262. package/dist/feedback/Banner.d.ts +1 -1
  263. package/dist/feedback/Banner.js +1 -1
  264. package/dist/feedback/Banner.js.map +1 -1
  265. package/dist/feedback/Empty.d.ts +1 -1
  266. package/dist/feedback/Empty.js +1 -1
  267. package/dist/feedback/Empty.js.map +1 -1
  268. package/dist/feedback/LoadingBar.d.ts +1 -1
  269. package/dist/feedback/LoadingBar.js +1 -1
  270. package/dist/feedback/LoadingBar.js.map +1 -1
  271. package/dist/feedback/LoadingOverlay.d.ts +1 -1
  272. package/dist/feedback/LoadingOverlay.js +1 -1
  273. package/dist/feedback/LoadingOverlay.js.map +1 -1
  274. package/dist/feedback/Progress.d.ts +1 -1
  275. package/dist/feedback/Progress.js +1 -1
  276. package/dist/feedback/Progress.js.map +1 -1
  277. package/dist/feedback/Result.d.ts +1 -1
  278. package/dist/feedback/Result.js +1 -1
  279. package/dist/feedback/Result.js.map +1 -1
  280. package/dist/feedback/Skeleton.d.ts +1 -1
  281. package/dist/feedback/Skeleton.js +1 -1
  282. package/dist/feedback/Skeleton.js.map +1 -1
  283. package/dist/feedback/SkeletonText.d.ts +1 -1
  284. package/dist/feedback/SkeletonText.js +1 -1
  285. package/dist/feedback/SkeletonText.js.map +1 -1
  286. package/dist/feedback/Toast.d.ts +1 -1
  287. package/dist/feedback/Toast.js +1 -1
  288. package/dist/feedback/Toast.js.map +1 -1
  289. package/dist/form/Field.d.ts +1 -1
  290. package/dist/form/Field.js +1 -1
  291. package/dist/form/Field.js.map +1 -1
  292. package/dist/form/FormErrorSummary.d.ts +1 -1
  293. package/dist/form/FormErrorSummary.js +1 -1
  294. package/dist/form/FormErrorSummary.js.map +1 -1
  295. package/dist/form/FormSection.d.ts +1 -1
  296. package/dist/form/FormSection.js +1 -1
  297. package/dist/form/FormSection.js.map +1 -1
  298. package/dist/form/schemas.d.ts +1 -1
  299. package/dist/form/schemas.js +1 -1
  300. package/dist/form/schemas.js.map +1 -1
  301. package/dist/input/Cascader.d.ts +1 -1
  302. package/dist/input/Cascader.js +1 -1
  303. package/dist/input/Cascader.js.map +1 -1
  304. package/dist/input/CharacterCount.d.ts +1 -1
  305. package/dist/input/CharacterCount.js +1 -1
  306. package/dist/input/CharacterCount.js.map +1 -1
  307. package/dist/input/Checkbox.d.ts +1 -1
  308. package/dist/input/Checkbox.js +1 -1
  309. package/dist/input/Checkbox.js.map +1 -1
  310. package/dist/input/ColorField.d.ts +1 -1
  311. package/dist/input/ColorField.js +1 -1
  312. package/dist/input/ColorField.js.map +1 -1
  313. package/dist/input/Combobox.d.ts +1 -1
  314. package/dist/input/Combobox.js +1 -1
  315. package/dist/input/Combobox.js.map +1 -1
  316. package/dist/input/ConditionBuilder.d.ts +1 -1
  317. package/dist/input/ConditionBuilder.js +1 -1
  318. package/dist/input/ConditionBuilder.js.map +1 -1
  319. package/dist/input/ControlGroup.d.ts +1 -1
  320. package/dist/input/ControlGroup.js +1 -1
  321. package/dist/input/ControlGroup.js.map +1 -1
  322. package/dist/input/FileDrop.d.ts +1 -1
  323. package/dist/input/FileDrop.js +1 -1
  324. package/dist/input/FileDrop.js.map +1 -1
  325. package/dist/input/ListPopover.d.ts +1 -1
  326. package/dist/input/ListPopover.js +1 -1
  327. package/dist/input/ListPopover.js.map +1 -1
  328. package/dist/input/Listbox.d.ts +1 -1
  329. package/dist/input/Listbox.js +1 -1
  330. package/dist/input/Listbox.js.map +1 -1
  331. package/dist/input/Mentions.d.ts +1 -1
  332. package/dist/input/Mentions.js +1 -1
  333. package/dist/input/Mentions.js.map +1 -1
  334. package/dist/input/NumberRangeField.d.ts +1 -1
  335. package/dist/input/NumberRangeField.js +1 -1
  336. package/dist/input/NumberRangeField.js.map +1 -1
  337. package/dist/input/OtpField.d.ts +1 -1
  338. package/dist/input/OtpField.js +1 -1
  339. package/dist/input/OtpField.js.map +1 -1
  340. package/dist/input/PeoplePicker.js +1 -1
  341. package/dist/input/PeoplePicker.js.map +1 -1
  342. package/dist/input/PeoplePickerPanel.d.ts +1 -1
  343. package/dist/input/PeoplePickerPanel.js +1 -1
  344. package/dist/input/PeoplePickerPanel.js.map +1 -1
  345. package/dist/input/Radio.d.ts +1 -1
  346. package/dist/input/Radio.js +1 -1
  347. package/dist/input/Radio.js.map +1 -1
  348. package/dist/input/Rating.d.ts +1 -1
  349. package/dist/input/Rating.js +1 -1
  350. package/dist/input/Rating.js.map +1 -1
  351. package/dist/input/Select.d.ts +1 -1
  352. package/dist/input/Select.js +1 -1
  353. package/dist/input/Select.js.map +1 -1
  354. package/dist/input/SelectedTags.d.ts +1 -1
  355. package/dist/input/SelectedTags.js +1 -1
  356. package/dist/input/SelectedTags.js.map +1 -1
  357. package/dist/input/Slider.d.ts +1 -1
  358. package/dist/input/Slider.js +1 -1
  359. package/dist/input/Slider.js.map +1 -1
  360. package/dist/input/Switch.d.ts +1 -1
  361. package/dist/input/Switch.js +1 -1
  362. package/dist/input/Switch.js.map +1 -1
  363. package/dist/input/TagsInput.d.ts +1 -1
  364. package/dist/input/TagsInput.js +1 -1
  365. package/dist/input/TagsInput.js.map +1 -1
  366. package/dist/input/Textarea.d.ts +1 -1
  367. package/dist/input/Textarea.js +1 -1
  368. package/dist/input/Textarea.js.map +1 -1
  369. package/dist/input/ToggleGroup.d.ts +1 -1
  370. package/dist/input/ToggleGroup.js +1 -1
  371. package/dist/input/ToggleGroup.js.map +1 -1
  372. package/dist/input/Transfer.d.ts +1 -1
  373. package/dist/input/Transfer.js +1 -1
  374. package/dist/input/Transfer.js.map +1 -1
  375. package/dist/input/TreeSelect.d.ts +1 -1
  376. package/dist/input/TreeSelect.js +1 -1
  377. package/dist/input/TreeSelect.js.map +1 -1
  378. package/dist/input/Upload.d.ts +1 -1
  379. package/dist/input/Upload.js +1 -1
  380. package/dist/input/Upload.js.map +1 -1
  381. package/dist/input/choice-styles.d.ts +1 -1
  382. package/dist/input/choice-styles.js +1 -1
  383. package/dist/input/choice-styles.js.map +1 -1
  384. package/dist/input/control.d.ts +1 -1
  385. package/dist/input/control.js +1 -1
  386. package/dist/input/control.js.map +1 -1
  387. package/dist/layout/Affix.d.ts +1 -1
  388. package/dist/layout/Affix.js +1 -1
  389. package/dist/layout/Affix.js.map +1 -1
  390. package/dist/layout/AsideLayout.d.ts +1 -1
  391. package/dist/layout/AsideLayout.js +1 -1
  392. package/dist/layout/AsideLayout.js.map +1 -1
  393. package/dist/layout/BackTop.d.ts +1 -1
  394. package/dist/layout/BackTop.js +1 -1
  395. package/dist/layout/BackTop.js.map +1 -1
  396. package/dist/layout/Container.d.ts +1 -1
  397. package/dist/layout/Container.js +1 -1
  398. package/dist/layout/Container.js.map +1 -1
  399. package/dist/layout/Flex.d.ts +1 -1
  400. package/dist/layout/Flex.js +1 -1
  401. package/dist/layout/Flex.js.map +1 -1
  402. package/dist/layout/Grid.d.ts +1 -1
  403. package/dist/layout/Grid.js +1 -1
  404. package/dist/layout/Grid.js.map +1 -1
  405. package/dist/layout/PageScrollbar.d.ts +1 -1
  406. package/dist/layout/PageScrollbar.js +1 -1
  407. package/dist/layout/PageScrollbar.js.map +1 -1
  408. package/dist/layout/Prose.d.ts +1 -1
  409. package/dist/layout/Prose.js +1 -1
  410. package/dist/layout/Prose.js.map +1 -1
  411. package/dist/layout/ResizeHandle.d.ts +1 -1
  412. package/dist/layout/ResizeHandle.js +1 -1
  413. package/dist/layout/ResizeHandle.js.map +1 -1
  414. package/dist/layout/ScrollArea.d.ts +1 -1
  415. package/dist/layout/ScrollArea.js +1 -1
  416. package/dist/layout/ScrollArea.js.map +1 -1
  417. package/dist/layout/Separator.d.ts +1 -1
  418. package/dist/layout/Separator.js +1 -1
  419. package/dist/layout/Separator.js.map +1 -1
  420. package/dist/layout/Splitter.d.ts +1 -1
  421. package/dist/layout/Splitter.js +1 -1
  422. package/dist/layout/Splitter.js.map +1 -1
  423. package/dist/layout/ViewportFill.d.ts +1 -1
  424. package/dist/layout/ViewportFill.js +1 -1
  425. package/dist/layout/ViewportFill.js.map +1 -1
  426. package/dist/navigation/Breadcrumbs.d.ts +1 -1
  427. package/dist/navigation/Breadcrumbs.js +1 -1
  428. package/dist/navigation/Breadcrumbs.js.map +1 -1
  429. package/dist/navigation/NavBar.d.ts +1 -1
  430. package/dist/navigation/NavBar.js +1 -1
  431. package/dist/navigation/NavBar.js.map +1 -1
  432. package/dist/navigation/NavList.d.ts +1 -1
  433. package/dist/navigation/NavList.js +1 -1
  434. package/dist/navigation/NavList.js.map +1 -1
  435. package/dist/navigation/PageJump.d.ts +1 -1
  436. package/dist/navigation/PageJump.js +1 -1
  437. package/dist/navigation/PageJump.js.map +1 -1
  438. package/dist/navigation/PageSizeSelect.d.ts +1 -1
  439. package/dist/navigation/PageSizeSelect.js +1 -1
  440. package/dist/navigation/PageSizeSelect.js.map +1 -1
  441. package/dist/navigation/Pager.d.ts +1 -1
  442. package/dist/navigation/Pager.js +1 -1
  443. package/dist/navigation/Pager.js.map +1 -1
  444. package/dist/navigation/Pagination.d.ts +1 -1
  445. package/dist/navigation/Pagination.js +1 -1
  446. package/dist/navigation/Pagination.js.map +1 -1
  447. package/dist/navigation/PaginationBar.d.ts +1 -1
  448. package/dist/navigation/PaginationBar.js +1 -1
  449. package/dist/navigation/PaginationBar.js.map +1 -1
  450. package/dist/navigation/SkipLink.d.ts +1 -1
  451. package/dist/navigation/SkipLink.js +1 -1
  452. package/dist/navigation/SkipLink.js.map +1 -1
  453. package/dist/navigation/Steps.d.ts +1 -1
  454. package/dist/navigation/Steps.js +1 -1
  455. package/dist/navigation/Steps.js.map +1 -1
  456. package/dist/navigation/TableOfContents.d.ts +1 -1
  457. package/dist/navigation/TableOfContents.js +1 -1
  458. package/dist/navigation/TableOfContents.js.map +1 -1
  459. package/dist/navigation/Tabs.d.ts +1 -1
  460. package/dist/navigation/Tabs.js +1 -1
  461. package/dist/navigation/Tabs.js.map +1 -1
  462. package/dist/navigation/Toolbar.d.ts +1 -1
  463. package/dist/navigation/Toolbar.js +1 -1
  464. package/dist/navigation/Toolbar.js.map +1 -1
  465. package/dist/overlay/CommandPalette.d.ts +1 -1
  466. package/dist/overlay/CommandPalette.js +1 -1
  467. package/dist/overlay/CommandPalette.js.map +1 -1
  468. package/dist/overlay/Dialog.d.ts +1 -1
  469. package/dist/overlay/Dialog.js +1 -1
  470. package/dist/overlay/Dialog.js.map +1 -1
  471. package/dist/overlay/Drawer.d.ts +1 -1
  472. package/dist/overlay/Drawer.js +1 -1
  473. package/dist/overlay/Drawer.js.map +1 -1
  474. package/dist/overlay/HoverCard.d.ts +1 -1
  475. package/dist/overlay/HoverCard.js +1 -1
  476. package/dist/overlay/HoverCard.js.map +1 -1
  477. package/dist/overlay/Lightbox.d.ts +1 -1
  478. package/dist/overlay/Lightbox.js +1 -1
  479. package/dist/overlay/Lightbox.js.map +1 -1
  480. package/dist/overlay/Menu.d.ts +1 -1
  481. package/dist/overlay/Menu.js +1 -1
  482. package/dist/overlay/Menu.js.map +1 -1
  483. package/dist/overlay/Popconfirm.d.ts +1 -1
  484. package/dist/overlay/Popconfirm.js +1 -1
  485. package/dist/overlay/Popconfirm.js.map +1 -1
  486. package/dist/overlay/Popover.d.ts +1 -1
  487. package/dist/overlay/Popover.js +1 -1
  488. package/dist/overlay/Popover.js.map +1 -1
  489. package/dist/overlay/Tooltip.d.ts +1 -1
  490. package/dist/overlay/Tooltip.js +1 -1
  491. package/dist/overlay/Tooltip.js.map +1 -1
  492. package/dist/overlay/Tour.d.ts +1 -1
  493. package/dist/overlay/Tour.js +1 -1
  494. package/dist/overlay/Tour.js.map +1 -1
  495. package/dist/patterns/ActionBar.d.ts +1 -1
  496. package/dist/patterns/ActionBar.js +1 -1
  497. package/dist/patterns/ActionBar.js.map +1 -1
  498. package/dist/patterns/AppShell.d.ts +1 -1
  499. package/dist/patterns/AppShell.js +1 -1
  500. package/dist/patterns/AppShell.js.map +1 -1
  501. package/dist/patterns/AuthLayout.d.ts +2 -2
  502. package/dist/patterns/AuthLayout.js +2 -2
  503. package/dist/patterns/AuthLayout.js.map +1 -1
  504. package/dist/patterns/CommentThread.d.ts +1 -1
  505. package/dist/patterns/CommentThread.js +1 -1
  506. package/dist/patterns/CommentThread.js.map +1 -1
  507. package/dist/patterns/DataImport.d.ts +1 -1
  508. package/dist/patterns/DataImport.js +1 -1
  509. package/dist/patterns/DataImport.js.map +1 -1
  510. package/dist/patterns/FilterBar.d.ts +1 -1
  511. package/dist/patterns/FilterBar.js +1 -1
  512. package/dist/patterns/FilterBar.js.map +1 -1
  513. package/dist/patterns/KanbanBoard.d.ts +1 -1
  514. package/dist/patterns/KanbanBoard.js +1 -1
  515. package/dist/patterns/KanbanBoard.js.map +1 -1
  516. package/dist/patterns/NotificationCenter.d.ts +1 -1
  517. package/dist/patterns/NotificationCenter.js +1 -1
  518. package/dist/patterns/NotificationCenter.js.map +1 -1
  519. package/dist/patterns/QueryTable.d.ts +1 -1
  520. package/dist/patterns/QueryTable.js +1 -1
  521. package/dist/patterns/QueryTable.js.map +1 -1
  522. package/dist/patterns/SlideCaptcha.d.ts +1 -1
  523. package/dist/patterns/SlideCaptcha.js +1 -1
  524. package/dist/patterns/SlideCaptcha.js.map +1 -1
  525. package/dist/patterns/StepsForm.d.ts +1 -1
  526. package/dist/patterns/StepsForm.js +1 -1
  527. package/dist/patterns/StepsForm.js.map +1 -1
  528. package/dist/table/ColumnHeaderActions.d.ts +1 -1
  529. package/dist/table/ColumnHeaderActions.js +1 -1
  530. package/dist/table/ColumnHeaderActions.js.map +1 -1
  531. package/dist/table/ColumnSettings.d.ts +1 -1
  532. package/dist/table/ColumnSettings.js +1 -1
  533. package/dist/table/ColumnSettings.js.map +1 -1
  534. package/dist/table/ColumnTable.d.ts +1 -1
  535. package/dist/table/ColumnTable.js +1 -1
  536. package/dist/table/ColumnTable.js.map +1 -1
  537. package/dist/table/DataTableView.d.ts +1 -1
  538. package/dist/table/DataTableView.js +1 -1
  539. package/dist/table/DataTableView.js.map +1 -1
  540. package/dist/table/PivotTable.d.ts +1 -1
  541. package/dist/table/PivotTable.js +1 -1
  542. package/dist/table/PivotTable.js.map +1 -1
  543. package/dist/table/SelectionBar.d.ts +1 -1
  544. package/dist/table/SelectionBar.js +1 -1
  545. package/dist/table/SelectionBar.js.map +1 -1
  546. package/dist/table/Table.d.ts +1 -1
  547. package/dist/table/Table.js +1 -1
  548. package/dist/table/Table.js.map +1 -1
  549. package/dist/table/TreeDataTable.d.ts +1 -1
  550. package/dist/table/TreeDataTable.js +1 -1
  551. package/dist/table/TreeDataTable.js.map +1 -1
  552. package/dist/table/table-styles.d.ts +1 -1
  553. package/dist/table/table-styles.js +1 -1
  554. package/dist/table/table-styles.js.map +1 -1
  555. package/dist/theme-customize/ThemeCustomizer.d.ts +1 -1
  556. package/dist/theme-customize/ThemeCustomizer.js +1 -1
  557. package/dist/theme-customize/ThemeCustomizer.js.map +1 -1
  558. package/dist/theme-customize/ThemeThumbnail.d.ts +1 -1
  559. package/dist/theme-customize/ThemeThumbnail.js +1 -1
  560. package/dist/theme-customize/ThemeThumbnail.js.map +1 -1
  561. package/dist/theme-customize/design-tokens.js +1 -1
  562. package/dist/theme-customize/design-tokens.js.map +1 -1
  563. package/dist/three/core/EffectSurface.d.ts +1 -1
  564. package/dist/three/core/EffectSurface.js +1 -1
  565. package/dist/three/core/EffectSurface.js.map +1 -1
  566. package/dist/three/core/ThreeCanvas.d.ts +1 -1
  567. package/dist/three/core/ThreeCanvas.js +1 -1
  568. package/dist/three/core/ThreeCanvas.js.map +1 -1
  569. package/dist/three/effects/Confetti.d.ts +1 -1
  570. package/dist/three/effects/Confetti.js +1 -1
  571. package/dist/three/effects/Confetti.js.map +1 -1
  572. package/dist/three/globe/Globe.d.ts +1 -1
  573. package/dist/three/globe/Globe.js +1 -1
  574. package/dist/three/globe/Globe.js.map +1 -1
  575. package/dist/three/model/ModelViewer.d.ts +1 -1
  576. package/dist/three/model/ModelViewer.js +1 -1
  577. package/dist/three/model/ModelViewer.js.map +1 -1
  578. package/dist/utils/dom/floating.d.ts +1 -1
  579. package/dist/utils/dom/floating.js +1 -1
  580. package/dist/utils/dom/floating.js.map +1 -1
  581. package/dist/utils/dom/ripple.d.ts +1 -1
  582. package/dist/utils/dom/ripple.js +1 -1
  583. package/dist/utils/dom/ripple.js.map +1 -1
  584. package/dist/utils/props.js +1 -1
  585. package/dist/utils/props.js.map +1 -1
  586. package/dist/utils/style/attached.d.ts +1 -1
  587. package/dist/utils/style/attached.js +1 -1
  588. package/dist/utils/style/attached.js.map +1 -1
  589. package/dist/utils/style/item-styles.d.ts +1 -1
  590. package/dist/utils/style/item-styles.js +1 -1
  591. package/dist/utils/style/item-styles.js.map +1 -1
  592. package/dist/utils/style/markers.d.ts +1 -1
  593. package/dist/utils/style/markers.js +1 -1
  594. package/dist/utils/style/markers.js.map +1 -1
  595. package/dist/utils/style/shimmer.d.ts +1 -1
  596. package/dist/utils/style/shimmer.js +1 -1
  597. package/dist/utils/style/shimmer.js.map +1 -1
  598. package/dist/utils/style/styles.d.ts +1 -1
  599. package/dist/utils/style/styles.js +1 -1
  600. package/dist/utils/style/styles.js.map +1 -1
  601. package/dist/utils/style/swatch-styles.d.ts +1 -1
  602. package/dist/utils/style/swatch-styles.js +1 -1
  603. package/dist/utils/style/swatch-styles.js.map +1 -1
  604. package/dist/utils/style/tone-styles.d.ts +1 -1
  605. package/dist/utils/style/tone-styles.js +1 -1
  606. package/dist/utils/style/tone-styles.js.map +1 -1
  607. package/dist/utils/style/transitions.d.ts +1 -1
  608. package/dist/utils/style/transitions.js +1 -1
  609. package/dist/utils/style/transitions.js.map +1 -1
  610. package/dist/utils/style/typography.d.ts +1 -1
  611. package/dist/utils/style/typography.js +1 -1
  612. package/dist/utils/style/typography.js.map +1 -1
  613. package/dist/utils/style/vars.d.ts +1 -1
  614. package/dist/utils/style/vars.js +1 -1
  615. package/dist/utils/style/vars.js.map +1 -1
  616. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"design-tokens.js","names":[],"sources":["../../src/theme-customize/design-tokens.ts"],"sourcesContent":["/**\n * 主题导出为设计令牌:W3C 设计令牌社区组(DTCG 2025.10)格式的 JSON,Figma 的变量面板可以直接导入,一个文件成为一个模式。\n *\n * const tokens = themeDesignTokens(lightTheme);\n * downloadFile('light.tokens.json', JSON.stringify(tokens, null, 2), 'application/json');\n *\n * 取值是页面上实际生效的 CSS 变量(含运行时覆盖),按 Figma 能导入的类型换算:\n * - 颜色写 sRGB 分量、透明度与 hex;\n * - 长度一律是 px(Figma 只认 px):em 按主题的 md 字号(组件的基准字号)、rem 按根元素字号换算,百分比这类没有固定长度的不导出;\n * - 时长是秒(Figma 只认 s);字重、行高、不透明度、描边宽度是数字;\n * - 字体取字体栈里 Figma 自带的开源字体:Figma 里没有系统字体;\n * - 阴影与缓动按 DTCG 的结构写出,Figma 变量没有这两种类型,导入时跳过。\n * 令牌按 token 组分组:colors/accent、space/md,与代码里的 `_accent`、`_space.md` 一一对应。\n */\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { CssVar } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { formatHex } from 'culori/fn';\nimport { parseColor } from '../utils/data/color';\nimport { applyStyleAttrs } from '../utils/props';\nimport { readToken, themeVariables, type Theme } from '../config/theme/theme';\nimport { t } from '../config/theme/tokens';\nimport { tokenCatalog } from './token-catalog';\n\n/** 一个设计令牌 */\nexport interface DesignToken {\n /** DTCG 类型:color、dimension、number、duration、fontFamily、shadow、cubicBezier */\n readonly $type: string;\n /** 取值:结构按类型(颜色是 colorSpace、components、alpha、hex,长度是 value 与 unit) */\n readonly $value: unknown;\n /** 说明,取自 token 目录 */\n readonly $description?: string;\n}\n\n/** 设计令牌文件:组名 → token 名 → 令牌 */\nexport type DesignTokens = Record<string, Record<string, DesignToken>>;\n\n/** 一套主题的取值:组名 → token 名 → CSS 取值 */\nexport type ThemeValues = Record<string, Record<string, string>>;\n\n/** 长度换算成 px 的基准 */\nexport interface DesignTokenBases {\n /** 1em 是多少 px:组件的基准字号 */\n em: number;\n /** 1rem 是多少 px:根元素字号 */\n rem: number;\n}\n\n/** Figma 自带的开源字体(Google Fonts):内置主题的每个字体栈里都有其中一个 */\nconst FIGMA_FONTS = ['Noto Sans SC', 'Noto Serif SC', 'JetBrains Mono'];\n\nconst round = (value: number, digits = 3) => Number(value.toFixed(digits));\n\n/** 长度换成 px;没有固定长度(百分比、auto)时返回 undefined */\nfunction toPx(value: string, bases: DesignTokenBases) {\n const match = /^(-?[\\d.]+)(px|em|rem)?$/.exec(value.trim());\n if (!match) return undefined;\n const factor = match[2] === 'em' ? bases.em : match[2] === 'rem' ? bases.rem : 1;\n return { value: round(Number(match[1]) * factor), unit: 'px' };\n}\n\nfunction toColor(value: string) {\n const color = parseColor(value);\n if (!color) throw new Error(`无法解析的颜色:${value}`);\n return {\n colorSpace: 'srgb',\n components: [color.r, color.g, color.b].map((channel) => round(channel, 4)),\n alpha: round(color.alpha ?? 1, 4),\n hex: formatHex(color),\n };\n}\n\n/** CSS 阴影 → DTCG 的阴影层:`0 1px 2px -1px rgba(…)`,多层用逗号隔开(括号里的逗号不算);none 不导出 */\nfunction toShadow(value: string, bases: DesignTokenBases) {\n if (value.trim() === 'none') return undefined;\n return value.split(/,(?![^(]*\\))/).map((layer) => {\n const parts = layer.trim().split(/\\s+(?![^(]*\\))/);\n const lengths = parts.filter((part) => toPx(part, bases));\n const color = parts.find((part) => part !== 'inset' && !lengths.includes(part));\n const [offsetX, offsetY, blur = '0', spread = '0'] = lengths.map((part) => toPx(part, bases));\n return {\n color: toColor(color ?? 'black'),\n offsetX,\n offsetY,\n blur,\n spread,\n inset: parts.includes('inset'),\n };\n });\n}\n\nfunction toNumber(value: string) {\n const number = Number(value);\n return Number.isFinite(number) ? number : undefined;\n}\n\n/** 一个 token 的类型与换算;换算不了(没有对应的固定值)时返回 undefined,不导出 */\ntype Convert = (value: string, bases: DesignTokenBases) => [string, unknown] | undefined;\n\nconst dimension: Convert = (value, bases) => {\n const px = toPx(value, bases);\n return px && ['dimension', px];\n};\nconst number: Convert = (value) => {\n const result = toNumber(value);\n return result === undefined ? undefined : ['number', result];\n};\n\n/** 每组的类型;新增 token 组时这里必须补上 */\nconst CONVERTERS: Record<keyof typeof t, Convert> = {\n colors: (value) => ['color', toColor(value)],\n fonts: (value) => {\n const families = value.split(',').map((family) => family.trim().replace(/^[\"']|[\"']$/g, ''));\n return ['fontFamily', families.find((family) => FIGMA_FONTS.includes(family)) ?? families[0]];\n },\n fontSizes: dimension,\n fontWeights: number,\n lineHeights: number,\n letterSpacings: dimension,\n space: dimension,\n sizes: dimension,\n radii: dimension,\n borderWidths: dimension,\n shadows: (value, bases) => {\n const layers = toShadow(value, bases);\n return layers && ['shadow', layers];\n },\n opacities: number,\n strokeWidths: number,\n durations: (value) => {\n const match = /^([\\d.]+)(ms|s)$/.exec(value.trim());\n if (!match) return undefined;\n const seconds = Number(match[1]) / (match[2] === 'ms' ? 1000 : 1);\n return ['duration', { value: round(seconds), unit: 's' }];\n },\n easings: (value) => {\n const match = /^cubic-bezier\\(([^)]+)\\)$/.exec(value.trim());\n return match ? ['cubicBezier', match[1]!.split(',').map(Number)] : undefined;\n },\n};\n\n/** 主题的取值换算成设计令牌;说明取自 token 目录,只导出目录里有的 token */\nexport function designTokens(values: ThemeValues, bases: DesignTokenBases): DesignTokens {\n const result: DesignTokens = {};\n for (const group of tokenCatalog) {\n const convert = CONVERTERS[group.name as keyof typeof t];\n const tokens: Record<string, DesignToken> = {};\n for (const token of group.tokens) {\n const value = values[group.name]?.[token.name];\n const converted = value === undefined ? undefined : convert(value, bases);\n if (!converted) continue;\n tokens[token.name] = {\n $type: converted[0],\n $value: converted[1],\n $description: token.description,\n };\n }\n result[group.name] = tokens;\n }\n return result;\n}\n\n/** 元素上实际生效的各组 token 取值(CSS 文本,如 radii.md → '0.4em');元素要已挂载 */\nexport function elementThemeValues(element: Element): ThemeValues {\n const read = (group: string, token: string) => {\n const vars = t[group as keyof typeof t] as unknown as Record<string, CssVar>;\n return readToken(element, vars[token]!);\n };\n return Object.fromEntries(\n tokenCatalog.map((group) => [\n group.name,\n Object.fromEntries(group.tokens.map((token) => [token.name, read(group.name, token.name)])),\n ]),\n );\n}\n\n/** 元素上实际生效的主题(所在 Provider 或页面根元素的主题)导出为设计令牌;元素要已挂载 */\nexport function elementDesignTokens(element: Element): DesignTokens {\n const values = elementThemeValues(element);\n const rem = Number.parseFloat(getComputedStyle(element.ownerDocument.documentElement).fontSize);\n const em = toPx(values.fontSizes!.md!, { em: rem, rem })!.value;\n return designTokens(values, { em, rem });\n}\n\n/** 在 container 里挂一个套着这套主题、不显示的空元素,读完就移除 */\nfunction probeTheme<T>(theme: Theme, container: Element, read: (probe: Element) => T): T {\n const probe = document.createElement('div');\n applyStyleAttrs(probe, css.attrs(...theme.styles));\n for (const [name, value] of Object.entries(themeVariables(theme))) {\n probe.style.setProperty(name, value);\n }\n probe.hidden = true;\n container.append(probe);\n try {\n return read(probe);\n } finally {\n probe.remove();\n }\n}\n\n/** 一套主题的各组 token 取值(CSS 文本):主题的取值编译成了样式,要放进页面里量 */\nexport function themeValues(theme: Theme, container: Element = document.body): ThemeValues {\n return probeTheme(theme, container, elementThemeValues);\n}\n\n/** 一套主题的设计令牌 */\nexport function themeDesignTokens(theme: Theme, container: Element = document.body): DesignTokens {\n return probeTheme(theme, container, elementDesignTokens);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"design-tokens.js","names":[],"sources":["../../src/theme-customize/design-tokens.ts"],"sourcesContent":["/**\n * 主题导出为设计令牌:W3C 设计令牌社区组(DTCG 2025.10)格式的 JSON,Figma 的变量面板可以直接导入,一个文件成为一个模式。\n *\n * const tokens = themeDesignTokens(lightTheme);\n * downloadFile('light.tokens.json', JSON.stringify(tokens, null, 2), 'application/json');\n *\n * 取值是页面上实际生效的 CSS 变量(含运行时覆盖),按 Figma 能导入的类型换算:\n * - 颜色写 sRGB 分量、透明度与 hex;\n * - 长度一律是 px(Figma 只认 px):em 按主题的 md 字号(组件的基准字号)、rem 按根元素字号换算,百分比这类没有固定长度的不导出;\n * - 时长是秒(Figma 只认 s);字重、行高、不透明度、描边宽度是数字;\n * - 字体取字体栈里 Figma 自带的开源字体:Figma 里没有系统字体;\n * - 阴影与缓动按 DTCG 的结构写出,Figma 变量没有这两种类型,导入时跳过。\n * 令牌按 token 组分组:colors/accent、space/md,与代码里的 `_accent`、`_space.md` 一一对应。\n */\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { CssVar } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { formatHex } from 'culori/fn';\nimport { parseColor } from '../utils/data/color';\nimport { applyStyleAttrs } from '../utils/props';\nimport { readToken, themeVariables, type Theme } from '../config/theme/theme';\nimport { t } from '../config/theme/tokens';\nimport { tokenCatalog } from './token-catalog';\n\n/** 一个设计令牌 */\nexport interface DesignToken {\n /** DTCG 类型:color、dimension、number、duration、fontFamily、shadow、cubicBezier */\n readonly $type: string;\n /** 取值:结构按类型(颜色是 colorSpace、components、alpha、hex,长度是 value 与 unit) */\n readonly $value: unknown;\n /** 说明,取自 token 目录 */\n readonly $description?: string;\n}\n\n/** 设计令牌文件:组名 → token 名 → 令牌 */\nexport type DesignTokens = Record<string, Record<string, DesignToken>>;\n\n/** 一套主题的取值:组名 → token 名 → CSS 取值 */\nexport type ThemeValues = Record<string, Record<string, string>>;\n\n/** 长度换算成 px 的基准 */\nexport interface DesignTokenBases {\n /** 1em 是多少 px:组件的基准字号 */\n em: number;\n /** 1rem 是多少 px:根元素字号 */\n rem: number;\n}\n\n/** Figma 自带的开源字体(Google Fonts):内置主题的每个字体栈里都有其中一个 */\nconst FIGMA_FONTS = ['Noto Sans SC', 'Noto Serif SC', 'JetBrains Mono'];\n\nconst round = (value: number, digits = 3) => Number(value.toFixed(digits));\n\n/** 长度换成 px;没有固定长度(百分比、auto)时返回 undefined */\nfunction toPx(value: string, bases: DesignTokenBases) {\n const match = /^(-?[\\d.]+)(px|em|rem)?$/.exec(value.trim());\n if (!match) return undefined;\n const factor = match[2] === 'em' ? bases.em : match[2] === 'rem' ? bases.rem : 1;\n return { value: round(Number(match[1]) * factor), unit: 'px' };\n}\n\nfunction toColor(value: string) {\n const color = parseColor(value);\n if (!color) throw new Error(`无法解析的颜色:${value}`);\n return {\n colorSpace: 'srgb',\n components: [color.r, color.g, color.b].map((channel) => round(channel, 4)),\n alpha: round(color.alpha ?? 1, 4),\n hex: formatHex(color),\n };\n}\n\n/** CSS 阴影 → DTCG 的阴影层:`0 1px 2px -1px rgba(…)`,多层用逗号隔开(括号里的逗号不算);none 不导出 */\nfunction toShadow(value: string, bases: DesignTokenBases) {\n if (value.trim() === 'none') return undefined;\n return value.split(/,(?![^(]*\\))/).map((layer) => {\n const parts = layer.trim().split(/\\s+(?![^(]*\\))/);\n const lengths = parts.filter((part) => toPx(part, bases));\n const color = parts.find((part) => part !== 'inset' && !lengths.includes(part));\n const [offsetX, offsetY, blur = '0', spread = '0'] = lengths.map((part) => toPx(part, bases));\n return {\n color: toColor(color ?? 'black'),\n offsetX,\n offsetY,\n blur,\n spread,\n inset: parts.includes('inset'),\n };\n });\n}\n\nfunction toNumber(value: string) {\n const number = Number(value);\n return Number.isFinite(number) ? number : undefined;\n}\n\n/** 一个 token 的类型与换算;换算不了(没有对应的固定值)时返回 undefined,不导出 */\ntype Convert = (value: string, bases: DesignTokenBases) => [string, unknown] | undefined;\n\nconst dimension: Convert = (value, bases) => {\n const px = toPx(value, bases);\n return px && ['dimension', px];\n};\nconst number: Convert = (value) => {\n const result = toNumber(value);\n return result === undefined ? undefined : ['number', result];\n};\n\n/** 每组的类型;新增 token 组时这里必须补上 */\nconst CONVERTERS: Record<keyof typeof t, Convert> = {\n colors: (value) => ['color', toColor(value)],\n fonts: (value) => {\n const families = value.split(',').map((family) => family.trim().replace(/^[\"']|[\"']$/g, ''));\n return ['fontFamily', families.find((family) => FIGMA_FONTS.includes(family)) ?? families[0]];\n },\n fontSizes: dimension,\n fontWeights: number,\n lineHeights: number,\n letterSpacings: dimension,\n space: dimension,\n sizes: dimension,\n radii: dimension,\n borderWidths: dimension,\n shadows: (value, bases) => {\n const layers = toShadow(value, bases);\n return layers && ['shadow', layers];\n },\n opacities: number,\n strokeWidths: number,\n durations: (value) => {\n const match = /^([\\d.]+)(ms|s)$/.exec(value.trim());\n if (!match) return undefined;\n const seconds = Number(match[1]) / (match[2] === 'ms' ? 1000 : 1);\n return ['duration', { value: round(seconds), unit: 's' }];\n },\n easings: (value) => {\n const match = /^cubic-bezier\\(([^)]+)\\)$/.exec(value.trim());\n return match ? ['cubicBezier', match[1]!.split(',').map(Number)] : undefined;\n },\n};\n\n/** 主题的取值换算成设计令牌;说明取自 token 目录,只导出目录里有的 token */\nexport function designTokens(values: ThemeValues, bases: DesignTokenBases): DesignTokens {\n const result: DesignTokens = {};\n for (const group of tokenCatalog) {\n const convert = CONVERTERS[group.name as keyof typeof t];\n const tokens: Record<string, DesignToken> = {};\n for (const token of group.tokens) {\n const value = values[group.name]?.[token.name];\n const converted = value === undefined ? undefined : convert(value, bases);\n if (!converted) continue;\n tokens[token.name] = {\n $type: converted[0],\n $value: converted[1],\n $description: token.description,\n };\n }\n result[group.name] = tokens;\n }\n return result;\n}\n\n/** 元素上实际生效的各组 token 取值(CSS 文本,如 radii.md → '0.4em');元素要已挂载 */\nexport function elementThemeValues(element: Element): ThemeValues {\n const read = (group: string, token: string) => {\n const vars = t[group as keyof typeof t] as unknown as Record<string, CssVar>;\n return readToken(element, vars[token]!);\n };\n return Object.fromEntries(\n tokenCatalog.map((group) => [\n group.name,\n Object.fromEntries(group.tokens.map((token) => [token.name, read(group.name, token.name)])),\n ]),\n );\n}\n\n/** 元素上实际生效的主题(所在 Provider 或页面根元素的主题)导出为设计令牌;元素要已挂载 */\nexport function elementDesignTokens(element: Element): DesignTokens {\n const values = elementThemeValues(element);\n const rem = Number.parseFloat(getComputedStyle(element.ownerDocument.documentElement).fontSize);\n const em = toPx(values.fontSizes!.md!, { em: rem, rem })!.value;\n return designTokens(values, { em, rem });\n}\n\n/** 在 container 里挂一个套着这套主题、不显示的空元素,读完就移除 */\nfunction probeTheme<T>(theme: Theme, container: Element, read: (probe: Element) => T): T {\n const probe = document.createElement('div');\n applyStyleAttrs(probe, css.attrs(...theme.styles));\n for (const [name, value] of Object.entries(themeVariables(theme))) {\n probe.style.setProperty(name, value);\n }\n probe.hidden = true;\n container.append(probe);\n try {\n return read(probe);\n } finally {\n probe.remove();\n }\n}\n\n/** 一套主题的各组 token 取值(CSS 文本):主题的取值编译成了样式,要放进页面里量 */\nexport function themeValues(theme: Theme, container: Element = document.body): ThemeValues {\n return probeTheme(theme, container, elementThemeValues);\n}\n\n/** 一套主题的设计令牌 */\nexport function themeDesignTokens(theme: Theme, container: Element = document.body): DesignTokens {\n return probeTheme(theme, container, elementDesignTokens);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import type { VNodeChild } from 'vue';
3
3
  import { type PartProps } from '../../utils/props';
4
4
  import type { ThreeQuality } from './quality';
@@ -2,7 +2,7 @@ import { hasContent, mergeAttrs, mergePartProps } from "../../utils/props.js";
2
2
  import { ThreeCanvas } from "./ThreeCanvas.js";
3
3
  import { createVNode } from "vue";
4
4
  import { _component, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
5
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
5
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
6
6
  //#region src/three/core/EffectSurface.tsx
7
7
  /** 各种效果共有的属性;未声明的属性落到外层 div 上 */
8
8
  /** EffectSurface 的样式:root、canvas、content */
@@ -1 +1 @@
1
- {"version":3,"file":"EffectSurface.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../../src/three/core/EffectSurface.tsx"],"sourcesContent":["/**\n * 效果的外层结构(ShaderBackground、ParticleField、WaveGrid 等共用):画布铺在底层,内容叠在上面。\n *\n * <MeshGradient sx={styles.hero}>\n * <h1>标题</h1> ← 内容照常排版、可以交互;画布在它下面,不接收指针\n * </MeshGradient>\n *\n * 根元素建立层叠上下文(isolation),画布层在内容下面、在根元素的背景上面;没有内容时只是一块效果。\n * 尺寸由使用方决定(sx 给高度,或由内容撑开)。画布是装饰,读屏跳过;要描述画面时给 propsCanvas 写 aria-label。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(div,有内容时才有)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { hasContent, mergeAttrs, mergePartProps, type PartProps } from '../../utils/props';\nimport type { ThreeQuality } from './quality';\nimport type { ThreeContext, ThreeSceneHandle } from './renderer';\nimport { ThreeCanvas, type ThreeCanvasProps } from './ThreeCanvas';\n\n/** 各种效果共有的属性;未声明的属性落到外层 div 上 */\nexport interface EffectProps extends PartProps<'div'> {\n /**\n * 画质档位:像素比上限、粒子密度、抗锯齿;off 不渲染,显示 fallback\n * @default 'auto'\n */\n quality?: ThreeQuality;\n /** 暂停动画,停在当前画面 */\n paused?: boolean;\n /** 渲染分辨率相对像素比的倍数(0.1–1),见 ThreeCanvas;各效果有自己的默认值 */\n resolution?: number;\n /** 没有 WebGL(或 quality 为 off)时显示的内容,默认是主题色的柔和渐变 */\n fallback?: VNodeChild;\n /** 画布(ThreeCanvas)的部件属性 */\n propsCanvas?: Omit<Partial<ThreeCanvasProps>, 'setup'>;\n /** 内容外层的部件属性 */\n propsContent?: PartProps<'div'>;\n /** 叠在效果上面的内容 */\n children?: VNodeChild;\n}\n\n/** EffectSurface 的样式:root、canvas、content */\nexport const effectSurfaceStyles = css.create({\n root: { position: 'relative', isolation: 'isolate', overflow: 'hidden' },\n canvas: {\n position: 'absolute',\n inset: 0,\n zIndex: -1,\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n },\n content: { position: 'relative' },\n});\n\n/** EffectSurface 的属性:效果的公共属性加上搭场景的 setup */\nexport interface EffectSurfaceProps extends EffectProps {\n /** 搭场景,见 ThreeCanvas */\n setup: (context: ThreeContext) => ThreeSceneHandle | void;\n /** 变了就重建场景(着色器、色板这类建好后不再改的配置) */\n sceneKey?: string;\n}\n\n/** 效果的外层结构:底层画布 + 上层内容 */\nexport const EffectSurface = _component(\n ({\n setup,\n sceneKey,\n quality,\n paused,\n resolution,\n fallback,\n propsCanvas,\n propsContent,\n children,\n ...rest\n }: EffectSurfaceProps) => {\n return () => (\n <div {...mergeAttrs<'div'>({ sx: effectSurfaceStyles.root }, rest)}>\n <ThreeCanvas\n key={sceneKey}\n {...mergePartProps<ThreeCanvasProps>(\n { sx: effectSurfaceStyles.canvas, setup, quality, paused, resolution, fallback },\n propsCanvas,\n )}\n />\n {hasContent(children) && (\n <div {...mergeAttrs<'div'>({ sx: effectSurfaceStyles.content }, propsContent)}>\n {children}\n </div>\n )}\n </div>\n );\n },\n);\n"],"mappings":";;;;;;;;AA0CA,IAAa,sBAAsB,IAAI,OAAO;CAC5C,MAAM;EAAE,UAAU;EAAY,WAAW;EAAW,UAAU;CAAS;CACvE,QAAQ;EACN,UAAU;EACV,OAAO;EACP,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,eAAe;CACjB;CACA,SAAS,EAAE,UAAU,WAAW;AAClC,CAAC;;;AAWD,IAAa,gBAAgB,0BAC3B,QAAA,SAW0B;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,WAAAC,aAAA,MAAA;CAAA,MADrB,OAAIC,UAAA,QAAA,MAAA,KAAA;CAEP,aAAOC,YAAA,OACI,WAAkB,EAAE,IAAI,oBAAoB,KAAK,GAAG,IAAI,GAAC,CAAAA,YAAA,aAAAC,cAAA,EAAA,OAAA,SAAA,MAAA,GAG1D,eACF;EAAE,IAAI,oBAAoB;EAAQ,OAAK,MAAA;EAAE,SAAO,QAAA;EAAE,QAAM,OAAA;EAAE,YAAU,WAAA;EAAE,UAAQ,SAAA;CAAC,GAAC,YAAA,KAElF,CAAC,GAAA,IAAA,GAEF,WAAU,SAAA,KAAS,KAACD,YAAA,OACV,WAAkB,EAAE,IAAI,oBAAoB,QAAQ,GAAC,aAAA,KAAc,GAAC,CAAA,SAAA,KAAA,CAAA,CAG9E,CAAA;AAGP,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
1
+ {"version":3,"file":"EffectSurface.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../../src/three/core/EffectSurface.tsx"],"sourcesContent":["/**\n * 效果的外层结构(ShaderBackground、ParticleField、WaveGrid 等共用):画布铺在底层,内容叠在上面。\n *\n * <MeshGradient sx={styles.hero}>\n * <h1>标题</h1> ← 内容照常排版、可以交互;画布在它下面,不接收指针\n * </MeshGradient>\n *\n * 根元素建立层叠上下文(isolation),画布层在内容下面、在根元素的背景上面;没有内容时只是一块效果。\n * 尺寸由使用方决定(sx 给高度,或由内容撑开)。画布是装饰,读屏跳过;要描述画面时给 propsCanvas 写 aria-label。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(div,有内容时才有)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { hasContent, mergeAttrs, mergePartProps, type PartProps } from '../../utils/props';\nimport type { ThreeQuality } from './quality';\nimport type { ThreeContext, ThreeSceneHandle } from './renderer';\nimport { ThreeCanvas, type ThreeCanvasProps } from './ThreeCanvas';\n\n/** 各种效果共有的属性;未声明的属性落到外层 div 上 */\nexport interface EffectProps extends PartProps<'div'> {\n /**\n * 画质档位:像素比上限、粒子密度、抗锯齿;off 不渲染,显示 fallback\n * @default 'auto'\n */\n quality?: ThreeQuality;\n /** 暂停动画,停在当前画面 */\n paused?: boolean;\n /** 渲染分辨率相对像素比的倍数(0.1–1),见 ThreeCanvas;各效果有自己的默认值 */\n resolution?: number;\n /** 没有 WebGL(或 quality 为 off)时显示的内容,默认是主题色的柔和渐变 */\n fallback?: VNodeChild;\n /** 画布(ThreeCanvas)的部件属性 */\n propsCanvas?: Omit<Partial<ThreeCanvasProps>, 'setup'>;\n /** 内容外层的部件属性 */\n propsContent?: PartProps<'div'>;\n /** 叠在效果上面的内容 */\n children?: VNodeChild;\n}\n\n/** EffectSurface 的样式:root、canvas、content */\nexport const effectSurfaceStyles = css.create({\n root: { position: 'relative', isolation: 'isolate', overflow: 'hidden' },\n canvas: {\n position: 'absolute',\n inset: 0,\n zIndex: -1,\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n },\n content: { position: 'relative' },\n});\n\n/** EffectSurface 的属性:效果的公共属性加上搭场景的 setup */\nexport interface EffectSurfaceProps extends EffectProps {\n /** 搭场景,见 ThreeCanvas */\n setup: (context: ThreeContext) => ThreeSceneHandle | void;\n /** 变了就重建场景(着色器、色板这类建好后不再改的配置) */\n sceneKey?: string;\n}\n\n/** 效果的外层结构:底层画布 + 上层内容 */\nexport const EffectSurface = _component(\n ({\n setup,\n sceneKey,\n quality,\n paused,\n resolution,\n fallback,\n propsCanvas,\n propsContent,\n children,\n ...rest\n }: EffectSurfaceProps) => {\n return () => (\n <div {...mergeAttrs<'div'>({ sx: effectSurfaceStyles.root }, rest)}>\n <ThreeCanvas\n key={sceneKey}\n {...mergePartProps<ThreeCanvasProps>(\n { sx: effectSurfaceStyles.canvas, setup, quality, paused, resolution, fallback },\n propsCanvas,\n )}\n />\n {hasContent(children) && (\n <div {...mergeAttrs<'div'>({ sx: effectSurfaceStyles.content }, propsContent)}>\n {children}\n </div>\n )}\n </div>\n );\n },\n);\n"],"mappings":";;;;;;;;AA0CA,IAAa,sBAAsB,IAAI,OAAO;CAC5C,MAAM;EAAE,UAAU;EAAY,WAAW;EAAW,UAAU;CAAS;CACvE,QAAQ;EACN,UAAU;EACV,OAAO;EACP,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,eAAe;CACjB;CACA,SAAS,EAAE,UAAU,WAAW;AAClC,CAAC;;;AAWD,IAAa,gBAAgB,0BAC3B,QAAA,SAW0B;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,WAAAC,aAAA,MAAA;CAAA,MADrB,OAAIC,UAAA,QAAA,MAAA,KAAA;CAEP,aAAOC,YAAA,OACI,WAAkB,EAAE,IAAI,oBAAoB,KAAK,GAAG,IAAI,GAAC,CAAAA,YAAA,aAAAC,cAAA,EAAA,OAAA,SAAA,MAAA,GAG1D,eACF;EAAE,IAAI,oBAAoB;EAAQ,OAAK,MAAA;EAAE,SAAO,QAAA;EAAE,QAAM,OAAA;EAAE,YAAU,WAAA;EAAE,UAAQ,SAAA;CAAC,GAAC,YAAA,KAElF,CAAC,GAAA,IAAA,GAEF,WAAU,SAAA,KAAS,KAACD,YAAA,OACV,WAAkB,EAAE,IAAI,oBAAoB,QAAQ,GAAC,aAAA,KAAc,GAAC,CAAA,SAAA,KAAA,CAAA,CAG9E,CAAA;AAGP,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import { type VNodeChild } from 'vue';
3
3
  import { type PartProps } from '../../utils/props';
4
4
  import type { ThreeQuality } from './quality';
@@ -3,7 +3,7 @@ import { mergeAttrs } from "../../utils/props.js";
3
3
  import { useThree } from "./renderer.js";
4
4
  import { createVNode, shallowRef, watch } from "vue";
5
5
  import { _component, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
6
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
6
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
7
7
  //#region src/three/core/ThreeCanvas.tsx
8
8
  /** 未声明的属性落到外层 div 上 */
9
9
  /** ThreeCanvas 的样式:root、canvas、fallback、fallbackGradient(默认的降级渐变) */
@@ -1 +1 @@
1
- {"version":3,"file":"ThreeCanvas.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../../src/three/core/ThreeCanvas.tsx"],"sourcesContent":["/**\n * three.js 画布(div > canvas):渲染器的生命周期交给 useThree,这里只负责外层结构、降级与无障碍。\n *\n * <ThreeCanvas\n * sx={styles.hero}\n * setup={(context) => {\n * const mesh = new Mesh(new IcosahedronGeometry(1, 4), new MeshNormalMaterial());\n * context.scene.add(mesh);\n * return { frame: ({ time }) => (mesh.rotation.y = time) };\n * }}\n * />\n *\n * - 尺寸由外层 div 决定(默认占满父元素),canvas 铺满它,背景透明;\n * - 没有 WebGL、或 quality=\"off\" 时显示 fallback,默认是一层主题色的柔和渐变;\n * - 默认是装饰(aria-hidden);传了 aria-label 时是一张图(role=\"img\");\n * - 渲染状态写在根元素的 data-state 上(idle / running / paused / still / fallback)。\n *\n * 部件:Root(div)、Canvas(canvas,重建时换新的一块)、Fallback(div,降级内容)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { watch, type VNodeChild } from 'vue';\nimport { mergeAttrs, type PartProps } from '../../utils/props';\nimport type { ThreeQuality } from './quality';\nimport { useThree, type ThreeContext, type ThreeSceneHandle, type ThreeStatus } from './renderer';\nimport { t } from '../../config/theme/tokens';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ThreeCanvasProps extends PartProps<'div', 'role' | 'data-state'> {\n /** 搭场景:每次创建渲染器时调用一次(被回收、上下文丢失后会重新调用),返回每帧、尺寸变化、释放的回调 */\n setup: (context: ThreeContext) => ThreeSceneHandle | void;\n /**\n * 画质档位:像素比上限、粒子密度、抗锯齿;变了会重建。off 不创建 WebGL,显示 fallback\n * @default 'auto'\n */\n quality?: ThreeQuality;\n /** 暂停动画,停在当前画面 */\n paused?: boolean;\n /**\n * 渲染分辨率相对像素比的倍数(0.1–1):平滑的渐变、模糊的效果降低它能大幅省下 GPU 开销\n * @default 1\n */\n resolution?: number;\n /** 没有 WebGL(或 quality 为 off)时显示的内容,默认是主题色的柔和渐变 */\n fallback?: VNodeChild;\n /** 渲染状态变化时调用(同根元素的 data-state),挂载时先调用一次:比如降级时改放一张静态图,或一次性的效果直接收尾 */\n onStatusChange?: (status: ThreeStatus) => void;\n /** canvas 的部件属性 */\n propsCanvas?: PartProps<'canvas', 'aria-hidden'>;\n /** 降级内容外层的部件属性 */\n propsFallback?: PartProps<'div', 'aria-hidden'>;\n}\n\n/** ThreeCanvas 的样式:root、canvas、fallback、fallbackGradient(默认的降级渐变) */\nexport const threeCanvasStyles = css.create({\n root: {\n position: 'relative',\n display: 'block',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n },\n canvas: {\n position: 'absolute',\n inset: 0,\n display: 'block',\n width: '100%',\n height: '100%',\n },\n fallback: { position: 'absolute', inset: 0 },\n fallbackGradient: {\n backgroundImage: `radial-gradient(circle at 20% 25%, color-mix(in oklab, ${t.colors.accent} 28%, transparent), transparent 55%), radial-gradient(circle at 80% 70%, color-mix(in oklab, ${t.colors.chart3} 24%, transparent), transparent 55%), radial-gradient(circle at 60% 15%, color-mix(in oklab, ${t.colors.chart5} 18%, transparent), transparent 50%)`,\n },\n});\n\n/** three.js 画布:生命周期、降级、无障碍,场景由 setup 搭建 */\nexport const ThreeCanvas = _component(\n ({\n setup,\n quality = 'auto',\n paused = false,\n resolution = 1,\n fallback,\n onStatusChange,\n propsCanvas,\n propsFallback,\n ...rest\n }: ThreeCanvasProps) => {\n let canvas = _state.raw<HTMLCanvasElement | null>(null);\n const three = useThree({\n canvas: () => canvas,\n setup: (context) => setup(context),\n quality: () => quality,\n paused: () => paused,\n resolution: () => resolution,\n });\n // 挂载时先报告一次:quality=\"off\" 一开始就是 fallback,之后不再变\n watch(\n () => three.status,\n (status) => onStatusChange?.(status),\n { immediate: true },\n );\n\n return () => {\n const labelled = rest['aria-label'] != null || rest['aria-labelledby'] != null;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: threeCanvasStyles.root, 'aria-hidden': labelled ? undefined : true },\n rest,\n { role: labelled ? 'img' : undefined },\n )}\n data-state={three.status}\n >\n {three.status === 'fallback' ? (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n threeCanvasStyles.fallback,\n fallback == null && threeCanvasStyles.fallbackGradient,\n ],\n },\n propsFallback,\n { 'aria-hidden': true },\n )}\n >\n {fallback}\n </div>\n ) : (\n <canvas\n key={three.generation}\n {...mergeAttrs<'canvas'>({ sx: threeCanvasStyles.canvas }, propsCanvas, {\n 'aria-hidden': true,\n ref: _toRef(canvas),\n })}\n />\n )}\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;AAsDA,IAAa,oBAAoB,IAAI,OAAO;CAC1C,MAAM;EACJ,UAAU;EACV,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;CACZ;CACA,QAAQ;EACN,UAAU;EACV,OAAO;EACP,SAAS;EACT,OAAO;EACP,QAAQ;CACV;CACA,UAAU;EAAE,UAAU;EAAY,OAAO;CAAE;CAC3C,kBAAkB,EAChB,iBAAiB,0DAA0D,EAAE,OAAO,OAAM,+FAAgG,EAAE,OAAO,OAAM,+FAAgG,EAAE,OAAO,OAAM,sCAC1T;AACF,CAAC;;AAGD,IAAa,cAAc,0BACzB,QAAA,SAUwB;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,WARZ,MAAM;CAAA,MAAA,SAAAA,aAAA,QAAA,UACP,KAAK;CAAA,MAAA,aAAAA,aAAA,QAAA,cACD,CAAC;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,iBAAAA,aAAA,QAAA,gBAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,eAAA;CAAA,MAKX,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,IAAI,SAAMC,WAAwC,IAAI;CACtD,MAAM,QAAQ,SAAS;EACrB,cAAQ,OAAA;EACR,QAAQ,YAAY,MAAA,MAAM,OAAO;EACjC,eAAS,QAAA;EACT,cAAQ,OAAA;EACR,kBAAY,WAAA;CACd,CAAC;CAED,YACQ,MAAM,SACX,WAAW,eAAA,QAAiB,MAAM,GACnC,EAAE,WAAW,KAAK,CACpB;CAEA,aAAa;EACX,MAAM,WAAW,KAAK,iBAAiB,QAAQ,KAAK,sBAAsB;EAC1E,OAAAC,YAAA,OAAAC,cAEQ,WACF;GAAE,IAAI,kBAAkB;GAAM,eAAe,WAAW,KAAA,IAAY;EAAK,GACzE,MACA,EAAE,MAAM,WAAW,QAAQ,KAAA,EAAU,CACvC,GAAC,EAAA,cACW,MAAM,OAAM,CAAA,GAAA,CAEvB,MAAM,WAAW,aAAUD,YAAA,OAEpB,WACF,EACE,IAAI,CACF,kBAAkB,UAClB,SAAA,SAAY,QAAQ,kBAAkB,gBAAgB,EAE1D,GAAC,cAAA,OAED,EAAE,eAAe,KAAK,CACxB,GAAC,CAAA,SAAA,KAAA,CAAA,IAAAA,YAAA,UAAAC,cAAA,EAAA,OAMI,MAAM,WAAU,GACjB,WAAqB,EAAE,IAAI,kBAAkB,OAAO,GAAC,YAAA,OAAe;GACtE,eAAe;GACf,KAAG;EACL,CAAC,CAAC,GAAA,IAAA,CAEL,CAAA;CAGP;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
1
+ {"version":3,"file":"ThreeCanvas.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../../src/three/core/ThreeCanvas.tsx"],"sourcesContent":["/**\n * three.js 画布(div > canvas):渲染器的生命周期交给 useThree,这里只负责外层结构、降级与无障碍。\n *\n * <ThreeCanvas\n * sx={styles.hero}\n * setup={(context) => {\n * const mesh = new Mesh(new IcosahedronGeometry(1, 4), new MeshNormalMaterial());\n * context.scene.add(mesh);\n * return { frame: ({ time }) => (mesh.rotation.y = time) };\n * }}\n * />\n *\n * - 尺寸由外层 div 决定(默认占满父元素),canvas 铺满它,背景透明;\n * - 没有 WebGL、或 quality=\"off\" 时显示 fallback,默认是一层主题色的柔和渐变;\n * - 默认是装饰(aria-hidden);传了 aria-label 时是一张图(role=\"img\");\n * - 渲染状态写在根元素的 data-state 上(idle / running / paused / still / fallback)。\n *\n * 部件:Root(div)、Canvas(canvas,重建时换新的一块)、Fallback(div,降级内容)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { watch, type VNodeChild } from 'vue';\nimport { mergeAttrs, type PartProps } from '../../utils/props';\nimport type { ThreeQuality } from './quality';\nimport { useThree, type ThreeContext, type ThreeSceneHandle, type ThreeStatus } from './renderer';\nimport { t } from '../../config/theme/tokens';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ThreeCanvasProps extends PartProps<'div', 'role' | 'data-state'> {\n /** 搭场景:每次创建渲染器时调用一次(被回收、上下文丢失后会重新调用),返回每帧、尺寸变化、释放的回调 */\n setup: (context: ThreeContext) => ThreeSceneHandle | void;\n /**\n * 画质档位:像素比上限、粒子密度、抗锯齿;变了会重建。off 不创建 WebGL,显示 fallback\n * @default 'auto'\n */\n quality?: ThreeQuality;\n /** 暂停动画,停在当前画面 */\n paused?: boolean;\n /**\n * 渲染分辨率相对像素比的倍数(0.1–1):平滑的渐变、模糊的效果降低它能大幅省下 GPU 开销\n * @default 1\n */\n resolution?: number;\n /** 没有 WebGL(或 quality 为 off)时显示的内容,默认是主题色的柔和渐变 */\n fallback?: VNodeChild;\n /** 渲染状态变化时调用(同根元素的 data-state),挂载时先调用一次:比如降级时改放一张静态图,或一次性的效果直接收尾 */\n onStatusChange?: (status: ThreeStatus) => void;\n /** canvas 的部件属性 */\n propsCanvas?: PartProps<'canvas', 'aria-hidden'>;\n /** 降级内容外层的部件属性 */\n propsFallback?: PartProps<'div', 'aria-hidden'>;\n}\n\n/** ThreeCanvas 的样式:root、canvas、fallback、fallbackGradient(默认的降级渐变) */\nexport const threeCanvasStyles = css.create({\n root: {\n position: 'relative',\n display: 'block',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n },\n canvas: {\n position: 'absolute',\n inset: 0,\n display: 'block',\n width: '100%',\n height: '100%',\n },\n fallback: { position: 'absolute', inset: 0 },\n fallbackGradient: {\n backgroundImage: `radial-gradient(circle at 20% 25%, color-mix(in oklab, ${t.colors.accent} 28%, transparent), transparent 55%), radial-gradient(circle at 80% 70%, color-mix(in oklab, ${t.colors.chart3} 24%, transparent), transparent 55%), radial-gradient(circle at 60% 15%, color-mix(in oklab, ${t.colors.chart5} 18%, transparent), transparent 50%)`,\n },\n});\n\n/** three.js 画布:生命周期、降级、无障碍,场景由 setup 搭建 */\nexport const ThreeCanvas = _component(\n ({\n setup,\n quality = 'auto',\n paused = false,\n resolution = 1,\n fallback,\n onStatusChange,\n propsCanvas,\n propsFallback,\n ...rest\n }: ThreeCanvasProps) => {\n let canvas = _state.raw<HTMLCanvasElement | null>(null);\n const three = useThree({\n canvas: () => canvas,\n setup: (context) => setup(context),\n quality: () => quality,\n paused: () => paused,\n resolution: () => resolution,\n });\n // 挂载时先报告一次:quality=\"off\" 一开始就是 fallback,之后不再变\n watch(\n () => three.status,\n (status) => onStatusChange?.(status),\n { immediate: true },\n );\n\n return () => {\n const labelled = rest['aria-label'] != null || rest['aria-labelledby'] != null;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: threeCanvasStyles.root, 'aria-hidden': labelled ? undefined : true },\n rest,\n { role: labelled ? 'img' : undefined },\n )}\n data-state={three.status}\n >\n {three.status === 'fallback' ? (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n threeCanvasStyles.fallback,\n fallback == null && threeCanvasStyles.fallbackGradient,\n ],\n },\n propsFallback,\n { 'aria-hidden': true },\n )}\n >\n {fallback}\n </div>\n ) : (\n <canvas\n key={three.generation}\n {...mergeAttrs<'canvas'>({ sx: threeCanvasStyles.canvas }, propsCanvas, {\n 'aria-hidden': true,\n ref: _toRef(canvas),\n })}\n />\n )}\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;AAsDA,IAAa,oBAAoB,IAAI,OAAO;CAC1C,MAAM;EACJ,UAAU;EACV,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;CACZ;CACA,QAAQ;EACN,UAAU;EACV,OAAO;EACP,SAAS;EACT,OAAO;EACP,QAAQ;CACV;CACA,UAAU;EAAE,UAAU;EAAY,OAAO;CAAE;CAC3C,kBAAkB,EAChB,iBAAiB,0DAA0D,EAAE,OAAO,OAAM,+FAAgG,EAAE,OAAO,OAAM,+FAAgG,EAAE,OAAO,OAAM,sCAC1T;AACF,CAAC;;AAGD,IAAa,cAAc,0BACzB,QAAA,SAUwB;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,WARZ,MAAM;CAAA,MAAA,SAAAA,aAAA,QAAA,UACP,KAAK;CAAA,MAAA,aAAAA,aAAA,QAAA,cACD,CAAC;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,iBAAAA,aAAA,QAAA,gBAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,eAAA;CAAA,MAKX,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,IAAI,SAAMC,WAAwC,IAAI;CACtD,MAAM,QAAQ,SAAS;EACrB,cAAQ,OAAA;EACR,QAAQ,YAAY,MAAA,MAAM,OAAO;EACjC,eAAS,QAAA;EACT,cAAQ,OAAA;EACR,kBAAY,WAAA;CACd,CAAC;CAED,YACQ,MAAM,SACX,WAAW,eAAA,QAAiB,MAAM,GACnC,EAAE,WAAW,KAAK,CACpB;CAEA,aAAa;EACX,MAAM,WAAW,KAAK,iBAAiB,QAAQ,KAAK,sBAAsB;EAC1E,OAAAC,YAAA,OAAAC,cAEQ,WACF;GAAE,IAAI,kBAAkB;GAAM,eAAe,WAAW,KAAA,IAAY;EAAK,GACzE,MACA,EAAE,MAAM,WAAW,QAAQ,KAAA,EAAU,CACvC,GAAC,EAAA,cACW,MAAM,OAAM,CAAA,GAAA,CAEvB,MAAM,WAAW,aAAUD,YAAA,OAEpB,WACF,EACE,IAAI,CACF,kBAAkB,UAClB,SAAA,SAAY,QAAQ,kBAAkB,gBAAgB,EAE1D,GAAC,cAAA,OAED,EAAE,eAAe,KAAK,CACxB,GAAC,CAAA,SAAA,KAAA,CAAA,IAAAA,YAAA,UAAAC,cAAA,EAAA,OAMI,MAAM,WAAU,GACjB,WAAqB,EAAE,IAAI,kBAAkB,OAAO,GAAC,YAAA,OAAe;GACtE,eAAe;GACf,KAAG;EACL,CAAC,CAAC,GAAA,IAAA,CAEL,CAAA;CAGP;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import { type EffectProps } from '../core/EffectSurface';
3
3
  /** 彩纸的默认色板:图表色板的前六个 */
4
4
  export declare const CONFETTI_PALETTE: readonly string[];
@@ -4,7 +4,7 @@ import { toElement } from "../../utils/dom/element.js";
4
4
  import { EffectSurface } from "../core/EffectSurface.js";
5
5
  import { createVNode, ref, watch } from "vue";
6
6
  import { _component, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
7
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
7
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
8
8
  import { Color, DoubleSide, InstancedMesh, Matrix4, MeshBasicMaterial, OrthographicCamera, PlaneGeometry, Quaternion, Vector3 } from "three";
9
9
  //#region src/three/effects/Confetti.tsx
10
10
  /** 彩纸的默认色板:图表色板的前六个 */
@@ -1 +1 @@
1
- {"version":3,"file":"Confetti.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../../src/three/effects/Confetti.tsx"],"sourcesContent":["/**\n * 彩纸(庆祝):trigger 每变一次放一批,彩纸从 origin 喷出,翻转着飘落后消失。参考 canvas-confetti 的 origin、angle、spread。\n *\n * <Confetti trigger={paidCount} /> // 铺满视口,从中间偏下向上喷\n * <Confetti trigger={n} origin={{ x: 0, y: 1 }} angle={60} /> // 从左下角斜着喷\n * <div style=\"position: relative\"><Confetti fullscreen={false} trigger={n} /></div>\n *\n * 只在彩纸还在飘的时候才有画布:不放的时候不占 WebGL 上下文。默认铺满视口、放在顶层(原生 popover,\n * 盖得住打开着的对话框),指针穿透;fullscreen 为 false 时铺满最近的定位父元素。\n * 颜色取主题的图表色板,换主题时跟着变;系统或主题要求减少动态效果时不放(onDone 照常调用)。画面是装饰,读屏跳过。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n Color,\n DoubleSide,\n InstancedMesh,\n Matrix4,\n MeshBasicMaterial,\n OrthographicCamera,\n PlaneGeometry,\n Quaternion,\n Vector3,\n} from 'three';\nimport { watch } from 'vue';\nimport { colors } from '../../config/theme/tokens';\nimport { toElement } from '../../utils/dom/element';\nimport { mergePartProps } from '../../utils/props';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport type { ThreeCanvasProps } from '../core/ThreeCanvas';\n\n/** 彩纸的默认色板:图表色板的前六个 */\nexport const CONFETTI_PALETTE: readonly string[] = [\n colors.chart1,\n colors.chart2,\n colors.chart3,\n colors.chart4,\n colors.chart5,\n colors.chart6,\n];\n\n/** 喷出的位置:相对区域的比例,x 从左到右、y 从上到下(0–1) */\nexport interface ConfettiOrigin {\n /** 从左(0)到右(1) */\n x: number;\n /** 从上(0)到下(1) */\n y: number;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ConfettiProps extends Omit<EffectProps, 'children' | 'fallback' | 'paused'> {\n /** 每变一次放一批(挂载时的初始值不放):写成计数、时间戳或任何会变的值 */\n trigger?: unknown;\n /**\n * 喷出的位置\n * @default { x: 0.5, y: 0.6 }\n */\n origin?: ConfettiOrigin;\n /**\n * 喷出的方向(度),90 是正上方,0 向右\n * @default 90\n */\n angle?: number;\n /**\n * 散开的角度(度)\n * @default 70\n */\n spread?: number;\n /**\n * 每批的数量\n * @default 160\n */\n count?: number;\n /**\n * 初速度的倍数\n * @default 1\n */\n velocity?: number;\n /**\n * 重力的倍数\n * @default 1\n */\n gravity?: number;\n /** 色板(token 或 CSS 颜色);变了下一次放时生效 */\n palette?: readonly string[];\n /**\n * 铺满视口,放在顶层;false 时铺满最近的定位父元素\n * @default true\n */\n fullscreen?: boolean;\n /** 这几批彩纸都落完(或减少动态效果时没有放)后调用 */\n onDone?: () => void;\n}\n\n/** Confetti 的样式:root、fullscreen */\nexport const confettiStyles = css.create({\n root: { position: 'absolute', inset: 0, pointerEvents: 'none' },\n // 原生 popover 的默认样式(居中、边框、底色)改成铺满视口的透明层\n fullscreen: {\n position: 'fixed',\n inset: 0,\n width: '100vw',\n height: '100vh',\n maxWidth: 'none',\n maxHeight: 'none',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n backgroundColor: 'transparent',\n overflow: 'hidden',\n },\n});\n\n/** 同时在飘的彩纸上限 */\nconst MAX_PIECES = 900;\n/** 空气阻力(每秒速度剩下 e^-DRAG):喷出后很快慢下来,落得轻飘 */\nconst DRAG = 2.6;\n/** 一片彩纸飘多久(秒),最后一段缩小消失 */\nconst LIFETIME = [3.2, 4.6] as const;\nconst SHRINK = 0.6;\n/** 重力:每秒加速多少个区域高度 */\nconst GRAVITY = 1.1;\n\n/** 一批:放的那一刻的参数 */\ninterface Burst {\n origin: ConfettiOrigin;\n angle: number;\n spread: number;\n count: number;\n velocity: number;\n gravity: number;\n}\n\nconst random = (min: number, max: number) => min + Math.random() * (max - min);\n\n/** 彩纸 */\nexport const Confetti = _component(\n ({\n trigger,\n origin = { x: 0.5, y: 0.6 },\n angle = 90,\n spread = 70,\n count = 160,\n velocity = 1,\n gravity = 1,\n palette = CONFETTI_PALETTE,\n fullscreen = true,\n onDone,\n ...rest\n }: ConfettiProps) => {\n // 还没放出去的批次:画布建好后在下一帧里放\n const pending: Burst[] = [];\n let active = _state(false);\n\n watch(\n () => trigger,\n () => {\n pending.push({ origin, angle, spread, count, velocity, gravity });\n active = true;\n },\n );\n\n function finish() {\n // 在帧回调里:等这一帧结束再卸载画布\n queueMicrotask(() => {\n if (pending.length) return;\n active = false;\n onDone?.();\n });\n }\n\n /** 顶层显示:卸载时元素随之移除,不用手动收起 */\n function showOnTop(element: unknown) {\n const root = toElement(element);\n if (!fullscreen || !root || !('showPopover' in root)) return;\n // 顶层里后进的在上面:同一刻打开的对话框(支付成功)会盖住彩纸,等这一帧过去再进顶层\n requestAnimationFrame(() => {\n if (root.isConnected && !root.matches(':popover-open')) root.showPopover();\n });\n }\n\n return () =>\n active && (\n <EffectSurface\n {...rest}\n {...{ ref: showOnTop }}\n sx={[confettiStyles.root, fullscreen && confettiStyles.fullscreen, rest.sx]}\n popover={fullscreen ? 'manual' : undefined}\n aria-hidden=\"true\"\n // 没有 WebGL:什么也不画(不要默认的渐变铺满屏幕),直接收尾\n fallback={false}\n propsCanvas={mergePartProps<Partial<ThreeCanvasProps>>({}, rest.propsCanvas, {\n onStatusChange: (status) => {\n if (status !== 'fallback') return;\n pending.length = 0;\n finish();\n },\n })}\n sceneKey={palette.join(',')}\n setup={({ scene, size: area, still, themeColorList }) => {\n if (still) {\n pending.length = 0;\n finish();\n return;\n }\n const camera = new OrthographicCamera(0, 1, 1, 0, -500, 500);\n const tints = themeColorList(palette);\n\n const mesh = new InstancedMesh(\n new PlaneGeometry(1, 1),\n new MeshBasicMaterial({ side: DoubleSide }),\n MAX_PIECES,\n );\n mesh.frustumCulled = false;\n mesh.count = 0;\n scene.add(mesh);\n\n // 每片的状态:位置、速度、尺寸、翻转轴与角度、摆动、寿命、颜色\n const position = new Float32Array(MAX_PIECES * 2);\n const speed = new Float32Array(MAX_PIECES * 2);\n const shape = new Float32Array(MAX_PIECES * 2);\n const axis = new Float32Array(MAX_PIECES * 3);\n const turn = new Float32Array(MAX_PIECES * 2);\n const sway = new Float32Array(MAX_PIECES * 2);\n const life = new Float32Array(MAX_PIECES * 2);\n const fall = new Float32Array(MAX_PIECES);\n const tint = new Uint8Array(MAX_PIECES);\n let alive = 0;\n\n function launch(burst: Burst) {\n const x0 = burst.origin.x * area.width;\n const y0 = (1 - burst.origin.y) * area.height;\n // 初速度与重力都按区域高度(H):大小不同的区域里看起来一样,最快的升到 0.9H 左右、最慢的 0.3H\n const base = area.height * 3.2 * burst.velocity;\n for (let n = 0; n < burst.count && alive < MAX_PIECES; n++, alive++) {\n const i = alive;\n const direction =\n ((burst.angle + random(-burst.spread / 2, burst.spread / 2)) * Math.PI) / 180;\n const v = base * random(0.45, 1);\n position[i * 2] = x0;\n position[i * 2 + 1] = y0;\n speed[i * 2] = Math.cos(direction) * v;\n speed[i * 2 + 1] = Math.sin(direction) * v;\n const width = random(7, 12);\n shape[i * 2] = width;\n shape[i * 2 + 1] = width * random(0.45, 0.8);\n const a = new Vector3(random(-1, 1), random(-1, 1), random(-1, 1)).normalize();\n axis.set([a.x, a.y, a.z], i * 3);\n turn[i * 2] = random(0, Math.PI * 2);\n turn[i * 2 + 1] = random(6, 14) * (Math.random() < 0.5 ? -1 : 1);\n sway[i * 2] = random(0, Math.PI * 2);\n sway[i * 2 + 1] = random(20, 60);\n life[i * 2] = 0;\n life[i * 2 + 1] = random(...LIFETIME);\n fall[i] = burst.gravity;\n tint[i] = Math.floor(Math.random() * tints.length);\n }\n }\n\n /** 把第 to 片换成第 from 片(落完的那片用最后一片补上,活着的始终在前面) */\n function move(from: number, to: number) {\n for (const [array, size] of [\n [position, 2],\n [speed, 2],\n [shape, 2],\n [axis, 3],\n [turn, 2],\n [sway, 2],\n [life, 2],\n ] as const) {\n array.copyWithin(to * size, from * size, from * size + size);\n }\n fall[to] = fall[from]!;\n tint[to] = tint[from]!;\n }\n\n const matrix = new Matrix4();\n const rotation = new Quaternion();\n const scale = new Vector3();\n const at = new Vector3();\n const normal = new Vector3();\n const shade = new Color();\n\n return {\n resize: (next, context) => {\n camera.right = next.width;\n camera.top = next.height;\n camera.updateProjectionMatrix();\n context.camera = camera;\n },\n frame: ({ delta }) => {\n // 画布刚建好的第一帧可能还没量到尺寸:量到了再放\n while (pending.length && area.height > 0) launch(pending.shift()!);\n const damping = Math.exp(-DRAG * delta);\n for (let i = 0; i < alive; i++) {\n life[i * 2]! += delta;\n const age = life[i * 2]!;\n const lifetime = life[i * 2 + 1]!;\n if (age >= lifetime || position[i * 2 + 1]! < -40) {\n move(--alive, i--);\n continue;\n }\n speed[i * 2]! *= damping;\n speed[i * 2 + 1] =\n speed[i * 2 + 1]! * damping - area.height * GRAVITY * fall[i]! * delta;\n // 左右摆动:像纸片在空气里飘\n sway[i * 2]! += delta * 4;\n position[i * 2]! +=\n (speed[i * 2]! + Math.sin(sway[i * 2]!) * sway[i * 2 + 1]!) * delta;\n position[i * 2 + 1]! += speed[i * 2 + 1]! * delta;\n turn[i * 2]! += turn[i * 2 + 1]! * delta;\n\n rotation.setFromAxisAngle(\n at.set(axis[i * 3]!, axis[i * 3 + 1]!, axis[i * 3 + 2]!),\n turn[i * 2]!,\n );\n const fade = Math.min(1, (lifetime - age) / SHRINK);\n scale.set(shape[i * 2]! * fade, shape[i * 2 + 1]! * fade, 1);\n matrix.compose(\n at.set(position[i * 2]!, position[i * 2 + 1]!, 0),\n rotation,\n scale,\n );\n mesh.setMatrixAt(i, matrix);\n // 翻到侧面时暗一些:正对屏幕最亮,看起来是在翻转的纸片\n const facing = Math.abs(normal.set(0, 0, 1).applyQuaternion(rotation).z);\n mesh.setColorAt(\n i,\n shade.copy(tints[tint[i]!]!).multiplyScalar(0.55 + 0.45 * facing),\n );\n }\n mesh.count = alive;\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;\n if (alive === 0) finish();\n },\n };\n }}\n />\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"Confetti.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../../src/three/effects/Confetti.tsx"],"sourcesContent":["/**\n * 彩纸(庆祝):trigger 每变一次放一批,彩纸从 origin 喷出,翻转着飘落后消失。参考 canvas-confetti 的 origin、angle、spread。\n *\n * <Confetti trigger={paidCount} /> // 铺满视口,从中间偏下向上喷\n * <Confetti trigger={n} origin={{ x: 0, y: 1 }} angle={60} /> // 从左下角斜着喷\n * <div style=\"position: relative\"><Confetti fullscreen={false} trigger={n} /></div>\n *\n * 只在彩纸还在飘的时候才有画布:不放的时候不占 WebGL 上下文。默认铺满视口、放在顶层(原生 popover,\n * 盖得住打开着的对话框),指针穿透;fullscreen 为 false 时铺满最近的定位父元素。\n * 颜色取主题的图表色板,换主题时跟着变;系统或主题要求减少动态效果时不放(onDone 照常调用)。画面是装饰,读屏跳过。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n Color,\n DoubleSide,\n InstancedMesh,\n Matrix4,\n MeshBasicMaterial,\n OrthographicCamera,\n PlaneGeometry,\n Quaternion,\n Vector3,\n} from 'three';\nimport { watch } from 'vue';\nimport { colors } from '../../config/theme/tokens';\nimport { toElement } from '../../utils/dom/element';\nimport { mergePartProps } from '../../utils/props';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport type { ThreeCanvasProps } from '../core/ThreeCanvas';\n\n/** 彩纸的默认色板:图表色板的前六个 */\nexport const CONFETTI_PALETTE: readonly string[] = [\n colors.chart1,\n colors.chart2,\n colors.chart3,\n colors.chart4,\n colors.chart5,\n colors.chart6,\n];\n\n/** 喷出的位置:相对区域的比例,x 从左到右、y 从上到下(0–1) */\nexport interface ConfettiOrigin {\n /** 从左(0)到右(1) */\n x: number;\n /** 从上(0)到下(1) */\n y: number;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ConfettiProps extends Omit<EffectProps, 'children' | 'fallback' | 'paused'> {\n /** 每变一次放一批(挂载时的初始值不放):写成计数、时间戳或任何会变的值 */\n trigger?: unknown;\n /**\n * 喷出的位置\n * @default { x: 0.5, y: 0.6 }\n */\n origin?: ConfettiOrigin;\n /**\n * 喷出的方向(度),90 是正上方,0 向右\n * @default 90\n */\n angle?: number;\n /**\n * 散开的角度(度)\n * @default 70\n */\n spread?: number;\n /**\n * 每批的数量\n * @default 160\n */\n count?: number;\n /**\n * 初速度的倍数\n * @default 1\n */\n velocity?: number;\n /**\n * 重力的倍数\n * @default 1\n */\n gravity?: number;\n /** 色板(token 或 CSS 颜色);变了下一次放时生效 */\n palette?: readonly string[];\n /**\n * 铺满视口,放在顶层;false 时铺满最近的定位父元素\n * @default true\n */\n fullscreen?: boolean;\n /** 这几批彩纸都落完(或减少动态效果时没有放)后调用 */\n onDone?: () => void;\n}\n\n/** Confetti 的样式:root、fullscreen */\nexport const confettiStyles = css.create({\n root: { position: 'absolute', inset: 0, pointerEvents: 'none' },\n // 原生 popover 的默认样式(居中、边框、底色)改成铺满视口的透明层\n fullscreen: {\n position: 'fixed',\n inset: 0,\n width: '100vw',\n height: '100vh',\n maxWidth: 'none',\n maxHeight: 'none',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n backgroundColor: 'transparent',\n overflow: 'hidden',\n },\n});\n\n/** 同时在飘的彩纸上限 */\nconst MAX_PIECES = 900;\n/** 空气阻力(每秒速度剩下 e^-DRAG):喷出后很快慢下来,落得轻飘 */\nconst DRAG = 2.6;\n/** 一片彩纸飘多久(秒),最后一段缩小消失 */\nconst LIFETIME = [3.2, 4.6] as const;\nconst SHRINK = 0.6;\n/** 重力:每秒加速多少个区域高度 */\nconst GRAVITY = 1.1;\n\n/** 一批:放的那一刻的参数 */\ninterface Burst {\n origin: ConfettiOrigin;\n angle: number;\n spread: number;\n count: number;\n velocity: number;\n gravity: number;\n}\n\nconst random = (min: number, max: number) => min + Math.random() * (max - min);\n\n/** 彩纸 */\nexport const Confetti = _component(\n ({\n trigger,\n origin = { x: 0.5, y: 0.6 },\n angle = 90,\n spread = 70,\n count = 160,\n velocity = 1,\n gravity = 1,\n palette = CONFETTI_PALETTE,\n fullscreen = true,\n onDone,\n ...rest\n }: ConfettiProps) => {\n // 还没放出去的批次:画布建好后在下一帧里放\n const pending: Burst[] = [];\n let active = _state(false);\n\n watch(\n () => trigger,\n () => {\n pending.push({ origin, angle, spread, count, velocity, gravity });\n active = true;\n },\n );\n\n function finish() {\n // 在帧回调里:等这一帧结束再卸载画布\n queueMicrotask(() => {\n if (pending.length) return;\n active = false;\n onDone?.();\n });\n }\n\n /** 顶层显示:卸载时元素随之移除,不用手动收起 */\n function showOnTop(element: unknown) {\n const root = toElement(element);\n if (!fullscreen || !root || !('showPopover' in root)) return;\n // 顶层里后进的在上面:同一刻打开的对话框(支付成功)会盖住彩纸,等这一帧过去再进顶层\n requestAnimationFrame(() => {\n if (root.isConnected && !root.matches(':popover-open')) root.showPopover();\n });\n }\n\n return () =>\n active && (\n <EffectSurface\n {...rest}\n {...{ ref: showOnTop }}\n sx={[confettiStyles.root, fullscreen && confettiStyles.fullscreen, rest.sx]}\n popover={fullscreen ? 'manual' : undefined}\n aria-hidden=\"true\"\n // 没有 WebGL:什么也不画(不要默认的渐变铺满屏幕),直接收尾\n fallback={false}\n propsCanvas={mergePartProps<Partial<ThreeCanvasProps>>({}, rest.propsCanvas, {\n onStatusChange: (status) => {\n if (status !== 'fallback') return;\n pending.length = 0;\n finish();\n },\n })}\n sceneKey={palette.join(',')}\n setup={({ scene, size: area, still, themeColorList }) => {\n if (still) {\n pending.length = 0;\n finish();\n return;\n }\n const camera = new OrthographicCamera(0, 1, 1, 0, -500, 500);\n const tints = themeColorList(palette);\n\n const mesh = new InstancedMesh(\n new PlaneGeometry(1, 1),\n new MeshBasicMaterial({ side: DoubleSide }),\n MAX_PIECES,\n );\n mesh.frustumCulled = false;\n mesh.count = 0;\n scene.add(mesh);\n\n // 每片的状态:位置、速度、尺寸、翻转轴与角度、摆动、寿命、颜色\n const position = new Float32Array(MAX_PIECES * 2);\n const speed = new Float32Array(MAX_PIECES * 2);\n const shape = new Float32Array(MAX_PIECES * 2);\n const axis = new Float32Array(MAX_PIECES * 3);\n const turn = new Float32Array(MAX_PIECES * 2);\n const sway = new Float32Array(MAX_PIECES * 2);\n const life = new Float32Array(MAX_PIECES * 2);\n const fall = new Float32Array(MAX_PIECES);\n const tint = new Uint8Array(MAX_PIECES);\n let alive = 0;\n\n function launch(burst: Burst) {\n const x0 = burst.origin.x * area.width;\n const y0 = (1 - burst.origin.y) * area.height;\n // 初速度与重力都按区域高度(H):大小不同的区域里看起来一样,最快的升到 0.9H 左右、最慢的 0.3H\n const base = area.height * 3.2 * burst.velocity;\n for (let n = 0; n < burst.count && alive < MAX_PIECES; n++, alive++) {\n const i = alive;\n const direction =\n ((burst.angle + random(-burst.spread / 2, burst.spread / 2)) * Math.PI) / 180;\n const v = base * random(0.45, 1);\n position[i * 2] = x0;\n position[i * 2 + 1] = y0;\n speed[i * 2] = Math.cos(direction) * v;\n speed[i * 2 + 1] = Math.sin(direction) * v;\n const width = random(7, 12);\n shape[i * 2] = width;\n shape[i * 2 + 1] = width * random(0.45, 0.8);\n const a = new Vector3(random(-1, 1), random(-1, 1), random(-1, 1)).normalize();\n axis.set([a.x, a.y, a.z], i * 3);\n turn[i * 2] = random(0, Math.PI * 2);\n turn[i * 2 + 1] = random(6, 14) * (Math.random() < 0.5 ? -1 : 1);\n sway[i * 2] = random(0, Math.PI * 2);\n sway[i * 2 + 1] = random(20, 60);\n life[i * 2] = 0;\n life[i * 2 + 1] = random(...LIFETIME);\n fall[i] = burst.gravity;\n tint[i] = Math.floor(Math.random() * tints.length);\n }\n }\n\n /** 把第 to 片换成第 from 片(落完的那片用最后一片补上,活着的始终在前面) */\n function move(from: number, to: number) {\n for (const [array, size] of [\n [position, 2],\n [speed, 2],\n [shape, 2],\n [axis, 3],\n [turn, 2],\n [sway, 2],\n [life, 2],\n ] as const) {\n array.copyWithin(to * size, from * size, from * size + size);\n }\n fall[to] = fall[from]!;\n tint[to] = tint[from]!;\n }\n\n const matrix = new Matrix4();\n const rotation = new Quaternion();\n const scale = new Vector3();\n const at = new Vector3();\n const normal = new Vector3();\n const shade = new Color();\n\n return {\n resize: (next, context) => {\n camera.right = next.width;\n camera.top = next.height;\n camera.updateProjectionMatrix();\n context.camera = camera;\n },\n frame: ({ delta }) => {\n // 画布刚建好的第一帧可能还没量到尺寸:量到了再放\n while (pending.length && area.height > 0) launch(pending.shift()!);\n const damping = Math.exp(-DRAG * delta);\n for (let i = 0; i < alive; i++) {\n life[i * 2]! += delta;\n const age = life[i * 2]!;\n const lifetime = life[i * 2 + 1]!;\n if (age >= lifetime || position[i * 2 + 1]! < -40) {\n move(--alive, i--);\n continue;\n }\n speed[i * 2]! *= damping;\n speed[i * 2 + 1] =\n speed[i * 2 + 1]! * damping - area.height * GRAVITY * fall[i]! * delta;\n // 左右摆动:像纸片在空气里飘\n sway[i * 2]! += delta * 4;\n position[i * 2]! +=\n (speed[i * 2]! + Math.sin(sway[i * 2]!) * sway[i * 2 + 1]!) * delta;\n position[i * 2 + 1]! += speed[i * 2 + 1]! * delta;\n turn[i * 2]! += turn[i * 2 + 1]! * delta;\n\n rotation.setFromAxisAngle(\n at.set(axis[i * 3]!, axis[i * 3 + 1]!, axis[i * 3 + 2]!),\n turn[i * 2]!,\n );\n const fade = Math.min(1, (lifetime - age) / SHRINK);\n scale.set(shape[i * 2]! * fade, shape[i * 2 + 1]! * fade, 1);\n matrix.compose(\n at.set(position[i * 2]!, position[i * 2 + 1]!, 0),\n rotation,\n scale,\n );\n mesh.setMatrixAt(i, matrix);\n // 翻到侧面时暗一些:正对屏幕最亮,看起来是在翻转的纸片\n const facing = Math.abs(normal.set(0, 0, 1).applyQuaternion(rotation).z);\n mesh.setColorAt(\n i,\n shade.copy(tints[tint[i]!]!).multiplyScalar(0.55 + 0.45 * facing),\n );\n }\n mesh.count = alive;\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;\n if (alive === 0) finish();\n },\n };\n }}\n />\n );\n },\n);\n"],"mappings":";;;;;;;;;;AAkCA,IAAa,mBAAsC;CACjD,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;AAAM;;;;AAyDf,IAAa,iBAAiB,IAAI,OAAO;CACvC,MAAM;EAAE,UAAU;EAAY,OAAO;EAAG,eAAe;CAAO;CAE9D,YAAY;EACV,UAAU;EACV,OAAO;EACP,OAAO;EACP,QAAQ;EACR,UAAU;EACV,WAAW;EACX,QAAQ;EACR,SAAS;EACT,aAAa;EACb,iBAAiB;EACjB,UAAU;CACZ;AACF,CAAC;;AAGD,IAAM,aAAa;;AAInB,IAAM,WAAW,CAAC,KAAK,GAAG;AAC1B,IAAM,SAAS;;AAEf,IAAM,UAAU;;AAYhB,IAAM,UAAU,KAAa,QAAgB,MAAM,KAAK,OAAO,KAAK,MAAM;;AAG1E,IAAa,WAAW,0BACtB,QAAA,SAYqB;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,SAAAA,aAAA,QAAA,iBAVV;EAAE,GAAG;EAAK,GAAG;CAAI,EAAC;CAAA,MAAA,QAAAA,aAAA,QAAA,SACnB,EAAE;CAAA,MAAA,SAAAA,aAAA,QAAA,UACD,EAAE;CAAA,MAAA,QAAAA,aAAA,QAAA,SACH,GAAG;CAAA,MAAA,WAAAA,aAAA,QAAA,YACA,CAAC;CAAA,MAAA,UAAAA,aAAA,QAAA,WACF,CAAC;CAAA,MAAA,UAAAA,aAAA,QAAA,iBACD,gBAAgB;CAAA,MAAA,aAAAA,aAAA,QAAA,cACb,IAAI;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAEd,OAAIC,UAAA,QAAA,MAAA,IAAA;CAGP,MAAM,UAAmB,CAAA;CACzB,IAAI,SAAMC,IAAU,KAAK;CAEzB,YACE,QAAA,aACM;EACJ,QAAQ,KAAK;GAAE,QAAM,OAAA;GAAE,OAAK,MAAA;GAAE,QAAM,OAAA;GAAE,OAAK,MAAA;GAAE,UAAQ,SAAA;GAAE,SAAO,QAAA;EAAC,CAAC;EAChE,OAAA,QAAS;CACX,CACF;CAEA,SAAS,SAAS;EAEhB,qBAAqB;GACnB,IAAI,QAAQ,QAAQ;GACpB,OAAA,QAAS;GACT,OAAA,QAAS;EACX,CAAC;CACH;;CAGA,SAAS,UAAU,SAAkB;EACnC,MAAM,OAAO,UAAU,OAAO;EAC9B,IAAI,CAAA,WAAA,SAAe,CAAC,QAAQ,EAAE,iBAAiB,OAAO;EAEtD,4BAA4B;GAC1B,IAAI,KAAK,eAAe,CAAC,KAAK,QAAQ,eAAe,GAAG,KAAK,YAAY;EAC3E,CAAC;CACH;CAEA,aACE,OAAA,SAAAC,YAAA,eAAAC,cAEQ,MAAI,EACF,KAAK,UAAS,GAAA;EAAA,MAChB;GAAC,eAAe;GAAM,WAAA,SAAc,eAAe;GAAY,KAAK;EAAE;EAAC,WAClE,WAAA,QAAa,WAAW,KAAA;EAAS,eAAA;EAAA,YAGhC;EAAK,eACF,eAA0C,CAAC,GAAG,KAAK,aAAa,EAC3E,iBAAiB,WAAW;GAC1B,IAAI,WAAW,YAAY;GAC3B,QAAQ,SAAS;GACjB,OAAO;EACT,EACF,CAAC;EAAC,YACQ,QAAA,MAAQ,KAAK,GAAG;EAAC,SAAA,OAAA,OAAA,OAAA,MACnB,EAAE,OAAO,MAAM,MAAM,OAAO,qBAAqB;GACvD,IAAI,OAAO;IACT,QAAQ,SAAS;IACjB,OAAO;IACP;GACF;GACA,MAAM,SAAS,IAAI,mBAAmB,GAAG,GAAG,GAAG,GAAG,MAAM,GAAG;GAC3D,MAAM,QAAQ,eAAc,QAAA,KAAQ;GAEpC,MAAM,OAAO,IAAI,cACf,IAAI,cAAc,GAAG,CAAC,GACtB,IAAI,kBAAkB,EAAE,MAAM,WAAW,CAAC,GAC1C,UACF;GACA,KAAK,gBAAgB;GACrB,KAAK,QAAQ;GACb,MAAM,IAAI,IAAI;GAGd,MAAM,WAAW,IAAI,aAAa,aAAa,CAAC;GAChD,MAAM,QAAQ,IAAI,aAAa,aAAa,CAAC;GAC7C,MAAM,QAAQ,IAAI,aAAa,aAAa,CAAC;GAC7C,MAAM,OAAO,IAAI,aAAa,aAAa,CAAC;GAC5C,MAAM,OAAO,IAAI,aAAa,aAAa,CAAC;GAC5C,MAAM,OAAO,IAAI,aAAa,aAAa,CAAC;GAC5C,MAAM,OAAO,IAAI,aAAa,aAAa,CAAC;GAC5C,MAAM,OAAO,IAAI,aAAa,UAAU;GACxC,MAAM,OAAO,IAAI,WAAW,UAAU;GACtC,IAAI,QAAQ;GAEZ,SAAS,OAAO,OAAc;IAC5B,MAAM,KAAK,MAAM,OAAO,IAAI,KAAK;IACjC,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK,KAAK;IAEvC,MAAM,OAAO,KAAK,SAAS,MAAM,MAAM;IACvC,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,SAAS,QAAQ,YAAY,KAAK,SAAS;KACnE,MAAM,IAAI;KACV,MAAM,aACF,MAAM,QAAQ,OAAO,CAAC,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,KAAK,KAAK,KAAM;KAC5E,MAAM,IAAI,OAAO,OAAO,KAAM,CAAC;KAC/B,SAAS,IAAI,KAAK;KAClB,SAAS,IAAI,IAAI,KAAK;KACtB,MAAM,IAAI,KAAK,KAAK,IAAI,SAAS,IAAI;KACrC,MAAM,IAAI,IAAI,KAAK,KAAK,IAAI,SAAS,IAAI;KACzC,MAAM,QAAQ,OAAO,GAAG,EAAE;KAC1B,MAAM,IAAI,KAAK;KACf,MAAM,IAAI,IAAI,KAAK,QAAQ,OAAO,KAAM,EAAG;KAC3C,MAAM,IAAI,IAAI,QAAQ,OAAO,IAAI,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU;KAC7E,KAAK,IAAI;MAAC,EAAE;MAAG,EAAE;MAAG,EAAE;KAAC,GAAG,IAAI,CAAC;KAC/B,KAAK,IAAI,KAAK,OAAO,GAAG,KAAK,KAAK,CAAC;KACnC,KAAK,IAAI,IAAI,KAAK,OAAO,GAAG,EAAE,KAAK,KAAK,OAAO,IAAI,KAAM,KAAK;KAC9D,KAAK,IAAI,KAAK,OAAO,GAAG,KAAK,KAAK,CAAC;KACnC,KAAK,IAAI,IAAI,KAAK,OAAO,IAAI,EAAE;KAC/B,KAAK,IAAI,KAAK;KACd,KAAK,IAAI,IAAI,KAAK,OAAO,GAAG,QAAQ;KACpC,KAAK,KAAK,MAAM;KAChB,KAAK,KAAK,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM;IACnD;GACF;;GAGA,SAAS,KAAK,MAAc,IAAY;IACtC,KAAK,MAAM,CAAC,OAAO,SAAS;KAC1B,CAAC,UAAU,CAAC;KACZ,CAAC,OAAO,CAAC;KACT,CAAC,OAAO,CAAC;KACT,CAAC,MAAM,CAAC;KACR,CAAC,MAAM,CAAC;KACR,CAAC,MAAM,CAAC;KACR,CAAC,MAAM,CAAC;IAAC,GAET,MAAM,WAAW,KAAK,MAAM,OAAO,MAAM,OAAO,OAAO,IAAI;IAE7D,KAAK,MAAM,KAAK;IAChB,KAAK,MAAM,KAAK;GAClB;GAEA,MAAM,SAAS,IAAI,QAAQ;GAC3B,MAAM,WAAW,IAAI,WAAW;GAChC,MAAM,QAAQ,IAAI,QAAQ;GAC1B,MAAM,KAAK,IAAI,QAAQ;GACvB,MAAM,SAAS,IAAI,QAAQ;GAC3B,MAAM,QAAQ,IAAI,MAAM;GAExB,OAAO;IACL,SAAS,MAAM,YAAY;KACzB,OAAO,QAAQ,KAAK;KACpB,OAAO,MAAM,KAAK;KAClB,OAAO,uBAAuB;KAC9B,QAAQ,SAAS;IACnB;IACA,QAAQ,EAAE,YAAY;KAEpB,OAAO,QAAQ,UAAU,KAAK,SAAS,GAAG,OAAO,QAAQ,MAAM,CAAE;KACjE,MAAM,UAAU,KAAK,IAAI,OAAQ,KAAK;KACtC,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;MAC9B,KAAK,IAAI,MAAO;MAChB,MAAM,MAAM,KAAK,IAAI;MACrB,MAAM,WAAW,KAAK,IAAI,IAAI;MAC9B,IAAI,OAAO,YAAY,SAAS,IAAI,IAAI,KAAM,KAAK;OACjD,KAAK,EAAE,OAAO,GAAG;OACjB;MACF;MACA,MAAM,IAAI,MAAO;MACjB,MAAM,IAAI,IAAI,KACZ,MAAM,IAAI,IAAI,KAAM,UAAU,KAAK,SAAS,UAAU,KAAK,KAAM;MAEnE,KAAK,IAAI,MAAO,QAAQ;MACxB,SAAS,IAAI,OACV,MAAM,IAAI,KAAM,KAAK,IAAI,KAAK,IAAI,EAAG,IAAI,KAAK,IAAI,IAAI,MAAO;MAChE,SAAS,IAAI,IAAI,MAAO,MAAM,IAAI,IAAI,KAAM;MAC5C,KAAK,IAAI,MAAO,KAAK,IAAI,IAAI,KAAM;MAEnC,SAAS,iBACP,GAAG,IAAI,KAAK,IAAI,IAAK,KAAK,IAAI,IAAI,IAAK,KAAK,IAAI,IAAI,EAAG,GACvD,KAAK,IAAI,EACX;MACA,MAAM,OAAO,KAAK,IAAI,IAAI,WAAW,OAAO,MAAM;MAClD,MAAM,IAAI,MAAM,IAAI,KAAM,MAAM,MAAM,IAAI,IAAI,KAAM,MAAM,CAAC;MAC3D,OAAO,QACL,GAAG,IAAI,SAAS,IAAI,IAAK,SAAS,IAAI,IAAI,IAAK,CAAC,GAChD,UACA,KACF;MACA,KAAK,YAAY,GAAG,MAAM;MAE1B,MAAM,SAAS,KAAK,IAAI,OAAO,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,gBAAgB,QAAQ,CAAC,CAAC,CAAC;MACvE,KAAK,WACH,GACA,MAAM,KAAK,MAAM,KAAK,GAAK,CAAC,CAAC,eAAe,MAAO,MAAO,MAAM,CAClE;KACF;KACA,KAAK,QAAQ;KACb,KAAK,eAAe,cAAc;KAClC,IAAI,KAAK,eAAe,KAAK,cAAc,cAAc;KACzD,IAAI,UAAU,GAAG,OAAO;IAC1B;GACF;EACF;CAAC,CAAA,GAAA,IAAA;AAGT,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import { Vector3 } from 'three';
3
3
  import { type EffectProps } from '../core/EffectSurface';
4
4
  /** 地图上的一个点:纬度(北正南负)、经度(东正西负),单位度 */
@@ -5,7 +5,7 @@ import { createOrbit } from "../core/orbit.js";
5
5
  import { LAND_BITS } from "./land.js";
6
6
  import { createVNode } from "vue";
7
7
  import { _component, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
8
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
8
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
9
9
  import { BufferAttribute, BufferGeometry, Group, LineSegments, Mesh, PerspectiveCamera, PlaneGeometry, Points, ShaderMaterial, Vector3 } from "three";
10
10
  //#region src/three/globe/Globe.tsx
11
11
  /** 地图上的一个点:纬度(北正南负)、经度(东正西负),单位度 */
@@ -1 +1 @@
1
- {"version":3,"file":"Globe.js","names":["_vtp_readonlyProp","_vtp_restProps","_vtp_untrack","_createVNode","_mergeProps"],"sources":["../../../src/three/globe/Globe.tsx"],"sourcesContent":["/**\n * 点阵地球(div):陆地画成一层细密的点,可以标注地点(markers,向外扩散的光圈),两地之间画弧线(arcs,光点沿弧线流动);\n * 缓缓自转,可以拖动转动(松手后带惯性)。参考 GitHub 首页的地球、cobe。\n *\n * <Globe markers={[{ lat: 31.23, lng: 121.47 }]} arcs={[{ from: [31.23, 121.47], to: [37.77, -122.42] }]} />\n * <Globe center={{ lat: 30, lng: 110 }} rotationSpeed={0} sx={styles.globe} />\n *\n * 陆地来自 Natural Earth 1:110m 的世界地图(1° 的位图,见 land.ts);点的疏密按画质档位。颜色跟随主题:\n * 陆地用次要文字色,标注、弧线与大气光晕用品牌色(可以单独给 color)。默认是正方形,尺寸由使用方决定。\n * 减少动态效果时停在一帧,不自转、弧线不流动。画面是装饰;要让读屏知道内容时给 propsCanvas 写 aria-label。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(div,有内容时才有)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n BufferAttribute,\n BufferGeometry,\n Group,\n LineSegments,\n Mesh,\n PerspectiveCamera,\n Points,\n ShaderMaterial,\n PlaneGeometry,\n Vector3,\n type Color,\n} from 'three';\nimport { colors } from '../../config/theme/tokens';\nimport { clamp } from '../../utils/data/number';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport { createOrbit } from '../core/orbit';\nimport { LAND_BITS, LAND_HEIGHT, LAND_WIDTH } from './land';\n\n/** 地图上的一个点:纬度(北正南负)、经度(东正西负),单位度 */\nexport interface GeoPoint {\n /** 纬度:北纬为正,-90 到 90 */\n lat: number;\n /** 经度:东经为正,-180 到 180 */\n lng: number;\n}\n\n/** 标注的地点 */\nexport interface GlobeMarker extends GeoPoint {\n /** 大小的倍数,默认 1 */\n size?: number;\n /** 颜色(token 或 CSS 颜色);不写时用 markerColor */\n color?: string;\n}\n\n/** 两地之间的弧线:[纬度, 经度] */\nexport interface GlobeArc {\n /** 起点 [纬度, 经度] */\n from: readonly [number, number];\n /** 终点 [纬度, 经度] */\n to: readonly [number, number];\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface GlobeProps extends EffectProps {\n /** 标注的地点 */\n markers?: readonly GlobeMarker[];\n /** 弧线 */\n arcs?: readonly GlobeArc[];\n /**\n * 一开始正对着的地方\n * @default { lat: 20, lng: 100 }\n */\n center?: GeoPoint;\n /**\n * 自转速度(度 / 秒,向东为正);0 时不自转\n * @default 6\n */\n rotationSpeed?: number;\n /**\n * 可以拖动转动\n * @default true\n */\n draggable?: boolean;\n /**\n * 陆地的点有多密(1 约一万个点,按画质档位再缩放)\n * @default 1\n */\n density?: number;\n /** 陆地点的颜色,默认次要文字色 */\n landColor?: string;\n /** 标注与弧线的颜色,默认品牌色 */\n markerColor?: string;\n /**\n * 大气光晕\n * @default true\n */\n glow?: boolean;\n}\n\n/** Globe 的样式:root、draggable、dragging */\nexport const globeStyles = css.create({\n root: { aspectRatio: '1', width: '100%' },\n draggable: { cursor: 'grab', touchAction: 'pan-y' },\n dragging: { cursor: 'grabbing' },\n});\n\nconst DEG = Math.PI / 180;\n/** 地球的轮廓占画面短边的比例:外面留给大气光晕 */\nconst FIT = 0.8;\nconst FOV = 40;\n\n/** 经纬度 → 球面上的点(半径 radius):经度 0 朝向 +z(正对相机),北极朝 +y */\nexport function latLngToVector(lat: number, lng: number, radius = 1, target = new Vector3()) {\n const phi = lat * DEG;\n const theta = lng * DEG;\n return target.set(\n radius * Math.cos(phi) * Math.sin(theta),\n radius * Math.sin(phi),\n radius * Math.cos(phi) * Math.cos(theta),\n );\n}\n\n/** 陆地位图:某个经纬度是不是陆地 */\nconst landBits = (() => {\n let bytes: Uint8Array | undefined;\n return (lat: number, lng: number) => {\n bytes ??= Uint8Array.from(atob(LAND_BITS), (char) => char.charCodeAt(0));\n const row = clamp(Math.floor(90 - lat), 0, LAND_HEIGHT - 1);\n const column = (((Math.floor(lng + 180) % LAND_WIDTH) + LAND_WIDTH) % LAND_WIDTH) | 0;\n const index = row * LAND_WIDTH + column;\n return (bytes[index >> 3]! & (1 << (index & 7))) !== 0;\n };\n})();\n\n// 点:正面清楚、转到背面淡出;大小随透视缩放\nconst dotVertex = /* glsl */ `\nuniform float uPixelRatio;\nuniform float uScale;\nattribute float aSize;\nattribute float aPhase;\nvarying float vFacing;\nvarying float vPhase;\nvoid main() {\n vec4 world = modelMatrix * vec4(position, 1.0);\n vFacing = dot(normalize(world.xyz), normalize(cameraPosition - world.xyz));\n vPhase = aPhase;\n vec4 view = viewMatrix * world;\n gl_PointSize = aSize * uScale * uPixelRatio / -view.z;\n gl_Position = projectionMatrix * view;\n}\n`;\n\nconst landFragment = /* glsl */ `\nuniform vec3 uColor;\nvarying float vFacing;\nvoid main() {\n float d = length(gl_PointCoord - 0.5);\n float alpha = smoothstep(0.5, 0.3, d) * smoothstep(-0.05, 0.35, vFacing) * 0.85;\n gl_FragColor = vec4(uColor, alpha);\n #include <colorspace_fragment>\n #include <premultiplied_alpha_fragment>\n}\n`;\n\n// 标注:实心的点加一圈向外扩散、渐淡的光圈\nconst markerFragment = /* glsl */ `\nuniform vec3 uColor;\nuniform float uTime;\nvarying float vFacing;\nvarying float vPhase;\nvoid main() {\n float d = length(gl_PointCoord - 0.5) * 2.0;\n float core = smoothstep(0.3, 0.2, d);\n float wave = fract(uTime * 0.6 + vPhase);\n float ring = smoothstep(0.08, 0.0, abs(d - wave)) * (1.0 - wave);\n float alpha = max(core, ring * 0.9) * smoothstep(-0.1, 0.25, vFacing);\n gl_FragColor = vec4(uColor, alpha);\n #include <colorspace_fragment>\n #include <premultiplied_alpha_fragment>\n}\n`;\n\n// 弧线:整条淡淡的底色,加一段从起点流向终点的亮光\nconst arcVertex = /* glsl */ `\nattribute float aT;\nattribute float aPhase;\nvarying float vT;\nvarying float vPhase;\nvarying float vFacing;\nvoid main() {\n vec4 world = modelMatrix * vec4(position, 1.0);\n vFacing = dot(normalize(world.xyz), normalize(cameraPosition - world.xyz));\n vT = aT;\n vPhase = aPhase;\n gl_Position = projectionMatrix * viewMatrix * world;\n}\n`;\n\nconst arcFragment = /* glsl */ `\nuniform vec3 uColor;\nuniform float uTime;\nvarying float vT;\nvarying float vPhase;\nvarying float vFacing;\nvoid main() {\n float head = fract(uTime * 0.35 + vPhase) * 1.4 - 0.2;\n float glow = exp(-pow((vT - head) * 7.0, 2.0));\n float alpha = (0.18 + 0.82 * glow) * smoothstep(-0.25, 0.2, vFacing);\n gl_FragColor = vec4(uColor, alpha);\n #include <colorspace_fragment>\n #include <premultiplied_alpha_fragment>\n}\n`;\n\n// 大气:正对相机的一块方形,按到球心的距离画径向的光(单位是地球半径,uEdge 是轮廓所在的半径):\n// 球面里只有一层淡淡的雾,轮廓外一圈亮边向外淡出\nconst glowVertex = /* glsl */ `\nvarying vec2 vPosition;\nvoid main() {\n vPosition = position.xy;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n`;\n\nconst glowFragment = /* glsl */ `\nuniform vec3 uColor;\nuniform float uEdge;\nuniform float uLimit;\nvarying vec2 vPosition;\nvoid main() {\n float r = length(vPosition) / uEdge;\n float inner = smoothstep(0.55, 1.0, r) * 0.22;\n // 到画布边缘(短边方向在 uLimit 处)之前淡完,不留方形的边\n float outer = exp(-(r - 1.0) * 9.0) * smoothstep(uLimit, uLimit - 0.12, r);\n float intensity = r < 1.0 ? inner : outer * 0.75;\n // 先转色彩空间再乘强度(预乘):反过来的话,sRGB 会把很淡的颜色提亮,方形的边缘就露出来了\n gl_FragColor = vec4(uColor, 1.0);\n #include <colorspace_fragment>\n gl_FragColor = vec4(gl_FragColor.rgb, 1.0) * intensity;\n}\n`;\n\n/** 透明叠加的着色器材质 */\nconst overlay = (params: ConstructorParameters<typeof ShaderMaterial>[0]) =>\n new ShaderMaterial({\n ...params,\n transparent: true,\n premultipliedAlpha: true,\n depthWrite: false,\n });\n\n/** 两地之间的大圆弧,抬离地面(越远抬得越高),采样成 segments 段 */\nfunction arcPoints({ from, to }: GlobeArc, segments: number): Vector3[] {\n const a = latLngToVector(from[0], from[1]);\n const b = latLngToVector(to[0], to[1]);\n const angle = a.angleTo(b);\n const lift = 0.06 + angle * 0.22;\n const points: Vector3[] = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n // 球面线性插值(slerp),再按 sin 抬高\n const point =\n angle < 1e-6\n ? a.clone()\n : a\n .clone()\n .multiplyScalar(Math.sin((1 - t) * angle) / Math.sin(angle))\n .add(b.clone().multiplyScalar(Math.sin(t * angle) / Math.sin(angle)));\n points.push(point.normalize().multiplyScalar(1 + lift * Math.sin(Math.PI * t)));\n }\n return points;\n}\n\n/** 点阵地球 */\nexport const Globe = _component(\n ({\n markers = [],\n arcs = [],\n center = { lat: 20, lng: 100 },\n rotationSpeed = 6,\n draggable = true,\n density = 1,\n landColor = colors.textMuted,\n markerColor = colors.accent,\n glow = true,\n ...rest\n }: GlobeProps) => {\n // 朝向:一开始正对 center;拖动左右改 yaw、上下改 pitch,松手后带惯性回到自转\n const start = _untrack(center);\n const orbit = createOrbit({ yaw: -start.lng * DEG, pitch: start.lat * DEG });\n\n return () => (\n <EffectSurface\n {...rest}\n sx={[\n globeStyles.root,\n draggable && globeStyles.draggable,\n orbit.dragging && globeStyles.dragging,\n rest.sx,\n ]}\n {...(draggable ? orbit.handlers : {})}\n // 颜色也在键里:改了 landColor、markerColor 要重建场景(颜色在 setup 里读一次)\n sceneKey={`${density}|${glow}|${landColor}|${markerColor}|${JSON.stringify(markers)}|${JSON.stringify(arcs)}`}\n setup={({ scene, quality, still, themeColors }) => {\n const camera = new PerspectiveCamera(FOV, 1, 0.1, 100);\n const palette = themeColors({ land: landColor, marker: markerColor }) as {\n land: Color;\n marker: Color;\n };\n // 标注按颜色分组:同色的一次画完\n const byColor = new Map<string, GlobeMarker[]>();\n for (const marker of markers) {\n const color = marker.color ?? markerColor;\n byColor.set(color, [...(byColor.get(color) ?? []), marker]);\n }\n const markerTints = themeColors(\n Object.fromEntries([...byColor.keys()].map((color, index) => [index, color])),\n ) as Record<string, Color>;\n\n const globe = new Group();\n scene.add(globe);\n const uniforms = {\n uPixelRatio: { value: 1 },\n uScale: { value: 1 },\n uTime: { value: 0 },\n };\n\n // 陆地:斐波那契球面上均匀撒点,落在陆地上的留下\n const candidates = Math.round(24_000 * density * Math.min(1, quality.density));\n const land: number[] = [];\n const golden = Math.PI * (3 - Math.sqrt(5));\n const at = new Vector3();\n for (let i = 0; i < candidates; i++) {\n const y = 1 - (2 * (i + 0.5)) / candidates;\n const lat = Math.asin(y) / DEG;\n const lng = (((((i * golden) / DEG) % 360) + 360) % 360) - 180;\n if (!landBits(lat, lng)) continue;\n latLngToVector(lat, lng, 1, at);\n land.push(at.x, at.y, at.z);\n }\n const landGeometry = new BufferGeometry();\n landGeometry.setAttribute('position', new BufferAttribute(new Float32Array(land), 3));\n const landCount = land.length / 3;\n landGeometry.setAttribute(\n 'aSize',\n new BufferAttribute(new Float32Array(landCount).fill(2.2), 1),\n );\n landGeometry.setAttribute('aPhase', new BufferAttribute(new Float32Array(landCount), 1));\n globe.add(\n new Points(\n landGeometry,\n overlay({\n vertexShader: dotVertex,\n fragmentShader: landFragment,\n uniforms: { ...uniforms, uColor: { value: palette.land } },\n }),\n ),\n );\n\n // 标注:实心点加扩散的光圈\n [...byColor.values()].forEach((list, group) => {\n const positions = new Float32Array(list.length * 3);\n list.forEach((marker, i) => {\n latLngToVector(marker.lat, marker.lng, 1.005, at).toArray(positions, i * 3);\n });\n const geometry = new BufferGeometry();\n geometry.setAttribute('position', new BufferAttribute(positions, 3));\n geometry.setAttribute(\n 'aSize',\n new BufferAttribute(\n Float32Array.from(list, (marker) => 22 * (marker.size ?? 1)),\n 1,\n ),\n );\n geometry.setAttribute(\n 'aPhase',\n new BufferAttribute(\n Float32Array.from(list, (_, i) => (i * 0.37) % 1),\n 1,\n ),\n );\n globe.add(\n new Points(\n geometry,\n overlay({\n vertexShader: dotVertex,\n fragmentShader: markerFragment,\n uniforms: { ...uniforms, uColor: { value: markerTints[group] } },\n }),\n ),\n );\n });\n\n // 弧线:所有弧线放在同一组线段里,一次画完\n if (arcs.length) {\n const SEGMENTS = 64;\n const positions: number[] = [];\n const ts: number[] = [];\n const phases: number[] = [];\n arcs.forEach((arc, index) => {\n const points = arcPoints(arc, SEGMENTS);\n const phase = (index * 0.29) % 1;\n for (let i = 0; i < SEGMENTS; i++) {\n positions.push(...points[i]!.toArray(), ...points[i + 1]!.toArray());\n ts.push(i / SEGMENTS, (i + 1) / SEGMENTS);\n phases.push(phase, phase);\n }\n });\n const geometry = new BufferGeometry();\n geometry.setAttribute('position', new BufferAttribute(new Float32Array(positions), 3));\n geometry.setAttribute('aT', new BufferAttribute(new Float32Array(ts), 1));\n geometry.setAttribute('aPhase', new BufferAttribute(new Float32Array(phases), 1));\n globe.add(\n new LineSegments(\n geometry,\n overlay({\n vertexShader: arcVertex,\n fragmentShader: arcFragment,\n uniforms: { uColor: { value: palette.marker }, uTime: uniforms.uTime },\n }),\n ),\n );\n }\n\n // 透视下球的轮廓比半径大一点:相机距离 d 时在 z = 0 平面上是 d / √(d² − 1)\n const edge = { value: 1 };\n if (glow) {\n // 不随地球转:相机在 z 轴上,xy 平面上的方形总是正对相机\n const atmosphere = new Mesh(\n new PlaneGeometry(3, 3),\n overlay({\n vertexShader: glowVertex,\n fragmentShader: glowFragment,\n uniforms: {\n uColor: { value: palette.marker },\n uEdge: edge,\n uLimit: { value: 1 / FIT },\n },\n }),\n );\n atmosphere.renderOrder = -1;\n scene.add(atmosphere);\n }\n\n const apply = () => globe.rotation.set(orbit.pitch, orbit.yaw, 0, 'XYZ');\n apply();\n\n return {\n resize: (size, context) => {\n camera.aspect = size.width / Math.max(size.height, 1);\n // 轮廓的直径占短边的 FIT:相机距离 d 处的轮廓半径是 d / √(d² − 1),\n // 要它等于 FIT · d · tan(fov / 2),解出 d(宽比高窄时再拉远)\n const t = FIT * Math.tan((FOV * DEG) / 2);\n const fitHeight = Math.sqrt(1 + 1 / (t * t));\n camera.position.z = fitHeight * Math.max(1, 1 / camera.aspect);\n camera.updateProjectionMatrix();\n context.camera = camera;\n const d = camera.position.z;\n edge.value = d / Math.sqrt(d * d - 1);\n uniforms.uPixelRatio.value = size.pixelRatio;\n // 点的大小(CSS 像素)在 z = 相机距离处不变:/ -view.z 的透视缩放乘回来,再按画布大小缩放\n uniforms.uScale.value = (camera.position.z * Math.min(size.width, size.height)) / 360;\n },\n frame: ({ time, delta }) => {\n uniforms.uTime.value = time;\n if (still) return;\n orbit.step(delta, rotationSpeed * DEG);\n apply();\n },\n };\n }}\n />\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"Globe.js","names":["_vtp_readonlyProp","_vtp_restProps","_vtp_untrack","_createVNode","_mergeProps"],"sources":["../../../src/three/globe/Globe.tsx"],"sourcesContent":["/**\n * 点阵地球(div):陆地画成一层细密的点,可以标注地点(markers,向外扩散的光圈),两地之间画弧线(arcs,光点沿弧线流动);\n * 缓缓自转,可以拖动转动(松手后带惯性)。参考 GitHub 首页的地球、cobe。\n *\n * <Globe markers={[{ lat: 31.23, lng: 121.47 }]} arcs={[{ from: [31.23, 121.47], to: [37.77, -122.42] }]} />\n * <Globe center={{ lat: 30, lng: 110 }} rotationSpeed={0} sx={styles.globe} />\n *\n * 陆地来自 Natural Earth 1:110m 的世界地图(1° 的位图,见 land.ts);点的疏密按画质档位。颜色跟随主题:\n * 陆地用次要文字色,标注、弧线与大气光晕用品牌色(可以单独给 color)。默认是正方形,尺寸由使用方决定。\n * 减少动态效果时停在一帧,不自转、弧线不流动。画面是装饰;要让读屏知道内容时给 propsCanvas 写 aria-label。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(div,有内容时才有)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n BufferAttribute,\n BufferGeometry,\n Group,\n LineSegments,\n Mesh,\n PerspectiveCamera,\n Points,\n ShaderMaterial,\n PlaneGeometry,\n Vector3,\n type Color,\n} from 'three';\nimport { colors } from '../../config/theme/tokens';\nimport { clamp } from '../../utils/data/number';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport { createOrbit } from '../core/orbit';\nimport { LAND_BITS, LAND_HEIGHT, LAND_WIDTH } from './land';\n\n/** 地图上的一个点:纬度(北正南负)、经度(东正西负),单位度 */\nexport interface GeoPoint {\n /** 纬度:北纬为正,-90 到 90 */\n lat: number;\n /** 经度:东经为正,-180 到 180 */\n lng: number;\n}\n\n/** 标注的地点 */\nexport interface GlobeMarker extends GeoPoint {\n /** 大小的倍数,默认 1 */\n size?: number;\n /** 颜色(token 或 CSS 颜色);不写时用 markerColor */\n color?: string;\n}\n\n/** 两地之间的弧线:[纬度, 经度] */\nexport interface GlobeArc {\n /** 起点 [纬度, 经度] */\n from: readonly [number, number];\n /** 终点 [纬度, 经度] */\n to: readonly [number, number];\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface GlobeProps extends EffectProps {\n /** 标注的地点 */\n markers?: readonly GlobeMarker[];\n /** 弧线 */\n arcs?: readonly GlobeArc[];\n /**\n * 一开始正对着的地方\n * @default { lat: 20, lng: 100 }\n */\n center?: GeoPoint;\n /**\n * 自转速度(度 / 秒,向东为正);0 时不自转\n * @default 6\n */\n rotationSpeed?: number;\n /**\n * 可以拖动转动\n * @default true\n */\n draggable?: boolean;\n /**\n * 陆地的点有多密(1 约一万个点,按画质档位再缩放)\n * @default 1\n */\n density?: number;\n /** 陆地点的颜色,默认次要文字色 */\n landColor?: string;\n /** 标注与弧线的颜色,默认品牌色 */\n markerColor?: string;\n /**\n * 大气光晕\n * @default true\n */\n glow?: boolean;\n}\n\n/** Globe 的样式:root、draggable、dragging */\nexport const globeStyles = css.create({\n root: { aspectRatio: '1', width: '100%' },\n draggable: { cursor: 'grab', touchAction: 'pan-y' },\n dragging: { cursor: 'grabbing' },\n});\n\nconst DEG = Math.PI / 180;\n/** 地球的轮廓占画面短边的比例:外面留给大气光晕 */\nconst FIT = 0.8;\nconst FOV = 40;\n\n/** 经纬度 → 球面上的点(半径 radius):经度 0 朝向 +z(正对相机),北极朝 +y */\nexport function latLngToVector(lat: number, lng: number, radius = 1, target = new Vector3()) {\n const phi = lat * DEG;\n const theta = lng * DEG;\n return target.set(\n radius * Math.cos(phi) * Math.sin(theta),\n radius * Math.sin(phi),\n radius * Math.cos(phi) * Math.cos(theta),\n );\n}\n\n/** 陆地位图:某个经纬度是不是陆地 */\nconst landBits = (() => {\n let bytes: Uint8Array | undefined;\n return (lat: number, lng: number) => {\n bytes ??= Uint8Array.from(atob(LAND_BITS), (char) => char.charCodeAt(0));\n const row = clamp(Math.floor(90 - lat), 0, LAND_HEIGHT - 1);\n const column = (((Math.floor(lng + 180) % LAND_WIDTH) + LAND_WIDTH) % LAND_WIDTH) | 0;\n const index = row * LAND_WIDTH + column;\n return (bytes[index >> 3]! & (1 << (index & 7))) !== 0;\n };\n})();\n\n// 点:正面清楚、转到背面淡出;大小随透视缩放\nconst dotVertex = /* glsl */ `\nuniform float uPixelRatio;\nuniform float uScale;\nattribute float aSize;\nattribute float aPhase;\nvarying float vFacing;\nvarying float vPhase;\nvoid main() {\n vec4 world = modelMatrix * vec4(position, 1.0);\n vFacing = dot(normalize(world.xyz), normalize(cameraPosition - world.xyz));\n vPhase = aPhase;\n vec4 view = viewMatrix * world;\n gl_PointSize = aSize * uScale * uPixelRatio / -view.z;\n gl_Position = projectionMatrix * view;\n}\n`;\n\nconst landFragment = /* glsl */ `\nuniform vec3 uColor;\nvarying float vFacing;\nvoid main() {\n float d = length(gl_PointCoord - 0.5);\n float alpha = smoothstep(0.5, 0.3, d) * smoothstep(-0.05, 0.35, vFacing) * 0.85;\n gl_FragColor = vec4(uColor, alpha);\n #include <colorspace_fragment>\n #include <premultiplied_alpha_fragment>\n}\n`;\n\n// 标注:实心的点加一圈向外扩散、渐淡的光圈\nconst markerFragment = /* glsl */ `\nuniform vec3 uColor;\nuniform float uTime;\nvarying float vFacing;\nvarying float vPhase;\nvoid main() {\n float d = length(gl_PointCoord - 0.5) * 2.0;\n float core = smoothstep(0.3, 0.2, d);\n float wave = fract(uTime * 0.6 + vPhase);\n float ring = smoothstep(0.08, 0.0, abs(d - wave)) * (1.0 - wave);\n float alpha = max(core, ring * 0.9) * smoothstep(-0.1, 0.25, vFacing);\n gl_FragColor = vec4(uColor, alpha);\n #include <colorspace_fragment>\n #include <premultiplied_alpha_fragment>\n}\n`;\n\n// 弧线:整条淡淡的底色,加一段从起点流向终点的亮光\nconst arcVertex = /* glsl */ `\nattribute float aT;\nattribute float aPhase;\nvarying float vT;\nvarying float vPhase;\nvarying float vFacing;\nvoid main() {\n vec4 world = modelMatrix * vec4(position, 1.0);\n vFacing = dot(normalize(world.xyz), normalize(cameraPosition - world.xyz));\n vT = aT;\n vPhase = aPhase;\n gl_Position = projectionMatrix * viewMatrix * world;\n}\n`;\n\nconst arcFragment = /* glsl */ `\nuniform vec3 uColor;\nuniform float uTime;\nvarying float vT;\nvarying float vPhase;\nvarying float vFacing;\nvoid main() {\n float head = fract(uTime * 0.35 + vPhase) * 1.4 - 0.2;\n float glow = exp(-pow((vT - head) * 7.0, 2.0));\n float alpha = (0.18 + 0.82 * glow) * smoothstep(-0.25, 0.2, vFacing);\n gl_FragColor = vec4(uColor, alpha);\n #include <colorspace_fragment>\n #include <premultiplied_alpha_fragment>\n}\n`;\n\n// 大气:正对相机的一块方形,按到球心的距离画径向的光(单位是地球半径,uEdge 是轮廓所在的半径):\n// 球面里只有一层淡淡的雾,轮廓外一圈亮边向外淡出\nconst glowVertex = /* glsl */ `\nvarying vec2 vPosition;\nvoid main() {\n vPosition = position.xy;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n`;\n\nconst glowFragment = /* glsl */ `\nuniform vec3 uColor;\nuniform float uEdge;\nuniform float uLimit;\nvarying vec2 vPosition;\nvoid main() {\n float r = length(vPosition) / uEdge;\n float inner = smoothstep(0.55, 1.0, r) * 0.22;\n // 到画布边缘(短边方向在 uLimit 处)之前淡完,不留方形的边\n float outer = exp(-(r - 1.0) * 9.0) * smoothstep(uLimit, uLimit - 0.12, r);\n float intensity = r < 1.0 ? inner : outer * 0.75;\n // 先转色彩空间再乘强度(预乘):反过来的话,sRGB 会把很淡的颜色提亮,方形的边缘就露出来了\n gl_FragColor = vec4(uColor, 1.0);\n #include <colorspace_fragment>\n gl_FragColor = vec4(gl_FragColor.rgb, 1.0) * intensity;\n}\n`;\n\n/** 透明叠加的着色器材质 */\nconst overlay = (params: ConstructorParameters<typeof ShaderMaterial>[0]) =>\n new ShaderMaterial({\n ...params,\n transparent: true,\n premultipliedAlpha: true,\n depthWrite: false,\n });\n\n/** 两地之间的大圆弧,抬离地面(越远抬得越高),采样成 segments 段 */\nfunction arcPoints({ from, to }: GlobeArc, segments: number): Vector3[] {\n const a = latLngToVector(from[0], from[1]);\n const b = latLngToVector(to[0], to[1]);\n const angle = a.angleTo(b);\n const lift = 0.06 + angle * 0.22;\n const points: Vector3[] = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n // 球面线性插值(slerp),再按 sin 抬高\n const point =\n angle < 1e-6\n ? a.clone()\n : a\n .clone()\n .multiplyScalar(Math.sin((1 - t) * angle) / Math.sin(angle))\n .add(b.clone().multiplyScalar(Math.sin(t * angle) / Math.sin(angle)));\n points.push(point.normalize().multiplyScalar(1 + lift * Math.sin(Math.PI * t)));\n }\n return points;\n}\n\n/** 点阵地球 */\nexport const Globe = _component(\n ({\n markers = [],\n arcs = [],\n center = { lat: 20, lng: 100 },\n rotationSpeed = 6,\n draggable = true,\n density = 1,\n landColor = colors.textMuted,\n markerColor = colors.accent,\n glow = true,\n ...rest\n }: GlobeProps) => {\n // 朝向:一开始正对 center;拖动左右改 yaw、上下改 pitch,松手后带惯性回到自转\n const start = _untrack(center);\n const orbit = createOrbit({ yaw: -start.lng * DEG, pitch: start.lat * DEG });\n\n return () => (\n <EffectSurface\n {...rest}\n sx={[\n globeStyles.root,\n draggable && globeStyles.draggable,\n orbit.dragging && globeStyles.dragging,\n rest.sx,\n ]}\n {...(draggable ? orbit.handlers : {})}\n // 颜色也在键里:改了 landColor、markerColor 要重建场景(颜色在 setup 里读一次)\n sceneKey={`${density}|${glow}|${landColor}|${markerColor}|${JSON.stringify(markers)}|${JSON.stringify(arcs)}`}\n setup={({ scene, quality, still, themeColors }) => {\n const camera = new PerspectiveCamera(FOV, 1, 0.1, 100);\n const palette = themeColors({ land: landColor, marker: markerColor }) as {\n land: Color;\n marker: Color;\n };\n // 标注按颜色分组:同色的一次画完\n const byColor = new Map<string, GlobeMarker[]>();\n for (const marker of markers) {\n const color = marker.color ?? markerColor;\n byColor.set(color, [...(byColor.get(color) ?? []), marker]);\n }\n const markerTints = themeColors(\n Object.fromEntries([...byColor.keys()].map((color, index) => [index, color])),\n ) as Record<string, Color>;\n\n const globe = new Group();\n scene.add(globe);\n const uniforms = {\n uPixelRatio: { value: 1 },\n uScale: { value: 1 },\n uTime: { value: 0 },\n };\n\n // 陆地:斐波那契球面上均匀撒点,落在陆地上的留下\n const candidates = Math.round(24_000 * density * Math.min(1, quality.density));\n const land: number[] = [];\n const golden = Math.PI * (3 - Math.sqrt(5));\n const at = new Vector3();\n for (let i = 0; i < candidates; i++) {\n const y = 1 - (2 * (i + 0.5)) / candidates;\n const lat = Math.asin(y) / DEG;\n const lng = (((((i * golden) / DEG) % 360) + 360) % 360) - 180;\n if (!landBits(lat, lng)) continue;\n latLngToVector(lat, lng, 1, at);\n land.push(at.x, at.y, at.z);\n }\n const landGeometry = new BufferGeometry();\n landGeometry.setAttribute('position', new BufferAttribute(new Float32Array(land), 3));\n const landCount = land.length / 3;\n landGeometry.setAttribute(\n 'aSize',\n new BufferAttribute(new Float32Array(landCount).fill(2.2), 1),\n );\n landGeometry.setAttribute('aPhase', new BufferAttribute(new Float32Array(landCount), 1));\n globe.add(\n new Points(\n landGeometry,\n overlay({\n vertexShader: dotVertex,\n fragmentShader: landFragment,\n uniforms: { ...uniforms, uColor: { value: palette.land } },\n }),\n ),\n );\n\n // 标注:实心点加扩散的光圈\n [...byColor.values()].forEach((list, group) => {\n const positions = new Float32Array(list.length * 3);\n list.forEach((marker, i) => {\n latLngToVector(marker.lat, marker.lng, 1.005, at).toArray(positions, i * 3);\n });\n const geometry = new BufferGeometry();\n geometry.setAttribute('position', new BufferAttribute(positions, 3));\n geometry.setAttribute(\n 'aSize',\n new BufferAttribute(\n Float32Array.from(list, (marker) => 22 * (marker.size ?? 1)),\n 1,\n ),\n );\n geometry.setAttribute(\n 'aPhase',\n new BufferAttribute(\n Float32Array.from(list, (_, i) => (i * 0.37) % 1),\n 1,\n ),\n );\n globe.add(\n new Points(\n geometry,\n overlay({\n vertexShader: dotVertex,\n fragmentShader: markerFragment,\n uniforms: { ...uniforms, uColor: { value: markerTints[group] } },\n }),\n ),\n );\n });\n\n // 弧线:所有弧线放在同一组线段里,一次画完\n if (arcs.length) {\n const SEGMENTS = 64;\n const positions: number[] = [];\n const ts: number[] = [];\n const phases: number[] = [];\n arcs.forEach((arc, index) => {\n const points = arcPoints(arc, SEGMENTS);\n const phase = (index * 0.29) % 1;\n for (let i = 0; i < SEGMENTS; i++) {\n positions.push(...points[i]!.toArray(), ...points[i + 1]!.toArray());\n ts.push(i / SEGMENTS, (i + 1) / SEGMENTS);\n phases.push(phase, phase);\n }\n });\n const geometry = new BufferGeometry();\n geometry.setAttribute('position', new BufferAttribute(new Float32Array(positions), 3));\n geometry.setAttribute('aT', new BufferAttribute(new Float32Array(ts), 1));\n geometry.setAttribute('aPhase', new BufferAttribute(new Float32Array(phases), 1));\n globe.add(\n new LineSegments(\n geometry,\n overlay({\n vertexShader: arcVertex,\n fragmentShader: arcFragment,\n uniforms: { uColor: { value: palette.marker }, uTime: uniforms.uTime },\n }),\n ),\n );\n }\n\n // 透视下球的轮廓比半径大一点:相机距离 d 时在 z = 0 平面上是 d / √(d² − 1)\n const edge = { value: 1 };\n if (glow) {\n // 不随地球转:相机在 z 轴上,xy 平面上的方形总是正对相机\n const atmosphere = new Mesh(\n new PlaneGeometry(3, 3),\n overlay({\n vertexShader: glowVertex,\n fragmentShader: glowFragment,\n uniforms: {\n uColor: { value: palette.marker },\n uEdge: edge,\n uLimit: { value: 1 / FIT },\n },\n }),\n );\n atmosphere.renderOrder = -1;\n scene.add(atmosphere);\n }\n\n const apply = () => globe.rotation.set(orbit.pitch, orbit.yaw, 0, 'XYZ');\n apply();\n\n return {\n resize: (size, context) => {\n camera.aspect = size.width / Math.max(size.height, 1);\n // 轮廓的直径占短边的 FIT:相机距离 d 处的轮廓半径是 d / √(d² − 1),\n // 要它等于 FIT · d · tan(fov / 2),解出 d(宽比高窄时再拉远)\n const t = FIT * Math.tan((FOV * DEG) / 2);\n const fitHeight = Math.sqrt(1 + 1 / (t * t));\n camera.position.z = fitHeight * Math.max(1, 1 / camera.aspect);\n camera.updateProjectionMatrix();\n context.camera = camera;\n const d = camera.position.z;\n edge.value = d / Math.sqrt(d * d - 1);\n uniforms.uPixelRatio.value = size.pixelRatio;\n // 点的大小(CSS 像素)在 z = 相机距离处不变:/ -view.z 的透视缩放乘回来,再按画布大小缩放\n uniforms.uScale.value = (camera.position.z * Math.min(size.width, size.height)) / 360;\n },\n frame: ({ time, delta }) => {\n uniforms.uTime.value = time;\n if (still) return;\n orbit.step(delta, rotationSpeed * DEG);\n apply();\n },\n };\n }}\n />\n );\n },\n);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import { type Object3D } from 'three';
3
3
  import { type EffectProps } from '../core/EffectSurface';
4
4
  /** 加载状态 */
@@ -6,7 +6,7 @@ import { EffectSurface } from "../core/EffectSurface.js";
6
6
  import { createOrbit } from "../core/orbit.js";
7
7
  import { createVNode, ref } from "vue";
8
8
  import { _component, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
9
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
9
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
10
10
  import { ACESFilmicToneMapping, Box3, Group, PMREMGenerator, PerspectiveCamera, Sphere, Vector3 } from "three";
11
11
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
12
12
  import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";
@@ -1 +1 @@
1
- {"version":3,"file":"ModelViewer.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_ref","_vtp_untrack","_createVNode","_mergeProps"],"sources":["../../../src/three/model/ModelViewer.tsx"],"sourcesContent":["/**\n * 模型查看器(div):加载 glTF / GLB(或直接给一个 three 的对象),自动居中、缩放到合适的大小,\n * 拖动环绕查看(松手带惯性),方向键也能转;没在拖时缓缓自转。参考 Google 的 <model-viewer>。\n *\n * <ModelViewer src=\"/models/chair.glb\" alt=\"扶手椅,胡桃木与灰色布面\" />\n * <ModelViewer object={mesh} rotationSpeed={0} zoom sx={styles.viewer} />\n *\n * 光照是一间柔和的摄影棚(RoomEnvironment 的环境光),金属、粗糙度材质都能正确地反光;exposure 调整体亮度。\n * 加载时中间显示转圈,失败时显示语言包里的提示(onError 拿到原因)。写了 alt 时整块是带名称的图像(role=\"img\")。\n * 默认正方形,尺寸由使用方决定。减少动态效果时不自转,拖动仍可用。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(加载中与出错的提示)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n ACESFilmicToneMapping,\n Box3,\n Group,\n PerspectiveCamera,\n PMREMGenerator,\n Sphere,\n Vector3,\n type Object3D,\n} from 'three';\nimport { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';\nimport { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';\nimport { Small } from '../../base/Text';\nimport { Spinner } from '../../base/Spinner';\nimport { useLang } from '../../config/context';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport { createOrbit } from '../core/orbit';\nimport { mergePartProps, type PartProps } from '../../utils/props';\n\n/** 加载状态 */\nexport interface ModelViewerStatuses {\n /** 加载中 */\n loading: unknown;\n /** 已显示 */\n loaded: unknown;\n /** 加载失败 */\n error: unknown;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ModelViewerProps extends Omit<EffectProps, 'children' | 'onLoad' | 'onError'> {\n /** 模型的地址(glTF / GLB);和 object 二选一 */\n src?: string;\n /** 直接给一个 three 的对象(程序生成的模型);和 src 二选一 */\n object?: Object3D;\n /** 模型的文字描述:写了时整块是 role=\"img\"、以它为名称 */\n alt?: string;\n /**\n * 自转速度(度 / 秒);0 时不自转\n * @default 20\n */\n rotationSpeed?: number;\n /**\n * 可以拖动、用方向键环绕查看\n * @default true\n */\n controls?: boolean;\n /**\n * 滚轮、+ / - 键缩放\n * @default false\n */\n zoom?: boolean;\n /**\n * 一开始的角度(度):yaw 绕竖轴,pitch 从上往下看为正\n * @default { yaw: 30, pitch: 15 }\n */\n orbit?: { yaw: number; pitch: number };\n /**\n * 曝光:整体亮度\n * @default 1\n */\n exposure?: number;\n /** 加载完成 */\n onLoad?: (model: Object3D) => void;\n /** 加载失败 */\n onError?: (error: unknown) => void;\n}\n\n/** ModelViewer 的样式:root、interactive、dragging、content、overlay */\nexport const modelViewerStyles = css.create({\n root: { aspectRatio: '1', width: '100%', outlineStyle: 'none' },\n interactive: { cursor: 'grab', touchAction: 'pan-y' },\n dragging: { cursor: 'grabbing' },\n // 内容层不定位:提示按外层(整块)铺满、居中\n content: { position: 'static' },\n // 加载中、出错的提示:盖在画布中间\n overlay: {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n },\n});\n\nconst DEG = Math.PI / 180;\nconst FOV = 35;\n/** 模型(外接球)占画面短边的比例 */\nconst FIT = 0.85;\n/** 缩放的范围:相对合适距离的倍数 */\nconst ZOOM_RANGE = [0.5, 2.5] as const;\n\n/** 模型查看器 */\nexport const ModelViewer = _component(\n ({\n src,\n object,\n alt,\n rotationSpeed = 20,\n controls = true,\n zoom = false,\n orbit: initial = { yaw: 30, pitch: 15 },\n exposure = 1,\n onLoad,\n onError,\n ...rest\n }: ModelViewerProps) => {\n const lang = useLang();\n let status = _state<keyof ModelViewerStatuses>('loading');\n const start = _untrack(initial);\n const orbit = createOrbit({ yaw: start.yaw * DEG, pitch: start.pitch * DEG, pitchLimit: 1.4 });\n let distance = 1;\n // 场景建好后换成真正的 invalidate:静止模式下交互也要重画\n let redraw = () => {};\n\n function onKeydown(event: KeyboardEvent) {\n if (!controls) return;\n const step = 15 * DEG;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, -step],\n ArrowDown: [0, step],\n };\n const move = moves[event.key];\n if (move) orbit.nudge(...move);\n else if (zoom && (event.key === '+' || event.key === '='))\n distance = Math.max(ZOOM_RANGE[0], distance / 1.15);\n else if (zoom && event.key === '-') distance = Math.min(ZOOM_RANGE[1], distance * 1.15);\n else return;\n event.preventDefault();\n redraw();\n }\n\n function onWheel(event: WheelEvent) {\n if (!zoom) return;\n event.preventDefault();\n distance = Math.min(\n ZOOM_RANGE[1],\n Math.max(ZOOM_RANGE[0], distance * Math.exp(event.deltaY * 0.001)),\n );\n redraw();\n }\n\n return () => (\n <EffectSurface\n {...rest}\n sx={[\n modelViewerStyles.root,\n controls && modelViewerStyles.interactive,\n orbit.dragging && modelViewerStyles.dragging,\n rest.sx,\n ]}\n role={alt ? 'img' : undefined}\n aria-label={alt}\n aria-busy={status === 'loading' || undefined}\n tabindex={controls ? 0 : undefined}\n data-status={status}\n {...(controls ? orbit.handlers : {})}\n onKeydown={onKeydown}\n onWheel={onWheel}\n propsContent={mergePartProps<PartProps<'div'>>(\n { sx: modelViewerStyles.content },\n rest.propsContent,\n )}\n sceneKey={src ?? object?.uuid}\n setup={({ renderer, scene, still, invalidate }) => {\n redraw = invalidate;\n renderer.toneMapping = ACESFilmicToneMapping;\n renderer.toneMappingExposure = exposure;\n const environment = new PMREMGenerator(renderer);\n scene.environment = environment.fromScene(new RoomEnvironment(), 0.04).texture;\n\n const camera = new PerspectiveCamera(FOV, 1, 0.01, 100);\n // 合适的距离:外接球(半径 1)正好占短边的 FIT\n let fit = 1 / Math.sin((FOV * DEG) / 2) / FIT;\n const holder = new Group();\n scene.add(holder);\n let disposed = false;\n\n status = 'loading';\n const source = object\n ? Promise.resolve(object)\n : new GLTFLoader().loadAsync(src ?? '').then((gltf) => gltf.scene);\n source.then(\n (model) => {\n if (disposed) return;\n // 居中,缩放到外接球半径为 1\n const sphere = new Box3().setFromObject(model).getBoundingSphere(new Sphere());\n const scale = sphere.radius > 0 ? 1 / sphere.radius : 1;\n holder.scale.setScalar(scale);\n holder.position.copy(sphere.center).multiplyScalar(-scale);\n holder.add(model);\n status = 'loaded';\n onLoad?.(model);\n invalidate();\n },\n (error: unknown) => {\n if (disposed) return;\n status = 'error';\n onError?.(error);\n },\n );\n\n const eye = new Vector3();\n const place = () => {\n const d = fit * distance;\n eye.set(\n Math.sin(orbit.yaw) * Math.cos(orbit.pitch),\n Math.sin(orbit.pitch),\n Math.cos(orbit.yaw) * Math.cos(orbit.pitch),\n );\n camera.position.copy(eye.multiplyScalar(d));\n camera.lookAt(0, 0, 0);\n };\n\n return {\n resize: (size, context) => {\n camera.aspect = size.width / Math.max(size.height, 1);\n fit = 1 / Math.sin((FOV * DEG) / 2) / FIT / Math.min(1, camera.aspect);\n camera.updateProjectionMatrix();\n context.camera = camera;\n place();\n },\n frame: ({ delta }) => {\n // 自转是相机绕模型反向转:看起来模型朝 rotationSpeed 的方向转\n orbit.step(delta, still ? 0 : -rotationSpeed * DEG);\n place();\n },\n dispose: () => {\n disposed = true;\n scene.environment?.dispose();\n environment.dispose();\n redraw = () => {};\n },\n };\n }}\n >\n {status !== 'loaded' && (\n <div {...css.attrs(modelViewerStyles.overlay)}>\n {status === 'loading' ? (\n <Spinner label={lang.modelViewerLoading} />\n ) : (\n <Small tone=\"muted\">{lang.modelViewerError}</Small>\n )}\n </div>\n )}\n </EffectSurface>\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"ModelViewer.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_ref","_vtp_untrack","_createVNode","_mergeProps"],"sources":["../../../src/three/model/ModelViewer.tsx"],"sourcesContent":["/**\n * 模型查看器(div):加载 glTF / GLB(或直接给一个 three 的对象),自动居中、缩放到合适的大小,\n * 拖动环绕查看(松手带惯性),方向键也能转;没在拖时缓缓自转。参考 Google 的 <model-viewer>。\n *\n * <ModelViewer src=\"/models/chair.glb\" alt=\"扶手椅,胡桃木与灰色布面\" />\n * <ModelViewer object={mesh} rotationSpeed={0} zoom sx={styles.viewer} />\n *\n * 光照是一间柔和的摄影棚(RoomEnvironment 的环境光),金属、粗糙度材质都能正确地反光;exposure 调整体亮度。\n * 加载时中间显示转圈,失败时显示语言包里的提示(onError 拿到原因)。写了 alt 时整块是带名称的图像(role=\"img\")。\n * 默认正方形,尺寸由使用方决定。减少动态效果时不自转,拖动仍可用。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(加载中与出错的提示)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n ACESFilmicToneMapping,\n Box3,\n Group,\n PerspectiveCamera,\n PMREMGenerator,\n Sphere,\n Vector3,\n type Object3D,\n} from 'three';\nimport { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';\nimport { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';\nimport { Small } from '../../base/Text';\nimport { Spinner } from '../../base/Spinner';\nimport { useLang } from '../../config/context';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport { createOrbit } from '../core/orbit';\nimport { mergePartProps, type PartProps } from '../../utils/props';\n\n/** 加载状态 */\nexport interface ModelViewerStatuses {\n /** 加载中 */\n loading: unknown;\n /** 已显示 */\n loaded: unknown;\n /** 加载失败 */\n error: unknown;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ModelViewerProps extends Omit<EffectProps, 'children' | 'onLoad' | 'onError'> {\n /** 模型的地址(glTF / GLB);和 object 二选一 */\n src?: string;\n /** 直接给一个 three 的对象(程序生成的模型);和 src 二选一 */\n object?: Object3D;\n /** 模型的文字描述:写了时整块是 role=\"img\"、以它为名称 */\n alt?: string;\n /**\n * 自转速度(度 / 秒);0 时不自转\n * @default 20\n */\n rotationSpeed?: number;\n /**\n * 可以拖动、用方向键环绕查看\n * @default true\n */\n controls?: boolean;\n /**\n * 滚轮、+ / - 键缩放\n * @default false\n */\n zoom?: boolean;\n /**\n * 一开始的角度(度):yaw 绕竖轴,pitch 从上往下看为正\n * @default { yaw: 30, pitch: 15 }\n */\n orbit?: { yaw: number; pitch: number };\n /**\n * 曝光:整体亮度\n * @default 1\n */\n exposure?: number;\n /** 加载完成 */\n onLoad?: (model: Object3D) => void;\n /** 加载失败 */\n onError?: (error: unknown) => void;\n}\n\n/** ModelViewer 的样式:root、interactive、dragging、content、overlay */\nexport const modelViewerStyles = css.create({\n root: { aspectRatio: '1', width: '100%', outlineStyle: 'none' },\n interactive: { cursor: 'grab', touchAction: 'pan-y' },\n dragging: { cursor: 'grabbing' },\n // 内容层不定位:提示按外层(整块)铺满、居中\n content: { position: 'static' },\n // 加载中、出错的提示:盖在画布中间\n overlay: {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n },\n});\n\nconst DEG = Math.PI / 180;\nconst FOV = 35;\n/** 模型(外接球)占画面短边的比例 */\nconst FIT = 0.85;\n/** 缩放的范围:相对合适距离的倍数 */\nconst ZOOM_RANGE = [0.5, 2.5] as const;\n\n/** 模型查看器 */\nexport const ModelViewer = _component(\n ({\n src,\n object,\n alt,\n rotationSpeed = 20,\n controls = true,\n zoom = false,\n orbit: initial = { yaw: 30, pitch: 15 },\n exposure = 1,\n onLoad,\n onError,\n ...rest\n }: ModelViewerProps) => {\n const lang = useLang();\n let status = _state<keyof ModelViewerStatuses>('loading');\n const start = _untrack(initial);\n const orbit = createOrbit({ yaw: start.yaw * DEG, pitch: start.pitch * DEG, pitchLimit: 1.4 });\n let distance = 1;\n // 场景建好后换成真正的 invalidate:静止模式下交互也要重画\n let redraw = () => {};\n\n function onKeydown(event: KeyboardEvent) {\n if (!controls) return;\n const step = 15 * DEG;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, -step],\n ArrowDown: [0, step],\n };\n const move = moves[event.key];\n if (move) orbit.nudge(...move);\n else if (zoom && (event.key === '+' || event.key === '='))\n distance = Math.max(ZOOM_RANGE[0], distance / 1.15);\n else if (zoom && event.key === '-') distance = Math.min(ZOOM_RANGE[1], distance * 1.15);\n else return;\n event.preventDefault();\n redraw();\n }\n\n function onWheel(event: WheelEvent) {\n if (!zoom) return;\n event.preventDefault();\n distance = Math.min(\n ZOOM_RANGE[1],\n Math.max(ZOOM_RANGE[0], distance * Math.exp(event.deltaY * 0.001)),\n );\n redraw();\n }\n\n return () => (\n <EffectSurface\n {...rest}\n sx={[\n modelViewerStyles.root,\n controls && modelViewerStyles.interactive,\n orbit.dragging && modelViewerStyles.dragging,\n rest.sx,\n ]}\n role={alt ? 'img' : undefined}\n aria-label={alt}\n aria-busy={status === 'loading' || undefined}\n tabindex={controls ? 0 : undefined}\n data-status={status}\n {...(controls ? orbit.handlers : {})}\n onKeydown={onKeydown}\n onWheel={onWheel}\n propsContent={mergePartProps<PartProps<'div'>>(\n { sx: modelViewerStyles.content },\n rest.propsContent,\n )}\n sceneKey={src ?? object?.uuid}\n setup={({ renderer, scene, still, invalidate }) => {\n redraw = invalidate;\n renderer.toneMapping = ACESFilmicToneMapping;\n renderer.toneMappingExposure = exposure;\n const environment = new PMREMGenerator(renderer);\n scene.environment = environment.fromScene(new RoomEnvironment(), 0.04).texture;\n\n const camera = new PerspectiveCamera(FOV, 1, 0.01, 100);\n // 合适的距离:外接球(半径 1)正好占短边的 FIT\n let fit = 1 / Math.sin((FOV * DEG) / 2) / FIT;\n const holder = new Group();\n scene.add(holder);\n let disposed = false;\n\n status = 'loading';\n const source = object\n ? Promise.resolve(object)\n : new GLTFLoader().loadAsync(src ?? '').then((gltf) => gltf.scene);\n source.then(\n (model) => {\n if (disposed) return;\n // 居中,缩放到外接球半径为 1\n const sphere = new Box3().setFromObject(model).getBoundingSphere(new Sphere());\n const scale = sphere.radius > 0 ? 1 / sphere.radius : 1;\n holder.scale.setScalar(scale);\n holder.position.copy(sphere.center).multiplyScalar(-scale);\n holder.add(model);\n status = 'loaded';\n onLoad?.(model);\n invalidate();\n },\n (error: unknown) => {\n if (disposed) return;\n status = 'error';\n onError?.(error);\n },\n );\n\n const eye = new Vector3();\n const place = () => {\n const d = fit * distance;\n eye.set(\n Math.sin(orbit.yaw) * Math.cos(orbit.pitch),\n Math.sin(orbit.pitch),\n Math.cos(orbit.yaw) * Math.cos(orbit.pitch),\n );\n camera.position.copy(eye.multiplyScalar(d));\n camera.lookAt(0, 0, 0);\n };\n\n return {\n resize: (size, context) => {\n camera.aspect = size.width / Math.max(size.height, 1);\n fit = 1 / Math.sin((FOV * DEG) / 2) / FIT / Math.min(1, camera.aspect);\n camera.updateProjectionMatrix();\n context.camera = camera;\n place();\n },\n frame: ({ delta }) => {\n // 自转是相机绕模型反向转:看起来模型朝 rotationSpeed 的方向转\n orbit.step(delta, still ? 0 : -rotationSpeed * DEG);\n place();\n },\n dispose: () => {\n disposed = true;\n scene.environment?.dispose();\n environment.dispose();\n redraw = () => {};\n },\n };\n }}\n >\n {status !== 'loaded' && (\n <div {...css.attrs(modelViewerStyles.overlay)}>\n {status === 'loading' ? (\n <Spinner label={lang.modelViewerLoading} />\n ) : (\n <Small tone=\"muted\">{lang.modelViewerError}</Small>\n )}\n </div>\n )}\n </EffectSurface>\n );\n },\n);\n"],"mappings":"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"}
@@ -13,7 +13,7 @@
13
13
  * - 最终方向写到 data-side / data-align,缩放原点(transform-origin)朝向锚点,进出场的 scale 过渡从锚点那侧展开。
14
14
  */
15
15
  import { type Placement, type VirtualElement } from '@floating-ui/dom';
16
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
16
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
17
17
  import type { SxStyles } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
18
18
  import { type TextSize } from '../style/typography';
19
19
  /** 弹出位置:主方向 + 对齐方式(start 对齐锚点的起始边,end 对齐结束边);空间不够时自动翻转 */
@@ -2,7 +2,7 @@ import { fontSizeStyles } from "../style/typography.js";
2
2
  import { transitions } from "../style/transitions.js";
3
3
  import { returnFocus } from "./focus.js";
4
4
  import { onScopeDispose, watchPostEffect } from "vue";
5
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
5
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
6
6
  import { arrow, autoUpdate, computePosition, flip, offset, shift, size } from "@floating-ui/dom";
7
7
  //#region src/utils/dom/floating.ts
8
8
  /**