@sharedex/ui 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/README.md +37 -2
  2. package/dist/backgrounds/hosts/CssHost.d.ts +2 -6
  3. package/dist/backgrounds/hosts/CssHost.js +3 -17
  4. package/dist/backgrounds/hosts/styleHref.d.ts +6 -0
  5. package/dist/backgrounds/hosts/styleHref.js +20 -0
  6. package/dist/buttons/pick.d.ts +9 -3
  7. package/dist/buttons/pick.js +4 -1
  8. package/dist/forms/base.d.ts +1 -0
  9. package/dist/forms/base.js +224 -0
  10. package/dist/forms/buddy.d.ts +6 -0
  11. package/dist/forms/buddy.js +150 -0
  12. package/dist/forms/chips.d.ts +1 -0
  13. package/dist/forms/chips.js +140 -0
  14. package/dist/forms/choice.d.ts +1 -0
  15. package/dist/forms/choice.js +208 -0
  16. package/dist/forms/controls/CheckGroup.d.ts +65 -0
  17. package/dist/forms/controls/CheckGroup.js +99 -0
  18. package/dist/forms/controls/Checkbox.d.ts +43 -0
  19. package/dist/forms/controls/Checkbox.js +67 -0
  20. package/dist/forms/controls/ChipGroup.d.ts +50 -0
  21. package/dist/forms/controls/ChipGroup.js +56 -0
  22. package/dist/forms/controls/Combobox.d.ts +75 -0
  23. package/dist/forms/controls/Combobox.js +249 -0
  24. package/dist/forms/controls/ErrorSummary.d.ts +29 -0
  25. package/dist/forms/controls/ErrorSummary.js +79 -0
  26. package/dist/forms/controls/Field.d.ts +92 -0
  27. package/dist/forms/controls/Field.js +219 -0
  28. package/dist/forms/controls/FileDrop.d.ts +81 -0
  29. package/dist/forms/controls/FileDrop.js +328 -0
  30. package/dist/forms/controls/FormBuddy.d.ts +22 -0
  31. package/dist/forms/controls/FormBuddy.js +143 -0
  32. package/dist/forms/controls/FormReveal.d.ts +21 -0
  33. package/dist/forms/controls/FormReveal.js +19 -0
  34. package/dist/forms/controls/FormSteps.d.ts +75 -0
  35. package/dist/forms/controls/FormSteps.js +205 -0
  36. package/dist/forms/controls/FormSwap.d.ts +27 -0
  37. package/dist/forms/controls/FormSwap.js +38 -0
  38. package/dist/forms/controls/InlineEdit.d.ts +50 -0
  39. package/dist/forms/controls/InlineEdit.js +136 -0
  40. package/dist/forms/controls/NumberField.d.ts +43 -0
  41. package/dist/forms/controls/NumberField.js +205 -0
  42. package/dist/forms/controls/OtpField.d.ts +46 -0
  43. package/dist/forms/controls/OtpField.js +195 -0
  44. package/dist/forms/controls/PasswordRules.d.ts +31 -0
  45. package/dist/forms/controls/PasswordRules.js +85 -0
  46. package/dist/forms/controls/RadioGroup.d.ts +69 -0
  47. package/dist/forms/controls/RadioGroup.js +95 -0
  48. package/dist/forms/controls/Range.d.ts +60 -0
  49. package/dist/forms/controls/Range.js +169 -0
  50. package/dist/forms/controls/SaveStatus.d.ts +25 -0
  51. package/dist/forms/controls/SaveStatus.js +88 -0
  52. package/dist/forms/controls/Select.d.ts +46 -0
  53. package/dist/forms/controls/Select.js +35 -0
  54. package/dist/forms/controls/Switch.d.ts +54 -0
  55. package/dist/forms/controls/Switch.js +91 -0
  56. package/dist/forms/controls/TagsField.d.ts +68 -0
  57. package/dist/forms/controls/TagsField.js +0 -0
  58. package/dist/forms/controls/choiceChecks.d.ts +11 -0
  59. package/dist/forms/controls/choiceChecks.js +19 -0
  60. package/dist/forms/controls/choiceParts.d.ts +40 -0
  61. package/dist/forms/controls/choiceParts.js +49 -0
  62. package/dist/forms/controls/fieldChecks.d.ts +17 -0
  63. package/dist/forms/controls/fieldChecks.js +34 -0
  64. package/dist/forms/controls/fieldTools.d.ts +62 -0
  65. package/dist/forms/controls/fieldTools.js +54 -0
  66. package/dist/forms/controls/pickerChecks.d.ts +10 -0
  67. package/dist/forms/controls/pickerChecks.js +27 -0
  68. package/dist/forms/controls/rangeChecks.d.ts +11 -0
  69. package/dist/forms/controls/rangeChecks.js +23 -0
  70. package/dist/forms/controls/shared.d.ts +8 -0
  71. package/dist/forms/controls/shared.js +18 -0
  72. package/dist/forms/effects/cards.d.ts +11 -0
  73. package/dist/forms/effects/cards.js +52 -0
  74. package/dist/forms/effects/check/checkCard.d.ts +10 -0
  75. package/dist/forms/effects/check/checkCard.js +15 -0
  76. package/dist/forms/effects/check/checkCard.schema.d.ts +1 -0
  77. package/dist/forms/effects/check/checkCard.schema.js +9 -0
  78. package/dist/forms/effects/check/checkConfetti.d.ts +18 -0
  79. package/dist/forms/effects/check/checkConfetti.js +38 -0
  80. package/dist/forms/effects/check/checkConfetti.schema.d.ts +1 -0
  81. package/dist/forms/effects/check/checkConfetti.schema.js +13 -0
  82. package/dist/forms/effects/check/checkDraw.d.ts +7 -0
  83. package/dist/forms/effects/check/checkDraw.js +12 -0
  84. package/dist/forms/effects/check/checkDraw.schema.d.ts +1 -0
  85. package/dist/forms/effects/check/checkDraw.schema.js +9 -0
  86. package/dist/forms/effects/check/checkHeart.d.ts +9 -0
  87. package/dist/forms/effects/check/checkHeart.js +84 -0
  88. package/dist/forms/effects/check/checkHeart.schema.d.ts +1 -0
  89. package/dist/forms/effects/check/checkHeart.schema.js +10 -0
  90. package/dist/forms/effects/check/checkJelly.d.ts +9 -0
  91. package/dist/forms/effects/check/checkJelly.js +23 -0
  92. package/dist/forms/effects/check/checkJelly.schema.d.ts +1 -0
  93. package/dist/forms/effects/check/checkJelly.schema.js +10 -0
  94. package/dist/forms/effects/check/checkMerge.d.ts +9 -0
  95. package/dist/forms/effects/check/checkMerge.js +37 -0
  96. package/dist/forms/effects/check/checkMerge.schema.d.ts +1 -0
  97. package/dist/forms/effects/check/checkMerge.schema.js +10 -0
  98. package/dist/forms/effects/check/checkMixed.d.ts +7 -0
  99. package/dist/forms/effects/check/checkMixed.js +25 -0
  100. package/dist/forms/effects/check/checkMixed.schema.d.ts +1 -0
  101. package/dist/forms/effects/check/checkMixed.schema.js +9 -0
  102. package/dist/forms/effects/check/checkMorph.d.ts +9 -0
  103. package/dist/forms/effects/check/checkMorph.js +53 -0
  104. package/dist/forms/effects/check/checkMorph.schema.d.ts +1 -0
  105. package/dist/forms/effects/check/checkMorph.schema.js +10 -0
  106. package/dist/forms/effects/check/checkPop.d.ts +9 -0
  107. package/dist/forms/effects/check/checkPop.js +27 -0
  108. package/dist/forms/effects/check/checkPop.schema.d.ts +1 -0
  109. package/dist/forms/effects/check/checkPop.schema.js +10 -0
  110. package/dist/forms/effects/check/checkRipple.d.ts +7 -0
  111. package/dist/forms/effects/check/checkRipple.js +33 -0
  112. package/dist/forms/effects/check/checkRipple.schema.d.ts +1 -0
  113. package/dist/forms/effects/check/checkRipple.schema.js +9 -0
  114. package/dist/forms/effects/check/checkScribble.d.ts +11 -0
  115. package/dist/forms/effects/check/checkScribble.js +42 -0
  116. package/dist/forms/effects/check/checkScribble.schema.d.ts +1 -0
  117. package/dist/forms/effects/check/checkScribble.schema.js +11 -0
  118. package/dist/forms/effects/check/checkStrike.d.ts +9 -0
  119. package/dist/forms/effects/check/checkStrike.js +54 -0
  120. package/dist/forms/effects/check/checkStrike.schema.d.ts +1 -0
  121. package/dist/forms/effects/check/checkStrike.schema.js +10 -0
  122. package/dist/forms/effects/chip/chipCheck.d.ts +7 -0
  123. package/dist/forms/effects/chip/chipCheck.js +26 -0
  124. package/dist/forms/effects/chip/chipCheck.schema.d.ts +1 -0
  125. package/dist/forms/effects/chip/chipCheck.schema.js +9 -0
  126. package/dist/forms/effects/chip/chipMerge.d.ts +9 -0
  127. package/dist/forms/effects/chip/chipMerge.js +63 -0
  128. package/dist/forms/effects/chip/chipMerge.schema.d.ts +1 -0
  129. package/dist/forms/effects/chip/chipMerge.schema.js +10 -0
  130. package/dist/forms/effects/file/fileButton.d.ts +7 -0
  131. package/dist/forms/effects/file/fileButton.js +28 -0
  132. package/dist/forms/effects/file/fileButton.schema.d.ts +1 -0
  133. package/dist/forms/effects/file/fileButton.schema.js +9 -0
  134. package/dist/forms/effects/file/fileCards.d.ts +7 -0
  135. package/dist/forms/effects/file/fileCards.js +38 -0
  136. package/dist/forms/effects/file/fileCards.schema.d.ts +1 -0
  137. package/dist/forms/effects/file/fileCards.schema.js +9 -0
  138. package/dist/forms/effects/file/fileDrag.d.ts +9 -0
  139. package/dist/forms/effects/file/fileDrag.js +45 -0
  140. package/dist/forms/effects/file/fileDrag.schema.d.ts +1 -0
  141. package/dist/forms/effects/file/fileDrag.schema.js +10 -0
  142. package/dist/forms/effects/file/filePage.d.ts +7 -0
  143. package/dist/forms/effects/file/filePage.js +46 -0
  144. package/dist/forms/effects/file/filePage.schema.d.ts +1 -0
  145. package/dist/forms/effects/file/filePage.schema.js +9 -0
  146. package/dist/forms/effects/file/filePreview.d.ts +7 -0
  147. package/dist/forms/effects/file/filePreview.js +17 -0
  148. package/dist/forms/effects/file/filePreview.schema.d.ts +1 -0
  149. package/dist/forms/effects/file/filePreview.schema.js +9 -0
  150. package/dist/forms/effects/file/fileProgress.d.ts +9 -0
  151. package/dist/forms/effects/file/fileProgress.js +92 -0
  152. package/dist/forms/effects/file/fileProgress.schema.d.ts +1 -0
  153. package/dist/forms/effects/file/fileProgress.schema.js +10 -0
  154. package/dist/forms/effects/file/fileReject.d.ts +7 -0
  155. package/dist/forms/effects/file/fileReject.js +24 -0
  156. package/dist/forms/effects/file/fileReject.schema.d.ts +1 -0
  157. package/dist/forms/effects/file/fileReject.schema.js +9 -0
  158. package/dist/forms/effects/input/inputAside.d.ts +11 -0
  159. package/dist/forms/effects/input/inputAside.js +42 -0
  160. package/dist/forms/effects/input/inputAside.schema.d.ts +1 -0
  161. package/dist/forms/effects/input/inputAside.schema.js +11 -0
  162. package/dist/forms/effects/input/inputBeam.d.ts +14 -0
  163. package/dist/forms/effects/input/inputBeam.js +51 -0
  164. package/dist/forms/effects/input/inputBeam.schema.d.ts +1 -0
  165. package/dist/forms/effects/input/inputBeam.schema.js +18 -0
  166. package/dist/forms/effects/input/inputCaret.d.ts +13 -0
  167. package/dist/forms/effects/input/inputCaret.js +33 -0
  168. package/dist/forms/effects/input/inputCaret.schema.d.ts +1 -0
  169. package/dist/forms/effects/input/inputCaret.schema.js +26 -0
  170. package/dist/forms/effects/input/inputCounter.d.ts +16 -0
  171. package/dist/forms/effects/input/inputCounter.js +84 -0
  172. package/dist/forms/effects/input/inputCounter.schema.d.ts +1 -0
  173. package/dist/forms/effects/input/inputCounter.schema.js +12 -0
  174. package/dist/forms/effects/input/inputCycle.d.ts +19 -0
  175. package/dist/forms/effects/input/inputCycle.js +93 -0
  176. package/dist/forms/effects/input/inputCycle.schema.d.ts +1 -0
  177. package/dist/forms/effects/input/inputCycle.schema.js +11 -0
  178. package/dist/forms/effects/input/inputDepth.d.ts +11 -0
  179. package/dist/forms/effects/input/inputDepth.js +31 -0
  180. package/dist/forms/effects/input/inputDepth.schema.d.ts +1 -0
  181. package/dist/forms/effects/input/inputDepth.schema.js +11 -0
  182. package/dist/forms/effects/input/inputDraw.d.ts +13 -0
  183. package/dist/forms/effects/input/inputDraw.js +27 -0
  184. package/dist/forms/effects/input/inputDraw.schema.d.ts +1 -0
  185. package/dist/forms/effects/input/inputDraw.schema.js +12 -0
  186. package/dist/forms/effects/input/inputFlap.d.ts +9 -0
  187. package/dist/forms/effects/input/inputFlap.js +24 -0
  188. package/dist/forms/effects/input/inputFlap.schema.d.ts +1 -0
  189. package/dist/forms/effects/input/inputFlap.schema.js +10 -0
  190. package/dist/forms/effects/input/inputFloat.d.ts +12 -0
  191. package/dist/forms/effects/input/inputFloat.js +46 -0
  192. package/dist/forms/effects/input/inputFloat.schema.d.ts +1 -0
  193. package/dist/forms/effects/input/inputFloat.schema.js +10 -0
  194. package/dist/forms/effects/input/inputFlood.d.ts +11 -0
  195. package/dist/forms/effects/input/inputFlood.js +30 -0
  196. package/dist/forms/effects/input/inputFlood.schema.d.ts +1 -0
  197. package/dist/forms/effects/input/inputFlood.schema.js +11 -0
  198. package/dist/forms/effects/input/inputFrame.d.ts +18 -0
  199. package/dist/forms/effects/input/inputFrame.js +77 -0
  200. package/dist/forms/effects/input/inputFrame.schema.d.ts +1 -0
  201. package/dist/forms/effects/input/inputFrame.schema.js +13 -0
  202. package/dist/forms/effects/input/inputIcon.d.ts +11 -0
  203. package/dist/forms/effects/input/inputIcon.js +18 -0
  204. package/dist/forms/effects/input/inputIcon.schema.d.ts +1 -0
  205. package/dist/forms/effects/input/inputIcon.schema.js +11 -0
  206. package/dist/forms/effects/input/inputNotch.d.ts +9 -0
  207. package/dist/forms/effects/input/inputNotch.js +70 -0
  208. package/dist/forms/effects/input/inputNotch.schema.d.ts +1 -0
  209. package/dist/forms/effects/input/inputNotch.schema.js +10 -0
  210. package/dist/forms/effects/input/inputReveal.d.ts +15 -0
  211. package/dist/forms/effects/input/inputReveal.js +56 -0
  212. package/dist/forms/effects/input/inputReveal.schema.d.ts +1 -0
  213. package/dist/forms/effects/input/inputReveal.schema.js +16 -0
  214. package/dist/forms/effects/input/inputRing.d.ts +13 -0
  215. package/dist/forms/effects/input/inputRing.js +27 -0
  216. package/dist/forms/effects/input/inputRing.schema.d.ts +1 -0
  217. package/dist/forms/effects/input/inputRing.schema.js +12 -0
  218. package/dist/forms/effects/input/inputRise.d.ts +9 -0
  219. package/dist/forms/effects/input/inputRise.js +22 -0
  220. package/dist/forms/effects/input/inputRise.schema.d.ts +1 -0
  221. package/dist/forms/effects/input/inputRise.schema.js +10 -0
  222. package/dist/forms/effects/input/inputSearch.d.ts +9 -0
  223. package/dist/forms/effects/input/inputSearch.js +37 -0
  224. package/dist/forms/effects/input/inputSearch.schema.d.ts +1 -0
  225. package/dist/forms/effects/input/inputSearch.schema.js +10 -0
  226. package/dist/forms/effects/input/inputSkeleton.d.ts +7 -0
  227. package/dist/forms/effects/input/inputSkeleton.js +41 -0
  228. package/dist/forms/effects/input/inputSkeleton.schema.d.ts +1 -0
  229. package/dist/forms/effects/input/inputSkeleton.schema.js +9 -0
  230. package/dist/forms/effects/input/inputSpotlight.d.ts +9 -0
  231. package/dist/forms/effects/input/inputSpotlight.js +20 -0
  232. package/dist/forms/effects/input/inputSpotlight.schema.d.ts +1 -0
  233. package/dist/forms/effects/input/inputSpotlight.schema.js +10 -0
  234. package/dist/forms/effects/input/inputStrength.d.ts +9 -0
  235. package/dist/forms/effects/input/inputStrength.js +29 -0
  236. package/dist/forms/effects/input/inputStrength.schema.d.ts +1 -0
  237. package/dist/forms/effects/input/inputStrength.schema.js +10 -0
  238. package/dist/forms/effects/input/inputSwap.d.ts +11 -0
  239. package/dist/forms/effects/input/inputSwap.js +39 -0
  240. package/dist/forms/effects/input/inputSwap.schema.d.ts +1 -0
  241. package/dist/forms/effects/input/inputSwap.schema.js +11 -0
  242. package/dist/forms/effects/input/inputUnderline.d.ts +13 -0
  243. package/dist/forms/effects/input/inputUnderline.js +36 -0
  244. package/dist/forms/effects/input/inputUnderline.schema.d.ts +1 -0
  245. package/dist/forms/effects/input/inputUnderline.schema.js +18 -0
  246. package/dist/forms/effects/input/inputWave.d.ts +11 -0
  247. package/dist/forms/effects/input/inputWave.js +23 -0
  248. package/dist/forms/effects/input/inputWave.schema.d.ts +1 -0
  249. package/dist/forms/effects/input/inputWave.schema.js +11 -0
  250. package/dist/forms/effects/input/inputWavy.d.ts +11 -0
  251. package/dist/forms/effects/input/inputWavy.js +53 -0
  252. package/dist/forms/effects/input/inputWavy.schema.d.ts +1 -0
  253. package/dist/forms/effects/input/inputWavy.schema.js +11 -0
  254. package/dist/forms/effects/kit.d.ts +213 -0
  255. package/dist/forms/effects/kit.js +226 -0
  256. package/dist/forms/effects/picker/chipPop.d.ts +7 -0
  257. package/dist/forms/effects/picker/chipPop.js +28 -0
  258. package/dist/forms/effects/picker/chipPop.schema.d.ts +1 -0
  259. package/dist/forms/effects/picker/chipPop.schema.js +9 -0
  260. package/dist/forms/effects/picker/listHighlight.d.ts +9 -0
  261. package/dist/forms/effects/picker/listHighlight.js +42 -0
  262. package/dist/forms/effects/picker/listHighlight.schema.d.ts +1 -0
  263. package/dist/forms/effects/picker/listHighlight.schema.js +10 -0
  264. package/dist/forms/effects/picker/listMatch.d.ts +7 -0
  265. package/dist/forms/effects/picker/listMatch.js +21 -0
  266. package/dist/forms/effects/picker/listMatch.schema.d.ts +1 -0
  267. package/dist/forms/effects/picker/listMatch.schema.js +9 -0
  268. package/dist/forms/effects/picker/pickerArrow.d.ts +9 -0
  269. package/dist/forms/effects/picker/pickerArrow.js +17 -0
  270. package/dist/forms/effects/picker/pickerArrow.schema.d.ts +1 -0
  271. package/dist/forms/effects/picker/pickerArrow.schema.js +10 -0
  272. package/dist/forms/effects/picker/pickerCheck.d.ts +7 -0
  273. package/dist/forms/effects/picker/pickerCheck.js +31 -0
  274. package/dist/forms/effects/picker/pickerCheck.schema.d.ts +1 -0
  275. package/dist/forms/effects/picker/pickerCheck.schema.js +9 -0
  276. package/dist/forms/effects/picker/pickerOpen.d.ts +12 -0
  277. package/dist/forms/effects/picker/pickerOpen.js +34 -0
  278. package/dist/forms/effects/picker/pickerOpen.schema.d.ts +1 -0
  279. package/dist/forms/effects/picker/pickerOpen.schema.js +16 -0
  280. package/dist/forms/effects/picker/pickerSheet.d.ts +9 -0
  281. package/dist/forms/effects/picker/pickerSheet.js +47 -0
  282. package/dist/forms/effects/picker/pickerSheet.schema.d.ts +1 -0
  283. package/dist/forms/effects/picker/pickerSheet.schema.js +10 -0
  284. package/dist/forms/effects/picker/pickerStagger.d.ts +9 -0
  285. package/dist/forms/effects/picker/pickerStagger.js +31 -0
  286. package/dist/forms/effects/picker/pickerStagger.schema.d.ts +1 -0
  287. package/dist/forms/effects/picker/pickerStagger.schema.js +10 -0
  288. package/dist/forms/effects/radio/radioCard.d.ts +10 -0
  289. package/dist/forms/effects/radio/radioCard.js +15 -0
  290. package/dist/forms/effects/radio/radioCard.schema.d.ts +1 -0
  291. package/dist/forms/effects/radio/radioCard.schema.js +9 -0
  292. package/dist/forms/effects/radio/radioCircle.d.ts +9 -0
  293. package/dist/forms/effects/radio/radioCircle.js +49 -0
  294. package/dist/forms/effects/radio/radioCircle.schema.d.ts +1 -0
  295. package/dist/forms/effects/radio/radioCircle.schema.js +10 -0
  296. package/dist/forms/effects/radio/radioDot.d.ts +7 -0
  297. package/dist/forms/effects/radio/radioDot.js +10 -0
  298. package/dist/forms/effects/radio/radioDot.schema.d.ts +1 -0
  299. package/dist/forms/effects/radio/radioDot.schema.js +9 -0
  300. package/dist/forms/effects/radio/radioEmoji.d.ts +9 -0
  301. package/dist/forms/effects/radio/radioEmoji.js +94 -0
  302. package/dist/forms/effects/radio/radioEmoji.schema.d.ts +1 -0
  303. package/dist/forms/effects/radio/radioEmoji.schema.js +10 -0
  304. package/dist/forms/effects/radio/radioPulse.d.ts +9 -0
  305. package/dist/forms/effects/radio/radioPulse.js +24 -0
  306. package/dist/forms/effects/radio/radioPulse.schema.d.ts +1 -0
  307. package/dist/forms/effects/radio/radioPulse.schema.js +10 -0
  308. package/dist/forms/effects/radio/radioScale.d.ts +9 -0
  309. package/dist/forms/effects/radio/radioScale.js +73 -0
  310. package/dist/forms/effects/radio/radioScale.schema.d.ts +1 -0
  311. package/dist/forms/effects/radio/radioScale.schema.js +10 -0
  312. package/dist/forms/effects/radio/radioSegment.d.ts +7 -0
  313. package/dist/forms/effects/radio/radioSegment.js +52 -0
  314. package/dist/forms/effects/radio/radioSegment.schema.d.ts +1 -0
  315. package/dist/forms/effects/radio/radioSegment.schema.js +9 -0
  316. package/dist/forms/effects/radio/radioStars.d.ts +15 -0
  317. package/dist/forms/effects/radio/radioStars.js +125 -0
  318. package/dist/forms/effects/radio/radioStars.schema.d.ts +1 -0
  319. package/dist/forms/effects/radio/radioStars.schema.js +13 -0
  320. package/dist/forms/effects/radio/radioTravel.d.ts +9 -0
  321. package/dist/forms/effects/radio/radioTravel.js +49 -0
  322. package/dist/forms/effects/radio/radioTravel.schema.d.ts +1 -0
  323. package/dist/forms/effects/radio/radioTravel.schema.js +10 -0
  324. package/dist/forms/effects/radio/radioUnderline.d.ts +9 -0
  325. package/dist/forms/effects/radio/radioUnderline.js +61 -0
  326. package/dist/forms/effects/radio/radioUnderline.schema.d.ts +1 -0
  327. package/dist/forms/effects/radio/radioUnderline.schema.js +10 -0
  328. package/dist/forms/effects/radio/shape.d.ts +13 -0
  329. package/dist/forms/effects/radio/shape.js +61 -0
  330. package/dist/forms/effects/range/rangeBubble.d.ts +9 -0
  331. package/dist/forms/effects/range/rangeBubble.js +54 -0
  332. package/dist/forms/effects/range/rangeBubble.schema.d.ts +1 -0
  333. package/dist/forms/effects/range/rangeBubble.schema.js +10 -0
  334. package/dist/forms/effects/range/rangeElastic.d.ts +9 -0
  335. package/dist/forms/effects/range/rangeElastic.js +101 -0
  336. package/dist/forms/effects/range/rangeElastic.schema.d.ts +1 -0
  337. package/dist/forms/effects/range/rangeElastic.schema.js +10 -0
  338. package/dist/forms/effects/range/rangeFace.d.ts +11 -0
  339. package/dist/forms/effects/range/rangeFace.js +68 -0
  340. package/dist/forms/effects/range/rangeFace.schema.d.ts +1 -0
  341. package/dist/forms/effects/range/rangeFace.schema.js +11 -0
  342. package/dist/forms/effects/range/rangeFill.d.ts +7 -0
  343. package/dist/forms/effects/range/rangeFill.js +29 -0
  344. package/dist/forms/effects/range/rangeFill.schema.d.ts +1 -0
  345. package/dist/forms/effects/range/rangeFill.schema.js +9 -0
  346. package/dist/forms/effects/range/rangeHistogram.d.ts +14 -0
  347. package/dist/forms/effects/range/rangeHistogram.js +65 -0
  348. package/dist/forms/effects/range/rangeHistogram.schema.d.ts +1 -0
  349. package/dist/forms/effects/range/rangeHistogram.schema.js +11 -0
  350. package/dist/forms/effects/range/rangeThumb.d.ts +9 -0
  351. package/dist/forms/effects/range/rangeThumb.js +39 -0
  352. package/dist/forms/effects/range/rangeThumb.schema.d.ts +1 -0
  353. package/dist/forms/effects/range/rangeThumb.schema.js +10 -0
  354. package/dist/forms/effects/range/rangeTicks.d.ts +9 -0
  355. package/dist/forms/effects/range/rangeTicks.js +44 -0
  356. package/dist/forms/effects/range/rangeTicks.schema.d.ts +1 -0
  357. package/dist/forms/effects/range/rangeTicks.schema.js +18 -0
  358. package/dist/forms/effects/ring.d.ts +5 -0
  359. package/dist/forms/effects/ring.js +12 -0
  360. package/dist/forms/effects/step/stepProgress.d.ts +9 -0
  361. package/dist/forms/effects/step/stepProgress.js +35 -0
  362. package/dist/forms/effects/step/stepProgress.schema.d.ts +1 -0
  363. package/dist/forms/effects/step/stepProgress.schema.js +10 -0
  364. package/dist/forms/effects/step/stepSlide.d.ts +9 -0
  365. package/dist/forms/effects/step/stepSlide.js +50 -0
  366. package/dist/forms/effects/step/stepSlide.schema.d.ts +1 -0
  367. package/dist/forms/effects/step/stepSlide.schema.js +10 -0
  368. package/dist/forms/effects/switch/switchBulb.d.ts +9 -0
  369. package/dist/forms/effects/switch/switchBulb.js +70 -0
  370. package/dist/forms/effects/switch/switchBulb.schema.d.ts +1 -0
  371. package/dist/forms/effects/switch/switchBulb.schema.js +10 -0
  372. package/dist/forms/effects/switch/switchDayNight.d.ts +15 -0
  373. package/dist/forms/effects/switch/switchDayNight.js +96 -0
  374. package/dist/forms/effects/switch/switchDayNight.schema.d.ts +1 -0
  375. package/dist/forms/effects/switch/switchDayNight.schema.js +13 -0
  376. package/dist/forms/effects/switch/switchFace.d.ts +7 -0
  377. package/dist/forms/effects/switch/switchFace.js +75 -0
  378. package/dist/forms/effects/switch/switchFace.schema.d.ts +1 -0
  379. package/dist/forms/effects/switch/switchFace.schema.js +9 -0
  380. package/dist/forms/effects/switch/switchFlip.d.ts +7 -0
  381. package/dist/forms/effects/switch/switchFlip.js +45 -0
  382. package/dist/forms/effects/switch/switchFlip.schema.d.ts +1 -0
  383. package/dist/forms/effects/switch/switchFlip.schema.js +9 -0
  384. package/dist/forms/effects/switch/switchGoo.d.ts +7 -0
  385. package/dist/forms/effects/switch/switchGoo.js +95 -0
  386. package/dist/forms/effects/switch/switchGoo.schema.d.ts +1 -0
  387. package/dist/forms/effects/switch/switchGoo.schema.js +9 -0
  388. package/dist/forms/effects/switch/switchIcon.d.ts +9 -0
  389. package/dist/forms/effects/switch/switchIcon.js +63 -0
  390. package/dist/forms/effects/switch/switchIcon.schema.d.ts +1 -0
  391. package/dist/forms/effects/switch/switchIcon.schema.js +10 -0
  392. package/dist/forms/effects/switch/switchLabels.d.ts +11 -0
  393. package/dist/forms/effects/switch/switchLabels.js +55 -0
  394. package/dist/forms/effects/switch/switchLabels.schema.d.ts +1 -0
  395. package/dist/forms/effects/switch/switchLabels.schema.js +11 -0
  396. package/dist/forms/effects/switch/switchMorph.d.ts +9 -0
  397. package/dist/forms/effects/switch/switchMorph.js +22 -0
  398. package/dist/forms/effects/switch/switchMorph.schema.d.ts +1 -0
  399. package/dist/forms/effects/switch/switchMorph.schema.js +10 -0
  400. package/dist/forms/effects/switch/switchNeon.d.ts +11 -0
  401. package/dist/forms/effects/switch/switchNeon.js +53 -0
  402. package/dist/forms/effects/switch/switchNeon.schema.d.ts +1 -0
  403. package/dist/forms/effects/switch/switchNeon.schema.js +11 -0
  404. package/dist/forms/effects/switch/switchSlide.d.ts +7 -0
  405. package/dist/forms/effects/switch/switchSlide.js +11 -0
  406. package/dist/forms/effects/switch/switchSlide.schema.d.ts +1 -0
  407. package/dist/forms/effects/switch/switchSlide.schema.js +9 -0
  408. package/dist/forms/effects/switch/switchStretch.d.ts +9 -0
  409. package/dist/forms/effects/switch/switchStretch.js +21 -0
  410. package/dist/forms/effects/switch/switchStretch.schema.d.ts +1 -0
  411. package/dist/forms/effects/switch/switchStretch.schema.js +10 -0
  412. package/dist/forms/effects/valid/validAsync.d.ts +7 -0
  413. package/dist/forms/effects/valid/validAsync.js +36 -0
  414. package/dist/forms/effects/valid/validAsync.schema.d.ts +1 -0
  415. package/dist/forms/effects/valid/validAsync.schema.js +9 -0
  416. package/dist/forms/effects/valid/validBubble.d.ts +7 -0
  417. package/dist/forms/effects/valid/validBubble.js +61 -0
  418. package/dist/forms/effects/valid/validBubble.schema.d.ts +1 -0
  419. package/dist/forms/effects/valid/validBubble.schema.js +9 -0
  420. package/dist/forms/effects/valid/validCheck.d.ts +9 -0
  421. package/dist/forms/effects/valid/validCheck.js +50 -0
  422. package/dist/forms/effects/valid/validCheck.schema.d.ts +1 -0
  423. package/dist/forms/effects/valid/validCheck.schema.js +10 -0
  424. package/dist/forms/effects/valid/validColor.d.ts +11 -0
  425. package/dist/forms/effects/valid/validColor.js +28 -0
  426. package/dist/forms/effects/valid/validColor.schema.d.ts +1 -0
  427. package/dist/forms/effects/valid/validColor.schema.js +11 -0
  428. package/dist/forms/effects/valid/validFlash.d.ts +9 -0
  429. package/dist/forms/effects/valid/validFlash.js +36 -0
  430. package/dist/forms/effects/valid/validFlash.schema.d.ts +1 -0
  431. package/dist/forms/effects/valid/validFlash.schema.js +10 -0
  432. package/dist/forms/effects/valid/validMessage.d.ts +7 -0
  433. package/dist/forms/effects/valid/validMessage.js +24 -0
  434. package/dist/forms/effects/valid/validMessage.schema.d.ts +1 -0
  435. package/dist/forms/effects/valid/validMessage.schema.js +9 -0
  436. package/dist/forms/effects/valid/validShake.d.ts +9 -0
  437. package/dist/forms/effects/valid/validShake.js +37 -0
  438. package/dist/forms/effects/valid/validShake.schema.d.ts +1 -0
  439. package/dist/forms/effects/valid/validShake.schema.js +10 -0
  440. package/dist/forms/effects/valid/validSwap.d.ts +7 -0
  441. package/dist/forms/effects/valid/validSwap.js +33 -0
  442. package/dist/forms/effects/valid/validSwap.schema.d.ts +1 -0
  443. package/dist/forms/effects/valid/validSwap.schema.js +9 -0
  444. package/dist/forms/errors.d.ts +12 -0
  445. package/dist/forms/errors.js +20 -0
  446. package/dist/forms/file.d.ts +1 -0
  447. package/dist/forms/file.js +268 -0
  448. package/dist/forms/files.d.ts +7 -0
  449. package/dist/forms/files.js +29 -0
  450. package/dist/forms/formSteps.d.ts +9 -0
  451. package/dist/forms/formSteps.js +6 -0
  452. package/dist/forms/ids.d.ts +17 -0
  453. package/dist/forms/ids.js +13 -0
  454. package/dist/forms/inline.d.ts +3 -0
  455. package/dist/forms/inline.js +128 -0
  456. package/dist/forms/number.d.ts +1 -0
  457. package/dist/forms/number.js +67 -0
  458. package/dist/forms/otp.d.ts +4 -0
  459. package/dist/forms/otp.js +171 -0
  460. package/dist/forms/picker.d.ts +1 -0
  461. package/dist/forms/picker.js +303 -0
  462. package/dist/forms/range.d.ts +3 -0
  463. package/dist/forms/range.js +223 -0
  464. package/dist/forms/registry.d.ts +4 -0
  465. package/dist/forms/registry.js +133 -0
  466. package/dist/forms/reveal.d.ts +6 -0
  467. package/dist/forms/reveal.js +51 -0
  468. package/dist/forms/runtime/focus.d.ts +16 -0
  469. package/dist/forms/runtime/focus.js +55 -0
  470. package/dist/forms/runtime/listMatch.d.ts +2 -0
  471. package/dist/forms/runtime/listMatch.js +33 -0
  472. package/dist/forms/runtime/origin.d.ts +10 -0
  473. package/dist/forms/runtime/origin.js +25 -0
  474. package/dist/forms/runtime/placePopup.d.ts +10 -0
  475. package/dist/forms/runtime/placePopup.js +55 -0
  476. package/dist/forms/runtime/useFlip.d.ts +7 -0
  477. package/dist/forms/runtime/useFlip.js +38 -0
  478. package/dist/forms/runtime/useMorph.d.ts +8 -0
  479. package/dist/forms/runtime/useMorph.js +56 -0
  480. package/dist/forms/runtime/useOffScreen.d.ts +3 -0
  481. package/dist/forms/runtime/useOffScreen.js +16 -0
  482. package/dist/forms/runtime/useSwitchDrag.d.ts +8 -0
  483. package/dist/forms/runtime/useSwitchDrag.js +83 -0
  484. package/dist/forms/runtime/vanish.d.ts +6 -0
  485. package/dist/forms/runtime/vanish.js +185 -0
  486. package/dist/forms/steps.d.ts +1 -0
  487. package/dist/forms/steps.js +149 -0
  488. package/dist/forms/swap.d.ts +7 -0
  489. package/dist/forms/swap.js +149 -0
  490. package/dist/forms/switch.d.ts +1 -0
  491. package/dist/forms/switch.js +99 -0
  492. package/dist/forms/tools.d.ts +3 -0
  493. package/dist/forms/tools.js +248 -0
  494. package/dist/forms/types.d.ts +161 -0
  495. package/dist/forms/types.js +5 -0
  496. package/dist/index.d.ts +234 -0
  497. package/dist/index.js +119 -0
  498. package/dist/schema/forms.d.ts +3 -0
  499. package/dist/schema/forms.js +194 -0
  500. package/dist/schema/index.d.ts +2 -1
  501. package/dist/schema/index.js +3 -1
  502. package/dist/schema/types.d.ts +2 -2
  503. package/dist/schema/types.js +1 -0
  504. package/guides/README.md +62 -61
  505. package/guides/contact.md +100 -77
  506. package/guides/forms.md +105 -0
  507. package/package.json +1 -1
  508. package/styles/form.css +594 -0
  509. package/theme.css +6 -1
@@ -0,0 +1,219 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useId, useRef, useState } from "react";
4
+ import { styleHref } from "../../backgrounds/hosts/CssHost.js";
5
+ import { renderSvgElement } from "../../backgrounds/hosts/svgElement.js";
6
+ import { splitLabel } from "../../text/split.js";
7
+ import { motionOnly } from "../../transitions/progress.js";
8
+ import { FORM_BASE_CSS } from "../base.js";
9
+ import { fieldDescribedBy, fieldIds } from "../ids.js";
10
+ import { attachOrigin } from "../runtime/origin.js";
11
+ import { useOffScreen } from "../runtime/useOffScreen.js";
12
+ import { FORM_TOOLS_CSS, FORM_TOOLS_MOTION } from "../tools.js";
13
+ import { usePrograms } from "./choiceParts.js";
14
+ import { checkField } from "./fieldChecks.js";
15
+ import { effectList, filled, withUid } from "./shared.js";
16
+ import { CapsIcon, ClearButton, Counter, FIELD_LABELS, HintButton, RevealButton, StatusMark, Strength, setNativeValue } from "./fieldTools.js";
17
+ /** The effects' label plans as one. */
18
+ function mergePlans(effects) {
19
+ const plans = effects.flatMap((e) => (e.label ? [e.label] : []));
20
+ return plans.length > 0 ? Object.assign({}, ...plans) : undefined;
21
+ }
22
+ function Layer({ effect, layer, uid, label }) {
23
+ const attrs = {
24
+ "data-sx-field-layer": effect.id,
25
+ "data-sx-field-part": layer.part,
26
+ "data-sx-field-slot": layer.slot,
27
+ "data-sx-field-keep": layer.keep ? "" : undefined,
28
+ "aria-hidden": true,
29
+ };
30
+ if (layer.legend) {
31
+ return (_jsx("fieldset", { ...attrs, children: _jsx("legend", { children: _jsx("span", { children: label }) }) }));
32
+ }
33
+ return (_jsxs("span", { ...attrs, children: [layer.svg ? (_jsx("svg", { viewBox: layer.svg.viewBox, preserveAspectRatio: layer.svg.preserveAspectRatio, focusable: "false", children: layer.svg.children.map((el, i) => renderSvgElement(el, uid, i, "data-sx-field-svg")) })) : null, layer.children?.map((part) => _jsx("span", { "data-sx-field-part": part }, part)), layer.lines?.map((line, i) => (_jsx("span", { "data-sx-field-part": "line", style: { "--sx-field-i": i }, children: line }, i))), layer.text ?? (layer.copy ? label : null)] }));
34
+ }
35
+ /** Every layer of these effects in one slot, in the effects' order. */
36
+ function layersIn(effects, slot, uid, label) {
37
+ return effects.flatMap((effect) => effect.layers.filter((l) => l.slot === slot).map((layer, i) => _jsx(Layer, { effect: effect, layer: layer, uid: uid, label: label }, `${effect.id}-${i}`)));
38
+ }
39
+ /** The label's words: plain, in a span, or cut into letters with one copy for screen readers. */
40
+ function LabelText({ plan, text, children }) {
41
+ if (plan?.split && text !== undefined) {
42
+ return (_jsxs("span", { "data-sx-field-text": "", children: [_jsx("span", { "data-sx-field-sr": "", children: text }), _jsx("span", { "data-sx-field-chars": "", dir: "auto", "aria-hidden": true, children: splitLabel(text).map((piece, i) => (_jsx("span", { "data-sx-field-char": "", style: { "--sx-field-i": i }, children: piece }, i))) })] }));
43
+ }
44
+ return plan?.wrap || plan?.split ? _jsx("span", { "data-sx-field-text": "", children: children }) : _jsx(_Fragment, { children: children });
45
+ }
46
+ /**
47
+ * A text field (input or textarea) that wears any number of effects. The real input does all the work: every prop and
48
+ * the `ref` go on it, and the effects only paint around it, reading its state from CSS.
49
+ *
50
+ * ```tsx
51
+ * <Field label="Email" type="email" effect={[inputFloat(), inputUnderline()]} {...register("email")}
52
+ * error={errors.email?.message} />
53
+ * ```
54
+ */
55
+ export function Field(props) {
56
+ const { as, label, description, error, invalid, icon, end, busy, clearable, reveal, capsLock, counter, strength, status, hint, grow, labels, effect, focusRing, inline, variant = "outline", unstyled, className, rootClassName, labelClassName, style, id: ownId, placeholder, required, ...rest } = props;
57
+ const Control = as ?? "input";
58
+ const effects = effectList(effect);
59
+ const words = { ...FIELD_LABELS, ...labels };
60
+ const type = rest.type;
61
+ const auto = useId();
62
+ const id = ownId ?? `sx-field${auto.replace(/[^\w-]/g, "")}`;
63
+ const ids = fieldIds(id);
64
+ const hintId = `${id}-hint`;
65
+ const hasError = filled(error);
66
+ const ownInvalid = rest["aria-invalid"];
67
+ const isInvalid = hasError || invalid === true || status === "invalid" || ownInvalid === true || ownInvalid === "true";
68
+ const own = [filled(hint) ? hintId : "", rest["aria-describedby"] ?? ""].filter(Boolean).join(" ") || undefined;
69
+ const describedBy = fieldDescribedBy(ids, { error: hasError, description: filled(description), own });
70
+ const plan = mergePlans(effects);
71
+ const text = typeof label === "string" ? label : undefined;
72
+ const root = useRef(null);
73
+ const box = useRef(null);
74
+ const hintBox = useRef(null);
75
+ const control = () => root.current?.querySelector("[data-sx-field-control]") ?? null;
76
+ const origin = effects.some((e) => e.needs.origin);
77
+ useEffect(() => {
78
+ if (!origin || !root.current || !box.current)
79
+ return;
80
+ return attachOrigin(root.current, box.current);
81
+ }, [origin]);
82
+ useOffScreen(root, effects.some((e) => e.needs.inView));
83
+ usePrograms(root, effects);
84
+ // --- the counter: the length, read from the input as it changes (also after a form reset or a value set in code) ---
85
+ const counted = counter !== undefined && counter !== false;
86
+ const limit = counter === true ? rest.maxLength : typeof counter === "number" ? counter : undefined;
87
+ if (process.env.NODE_ENV !== "production") {
88
+ checkField({
89
+ effects, plan, as, type, hasError, status, reveal, counter, limit, grow, focusRing,
90
+ labelled: filled(label) || !!rest["aria-label"] || !!rest["aria-labelledby"],
91
+ labelIsText: text !== undefined,
92
+ });
93
+ }
94
+ const [length, setLength] = useState(() => String(rest.value ?? rest.defaultValue ?? "").length);
95
+ useEffect(() => {
96
+ const el = control();
97
+ if (!counted || !el)
98
+ return;
99
+ const sync = () => setLength(el.value.length);
100
+ const later = () => setTimeout(sync);
101
+ el.addEventListener("input", sync);
102
+ el.form?.addEventListener("reset", later);
103
+ return () => {
104
+ el.removeEventListener("input", sync);
105
+ el.form?.removeEventListener("reset", later);
106
+ };
107
+ }, [counted]);
108
+ useEffect(() => {
109
+ const el = control();
110
+ if (counted && el)
111
+ setLength(el.value.length);
112
+ });
113
+ const left = limit === undefined ? 0 : limit - length;
114
+ const near = limit !== undefined && left <= Math.max(10, Math.round(limit * 0.1));
115
+ const [said, setSaid] = useState("");
116
+ useEffect(() => {
117
+ if (limit === undefined)
118
+ return;
119
+ // read out once the typing stops, and only near the limit: every keystroke would drown the screen reader
120
+ const next = left < 0 ? words.over.replace("{n}", String(-left)) : near ? words.left.replace("{n}", String(left)) : "";
121
+ const timer = setTimeout(() => setSaid(next), 700);
122
+ return () => clearTimeout(timer);
123
+ }, [limit, left, near, words.over, words.left]);
124
+ // --- show password: the type flips, the caret stays where it was, and a submit hides it again ---
125
+ const [shown, setShown] = useState(false);
126
+ const caret = useRef(null);
127
+ const toggle = () => {
128
+ const el = control();
129
+ if (el)
130
+ caret.current = [el.selectionStart, el.selectionEnd];
131
+ setShown((s) => !s);
132
+ };
133
+ useEffect(() => {
134
+ const el = control();
135
+ const at = caret.current;
136
+ if (!el || !at)
137
+ return;
138
+ caret.current = null;
139
+ try {
140
+ el.setSelectionRange(at[0], at[1]);
141
+ }
142
+ catch {
143
+ // a type without a selection
144
+ }
145
+ }, [shown]);
146
+ useEffect(() => {
147
+ const form = reveal ? control()?.form : undefined;
148
+ if (!form)
149
+ return;
150
+ const hide = () => setShown(false);
151
+ form.addEventListener("submit", hide);
152
+ return () => form.removeEventListener("submit", hide);
153
+ }, [reveal]);
154
+ // --- Caps Lock: read from each key, forgotten when the field loses the focus ---
155
+ const caps = capsLock ?? type === "password";
156
+ const [capsOn, setCapsOn] = useState(false);
157
+ const readCaps = (e) => setCapsOn(e.getModifierState("CapsLock"));
158
+ const capsHandlers = caps
159
+ ? {
160
+ onKeyDown: (e) => {
161
+ readCaps(e);
162
+ rest.onKeyDown?.(e);
163
+ },
164
+ onKeyUp: (e) => {
165
+ readCaps(e);
166
+ rest.onKeyUp?.(e);
167
+ },
168
+ onBlur: (e) => {
169
+ setCapsOn(false);
170
+ rest.onBlur?.(e);
171
+ },
172
+ }
173
+ : {};
174
+ // --- the hint: popover="hint" where it exists, else "auto" (it closes on a click outside too, but also closes other
175
+ // popovers). Anchor positioning places it; without that, the tools sheet docks it at the bottom of the screen ---
176
+ const hinted = filled(hint);
177
+ useEffect(() => {
178
+ const el = hintBox.current;
179
+ if (el && el.popover !== "hint")
180
+ el.popover = "auto";
181
+ }, [hinted]);
182
+ // ids for filters and gradients inside layers, unique per field and valid in url(#…)
183
+ const uid = `sx${auto.replace(/[^\w-]/g, "")}`;
184
+ const fills = layersIn(effects, "fill", uid, label);
185
+ const ends = layersIn(effects, "end", uid, label);
186
+ const keepFill = effects.some((e) => e.layers.some((l) => l.slot === "fill" && l.keep));
187
+ const level = strength === undefined ? undefined : Math.max(0, Math.min(4, Math.round(strength)));
188
+ const vars = {
189
+ ...withUid(Object.assign({}, ...effects.map((e) => e.vars)), uid),
190
+ ...(limit === undefined ? {} : { "--sx-field-used": Math.max(0, Math.min(1, length / limit)) }),
191
+ ...(grow ? { "--sx-field-rows": rest.rows ?? 2, ...(typeof grow === "number" ? { "--sx-field-rows-max": grow } : {}) } : {}),
192
+ ...style,
193
+ };
194
+ const hasEnd = ends.length > 0 || status || counted || clearable || reveal || hinted || filled(end);
195
+ const controlProps = {
196
+ ...rest,
197
+ ...capsHandlers,
198
+ id,
199
+ type: reveal && shown ? "text" : type,
200
+ "data-sx-field-control": "",
201
+ // a floating label needs :placeholder-shown, and an empty field shows a placeholder only when it has one
202
+ placeholder: placeholder ?? " ",
203
+ required,
204
+ "aria-required": required || undefined,
205
+ "aria-invalid": isInvalid || undefined,
206
+ "aria-describedby": describedBy,
207
+ "aria-busy": busy || undefined,
208
+ };
209
+ return (_jsxs(_Fragment, { children: [_jsx("style", { href: styleHref("form-base", FORM_BASE_CSS), precedence: "sx", children: FORM_BASE_CSS }), _jsx("style", { href: styleHref("form-tools", FORM_TOOLS_CSS), precedence: "sx", children: FORM_TOOLS_CSS }), _jsx("style", { href: styleHref("form-tools-motion", FORM_TOOLS_MOTION), precedence: "sx", children: motionOnly(FORM_TOOLS_MOTION) }), effects.filter((e) => e.css).map((e) => {
210
+ const css = motionOnly(e.css);
211
+ return (_jsx("style", { href: styleHref(`form-${e.id}`, css), precedence: "sx", children: css }, e.id));
212
+ }), effects.filter((e) => e.stateCss).map((e) => (_jsx("style", { href: styleHref(`form-${e.id}-state`, e.stateCss), precedence: "sx", children: e.stateCss }, e.id))), _jsxs("div", { ref: root, "data-sx-field": effects.map((e) => e.id).join(" "), "data-sx-styled": unstyled ? undefined : "", "data-sx-variant": unstyled ? undefined : variant, "data-sx-status": status, "data-sx-strength": level, "data-sx-count": near ? (left < 0 ? "over" : "near") : undefined, "data-sx-revealed": reveal && shown ? "" : undefined, "data-sx-field-grow": grow ? "" : undefined, "data-sx-ring": focusRing === "auto" ? undefined : focusRing, "data-sx-inline": inline ? "" : undefined, className: rootClassName, style: vars, children: [filled(label) ? (_jsxs("label", { "data-sx-field-label": "", id: ids.label, htmlFor: id, className: labelClassName, children: [_jsx(LabelText, { plan: plan, text: text, children: label }), layersIn(effects, "label", uid, label)] })) : null, layersIn(effects, "behind", uid, label), _jsxs("div", { ref: box, "data-sx-field-box": "", className: className, children: [layersIn(effects, "under", uid, label), fills.length > 0 ? (_jsx("span", { "data-sx-field-clip": "", "data-sx-field-keep": keepFill ? "" : undefined, "aria-hidden": true, children: fills })) : null, filled(icon) ? (_jsx("span", { "data-sx-field-icon": "", "aria-hidden": true, children: icon })) : null, _jsx(Control, { ...controlProps }), hasEnd ? (_jsxs("span", { "data-sx-field-end": "", children: [ends, status ? _jsx(StatusMark, {}) : null, counted ? (_jsx(Counter, { used: length, limit: limit, children: layersIn(effects, "counter", uid, label) })) : null, clearable ? (_jsx(ClearButton, { label: words.clear, controls: id, onClick: () => {
213
+ const el = control();
214
+ if (!el)
215
+ return;
216
+ setNativeValue(el, "");
217
+ el.focus();
218
+ } })) : null, reveal ? _jsx(RevealButton, { label: words.show, controls: id, pressed: shown, onClick: toggle }) : null, hinted ? _jsx(HintButton, { label: words.hint, target: hintId, anchor: `--${uid}-hint` }) : null, end] })) : null, layersIn(effects, "edge", uid, label)] }), level === undefined ? null : _jsx(Strength, { level: level, text: words.strength.replace("{level}", words.levels[level] ?? "") }), filled(description) ? (_jsx("p", { "data-sx-field-description": "", id: ids.description, children: description })) : null, caps ? (_jsx("p", { "data-sx-field-note": "", role: "status", children: capsOn ? (_jsxs("span", { children: [_jsx(CapsIcon, {}), words.capsLock] })) : null })) : null, _jsx("div", { "data-sx-field-message": "", children: _jsx("p", { "data-sx-field-error": "", id: ids.error, role: "alert", children: hasError ? (_jsx("span", { "data-sx-field-says": "", children: error }, typeof error === "string" ? error : undefined)) : null }) }), hinted ? (_jsx("div", { ref: hintBox, id: hintId, popover: "hint", "data-sx-field-hint": "", style: { positionAnchor: `--${uid}-hint` }, children: hint })) : null, limit === undefined ? null : (_jsx("span", { "data-sx-field-sr": "", role: "status", children: said })), status ? (_jsx("span", { "data-sx-field-sr": "", role: "status", children: status === "checking" ? words.checking : status === "valid" ? words.valid : "" })) : null] })] }));
219
+ }
@@ -0,0 +1,81 @@
1
+ import { type CSSProperties, type FocusEvent, type ReactNode, type Ref } from "react";
2
+ import type { FormEffect } from "../types.js";
3
+ /** The words a FileDrop says, for your language. `{name}` is a file's name, `{n}` a number, `{max}` a size. */
4
+ export interface FileDropLabels {
5
+ readonly drop?: string;
6
+ readonly page?: string;
7
+ readonly list?: string;
8
+ readonly remove?: string;
9
+ readonly up?: string;
10
+ readonly down?: string;
11
+ readonly added?: string;
12
+ readonly removed?: string;
13
+ readonly moved?: string;
14
+ readonly uploaded?: string;
15
+ readonly tooBig?: string;
16
+ readonly wrongType?: string;
17
+ readonly tooMany?: string;
18
+ readonly twice?: string;
19
+ }
20
+ export interface FileDropProps {
21
+ /** The visible label: a real `<label for>` on the file input. */
22
+ readonly label?: ReactNode;
23
+ /** Help under the zone: what it takes ("PDF or images, up to 5 MB"). */
24
+ readonly description?: ReactNode;
25
+ /** The error message (the app's). Without one, the zone's own refusals show here. */
26
+ readonly error?: ReactNode;
27
+ readonly invalid?: boolean;
28
+ /** The files, when you hold them (a `Controller`'s `field.value`). */
29
+ readonly value?: readonly File[];
30
+ readonly defaultValue?: readonly File[];
31
+ /** Called with every file after a change: `field.onChange` fits. */
32
+ readonly onChange?: (files: File[]) => void;
33
+ readonly onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
34
+ /** Submitted with a plain form: the real input carries every file in the list. */
35
+ readonly name?: string;
36
+ readonly id?: string;
37
+ /** Goes on the real file input (React Hook Form focuses it on an error). */
38
+ readonly ref?: Ref<HTMLInputElement>;
39
+ readonly disabled?: boolean;
40
+ readonly required?: boolean;
41
+ /** As on a file input: `"image/*,.pdf"`. Anything else is refused, with words. */
42
+ readonly accept?: string;
43
+ /** The largest file, in bytes. */
44
+ readonly maxSize?: number;
45
+ /** The most files. Default: no limit, or 1 without `multiple`. */
46
+ readonly maxFiles?: number;
47
+ /** Several files (a new one adds); `false`: one (a new one replaces it). Default `true`. */
48
+ readonly multiple?: boolean;
49
+ /** Files dragged anywhere over the page land here, under an overlay that says so. */
50
+ readonly page?: boolean;
51
+ /** Up and down buttons on each card, to set the order. */
52
+ readonly reorder?: boolean;
53
+ /** How far each file's upload has got, 0 to 1 (1: done, a check shows). You upload; this shows it. */
54
+ readonly progress?: (file: File) => number | undefined;
55
+ /** The zone's icon. */
56
+ readonly icon?: ReactNode;
57
+ /** The language for file sizes. Default the visitor's. */
58
+ readonly locale?: string;
59
+ readonly effect?: FormEffect | readonly FormEffect[];
60
+ readonly labels?: FileDropLabels;
61
+ readonly unstyled?: boolean;
62
+ /** Goes on the drop zone. */
63
+ readonly className?: string;
64
+ readonly rootClassName?: string;
65
+ readonly labelClassName?: string;
66
+ readonly style?: CSSProperties;
67
+ }
68
+ /**
69
+ * A drop zone round the real file input. Drop files on it, or press its button (the browser's own, from the keyboard
70
+ * too) to pick them; each lands in a list of cards with its name, size and a remove button (with `reorder`, up and down
71
+ * too). It checks `accept`, `maxSize`, `maxFiles` and twins (same name and size) before a file gets in, and says why one
72
+ * didn't. The files are the value: hold them with `value` / `onChange` (a `Controller`), upload them yourself, and pass
73
+ * `progress`. The real input always carries the whole list, so a plain form submits them.
74
+ *
75
+ * ```tsx
76
+ * <Controller name="files" control={control} render={({ field }) => (
77
+ * <FileDrop label="Attachments" accept="image/*,.pdf" maxSize={5e6} effect={[fileDrag(), fileCards()]} {...field} />
78
+ * )} />
79
+ * ```
80
+ */
81
+ export declare function FileDrop(props: FileDropProps): import("react").JSX.Element;
@@ -0,0 +1,328 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useMemo, useRef, useState } from "react";
4
+ import { warnOnce } from "../../buttons/runtime/dev.js";
5
+ import { renderSvgElement } from "../../backgrounds/hosts/svgElement.js";
6
+ import { FILE_CSS } from "../file.js";
7
+ import { accepts, fileSize } from "../files.js";
8
+ import { fieldDescribedBy, fieldIds } from "../ids.js";
9
+ import { useFlip } from "../runtime/useFlip.js";
10
+ import { EffectSheets, usePrograms } from "./choiceParts.js";
11
+ import { effectList, filled, withUid } from "./shared.js";
12
+ const WORDS = {
13
+ drop: "Drop files here, or",
14
+ page: "Drop to add",
15
+ list: "Chosen files",
16
+ remove: "Remove {name}",
17
+ up: "Move {name} up",
18
+ down: "Move {name} down",
19
+ added: "Added: {name}",
20
+ removed: "{name} removed",
21
+ moved: "{name} moved to place {n}",
22
+ uploaded: "{name} uploaded",
23
+ tooBig: "{name} is larger than {max}.",
24
+ wrongType: "{name} isn't a kind of file this takes.",
25
+ tooMany: "Only {n} files can be added.",
26
+ twice: "{name} is already here.",
27
+ };
28
+ const twin = (a, b) => a.name === b.name && a.size === b.size;
29
+ /** Dragged items' types, where the browser tells them during the drag (Chromium and Firefox; Safari says only "Files"). */
30
+ const draggedTypes = (e) => [...(e.dataTransfer?.items ?? [])].filter((i) => i.kind === "file").map((i) => i.type);
31
+ const hasFiles = (e) => [...(e.dataTransfer?.types ?? [])].includes("Files");
32
+ const Icon = ({ children }) => (_jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": true, focusable: "false", children: children }));
33
+ const UPLOAD = _jsx(Icon, { children: _jsx("path", { d: "M12 15V4m0 0L7.5 8.5M12 4l4.5 4.5M4.5 15v3.5a1.5 1.5 0 0 0 1.5 1.5h12a1.5 1.5 0 0 0 1.5-1.5V15" }) });
34
+ const DOC = _jsx(Icon, { children: _jsx("path", { d: "M14 3.5H7A1.5 1.5 0 0 0 5.5 5v14A1.5 1.5 0 0 0 7 20.5h10a1.5 1.5 0 0 0 1.5-1.5V8L14 3.5ZM14 3.5V8h4.5" }) });
35
+ function Layers({ effects, slot, uid }) {
36
+ return (_jsx(_Fragment, { children: effects.flatMap((e) => e.layers
37
+ .filter((l) => l.slot === slot)
38
+ .map((l, i) => (_jsx("span", { "data-sx-file-layer": e.id, "data-sx-file-part": l.part, "data-sx-file-keep": l.keep ? "" : undefined, "aria-hidden": true, children: l.svg ? (_jsx("svg", { viewBox: l.svg.viewBox, focusable: "false", children: l.svg.children.map((el, k) => renderSvgElement(el, uid, k, "data-sx-file-svg")) })) : null }, `${e.id}-${i}`)))) }));
39
+ }
40
+ /**
41
+ * A drop zone round the real file input. Drop files on it, or press its button (the browser's own, from the keyboard
42
+ * too) to pick them; each lands in a list of cards with its name, size and a remove button (with `reorder`, up and down
43
+ * too). It checks `accept`, `maxSize`, `maxFiles` and twins (same name and size) before a file gets in, and says why one
44
+ * didn't. The files are the value: hold them with `value` / `onChange` (a `Controller`), upload them yourself, and pass
45
+ * `progress`. The real input always carries the whole list, so a plain form submits them.
46
+ *
47
+ * ```tsx
48
+ * <Controller name="files" control={control} render={({ field }) => (
49
+ * <FileDrop label="Attachments" accept="image/*,.pdf" maxSize={5e6} effect={[fileDrag(), fileCards()]} {...field} />
50
+ * )} />
51
+ * ```
52
+ */
53
+ export function FileDrop(props) {
54
+ const { label, description, error, invalid, value, defaultValue, onChange, onBlur, name, id: ownId, ref, disabled, required, accept, maxSize, maxFiles, multiple = true, page, reorder, progress, icon, locale, effect, labels, unstyled, className, rootClassName, labelClassName, style, } = props;
55
+ const effects = effectList(effect);
56
+ const words = { ...WORDS, ...labels };
57
+ const auto = useId().replace(/[^\w-]/g, "");
58
+ const id = ownId ?? `sx-file${auto}`;
59
+ const uid = `sx${auto}`;
60
+ const ids = fieldIds(id);
61
+ const hintId = `${id}-hint`;
62
+ if (process.env.NODE_ENV !== "production") {
63
+ for (const e of effects)
64
+ if (!e.fits.includes("file"))
65
+ warnOnce(`the effect ${e.id} is not made for a FileDrop: it fits ${e.fits.join(", ")}.`);
66
+ if (!filled(label))
67
+ warnOnce("a FileDrop has no label: give it `label`.");
68
+ if (effects.some((e) => e.id === "filePage") && !page)
69
+ warnOnce("filePage animates the page-wide overlay: give the FileDrop `page`.");
70
+ }
71
+ const controlled = value !== undefined;
72
+ const [held, setHeld] = useState(() => defaultValue ?? []);
73
+ const files = controlled ? value : held;
74
+ const [leaving, setLeaving] = useState([]);
75
+ const [refusal, setRefusal] = useState(null);
76
+ const [said, setSaid] = useState("");
77
+ const [over, setOver] = useState(null);
78
+ const [pageOver, setPageOver] = useState(false);
79
+ const [shake, setShake] = useState(false);
80
+ const [live, setLive] = useState(false);
81
+ const root = useRef(null);
82
+ const list = useRef(null);
83
+ const input = useRef(null);
84
+ const flips = effects.some((e) => e.needs.flip);
85
+ const previews = effects.some((e) => e.needs.preview);
86
+ const limit = maxFiles ?? (multiple ? Infinity : 1);
87
+ useFlip(list, flips, "[data-sx-file-card]");
88
+ usePrograms(root, effects);
89
+ const say = (s) => setSaid((now) => (now === s ? `${s} ` : s));
90
+ /** The real input carries every file in the list, for a plain form submit. */
91
+ const carry = (next) => {
92
+ const el = input.current;
93
+ if (!el || typeof DataTransfer === "undefined")
94
+ return;
95
+ try {
96
+ const dt = new DataTransfer();
97
+ for (const f of next)
98
+ dt.items.add(f);
99
+ el.files = dt.files;
100
+ }
101
+ catch {
102
+ // an engine that can't set files: the list is still the value
103
+ }
104
+ };
105
+ const set = (next) => {
106
+ if (!controlled)
107
+ setHeld(next);
108
+ carry(next);
109
+ onChange?.(next);
110
+ };
111
+ const add = (incoming) => {
112
+ if (disabled || incoming.length === 0)
113
+ return;
114
+ setLive(true);
115
+ const took = [];
116
+ const why = [];
117
+ const max = maxSize === undefined ? "" : fileSize(maxSize, locale);
118
+ for (const f of incoming) {
119
+ if (!accepts(f, accept))
120
+ why.push(words.wrongType.replace("{name}", f.name));
121
+ else if (maxSize !== undefined && f.size > maxSize)
122
+ why.push(words.tooBig.replace("{name}", f.name).replace("{max}", max));
123
+ else if (multiple && [...files, ...took].some((g) => twin(f, g)))
124
+ why.push(words.twice.replace("{name}", f.name));
125
+ else
126
+ took.push(f);
127
+ }
128
+ const room = multiple ? Math.max(0, limit - files.length) : 1;
129
+ if (took.length > room) {
130
+ why.push(words.tooMany.replace("{n}", String(limit)));
131
+ took.length = room;
132
+ }
133
+ const next = multiple ? [...files, ...took] : took.length > 0 ? took : [...files];
134
+ if (!multiple && took.length > 0 && files[0] && flips)
135
+ setLeaving((l) => [...l, files[0]]);
136
+ if (took.length > 0)
137
+ set(next);
138
+ else
139
+ carry(files);
140
+ setRefusal(why.length > 0 ? why.join(" ") : null);
141
+ if (why.length > 0) {
142
+ // a frame without the mark, so a second refusal shakes again
143
+ setShake(false);
144
+ requestAnimationFrame(() => setShake(true));
145
+ }
146
+ say([took.length > 0 ? words.added.replace("{name}", took.map((f) => f.name).join(", ")) : "", ...why].filter(Boolean).join(" "));
147
+ };
148
+ const remove = (at) => {
149
+ const gone = files[at];
150
+ if (!gone)
151
+ return;
152
+ setLive(true);
153
+ if (flips)
154
+ setLeaving((l) => [...l, gone]);
155
+ const next = files.filter((_, i) => i !== at);
156
+ set(next);
157
+ setRefusal(null);
158
+ say(words.removed.replace("{name}", gone.name));
159
+ // the focus goes to the card now in its place, or back to the input
160
+ requestAnimationFrame(() => {
161
+ const cards = list.current?.querySelectorAll("[data-sx-file-card]:not([data-sx-leaving]) [data-sx-file-remove]");
162
+ (cards?.[Math.min(at, next.length - 1)] ?? input.current)?.focus();
163
+ });
164
+ };
165
+ const move = (at, by) => {
166
+ const to = at + by;
167
+ if (to < 0 || to >= files.length)
168
+ return;
169
+ const next = [...files];
170
+ [next[at], next[to]] = [next[to], next[at]];
171
+ set(next);
172
+ say(words.moved.replace("{name}", files[at].name).replace("{n}", String(to + 1)));
173
+ };
174
+ useEffect(() => {
175
+ if (!shake)
176
+ return;
177
+ const t = setTimeout(() => setShake(false), 500);
178
+ return () => clearTimeout(t);
179
+ }, [shake]);
180
+ // a value set by the app (a Controller, a reset) is carried by the input too
181
+ useEffect(() => carry(files), [files]); // eslint-disable-line react-hooks/exhaustive-deps
182
+ useEffect(() => {
183
+ const form = input.current?.form;
184
+ if (!form || controlled)
185
+ return;
186
+ const reset = () => setTimeout(() => setHeld([]));
187
+ form.addEventListener("reset", reset);
188
+ return () => form.removeEventListener("reset", reset);
189
+ }, [controlled]);
190
+ // cards leaving: gone once their animation ends (at once when nothing animates them)
191
+ useEffect(() => {
192
+ for (const card of list.current?.querySelectorAll("[data-sx-leaving]") ?? []) {
193
+ const key = card.dataset.key;
194
+ const drop = () => setLeaving((l) => l.filter((f) => keyOf(f) !== key));
195
+ if (getComputedStyle(card).animationName === "none")
196
+ drop();
197
+ else
198
+ card.addEventListener("animationend", drop, { once: true });
199
+ }
200
+ }, [leaving]); // eslint-disable-line react-hooks/exhaustive-deps
201
+ // pictures: an object URL each, let go when the file leaves the list or the zone unmounts
202
+ const urls = useRef(new Map());
203
+ const shown = useMemo(() => [...files, ...leaving.filter((f) => !files.includes(f))], [files, leaving]);
204
+ const picture = (f) => {
205
+ if (!previews || !f.type.startsWith("image/") || typeof URL === "undefined")
206
+ return undefined;
207
+ let url = urls.current.get(f);
208
+ if (!url) {
209
+ url = URL.createObjectURL(f);
210
+ urls.current.set(f, url);
211
+ }
212
+ return url;
213
+ };
214
+ useEffect(() => {
215
+ for (const [f, url] of urls.current) {
216
+ if (!shown.includes(f)) {
217
+ URL.revokeObjectURL(url);
218
+ urls.current.delete(f);
219
+ }
220
+ }
221
+ }, [shown]);
222
+ useEffect(() => () => urls.current.forEach((url) => URL.revokeObjectURL(url)), []);
223
+ // the whole page takes a drop: an overlay says so while files are dragged over the window
224
+ useEffect(() => {
225
+ if (!page)
226
+ return;
227
+ let depth = 0;
228
+ const enter = (e) => {
229
+ if (!hasFiles(e))
230
+ return;
231
+ depth++;
232
+ setPageOver(true);
233
+ };
234
+ const leave = () => {
235
+ depth = Math.max(0, depth - 1);
236
+ if (depth === 0)
237
+ setPageOver(false);
238
+ };
239
+ const overPage = (e) => {
240
+ if (hasFiles(e))
241
+ e.preventDefault();
242
+ };
243
+ const drop = (e) => {
244
+ if (!hasFiles(e))
245
+ return;
246
+ e.preventDefault();
247
+ depth = 0;
248
+ setPageOver(false);
249
+ setOver(null);
250
+ if (!root.current?.querySelector("[data-sx-file-zone]")?.contains(e.target))
251
+ add([...(e.dataTransfer?.files ?? [])]);
252
+ };
253
+ window.addEventListener("dragenter", enter);
254
+ window.addEventListener("dragleave", leave);
255
+ window.addEventListener("dragover", overPage);
256
+ window.addEventListener("drop", drop);
257
+ return () => {
258
+ window.removeEventListener("dragenter", enter);
259
+ window.removeEventListener("dragleave", leave);
260
+ window.removeEventListener("dragover", overPage);
261
+ window.removeEventListener("drop", drop);
262
+ };
263
+ });
264
+ const zoneDrag = {
265
+ onDragEnter: (e) => {
266
+ if (!hasFiles(e) || disabled)
267
+ return;
268
+ e.preventDefault();
269
+ const types = draggedTypes(e);
270
+ setOver(types.length > 0 && types.every((t) => t) && !types.some((t) => accepts({ name: "", type: t }, accept)) ? "reject" : "ok");
271
+ },
272
+ onDragOver: (e) => {
273
+ if (!hasFiles(e) || disabled)
274
+ return;
275
+ e.preventDefault();
276
+ if (e.dataTransfer)
277
+ e.dataTransfer.dropEffect = "copy";
278
+ },
279
+ onDragLeave: (e) => {
280
+ if (!e.currentTarget.contains(e.relatedTarget))
281
+ setOver(null);
282
+ },
283
+ onDrop: (e) => {
284
+ if (!hasFiles(e))
285
+ return;
286
+ e.preventDefault();
287
+ setOver(null);
288
+ if (page)
289
+ setPageOver(false);
290
+ add([...(e.dataTransfer?.files ?? [])]);
291
+ },
292
+ };
293
+ const setRef = (el) => {
294
+ input.current = el;
295
+ if (typeof ref === "function")
296
+ ref(el);
297
+ else if (ref)
298
+ ref.current = el;
299
+ };
300
+ const hasError = filled(error);
301
+ const message = hasError ? error : refusal;
302
+ const isInvalid = hasError || invalid === true;
303
+ const describedBy = [hintId, fieldDescribedBy(ids, { error: filled(message), description: filled(description) })].filter(Boolean).join(" ");
304
+ const vars = { ...withUid(Object.assign({}, ...effects.map((e) => e.vars)), uid), ...style };
305
+ return (_jsxs(_Fragment, { children: [_jsx(EffectSheets, { name: "form-file", base: FILE_CSS, effects: effects }), _jsxs("div", { ref: root, "data-sx-file": effects.map((e) => e.id).join(" "), "data-sx-styled": unstyled ? undefined : "", "data-sx-over": over ?? undefined, "data-sx-page-over": pageOver ? "" : undefined, "data-sx-rejected": shake ? "" : undefined, "data-sx-live": live ? "" : undefined, className: rootClassName, style: vars, children: [filled(label) ? (_jsx("label", { "data-sx-file-label": "", id: ids.label, htmlFor: id, className: labelClassName, children: label })) : null, _jsxs("div", { "data-sx-file-zone": "", className: className, ...zoneDrag, onClick: (e) => {
306
+ // the whole zone opens the picker; the input's own button does so by itself
307
+ if (e.target !== input.current && !disabled)
308
+ input.current?.click();
309
+ }, children: [_jsx(Layers, { effects: effects, slot: "zone", uid: uid }), _jsx("span", { "data-sx-file-icon": "", "aria-hidden": true, children: icon ?? UPLOAD }), _jsx("span", { "data-sx-file-hint": "", id: hintId, children: words.drop }), _jsx("input", { ref: setRef, id: id, type: "file", name: name, accept: accept, multiple: multiple, disabled: disabled, "data-sx-file-control": "", "aria-invalid": isInvalid || filled(refusal) || undefined, "aria-required": required || undefined, "aria-describedby": describedBy, onChange: (e) => add([...(e.target.files ?? [])]), onBlur: onBlur })] }), filled(description) ? (_jsx("p", { "data-sx-file-description": "", id: ids.description, children: description })) : null, shown.length > 0 ? (_jsx("ul", { ref: list, "data-sx-file-list": "", "aria-label": words.list, children: shown.map((f) => {
310
+ const at = files.indexOf(f);
311
+ const gone = at === -1;
312
+ const p = gone ? undefined : progress?.(f);
313
+ const done = p !== undefined && p >= 1;
314
+ const src = picture(f);
315
+ return (_jsxs("li", { "data-key": keyOf(f), "data-sx-file-card": "", "data-sx-leaving": gone ? "" : undefined, "data-sx-done": done ? "" : undefined, "data-sx-uploading": p !== undefined && !done ? "" : undefined, style: { "--sx-file-progress": p ?? 0, "--sx-file-i": at }, children: [_jsx(Layers, { effects: effects, slot: "card", uid: uid }), _jsx("span", { "data-sx-file-thumb": "", "aria-hidden": true, children: src ? _jsx("img", { src: src, alt: "", onLoad: (e) => e.currentTarget.setAttribute("data-sx-loaded", "") }) : DOC }), _jsxs("span", { "data-sx-file-info": "", children: [_jsx("span", { "data-sx-file-name": "", children: f.name }), _jsx("span", { "data-sx-file-size": "", children: fileSize(f.size, locale) }), p !== undefined ? (_jsx("span", { "data-sx-file-bar": "", role: "progressbar", "aria-label": f.name, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(Math.min(1, p) * 100), children: _jsx("span", { "data-sx-file-fill": "" }) })) : null] }), _jsx("span", { "data-sx-file-done": "", "aria-hidden": true, children: _jsx(Icon, { children: _jsx("path", { d: "m5 12.5 4.5 4.5L19 7.5", pathLength: 1 }) }) }), _jsxs("span", { "data-sx-file-actions": "", children: [reorder ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "data-sx-file-up": "", "aria-label": words.up.replace("{name}", f.name), disabled: gone || disabled || at === 0, onClick: () => move(at, -1), children: _jsx(Icon, { children: _jsx("path", { d: "m6 14 6-6 6 6" }) }) }), _jsx("button", { type: "button", "data-sx-file-down": "", "aria-label": words.down.replace("{name}", f.name), disabled: gone || disabled || at === files.length - 1, onClick: () => move(at, 1), children: _jsx(Icon, { children: _jsx("path", { d: "m6 10 6 6 6-6" }) }) })] })) : null, _jsx("button", { type: "button", "data-sx-file-remove": "", "aria-label": words.remove.replace("{name}", f.name), disabled: disabled, tabIndex: gone ? -1 : undefined, onClick: () => remove(at), children: _jsx(Icon, { children: _jsx("path", { d: "m7 7 10 10M17 7 7 17" }) }) })] })] }, keyOf(f)));
316
+ }) })) : null, _jsx("span", { "data-sx-file-sr": "", role: "status", children: said }), _jsx("div", { "data-sx-file-message": "", children: _jsx("p", { "data-sx-file-error": "", id: ids.error, role: "alert", children: filled(message) ? (_jsx("span", { "data-sx-file-says": "", children: message }, typeof message === "string" ? message : undefined)) : null }) }), page ? (_jsxs("div", { "data-sx-file-page": "", "aria-hidden": true, children: [_jsx(Layers, { effects: effects, slot: "page", uid: uid }), _jsx("span", { "data-sx-file-page-words": "", children: words.page })] })) : null] })] }));
317
+ }
318
+ /** A card's key: the same file keeps its card through a move. */
319
+ const keys = new WeakMap();
320
+ let count = 0;
321
+ function keyOf(f) {
322
+ let k = keys.get(f);
323
+ if (!k) {
324
+ k = `f${++count}`;
325
+ keys.set(f, k);
326
+ }
327
+ return k;
328
+ }
@@ -0,0 +1,22 @@
1
+ import { type CSSProperties } from "react";
2
+ export interface FormBuddyProps {
3
+ /** The form it watches, by `id`. Default: the form it sits in, else the first form beside it. */
4
+ readonly form?: string;
5
+ /** Your call on its face: `"happy"` once the form went through, `"worried"` on a failure. Default: worried while a field is flagged wrong. */
6
+ readonly mood?: "happy" | "worried";
7
+ /** How wide it is: any CSS length. Default `8rem`. */
8
+ readonly size?: string;
9
+ readonly className?: string;
10
+ readonly style?: CSSProperties;
11
+ }
12
+ /**
13
+ * Our own little character for a sign-in form: a round sprout on the form's top edge. Its eyes follow the caret in
14
+ * the field you type in; on a password it covers its eyes, and peeks when the password is shown; it looks worried while
15
+ * a field is wrong, and happy when you say so (`mood="happy"`). Decoration only: hidden from screen readers, it never
16
+ * takes the pointer and never covers a field. Under reduced motion its face changes without moving.
17
+ *
18
+ * ```tsx
19
+ * <form id="sign-in"> <FormBuddy mood={done ? "happy" : undefined} /> <Field label="Email" … /> … </form>
20
+ * ```
21
+ */
22
+ export declare function FormBuddy({ form, mood, size, className, style }: FormBuddyProps): import("react").JSX.Element;