tyrell-components 1.0.0-RC13 → 1.0.0-RC15

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 (358) hide show
  1. package/README.md +10 -2
  2. package/css/tyrell-theme.css +192 -180
  3. package/css/tyrell.css +23 -0
  4. package/dist/tyrell-colors-static.css +1 -316
  5. package/dist/tyrell-theme.css +1 -1454
  6. package/dist/tyrell.css +1 -1371
  7. package/dist/tyrell.js +1 -1
  8. package/lib/base/ty-component.d.ts +20 -10
  9. package/lib/base/ty-component.js +196 -319
  10. package/lib/components/button.d.ts +3 -17
  11. package/lib/components/button.js +261 -295
  12. package/lib/components/calendar-month.d.ts +4 -50
  13. package/lib/components/calendar-month.js +443 -582
  14. package/lib/components/calendar-navigation.d.ts +3 -48
  15. package/lib/components/calendar-navigation.js +239 -362
  16. package/lib/components/calendar.d.ts +8 -83
  17. package/lib/components/calendar.js +616 -829
  18. package/lib/components/checkbox.d.ts +5 -72
  19. package/lib/components/checkbox.js +273 -416
  20. package/lib/components/copy.d.ts +4 -57
  21. package/lib/components/copy.js +280 -397
  22. package/lib/components/date-picker.d.ts +21 -163
  23. package/lib/components/date-picker.js +1143 -1674
  24. package/lib/components/file-upload.d.ts +9 -15
  25. package/lib/components/file-upload.js +404 -426
  26. package/lib/components/icon.d.ts +3 -24
  27. package/lib/components/icon.js +141 -230
  28. package/lib/components/input.d.ts +8 -108
  29. package/lib/components/input.js +593 -784
  30. package/lib/components/modal.d.ts +17 -26
  31. package/lib/components/modal.js +340 -484
  32. package/lib/components/option.d.ts +2 -9
  33. package/lib/components/option.js +168 -216
  34. package/lib/components/popup.d.ts +2 -17
  35. package/lib/components/popup.js +249 -380
  36. package/lib/components/radio.d.ts +5 -25
  37. package/lib/components/radio.js +407 -461
  38. package/lib/components/resize-observer.d.ts +3 -30
  39. package/lib/components/resize-observer.js +69 -103
  40. package/lib/components/scroll-container.d.ts +2 -12
  41. package/lib/components/scroll-container.js +293 -338
  42. package/lib/components/select.d.ts +87 -159
  43. package/lib/components/select.js +1609 -2090
  44. package/lib/components/selected-tags.d.ts +5 -48
  45. package/lib/components/selected-tags.js +188 -276
  46. package/lib/components/step.d.ts +1 -6
  47. package/lib/components/step.js +62 -68
  48. package/lib/components/switch.d.ts +1 -12
  49. package/lib/components/switch.js +214 -247
  50. package/lib/components/tab.d.ts +1 -6
  51. package/lib/components/tab.js +62 -69
  52. package/lib/components/tabs.d.ts +6 -63
  53. package/lib/components/tabs.js +545 -777
  54. package/lib/components/tag.d.ts +3 -37
  55. package/lib/components/tag.js +236 -335
  56. package/lib/components/textarea.d.ts +7 -87
  57. package/lib/components/textarea.js +457 -627
  58. package/lib/components/tooltip.d.ts +3 -11
  59. package/lib/components/tooltip.js +307 -443
  60. package/lib/components/wizard.d.ts +6 -54
  61. package/lib/components/wizard.js +405 -618
  62. package/lib/icons/fontawesome/brands.d.ts +0 -1
  63. package/lib/icons/fontawesome/brands.js +0 -8
  64. package/lib/icons/fontawesome/regular.d.ts +0 -1
  65. package/lib/icons/fontawesome/regular.js +0 -8
  66. package/lib/icons/fontawesome/solid.d.ts +0 -1
  67. package/lib/icons/fontawesome/solid.js +0 -8
  68. package/lib/icons/heroicons/micro.d.ts +0 -1
  69. package/lib/icons/heroicons/micro.js +392 -400
  70. package/lib/icons/heroicons/mini.d.ts +0 -1
  71. package/lib/icons/heroicons/mini.js +382 -390
  72. package/lib/icons/heroicons/outline.d.ts +0 -1
  73. package/lib/icons/heroicons/outline.js +337 -345
  74. package/lib/icons/heroicons/solid.d.ts +0 -1
  75. package/lib/icons/heroicons/solid.js +407 -415
  76. package/lib/icons/lucide.d.ts +0 -1
  77. package/lib/icons/lucide.js +24479 -26351
  78. package/lib/icons/material/filled.d.ts +0 -1
  79. package/lib/icons/material/filled.js +9653 -9663
  80. package/lib/icons/material/outlined.d.ts +0 -1
  81. package/lib/icons/material/outlined.js +10271 -10281
  82. package/lib/icons/material/round.d.ts +0 -1
  83. package/lib/icons/material/round.js +10495 -10505
  84. package/lib/icons/material/sharp.d.ts +0 -1
  85. package/lib/icons/material/sharp.js +9905 -9915
  86. package/lib/icons/material/two-tone.d.ts +0 -1
  87. package/lib/icons/material/two-tone.js +12792 -12802
  88. package/lib/index.d.ts +0 -1
  89. package/lib/index.js +21 -41
  90. package/lib/styles/button.d.ts +2 -20
  91. package/lib/styles/button.js +202 -404
  92. package/lib/styles/calendar-month.d.ts +1 -5
  93. package/lib/styles/calendar-month.js +127 -244
  94. package/lib/styles/calendar-navigation.d.ts +2 -6
  95. package/lib/styles/calendar-navigation.js +64 -104
  96. package/lib/styles/calendar.d.ts +1 -2
  97. package/lib/styles/calendar.js +9 -22
  98. package/lib/styles/checkbox.d.ts +0 -1
  99. package/lib/styles/checkbox.js +45 -94
  100. package/lib/styles/copy.d.ts +0 -1
  101. package/lib/styles/copy.js +67 -106
  102. package/lib/styles/custom-scrollbar.d.ts +1 -2
  103. package/lib/styles/custom-scrollbar.js +80 -115
  104. package/lib/styles/date-picker.d.ts +1 -5
  105. package/lib/styles/date-picker.js +261 -335
  106. package/lib/styles/field-size.d.ts +6 -0
  107. package/lib/styles/field-size.js +91 -0
  108. package/lib/styles/file-upload.d.ts +1 -2
  109. package/lib/styles/file-upload.js +143 -188
  110. package/lib/styles/icon.d.ts +2 -6
  111. package/lib/styles/icon.js +92 -170
  112. package/lib/styles/input.d.ts +1 -6
  113. package/lib/styles/input.js +125 -290
  114. package/lib/styles/modal.d.ts +1 -2
  115. package/lib/styles/modal.js +71 -108
  116. package/lib/styles/option.d.ts +2 -6
  117. package/lib/styles/option.js +49 -64
  118. package/lib/styles/popup.d.ts +1 -2
  119. package/lib/styles/popup.js +42 -77
  120. package/lib/styles/radio.d.ts +0 -1
  121. package/lib/styles/radio.js +69 -110
  122. package/lib/styles/resize-observer.d.ts +1 -2
  123. package/lib/styles/resize-observer.js +2 -12
  124. package/lib/styles/scroll-container.d.ts +1 -2
  125. package/lib/styles/scroll-container.js +100 -149
  126. package/lib/styles/select-base.d.ts +0 -1
  127. package/lib/styles/select-base.js +597 -785
  128. package/lib/styles/select.d.ts +1 -2
  129. package/lib/styles/select.js +140 -236
  130. package/lib/styles/step.d.ts +1 -2
  131. package/lib/styles/step.js +22 -33
  132. package/lib/styles/switch.d.ts +0 -1
  133. package/lib/styles/switch.js +34 -73
  134. package/lib/styles/tab.d.ts +1 -2
  135. package/lib/styles/tab.js +22 -34
  136. package/lib/styles/tabs.d.ts +3 -11
  137. package/lib/styles/tabs.js +190 -222
  138. package/lib/styles/tag.d.ts +1 -5
  139. package/lib/styles/tag.js +136 -218
  140. package/lib/styles/textarea.d.ts +1 -2
  141. package/lib/styles/textarea.js +210 -319
  142. package/lib/styles/tooltip.d.ts +0 -1
  143. package/lib/styles/tooltip.js +3 -13
  144. package/lib/styles/wizard.d.ts +5 -21
  145. package/lib/styles/wizard.js +170 -306
  146. package/lib/types/common.d.ts +2 -2
  147. package/lib/types/common.js +6 -17
  148. package/lib/utils/calendar-utils.d.ts +4 -21
  149. package/lib/utils/calendar-utils.js +100 -273
  150. package/lib/utils/custom-scrollbar.d.ts +6 -20
  151. package/lib/utils/custom-scrollbar.js +273 -317
  152. package/lib/utils/flavor-sheet.d.ts +0 -1
  153. package/lib/utils/flavor-sheet.js +14 -37
  154. package/lib/utils/icon-registry.d.ts +0 -2
  155. package/lib/utils/icon-registry.js +137 -243
  156. package/lib/utils/icons.d.ts +0 -1
  157. package/lib/utils/icons.js +0 -9
  158. package/lib/utils/loader-registry.d.ts +0 -1
  159. package/lib/utils/loader-registry.js +3 -35
  160. package/lib/utils/locale.d.ts +2 -23
  161. package/lib/utils/locale.js +34 -120
  162. package/lib/utils/mobile.d.ts +0 -1
  163. package/lib/utils/mobile.js +1 -18
  164. package/lib/utils/number-format.d.ts +6 -3
  165. package/lib/utils/number-format.js +54 -110
  166. package/lib/utils/positioning.d.ts +50 -7
  167. package/lib/utils/positioning.js +224 -234
  168. package/lib/utils/property-capture.d.ts +5 -27
  169. package/lib/utils/property-capture.js +36 -144
  170. package/lib/utils/property-manager.d.ts +0 -1
  171. package/lib/utils/property-manager.js +126 -196
  172. package/lib/utils/resize-observer.d.ts +0 -1
  173. package/lib/utils/resize-observer.js +23 -59
  174. package/lib/utils/scroll-lock.d.ts +4 -11
  175. package/lib/utils/scroll-lock.js +65 -172
  176. package/lib/utils/styles.d.ts +0 -1
  177. package/lib/utils/styles.js +17 -41
  178. package/lib/version.d.ts +1 -2
  179. package/lib/version.js +1 -11
  180. package/package.json +4 -4
  181. package/lib/base/ty-component.d.ts.map +0 -1
  182. package/lib/base/ty-component.js.map +0 -1
  183. package/lib/components/button.d.ts.map +0 -1
  184. package/lib/components/button.js.map +0 -1
  185. package/lib/components/calendar-month.d.ts.map +0 -1
  186. package/lib/components/calendar-month.js.map +0 -1
  187. package/lib/components/calendar-navigation.d.ts.map +0 -1
  188. package/lib/components/calendar-navigation.js.map +0 -1
  189. package/lib/components/calendar.d.ts.map +0 -1
  190. package/lib/components/calendar.js.map +0 -1
  191. package/lib/components/checkbox.d.ts.map +0 -1
  192. package/lib/components/checkbox.js.map +0 -1
  193. package/lib/components/copy.d.ts.map +0 -1
  194. package/lib/components/copy.js.map +0 -1
  195. package/lib/components/date-picker.d.ts.map +0 -1
  196. package/lib/components/date-picker.js.map +0 -1
  197. package/lib/components/file-upload.d.ts.map +0 -1
  198. package/lib/components/file-upload.js.map +0 -1
  199. package/lib/components/icon.d.ts.map +0 -1
  200. package/lib/components/icon.js.map +0 -1
  201. package/lib/components/input.d.ts.map +0 -1
  202. package/lib/components/input.js.map +0 -1
  203. package/lib/components/modal.d.ts.map +0 -1
  204. package/lib/components/modal.js.map +0 -1
  205. package/lib/components/option.d.ts.map +0 -1
  206. package/lib/components/option.js.map +0 -1
  207. package/lib/components/popup.d.ts.map +0 -1
  208. package/lib/components/popup.js.map +0 -1
  209. package/lib/components/radio.d.ts.map +0 -1
  210. package/lib/components/radio.js.map +0 -1
  211. package/lib/components/resize-observer.d.ts.map +0 -1
  212. package/lib/components/resize-observer.js.map +0 -1
  213. package/lib/components/scroll-container.d.ts.map +0 -1
  214. package/lib/components/scroll-container.js.map +0 -1
  215. package/lib/components/select.d.ts.map +0 -1
  216. package/lib/components/select.js.map +0 -1
  217. package/lib/components/selected-tags.d.ts.map +0 -1
  218. package/lib/components/selected-tags.js.map +0 -1
  219. package/lib/components/step.d.ts.map +0 -1
  220. package/lib/components/step.js.map +0 -1
  221. package/lib/components/switch.d.ts.map +0 -1
  222. package/lib/components/switch.js.map +0 -1
  223. package/lib/components/tab.d.ts.map +0 -1
  224. package/lib/components/tab.js.map +0 -1
  225. package/lib/components/tabs.d.ts.map +0 -1
  226. package/lib/components/tabs.js.map +0 -1
  227. package/lib/components/tag.d.ts.map +0 -1
  228. package/lib/components/tag.js.map +0 -1
  229. package/lib/components/textarea.d.ts.map +0 -1
  230. package/lib/components/textarea.js.map +0 -1
  231. package/lib/components/tooltip.d.ts.map +0 -1
  232. package/lib/components/tooltip.js.map +0 -1
  233. package/lib/components/wizard.d.ts.map +0 -1
  234. package/lib/components/wizard.js.map +0 -1
  235. package/lib/icons/fontawesome/brands.d.ts.map +0 -1
  236. package/lib/icons/fontawesome/brands.js.map +0 -1
  237. package/lib/icons/fontawesome/regular.d.ts.map +0 -1
  238. package/lib/icons/fontawesome/regular.js.map +0 -1
  239. package/lib/icons/fontawesome/solid.d.ts.map +0 -1
  240. package/lib/icons/fontawesome/solid.js.map +0 -1
  241. package/lib/icons/heroicons/micro.d.ts.map +0 -1
  242. package/lib/icons/heroicons/micro.js.map +0 -1
  243. package/lib/icons/heroicons/mini.d.ts.map +0 -1
  244. package/lib/icons/heroicons/mini.js.map +0 -1
  245. package/lib/icons/heroicons/outline.d.ts.map +0 -1
  246. package/lib/icons/heroicons/outline.js.map +0 -1
  247. package/lib/icons/heroicons/solid.d.ts.map +0 -1
  248. package/lib/icons/heroicons/solid.js.map +0 -1
  249. package/lib/icons/lucide.d.ts.map +0 -1
  250. package/lib/icons/lucide.js.map +0 -1
  251. package/lib/icons/material/filled.d.ts.map +0 -1
  252. package/lib/icons/material/filled.js.map +0 -1
  253. package/lib/icons/material/outlined.d.ts.map +0 -1
  254. package/lib/icons/material/outlined.js.map +0 -1
  255. package/lib/icons/material/round.d.ts.map +0 -1
  256. package/lib/icons/material/round.js.map +0 -1
  257. package/lib/icons/material/sharp.d.ts.map +0 -1
  258. package/lib/icons/material/sharp.js.map +0 -1
  259. package/lib/icons/material/two-tone.d.ts.map +0 -1
  260. package/lib/icons/material/two-tone.js.map +0 -1
  261. package/lib/index.d.ts.map +0 -1
  262. package/lib/index.js.map +0 -1
  263. package/lib/styles/button.d.ts.map +0 -1
  264. package/lib/styles/button.js.map +0 -1
  265. package/lib/styles/calendar-month.d.ts.map +0 -1
  266. package/lib/styles/calendar-month.js.map +0 -1
  267. package/lib/styles/calendar-navigation.d.ts.map +0 -1
  268. package/lib/styles/calendar-navigation.js.map +0 -1
  269. package/lib/styles/calendar.d.ts.map +0 -1
  270. package/lib/styles/calendar.js.map +0 -1
  271. package/lib/styles/checkbox.d.ts.map +0 -1
  272. package/lib/styles/checkbox.js.map +0 -1
  273. package/lib/styles/copy.d.ts.map +0 -1
  274. package/lib/styles/copy.js.map +0 -1
  275. package/lib/styles/custom-scrollbar.d.ts.map +0 -1
  276. package/lib/styles/custom-scrollbar.js.map +0 -1
  277. package/lib/styles/date-picker.d.ts.map +0 -1
  278. package/lib/styles/date-picker.js.map +0 -1
  279. package/lib/styles/file-upload.d.ts.map +0 -1
  280. package/lib/styles/file-upload.js.map +0 -1
  281. package/lib/styles/icon.d.ts.map +0 -1
  282. package/lib/styles/icon.js.map +0 -1
  283. package/lib/styles/input.d.ts.map +0 -1
  284. package/lib/styles/input.js.map +0 -1
  285. package/lib/styles/modal.d.ts.map +0 -1
  286. package/lib/styles/modal.js.map +0 -1
  287. package/lib/styles/multiselect.d.ts +0 -8
  288. package/lib/styles/multiselect.d.ts.map +0 -1
  289. package/lib/styles/multiselect.js +0 -849
  290. package/lib/styles/multiselect.js.map +0 -1
  291. package/lib/styles/option.d.ts.map +0 -1
  292. package/lib/styles/option.js.map +0 -1
  293. package/lib/styles/popup.d.ts.map +0 -1
  294. package/lib/styles/popup.js.map +0 -1
  295. package/lib/styles/radio.d.ts.map +0 -1
  296. package/lib/styles/radio.js.map +0 -1
  297. package/lib/styles/resize-observer.d.ts.map +0 -1
  298. package/lib/styles/resize-observer.js.map +0 -1
  299. package/lib/styles/scroll-container.d.ts.map +0 -1
  300. package/lib/styles/scroll-container.js.map +0 -1
  301. package/lib/styles/select-base.d.ts.map +0 -1
  302. package/lib/styles/select-base.js.map +0 -1
  303. package/lib/styles/select.d.ts.map +0 -1
  304. package/lib/styles/select.js.map +0 -1
  305. package/lib/styles/step.d.ts.map +0 -1
  306. package/lib/styles/step.js.map +0 -1
  307. package/lib/styles/switch.d.ts.map +0 -1
  308. package/lib/styles/switch.js.map +0 -1
  309. package/lib/styles/tab.d.ts.map +0 -1
  310. package/lib/styles/tab.js.map +0 -1
  311. package/lib/styles/tabs.d.ts.map +0 -1
  312. package/lib/styles/tabs.js.map +0 -1
  313. package/lib/styles/tag.d.ts.map +0 -1
  314. package/lib/styles/tag.js.map +0 -1
  315. package/lib/styles/textarea.d.ts.map +0 -1
  316. package/lib/styles/textarea.js.map +0 -1
  317. package/lib/styles/tooltip.d.ts.map +0 -1
  318. package/lib/styles/tooltip.js.map +0 -1
  319. package/lib/styles/wizard.d.ts.map +0 -1
  320. package/lib/styles/wizard.js.map +0 -1
  321. package/lib/types/common.d.ts.map +0 -1
  322. package/lib/types/common.js.map +0 -1
  323. package/lib/utils/calendar-utils.d.ts.map +0 -1
  324. package/lib/utils/calendar-utils.js.map +0 -1
  325. package/lib/utils/custom-scrollbar.d.ts.map +0 -1
  326. package/lib/utils/custom-scrollbar.js.map +0 -1
  327. package/lib/utils/flavor-sheet.d.ts.map +0 -1
  328. package/lib/utils/flavor-sheet.js.map +0 -1
  329. package/lib/utils/icon-registry.d.ts.map +0 -1
  330. package/lib/utils/icon-registry.js.map +0 -1
  331. package/lib/utils/icons.d.ts.map +0 -1
  332. package/lib/utils/icons.js.map +0 -1
  333. package/lib/utils/loader-registry.d.ts.map +0 -1
  334. package/lib/utils/loader-registry.js.map +0 -1
  335. package/lib/utils/locale.d.ts.map +0 -1
  336. package/lib/utils/locale.js.map +0 -1
  337. package/lib/utils/mobile.d.ts.map +0 -1
  338. package/lib/utils/mobile.js.map +0 -1
  339. package/lib/utils/number-format.d.ts.map +0 -1
  340. package/lib/utils/number-format.js.map +0 -1
  341. package/lib/utils/parse-boolean.d.ts +0 -39
  342. package/lib/utils/parse-boolean.d.ts.map +0 -1
  343. package/lib/utils/parse-boolean.js +0 -58
  344. package/lib/utils/parse-boolean.js.map +0 -1
  345. package/lib/utils/positioning.d.ts.map +0 -1
  346. package/lib/utils/positioning.js.map +0 -1
  347. package/lib/utils/property-capture.d.ts.map +0 -1
  348. package/lib/utils/property-capture.js.map +0 -1
  349. package/lib/utils/property-manager.d.ts.map +0 -1
  350. package/lib/utils/property-manager.js.map +0 -1
  351. package/lib/utils/resize-observer.d.ts.map +0 -1
  352. package/lib/utils/resize-observer.js.map +0 -1
  353. package/lib/utils/scroll-lock.d.ts.map +0 -1
  354. package/lib/utils/scroll-lock.js.map +0 -1
  355. package/lib/utils/styles.d.ts.map +0 -1
  356. package/lib/utils/styles.js.map +0 -1
  357. package/lib/version.d.ts.map +0 -1
  358. package/lib/version.js.map +0 -1
@@ -1,19 +1,3 @@
1
- /**
2
- * TyFileUpload Web Component
3
- *
4
- * Drop zone + file picker primitive. Replaces `<input type="file">` with
5
- * a styleable, drag-and-drop-capable equivalent that works everywhere.
6
- *
7
- * - Click to browse or drag-and-drop
8
- * - Multiple file support
9
- * - Accept filter passed to the underlying file input
10
- * - Emits `change` with `{ files, names }` on every selection
11
- * - Form-associated: participates in FormData and form.reset()
12
- *
13
- * @example
14
- * <ty-file-upload name="avatar" accept="image/*" label="Profile photo"></ty-file-upload>
15
- * <ty-file-upload name="docs" multiple accept=".pdf,.docx" label="Attachments"></ty-file-upload>
16
- */
17
1
  import { TyComponent } from "../base/ty-component.js";
18
2
  import { ensureStyles } from "../utils/styles.js";
19
3
  import { fileUploadStyles } from "../styles/file-upload.js";
@@ -21,421 +5,415 @@ const UPLOAD_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
21
5
  const FILE_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>`;
22
6
  const X_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`;
23
7
  function formatBytes(bytes) {
24
- if (bytes < 1024)
25
- return `${bytes} B`;
26
- if (bytes < 1024 * 1024)
27
- return `${(bytes / 1024).toFixed(1)} KB`;
28
- if (bytes < 1024 * 1024 * 1024)
29
- return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
30
- return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GB`;
8
+ if (bytes < 1024)
9
+ return `${bytes} B`;
10
+ if (bytes < 1024 * 1024)
11
+ return `${(bytes / 1024).toFixed(1)} KB`;
12
+ if (bytes < 1024 * 1024 * 1024)
13
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
14
+ return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GB`;
31
15
  }
32
16
  export class TyFileUpload extends TyComponent {
33
- constructor() {
34
- super();
35
- this._files = [];
36
- this._isDragging = false;
37
- this._listenersSetup = false;
38
- this._dropZoneClickHandler = null;
39
- this._dropZoneKeydownHandler = null;
40
- this._dropZoneFocusHandler = null;
41
- this._dropZoneBlurHandler = null;
42
- this._dragoverHandler = null;
43
- this._dragleaveHandler = null;
44
- this._dropHandler = null;
45
- this._inputChangeHandler = null;
46
- ensureStyles(this.shadowRoot, { css: fileUploadStyles, id: "ty-file-upload" });
47
- }
48
- onConnect() { }
49
- onDisconnect() {
50
- this.removeEventListeners();
51
- }
52
- onPropertiesChanged(_changes) { }
53
- onFormReset() {
54
- this._files = [];
55
- this.updateFormValue();
56
- if (this._connected)
57
- this.render();
58
- const fileInput = this.shadowRoot?.querySelector(".file-input");
59
- if (fileInput)
60
- fileInput.value = "";
61
- }
62
- getFormValue() {
63
- if (this._files.length === 0)
64
- return null;
65
- const fd = new FormData();
66
- const fieldName = this.name || "files";
67
- for (const file of this._files) {
68
- fd.append(fieldName, file);
69
- }
70
- return fd;
71
- }
72
- // ============================================================================
73
- // PUBLIC API
74
- // ============================================================================
75
- get files() {
76
- return [...this._files];
77
- }
78
- get multiple() {
79
- return this.getProperty("multiple");
80
- }
81
- set multiple(v) {
82
- this.setProperty("multiple", v);
83
- }
84
- get accept() {
85
- return this.getProperty("accept");
86
- }
87
- set accept(v) {
88
- this.setProperty("accept", v);
89
- }
90
- get name() {
91
- return this.getProperty("name");
92
- }
93
- set name(v) {
94
- this.setProperty("name", v);
95
- }
96
- get disabled() {
97
- return this.getProperty("disabled");
98
- }
99
- set disabled(v) {
100
- this.setProperty("disabled", v);
101
- }
102
- get required() {
103
- return this.getProperty("required");
104
- }
105
- set required(v) {
106
- this.setProperty("required", v);
107
- }
108
- get label() {
109
- return this.getProperty("label");
110
- }
111
- set label(v) {
112
- this.setProperty("label", v);
113
- }
114
- get placeholder() {
115
- return this.getProperty("placeholder");
116
- }
117
- set placeholder(v) {
118
- this.setProperty("placeholder", v);
119
- }
120
- get error() {
121
- return this.getProperty("error");
122
- }
123
- set error(v) {
124
- this.setProperty("error", v);
125
- }
126
- get form() {
127
- return this._internals.form;
128
- }
129
- // ============================================================================
130
- // INTERNAL FILE MANAGEMENT
131
- // ============================================================================
132
- setFiles(newFiles) {
133
- this._files = this.multiple ? newFiles : newFiles.slice(0, 1);
134
- this.updateFormValue();
135
- this.render();
136
- const detail = {
137
- value: this._files,
138
- files: this._files,
139
- names: this._files.map((f) => f.name),
140
- };
141
- setTimeout(() => {
142
- this.dispatchEvent(new CustomEvent("change", { detail, bubbles: true, composed: true }));
143
- }, 0);
144
- }
145
- removeFile(index) {
146
- const updated = [...this._files];
147
- updated.splice(index, 1);
148
- this.setFiles(updated);
149
- const fileInput = this.shadowRoot?.querySelector(".file-input");
150
- if (fileInput)
151
- fileInput.value = "";
152
- }
153
- // ============================================================================
154
- // EVENT LISTENERS
155
- // ============================================================================
156
- setupEventListeners() {
157
- if (this._listenersSetup)
158
- return;
159
- const shadow = this.shadowRoot;
160
- const dropZone = shadow.querySelector(".drop-zone");
161
- const fileInput = shadow.querySelector(".file-input");
162
- this._dropZoneClickHandler = (e) => {
163
- if (this.disabled)
164
- return;
165
- if (e.target.closest(".file-remove"))
166
- return;
167
- fileInput.click();
168
- };
169
- this._dropZoneKeydownHandler = (e) => {
170
- if (this.disabled)
171
- return;
172
- if (e.key === "Enter" || e.key === " ") {
173
- e.preventDefault();
174
- fileInput.click();
175
- }
176
- };
177
- this._dropZoneFocusHandler = () => {
178
- dropZone.classList.add("focused");
179
- };
180
- this._dropZoneBlurHandler = () => {
181
- dropZone.classList.remove("focused");
182
- };
183
- this._dragoverHandler = (e) => {
184
- if (this.disabled)
185
- return;
186
- e.preventDefault();
187
- e.stopPropagation();
188
- if (!this._isDragging) {
189
- this._isDragging = true;
190
- dropZone.classList.add("drag-active");
191
- }
192
- };
193
- this._dragleaveHandler = (e) => {
194
- if (!dropZone.contains(e.relatedTarget)) {
195
- this._isDragging = false;
196
- dropZone.classList.remove("drag-active");
197
- }
198
- };
199
- this._dropHandler = (e) => {
200
- if (this.disabled)
201
- return;
202
- e.preventDefault();
203
- e.stopPropagation();
204
- this._isDragging = false;
205
- dropZone.classList.remove("drag-active");
206
- const files = Array.from(e.dataTransfer?.files ?? []);
207
- if (files.length > 0)
208
- this.setFiles(files);
209
- };
210
- this._inputChangeHandler = (e) => {
211
- const input = e.target;
212
- if (input.files && input.files.length > 0) {
213
- this.setFiles(Array.from(input.files));
214
- }
215
- };
216
- dropZone.addEventListener("click", this._dropZoneClickHandler);
217
- dropZone.addEventListener("keydown", this._dropZoneKeydownHandler);
218
- dropZone.addEventListener("focus", this._dropZoneFocusHandler);
219
- dropZone.addEventListener("blur", this._dropZoneBlurHandler);
220
- dropZone.addEventListener("dragover", this._dragoverHandler);
221
- dropZone.addEventListener("dragleave", this._dragleaveHandler);
222
- dropZone.addEventListener("drop", this._dropHandler);
223
- fileInput.addEventListener("change", this._inputChangeHandler);
224
- this._listenersSetup = true;
225
- }
226
- removeEventListeners() {
227
- if (!this._listenersSetup)
228
- return;
229
- const shadow = this.shadowRoot;
230
- if (!shadow)
231
- return;
232
- const dropZone = shadow.querySelector(".drop-zone");
233
- const fileInput = shadow.querySelector(".file-input");
234
- if (!dropZone || !fileInput)
235
- return;
236
- if (this._dropZoneClickHandler)
237
- dropZone.removeEventListener("click", this._dropZoneClickHandler);
238
- if (this._dropZoneKeydownHandler)
239
- dropZone.removeEventListener("keydown", this._dropZoneKeydownHandler);
240
- if (this._dropZoneFocusHandler)
241
- dropZone.removeEventListener("focus", this._dropZoneFocusHandler);
242
- if (this._dropZoneBlurHandler)
243
- dropZone.removeEventListener("blur", this._dropZoneBlurHandler);
244
- if (this._dragoverHandler)
245
- dropZone.removeEventListener("dragover", this._dragoverHandler);
246
- if (this._dragleaveHandler)
247
- dropZone.removeEventListener("dragleave", this._dragleaveHandler);
248
- if (this._dropHandler)
249
- dropZone.removeEventListener("drop", this._dropHandler);
250
- if (this._inputChangeHandler)
251
- fileInput.removeEventListener("change", this._inputChangeHandler);
252
- this._listenersSetup = false;
253
- }
254
- // ============================================================================
255
- // RENDERING
256
- // ============================================================================
257
- buildDropZoneClasses() {
258
- const classes = ["drop-zone"];
259
- if (this._isDragging)
260
- classes.push("drag-active");
261
- if (this._files.length > 0)
262
- classes.push("has-files");
263
- if (this.disabled)
264
- classes.push("disabled");
265
- if (this.error)
266
- classes.push("error");
267
- return classes.join(" ");
268
- }
269
- renderFileList(fileList) {
270
- fileList.innerHTML = "";
271
- for (let i = 0; i < this._files.length; i++) {
272
- const file = this._files[i];
273
- const item = document.createElement("div");
274
- item.className = "file-item";
275
- const icon = document.createElement("span");
276
- icon.className = "file-icon";
277
- icon.innerHTML = FILE_ICON;
278
- const name = document.createElement("span");
279
- name.className = "file-name";
280
- name.textContent = file.name;
281
- name.title = file.name;
282
- const size = document.createElement("span");
283
- size.className = "file-size";
284
- size.textContent = formatBytes(file.size);
285
- const removeBtn = document.createElement("button");
286
- removeBtn.className = "file-remove";
287
- removeBtn.type = "button";
288
- removeBtn.innerHTML = X_ICON;
289
- removeBtn.setAttribute("aria-label", `Remove ${file.name}`);
290
- const capturedIndex = i;
291
- removeBtn.addEventListener("click", (e) => {
292
- e.stopPropagation();
293
- this.removeFile(capturedIndex);
294
- });
295
- item.appendChild(icon);
296
- item.appendChild(name);
297
- item.appendChild(size);
298
- item.appendChild(removeBtn);
299
- fileList.appendChild(item);
300
- }
301
- }
302
- render() {
303
- const shadow = this.shadowRoot;
304
- let container = shadow.querySelector(".file-upload-container");
305
- if (!container) {
306
- container = document.createElement("div");
307
- container.className = "file-upload-container";
308
- const labelEl = document.createElement("div");
309
- labelEl.className = "upload-label";
310
- container.appendChild(labelEl);
311
- const dropZone = document.createElement("div");
312
- dropZone.className = "drop-zone";
313
- dropZone.setAttribute("role", "button");
314
- const fileInput = document.createElement("input");
315
- fileInput.type = "file";
316
- fileInput.className = "file-input";
317
- fileInput.style.display = "none";
318
- dropZone.appendChild(fileInput);
319
- const uploadIcon = document.createElement("div");
320
- uploadIcon.className = "upload-icon";
321
- uploadIcon.innerHTML = UPLOAD_ICON;
322
- dropZone.appendChild(uploadIcon);
323
- const hintEl = document.createElement("div");
324
- hintEl.className = "upload-hint";
325
- dropZone.appendChild(hintEl);
326
- const subHintEl = document.createElement("div");
327
- subHintEl.className = "upload-sub-hint";
328
- dropZone.appendChild(subHintEl);
329
- container.appendChild(dropZone);
330
- const fileList = document.createElement("div");
331
- fileList.className = "file-list";
332
- container.appendChild(fileList);
333
- const errorEl = document.createElement("div");
334
- errorEl.className = "error-message";
335
- container.appendChild(errorEl);
336
- shadow.appendChild(container);
337
- this.setupEventListeners();
338
- }
339
- // Label
340
- const labelEl = container.querySelector(".upload-label");
341
- if (this.label) {
342
- labelEl.style.display = "";
343
- labelEl.innerHTML = "";
344
- labelEl.appendChild(document.createTextNode(this.label));
345
- if (this.required) {
346
- const req = document.createElement("span");
347
- req.className = "required-icon";
348
- req.textContent = "*";
349
- req.setAttribute("aria-hidden", "true");
350
- labelEl.appendChild(req);
351
- }
352
- }
353
- else {
354
- labelEl.style.display = "none";
355
- }
356
- // Drop zone
357
- const dropZone = container.querySelector(".drop-zone");
358
- dropZone.className = this.buildDropZoneClasses();
359
- dropZone.tabIndex = this.disabled ? -1 : 0;
360
- dropZone.setAttribute("aria-disabled", String(this.disabled));
361
- dropZone.setAttribute("aria-label", this.placeholder || "Upload files");
362
- // File input
363
- const fileInput = container.querySelector(".file-input");
364
- fileInput.multiple = this.multiple;
365
- fileInput.accept = this.accept;
366
- fileInput.disabled = this.disabled;
367
- // Upload icon — hide once files are selected to give room to the compact zone
368
- const uploadIcon = container.querySelector(".upload-icon");
369
- uploadIcon.style.display = this._files.length > 0 ? "none" : "";
370
- // Hint text
371
- const hintEl = container.querySelector(".upload-hint");
372
- if (this._files.length > 0) {
373
- hintEl.innerHTML = `<strong>${this._files.length} file${this._files.length !== 1 ? "s" : ""} selected</strong>`;
374
- }
375
- else {
376
- hintEl.innerHTML = `Drop files here or <span class="browse-link">click to browse</span>`;
377
- }
378
- // Sub-hint
379
- const subHintEl = container.querySelector(".upload-sub-hint");
380
- if (this.accept && this._files.length === 0) {
381
- subHintEl.textContent = `Accepted: ${this.accept}`;
382
- subHintEl.style.display = "";
383
- }
384
- else {
385
- subHintEl.style.display = "none";
386
- }
387
- // File list
388
- const fileList = container.querySelector(".file-list");
389
- this.renderFileList(fileList);
390
- // Error message
391
- const errorEl = container.querySelector(".error-message");
392
- errorEl.textContent = this.error;
393
- errorEl.style.display = this.error ? "" : "none";
394
- }
17
+ constructor() {
18
+ super();
19
+ this._files = [];
20
+ this._isDragging = false;
21
+ this._listenersSetup = false;
22
+ this._dropZoneClickHandler = null;
23
+ this._dropZoneKeydownHandler = null;
24
+ this._dropZoneFocusHandler = null;
25
+ this._dropZoneBlurHandler = null;
26
+ this._dragoverHandler = null;
27
+ this._dragleaveHandler = null;
28
+ this._dropHandler = null;
29
+ this._inputChangeHandler = null;
30
+ ensureStyles(this.shadowRoot, { css: fileUploadStyles, id: "ty-file-upload" });
31
+ }
32
+ onConnect() { }
33
+ onDisconnect() {
34
+ this.removeEventListeners();
35
+ }
36
+ onPropertiesChanged(_changes) { }
37
+ onFormReset() {
38
+ this._files = [];
39
+ this.updateFormValue();
40
+ if (this._connected)
41
+ this.render();
42
+ const fileInput = this.shadowRoot?.querySelector(".file-input");
43
+ if (fileInput)
44
+ fileInput.value = "";
45
+ }
46
+ getFormValue() {
47
+ if (this._files.length === 0 || !this.name)
48
+ return null;
49
+ const fd = new FormData();
50
+ for (const file of this._files) {
51
+ fd.append(this.name, file);
52
+ }
53
+ return fd;
54
+ }
55
+ matchesAccept(file) {
56
+ const accept = this.accept?.trim();
57
+ if (!accept)
58
+ return true;
59
+ return accept.split(",").some((raw) => {
60
+ const entry = raw.trim().toLowerCase();
61
+ if (!entry)
62
+ return false;
63
+ if (entry.startsWith("."))
64
+ return file.name.toLowerCase().endsWith(entry);
65
+ const type = file.type.toLowerCase();
66
+ if (entry.endsWith("/*"))
67
+ return type.startsWith(entry.slice(0, -1));
68
+ return type === entry;
69
+ });
70
+ }
71
+ get files() {
72
+ return [...this._files];
73
+ }
74
+ get multiple() {
75
+ return this.getProperty("multiple");
76
+ }
77
+ set multiple(v) {
78
+ this.setProperty("multiple", v);
79
+ }
80
+ get accept() {
81
+ return this.getProperty("accept");
82
+ }
83
+ set accept(v) {
84
+ this.setProperty("accept", v);
85
+ }
86
+ get name() {
87
+ return this.getProperty("name");
88
+ }
89
+ set name(v) {
90
+ this.setProperty("name", v);
91
+ }
92
+ get disabled() {
93
+ return this.getProperty("disabled");
94
+ }
95
+ set disabled(v) {
96
+ this.setProperty("disabled", v);
97
+ }
98
+ get required() {
99
+ return this.getProperty("required");
100
+ }
101
+ set required(v) {
102
+ this.setProperty("required", v);
103
+ }
104
+ get label() {
105
+ return this.getProperty("label");
106
+ }
107
+ set label(v) {
108
+ this.setProperty("label", v);
109
+ }
110
+ get placeholder() {
111
+ return this.getProperty("placeholder");
112
+ }
113
+ set placeholder(v) {
114
+ this.setProperty("placeholder", v);
115
+ }
116
+ get error() {
117
+ return this.getProperty("error");
118
+ }
119
+ set error(v) {
120
+ this.setProperty("error", v);
121
+ }
122
+ get form() {
123
+ return this._internals.form;
124
+ }
125
+ setFiles(newFiles) {
126
+ this._files = this.multiple ? newFiles : newFiles.slice(0, 1);
127
+ this.updateFormValue();
128
+ this.render();
129
+ const detail = {
130
+ value: this._files,
131
+ files: this._files,
132
+ names: this._files.map((f) => f.name),
133
+ };
134
+ setTimeout(() => {
135
+ this.dispatchEvent(new CustomEvent("change", { detail, bubbles: true, composed: true }));
136
+ }, 0);
137
+ }
138
+ removeFile(index) {
139
+ const updated = [...this._files];
140
+ updated.splice(index, 1);
141
+ this.setFiles(updated);
142
+ const fileInput = this.shadowRoot?.querySelector(".file-input");
143
+ if (fileInput)
144
+ fileInput.value = "";
145
+ }
146
+ setupEventListeners() {
147
+ if (this._listenersSetup)
148
+ return;
149
+ const shadow = this.shadowRoot;
150
+ const dropZone = shadow.querySelector(".drop-zone");
151
+ const fileInput = shadow.querySelector(".file-input");
152
+ this._dropZoneClickHandler = (e) => {
153
+ if (this.disabled)
154
+ return;
155
+ if (e.target.closest(".file-remove"))
156
+ return;
157
+ fileInput.click();
158
+ };
159
+ this._dropZoneKeydownHandler = (e) => {
160
+ if (this.disabled)
161
+ return;
162
+ if (e.key === "Enter" || e.key === " ") {
163
+ e.preventDefault();
164
+ fileInput.click();
165
+ }
166
+ };
167
+ this._dropZoneFocusHandler = () => {
168
+ dropZone.classList.add("focused");
169
+ };
170
+ this._dropZoneBlurHandler = () => {
171
+ dropZone.classList.remove("focused");
172
+ };
173
+ this._dragoverHandler = (e) => {
174
+ if (this.disabled)
175
+ return;
176
+ e.preventDefault();
177
+ e.stopPropagation();
178
+ if (!this._isDragging) {
179
+ this._isDragging = true;
180
+ dropZone.classList.add("drag-active");
181
+ }
182
+ };
183
+ this._dragleaveHandler = (e) => {
184
+ if (!dropZone.contains(e.relatedTarget)) {
185
+ this._isDragging = false;
186
+ dropZone.classList.remove("drag-active");
187
+ }
188
+ };
189
+ this._dropHandler = (e) => {
190
+ if (this.disabled)
191
+ return;
192
+ e.preventDefault();
193
+ e.stopPropagation();
194
+ this._isDragging = false;
195
+ dropZone.classList.remove("drag-active");
196
+ const files = Array.from(e.dataTransfer?.files ?? []).filter((f) => this.matchesAccept(f));
197
+ if (files.length > 0)
198
+ this.setFiles(files);
199
+ };
200
+ this._inputChangeHandler = (e) => {
201
+ const input = e.target;
202
+ if (input.files && input.files.length > 0) {
203
+ this.setFiles(Array.from(input.files));
204
+ }
205
+ };
206
+ dropZone.addEventListener("click", this._dropZoneClickHandler);
207
+ dropZone.addEventListener("keydown", this._dropZoneKeydownHandler);
208
+ dropZone.addEventListener("focus", this._dropZoneFocusHandler);
209
+ dropZone.addEventListener("blur", this._dropZoneBlurHandler);
210
+ dropZone.addEventListener("dragover", this._dragoverHandler);
211
+ dropZone.addEventListener("dragleave", this._dragleaveHandler);
212
+ dropZone.addEventListener("drop", this._dropHandler);
213
+ fileInput.addEventListener("change", this._inputChangeHandler);
214
+ this._listenersSetup = true;
215
+ }
216
+ removeEventListeners() {
217
+ if (!this._listenersSetup)
218
+ return;
219
+ const shadow = this.shadowRoot;
220
+ if (!shadow)
221
+ return;
222
+ const dropZone = shadow.querySelector(".drop-zone");
223
+ const fileInput = shadow.querySelector(".file-input");
224
+ if (!dropZone || !fileInput)
225
+ return;
226
+ if (this._dropZoneClickHandler)
227
+ dropZone.removeEventListener("click", this._dropZoneClickHandler);
228
+ if (this._dropZoneKeydownHandler)
229
+ dropZone.removeEventListener("keydown", this._dropZoneKeydownHandler);
230
+ if (this._dropZoneFocusHandler)
231
+ dropZone.removeEventListener("focus", this._dropZoneFocusHandler);
232
+ if (this._dropZoneBlurHandler)
233
+ dropZone.removeEventListener("blur", this._dropZoneBlurHandler);
234
+ if (this._dragoverHandler)
235
+ dropZone.removeEventListener("dragover", this._dragoverHandler);
236
+ if (this._dragleaveHandler)
237
+ dropZone.removeEventListener("dragleave", this._dragleaveHandler);
238
+ if (this._dropHandler)
239
+ dropZone.removeEventListener("drop", this._dropHandler);
240
+ if (this._inputChangeHandler)
241
+ fileInput.removeEventListener("change", this._inputChangeHandler);
242
+ this._listenersSetup = false;
243
+ }
244
+ buildDropZoneClasses() {
245
+ const classes = ["drop-zone"];
246
+ if (this._isDragging)
247
+ classes.push("drag-active");
248
+ if (this._files.length > 0)
249
+ classes.push("has-files");
250
+ if (this.disabled)
251
+ classes.push("disabled");
252
+ if (this.error)
253
+ classes.push("error");
254
+ return classes.join(" ");
255
+ }
256
+ renderFileList(fileList) {
257
+ fileList.innerHTML = "";
258
+ for (let i = 0; i < this._files.length; i++) {
259
+ const file = this._files[i];
260
+ const item = document.createElement("div");
261
+ item.className = "file-item";
262
+ const icon = document.createElement("span");
263
+ icon.className = "file-icon";
264
+ icon.innerHTML = FILE_ICON;
265
+ const name = document.createElement("span");
266
+ name.className = "file-name";
267
+ name.textContent = file.name;
268
+ name.title = file.name;
269
+ const size = document.createElement("span");
270
+ size.className = "file-size";
271
+ size.textContent = formatBytes(file.size);
272
+ const removeBtn = document.createElement("button");
273
+ removeBtn.className = "file-remove";
274
+ removeBtn.type = "button";
275
+ removeBtn.innerHTML = X_ICON;
276
+ removeBtn.setAttribute("aria-label", `Remove ${file.name}`);
277
+ const capturedIndex = i;
278
+ removeBtn.addEventListener("click", (e) => {
279
+ e.stopPropagation();
280
+ this.removeFile(capturedIndex);
281
+ });
282
+ item.appendChild(icon);
283
+ item.appendChild(name);
284
+ item.appendChild(size);
285
+ item.appendChild(removeBtn);
286
+ fileList.appendChild(item);
287
+ }
288
+ }
289
+ render() {
290
+ const shadow = this.shadowRoot;
291
+ let container = shadow.querySelector(".file-upload-container");
292
+ if (!container) {
293
+ container = document.createElement("div");
294
+ container.className = "file-upload-container";
295
+ const labelEl = document.createElement("div");
296
+ labelEl.className = "upload-label";
297
+ container.appendChild(labelEl);
298
+ const dropZone = document.createElement("div");
299
+ dropZone.className = "drop-zone";
300
+ dropZone.setAttribute("role", "button");
301
+ const fileInput = document.createElement("input");
302
+ fileInput.type = "file";
303
+ fileInput.className = "file-input";
304
+ fileInput.style.display = "none";
305
+ dropZone.appendChild(fileInput);
306
+ const uploadIcon = document.createElement("div");
307
+ uploadIcon.className = "upload-icon";
308
+ uploadIcon.innerHTML = UPLOAD_ICON;
309
+ dropZone.appendChild(uploadIcon);
310
+ const hintEl = document.createElement("div");
311
+ hintEl.className = "upload-hint";
312
+ dropZone.appendChild(hintEl);
313
+ const subHintEl = document.createElement("div");
314
+ subHintEl.className = "upload-sub-hint";
315
+ dropZone.appendChild(subHintEl);
316
+ container.appendChild(dropZone);
317
+ const fileList = document.createElement("div");
318
+ fileList.className = "file-list";
319
+ container.appendChild(fileList);
320
+ const errorEl = document.createElement("div");
321
+ errorEl.className = "error-message";
322
+ container.appendChild(errorEl);
323
+ shadow.appendChild(container);
324
+ this.setupEventListeners();
325
+ }
326
+ const labelEl = container.querySelector(".upload-label");
327
+ if (this.label) {
328
+ labelEl.style.display = "";
329
+ labelEl.innerHTML = "";
330
+ labelEl.appendChild(document.createTextNode(this.label));
331
+ if (this.required) {
332
+ const req = document.createElement("span");
333
+ req.className = "required-icon";
334
+ req.textContent = "*";
335
+ req.setAttribute("aria-hidden", "true");
336
+ labelEl.appendChild(req);
337
+ }
338
+ }
339
+ else {
340
+ labelEl.style.display = "none";
341
+ }
342
+ const dropZone = container.querySelector(".drop-zone");
343
+ dropZone.className = this.buildDropZoneClasses();
344
+ dropZone.tabIndex = this.disabled ? -1 : 0;
345
+ dropZone.setAttribute("aria-disabled", String(this.disabled));
346
+ dropZone.setAttribute("aria-label", this.placeholder || "Upload files");
347
+ const fileInput = container.querySelector(".file-input");
348
+ fileInput.multiple = this.multiple;
349
+ fileInput.accept = this.accept;
350
+ fileInput.disabled = this.disabled;
351
+ const uploadIcon = container.querySelector(".upload-icon");
352
+ uploadIcon.style.display = this._files.length > 0 ? "none" : "";
353
+ const hintEl = container.querySelector(".upload-hint");
354
+ if (this._files.length > 0) {
355
+ hintEl.innerHTML = `<strong>${this._files.length} file${this._files.length !== 1 ? "s" : ""} selected</strong>`;
356
+ }
357
+ else {
358
+ hintEl.innerHTML = `Drop files here or <span class="browse-link">click to browse</span>`;
359
+ }
360
+ const subHintEl = container.querySelector(".upload-sub-hint");
361
+ if (this.accept && this._files.length === 0) {
362
+ subHintEl.textContent = `Accepted: ${this.accept}`;
363
+ subHintEl.style.display = "";
364
+ }
365
+ else {
366
+ subHintEl.style.display = "none";
367
+ }
368
+ const fileList = container.querySelector(".file-list");
369
+ this.renderFileList(fileList);
370
+ const errorEl = container.querySelector(".error-message");
371
+ errorEl.textContent = this.error;
372
+ errorEl.style.display = this.error ? "" : "none";
373
+ }
395
374
  }
396
375
  TyFileUpload.formAssociated = true;
397
376
  TyFileUpload.properties = {
398
- multiple: {
399
- type: "boolean",
400
- visual: true,
401
- default: false,
402
- },
403
- accept: {
404
- type: "string",
405
- visual: true,
406
- default: "",
407
- },
408
- name: {
409
- type: "string",
410
- default: "",
411
- },
412
- disabled: {
413
- type: "boolean",
414
- visual: true,
415
- default: false,
416
- },
417
- required: {
418
- type: "boolean",
419
- visual: true,
420
- default: false,
421
- },
422
- label: {
423
- type: "string",
424
- visual: true,
425
- default: "",
426
- },
427
- placeholder: {
428
- type: "string",
429
- visual: true,
430
- default: "Drop files here or click to browse",
431
- },
432
- error: {
433
- type: "string",
434
- visual: true,
435
- default: "",
436
- },
377
+ multiple: {
378
+ type: "boolean",
379
+ visual: true,
380
+ default: false,
381
+ },
382
+ accept: {
383
+ type: "string",
384
+ visual: true,
385
+ default: "",
386
+ },
387
+ name: {
388
+ type: "string",
389
+ default: "",
390
+ },
391
+ disabled: {
392
+ type: "boolean",
393
+ visual: true,
394
+ default: false,
395
+ },
396
+ required: {
397
+ type: "boolean",
398
+ visual: true,
399
+ default: false,
400
+ },
401
+ label: {
402
+ type: "string",
403
+ visual: true,
404
+ default: "",
405
+ },
406
+ placeholder: {
407
+ type: "string",
408
+ visual: true,
409
+ default: "Drop files here or click to browse",
410
+ },
411
+ error: {
412
+ type: "string",
413
+ visual: true,
414
+ default: "",
415
+ },
437
416
  };
438
417
  if (!customElements.get("ty-file-upload")) {
439
- customElements.define("ty-file-upload", TyFileUpload);
418
+ customElements.define("ty-file-upload", TyFileUpload);
440
419
  }
441
- //# sourceMappingURL=file-upload.js.map