@hypoth-ui/cli 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -115
  3. package/dist/{add-PDBC4JTE.js → add-V5PW73GC.js} +29 -17
  4. package/dist/{chunk-5LTQ2XVL.js → chunk-27CLUUVC.js} +0 -2
  5. package/dist/{chunk-YPKFYE45.js → chunk-NWIRSZUQ.js} +6 -13
  6. package/dist/{chunk-GJ6JOQ3Q.js → chunk-PBK72SJJ.js} +1 -1
  7. package/dist/{diff-BQEXG7HU.js → diff-776UATCA.js} +2 -2
  8. package/dist/index.js +5 -5
  9. package/dist/{init-7AZXYAPJ.js → init-GDU2PW7K.js} +10 -13
  10. package/dist/{list-X6ZLM2NQ.js → list-XDP5I537.js} +3 -3
  11. package/package.json +16 -12
  12. package/registry/components.json +1820 -206
  13. package/templates/accordion/index.tsx +266 -0
  14. package/templates/accordion/wc/accordion-content.ts +113 -0
  15. package/templates/accordion/wc/accordion-item.ts +111 -0
  16. package/templates/accordion/wc/accordion-trigger.ts +105 -0
  17. package/templates/accordion/wc/accordion.ts +213 -0
  18. package/templates/accordion/wc/index.ts +12 -0
  19. package/templates/alert/index.tsx +177 -0
  20. package/templates/alert/wc/alert.ts +167 -0
  21. package/templates/alert/wc/index.ts +1 -0
  22. package/templates/alert-dialog/index.tsx +360 -0
  23. package/templates/alert-dialog/wc/alert-dialog-action.ts +43 -0
  24. package/templates/alert-dialog/wc/alert-dialog-cancel.ts +43 -0
  25. package/templates/alert-dialog/wc/alert-dialog-content.ts +42 -0
  26. package/templates/alert-dialog/wc/alert-dialog-description.ts +34 -0
  27. package/templates/alert-dialog/wc/alert-dialog-footer.ts +25 -0
  28. package/templates/alert-dialog/wc/alert-dialog-header.ts +25 -0
  29. package/templates/alert-dialog/wc/alert-dialog-title.ts +34 -0
  30. package/templates/alert-dialog/wc/alert-dialog-trigger.ts +46 -0
  31. package/templates/alert-dialog/wc/alert-dialog.ts +302 -0
  32. package/templates/alert-dialog/wc/index.ts +13 -0
  33. package/templates/aspect-ratio/index.tsx +50 -0
  34. package/templates/aspect-ratio/wc/aspect-ratio.ts +78 -0
  35. package/templates/aspect-ratio/wc/index.ts +5 -0
  36. package/templates/avatar/avatar-group.tsx +88 -0
  37. package/templates/avatar/avatar.tsx +124 -0
  38. package/templates/avatar/index.tsx +33 -0
  39. package/templates/avatar/wc/avatar-group.ts +112 -0
  40. package/templates/avatar/wc/avatar.ts +184 -0
  41. package/templates/avatar/wc/index.ts +5 -0
  42. package/templates/badge/index.tsx +140 -0
  43. package/templates/badge/wc/badge.ts +119 -0
  44. package/templates/badge/wc/index.ts +9 -0
  45. package/templates/breadcrumb/index.tsx +157 -0
  46. package/templates/breadcrumb/wc/breadcrumb-item.ts +30 -0
  47. package/templates/breadcrumb/wc/breadcrumb-link.ts +70 -0
  48. package/templates/breadcrumb/wc/breadcrumb-list.ts +30 -0
  49. package/templates/breadcrumb/wc/breadcrumb-page.ts +32 -0
  50. package/templates/breadcrumb/wc/breadcrumb-separator.ts +31 -0
  51. package/templates/breadcrumb/wc/breadcrumb.ts +55 -0
  52. package/templates/breadcrumb/wc/index.ts +10 -0
  53. package/templates/button/button.tsx +119 -0
  54. package/templates/button/index.ts +1 -0
  55. package/templates/button/wc/button.ts +169 -0
  56. package/templates/calendar/index.tsx +149 -0
  57. package/templates/calendar/wc/calendar.ts +316 -0
  58. package/templates/calendar/wc/index.ts +4 -0
  59. package/templates/card/index.tsx +108 -0
  60. package/templates/card/wc/card-content.ts +25 -0
  61. package/templates/card/wc/card-footer.ts +25 -0
  62. package/templates/card/wc/card-header.ts +25 -0
  63. package/templates/card/wc/card.ts +43 -0
  64. package/templates/card/wc/index.ts +8 -0
  65. package/templates/checkbox/checkbox.tsx +85 -0
  66. package/templates/checkbox/wc/checkbox.ts +247 -0
  67. package/templates/collapsible/index.tsx +172 -0
  68. package/templates/collapsible/wc/collapsible-content.ts +97 -0
  69. package/templates/collapsible/wc/collapsible-trigger.ts +39 -0
  70. package/templates/collapsible/wc/collapsible.ts +143 -0
  71. package/templates/collapsible/wc/index.ts +7 -0
  72. package/templates/combobox/combobox-content.tsx +141 -0
  73. package/templates/combobox/combobox-context.ts +36 -0
  74. package/templates/combobox/combobox-empty.tsx +38 -0
  75. package/templates/combobox/combobox-input.tsx +159 -0
  76. package/templates/combobox/combobox-loading.tsx +38 -0
  77. package/templates/combobox/combobox-option.tsx +99 -0
  78. package/templates/combobox/combobox-root.tsx +207 -0
  79. package/templates/combobox/combobox-tag.tsx +62 -0
  80. package/templates/combobox/index.ts +62 -0
  81. package/templates/combobox/wc/combobox-content.ts +97 -0
  82. package/templates/combobox/wc/combobox-input.ts +134 -0
  83. package/templates/combobox/wc/combobox-option.ts +111 -0
  84. package/templates/combobox/wc/combobox-tag.ts +103 -0
  85. package/templates/combobox/wc/combobox.ts +981 -0
  86. package/templates/combobox/wc/index.ts +5 -0
  87. package/templates/command/index.tsx +279 -0
  88. package/templates/command/wc/command-empty.ts +24 -0
  89. package/templates/command/wc/command-group.ts +60 -0
  90. package/templates/command/wc/command-input.ts +136 -0
  91. package/templates/command/wc/command-item.ts +78 -0
  92. package/templates/command/wc/command-list.ts +103 -0
  93. package/templates/command/wc/command-loading.ts +24 -0
  94. package/templates/command/wc/command-separator.ts +23 -0
  95. package/templates/command/wc/command.ts +176 -0
  96. package/templates/context-menu/index.tsx +262 -0
  97. package/templates/context-menu/wc/context-menu-content.ts +41 -0
  98. package/templates/context-menu/wc/context-menu-item.ts +83 -0
  99. package/templates/context-menu/wc/context-menu-label.ts +30 -0
  100. package/templates/context-menu/wc/context-menu-separator.ts +28 -0
  101. package/templates/context-menu/wc/context-menu.ts +324 -0
  102. package/templates/context-menu/wc/index.ts +9 -0
  103. package/templates/data-table/index.tsx +263 -0
  104. package/templates/data-table/wc/data-table.ts +405 -0
  105. package/templates/data-table/wc/index.ts +10 -0
  106. package/templates/date-picker/date-picker-calendar.tsx +352 -0
  107. package/templates/date-picker/date-picker-content.tsx +121 -0
  108. package/templates/date-picker/date-picker-context.ts +46 -0
  109. package/templates/date-picker/date-picker-root.tsx +201 -0
  110. package/templates/date-picker/date-picker-trigger.tsx +95 -0
  111. package/templates/date-picker/index.ts +44 -0
  112. package/templates/date-picker/wc/date-picker-calendar.ts +457 -0
  113. package/templates/date-picker/wc/date-picker.ts +592 -0
  114. package/templates/date-picker/wc/date-utils.ts +467 -0
  115. package/templates/date-picker/wc/index.ts +3 -0
  116. package/templates/dialog/dialog-close.tsx +57 -0
  117. package/templates/dialog/dialog-content.tsx +106 -0
  118. package/templates/dialog/dialog-context.ts +24 -0
  119. package/templates/dialog/dialog-description.tsx +51 -0
  120. package/templates/dialog/dialog-root.tsx +104 -0
  121. package/templates/dialog/dialog-title.tsx +38 -0
  122. package/templates/dialog/dialog-trigger.tsx +94 -0
  123. package/templates/dialog/index.ts +52 -0
  124. package/templates/dialog/wc/dialog-content.ts +59 -0
  125. package/templates/dialog/wc/dialog-description.ts +58 -0
  126. package/templates/dialog/wc/dialog-title.ts +56 -0
  127. package/templates/dialog/wc/dialog.ts +411 -0
  128. package/templates/drawer/index.tsx +263 -0
  129. package/templates/drawer/wc/drawer-content.ts +150 -0
  130. package/templates/drawer/wc/drawer-description.ts +34 -0
  131. package/templates/drawer/wc/drawer-footer.ts +25 -0
  132. package/templates/drawer/wc/drawer-header.ts +25 -0
  133. package/templates/drawer/wc/drawer-title.ts +34 -0
  134. package/templates/drawer/wc/drawer.ts +348 -0
  135. package/templates/drawer/wc/index.ts +10 -0
  136. package/templates/dropdown-menu/index.tsx +454 -0
  137. package/templates/dropdown-menu/wc/dropdown-menu-checkbox-item.ts +93 -0
  138. package/templates/dropdown-menu/wc/dropdown-menu-content.ts +43 -0
  139. package/templates/dropdown-menu/wc/dropdown-menu-item.ts +85 -0
  140. package/templates/dropdown-menu/wc/dropdown-menu-label.ts +31 -0
  141. package/templates/dropdown-menu/wc/dropdown-menu-radio-group.ts +80 -0
  142. package/templates/dropdown-menu/wc/dropdown-menu-radio-item.ts +101 -0
  143. package/templates/dropdown-menu/wc/dropdown-menu-separator.ts +28 -0
  144. package/templates/dropdown-menu/wc/dropdown-menu.ts +358 -0
  145. package/templates/dropdown-menu/wc/index.ts +12 -0
  146. package/templates/field/field-description.tsx +39 -0
  147. package/templates/field/field-error.tsx +37 -0
  148. package/templates/field/field.tsx +46 -0
  149. package/templates/field/index.ts +4 -0
  150. package/templates/field/label.tsx +40 -0
  151. package/templates/field/wc/field-description.ts +42 -0
  152. package/templates/field/wc/field-error.ts +46 -0
  153. package/templates/field/wc/field.ts +210 -0
  154. package/templates/field/wc/label.ts +54 -0
  155. package/templates/file-upload/file-upload-context.ts +26 -0
  156. package/templates/file-upload/file-upload-dropzone.tsx +111 -0
  157. package/templates/file-upload/file-upload-input.tsx +86 -0
  158. package/templates/file-upload/file-upload-item.tsx +105 -0
  159. package/templates/file-upload/file-upload-root.tsx +115 -0
  160. package/templates/file-upload/index.ts +50 -0
  161. package/templates/file-upload/wc/file-upload.ts +380 -0
  162. package/templates/file-upload/wc/index.ts +1 -0
  163. package/templates/hover-card/index.tsx +203 -0
  164. package/templates/hover-card/wc/hover-card-content.ts +50 -0
  165. package/templates/hover-card/wc/hover-card.ts +382 -0
  166. package/templates/hover-card/wc/index.ts +6 -0
  167. package/templates/icon/icon.tsx +76 -0
  168. package/templates/icon/wc/icon-adapter.ts +108 -0
  169. package/templates/icon/wc/icon.ts +161 -0
  170. package/templates/input/input.tsx +130 -0
  171. package/templates/input/wc/input.ts +216 -0
  172. package/templates/layout/app-shell.tsx +177 -0
  173. package/templates/layout/box.tsx +53 -0
  174. package/templates/layout/center.tsx +42 -0
  175. package/templates/layout/container.tsx +43 -0
  176. package/templates/layout/flow.tsx +83 -0
  177. package/templates/layout/grid.tsx +79 -0
  178. package/templates/layout/index.ts +33 -0
  179. package/templates/layout/inline.tsx +16 -0
  180. package/templates/layout/page.tsx +43 -0
  181. package/templates/layout/section.tsx +39 -0
  182. package/templates/layout/spacer.tsx +30 -0
  183. package/templates/layout/split.tsx +47 -0
  184. package/templates/layout/stack.tsx +16 -0
  185. package/templates/layout/wc/app-shell.ts +58 -0
  186. package/templates/layout/wc/box.ts +117 -0
  187. package/templates/layout/wc/center.ts +78 -0
  188. package/templates/layout/wc/container.ts +77 -0
  189. package/templates/layout/wc/flow.ts +149 -0
  190. package/templates/layout/wc/footer.ts +57 -0
  191. package/templates/layout/wc/grid.ts +142 -0
  192. package/templates/layout/wc/header.ts +57 -0
  193. package/templates/layout/wc/index.ts +41 -0
  194. package/templates/layout/wc/main.ts +46 -0
  195. package/templates/layout/wc/page.ts +81 -0
  196. package/templates/layout/wc/section.ts +65 -0
  197. package/templates/layout/wc/spacer.ts +77 -0
  198. package/templates/layout/wc/split.ts +94 -0
  199. package/templates/layout/wc/wrap.ts +93 -0
  200. package/templates/layout/wrap.tsx +46 -0
  201. package/templates/link/link.tsx +109 -0
  202. package/templates/link/wc/link.ts +124 -0
  203. package/templates/list/index.tsx +55 -0
  204. package/templates/list/list-item.tsx +117 -0
  205. package/templates/list/list.tsx +115 -0
  206. package/templates/list/wc/index.ts +5 -0
  207. package/templates/list/wc/list-item.ts +127 -0
  208. package/templates/list/wc/list.ts +114 -0
  209. package/templates/menu/index.ts +49 -0
  210. package/templates/menu/menu-content.tsx +109 -0
  211. package/templates/menu/menu-context.ts +17 -0
  212. package/templates/menu/menu-item.tsx +108 -0
  213. package/templates/menu/menu-label.tsx +32 -0
  214. package/templates/menu/menu-root.tsx +108 -0
  215. package/templates/menu/menu-separator.tsx +24 -0
  216. package/templates/menu/menu-trigger.tsx +104 -0
  217. package/templates/menu/wc/menu-content.ts +67 -0
  218. package/templates/menu/wc/menu-item.ts +109 -0
  219. package/templates/menu/wc/menu.ts +449 -0
  220. package/templates/navigation-menu/index.tsx +328 -0
  221. package/templates/navigation-menu/wc/index.ts +12 -0
  222. package/templates/navigation-menu/wc/navigation-menu-content.ts +30 -0
  223. package/templates/navigation-menu/wc/navigation-menu-indicator.ts +30 -0
  224. package/templates/navigation-menu/wc/navigation-menu-item.ts +60 -0
  225. package/templates/navigation-menu/wc/navigation-menu-link.ts +97 -0
  226. package/templates/navigation-menu/wc/navigation-menu-list.ts +30 -0
  227. package/templates/navigation-menu/wc/navigation-menu-trigger.ts +110 -0
  228. package/templates/navigation-menu/wc/navigation-menu-viewport.ts +85 -0
  229. package/templates/navigation-menu/wc/navigation-menu.ts +272 -0
  230. package/templates/number-input/index.ts +46 -0
  231. package/templates/number-input/number-input-context.ts +38 -0
  232. package/templates/number-input/number-input-decrement.tsx +53 -0
  233. package/templates/number-input/number-input-field.tsx +93 -0
  234. package/templates/number-input/number-input-increment.tsx +53 -0
  235. package/templates/number-input/number-input-root.tsx +137 -0
  236. package/templates/number-input/wc/index.ts +1 -0
  237. package/templates/number-input/wc/number-input.ts +283 -0
  238. package/templates/pagination/index.tsx +198 -0
  239. package/templates/pagination/wc/index.ts +11 -0
  240. package/templates/pagination/wc/pagination-content.ts +30 -0
  241. package/templates/pagination/wc/pagination-ellipsis.ts +28 -0
  242. package/templates/pagination/wc/pagination-item.ts +30 -0
  243. package/templates/pagination/wc/pagination-link.ts +76 -0
  244. package/templates/pagination/wc/pagination-next.ts +69 -0
  245. package/templates/pagination/wc/pagination-previous.ts +69 -0
  246. package/templates/pagination/wc/pagination.ts +156 -0
  247. package/templates/pin-input/index.ts +39 -0
  248. package/templates/pin-input/pin-input-context.ts +30 -0
  249. package/templates/pin-input/pin-input-field.tsx +186 -0
  250. package/templates/pin-input/pin-input-root.tsx +120 -0
  251. package/templates/pin-input/wc/index.ts +1 -0
  252. package/templates/pin-input/wc/pin-input.ts +259 -0
  253. package/templates/popover/popover.tsx +121 -0
  254. package/templates/popover/wc/popover-content.ts +66 -0
  255. package/templates/popover/wc/popover.ts +343 -0
  256. package/templates/progress/index.tsx +117 -0
  257. package/templates/progress/wc/index.ts +4 -0
  258. package/templates/progress/wc/progress.ts +174 -0
  259. package/templates/radio/radio.tsx +43 -0
  260. package/templates/radio/wc/radio-group.ts +261 -0
  261. package/templates/radio/wc/radio.ts +145 -0
  262. package/templates/scroll-area/index.tsx +144 -0
  263. package/templates/scroll-area/wc/index.ts +8 -0
  264. package/templates/scroll-area/wc/scroll-area-scrollbar.ts +143 -0
  265. package/templates/scroll-area/wc/scroll-area-thumb.ts +225 -0
  266. package/templates/scroll-area/wc/scroll-area-viewport.ts +120 -0
  267. package/templates/scroll-area/wc/scroll-area.ts +63 -0
  268. package/templates/select/index.ts +57 -0
  269. package/templates/select/select-content.tsx +243 -0
  270. package/templates/select/select-context.ts +30 -0
  271. package/templates/select/select-group.tsx +53 -0
  272. package/templates/select/select-label.tsx +34 -0
  273. package/templates/select/select-option.tsx +97 -0
  274. package/templates/select/select-root.tsx +153 -0
  275. package/templates/select/select-separator.tsx +27 -0
  276. package/templates/select/select-trigger.tsx +112 -0
  277. package/templates/select/select-value.tsx +48 -0
  278. package/templates/select/wc/index.ts +6 -0
  279. package/templates/select/wc/select-content.ts +89 -0
  280. package/templates/select/wc/select-group.ts +82 -0
  281. package/templates/select/wc/select-label.ts +49 -0
  282. package/templates/select/wc/select-option.ts +111 -0
  283. package/templates/select/wc/select-trigger.ts +101 -0
  284. package/templates/select/wc/select.ts +840 -0
  285. package/templates/separator/index.tsx +49 -0
  286. package/templates/separator/wc/index.ts +5 -0
  287. package/templates/separator/wc/separator.ts +60 -0
  288. package/templates/sheet/index.tsx +291 -0
  289. package/templates/sheet/wc/index.ts +12 -0
  290. package/templates/sheet/wc/sheet-close.ts +43 -0
  291. package/templates/sheet/wc/sheet-content.ts +47 -0
  292. package/templates/sheet/wc/sheet-description.ts +34 -0
  293. package/templates/sheet/wc/sheet-footer.ts +25 -0
  294. package/templates/sheet/wc/sheet-header.ts +25 -0
  295. package/templates/sheet/wc/sheet-overlay.ts +23 -0
  296. package/templates/sheet/wc/sheet-title.ts +34 -0
  297. package/templates/sheet/wc/sheet.ts +336 -0
  298. package/templates/skeleton/index.tsx +131 -0
  299. package/templates/skeleton/wc/index.ts +10 -0
  300. package/templates/skeleton/wc/skeleton.ts +107 -0
  301. package/templates/slider/index.ts +41 -0
  302. package/templates/slider/slider-context.ts +36 -0
  303. package/templates/slider/slider-range.tsx +59 -0
  304. package/templates/slider/slider-root.tsx +166 -0
  305. package/templates/slider/slider-thumb.tsx +213 -0
  306. package/templates/slider/slider-track.tsx +113 -0
  307. package/templates/slider/wc/index.ts +1 -0
  308. package/templates/slider/wc/slider.ts +465 -0
  309. package/templates/spinner/spinner.tsx +64 -0
  310. package/templates/spinner/wc/spinner.ts +70 -0
  311. package/templates/stepper/index.tsx +230 -0
  312. package/templates/stepper/wc/index.ts +12 -0
  313. package/templates/stepper/wc/stepper-content.ts +30 -0
  314. package/templates/stepper/wc/stepper-description.ts +25 -0
  315. package/templates/stepper/wc/stepper-indicator.ts +30 -0
  316. package/templates/stepper/wc/stepper-item.ts +55 -0
  317. package/templates/stepper/wc/stepper-separator.ts +29 -0
  318. package/templates/stepper/wc/stepper-title.ts +25 -0
  319. package/templates/stepper/wc/stepper-trigger.ts +67 -0
  320. package/templates/stepper/wc/stepper.ts +164 -0
  321. package/templates/switch/switch.tsx +90 -0
  322. package/templates/switch/wc/switch.ts +228 -0
  323. package/templates/table/body.tsx +21 -0
  324. package/templates/table/cell.tsx +44 -0
  325. package/templates/table/head.tsx +112 -0
  326. package/templates/table/header.tsx +21 -0
  327. package/templates/table/index.tsx +93 -0
  328. package/templates/table/root.tsx +82 -0
  329. package/templates/table/row.tsx +36 -0
  330. package/templates/table/wc/index.ts +9 -0
  331. package/templates/table/wc/table-body.ts +32 -0
  332. package/templates/table/wc/table-cell.ts +58 -0
  333. package/templates/table/wc/table-head.ts +129 -0
  334. package/templates/table/wc/table-header.ts +32 -0
  335. package/templates/table/wc/table-row.ts +50 -0
  336. package/templates/table/wc/table.ts +93 -0
  337. package/templates/tabs/index.tsx +222 -0
  338. package/templates/tabs/wc/index.ts +8 -0
  339. package/templates/tabs/wc/tabs-content.ts +82 -0
  340. package/templates/tabs/wc/tabs-list.ts +56 -0
  341. package/templates/tabs/wc/tabs-trigger.ts +136 -0
  342. package/templates/tabs/wc/tabs.ts +202 -0
  343. package/templates/tag/index.tsx +186 -0
  344. package/templates/tag/wc/index.ts +4 -0
  345. package/templates/tag/wc/tag.ts +166 -0
  346. package/templates/text/text.tsx +100 -0
  347. package/templates/text/wc/text.ts +94 -0
  348. package/templates/textarea/textarea.tsx +134 -0
  349. package/templates/textarea/wc/textarea.ts +280 -0
  350. package/templates/time-picker/index.ts +42 -0
  351. package/templates/time-picker/time-picker-context.ts +28 -0
  352. package/templates/time-picker/time-picker-root.tsx +113 -0
  353. package/templates/time-picker/time-picker-segment.tsx +91 -0
  354. package/templates/time-picker/wc/index.ts +1 -0
  355. package/templates/time-picker/wc/time-picker.ts +221 -0
  356. package/templates/toast/index.tsx +71 -0
  357. package/templates/toast/provider.tsx +228 -0
  358. package/templates/toast/toast.tsx +142 -0
  359. package/templates/toast/use-toast.ts +89 -0
  360. package/templates/toast/wc/index.ts +15 -0
  361. package/templates/toast/wc/toast-controller.ts +282 -0
  362. package/templates/toast/wc/toast-provider.ts +161 -0
  363. package/templates/toast/wc/toast.ts +165 -0
  364. package/templates/tooltip/tooltip.tsx +62 -0
  365. package/templates/tooltip/wc/tooltip-content.ts +64 -0
  366. package/templates/tooltip/wc/tooltip.ts +289 -0
  367. package/templates/tree/index.tsx +60 -0
  368. package/templates/tree/tree-item.tsx +131 -0
  369. package/templates/tree/tree.tsx +138 -0
  370. package/templates/tree/wc/index.ts +11 -0
  371. package/templates/tree/wc/tree-item.ts +273 -0
  372. package/templates/tree/wc/tree-utils.ts +143 -0
  373. package/templates/tree/wc/tree.ts +139 -0
  374. package/templates/visually-hidden/visually-hidden.tsx +45 -0
  375. package/templates/visually-hidden/wc/visually-hidden.ts +64 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * DropdownMenu compound component exports.
3
+ *
4
+ * DropdownMenu is used for action menus triggered by a button, with support
5
+ * for items, separators, labels, checkbox items, and radio groups.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { DropdownMenu } from "@/components/ui";
10
+ *
11
+ * <DropdownMenu.Root>
12
+ * <DropdownMenu.Trigger>
13
+ * <button>Actions</button>
14
+ * </DropdownMenu.Trigger>
15
+ * <DropdownMenu.Content>
16
+ * <DropdownMenu.Label>Actions</DropdownMenu.Label>
17
+ * <DropdownMenu.Item value="edit">Edit</DropdownMenu.Item>
18
+ * <DropdownMenu.Separator />
19
+ * <DropdownMenu.Item value="delete" variant="destructive">Delete</DropdownMenu.Item>
20
+ * </DropdownMenu.Content>
21
+ * </DropdownMenu.Root>
22
+ * ```
23
+ */
24
+
25
+ import {
26
+ type HTMLAttributes,
27
+ type ReactNode,
28
+ createElement,
29
+ forwardRef,
30
+ useCallback,
31
+ useEffect,
32
+ useRef,
33
+ useState,
34
+ } from "react";
35
+
36
+ // ============================================================================
37
+ // Types
38
+ // ============================================================================
39
+
40
+ export type DropdownMenuPlacement =
41
+ | "top"
42
+ | "top-start"
43
+ | "top-end"
44
+ | "bottom"
45
+ | "bottom-start"
46
+ | "bottom-end"
47
+ | "left"
48
+ | "left-start"
49
+ | "left-end"
50
+ | "right"
51
+ | "right-start"
52
+ | "right-end";
53
+
54
+ export type DropdownMenuItemVariant = "default" | "destructive";
55
+
56
+ export interface DropdownMenuRootProps extends HTMLAttributes<HTMLElement> {
57
+ /** Content */
58
+ children?: ReactNode;
59
+ /** Controlled open state */
60
+ open?: boolean;
61
+ /** Default open state (uncontrolled) */
62
+ defaultOpen?: boolean;
63
+ /** Called when open state changes */
64
+ onOpenChange?: (open: boolean) => void;
65
+ /** Placement relative to trigger */
66
+ placement?: DropdownMenuPlacement;
67
+ /** Offset distance from trigger in pixels */
68
+ offset?: number;
69
+ /** Whether to flip placement when near viewport edge */
70
+ flip?: boolean;
71
+ /** Whether to animate open/close transitions */
72
+ animated?: boolean;
73
+ /** Modal behavior - blocks interaction outside menu */
74
+ modal?: boolean;
75
+ }
76
+
77
+ export interface DropdownMenuTriggerProps extends HTMLAttributes<HTMLElement> {
78
+ /** Trigger content (typically a button) */
79
+ children?: ReactNode;
80
+ }
81
+
82
+ export interface DropdownMenuContentProps extends HTMLAttributes<HTMLElement> {
83
+ /** Content */
84
+ children?: ReactNode;
85
+ }
86
+
87
+ export interface DropdownMenuItemProps extends Omit<HTMLAttributes<HTMLElement>, "onSelect"> {
88
+ /** Item content */
89
+ children?: ReactNode;
90
+ /** Value for selection events */
91
+ value?: string;
92
+ /** Visual variant */
93
+ variant?: DropdownMenuItemVariant;
94
+ /** Disabled state */
95
+ disabled?: boolean;
96
+ /** Called when item is selected */
97
+ onSelect?: (value: string) => void;
98
+ }
99
+
100
+ export interface DropdownMenuSeparatorProps extends HTMLAttributes<HTMLElement> {}
101
+
102
+ export interface DropdownMenuLabelProps extends HTMLAttributes<HTMLElement> {
103
+ /** Label content */
104
+ children?: ReactNode;
105
+ }
106
+
107
+ export interface DropdownMenuCheckboxItemProps extends HTMLAttributes<HTMLElement> {
108
+ /** Item content */
109
+ children?: ReactNode;
110
+ /** Whether the checkbox is checked */
111
+ checked?: boolean;
112
+ /** Called when checkbox state changes */
113
+ onCheckedChange?: (checked: boolean) => void;
114
+ /** Disabled state */
115
+ disabled?: boolean;
116
+ }
117
+
118
+ export interface DropdownMenuRadioGroupProps extends HTMLAttributes<HTMLElement> {
119
+ /** Radio items */
120
+ children?: ReactNode;
121
+ /** Currently selected value */
122
+ value?: string;
123
+ /** Called when selection changes */
124
+ onValueChange?: (value: string) => void;
125
+ }
126
+
127
+ export interface DropdownMenuRadioItemProps extends HTMLAttributes<HTMLElement> {
128
+ /** Item content */
129
+ children?: ReactNode;
130
+ /** Value for this radio item */
131
+ value: string;
132
+ /** Disabled state */
133
+ disabled?: boolean;
134
+ }
135
+
136
+ // ============================================================================
137
+ // Components
138
+ // ============================================================================
139
+
140
+ /**
141
+ * DropdownMenu root component.
142
+ */
143
+ const DropdownMenuRoot = forwardRef<HTMLElement, DropdownMenuRootProps>(function DropdownMenuRoot(
144
+ {
145
+ children,
146
+ className,
147
+ open: controlledOpen,
148
+ defaultOpen = false,
149
+ onOpenChange,
150
+ placement = "bottom-start",
151
+ offset = 4,
152
+ flip = true,
153
+ animated = true,
154
+ modal = true,
155
+ ...props
156
+ },
157
+ ref
158
+ ) {
159
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
160
+ const isControlled = controlledOpen !== undefined;
161
+ const open = isControlled ? controlledOpen : internalOpen;
162
+ const elementRef = useRef<HTMLElement>(null);
163
+
164
+ // Combine refs
165
+ const combinedRef = (node: HTMLElement | null) => {
166
+ (elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
167
+ if (typeof ref === "function") {
168
+ ref(node);
169
+ } else if (ref) {
170
+ (ref as React.MutableRefObject<HTMLElement | null>).current = node;
171
+ }
172
+ };
173
+
174
+ const handleOpenChange = useCallback(
175
+ (event: Event) => {
176
+ const customEvent = event as CustomEvent;
177
+ const isOpen = customEvent.type === "ds:open";
178
+
179
+ if (!isControlled) {
180
+ setInternalOpen(isOpen);
181
+ }
182
+ onOpenChange?.(isOpen);
183
+ },
184
+ [isControlled, onOpenChange]
185
+ );
186
+
187
+ // Attach event listeners
188
+ useEffect(() => {
189
+ const element = elementRef.current;
190
+ if (!element) return;
191
+
192
+ element.addEventListener("ds:open", handleOpenChange);
193
+ element.addEventListener("ds:close", handleOpenChange);
194
+
195
+ return () => {
196
+ element.removeEventListener("ds:open", handleOpenChange);
197
+ element.removeEventListener("ds:close", handleOpenChange);
198
+ };
199
+ }, [handleOpenChange]);
200
+
201
+ return createElement(
202
+ "ds-dropdown-menu",
203
+ {
204
+ ref: combinedRef,
205
+ class: className,
206
+ open: open || undefined,
207
+ placement,
208
+ offset,
209
+ flip: flip || undefined,
210
+ animated: animated || undefined,
211
+ modal: modal || undefined,
212
+ ...props,
213
+ },
214
+ children
215
+ );
216
+ });
217
+ DropdownMenuRoot.displayName = "DropdownMenu.Root";
218
+
219
+ /**
220
+ * DropdownMenu trigger component.
221
+ */
222
+ const DropdownMenuTrigger = forwardRef<HTMLElement, DropdownMenuTriggerProps>(
223
+ function DropdownMenuTrigger({ children, className, ...props }, ref) {
224
+ return createElement("span", { ref, className, slot: "trigger", ...props }, children);
225
+ }
226
+ );
227
+ DropdownMenuTrigger.displayName = "DropdownMenu.Trigger";
228
+
229
+ /**
230
+ * DropdownMenu content component.
231
+ */
232
+ const DropdownMenuContent = forwardRef<HTMLElement, DropdownMenuContentProps>(
233
+ function DropdownMenuContent({ children, className, ...props }, ref) {
234
+ return createElement("ds-dropdown-menu-content", { ref, class: className, ...props }, children);
235
+ }
236
+ );
237
+ DropdownMenuContent.displayName = "DropdownMenu.Content";
238
+
239
+ /**
240
+ * DropdownMenu item component.
241
+ */
242
+ const DropdownMenuItem = forwardRef<HTMLElement, DropdownMenuItemProps>(function DropdownMenuItem(
243
+ { children, className, value, variant = "default", disabled = false, onSelect, ...props },
244
+ ref
245
+ ) {
246
+ const elementRef = useRef<HTMLElement>(null);
247
+
248
+ // Combine refs
249
+ const combinedRef = (node: HTMLElement | null) => {
250
+ (elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
251
+ if (typeof ref === "function") {
252
+ ref(node);
253
+ } else if (ref) {
254
+ (ref as React.MutableRefObject<HTMLElement | null>).current = node;
255
+ }
256
+ };
257
+
258
+ // Attach select handler
259
+ useEffect(() => {
260
+ const element = elementRef.current;
261
+ if (!element || !onSelect) return;
262
+
263
+ const handleSelect = (event: Event) => {
264
+ const customEvent = event as CustomEvent<{ value: string }>;
265
+ onSelect(customEvent.detail.value);
266
+ };
267
+ element.addEventListener("ds:select", handleSelect);
268
+
269
+ return () => {
270
+ element.removeEventListener("ds:select", handleSelect);
271
+ };
272
+ }, [onSelect]);
273
+
274
+ return createElement(
275
+ "ds-dropdown-menu-item",
276
+ {
277
+ ref: combinedRef,
278
+ class: className,
279
+ value,
280
+ variant,
281
+ disabled: disabled || undefined,
282
+ ...props,
283
+ },
284
+ children
285
+ );
286
+ });
287
+ DropdownMenuItem.displayName = "DropdownMenu.Item";
288
+
289
+ /**
290
+ * DropdownMenu separator component.
291
+ */
292
+ const DropdownMenuSeparator = forwardRef<HTMLElement, DropdownMenuSeparatorProps>(
293
+ function DropdownMenuSeparator({ className, ...props }, ref) {
294
+ return createElement("ds-dropdown-menu-separator", { ref, class: className, ...props });
295
+ }
296
+ );
297
+ DropdownMenuSeparator.displayName = "DropdownMenu.Separator";
298
+
299
+ /**
300
+ * DropdownMenu label component.
301
+ */
302
+ const DropdownMenuLabel = forwardRef<HTMLElement, DropdownMenuLabelProps>(
303
+ function DropdownMenuLabel({ children, className, ...props }, ref) {
304
+ return createElement("ds-dropdown-menu-label", { ref, class: className, ...props }, children);
305
+ }
306
+ );
307
+ DropdownMenuLabel.displayName = "DropdownMenu.Label";
308
+
309
+ /**
310
+ * DropdownMenu checkbox item component.
311
+ */
312
+ const DropdownMenuCheckboxItem = forwardRef<HTMLElement, DropdownMenuCheckboxItemProps>(
313
+ function DropdownMenuCheckboxItem(
314
+ { children, className, checked = false, onCheckedChange, disabled = false, ...props },
315
+ ref
316
+ ) {
317
+ const elementRef = useRef<HTMLElement>(null);
318
+
319
+ // Combine refs
320
+ const combinedRef = (node: HTMLElement | null) => {
321
+ (elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
322
+ if (typeof ref === "function") {
323
+ ref(node);
324
+ } else if (ref) {
325
+ (ref as React.MutableRefObject<HTMLElement | null>).current = node;
326
+ }
327
+ };
328
+
329
+ // Attach change handler
330
+ useEffect(() => {
331
+ const element = elementRef.current;
332
+ if (!element || !onCheckedChange) return;
333
+
334
+ const handleSelect = (event: Event) => {
335
+ const customEvent = event as CustomEvent<{ checked: boolean }>;
336
+ onCheckedChange(customEvent.detail.checked);
337
+ };
338
+ element.addEventListener("ds:select", handleSelect);
339
+
340
+ return () => {
341
+ element.removeEventListener("ds:select", handleSelect);
342
+ };
343
+ }, [onCheckedChange]);
344
+
345
+ return createElement(
346
+ "ds-dropdown-menu-checkbox-item",
347
+ {
348
+ ref: combinedRef,
349
+ class: className,
350
+ checked: checked || undefined,
351
+ disabled: disabled || undefined,
352
+ ...props,
353
+ },
354
+ children
355
+ );
356
+ }
357
+ );
358
+ DropdownMenuCheckboxItem.displayName = "DropdownMenu.CheckboxItem";
359
+
360
+ /**
361
+ * DropdownMenu radio group component.
362
+ */
363
+ const DropdownMenuRadioGroup = forwardRef<HTMLElement, DropdownMenuRadioGroupProps>(
364
+ function DropdownMenuRadioGroup({ children, className, value, onValueChange, ...props }, ref) {
365
+ const elementRef = useRef<HTMLElement>(null);
366
+
367
+ // Combine refs
368
+ const combinedRef = (node: HTMLElement | null) => {
369
+ (elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
370
+ if (typeof ref === "function") {
371
+ ref(node);
372
+ } else if (ref) {
373
+ (ref as React.MutableRefObject<HTMLElement | null>).current = node;
374
+ }
375
+ };
376
+
377
+ // Attach change handler
378
+ useEffect(() => {
379
+ const element = elementRef.current;
380
+ if (!element || !onValueChange) return;
381
+
382
+ const handleChange = (event: Event) => {
383
+ const customEvent = event as CustomEvent<{ value: string }>;
384
+ onValueChange(customEvent.detail.value);
385
+ };
386
+ element.addEventListener("ds:change", handleChange);
387
+
388
+ return () => {
389
+ element.removeEventListener("ds:change", handleChange);
390
+ };
391
+ }, [onValueChange]);
392
+
393
+ return createElement(
394
+ "ds-dropdown-menu-radio-group",
395
+ {
396
+ ref: combinedRef,
397
+ class: className,
398
+ value,
399
+ ...props,
400
+ },
401
+ children
402
+ );
403
+ }
404
+ );
405
+ DropdownMenuRadioGroup.displayName = "DropdownMenu.RadioGroup";
406
+
407
+ /**
408
+ * DropdownMenu radio item component.
409
+ */
410
+ const DropdownMenuRadioItem = forwardRef<HTMLElement, DropdownMenuRadioItemProps>(
411
+ function DropdownMenuRadioItem({ children, className, value, disabled = false, ...props }, ref) {
412
+ return createElement(
413
+ "ds-dropdown-menu-radio-item",
414
+ {
415
+ ref,
416
+ class: className,
417
+ value,
418
+ disabled: disabled || undefined,
419
+ ...props,
420
+ },
421
+ children
422
+ );
423
+ }
424
+ );
425
+ DropdownMenuRadioItem.displayName = "DropdownMenu.RadioItem";
426
+
427
+ // ============================================================================
428
+ // Compound Component
429
+ // ============================================================================
430
+
431
+ export const DropdownMenu = {
432
+ Root: DropdownMenuRoot,
433
+ Trigger: DropdownMenuTrigger,
434
+ Content: DropdownMenuContent,
435
+ Item: DropdownMenuItem,
436
+ Separator: DropdownMenuSeparator,
437
+ Label: DropdownMenuLabel,
438
+ CheckboxItem: DropdownMenuCheckboxItem,
439
+ RadioGroup: DropdownMenuRadioGroup,
440
+ RadioItem: DropdownMenuRadioItem,
441
+ };
442
+
443
+ // Also export individual components
444
+ export {
445
+ DropdownMenuRoot,
446
+ DropdownMenuTrigger,
447
+ DropdownMenuContent,
448
+ DropdownMenuItem,
449
+ DropdownMenuSeparator,
450
+ DropdownMenuLabel,
451
+ DropdownMenuCheckboxItem,
452
+ DropdownMenuRadioGroup,
453
+ DropdownMenuRadioItem,
454
+ };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * DropdownMenuCheckboxItem component - toggleable checkbox menu item.
3
+ *
4
+ * @element ds-dropdown-menu-checkbox-item
5
+ *
6
+ * @slot - Item content
7
+ *
8
+ * @fires ds:select - Fired when item is toggled
9
+ */
10
+
11
+ import { html } from "lit";
12
+ import { property } from "lit/decorators.js";
13
+ import { DSElement } from "../../base/ds-element.js";
14
+ import { emitEvent } from "../../events/emit.js";
15
+ import { define } from "../../registry/define.js";
16
+
17
+ export class DsDropdownMenuCheckboxItem extends DSElement {
18
+ /** Whether the checkbox is checked */
19
+ @property({ type: Boolean, reflect: true })
20
+ checked = false;
21
+
22
+ /** Disabled state */
23
+ @property({ type: Boolean, reflect: true })
24
+ disabled = false;
25
+
26
+ override connectedCallback(): void {
27
+ super.connectedCallback();
28
+
29
+ this.setAttribute("role", "menuitemcheckbox");
30
+ this.setAttribute("tabindex", "-1");
31
+ this.updateAriaChecked();
32
+
33
+ this.addEventListener("click", this.handleToggle);
34
+ this.addEventListener("keydown", this.handleKeyDown);
35
+ }
36
+
37
+ override disconnectedCallback(): void {
38
+ super.disconnectedCallback();
39
+ this.removeEventListener("click", this.handleToggle);
40
+ this.removeEventListener("keydown", this.handleKeyDown);
41
+ }
42
+
43
+ private handleToggle = (): void => {
44
+ if (this.disabled) return;
45
+
46
+ this.checked = !this.checked;
47
+ this.updateAriaChecked();
48
+
49
+ emitEvent(this, "ds:select", {
50
+ detail: { checked: this.checked },
51
+ bubbles: true,
52
+ });
53
+ };
54
+
55
+ private handleKeyDown = (event: KeyboardEvent): void => {
56
+ if (this.disabled) return;
57
+
58
+ if (event.key === "Enter" || event.key === " ") {
59
+ event.preventDefault();
60
+ this.handleToggle();
61
+ }
62
+ };
63
+
64
+ private updateAriaChecked(): void {
65
+ this.setAttribute("aria-checked", String(this.checked));
66
+ }
67
+
68
+ override updated(changedProperties: Map<string, unknown>): void {
69
+ if (changedProperties.has("disabled")) {
70
+ this.setAttribute("aria-disabled", String(this.disabled));
71
+ }
72
+ if (changedProperties.has("checked")) {
73
+ this.updateAriaChecked();
74
+ }
75
+ }
76
+
77
+ override render() {
78
+ return html`
79
+ <span class="ds-dropdown-menu-checkbox-item__indicator" aria-hidden="true">
80
+ ${this.checked ? "✓" : ""}
81
+ </span>
82
+ <slot></slot>
83
+ `;
84
+ }
85
+ }
86
+
87
+ define("ds-dropdown-menu-checkbox-item", DsDropdownMenuCheckboxItem);
88
+
89
+ declare global {
90
+ interface HTMLElementTagNameMap {
91
+ "ds-dropdown-menu-checkbox-item": DsDropdownMenuCheckboxItem;
92
+ }
93
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * DropdownMenuContent component - container for menu items.
3
+ *
4
+ * @element ds-dropdown-menu-content
5
+ *
6
+ * @slot - Menu items
7
+ */
8
+
9
+ import { html } from "lit";
10
+ import { property } from "lit/decorators.js";
11
+ import { DSElement } from "../../base/ds-element.js";
12
+ import { define } from "../../registry/define.js";
13
+
14
+ export class DsDropdownMenuContent extends DSElement {
15
+ /** Data state for animations */
16
+ @property({ attribute: "data-state", reflect: true })
17
+ dataState: "open" | "closed" = "closed";
18
+
19
+ override connectedCallback(): void {
20
+ super.connectedCallback();
21
+
22
+ // Generate ID for ARIA
23
+ if (!this.id) {
24
+ this.id = `dropdown-menu-content-${crypto.randomUUID().slice(0, 8)}`;
25
+ }
26
+
27
+ // Set ARIA role
28
+ this.setAttribute("role", "menu");
29
+ this.setAttribute("hidden", "");
30
+ }
31
+
32
+ override render() {
33
+ return html`<slot></slot>`;
34
+ }
35
+ }
36
+
37
+ define("ds-dropdown-menu-content", DsDropdownMenuContent);
38
+
39
+ declare global {
40
+ interface HTMLElementTagNameMap {
41
+ "ds-dropdown-menu-content": DsDropdownMenuContent;
42
+ }
43
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * DropdownMenuItem component - selectable menu item.
3
+ *
4
+ * @element ds-dropdown-menu-item
5
+ *
6
+ * @slot - Item content
7
+ *
8
+ * @fires ds:select - Fired when item is selected
9
+ */
10
+
11
+ import { html } from "lit";
12
+ import { property } from "lit/decorators.js";
13
+ import { DSElement } from "../../base/ds-element.js";
14
+ import { emitEvent } from "../../events/emit.js";
15
+ import { define } from "../../registry/define.js";
16
+
17
+ export type DropdownMenuItemVariant = "default" | "destructive";
18
+
19
+ export class DsDropdownMenuItem extends DSElement {
20
+ /** Value for selection events */
21
+ @property()
22
+ value = "";
23
+
24
+ /** Visual variant */
25
+ @property({ reflect: true })
26
+ variant: DropdownMenuItemVariant = "default";
27
+
28
+ /** Disabled state */
29
+ @property({ type: Boolean, reflect: true })
30
+ disabled = false;
31
+
32
+ override connectedCallback(): void {
33
+ super.connectedCallback();
34
+
35
+ // Set ARIA role
36
+ this.setAttribute("role", "menuitem");
37
+ this.setAttribute("tabindex", "-1");
38
+
39
+ // Listen for selection triggers
40
+ this.addEventListener("click", this.handleSelect);
41
+ this.addEventListener("keydown", this.handleKeyDown);
42
+ }
43
+
44
+ override disconnectedCallback(): void {
45
+ super.disconnectedCallback();
46
+ this.removeEventListener("click", this.handleSelect);
47
+ this.removeEventListener("keydown", this.handleKeyDown);
48
+ }
49
+
50
+ private handleSelect = (): void => {
51
+ if (this.disabled) return;
52
+
53
+ emitEvent(this, "ds:select", {
54
+ detail: { value: this.value },
55
+ bubbles: true,
56
+ });
57
+ };
58
+
59
+ private handleKeyDown = (event: KeyboardEvent): void => {
60
+ if (this.disabled) return;
61
+
62
+ if (event.key === "Enter" || event.key === " ") {
63
+ event.preventDefault();
64
+ this.handleSelect();
65
+ }
66
+ };
67
+
68
+ override updated(changedProperties: Map<string, unknown>): void {
69
+ if (changedProperties.has("disabled")) {
70
+ this.setAttribute("aria-disabled", String(this.disabled));
71
+ }
72
+ }
73
+
74
+ override render() {
75
+ return html`<slot></slot>`;
76
+ }
77
+ }
78
+
79
+ define("ds-dropdown-menu-item", DsDropdownMenuItem);
80
+
81
+ declare global {
82
+ interface HTMLElementTagNameMap {
83
+ "ds-dropdown-menu-item": DsDropdownMenuItem;
84
+ }
85
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * DropdownMenuLabel component - non-interactive label for menu sections.
3
+ *
4
+ * @element ds-dropdown-menu-label
5
+ *
6
+ * @slot - Label content
7
+ */
8
+
9
+ import { html } from "lit";
10
+ import { DSElement } from "../../base/ds-element.js";
11
+ import { define } from "../../registry/define.js";
12
+
13
+ export class DsDropdownMenuLabel extends DSElement {
14
+ override connectedCallback(): void {
15
+ super.connectedCallback();
16
+ // Labels are not focusable
17
+ this.setAttribute("aria-hidden", "true");
18
+ }
19
+
20
+ override render() {
21
+ return html`<slot></slot>`;
22
+ }
23
+ }
24
+
25
+ define("ds-dropdown-menu-label", DsDropdownMenuLabel);
26
+
27
+ declare global {
28
+ interface HTMLElementTagNameMap {
29
+ "ds-dropdown-menu-label": DsDropdownMenuLabel;
30
+ }
31
+ }