@qw-ui/core 0.3.0-next.4 → 0.3.0-next.42

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 (415) hide show
  1. package/README.md +21 -37
  2. package/dist/action-sheet/action-sheet.d.ts +110 -0
  3. package/dist/action-sheet/index.d.ts +2 -0
  4. package/dist/action-sheet/index.js +2 -0
  5. package/dist/action-sheet-Cvcr1S_m.js +183 -0
  6. package/dist/action-sheet-Cvcr1S_m.js.map +1 -0
  7. package/dist/area-picker/area-picker.d.ts +113 -0
  8. package/dist/area-picker/index.d.ts +1 -0
  9. package/dist/area-picker/index.js +348 -0
  10. package/dist/area-picker/index.js.map +1 -0
  11. package/dist/aria-description-CimD2M_C.js +13 -0
  12. package/dist/aria-description-CimD2M_C.js.map +1 -0
  13. package/dist/aria-description.d.ts +2 -0
  14. package/dist/avatar/avatar-load.d.ts +76 -0
  15. package/dist/avatar/avatar.d.ts +22 -5
  16. package/dist/avatar/index.d.ts +1 -0
  17. package/dist/avatar/index.js +57 -18
  18. package/dist/avatar/index.js.map +1 -1
  19. package/dist/avatar-load-w9dq05oV.js +139 -0
  20. package/dist/avatar-load-w9dq05oV.js.map +1 -0
  21. package/dist/back-top/back-top.d.ts +77 -0
  22. package/dist/back-top/index.d.ts +1 -0
  23. package/dist/back-top/index.js +189 -0
  24. package/dist/back-top/index.js.map +1 -0
  25. package/dist/badge/badge.d.ts +85 -0
  26. package/dist/badge/index.d.ts +1 -0
  27. package/dist/badge/index.js +88 -0
  28. package/dist/badge/index.js.map +1 -0
  29. package/dist/button/button.d.ts +13 -0
  30. package/dist/button/index.js +3 -5
  31. package/dist/button/index.js.map +1 -1
  32. package/dist/calendar/calendar.d.ts +100 -0
  33. package/dist/calendar/index.d.ts +1 -0
  34. package/dist/calendar/index.js +2 -0
  35. package/dist/calendar-CmpK3stz.js +363 -0
  36. package/dist/calendar-CmpK3stz.js.map +1 -0
  37. package/dist/card/card.d.ts +68 -0
  38. package/dist/card/index.d.ts +2 -0
  39. package/dist/card/index.js +2 -0
  40. package/dist/card-DRtWa6Cr.js +107 -0
  41. package/dist/card-DRtWa6Cr.js.map +1 -0
  42. package/dist/cascader/cascader.d.ts +115 -0
  43. package/dist/cascader/index.d.ts +1 -0
  44. package/dist/cascader/index.js +2 -0
  45. package/dist/cascader-D-xMjs7P.js +333 -0
  46. package/dist/cascader-D-xMjs7P.js.map +1 -0
  47. package/dist/cell/cell.d.ts +41 -0
  48. package/dist/cell/index.d.ts +1 -0
  49. package/dist/cell/index.js +43 -0
  50. package/dist/cell/index.js.map +1 -0
  51. package/dist/check-list/check-list.d.ts +78 -0
  52. package/dist/check-list/index.d.ts +2 -0
  53. package/dist/check-list/index.js +2 -0
  54. package/dist/check-list-BvZHQt5w.js +60 -0
  55. package/dist/check-list-BvZHQt5w.js.map +1 -0
  56. package/dist/checkbox/checkbox.d.ts +59 -0
  57. package/dist/checkbox/index.d.ts +2 -0
  58. package/dist/checkbox/index.js +2 -0
  59. package/dist/checkbox-BlndJrz5.js +127 -0
  60. package/dist/checkbox-BlndJrz5.js.map +1 -0
  61. package/dist/checkbox-group/checkbox-group.d.ts +86 -0
  62. package/dist/checkbox-group/index.d.ts +3 -0
  63. package/dist/checkbox-group/index.js +2 -0
  64. package/dist/checkbox-group-gGfsTv-e.js +223 -0
  65. package/dist/checkbox-group-gGfsTv-e.js.map +1 -0
  66. package/dist/choice-group-C4c9m0qe.js +373 -0
  67. package/dist/choice-group-C4c9m0qe.js.map +1 -0
  68. package/dist/circle/circle.d.ts +97 -0
  69. package/dist/circle/index.d.ts +1 -0
  70. package/dist/circle/index.js +119 -0
  71. package/dist/circle/index.js.map +1 -0
  72. package/dist/collapse/collapse.d.ts +98 -0
  73. package/dist/collapse/index.d.ts +2 -0
  74. package/dist/collapse/index.js +2 -0
  75. package/dist/collapse-B969h7-H.js +226 -0
  76. package/dist/collapse-B969h7-H.js.map +1 -0
  77. package/dist/countdown/countdown.d.ts +114 -0
  78. package/dist/countdown/index.d.ts +1 -0
  79. package/dist/countdown/index.js +309 -0
  80. package/dist/countdown/index.js.map +1 -0
  81. package/dist/date-picker/date-picker.d.ts +168 -0
  82. package/dist/date-picker/index.d.ts +1 -0
  83. package/dist/date-picker/index.js +401 -0
  84. package/dist/date-picker/index.js.map +1 -0
  85. package/dist/descriptions/descriptions.d.ts +69 -0
  86. package/dist/descriptions/index.d.ts +1 -0
  87. package/dist/descriptions/index.js +86 -0
  88. package/dist/descriptions/index.js.map +1 -0
  89. package/dist/dialog/dialog.d.ts +61 -43
  90. package/dist/dialog/index.js +73 -19
  91. package/dist/dialog/index.js.map +1 -1
  92. package/dist/divider/divider.d.ts +18 -2
  93. package/dist/divider/index.js +20 -2
  94. package/dist/divider/index.js.map +1 -1
  95. package/dist/dropdown/dropdown.d.ts +172 -0
  96. package/dist/dropdown/index.d.ts +2 -0
  97. package/dist/dropdown/index.js +467 -0
  98. package/dist/dropdown/index.js.map +1 -0
  99. package/dist/ellipsis/ellipsis-layout.d.ts +34 -0
  100. package/dist/ellipsis/ellipsis.d.ts +88 -0
  101. package/dist/ellipsis/index.d.ts +2 -0
  102. package/dist/ellipsis/index.js +320 -0
  103. package/dist/ellipsis/index.js.map +1 -0
  104. package/dist/empty/empty-illustration.d.ts +3 -0
  105. package/dist/empty/empty.d.ts +43 -1
  106. package/dist/empty/index.js +2 -21
  107. package/dist/empty-CAgyvhUI.js +166 -0
  108. package/dist/empty-CAgyvhUI.js.map +1 -0
  109. package/dist/field/field.d.ts +95 -0
  110. package/dist/field/index.d.ts +2 -0
  111. package/dist/field/index.js +2 -0
  112. package/dist/field-DMHGIMZF.js +241 -0
  113. package/dist/field-DMHGIMZF.js.map +1 -0
  114. package/dist/floating-bubble/floating-bubble.d.ts +116 -0
  115. package/dist/floating-bubble/index.d.ts +1 -0
  116. package/dist/floating-bubble/index.js +333 -0
  117. package/dist/floating-bubble/index.js.map +1 -0
  118. package/dist/floating-panel/floating-panel.d.ts +80 -0
  119. package/dist/floating-panel/index.d.ts +2 -0
  120. package/dist/floating-panel/index.js +2 -0
  121. package/dist/floating-panel-Cbm5njBJ.js +363 -0
  122. package/dist/floating-panel-Cbm5njBJ.js.map +1 -0
  123. package/dist/footer/footer.d.ts +94 -0
  124. package/dist/footer/index.d.ts +1 -0
  125. package/dist/footer/index.js +154 -0
  126. package/dist/footer/index.js.map +1 -0
  127. package/dist/form/connect.d.ts +6 -0
  128. package/dist/form/form.d.ts +100 -0
  129. package/dist/form/ids.d.ts +14 -0
  130. package/dist/form/index.d.ts +13 -0
  131. package/dist/form/index.js +3 -0
  132. package/dist/form/methods.d.ts +5 -0
  133. package/dist/form/model.d.ts +24 -0
  134. package/dist/form/native.d.ts +25 -0
  135. package/dist/form/rules.d.ts +40 -0
  136. package/dist/form/ssr.d.ts +7 -0
  137. package/dist/form/types.d.ts +150 -0
  138. package/dist/form-BAGkIEMY.js +1354 -0
  139. package/dist/form-BAGkIEMY.js.map +1 -0
  140. package/dist/format-BDUY0C_c.js +89 -0
  141. package/dist/format-BDUY0C_c.js.map +1 -0
  142. package/dist/gesture-_SRHIvBm.js +30 -0
  143. package/dist/gesture-_SRHIvBm.js.map +1 -0
  144. package/dist/grid/grid-item.d.ts +22 -0
  145. package/dist/grid/grid.d.ts +42 -0
  146. package/dist/grid/index.d.ts +2 -0
  147. package/dist/grid/index.js +73 -0
  148. package/dist/grid/index.js.map +1 -0
  149. package/dist/icon/icon.d.ts +37 -1
  150. package/dist/icon/identity.d.ts +3 -0
  151. package/dist/icon/index.js +2 -20
  152. package/dist/icon-Cgdbnk1u.js +77 -0
  153. package/dist/icon-Cgdbnk1u.js.map +1 -0
  154. package/dist/image/image-load.d.ts +24 -0
  155. package/dist/image/image.d.ts +45 -8
  156. package/dist/image/index.d.ts +1 -0
  157. package/dist/image/index.js +116 -14
  158. package/dist/image/index.js.map +1 -1
  159. package/dist/image-preview/image-preview.d.ts +124 -0
  160. package/dist/image-preview/index.d.ts +1 -0
  161. package/dist/image-preview/index.js +450 -0
  162. package/dist/image-preview/index.js.map +1 -0
  163. package/dist/index-bar/index-bar.d.ts +121 -0
  164. package/dist/index-bar/index.d.ts +1 -0
  165. package/dist/index-bar/index.js +386 -0
  166. package/dist/index-bar/index.js.map +1 -0
  167. package/dist/index.d.ts +115 -10
  168. package/dist/index.js +151 -11
  169. package/dist/index.js.map +1 -0
  170. package/dist/infinite-scroll/index.d.ts +1 -0
  171. package/dist/infinite-scroll/index.js +248 -0
  172. package/dist/infinite-scroll/index.js.map +1 -0
  173. package/dist/infinite-scroll/infinite-scroll.d.ts +95 -0
  174. package/dist/input/index.js +181 -22
  175. package/dist/input/index.js.map +1 -1
  176. package/dist/input/input.d.ts +44 -1
  177. package/dist/layer-IpFrl5--.js +414 -0
  178. package/dist/layer-IpFrl5--.js.map +1 -0
  179. package/dist/layout-BRSqi4AQ.js +43 -0
  180. package/dist/layout-BRSqi4AQ.js.map +1 -0
  181. package/dist/layout.d.ts +13 -0
  182. package/dist/list/index.d.ts +2 -0
  183. package/dist/list/index.js +2 -0
  184. package/dist/list/list.d.ts +30 -0
  185. package/dist/list-6-iz-Irh.js +28 -0
  186. package/dist/list-6-iz-Irh.js.map +1 -0
  187. package/dist/loading/index.js +45 -2
  188. package/dist/loading/index.js.map +1 -1
  189. package/dist/loading/loading.d.ts +45 -2
  190. package/dist/modal-dialog-machine-CF9_z3Dm.js +487 -0
  191. package/dist/modal-dialog-machine-CF9_z3Dm.js.map +1 -0
  192. package/dist/modal-dialog-machine.d.ts +21 -0
  193. package/dist/modal-dismissable-lifetime.d.ts +21 -0
  194. package/dist/modal-registry.d.ts +24 -0
  195. package/dist/modal-render-hydration.d.ts +35 -0
  196. package/dist/modal-render-runtime.d.ts +19 -0
  197. package/dist/modal-render-scope.d.ts +63 -0
  198. package/dist/nav-bar/index.d.ts +1 -0
  199. package/dist/nav-bar/index.js +115 -0
  200. package/dist/nav-bar/index.js.map +1 -0
  201. package/dist/nav-bar/nav-bar.d.ts +76 -0
  202. package/dist/notice-bar/index.d.ts +2 -0
  203. package/dist/notice-bar/index.js +2 -0
  204. package/dist/notice-bar/notice-bar.d.ts +103 -0
  205. package/dist/notice-bar-DMpwLvRb.js +231 -0
  206. package/dist/notice-bar-DMpwLvRb.js.map +1 -0
  207. package/dist/notify/index.d.ts +1 -0
  208. package/dist/notify/index.js +251 -0
  209. package/dist/notify/index.js.map +1 -0
  210. package/dist/notify/notify.d.ts +123 -0
  211. package/dist/number-keyboard/index.d.ts +1 -0
  212. package/dist/number-keyboard/index.js +333 -0
  213. package/dist/number-keyboard/index.js.map +1 -0
  214. package/dist/number-keyboard/number-keyboard.d.ts +141 -0
  215. package/dist/overlay-panel/index.d.ts +2 -0
  216. package/dist/overlay-panel/index.js +2 -0
  217. package/dist/overlay-panel/overlay-panel.d.ts +20 -0
  218. package/dist/overlay-panel-Z_qdKeBj.js +26 -0
  219. package/dist/overlay-panel-Z_qdKeBj.js.map +1 -0
  220. package/dist/page-indicator/index.d.ts +1 -0
  221. package/dist/page-indicator/index.js +138 -0
  222. package/dist/page-indicator/index.js.map +1 -0
  223. package/dist/page-indicator/page-indicator.d.ts +93 -0
  224. package/dist/pagination/index.d.ts +1 -0
  225. package/dist/pagination/index.js +198 -0
  226. package/dist/pagination/index.js.map +1 -0
  227. package/dist/pagination/pagination.d.ts +125 -0
  228. package/dist/password-input/index.d.ts +1 -0
  229. package/dist/password-input/index.js +317 -0
  230. package/dist/password-input/index.js.map +1 -0
  231. package/dist/password-input/password-input.d.ts +144 -0
  232. package/dist/picker/index.d.ts +8 -0
  233. package/dist/picker/index.js +2 -0
  234. package/dist/picker/picker-machine.d.ts +80 -0
  235. package/dist/picker/picker.d.ts +121 -0
  236. package/dist/picker/platform.d.ts +84 -0
  237. package/dist/picker/selection-connect.d.ts +90 -0
  238. package/dist/picker/selection-model.d.ts +211 -0
  239. package/dist/picker-BykFntQN.js +1675 -0
  240. package/dist/picker-BykFntQN.js.map +1 -0
  241. package/dist/popover/index.d.ts +3 -0
  242. package/dist/popover/index.js +253 -0
  243. package/dist/popover/index.js.map +1 -0
  244. package/dist/popover/layer.d.ts +44 -0
  245. package/dist/popover/popover.d.ts +104 -0
  246. package/dist/popover/positioning.d.ts +132 -0
  247. package/dist/popup/index.d.ts +2 -0
  248. package/dist/popup/index.js +2 -0
  249. package/dist/popup/popup.d.ts +60 -0
  250. package/dist/popup-z5d8IYCt.js +576 -0
  251. package/dist/popup-z5d8IYCt.js.map +1 -0
  252. package/dist/portal-BHCNTWhg.js +78 -0
  253. package/dist/portal-BHCNTWhg.js.map +1 -0
  254. package/dist/portal.d.ts +61 -0
  255. package/dist/price/format.d.ts +19 -0
  256. package/dist/price/index.d.ts +1 -0
  257. package/dist/price/index.js +154 -0
  258. package/dist/price/index.js.map +1 -0
  259. package/dist/price/price.d.ts +88 -0
  260. package/dist/progress/index.d.ts +1 -0
  261. package/dist/progress/index.js +2 -0
  262. package/dist/progress/progress.d.ts +32 -0
  263. package/dist/progress-f3iYEfdA.js +37 -0
  264. package/dist/progress-f3iYEfdA.js.map +1 -0
  265. package/dist/pull-refresh/index.d.ts +1 -0
  266. package/dist/pull-refresh/index.js +414 -0
  267. package/dist/pull-refresh/index.js.map +1 -0
  268. package/dist/pull-refresh/pull-refresh.d.ts +118 -0
  269. package/dist/radio-group/index.d.ts +3 -0
  270. package/dist/radio-group/index.js +2 -0
  271. package/dist/radio-group/radio-group.d.ts +78 -0
  272. package/dist/radio-group-BOIMuqnS.js +230 -0
  273. package/dist/radio-group-BOIMuqnS.js.map +1 -0
  274. package/dist/rate/index.d.ts +1 -0
  275. package/dist/rate/index.js +2 -0
  276. package/dist/rate/rate-form.d.ts +28 -0
  277. package/dist/rate/rate.d.ts +144 -0
  278. package/dist/rate-5XsU2QkY.js +631 -0
  279. package/dist/rate-5XsU2QkY.js.map +1 -0
  280. package/dist/reorder/index.d.ts +1 -0
  281. package/dist/reorder/index.js +720 -0
  282. package/dist/reorder/index.js.map +1 -0
  283. package/dist/reorder/reorder.d.ts +190 -0
  284. package/dist/result/index.d.ts +1 -0
  285. package/dist/result/index.js +123 -0
  286. package/dist/result/index.js.map +1 -0
  287. package/dist/result/result.d.ts +88 -0
  288. package/dist/safe-area/index.d.ts +1 -0
  289. package/dist/safe-area/index.js +42 -0
  290. package/dist/safe-area/index.js.map +1 -0
  291. package/dist/safe-area/safe-area.d.ts +28 -0
  292. package/dist/search-bar/index.js +4 -2
  293. package/dist/search-bar/index.js.map +1 -1
  294. package/dist/search-bar/search-bar.d.ts +6 -0
  295. package/dist/segmented/index.d.ts +2 -0
  296. package/dist/segmented/index.js +2 -0
  297. package/dist/segmented/segmented.d.ts +127 -0
  298. package/dist/segmented-BaU38_L4.js +367 -0
  299. package/dist/segmented-BaU38_L4.js.map +1 -0
  300. package/dist/selection-form-BOM_odUk.js +88 -0
  301. package/dist/selection-form-BOM_odUk.js.map +1 -0
  302. package/dist/selection-form.d.ts +27 -0
  303. package/dist/selection-ivXqO1eu.js +55 -0
  304. package/dist/selection-ivXqO1eu.js.map +1 -0
  305. package/dist/selection.d.ts +29 -0
  306. package/dist/selector/choice-group.d.ts +114 -0
  307. package/dist/selector/index.d.ts +2 -0
  308. package/dist/selector/index.js +2 -0
  309. package/dist/selector/selector.d.ts +90 -0
  310. package/dist/selector-BU2MMJ4N.js +93 -0
  311. package/dist/selector-BU2MMJ4N.js.map +1 -0
  312. package/dist/share-sheet/index.d.ts +1 -0
  313. package/dist/share-sheet/index.js +138 -0
  314. package/dist/share-sheet/index.js.map +1 -0
  315. package/dist/share-sheet/share-sheet.d.ts +139 -0
  316. package/dist/side-nav/index.d.ts +1 -0
  317. package/dist/side-nav/index.js +99 -0
  318. package/dist/side-nav/index.js.map +1 -0
  319. package/dist/side-nav/side-nav.d.ts +94 -0
  320. package/dist/skeleton/index.js +51 -2
  321. package/dist/skeleton/index.js.map +1 -1
  322. package/dist/skeleton/skeleton.d.ts +34 -3
  323. package/dist/slider/index.d.ts +1 -0
  324. package/dist/slider/index.js +482 -0
  325. package/dist/slider/index.js.map +1 -0
  326. package/dist/slider/slider.d.ts +174 -0
  327. package/dist/space/index.d.ts +1 -0
  328. package/dist/space/index.js +52 -0
  329. package/dist/space/index.js.map +1 -0
  330. package/dist/space/space.d.ts +46 -0
  331. package/dist/statistic/index.d.ts +1 -0
  332. package/dist/statistic/index.js +152 -0
  333. package/dist/statistic/index.js.map +1 -0
  334. package/dist/statistic/statistic.d.ts +101 -0
  335. package/dist/stepper/index.d.ts +1 -0
  336. package/dist/stepper/index.js +172 -0
  337. package/dist/stepper/index.js.map +1 -0
  338. package/dist/stepper/stepper.d.ts +161 -0
  339. package/dist/steps/index.d.ts +1 -0
  340. package/dist/steps/index.js +72 -0
  341. package/dist/steps/index.js.map +1 -0
  342. package/dist/steps/steps.d.ts +67 -0
  343. package/dist/sticky/index.d.ts +1 -0
  344. package/dist/sticky/index.js +145 -0
  345. package/dist/sticky/index.js.map +1 -0
  346. package/dist/sticky/sticky.d.ts +70 -0
  347. package/dist/swipe-action/index.d.ts +1 -0
  348. package/dist/swipe-action/index.js +417 -0
  349. package/dist/swipe-action/index.js.map +1 -0
  350. package/dist/swipe-action/swipe-action.d.ts +148 -0
  351. package/dist/swiper/gesture.d.ts +32 -0
  352. package/dist/swiper/index.d.ts +1 -0
  353. package/dist/swiper/index.js +2 -0
  354. package/dist/swiper/swiper.d.ts +177 -0
  355. package/dist/swiper-BKivDkHp.js +550 -0
  356. package/dist/swiper-BKivDkHp.js.map +1 -0
  357. package/dist/switch/index.d.ts +1 -0
  358. package/dist/switch/index.js +168 -0
  359. package/dist/switch/index.js.map +1 -0
  360. package/dist/switch/switch.d.ts +142 -0
  361. package/dist/tabbar/index.d.ts +1 -0
  362. package/dist/tabbar/index.js +95 -0
  363. package/dist/tabbar/index.js.map +1 -0
  364. package/dist/tabbar/tabbar.d.ts +119 -0
  365. package/dist/tabs/index.js +22 -1
  366. package/dist/tabs/index.js.map +1 -1
  367. package/dist/tabs/tabs.d.ts +12 -8
  368. package/dist/tag/index.js +123 -2
  369. package/dist/tag/index.js.map +1 -1
  370. package/dist/tag/tag.d.ts +67 -1
  371. package/dist/textarea/index.d.ts +2 -0
  372. package/dist/textarea/index.js +2 -242
  373. package/dist/textarea/platform.d.ts +22 -0
  374. package/dist/textarea/textarea.d.ts +169 -46
  375. package/dist/textarea-qbnruDUG.js +775 -0
  376. package/dist/textarea-qbnruDUG.js.map +1 -0
  377. package/dist/time-picker/index.d.ts +1 -0
  378. package/dist/time-picker/index.js +228 -0
  379. package/dist/time-picker/index.js.map +1 -0
  380. package/dist/time-picker/time-picker.d.ts +83 -0
  381. package/dist/timeline/index.d.ts +1 -0
  382. package/dist/timeline/index.js +131 -0
  383. package/dist/timeline/index.js.map +1 -0
  384. package/dist/timeline/timeline.d.ts +79 -0
  385. package/dist/toast/index.js +47 -4
  386. package/dist/toast/index.js.map +1 -1
  387. package/dist/toast/toast.d.ts +26 -3
  388. package/dist/top-bar/index.js +16 -2
  389. package/dist/top-bar/index.js.map +1 -1
  390. package/dist/top-bar/top-bar.d.ts +13 -2
  391. package/dist/tree-select/index.d.ts +1 -0
  392. package/dist/tree-select/index.js +512 -0
  393. package/dist/tree-select/index.js.map +1 -0
  394. package/dist/tree-select/tree-select.d.ts +215 -0
  395. package/dist/typography/index.d.ts +1 -0
  396. package/dist/typography/index.js +82 -0
  397. package/dist/typography/index.js.map +1 -0
  398. package/dist/typography/typography.d.ts +54 -0
  399. package/dist/upload/index.d.ts +1 -0
  400. package/dist/upload/index.js +458 -0
  401. package/dist/upload/index.js.map +1 -0
  402. package/dist/upload/upload.d.ts +172 -0
  403. package/dist/virtual-list/index.d.ts +1 -0
  404. package/dist/virtual-list/index.js +445 -0
  405. package/dist/virtual-list/index.js.map +1 -0
  406. package/dist/virtual-list/virtual-list.d.ts +160 -0
  407. package/dist/visual-manifest.d.ts +27 -0
  408. package/dist/watermark/index.d.ts +1 -0
  409. package/dist/watermark/index.js +260 -0
  410. package/dist/watermark/index.js.map +1 -0
  411. package/dist/watermark/watermark.d.ts +106 -0
  412. package/package.json +417 -44
  413. package/dist/empty/index.js.map +0 -1
  414. package/dist/icon/index.js.map +0 -1
  415. package/dist/textarea/index.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/dropdown/dropdown.ts"],"sourcesContent":["import { createMachine, type Machine, type Service } from \"@zag-js/core\";\nimport type { NormalizeProps, PropTypes } from \"@zag-js/types\";\nimport {\n getFloatingPositionerStyle, resolveFloatingPlacement, sameFloatingLayout, splitFloatingPlacement, trackFloatingLayout,\n type FloatingAlign, type FloatingLayout, type FloatingPlacement, type FloatingSide,\n} from \"../popover/positioning.js\";\nimport { focusWhenReady, restoreFloatingFocus, trackFloatingDismiss, type FloatingCloseRequest } from \"../popover/layer.js\";\n\n/** Stable DOM parts shared by every adapter. */\nexport const DROPDOWN_PARTS = [\"trigger\", \"positioner\", \"content\", \"item\"] as const;\nexport type DropdownPlacement = FloatingPlacement;\nexport const DROPDOWN_DEFAULT_PLACEMENT: DropdownPlacement = \"bottom-start\";\n/** Main-axis gap between the trigger and the menu in CSS px. */\nexport const DROPDOWN_DEFAULT_OFFSET = 4;\n/** Characters typed within this many milliseconds extend the typeahead query. */\nexport const DROPDOWN_TYPEAHEAD_TIMEOUT = 500;\nexport const DROPDOWN_MOVES = [\"first\", \"last\", \"next\", \"prev\"] as const;\nexport type DropdownMove = (typeof DROPDOWN_MOVES)[number];\n\n/** One text menu item. value is the exact selection notification; label is the visible and typeahead text. */\nexport interface QwDropdownItem {\n value: string;\n label: string;\n /** Visible and announced (aria-disabled) but skipped by roving focus and never selected. */\n disabled?: boolean;\n /** Destructive styling only; there is no second confirmation. */\n danger?: boolean;\n}\nexport interface QwResolvedDropdownItem {\n readonly source: QwDropdownItem;\n /** Position in the caller's items array; part of the item id. */\n readonly index: number;\n readonly value: string;\n readonly label: string;\n /** Disabled by the caller, or a later duplicate of an earlier value. */\n readonly disabled: boolean;\n readonly danger: boolean;\n readonly duplicate: boolean;\n}\n/** keyboard: ArrowDown/ArrowUp on the trigger; tab / focus-outside: focus left the menu; select: an item was chosen. */\nexport type DropdownOpenChangeReason = \"trigger\" | \"keyboard\" | \"escape\" | \"outside\" | \"focus-outside\" | \"tab\" | \"select\" | \"api\";\nexport interface DropdownOpenChangeDetails { open: boolean; reason: DropdownOpenChangeReason }\nexport interface DropdownSelectDetails { value: string }\n\nexport interface QwDropdownProps {\n /** Page-unique instance identity; adapters generate one when omitted. */\n id?: string;\n /** Caller-owned menu items, never mutated; default []. */\n items?: readonly QwDropdownItem[];\n /** Controlled open state; undefined lets Core own it. */\n open?: boolean;\n /** Initial open state when uncontrolled. */\n defaultOpen?: boolean;\n /** Every open/close request, controlled or not; controlled owners accept by updating open, or refuse by keeping it. */\n onOpenChange?: (details: DropdownOpenChangeDetails) => void;\n /** An enabled item was activated (click, Enter or Space); a close request (reason select) follows. */\n onSelect?: (details: DropdownSelectDetails) => void;\n /** Preferred placement (default bottom-start; unknown values use it); positioning is Popover's Core module. */\n placement?: DropdownPlacement;\n /** Main-axis gap in CSS px; default 4. */\n offset?: number;\n /** Accessible name of the menu; omitted names it by the trigger (aria-labelledby). */\n label?: string;\n}\nexport interface ResolvedDropdownState { placement: DropdownPlacement; offset: number; label: string | undefined }\nconst text = (value: unknown): string | undefined => typeof value === \"string\" && value.trim() ? value.trim() : undefined;\nexport function resolveDropdownState(props: QwDropdownProps = {}): ResolvedDropdownState {\n return {\n placement: resolveFloatingPlacement(props.placement, DROPDOWN_DEFAULT_PLACEMENT),\n offset: typeof props.offset === \"number\" && Number.isFinite(props.offset) ? props.offset : DROPDOWN_DEFAULT_OFFSET,\n label: text(props.label),\n };\n}\n/** Keeps every item in order; a repeated value only keeps its first item enabled (a disabled first item does not promote a later one). */\nexport function resolveDropdownItems(items: readonly QwDropdownItem[] | undefined): readonly QwResolvedDropdownItem[] {\n const seen = new Set<string>();\n return (Array.isArray(items) ? items : []).map((source: QwDropdownItem, index) => {\n const value = String(source?.value ?? \"\"), duplicate = seen.has(value);\n seen.add(value);\n return { source, index, value, label: String(source?.label ?? \"\"), disabled: source?.disabled === true || duplicate, danger: source?.danger === true, duplicate };\n });\n}\n/** Source index of the enabled item a move lands on, or -1 when nothing is enabled. next/prev wrap; from no highlight they start at the ends. */\nexport function getDropdownMoveTarget(items: readonly QwResolvedDropdownItem[], current: string | null, move: DropdownMove): number {\n const enabled = items.filter((item) => !item.disabled);\n if (!enabled.length) return -1;\n const at = enabled.findIndex((item) => item.value === current), last = enabled.length - 1;\n const position = move === \"first\" ? 0 : move === \"last\" ? last\n : move === \"next\" ? (at < 0 || at === last ? 0 : at + 1)\n : (at <= 0 ? last : at - 1);\n return enabled[position]!.index;\n}\n/**\n * Explicit text match: the first enabled item, searching forward and wrapping, whose trimmed label starts\n * with the query (locale lower case). A single or repeated character starts after the current item (so\n * repeating it cycles); a longer query keeps the current item while it still matches. -1 when none matches.\n */\nexport function getDropdownTypeaheadTarget(items: readonly QwResolvedDropdownItem[], current: string | null, query: string): number {\n const search = query.toLocaleLowerCase();\n if (!search) return -1;\n const repeated = [...search].every((char) => char === search[0]), needle = repeated ? search[0]! : search;\n const enabled = items.filter((item) => !item.disabled);\n const at = enabled.findIndex((item) => item.value === current), start = at < 0 ? 0 : repeated ? at + 1 : at;\n for (let step = 0; step < enabled.length; step += 1) {\n const item = enabled[(start + step) % enabled.length]!;\n if (item.label.trim().toLocaleLowerCase().startsWith(needle)) return item.index;\n }\n return -1;\n}\nexport function createDropdownProps(props: QwDropdownProps = {}): QwDropdownProps {\n if (props.id !== undefined && (typeof props.id !== \"string\" || !props.id.trim())) throw new TypeError(\"Dropdown requires a nonempty instance id when provided\");\n return { ...props };\n}\n\ntype FocusIntent = \"first\" | \"last\";\nexport interface QwDropdownSchema {\n props: QwDropdownProps;\n context: { dismissReady: boolean; layout: FloatingLayout | null; highlighted: string | null };\n refs: { request: FloatingCloseRequest | null; focus: FocusIntent | null; typeahead: { query: string; at: number }; cancelFocus: (() => void) | null };\n state: \"open\" | \"closed\";\n guard: \"isControlled\";\n action: \"notifyOpen\" | \"notifyClose\" | \"restoreFocus\" | \"setLayout\" | \"dismissReady\" | \"clearLayout\" | \"syncControlled\" | \"highlight\" | \"move\" | \"typeahead\" | \"select\" | \"reconcile\";\n effect: \"trackLayout\" | \"trackDismiss\";\n event:\n | { type: \"DISMISS.READY\" }\n | { type: \"OPEN\" | \"TOGGLE\"; reason?: DropdownOpenChangeReason; focus?: FocusIntent }\n | { type: \"CLOSE\"; reason?: DropdownOpenChangeReason; focusable?: boolean }\n | { type: \"CONTROLLED.OPEN\" | \"CONTROLLED.CLOSE\" }\n | { type: \"LAYOUT\"; layout: FloatingLayout }\n | { type: \"HIGHLIGHT\"; value: string }\n | { type: \"MOVE\"; to: DropdownMove }\n | { type: \"TYPEAHEAD\"; key: string }\n | { type: \"SELECT\"; index: number; value: string };\n}\nexport type QwDropdownMachine = Machine<QwDropdownSchema>;\nexport type QwDropdownService = Service<QwDropdownSchema>;\ntype Scope = QwDropdownService[\"scope\"];\ntype Context = QwDropdownService[\"context\"];\nconst ids = (scope: Scope) => {\n const base = `dropdown:${scope.id}`;\n return { trigger: `${base}:trigger`, positioner: `${base}:positioner`, content: `${base}:content`, item: (index: number) => `${base}:item:${index}` };\n};\nconst live = (prop: QwDropdownService[\"prop\"]) => resolveDropdownState({ placement: prop(\"placement\"), offset: prop(\"offset\"), label: prop(\"label\") });\nconst reasonOf = (event: { readonly [key: string]: unknown }): DropdownOpenChangeReason => typeof event.reason === \"string\" ? event.reason as DropdownOpenChangeReason : \"api\";\n/** Primitive signature for zag's tracker: value, order and enabled state of every item. */\nconst signature = (items: readonly QwDropdownItem[] | undefined) => resolveDropdownItems(items).map((item) => `${item.disabled ? 0 : 1}${item.value}`).join(\"\\u0000\");\n/** Roving focus: real DOM focus on the item (scrolled into the menu's view), or the menu itself when nothing is enabled. */\nfunction focusItem(scope: Scope, context: Context, items: readonly QwResolvedDropdownItem[], index: number): void {\n const id = ids(scope), item = items[index];\n if (!item) { scope.getById(id.content)?.focus({ preventScroll: true }); return; }\n context.set(\"highlighted\", item.value);\n const node = scope.getById(id.item(index));\n node?.focus({ preventScroll: true });\n node?.scrollIntoView?.({ block: \"nearest\" });\n}\n\n/**\n * Core owns the menu: open/close with controlled refusal, Popover's positioning module while open, the\n * shared non-modal layer (Escape, outside pointer, focus leaving), roving focus, typeahead, selection and\n * focus return to the original trigger.\n */\nexport const dropdownMachine: QwDropdownMachine = createMachine<QwDropdownSchema>({\n props: ({ props }) => createDropdownProps(props),\n initialState: ({ prop }) => (prop(\"open\") ?? prop(\"defaultOpen\")) ? \"open\" : \"closed\",\n context: ({ bindable }) => ({ dismissReady: bindable(() => ({ defaultValue: false })),\n layout: bindable<FloatingLayout | null>(() => ({ defaultValue: null, isEqual: sameFloatingLayout })),\n highlighted: bindable<string | null>(() => ({ defaultValue: null })),\n }),\n refs: () => ({ request: null, focus: null, typeahead: { query: \"\", at: 0 }, cancelFocus: null }),\n watch({ track, prop, action }) {\n track([() => prop(\"open\")], () => action([\"syncControlled\"]));\n track([() => signature(prop(\"items\"))], () => action([\"reconcile\"]));\n },\n states: {\n closed: {\n on: {\n \"CONTROLLED.OPEN\": { target: \"open\" },\n OPEN: [{ guard: \"isControlled\", actions: [\"notifyOpen\"] }, { target: \"open\", actions: [\"notifyOpen\"] }],\n TOGGLE: [{ guard: \"isControlled\", actions: [\"notifyOpen\"] }, { target: \"open\", actions: [\"notifyOpen\"] }],\n },\n },\n open: {\n effects: [\"trackLayout\", \"trackDismiss\"],\n exit: [\"clearLayout\"],\n on: {\n \"CONTROLLED.CLOSE\": { target: \"closed\", actions: [\"restoreFocus\"] },\n CLOSE: [{ guard: \"isControlled\", actions: [\"notifyClose\"] }, { target: \"closed\", actions: [\"notifyClose\", \"restoreFocus\"] }],\n TOGGLE: [{ guard: \"isControlled\", actions: [\"notifyClose\"] }, { target: \"closed\", actions: [\"notifyClose\", \"restoreFocus\"] }],\n LAYOUT: { actions: [\"setLayout\"] },\n \"DISMISS.READY\": { actions: [\"dismissReady\"] },\n HIGHLIGHT: { actions: [\"highlight\"] },\n MOVE: { actions: [\"move\"] },\n TYPEAHEAD: { actions: [\"typeahead\"] },\n SELECT: { actions: [\"select\"] },\n },\n },\n },\n implementations: {\n guards: { isControlled: ({ prop }) => prop(\"open\") !== undefined },\n actions: {\n notifyOpen({ prop, event, refs }) {\n refs.set(\"request\", null);\n refs.set(\"focus\", event.focus === \"last\" ? \"last\" : event.focus === \"first\" ? \"first\" : null);\n prop(\"onOpenChange\")?.({ open: true, reason: reasonOf(event) });\n },\n notifyClose({ prop, event, refs }) {\n const reason = reasonOf(event);\n refs.set(\"request\", { reason, focusable: event.focusable === true });\n prop(\"onOpenChange\")?.({ open: false, reason });\n },\n // Runs while the menu is still in the DOM: focus moves before the items unmount.\n restoreFocus({ scope, refs }) {\n const request = refs.get(\"request\") ?? { reason: \"api\", focusable: false }, id = ids(scope);\n refs.set(\"request\", null);\n refs.set(\"focus\", null);\n restoreFloatingFocus(scope.getDoc(), scope.getById(id.trigger), scope.getById(id.content), request);\n },\n // The first layout makes the menu visible; a requested open then moves focus into it.\n setLayout({ context, event, refs, scope, prop }) {\n if (event.type !== \"LAYOUT\") return;\n context.set(\"layout\", event.layout);\n const intent = refs.get(\"focus\");\n if (!intent) return;\n refs.set(\"focus\", null);\n const items = resolveDropdownItems(prop(\"items\")), index = getDropdownMoveTarget(items, null, intent), id = ids(scope);\n if (index >= 0) context.set(\"highlighted\", items[index]!.value);\n refs.get(\"cancelFocus\")?.();\n refs.set(\"cancelFocus\", focusWhenReady(scope.getDoc(), () => scope.getById(index >= 0 ? id.item(index) : id.content)));\n },\n dismissReady({ context }) { context.set(\"dismissReady\", true); },\n clearLayout({ context, refs }) {\n context.set(\"dismissReady\", false);\n refs.get(\"cancelFocus\")?.();\n refs.set(\"cancelFocus\", null);\n refs.set(\"typeahead\", { query: \"\", at: 0 });\n context.set(\"layout\", null);\n context.set(\"highlighted\", null);\n },\n syncControlled({ prop, send }) {\n const open = prop(\"open\");\n if (open !== undefined) send({ type: open ? \"CONTROLLED.OPEN\" : \"CONTROLLED.CLOSE\" });\n },\n highlight({ context, event, prop }) {\n if (event.type !== \"HIGHLIGHT\") return;\n const item = resolveDropdownItems(prop(\"items\")).find((entry) => entry.value === event.value && !entry.disabled);\n if (item && context.get(\"highlighted\") !== item.value) context.set(\"highlighted\", item.value);\n },\n move({ context, event, prop, scope }) {\n if (event.type !== \"MOVE\") return;\n const items = resolveDropdownItems(prop(\"items\"));\n focusItem(scope, context, items, getDropdownMoveTarget(items, context.get(\"highlighted\"), event.to));\n },\n typeahead({ context, event, prop, refs, scope }) {\n if (event.type !== \"TYPEAHEAD\") return;\n const now = Date.now(), previous = refs.get(\"typeahead\");\n const query = now - previous.at > DROPDOWN_TYPEAHEAD_TIMEOUT ? event.key : previous.query + event.key;\n refs.set(\"typeahead\", { query, at: now });\n const items = resolveDropdownItems(prop(\"items\")), index = getDropdownTypeaheadTarget(items, context.get(\"highlighted\"), query);\n if (index >= 0) focusItem(scope, context, items, index);\n },\n // Re-validated against the latest items: a removed, replaced, disabled or duplicated item is never selected.\n select({ event, prop, send }) {\n if (event.type !== \"SELECT\") return;\n const item = resolveDropdownItems(prop(\"items\"))[event.index];\n if (!item || item.disabled || item.value !== event.value) return;\n prop(\"onSelect\")?.({ value: item.value });\n send({ type: \"CLOSE\", reason: \"select\" });\n },\n // Items changed while open: a highlight that is gone or disabled is dropped, keeping focus inside the menu.\n reconcile({ context, prop, scope, state }) {\n const value = context.get(\"highlighted\");\n if (!state.matches(\"open\") || value === null) return;\n if (resolveDropdownItems(prop(\"items\")).some((item) => item.value === value && !item.disabled)) return;\n context.set(\"highlighted\", null);\n const doc = scope.getDoc(), id = ids(scope);\n const keep = () => {\n const content = scope.getById(id.content), active = doc.activeElement;\n if (content && (!active || active === doc.body || active.getAttribute(\"aria-disabled\") === \"true\")) content.focus({ preventScroll: true });\n };\n const win = doc.defaultView;\n if (win) win.requestAnimationFrame(keep); else keep();\n },\n },\n effects: {\n trackLayout({ scope, prop, send }) {\n const id = ids(scope);\n return trackFloatingLayout(scope.getDoc(), {\n anchor: () => scope.getById(id.trigger), positioner: () => scope.getById(id.positioner), content: () => scope.getById(id.content), arrow: () => null,\n placement: () => live(prop).placement, offset: () => live(prop).offset, fallback: DROPDOWN_DEFAULT_PLACEMENT,\n onLayout: (layout) => send({ type: \"LAYOUT\", layout }),\n });\n },\n trackDismiss({ scope, send }) {\n const id = ids(scope);\n return trackFloatingDismiss(scope.getDoc(), {\n onReady: () => send({ type: \"DISMISS.READY\" }),\n type: \"menu\", content: () => scope.getById(id.content), trigger: () => scope.getById(id.trigger),\n closeOnEscape: () => true, closeOnOutside: () => true, closeOnFocusOutside: () => true,\n onDismiss: (request) => send({ type: \"CLOSE\", reason: request.reason, focusable: request.focusable }),\n });\n },\n },\n },\n});\n\n/** Minimal event surfaces shared by React, Vue and native events. */\nexport interface DropdownDomEvent { readonly defaultPrevented: boolean; preventDefault(): void }\nexport interface DropdownKeyboardEvent extends DropdownDomEvent {\n readonly key: string;\n readonly shiftKey?: boolean;\n readonly altKey?: boolean;\n readonly ctrlKey?: boolean;\n readonly metaKey?: boolean;\n readonly isComposing?: boolean;\n}\nconst CONTENT_MOVES: Readonly<Record<string, DropdownMove>> = { ArrowDown: \"next\", ArrowUp: \"prev\", Home: \"first\", End: \"last\" };\n\nexport interface QwDropdownApi<T extends PropTypes = PropTypes> {\n open: boolean;\n /** The measured placement while open (after flipping), otherwise the preferred one. */\n placement: DropdownPlacement;\n side: FloatingSide;\n align: FloatingAlign;\n positioned: boolean;\n items: readonly QwResolvedDropdownItem[];\n /** Value of the item holding roving focus. */\n highlighted: string | null;\n /** Request a state; controlled owners decide through onOpenChange (reason api). */\n setOpen(open: boolean): void;\n /** Merge onto the caller's own trigger node (click toggles; ArrowDown/ArrowUp open on the first/last item); preventDefault() in its handlers skips Core. */\n getTriggerProps(): T[\"element\"];\n getPositionerProps(): T[\"element\"];\n getContentProps(): T[\"element\"];\n getItemProps(item: QwResolvedDropdownItem): T[\"element\"];\n}\nexport function connectDropdown<T extends PropTypes>(service: QwDropdownService, normalize: NormalizeProps<T>): QwDropdownApi<T> {\n const state = live(service.prop), id = ids(service.scope), open = service.state.matches(\"open\");\n const layout = open && service.context.get(\"dismissReady\") ? service.context.get(\"layout\") : null, highlighted = open ? service.context.get(\"highlighted\") : null;\n const items = resolveDropdownItems(service.prop(\"items\"));\n const placement = layout?.placement ?? state.placement, { side, align } = layout ?? splitFloatingPlacement(state.placement);\n const part = (name: (typeof DROPDOWN_PARTS)[number]) => ({ \"data-scope\": \"dropdown\", \"data-part\": name });\n const select = (item: QwResolvedDropdownItem) => service.send({ type: \"SELECT\", index: item.index, value: item.value });\n return {\n open, placement, side, align, positioned: !!layout, items, highlighted,\n setOpen(next) { if (next !== open) service.send({ type: next ? \"OPEN\" : \"CLOSE\", reason: \"api\" }); },\n getTriggerProps: () => normalize.element({\n ...part(\"trigger\"), id: id.trigger, \"aria-haspopup\": \"menu\", \"aria-expanded\": open, \"aria-controls\": id.content, \"data-state\": open ? \"open\" : \"closed\",\n onClick(event: DropdownDomEvent) { if (!event.defaultPrevented) service.send({ type: \"TOGGLE\", reason: \"trigger\", focus: \"first\" }); },\n onKeyDown(event: DropdownKeyboardEvent) {\n const focus = event.key === \"ArrowDown\" ? \"first\" : event.key === \"ArrowUp\" ? \"last\" : null;\n if (event.defaultPrevented || !focus) return;\n event.preventDefault();\n if (open) service.send({ type: \"MOVE\", to: focus });\n else service.send({ type: \"OPEN\", reason: \"keyboard\", focus });\n },\n }),\n getPositionerProps: () => normalize.element({\n ...part(\"positioner\"), id: id.positioner, \"data-placement\": placement, \"data-side\": side, \"data-align\": align,\n \"data-positioned\": layout ? \"\" : undefined, style: getFloatingPositionerStyle(layout),\n }),\n getContentProps: () => normalize.element({\n ...part(\"content\"), id: id.content, role: \"menu\", tabIndex: -1, \"aria-label\": state.label, \"aria-labelledby\": state.label ? undefined : id.trigger,\n \"data-state\": open ? \"open\" : \"closed\", \"data-side\": side, \"data-empty\": items.length ? undefined : \"\",\n onKeyDown(event: DropdownKeyboardEvent) {\n if (event.defaultPrevented || event.isComposing) return;\n const key = event.key, move = CONTENT_MOVES[key];\n if (move) { event.preventDefault(); service.send({ type: \"MOVE\", to: move }); return; }\n if (key === \"Enter\" || key === \" \") {\n event.preventDefault();\n const current = service.context.get(\"highlighted\"), item = items.find((entry) => entry.value === current && !entry.disabled);\n if (item) select(item);\n return;\n }\n if (key === \"Tab\") {\n // Leave from the trigger's place in the tab order: Tab continues past it, Shift+Tab stops on it.\n service.scope.getById(id.trigger)?.focus({ preventScroll: true });\n if (event.shiftKey) event.preventDefault();\n service.send({ type: \"CLOSE\", reason: \"tab\" });\n return;\n }\n if (key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) { event.preventDefault(); service.send({ type: \"TYPEAHEAD\", key }); }\n },\n }),\n getItemProps: (item) => normalize.element({\n ...part(\"item\"), id: id.item(item.index), role: \"menuitem\", tabIndex: item.disabled ? undefined : -1, \"aria-disabled\": item.disabled ? \"true\" : undefined,\n \"data-value\": item.value, \"data-disabled\": item.disabled ? \"\" : undefined, \"data-danger\": item.danger ? \"\" : undefined,\n \"data-highlighted\": !item.disabled && highlighted === item.value ? \"\" : undefined,\n onClick(event: DropdownDomEvent) { if (!event.defaultPrevented && !item.disabled) select(item); },\n onFocus() { if (!item.disabled) service.send({ type: \"HIGHLIGHT\", value: item.value }); },\n }),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { EllipsisDirection } from "./ellipsis.js";
2
+ /**
3
+ * Ellipsis platform boundary: DOM measurement and resize observation only.
4
+ * Truncation search and expanded/collapsed decisions stay in ellipsis.ts.
5
+ * Nothing here runs at module top level, so importing it is SSR-safe.
6
+ */
7
+ export interface EllipsisMeasureInput {
8
+ content: string;
9
+ rows: number;
10
+ direction: EllipsisDirection;
11
+ symbol: string;
12
+ /** Visible action label measured on the same line as the truncated text ("" = none). */
13
+ actionText: string;
14
+ }
15
+ export interface EllipsisMeasurement {
16
+ /** True when the full content exceeds `rows` lines. */
17
+ overflow: boolean;
18
+ /** Collapsed visible text (with symbol) when overflowing; otherwise the full content. */
19
+ text: string;
20
+ /** Inline size used for the decision, in CSS pixels. */
21
+ width: number;
22
+ }
23
+ export declare const ELLIPSIS_PROBE_ATTRIBUTE = "data-qw-ellipsis-probe";
24
+ /** Code-point safe truncation candidates; `kept` counts content code points that remain visible. */
25
+ export declare function buildEllipsisCandidate(chars: readonly string[], kept: number, direction: EllipsisDirection, symbol: string): string;
26
+ /**
27
+ * Pure search: longest candidate that `fits`. `fits` must be monotonic (fewer kept characters never fit worse).
28
+ * Returns null when the full content fits.
29
+ */
30
+ export declare function findEllipsisText(content: string, direction: EllipsisDirection, symbol: string, fits: (candidate: string) => boolean): string | null;
31
+ /** Measures with a detached-from-layout probe in the same document; returns null when not laid out (zero width). */
32
+ export declare function measureEllipsisLayout(root: HTMLElement, input: EllipsisMeasureInput): EllipsisMeasurement | null;
33
+ /** Calls `onChange` when the observed inline size changes (and once on start). Returns stop. */
34
+ export declare function observeEllipsisLayout(root: HTMLElement, onChange: () => void): () => void;
@@ -0,0 +1,88 @@
1
+ import { type Machine, type Service } from "@zag-js/core";
2
+ import type { NormalizeProps, PropTypes } from "@zag-js/types";
3
+ import { type EllipsisMeasurement } from "./ellipsis-layout.js";
4
+ export declare const ELLIPSIS_DIRECTIONS: readonly ["end", "start", "middle"];
5
+ export declare const ELLIPSIS_PARTS: readonly ["root", "content", "text", "full-text", "toggle"];
6
+ export type EllipsisDirection = (typeof ELLIPSIS_DIRECTIONS)[number];
7
+ export type EllipsisPart = (typeof ELLIPSIS_PARTS)[number];
8
+ export interface EllipsisExpandedChangeDetails {
9
+ expanded: boolean;
10
+ }
11
+ export interface QwEllipsisProps {
12
+ /** Stable instance identity for aria-controls; frameworks generate one when omitted. */
13
+ id?: string;
14
+ /** Plain text content (measurement requires text). */
15
+ content: string;
16
+ /** Visible lines when collapsed; integer ≥ 1, invalid → 1. */
17
+ rows?: number;
18
+ /** Where the ellipsis symbol goes. Default end. */
19
+ direction?: EllipsisDirection;
20
+ /** Controlled expanded state when defined. */
21
+ expanded?: boolean;
22
+ defaultExpanded?: boolean;
23
+ /** Expand action label; "" disables expansion. Default 展开. */
24
+ expandText?: string;
25
+ /** Collapse action label; "" hides the collapse action. Default 收起. */
26
+ collapseText?: string;
27
+ /** Ellipsis symbol. Default …. */
28
+ symbol?: string;
29
+ onExpandedChange?: (details: EllipsisExpandedChangeDetails) => void;
30
+ }
31
+ export declare function normalizeEllipsisRows(rows: unknown): number;
32
+ type NormalizedProps = QwEllipsisProps & {
33
+ content: string;
34
+ rows: number;
35
+ direction: EllipsisDirection;
36
+ expandText: string;
37
+ collapseText: string;
38
+ symbol: string;
39
+ defaultExpanded: boolean;
40
+ };
41
+ export declare function createEllipsisProps(props: QwEllipsisProps): NormalizedProps;
42
+ interface KeyedMeasurement extends EllipsisMeasurement {
43
+ key: string;
44
+ }
45
+ export interface QwEllipsisSchema {
46
+ props: NormalizedProps;
47
+ context: {
48
+ expanded: boolean;
49
+ measurement: KeyedMeasurement | null;
50
+ };
51
+ state: "ready";
52
+ action: "toggle" | "setExpanded" | "measure";
53
+ effect: "observeLayout";
54
+ event: {
55
+ type: "TOGGLE";
56
+ } | {
57
+ type: "EXPANDED.SET";
58
+ value: boolean;
59
+ } | {
60
+ type: "MEASURE";
61
+ };
62
+ }
63
+ export type QwEllipsisMachine = Machine<QwEllipsisSchema>;
64
+ export type QwEllipsisService = Service<QwEllipsisSchema>;
65
+ /** Expanded state + measurement lifecycle. The resize observer is a Core effect: start on mount, stop on unmount. */
66
+ export declare const ellipsisMachine: QwEllipsisMachine;
67
+ export interface QwEllipsisApi<T extends PropTypes = PropTypes> {
68
+ content: string;
69
+ expanded: boolean;
70
+ /** A current measurement exists for these props. */
71
+ measured: boolean;
72
+ overflow: boolean;
73
+ /** Visible text is shortened; full text is provided to assistive technology separately. */
74
+ truncated: boolean;
75
+ visibleText: string;
76
+ toggleText: string;
77
+ showToggle: boolean;
78
+ setExpanded(expanded: boolean): void;
79
+ /** Re-run measurement (for example after a caller-driven style change). */
80
+ remeasure(): void;
81
+ getRootProps(): T["element"];
82
+ getContentProps(): T["element"];
83
+ getTextProps(): T["element"];
84
+ getFullTextProps(): T["element"];
85
+ getToggleProps(): T["button"];
86
+ }
87
+ export declare function connectEllipsis<T extends PropTypes>(service: QwEllipsisService, normalize: NormalizeProps<T>): QwEllipsisApi<T>;
88
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./ellipsis.js";
2
+ export * from "./ellipsis-layout.js";
@@ -0,0 +1,320 @@
1
+ import { createMachine } from "@zag-js/core";
2
+ import { dataAttr, visuallyHiddenStyle } from "@zag-js/dom-query";
3
+ //#region src/ellipsis/ellipsis-layout.ts
4
+ /** Inherited typography that determines line breaking. */
5
+ const COPIED_STYLES = [
6
+ "font-family",
7
+ "font-size",
8
+ "font-weight",
9
+ "font-style",
10
+ "font-variant",
11
+ "font-stretch",
12
+ "font-feature-settings",
13
+ "letter-spacing",
14
+ "word-spacing",
15
+ "line-height",
16
+ "text-transform",
17
+ "text-indent",
18
+ "word-break",
19
+ "overflow-wrap",
20
+ "line-break",
21
+ "hyphens",
22
+ "tab-size",
23
+ "direction",
24
+ "unicode-bidi",
25
+ "writing-mode"
26
+ ];
27
+ const ELLIPSIS_PROBE_ATTRIBUTE = "data-qw-ellipsis-probe";
28
+ /** Code-point safe truncation candidates; `kept` counts content code points that remain visible. */
29
+ function buildEllipsisCandidate(chars, kept, direction, symbol) {
30
+ const count = Math.max(0, Math.min(chars.length, Math.floor(kept)));
31
+ if (direction === "start") return symbol + chars.slice(chars.length - count).join("");
32
+ if (direction === "middle") {
33
+ const head = Math.ceil(count / 2), tail = count - head;
34
+ return chars.slice(0, head).join("") + symbol + (tail ? chars.slice(chars.length - tail).join("") : "");
35
+ }
36
+ return chars.slice(0, count).join("") + symbol;
37
+ }
38
+ /**
39
+ * Pure search: longest candidate that `fits`. `fits` must be monotonic (fewer kept characters never fit worse).
40
+ * Returns null when the full content fits.
41
+ */
42
+ function findEllipsisText(content, direction, symbol, fits) {
43
+ if (fits(content)) return null;
44
+ const chars = Array.from(content);
45
+ let low = 0, high = chars.length - 1, best = 0;
46
+ while (low <= high) {
47
+ const mid = low + high >> 1;
48
+ if (fits(buildEllipsisCandidate(chars, mid, direction, symbol))) {
49
+ best = mid;
50
+ low = mid + 1;
51
+ } else high = mid - 1;
52
+ }
53
+ return buildEllipsisCandidate(chars, best, direction, symbol);
54
+ }
55
+ function px(value) {
56
+ const parsed = Number.parseFloat(value);
57
+ return Number.isFinite(parsed) ? parsed : 0;
58
+ }
59
+ /** Measures with a detached-from-layout probe in the same document; returns null when not laid out (zero width). */
60
+ function measureEllipsisLayout(root, input) {
61
+ const doc = root.ownerDocument, view = doc.defaultView;
62
+ if (!view || !doc.body || !root.isConnected) return null;
63
+ const style = view.getComputedStyle(root);
64
+ const width = root.getBoundingClientRect().width - px(style.paddingLeft) - px(style.paddingRight) - px(style.borderLeftWidth) - px(style.borderRightWidth);
65
+ if (!(width > 0)) return null;
66
+ const probe = doc.createElement("div");
67
+ probe.setAttribute(ELLIPSIS_PROBE_ATTRIBUTE, "");
68
+ probe.setAttribute("aria-hidden", "true");
69
+ for (const name of COPIED_STYLES) probe.style.setProperty(name, style.getPropertyValue(name));
70
+ for (const [name, value] of [
71
+ ["position", "absolute"],
72
+ ["visibility", "hidden"],
73
+ ["pointer-events", "none"],
74
+ ["inset-block-start", "0"],
75
+ ["inset-inline-start", "0"],
76
+ ["display", "block"],
77
+ ["box-sizing", "content-box"],
78
+ ["padding", "0"],
79
+ ["border", "0"],
80
+ ["margin", "0"],
81
+ ["inline-size", `${width}px`],
82
+ ["block-size", "auto"],
83
+ ["max-block-size", "none"],
84
+ ["overflow", "visible"],
85
+ ["white-space", style.whiteSpace === "nowrap" || style.whiteSpace === "pre" ? "pre-wrap" : style.whiteSpace || "normal"],
86
+ ["-webkit-line-clamp", "none"]
87
+ ]) probe.style.setProperty(name, value);
88
+ probe.style.setProperty("width", `${width}px`);
89
+ doc.body.append(probe);
90
+ try {
91
+ probe.replaceChildren();
92
+ for (let line = 0; line < input.rows; line++) {
93
+ if (line) probe.append(doc.createElement("br"));
94
+ probe.append(doc.createTextNode("\xA0"));
95
+ }
96
+ const limit = probe.getBoundingClientRect().height + .5;
97
+ const suffix = input.actionText ? `\u00a0${input.actionText}\u00a0` : "";
98
+ const height = (text) => {
99
+ probe.textContent = text;
100
+ return probe.getBoundingClientRect().height;
101
+ };
102
+ if (height(input.content) <= limit) return {
103
+ overflow: false,
104
+ text: input.content,
105
+ width
106
+ };
107
+ const text = findEllipsisText(input.content, input.direction, input.symbol, (candidate) => height(candidate + suffix) <= limit);
108
+ return {
109
+ overflow: text !== null,
110
+ text: text ?? input.content,
111
+ width
112
+ };
113
+ } finally {
114
+ probe.remove();
115
+ }
116
+ }
117
+ /** Calls `onChange` when the observed inline size changes (and once on start). Returns stop. */
118
+ function observeEllipsisLayout(root, onChange) {
119
+ const view = root.ownerDocument.defaultView;
120
+ let disposed = false, last = NaN;
121
+ const notify = () => {
122
+ if (!disposed) onChange();
123
+ };
124
+ let observer;
125
+ if (view && typeof view.ResizeObserver === "function") {
126
+ observer = new view.ResizeObserver((entries) => {
127
+ const width = entries[entries.length - 1]?.contentRect?.width;
128
+ if (typeof width === "number" && width === last) return;
129
+ if (typeof width === "number") last = width;
130
+ notify();
131
+ });
132
+ observer.observe(root);
133
+ } else queueMicrotask(notify);
134
+ const fonts = root.ownerDocument.fonts;
135
+ if (fonts?.ready) fonts.ready.then(notify, () => {});
136
+ return () => {
137
+ disposed = true;
138
+ observer?.disconnect();
139
+ };
140
+ }
141
+ //#endregion
142
+ //#region src/ellipsis/ellipsis.ts
143
+ const ELLIPSIS_DIRECTIONS = [
144
+ "end",
145
+ "start",
146
+ "middle"
147
+ ];
148
+ const ELLIPSIS_PARTS = [
149
+ "root",
150
+ "content",
151
+ "text",
152
+ "full-text",
153
+ "toggle"
154
+ ];
155
+ function normalizeEllipsisRows(rows) {
156
+ return typeof rows === "number" && Number.isFinite(rows) && rows >= 1 ? Math.min(1e3, Math.floor(rows)) : 1;
157
+ }
158
+ function createEllipsisProps(props) {
159
+ if (props.id !== void 0 && (typeof props.id !== "string" || !props.id.trim())) throw new TypeError("Ellipsis requires a nonempty instance id when provided");
160
+ return {
161
+ ...props,
162
+ content: typeof props.content === "string" ? props.content : String(props.content ?? ""),
163
+ rows: normalizeEllipsisRows(props.rows),
164
+ direction: ELLIPSIS_DIRECTIONS.includes(props.direction) ? props.direction : "end",
165
+ expandText: typeof props.expandText === "string" ? props.expandText : "展开",
166
+ collapseText: typeof props.collapseText === "string" ? props.collapseText : "收起",
167
+ symbol: typeof props.symbol === "string" ? props.symbol : "…",
168
+ defaultExpanded: props.defaultExpanded === true,
169
+ expanded: typeof props.expanded === "boolean" ? props.expanded : void 0
170
+ };
171
+ }
172
+ function hex(id) {
173
+ return id.split("").map((char) => char.charCodeAt(0).toString(16).padStart(4, "0")).join("");
174
+ }
175
+ const rootId = (scope) => {
176
+ if (!scope.id?.trim()) throw new TypeError("Ellipsis requires a nonempty stable id");
177
+ return `qw-ellipsis-${hex(scope.id)}`;
178
+ };
179
+ const contentId = (scope) => `${rootId(scope)}-content`;
180
+ /** Measurement identity: a result for other text/options is never shown. */
181
+ const measureKey = (params) => JSON.stringify([
182
+ params.prop("content"),
183
+ params.prop("rows"),
184
+ params.prop("direction"),
185
+ params.prop("symbol"),
186
+ params.prop("expandText")
187
+ ]);
188
+ function measure(params) {
189
+ const root = params.scope.getById(rootId(params.scope));
190
+ if (!root) return;
191
+ const result = measureEllipsisLayout(root, {
192
+ content: params.prop("content"),
193
+ rows: params.prop("rows"),
194
+ direction: params.prop("direction"),
195
+ symbol: params.prop("symbol"),
196
+ actionText: params.prop("expandText")
197
+ });
198
+ if (!result) return;
199
+ const key = measureKey(params), previous = params.context.get("measurement");
200
+ if (previous && previous.key === key && previous.overflow === result.overflow && previous.text === result.text) return;
201
+ params.context.set("measurement", {
202
+ ...result,
203
+ key
204
+ });
205
+ }
206
+ /** Expanded state + measurement lifecycle. The resize observer is a Core effect: start on mount, stop on unmount. */
207
+ const ellipsisMachine = createMachine({
208
+ props: ({ props }) => createEllipsisProps({
209
+ ...props,
210
+ content: props.content ?? ""
211
+ }),
212
+ initialState: () => "ready",
213
+ context({ prop, bindable }) {
214
+ return {
215
+ expanded: bindable(() => ({
216
+ defaultValue: prop("defaultExpanded"),
217
+ value: prop("expanded"),
218
+ onChange: (expanded) => prop("onExpandedChange")?.({ expanded })
219
+ })),
220
+ measurement: bindable(() => ({ defaultValue: null }))
221
+ };
222
+ },
223
+ watch({ track, prop, send }) {
224
+ track([
225
+ () => prop("content"),
226
+ () => prop("rows"),
227
+ () => prop("direction"),
228
+ () => prop("symbol"),
229
+ () => prop("expandText")
230
+ ], () => send({ type: "MEASURE" }));
231
+ },
232
+ effects: ["observeLayout"],
233
+ on: {
234
+ TOGGLE: { actions: ["toggle"] },
235
+ "EXPANDED.SET": { actions: ["setExpanded"] },
236
+ MEASURE: { actions: ["measure"] }
237
+ },
238
+ states: { ready: {} },
239
+ implementations: {
240
+ effects: { observeLayout({ scope, send }) {
241
+ const root = scope.getById(rootId(scope));
242
+ if (!root) return;
243
+ return observeEllipsisLayout(root, () => send({ type: "MEASURE" }));
244
+ } },
245
+ actions: {
246
+ toggle({ context, prop }) {
247
+ if (prop("expandText") || context.get("expanded")) context.set("expanded", !context.get("expanded"));
248
+ },
249
+ setExpanded({ context, event }) {
250
+ if (event.type === "EXPANDED.SET") context.set("expanded", event.value);
251
+ },
252
+ measure
253
+ }
254
+ }
255
+ });
256
+ function connectEllipsis(service, normalize) {
257
+ const content = service.prop("content"), expanded = !!service.context.get("expanded");
258
+ const stored = service.context.get("measurement");
259
+ const current = stored && stored.key === measureKey(service) ? stored : null;
260
+ const overflow = !!current?.overflow, truncated = overflow && !expanded;
261
+ const toggleText = expanded ? service.prop("collapseText") : service.prop("expandText");
262
+ const showToggle = overflow && toggleText !== "";
263
+ const part = (name) => ({
264
+ "data-scope": "ellipsis",
265
+ "data-part": name
266
+ });
267
+ const id = rootId(service.scope);
268
+ return {
269
+ content,
270
+ expanded,
271
+ measured: current !== null,
272
+ overflow,
273
+ truncated,
274
+ visibleText: truncated ? current.text : content,
275
+ toggleText,
276
+ showToggle,
277
+ setExpanded: (value) => service.send({
278
+ type: "EXPANDED.SET",
279
+ value
280
+ }),
281
+ remeasure: () => service.send({ type: "MEASURE" }),
282
+ getRootProps: () => normalize.element({
283
+ ...part("root"),
284
+ id,
285
+ "data-direction": service.prop("direction"),
286
+ "data-expanded": dataAttr(expanded),
287
+ "data-measured": dataAttr(current !== null),
288
+ "data-overflow": dataAttr(overflow),
289
+ "data-truncated": dataAttr(truncated),
290
+ style: { "--qw-ellipsis-rows": String(service.prop("rows")) }
291
+ }),
292
+ getContentProps: () => normalize.element({
293
+ ...part("content"),
294
+ id: contentId(service.scope)
295
+ }),
296
+ getTextProps: () => normalize.element({
297
+ ...part("text"),
298
+ "aria-hidden": truncated ? "true" : void 0
299
+ }),
300
+ getFullTextProps: () => normalize.element({
301
+ ...part("full-text"),
302
+ hidden: !truncated,
303
+ style: truncated ? visuallyHiddenStyle : void 0
304
+ }),
305
+ getToggleProps: () => normalize.button({
306
+ ...part("toggle"),
307
+ type: "button",
308
+ hidden: !showToggle,
309
+ "aria-expanded": expanded,
310
+ "aria-controls": contentId(service.scope),
311
+ onClick() {
312
+ service.send({ type: "TOGGLE" });
313
+ }
314
+ })
315
+ };
316
+ }
317
+ //#endregion
318
+ export { ELLIPSIS_DIRECTIONS, ELLIPSIS_PARTS, ELLIPSIS_PROBE_ATTRIBUTE, buildEllipsisCandidate, connectEllipsis, createEllipsisProps, ellipsisMachine, findEllipsisText, measureEllipsisLayout, normalizeEllipsisRows, observeEllipsisLayout };
319
+
320
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/ellipsis/ellipsis-layout.ts","../../src/ellipsis/ellipsis.ts"],"sourcesContent":["import type { EllipsisDirection } from \"./ellipsis.js\";\n\n/**\n * Ellipsis platform boundary: DOM measurement and resize observation only.\n * Truncation search and expanded/collapsed decisions stay in ellipsis.ts.\n * Nothing here runs at module top level, so importing it is SSR-safe.\n */\nexport interface EllipsisMeasureInput {\n content: string;\n rows: number;\n direction: EllipsisDirection;\n symbol: string;\n /** Visible action label measured on the same line as the truncated text (\"\" = none). */\n actionText: string;\n}\nexport interface EllipsisMeasurement {\n /** True when the full content exceeds `rows` lines. */\n overflow: boolean;\n /** Collapsed visible text (with symbol) when overflowing; otherwise the full content. */\n text: string;\n /** Inline size used for the decision, in CSS pixels. */\n width: number;\n}\n\n/** Inherited typography that determines line breaking. */\nconst COPIED_STYLES = [\"font-family\", \"font-size\", \"font-weight\", \"font-style\", \"font-variant\", \"font-stretch\", \"font-feature-settings\", \"letter-spacing\", \"word-spacing\", \"line-height\", \"text-transform\", \"text-indent\", \"word-break\", \"overflow-wrap\", \"line-break\", \"hyphens\", \"tab-size\", \"direction\", \"unicode-bidi\", \"writing-mode\"] as const;\nexport const ELLIPSIS_PROBE_ATTRIBUTE = \"data-qw-ellipsis-probe\";\n\n/** Code-point safe truncation candidates; `kept` counts content code points that remain visible. */\nexport function buildEllipsisCandidate(chars: readonly string[], kept: number, direction: EllipsisDirection, symbol: string): string {\n const count = Math.max(0, Math.min(chars.length, Math.floor(kept)));\n if (direction === \"start\") return symbol + chars.slice(chars.length - count).join(\"\");\n if (direction === \"middle\") {\n const head = Math.ceil(count / 2), tail = count - head;\n return chars.slice(0, head).join(\"\") + symbol + (tail ? chars.slice(chars.length - tail).join(\"\") : \"\");\n }\n return chars.slice(0, count).join(\"\") + symbol;\n}\n\n/**\n * Pure search: longest candidate that `fits`. `fits` must be monotonic (fewer kept characters never fit worse).\n * Returns null when the full content fits.\n */\nexport function findEllipsisText(content: string, direction: EllipsisDirection, symbol: string, fits: (candidate: string) => boolean): string | null {\n if (fits(content)) return null;\n const chars = Array.from(content);\n let low = 0, high = chars.length - 1, best = 0;\n while (low <= high) {\n const mid = (low + high) >> 1;\n if (fits(buildEllipsisCandidate(chars, mid, direction, symbol))) { best = mid; low = mid + 1; } else high = mid - 1;\n }\n return buildEllipsisCandidate(chars, best, direction, symbol);\n}\n\nfunction px(value: string): number { const parsed = Number.parseFloat(value); return Number.isFinite(parsed) ? parsed : 0; }\n\n/** Measures with a detached-from-layout probe in the same document; returns null when not laid out (zero width). */\nexport function measureEllipsisLayout(root: HTMLElement, input: EllipsisMeasureInput): EllipsisMeasurement | null {\n const doc = root.ownerDocument, view = doc.defaultView;\n if (!view || !doc.body || !root.isConnected) return null;\n const style = view.getComputedStyle(root);\n const width = root.getBoundingClientRect().width - px(style.paddingLeft) - px(style.paddingRight) - px(style.borderLeftWidth) - px(style.borderRightWidth);\n if (!(width > 0)) return null;\n const probe = doc.createElement(\"div\");\n probe.setAttribute(ELLIPSIS_PROBE_ATTRIBUTE, \"\");\n probe.setAttribute(\"aria-hidden\", \"true\");\n for (const name of COPIED_STYLES) probe.style.setProperty(name, style.getPropertyValue(name));\n for (const [name, value] of [[\"position\", \"absolute\"], [\"visibility\", \"hidden\"], [\"pointer-events\", \"none\"], [\"inset-block-start\", \"0\"], [\"inset-inline-start\", \"0\"], [\"display\", \"block\"], [\"box-sizing\", \"content-box\"], [\"padding\", \"0\"], [\"border\", \"0\"], [\"margin\", \"0\"], [\"inline-size\", `${width}px`], [\"block-size\", \"auto\"], [\"max-block-size\", \"none\"], [\"overflow\", \"visible\"], [\"white-space\", style.whiteSpace === \"nowrap\" || style.whiteSpace === \"pre\" ? \"pre-wrap\" : style.whiteSpace || \"normal\"], [\"-webkit-line-clamp\", \"none\"]] as const) probe.style.setProperty(name, value);\n probe.style.setProperty(\"width\", `${width}px`);\n doc.body.append(probe);\n try {\n probe.replaceChildren();\n for (let line = 0; line < input.rows; line++) { if (line) probe.append(doc.createElement(\"br\")); probe.append(doc.createTextNode(\"\\u00a0\")); }\n const limit = probe.getBoundingClientRect().height + 0.5;\n const suffix = input.actionText ? `\\u00a0${input.actionText}\\u00a0` : \"\";\n const height = (text: string) => { probe.textContent = text; return probe.getBoundingClientRect().height; };\n if (height(input.content) <= limit) return { overflow: false, text: input.content, width };\n const text = findEllipsisText(input.content, input.direction, input.symbol, (candidate) => height(candidate + suffix) <= limit);\n return { overflow: text !== null, text: text ?? input.content, width };\n } finally {\n probe.remove();\n }\n}\n\n/** Calls `onChange` when the observed inline size changes (and once on start). Returns stop. */\nexport function observeEllipsisLayout(root: HTMLElement, onChange: () => void): () => void {\n const view = root.ownerDocument.defaultView;\n let disposed = false, last = Number.NaN;\n const notify = () => { if (!disposed) onChange(); };\n let observer: ResizeObserver | undefined;\n if (view && typeof view.ResizeObserver === \"function\") {\n observer = new view.ResizeObserver((entries) => {\n const width = entries[entries.length - 1]?.contentRect?.width;\n if (typeof width === \"number\" && width === last) return;\n if (typeof width === \"number\") last = width;\n notify();\n });\n observer.observe(root);\n } else queueMicrotask(notify);\n const fonts = root.ownerDocument.fonts;\n if (fonts?.ready) void fonts.ready.then(notify, () => {});\n return () => { disposed = true; observer?.disconnect(); };\n}\n","import { createMachine, type Machine, type Params, type Service } from \"@zag-js/core\";\nimport { dataAttr, visuallyHiddenStyle } from \"@zag-js/dom-query\";\nimport type { NormalizeProps, PropTypes } from \"@zag-js/types\";\nimport { measureEllipsisLayout, observeEllipsisLayout, type EllipsisMeasurement } from \"./ellipsis-layout.js\";\n\nexport const ELLIPSIS_DIRECTIONS = [\"end\", \"start\", \"middle\"] as const;\nexport const ELLIPSIS_PARTS = [\"root\", \"content\", \"text\", \"full-text\", \"toggle\"] as const;\nexport type EllipsisDirection = (typeof ELLIPSIS_DIRECTIONS)[number];\nexport type EllipsisPart = (typeof ELLIPSIS_PARTS)[number];\nexport interface EllipsisExpandedChangeDetails { expanded: boolean }\n\nexport interface QwEllipsisProps {\n /** Stable instance identity for aria-controls; frameworks generate one when omitted. */\n id?: string;\n /** Plain text content (measurement requires text). */\n content: string;\n /** Visible lines when collapsed; integer ≥ 1, invalid → 1. */\n rows?: number;\n /** Where the ellipsis symbol goes. Default end. */\n direction?: EllipsisDirection;\n /** Controlled expanded state when defined. */\n expanded?: boolean;\n defaultExpanded?: boolean;\n /** Expand action label; \"\" disables expansion. Default 展开. */\n expandText?: string;\n /** Collapse action label; \"\" hides the collapse action. Default 收起. */\n collapseText?: string;\n /** Ellipsis symbol. Default …. */\n symbol?: string;\n onExpandedChange?: (details: EllipsisExpandedChangeDetails) => void;\n}\n\nexport function normalizeEllipsisRows(rows: unknown): number {\n return typeof rows === \"number\" && Number.isFinite(rows) && rows >= 1 ? Math.min(1000, Math.floor(rows)) : 1;\n}\ntype NormalizedProps = QwEllipsisProps & { content: string; rows: number; direction: EllipsisDirection; expandText: string; collapseText: string; symbol: string; defaultExpanded: boolean };\nexport function createEllipsisProps(props: QwEllipsisProps): NormalizedProps {\n if (props.id !== undefined && (typeof props.id !== \"string\" || !props.id.trim())) throw new TypeError(\"Ellipsis requires a nonempty instance id when provided\");\n return {\n ...props,\n content: typeof props.content === \"string\" ? props.content : String(props.content ?? \"\"),\n rows: normalizeEllipsisRows(props.rows),\n direction: ELLIPSIS_DIRECTIONS.includes(props.direction!) ? props.direction! : \"end\",\n expandText: typeof props.expandText === \"string\" ? props.expandText : \"展开\",\n collapseText: typeof props.collapseText === \"string\" ? props.collapseText : \"收起\",\n symbol: typeof props.symbol === \"string\" ? props.symbol : \"…\",\n defaultExpanded: props.defaultExpanded === true,\n expanded: typeof props.expanded === \"boolean\" ? props.expanded : undefined,\n };\n}\ninterface KeyedMeasurement extends EllipsisMeasurement { key: string }\nexport interface QwEllipsisSchema {\n props: NormalizedProps;\n context: { expanded: boolean; measurement: KeyedMeasurement | null };\n state: \"ready\";\n action: \"toggle\" | \"setExpanded\" | \"measure\";\n effect: \"observeLayout\";\n event: { type: \"TOGGLE\" } | { type: \"EXPANDED.SET\"; value: boolean } | { type: \"MEASURE\" };\n}\nexport type QwEllipsisMachine = Machine<QwEllipsisSchema>;\nexport type QwEllipsisService = Service<QwEllipsisSchema>;\ntype EllipsisParams = Pick<Params<QwEllipsisSchema>, \"context\" | \"prop\" | \"scope\">;\n\nfunction hex(id: string) { return id.split(\"\").map((char) => char.charCodeAt(0).toString(16).padStart(4, \"0\")).join(\"\"); }\nconst rootId = (scope: QwEllipsisService[\"scope\"]) => { if (!scope.id?.trim()) throw new TypeError(\"Ellipsis requires a nonempty stable id\"); return `qw-ellipsis-${hex(scope.id)}`; };\nconst contentId = (scope: QwEllipsisService[\"scope\"]) => `${rootId(scope)}-content`;\n/** Measurement identity: a result for other text/options is never shown. */\nconst measureKey = (params: Pick<EllipsisParams, \"prop\">) => JSON.stringify([params.prop(\"content\"), params.prop(\"rows\"), params.prop(\"direction\"), params.prop(\"symbol\"), params.prop(\"expandText\")]);\nfunction measure(params: EllipsisParams) {\n const root = params.scope.getById<HTMLElement>(rootId(params.scope));\n if (!root) return;\n const result = measureEllipsisLayout(root, { content: params.prop(\"content\"), rows: params.prop(\"rows\"), direction: params.prop(\"direction\"), symbol: params.prop(\"symbol\"), actionText: params.prop(\"expandText\") });\n if (!result) return;\n const key = measureKey(params), previous = params.context.get(\"measurement\");\n if (previous && previous.key === key && previous.overflow === result.overflow && previous.text === result.text) return;\n params.context.set(\"measurement\", { ...result, key });\n}\n\n/** Expanded state + measurement lifecycle. The resize observer is a Core effect: start on mount, stop on unmount. */\nexport const ellipsisMachine: QwEllipsisMachine = createMachine<QwEllipsisSchema>({\n props: ({ props }) => createEllipsisProps({ ...props, content: props.content ?? \"\" }),\n initialState: () => \"ready\",\n context({ prop, bindable }) {\n return {\n expanded: bindable(() => ({ defaultValue: prop(\"defaultExpanded\"), value: prop(\"expanded\"), onChange: (expanded) => prop(\"onExpandedChange\")?.({ expanded }) })),\n measurement: bindable<KeyedMeasurement | null>(() => ({ defaultValue: null })),\n };\n },\n watch({ track, prop, send }) {\n track([() => prop(\"content\"), () => prop(\"rows\"), () => prop(\"direction\"), () => prop(\"symbol\"), () => prop(\"expandText\")], () => send({ type: \"MEASURE\" }));\n },\n effects: [\"observeLayout\"],\n on: { TOGGLE: { actions: [\"toggle\"] }, \"EXPANDED.SET\": { actions: [\"setExpanded\"] }, MEASURE: { actions: [\"measure\"] } },\n states: { ready: {} },\n implementations: {\n effects: {\n observeLayout({ scope, send }) {\n const root = scope.getById<HTMLElement>(rootId(scope));\n if (!root) return;\n return observeEllipsisLayout(root, () => send({ type: \"MEASURE\" }));\n },\n },\n actions: {\n toggle({ context, prop }) { if (prop(\"expandText\") || context.get(\"expanded\")) context.set(\"expanded\", !context.get(\"expanded\")); },\n setExpanded({ context, event }) { if (event.type === \"EXPANDED.SET\") context.set(\"expanded\", event.value); },\n measure,\n },\n },\n});\n\nexport interface QwEllipsisApi<T extends PropTypes = PropTypes> {\n content: string;\n expanded: boolean;\n /** A current measurement exists for these props. */\n measured: boolean;\n overflow: boolean;\n /** Visible text is shortened; full text is provided to assistive technology separately. */\n truncated: boolean;\n visibleText: string;\n toggleText: string;\n showToggle: boolean;\n setExpanded(expanded: boolean): void;\n /** Re-run measurement (for example after a caller-driven style change). */\n remeasure(): void;\n getRootProps(): T[\"element\"];\n getContentProps(): T[\"element\"];\n getTextProps(): T[\"element\"];\n getFullTextProps(): T[\"element\"];\n getToggleProps(): T[\"button\"];\n}\n\nexport function connectEllipsis<T extends PropTypes>(service: QwEllipsisService, normalize: NormalizeProps<T>): QwEllipsisApi<T> {\n const content = service.prop(\"content\"), expanded = !!service.context.get(\"expanded\");\n const stored = service.context.get(\"measurement\");\n const current = stored && stored.key === measureKey(service) ? stored : null;\n const overflow = !!current?.overflow, truncated = overflow && !expanded;\n const toggleText = expanded ? service.prop(\"collapseText\") : service.prop(\"expandText\");\n const showToggle = overflow && toggleText !== \"\";\n const part = (name: EllipsisPart) => ({ \"data-scope\": \"ellipsis\", \"data-part\": name });\n const id = rootId(service.scope);\n return {\n content, expanded, measured: current !== null, overflow, truncated,\n visibleText: truncated ? current!.text : content, toggleText, showToggle,\n setExpanded: (value) => service.send({ type: \"EXPANDED.SET\", value }),\n remeasure: () => service.send({ type: \"MEASURE\" }),\n getRootProps: () => normalize.element({ ...part(\"root\"), id, \"data-direction\": service.prop(\"direction\"), \"data-expanded\": dataAttr(expanded), \"data-measured\": dataAttr(current !== null), \"data-overflow\": dataAttr(overflow), \"data-truncated\": dataAttr(truncated), style: { \"--qw-ellipsis-rows\": String(service.prop(\"rows\")) } }),\n getContentProps: () => normalize.element({ ...part(\"content\"), id: contentId(service.scope) }),\n getTextProps: () => normalize.element({ ...part(\"text\"), \"aria-hidden\": truncated ? \"true\" : undefined }),\n getFullTextProps: () => normalize.element({ ...part(\"full-text\"), hidden: !truncated, style: truncated ? visuallyHiddenStyle : undefined }),\n getToggleProps: () => normalize.button({ ...part(\"toggle\"), type: \"button\", hidden: !showToggle, \"aria-expanded\": expanded, \"aria-controls\": contentId(service.scope),\n onClick() { service.send({ type: \"TOGGLE\" }); } }),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Original 015-empty decorative SVG asset; retained gradient colors are asset data, not component chrome. */
2
+ import type { EmptyVectorNode } from "./empty.js";
3
+ export declare const EMPTY_ILLUSTRATION_ASSET: EmptyVectorNode;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Empty 契约 — 原型 A(无状态),core 无 machine 也无共享枚举。
2
+ * Empty 契约 — 原型 A(无状态),Core 为三栈结构与原有插画的唯一来源。
3
3
  * 本目录是 Empty 的"源头锚点":契约文档与 demo 清单在 ./docs/ 下维护,
4
4
  * 双栈实现(React props / Vue props+slots)必须与 docs 清单严格对齐。
5
5
  * 渲染契约:`data-scope="empty"`,data-part 为 root / icon / title / description / actions。
@@ -10,3 +10,45 @@
10
10
  export declare const EMPTY_PARTS: readonly ["root", "icon", "title", "description", "actions"];
11
11
  /** Empty 各渲染部位(data-part 取值)。 */
12
12
  export type EmptyPart = (typeof EMPTY_PARTS)[number];
13
+ /** Scalar Empty inputs; framework-rich values use content presence. */
14
+ export interface QwEmptyProps {
15
+ title?: string | null;
16
+ description?: string | null;
17
+ hideIcon?: boolean;
18
+ }
19
+ /** Content presence distinguishes omitted from explicitly empty SSR channels. */
20
+ export interface EmptyContentPresence {
21
+ readonly icon?: boolean;
22
+ readonly title?: boolean;
23
+ readonly description?: boolean;
24
+ readonly default?: boolean;
25
+ }
26
+ /** Shared passive structure decisions; no generated role or live region. */
27
+ export interface EmptyState {
28
+ readonly iconMode: "default" | "custom" | "hidden";
29
+ readonly hasTitle: boolean;
30
+ readonly hasDescription: boolean;
31
+ readonly hasActions: boolean;
32
+ readonly titleFromContent: boolean;
33
+ readonly descriptionFromContent: boolean;
34
+ }
35
+ /** Resolve structure once, with explicit channel presence overriding scalars. */
36
+ export declare function resolveEmptyState(props?: QwEmptyProps, presence?: EmptyContentPresence): EmptyState;
37
+ /** Plain passive Empty root. */
38
+ export declare function getEmptyRootProps(): {
39
+ "data-scope": "empty";
40
+ "data-part": "actions" | "description" | "icon" | "root" | "title";
41
+ };
42
+ /** Shared stable selectors for Empty structure. */
43
+ export declare function getEmptyPartProps(part: EmptyPart): {
44
+ "data-scope": "empty";
45
+ "data-part": "actions" | "description" | "icon" | "root" | "title";
46
+ };
47
+ /** Framework-independent retained original vector asset. */
48
+ export interface EmptyVectorNode {
49
+ readonly tag: string;
50
+ readonly attrs: Readonly<Record<string, string>>;
51
+ readonly children: readonly EmptyVectorNode[];
52
+ }
53
+ /** Copy the original illustration with injectively scoped local SVG references. */
54
+ export declare function getEmptyIllustration(identity: string): EmptyVectorNode;