iss-ctrl 0.0.11 → 0.0.12

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 (287) hide show
  1. package/fesm2022/{iss-ctrl-iss-ctrl-hz0ibyPg.mjs → iss-ctrl-iss-ctrl-WfIqBEcL.mjs} +1348 -195
  2. package/fesm2022/iss-ctrl-iss-ctrl-WfIqBEcL.mjs.map +1 -0
  3. package/fesm2022/{iss-ctrl-load-event-BW5dKG8R.mjs → iss-ctrl-load-event-SlQmVmyf.mjs} +3 -3
  4. package/fesm2022/{iss-ctrl-load-event-BW5dKG8R.mjs.map → iss-ctrl-load-event-SlQmVmyf.mjs.map} +1 -1
  5. package/fesm2022/{iss-ctrl-load-options-event-ClX9TiiD.mjs → iss-ctrl-load-options-event-CBejHpME.mjs} +3 -3
  6. package/fesm2022/{iss-ctrl-load-options-event-ClX9TiiD.mjs.map → iss-ctrl-load-options-event-CBejHpME.mjs.map} +1 -1
  7. package/fesm2022/{iss-ctrl-load-value-event-DThpI9BA.mjs → iss-ctrl-load-value-event-Bu9-rZ6T.mjs} +3 -3
  8. package/fesm2022/{iss-ctrl-load-value-event-DThpI9BA.mjs.map → iss-ctrl-load-value-event-Bu9-rZ6T.mjs.map} +1 -1
  9. package/fesm2022/{iss-ctrl-note.field-4uLl0oS_.mjs → iss-ctrl-note.field-onDjqI_X.mjs} +24 -2
  10. package/fesm2022/iss-ctrl-note.field-onDjqI_X.mjs.map +1 -0
  11. package/fesm2022/{iss-ctrl-replace-api-keys-BQL9zimJ.mjs → iss-ctrl-replace-api-keys-Chwe42Nu.mjs} +2 -2
  12. package/fesm2022/{iss-ctrl-replace-api-keys-BQL9zimJ.mjs.map → iss-ctrl-replace-api-keys-Chwe42Nu.mjs.map} +1 -1
  13. package/fesm2022/{iss-ctrl-set-value-event-BbEYFBe3.mjs → iss-ctrl-set-value-event-DiHESiPT.mjs} +2 -2
  14. package/fesm2022/{iss-ctrl-set-value-event-BbEYFBe3.mjs.map → iss-ctrl-set-value-event-DiHESiPT.mjs.map} +1 -1
  15. package/fesm2022/{iss-ctrl-table.field-kPIwve-M.mjs → iss-ctrl-table.field-DxwfNXNc.mjs} +77 -2
  16. package/fesm2022/iss-ctrl-table.field-DxwfNXNc.mjs.map +1 -0
  17. package/fesm2022/{iss-ctrl-trigger-based-on-json-value-DuLD4SOS.mjs → iss-ctrl-trigger-based-on-json-value-CprcFCWi.mjs} +2 -2
  18. package/fesm2022/{iss-ctrl-trigger-based-on-json-value-DuLD4SOS.mjs.map → iss-ctrl-trigger-based-on-json-value-CprcFCWi.mjs.map} +1 -1
  19. package/fesm2022/{iss-ctrl-user-picker.field-l-0bW6lP.mjs → iss-ctrl-user-picker.field-Mqi37i7D.mjs} +33 -8
  20. package/fesm2022/iss-ctrl-user-picker.field-Mqi37i7D.mjs.map +1 -0
  21. package/fesm2022/iss-ctrl.mjs +1 -1
  22. package/package.json +1 -1
  23. package/types/iss-ctrl.d.ts +1117 -0
  24. package/fesm2022/iss-ctrl-iss-ctrl-hz0ibyPg.mjs.map +0 -1
  25. package/fesm2022/iss-ctrl-note.field-4uLl0oS_.mjs.map +0 -1
  26. package/fesm2022/iss-ctrl-table.field-kPIwve-M.mjs.map +0 -1
  27. package/fesm2022/iss-ctrl-user-picker.field-l-0bW6lP.mjs.map +0 -1
  28. package/src/components/controls/mobile/flags/ad.svg +0 -282
  29. package/src/components/controls/mobile/flags/ae.svg +0 -6
  30. package/src/components/controls/mobile/flags/af.svg +0 -9
  31. package/src/components/controls/mobile/flags/ag.svg +0 -15
  32. package/src/components/controls/mobile/flags/ai.svg +0 -35
  33. package/src/components/controls/mobile/flags/al.svg +0 -7
  34. package/src/components/controls/mobile/flags/am.svg +0 -5
  35. package/src/components/controls/mobile/flags/ao.svg +0 -19
  36. package/src/components/controls/mobile/flags/aq.svg +0 -45
  37. package/src/components/controls/mobile/flags/ar.svg +0 -66
  38. package/src/components/controls/mobile/flags/as.svg +0 -225
  39. package/src/components/controls/mobile/flags/at.svg +0 -4
  40. package/src/components/controls/mobile/flags/au.svg +0 -32
  41. package/src/components/controls/mobile/flags/aw.svg +0 -11
  42. package/src/components/controls/mobile/flags/ax.svg +0 -11
  43. package/src/components/controls/mobile/flags/az.svg +0 -11
  44. package/src/components/controls/mobile/flags/ba.svg +0 -18
  45. package/src/components/controls/mobile/flags/bb.svg +0 -11
  46. package/src/components/controls/mobile/flags/bd.svg +0 -4
  47. package/src/components/controls/mobile/flags/be.svg +0 -5
  48. package/src/components/controls/mobile/flags/bf.svg +0 -14
  49. package/src/components/controls/mobile/flags/bg.svg +0 -5
  50. package/src/components/controls/mobile/flags/bh.svg +0 -4
  51. package/src/components/controls/mobile/flags/bi.svg +0 -26
  52. package/src/components/controls/mobile/flags/bj.svg +0 -5
  53. package/src/components/controls/mobile/flags/bl.svg +0 -5
  54. package/src/components/controls/mobile/flags/bm.svg +0 -374
  55. package/src/components/controls/mobile/flags/bn.svg +0 -70
  56. package/src/components/controls/mobile/flags/bo.svg +0 -3625
  57. package/src/components/controls/mobile/flags/bq.svg +0 -5
  58. package/src/components/controls/mobile/flags/br.svg +0 -92
  59. package/src/components/controls/mobile/flags/bs.svg +0 -5
  60. package/src/components/controls/mobile/flags/bt.svg +0 -487
  61. package/src/components/controls/mobile/flags/bv.svg +0 -11
  62. package/src/components/controls/mobile/flags/bw.svg +0 -5
  63. package/src/components/controls/mobile/flags/by.svg +0 -15
  64. package/src/components/controls/mobile/flags/bz.svg +0 -629
  65. package/src/components/controls/mobile/flags/ca.svg +0 -7
  66. package/src/components/controls/mobile/flags/cc.svg +0 -33
  67. package/src/components/controls/mobile/flags/cd.svg +0 -5
  68. package/src/components/controls/mobile/flags/cf.svg +0 -7
  69. package/src/components/controls/mobile/flags/cg.svg +0 -5
  70. package/src/components/controls/mobile/flags/ch.svg +0 -4
  71. package/src/components/controls/mobile/flags/ci.svg +0 -5
  72. package/src/components/controls/mobile/flags/ck.svg +0 -29
  73. package/src/components/controls/mobile/flags/cl.svg +0 -14
  74. package/src/components/controls/mobile/flags/cm.svg +0 -15
  75. package/src/components/controls/mobile/flags/cn.svg +0 -11
  76. package/src/components/controls/mobile/flags/co.svg +0 -5
  77. package/src/components/controls/mobile/flags/cr.svg +0 -1332
  78. package/src/components/controls/mobile/flags/cu.svg +0 -6
  79. package/src/components/controls/mobile/flags/cv.svg +0 -24
  80. package/src/components/controls/mobile/flags/cw.svg +0 -16
  81. package/src/components/controls/mobile/flags/cx.svg +0 -24
  82. package/src/components/controls/mobile/flags/cy.svg +0 -13
  83. package/src/components/controls/mobile/flags/cz.svg +0 -5
  84. package/src/components/controls/mobile/flags/de.svg +0 -5
  85. package/src/components/controls/mobile/flags/dj.svg +0 -6
  86. package/src/components/controls/mobile/flags/dk.svg +0 -5
  87. package/src/components/controls/mobile/flags/dm.svg +0 -198
  88. package/src/components/controls/mobile/flags/do.svg +0 -238
  89. package/src/components/controls/mobile/flags/dz.svg +0 -5
  90. package/src/components/controls/mobile/flags/ec.svg +0 -1292
  91. package/src/components/controls/mobile/flags/ee.svg +0 -5
  92. package/src/components/controls/mobile/flags/eg.svg +0 -125
  93. package/src/components/controls/mobile/flags/eh.svg +0 -12
  94. package/src/components/controls/mobile/flags/er.svg +0 -9
  95. package/src/components/controls/mobile/flags/es.svg +0 -445
  96. package/src/components/controls/mobile/flags/et.svg +0 -16
  97. package/src/components/controls/mobile/flags/eu.svg +0 -28
  98. package/src/components/controls/mobile/flags/fi.svg +0 -5
  99. package/src/components/controls/mobile/flags/fj.svg +0 -203
  100. package/src/components/controls/mobile/flags/fk.svg +0 -922
  101. package/src/components/controls/mobile/flags/flags.png +0 -0
  102. package/src/components/controls/mobile/flags/flags@2x.png +0 -0
  103. package/src/components/controls/mobile/flags/fm.svg +0 -16
  104. package/src/components/controls/mobile/flags/fo.svg +0 -11
  105. package/src/components/controls/mobile/flags/fonts.css +0 -271
  106. package/src/components/controls/mobile/flags/fr.svg +0 -5
  107. package/src/components/controls/mobile/flags/ga.svg +0 -5
  108. package/src/components/controls/mobile/flags/gb-eng.svg +0 -7
  109. package/src/components/controls/mobile/flags/gb-nir.svg +0 -15
  110. package/src/components/controls/mobile/flags/gb-sct.svg +0 -11
  111. package/src/components/controls/mobile/flags/gb-wls.svg +0 -16
  112. package/src/components/controls/mobile/flags/gb.svg +0 -15
  113. package/src/components/controls/mobile/flags/gd.svg +0 -11
  114. package/src/components/controls/mobile/flags/ge.svg +0 -17
  115. package/src/components/controls/mobile/flags/gf.svg +0 -5
  116. package/src/components/controls/mobile/flags/gg.svg +0 -8
  117. package/src/components/controls/mobile/flags/gh.svg +0 -6
  118. package/src/components/controls/mobile/flags/gi.svg +0 -69
  119. package/src/components/controls/mobile/flags/gl.svg +0 -4
  120. package/src/components/controls/mobile/flags/gm.svg +0 -7
  121. package/src/components/controls/mobile/flags/gn.svg +0 -5
  122. package/src/components/controls/mobile/flags/gp.svg +0 -5
  123. package/src/components/controls/mobile/flags/gq.svg +0 -88
  124. package/src/components/controls/mobile/flags/gr.svg +0 -4
  125. package/src/components/controls/mobile/flags/gs.svg +0 -693
  126. package/src/components/controls/mobile/flags/gt.svg +0 -317
  127. package/src/components/controls/mobile/flags/gu.svg +0 -58
  128. package/src/components/controls/mobile/flags/gw.svg +0 -13
  129. package/src/components/controls/mobile/flags/gy.svg +0 -7
  130. package/src/components/controls/mobile/flags/hk.svg +0 -17
  131. package/src/components/controls/mobile/flags/hm.svg +0 -32
  132. package/src/components/controls/mobile/flags/hn.svg +0 -10
  133. package/src/components/controls/mobile/flags/hr.svg +0 -282
  134. package/src/components/controls/mobile/flags/ht.svg +0 -1470
  135. package/src/components/controls/mobile/flags/hu.svg +0 -5
  136. package/src/components/controls/mobile/flags/id.svg +0 -4
  137. package/src/components/controls/mobile/flags/ie.svg +0 -5
  138. package/src/components/controls/mobile/flags/il.svg +0 -5
  139. package/src/components/controls/mobile/flags/im.svg +0 -33
  140. package/src/components/controls/mobile/flags/in.svg +0 -25
  141. package/src/components/controls/mobile/flags/io.svg +0 -895
  142. package/src/components/controls/mobile/flags/iq.svg +0 -12
  143. package/src/components/controls/mobile/flags/ir.svg +0 -31
  144. package/src/components/controls/mobile/flags/is.svg +0 -5
  145. package/src/components/controls/mobile/flags/it.svg +0 -5
  146. package/src/components/controls/mobile/flags/je.svg +0 -40
  147. package/src/components/controls/mobile/flags/jm.svg +0 -9
  148. package/src/components/controls/mobile/flags/jo.svg +0 -10
  149. package/src/components/controls/mobile/flags/jp.svg +0 -4
  150. package/src/components/controls/mobile/flags/ke.svg +0 -28
  151. package/src/components/controls/mobile/flags/kg.svg +0 -7
  152. package/src/components/controls/mobile/flags/kh.svg +0 -133
  153. package/src/components/controls/mobile/flags/ki.svg +0 -54
  154. package/src/components/controls/mobile/flags/km.svg +0 -13
  155. package/src/components/controls/mobile/flags/kn.svg +0 -24
  156. package/src/components/controls/mobile/flags/kp.svg +0 -16
  157. package/src/components/controls/mobile/flags/kr.svg +0 -16
  158. package/src/components/controls/mobile/flags/kw.svg +0 -6
  159. package/src/components/controls/mobile/flags/ky.svg +0 -153
  160. package/src/components/controls/mobile/flags/kz.svg +0 -49
  161. package/src/components/controls/mobile/flags/la.svg +0 -5
  162. package/src/components/controls/mobile/flags/lb.svg +0 -8
  163. package/src/components/controls/mobile/flags/lc.svg +0 -6
  164. package/src/components/controls/mobile/flags/li.svg +0 -75
  165. package/src/components/controls/mobile/flags/lk.svg +0 -50
  166. package/src/components/controls/mobile/flags/lr.svg +0 -15
  167. package/src/components/controls/mobile/flags/ls.svg +0 -32
  168. package/src/components/controls/mobile/flags/lt.svg +0 -5
  169. package/src/components/controls/mobile/flags/lu.svg +0 -5
  170. package/src/components/controls/mobile/flags/lv.svg +0 -4
  171. package/src/components/controls/mobile/flags/ly.svg +0 -8
  172. package/src/components/controls/mobile/flags/ma.svg +0 -4
  173. package/src/components/controls/mobile/flags/mc.svg +0 -4
  174. package/src/components/controls/mobile/flags/md.svg +0 -102
  175. package/src/components/controls/mobile/flags/me.svg +0 -240
  176. package/src/components/controls/mobile/flags/mf.svg +0 -5
  177. package/src/components/controls/mobile/flags/mg.svg +0 -5
  178. package/src/components/controls/mobile/flags/mh.svg +0 -18
  179. package/src/components/controls/mobile/flags/mk.svg +0 -6
  180. package/src/components/controls/mobile/flags/ml.svg +0 -5
  181. package/src/components/controls/mobile/flags/mm.svg +0 -12
  182. package/src/components/controls/mobile/flags/mn.svg +0 -12
  183. package/src/components/controls/mobile/flags/mo.svg +0 -13
  184. package/src/components/controls/mobile/flags/mp.svg +0 -2919
  185. package/src/components/controls/mobile/flags/mq.svg +0 -5
  186. package/src/components/controls/mobile/flags/mr.svg +0 -5
  187. package/src/components/controls/mobile/flags/ms.svg +0 -59
  188. package/src/components/controls/mobile/flags/mt.svg +0 -52
  189. package/src/components/controls/mobile/flags/mu.svg +0 -6
  190. package/src/components/controls/mobile/flags/mv.svg +0 -8
  191. package/src/components/controls/mobile/flags/mw.svg +0 -24
  192. package/src/components/controls/mobile/flags/mx.svg +0 -1129
  193. package/src/components/controls/mobile/flags/my.svg +0 -12
  194. package/src/components/controls/mobile/flags/mz.svg +0 -50
  195. package/src/components/controls/mobile/flags/na.svg +0 -17
  196. package/src/components/controls/mobile/flags/nc.svg +0 -5
  197. package/src/components/controls/mobile/flags/ne.svg +0 -6
  198. package/src/components/controls/mobile/flags/nf.svg +0 -8
  199. package/src/components/controls/mobile/flags/ng.svg +0 -4
  200. package/src/components/controls/mobile/flags/ni.svg +0 -281
  201. package/src/components/controls/mobile/flags/nl.svg +0 -5
  202. package/src/components/controls/mobile/flags/no.svg +0 -11
  203. package/src/components/controls/mobile/flags/np.svg +0 -33
  204. package/src/components/controls/mobile/flags/nr.svg +0 -8
  205. package/src/components/controls/mobile/flags/nu.svg +0 -23
  206. package/src/components/controls/mobile/flags/nz.svg +0 -37
  207. package/src/components/controls/mobile/flags/om.svg +0 -307
  208. package/src/components/controls/mobile/flags/pa.svg +0 -15
  209. package/src/components/controls/mobile/flags/pe.svg +0 -767
  210. package/src/components/controls/mobile/flags/pf.svg +0 -38
  211. package/src/components/controls/mobile/flags/pg.svg +0 -16
  212. package/src/components/controls/mobile/flags/ph.svg +0 -28
  213. package/src/components/controls/mobile/flags/pk.svg +0 -7
  214. package/src/components/controls/mobile/flags/pl.svg +0 -4
  215. package/src/components/controls/mobile/flags/pm.svg +0 -5
  216. package/src/components/controls/mobile/flags/pn.svg +0 -131
  217. package/src/components/controls/mobile/flags/pr.svg +0 -6
  218. package/src/components/controls/mobile/flags/ps.svg +0 -6
  219. package/src/components/controls/mobile/flags/pt.svg +0 -79
  220. package/src/components/controls/mobile/flags/pw.svg +0 -4
  221. package/src/components/controls/mobile/flags/py.svg +0 -192
  222. package/src/components/controls/mobile/flags/qa.svg +0 -7
  223. package/src/components/controls/mobile/flags/re.svg +0 -5
  224. package/src/components/controls/mobile/flags/ro.svg +0 -5
  225. package/src/components/controls/mobile/flags/rs.svg +0 -1143
  226. package/src/components/controls/mobile/flags/ru.svg +0 -5
  227. package/src/components/controls/mobile/flags/rw.svg +0 -17
  228. package/src/components/controls/mobile/flags/sa.svg +0 -23
  229. package/src/components/controls/mobile/flags/sb.svg +0 -30
  230. package/src/components/controls/mobile/flags/sc.svg +0 -7
  231. package/src/components/controls/mobile/flags/sd.svg +0 -6
  232. package/src/components/controls/mobile/flags/se.svg +0 -5
  233. package/src/components/controls/mobile/flags/sg.svg +0 -15
  234. package/src/components/controls/mobile/flags/sh.svg +0 -15
  235. package/src/components/controls/mobile/flags/si.svg +0 -30
  236. package/src/components/controls/mobile/flags/sj.svg +0 -11
  237. package/src/components/controls/mobile/flags/sk.svg +0 -21
  238. package/src/components/controls/mobile/flags/sl.svg +0 -5
  239. package/src/components/controls/mobile/flags/sm.svg +0 -847
  240. package/src/components/controls/mobile/flags/sn.svg +0 -15
  241. package/src/components/controls/mobile/flags/so.svg +0 -13
  242. package/src/components/controls/mobile/flags/sr.svg +0 -6
  243. package/src/components/controls/mobile/flags/ss.svg +0 -8
  244. package/src/components/controls/mobile/flags/st.svg +0 -16
  245. package/src/components/controls/mobile/flags/stc-icons.css +0 -1
  246. package/src/components/controls/mobile/flags/sv.svg +0 -3368
  247. package/src/components/controls/mobile/flags/sx.svg +0 -172
  248. package/src/components/controls/mobile/flags/sy.svg +0 -6
  249. package/src/components/controls/mobile/flags/sz.svg +0 -54
  250. package/src/components/controls/mobile/flags/tc.svg +0 -88
  251. package/src/components/controls/mobile/flags/td.svg +0 -5
  252. package/src/components/controls/mobile/flags/tf.svg +0 -18
  253. package/src/components/controls/mobile/flags/tg.svg +0 -15
  254. package/src/components/controls/mobile/flags/th.svg +0 -5
  255. package/src/components/controls/mobile/flags/tj.svg +0 -32
  256. package/src/components/controls/mobile/flags/tk.svg +0 -25
  257. package/src/components/controls/mobile/flags/tl.svg +0 -6
  258. package/src/components/controls/mobile/flags/tm.svg +0 -349
  259. package/src/components/controls/mobile/flags/tn.svg +0 -9
  260. package/src/components/controls/mobile/flags/to.svg +0 -8
  261. package/src/components/controls/mobile/flags/tr.svg +0 -6
  262. package/src/components/controls/mobile/flags/tt.svg +0 -5
  263. package/src/components/controls/mobile/flags/tv.svg +0 -18
  264. package/src/components/controls/mobile/flags/tw.svg +0 -12
  265. package/src/components/controls/mobile/flags/tz.svg +0 -13
  266. package/src/components/controls/mobile/flags/ua.svg +0 -4
  267. package/src/components/controls/mobile/flags/ug.svg +0 -46
  268. package/src/components/controls/mobile/flags/um.svg +0 -25
  269. package/src/components/controls/mobile/flags/us.svg +0 -25
  270. package/src/components/controls/mobile/flags/uy.svg +0 -138
  271. package/src/components/controls/mobile/flags/uz.svg +0 -30
  272. package/src/components/controls/mobile/flags/va.svg +0 -277
  273. package/src/components/controls/mobile/flags/vc.svg +0 -9
  274. package/src/components/controls/mobile/flags/ve.svg +0 -28
  275. package/src/components/controls/mobile/flags/vg.svg +0 -96
  276. package/src/components/controls/mobile/flags/vi.svg +0 -311
  277. package/src/components/controls/mobile/flags/vn.svg +0 -12
  278. package/src/components/controls/mobile/flags/vu.svg +0 -20
  279. package/src/components/controls/mobile/flags/wf.svg +0 -7
  280. package/src/components/controls/mobile/flags/ws.svg +0 -14
  281. package/src/components/controls/mobile/flags/xk.svg +0 -11
  282. package/src/components/controls/mobile/flags/ye.svg +0 -5
  283. package/src/components/controls/mobile/flags/yt.svg +0 -5
  284. package/src/components/controls/mobile/flags/za.svg +0 -17
  285. package/src/components/controls/mobile/flags/zm.svg +0 -20
  286. package/src/components/controls/mobile/flags/zw.svg +0 -130
  287. package/src/upgrade.scss +0 -68
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Pipe, input, signal, output, Component, CUSTOM_ELEMENTS_SCHEMA, HostListener, Directive, computed, effect, ChangeDetectionStrategy, Injectable, inject, ElementRef, contentChild, isSignal, Injector, InjectionToken, DestroyRef } from '@angular/core';
2
+ import { Pipe, input, signal, output, inject, ElementRef, afterNextRender, Component, CUSTOM_ELEMENTS_SCHEMA, HostListener, Directive, computed, effect, ChangeDetectionStrategy, Injectable, contentChild, isSignal, Injector, InjectionToken, DestroyRef } from '@angular/core';
3
3
  import * as i1$2 from '@angular/forms';
4
4
  import { FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormGroup, FormsModule, Validators, ControlContainer } from '@angular/forms';
5
5
  import * as i1 from '@angular/material/checkbox';
@@ -49,21 +49,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
49
49
  args: [{ name: "selectStatus" }]
50
50
  }] });
51
51
 
52
+ /**
53
+ * Base class for every `iss-ctrl-*` control.
54
+ *
55
+ * Controls are the presentational layer: they know nothing about {@link IssField} and are
56
+ * driven purely by bindings, so they can be used standalone inside any reactive form.
57
+ * Every control below inherits the properties declared here and adds its own on top.
58
+ *
59
+ * ### Inherited inputs
60
+ * | Property | Type | Default | Description |
61
+ * | --- | --- | --- | --- |
62
+ * | `formControlName` | `string` | `""` | Name of the control in the surrounding `FormGroup`. |
63
+ * | `placeholder` | `string` | `""` | Placeholder text shown while the field is empty. |
64
+ * | `readonly` | `boolean` | `false` | Renders the value but blocks every interaction. |
65
+ * | `multiple` | `boolean \| undefined` | `false` | Allows more than one value, where the control supports it. |
66
+ * | `min` | `number \| string \| null` | `null` | Lower bound (number or date/time string). |
67
+ * | `max` | `number \| string \| null` | `null` | Upper bound (number or date/time string). |
68
+ * | `minLength` | `number \| null` | `null` | Minimum number of characters. |
69
+ * | `maxLength` | `number \| null` | `null` | Maximum number of characters. |
70
+ * | `hints` | `Hint[]` | `[]` | Helper messages rendered under the field. |
71
+ * | `className` | `string \| null` | `null` | Extra CSS classes for the host. |
72
+ *
73
+ * ### Inherited outputs
74
+ * | Event | Payload | Description |
75
+ * | --- | --- | --- |
76
+ * | `(onChange)` | `any` | Fires after every committed value change. |
77
+ *
78
+ * ### Not inputs
79
+ * `disabled` and `touched` are signals owned by the control. Disable a control through the
80
+ * forms API (`ctrl.disable()` or a `disabled` field config), never with a template binding.
81
+ *
82
+ * ### Content projection
83
+ * Controls that render a `mat-form-field` project `<label>` into the floating label.
84
+ * The label space collapses automatically when no `<label>` is supplied.
85
+ *
86
+ * @example
87
+ * ```html
88
+ * <iss-ctrl-input formControlName="email" [readonly]="false" (onChange)="save($event)">
89
+ * <label>Email</label>
90
+ * </iss-ctrl-input>
91
+ * ```
92
+ */
52
93
  class ControlBase {
94
+ /**
95
+ * Name of this control inside the surrounding `FormGroup`.
96
+ */
53
97
  formControlName = input("", ...(ngDevMode ? [{ debugName: "formControlName" }] : /* istanbul ignore next */ []));
98
+ /**
99
+ * Lower bound forwarded to the underlying input — a number, or a date/time string.
100
+ */
54
101
  min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
102
+ /**
103
+ * Upper bound forwarded to the underlying input — a number, or a date/time string.
104
+ */
55
105
  max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
106
+ /**
107
+ * Minimum number of characters accepted by the underlying input.
108
+ */
56
109
  minLength = input(null, ...(ngDevMode ? [{ debugName: "minLength" }] : /* istanbul ignore next */ []));
110
+ /**
111
+ * Maximum number of characters accepted by the underlying input.
112
+ */
57
113
  maxLength = input(null, ...(ngDevMode ? [{ debugName: "maxLength" }] : /* istanbul ignore next */ []));
114
+ /**
115
+ * Disabled state. **Not an input** — it is set by the forms API through
116
+ * {@link ControlBase.setDisabledState}. Disable via `ctrl.disable()` or the field config.
117
+ */
58
118
  disabled = signal(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
119
+ /**
120
+ * Renders the current value but blocks every user interaction.
121
+ */
59
122
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
123
+ /**
124
+ * Allows selecting/entering more than one value, on controls that support it.
125
+ */
60
126
  multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
127
+ /**
128
+ * Placeholder text shown while the control has no value.
129
+ */
61
130
  placeholder = input("", ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
131
+ /**
132
+ * Helper messages rendered beneath the field. See {@link Hint}.
133
+ */
62
134
  hints = input([], ...(ngDevMode ? [{ debugName: "hints" }] : /* istanbul ignore next */ []));
135
+ /**
136
+ * Extra CSS class names applied to the control host.
137
+ */
63
138
  className = input(null, ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
139
+ /**
140
+ * Whether the user has interacted with the control. Owned by the control, not an input.
141
+ */
64
142
  touched = signal(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
143
+ /**
144
+ * Emits the committed value after every change.
145
+ */
65
146
  onChange = output();
66
147
  ctrl = new FormControl(null);
148
+ // mat-form-field reserves the floating-label space as soon as a <mat-label> exists, so an
149
+ // unused `<ng-content select="label">` leaves an empty gap above the field. Templates guard
150
+ // their <mat-label> with this flag, which is resolved once the projected content is rendered.
151
+ hasLabel = signal(true, ...(ngDevMode ? [{ debugName: "hasLabel" }] : /* istanbul ignore next */ []));
152
+ hostRef = inject(ElementRef);
153
+ constructor() {
154
+ afterNextRender(() => this.hasLabel.set(this.hasProjectedLabel()));
155
+ }
67
156
  registerOnChange(fn) {
68
157
  this.onPropagateValue = fn;
69
158
  }
@@ -89,6 +178,10 @@ class ControlBase {
89
178
  validate(control) {
90
179
  return this.ctrl.errors;
91
180
  }
181
+ hasProjectedLabel() {
182
+ const label = this.hostRef.nativeElement.querySelector("mat-label label");
183
+ return !!label && !!(label.textContent || "").trim();
184
+ }
92
185
  onTouch = () => { };
93
186
  onPropagateValue = (_) => { };
94
187
  emitValue(value) {
@@ -119,10 +212,37 @@ class ControlBase {
119
212
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ControlBase, decorators: [{
120
213
  type: Component,
121
214
  args: [{ template: `` }]
122
- }], propDecorators: { formControlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "formControlName", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hints: [{ type: i0.Input, args: [{ isSignal: true, alias: "hints", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], onChange: [{ type: i0.Output, args: ["onChange"] }] } });
215
+ }], ctorParameters: () => [], propDecorators: { formControlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "formControlName", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hints: [{ type: i0.Input, args: [{ isSignal: true, alias: "hints", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], onChange: [{ type: i0.Output, args: ["onChange"] }] } });
123
216
 
217
+ /**
218
+ * `<iss-ctrl-checkbox>` — a list of checkboxes over a fixed set of options.
219
+ *
220
+ * The form value is the comma separated list of selected option values, while `(onChange)`
221
+ * emits the resolved `Option[]` (or `null` when nothing is selected).
222
+ *
223
+ * @example
224
+ * ```html
225
+ * <iss-ctrl-checkbox formControlName="days" [options]="days" (onChange)="pick($event)"/>
226
+ * ```
227
+ *
228
+ * ### Own inputs
229
+ * | Property | Type | Default | Description |
230
+ * | --- | --- | --- | --- |
231
+ * | `options` | `Option[]` | **required** | The selectable choices. |
232
+ *
233
+ * ### Inherited from {@link ControlBase}
234
+ * `formControlName` · `readonly` · `className` · `(onChange)`
235
+ *
236
+ * Does not project a label — the field label is rendered by the wrapping `iss-field-*`.
237
+ */
124
238
  class CheckboxControl extends ControlBase {
239
+ /**
240
+ * Selectable choices, each a `{ value, label }` pair. Required.
241
+ */
125
242
  options = input.required(...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
243
+ /**
244
+ * Currently checked options, keyed by value. Internal state, not an input.
245
+ */
126
246
  selectedOptions = signal(new Map(), ...(ngDevMode ? [{ debugName: "selectedOptions" }] : /* istanbul ignore next */ []));
127
247
  writeValue(value) {
128
248
  this.#reset();
@@ -191,7 +311,7 @@ class CheckboxControl extends ControlBase {
191
311
  <ul class="list-unstyled">
192
312
  @for (option of options(); track option.value) {
193
313
  <li class="mb-2">
194
- <mat-checkbox [checked]="option | selectStatus: selectedOptions()" [disabled]="disabled() || readonly()" (change)="onCheckboxChange($event.checked, option.value)">
314
+ <mat-checkbox [checked]="option | selectStatus: selectedOptions()" [disabled]="disabled() || readonly()" (change)="onCheckboxChange($event.checked, option.value)">
195
315
  {{ option.label }}
196
316
  </mat-checkbox>
197
317
  </li>
@@ -211,7 +331,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
211
331
  <ul class="list-unstyled">
212
332
  @for (option of options(); track option.value) {
213
333
  <li class="mb-2">
214
- <mat-checkbox [checked]="option | selectStatus: selectedOptions()" [disabled]="disabled() || readonly()" (change)="onCheckboxChange($event.checked, option.value)">
334
+ <mat-checkbox [checked]="option | selectStatus: selectedOptions()" [disabled]="disabled() || readonly()" (change)="onCheckboxChange($event.checked, option.value)">
215
335
  {{ option.label }}
216
336
  </mat-checkbox>
217
337
  </li>
@@ -221,7 +341,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
221
341
  }]
222
342
  }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }] } });
223
343
 
344
+ /**
345
+ * `<iss-ctrl-chips>` — free text entered as removable chips.
346
+ *
347
+ * Each `Enter` turns the typed text into a chip. The form value is the comma separated list
348
+ * of chip labels.
349
+ *
350
+ * @example
351
+ * ```html
352
+ * <iss-ctrl-chips formControlName="tags" placeholder="Add a tag">
353
+ * <label>Tags</label>
354
+ * </iss-ctrl-chips>
355
+ * ```
356
+ *
357
+ * ### Own inputs
358
+ * None — the control is configured entirely through the inherited properties.
359
+ *
360
+ * ### Inherited from {@link ControlBase}
361
+ * `formControlName` · `readonly` · `className` · `(onChange)` · `placeholder`
362
+ *
363
+ * Projects `<label>` into the floating label; omit it to render the control without one.
364
+ */
224
365
  class ChipsControl extends ControlBase {
366
+ /**
367
+ * The chips currently rendered. Internal state, not an input.
368
+ */
225
369
  keywords = signal([], ...(ngDevMode ? [{ debugName: "keywords" }] : /* istanbul ignore next */ []));
226
370
  writeValue(value) {
227
371
  if (typeof value === "string") {
@@ -269,15 +413,17 @@ class ChipsControl extends ControlBase {
269
413
  { provide: NG_VALUE_ACCESSOR, useExisting: ChipsControl, multi: true }
270
414
  ], usesInheritance: true, ngImport: i0, template: `
271
415
  <mat-form-field floatLabel="auto" class="">
272
- <mat-label class="fs-16 fc-black">
273
- <ng-content select="label"></ng-content>
274
- </mat-label>
416
+ @if (hasLabel()) {
417
+ <mat-label class="fs-16 fc-black">
418
+ <ng-content select="label"></ng-content>
419
+ </mat-label>
420
+ }
275
421
  <input
276
422
  matInput
277
- [placeholder]="placeholder()"
278
- [matChipInputFor]="chipGrid"
279
- [disabled]="disabled()"
280
- [readonly]="readonly()"
423
+ [placeholder]="placeholder()"
424
+ [matChipInputFor]="chipGrid"
425
+ [disabled]="disabled()"
426
+ [readonly]="readonly()"
281
427
  (matChipInputTokenEnd)="add($event)"
282
428
  />
283
429
  </mat-form-field>
@@ -285,7 +431,7 @@ class ChipsControl extends ControlBase {
285
431
  @for (keyword of keywords(); track keyword) {
286
432
  <mat-chip-row (removed)="remove(keyword)">
287
433
  {{ keyword }}
288
- <button matChipRemove [disabled]="disabled() || readonly()">
434
+ <button matChipRemove [disabled]="disabled() || readonly()">
289
435
  <ds-icon icon="trash" class="fc-red"></ds-icon>
290
436
  </button>
291
437
  </mat-chip-row>
@@ -313,15 +459,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
313
459
  ],
314
460
  template: `
315
461
  <mat-form-field floatLabel="auto" class="">
316
- <mat-label class="fs-16 fc-black">
317
- <ng-content select="label"></ng-content>
318
- </mat-label>
462
+ @if (hasLabel()) {
463
+ <mat-label class="fs-16 fc-black">
464
+ <ng-content select="label"></ng-content>
465
+ </mat-label>
466
+ }
319
467
  <input
320
468
  matInput
321
- [placeholder]="placeholder()"
322
- [matChipInputFor]="chipGrid"
323
- [disabled]="disabled()"
324
- [readonly]="readonly()"
469
+ [placeholder]="placeholder()"
470
+ [matChipInputFor]="chipGrid"
471
+ [disabled]="disabled()"
472
+ [readonly]="readonly()"
325
473
  (matChipInputTokenEnd)="add($event)"
326
474
  />
327
475
  </mat-form-field>
@@ -329,7 +477,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
329
477
  @for (keyword of keywords(); track keyword) {
330
478
  <mat-chip-row (removed)="remove(keyword)">
331
479
  {{ keyword }}
332
- <button matChipRemove [disabled]="disabled() || readonly()">
480
+ <button matChipRemove [disabled]="disabled() || readonly()">
333
481
  <ds-icon icon="trash" class="fc-red"></ds-icon>
334
482
  </button>
335
483
  </mat-chip-row>
@@ -355,9 +503,43 @@ const DATE_FORMAT_ADAPTER = {
355
503
  };
356
504
  const DATETIME_FORMAT = "dd/MM/yyyy hh:mm a";
357
505
 
506
+ /**
507
+ * `<iss-ctrl-date-picker>` — single date selection through a Material calendar.
508
+ *
509
+ * The input itself is read-only; clicking it opens the calendar. The emitted value is a
510
+ * `yyyy-MM-dd` string, and a clear button appears once a date is picked.
511
+ *
512
+ * @example
513
+ * ```html
514
+ * <iss-ctrl-date-picker formControlName="startsOn" [minDate]="today" [disabledDays]="[5, 6]">
515
+ * <label>Start date</label>
516
+ * </iss-ctrl-date-picker>
517
+ * ```
518
+ *
519
+ * ### Own inputs
520
+ * | Property | Type | Default | Description |
521
+ * | --- | --- | --- | --- |
522
+ * | `minDate` | `Date \| null` | `null` | Earliest selectable date. |
523
+ * | `maxDate` | `Date \| null` | `null` | Latest selectable date. |
524
+ * | `disabledDays` | `number[]` | `[]` | Week days to block, `0` = Sunday … `6` = Saturday. |
525
+ *
526
+ * ### Inherited from {@link ControlBase}
527
+ * `formControlName` · `readonly` · `className` · `(onChange)`
528
+ *
529
+ * Projects `<label>` into the floating label; omit it to render the control without one.
530
+ */
358
531
  class DatePickerControl extends ControlBase {
532
+ /**
533
+ * Week days that cannot be selected — `0` is Sunday through `6` for Saturday.
534
+ */
359
535
  disabledDays = input([], ...(ngDevMode ? [{ debugName: "disabledDays" }] : /* istanbul ignore next */ []));
536
+ /**
537
+ * Earliest selectable date.
538
+ */
360
539
  minDate = input(null, ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
540
+ /**
541
+ * Latest selectable date.
542
+ */
361
543
  maxDate = input(null, ...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
362
544
  clear(event) {
363
545
  if (this.readonly()) {
@@ -397,17 +579,19 @@ class DatePickerControl extends ControlBase {
397
579
  { provide: NG_VALIDATORS, useExisting: DatePickerControl, multi: true },
398
580
  ], usesInheritance: true, ngImport: i0, template: `
399
581
  <mat-form-field floatLabel="auto" class="">
400
- <mat-label class="fs-16 fc-black">
401
- <ng-content select="label"></ng-content>
402
- </mat-label>
582
+ @if (hasLabel()) {
583
+ <mat-label class="fs-16 fc-black">
584
+ <ng-content select="label"></ng-content>
585
+ </mat-label>
586
+ }
403
587
  <input
404
588
  class="cursor-pointer"
405
589
  matInput
406
590
  readonly
407
591
  [matDatepicker]="picker"
408
- (click)="openPicker(picker)"
409
- [formControl]="ctrl"
410
- [readonly]="readonly()"
592
+ (click)="openPicker(picker)"
593
+ [formControl]="ctrl"
594
+ [readonly]="readonly()"
411
595
  [min]="minDate()"
412
596
  [max]="maxDate()"
413
597
  [matDatepickerFilter]="calendarDaysFilter"
@@ -416,7 +600,7 @@ class DatePickerControl extends ControlBase {
416
600
  @if (ctrl.getRawValue()) {
417
601
  <mat-icon matSuffix style="cursor: pointer" (click)="clear($event)">close</mat-icon>
418
602
  }
419
- <mat-datepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
603
+ <mat-datepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
420
604
  <mat-datepicker #picker></mat-datepicker>
421
605
 
422
606
  </mat-form-field>
@@ -432,17 +616,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
432
616
  { provide: NG_VALIDATORS, useExisting: DatePickerControl, multi: true },
433
617
  ], template: `
434
618
  <mat-form-field floatLabel="auto" class="">
435
- <mat-label class="fs-16 fc-black">
436
- <ng-content select="label"></ng-content>
437
- </mat-label>
619
+ @if (hasLabel()) {
620
+ <mat-label class="fs-16 fc-black">
621
+ <ng-content select="label"></ng-content>
622
+ </mat-label>
623
+ }
438
624
  <input
439
625
  class="cursor-pointer"
440
626
  matInput
441
627
  readonly
442
628
  [matDatepicker]="picker"
443
- (click)="openPicker(picker)"
444
- [formControl]="ctrl"
445
- [readonly]="readonly()"
629
+ (click)="openPicker(picker)"
630
+ [formControl]="ctrl"
631
+ [readonly]="readonly()"
446
632
  [min]="minDate()"
447
633
  [max]="maxDate()"
448
634
  [matDatepickerFilter]="calendarDaysFilter"
@@ -451,18 +637,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
451
637
  @if (ctrl.getRawValue()) {
452
638
  <mat-icon matSuffix style="cursor: pointer" (click)="clear($event)">close</mat-icon>
453
639
  }
454
- <mat-datepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
640
+ <mat-datepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
455
641
  <mat-datepicker #picker></mat-datepicker>
456
642
 
457
643
  </mat-form-field>
458
644
  ` }]
459
645
  }], propDecorators: { disabledDays: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDays", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }] } });
460
646
 
647
+ /**
648
+ * `<iss-ctrl-date-range-picker>` — a start/end date range in one field.
649
+ *
650
+ * A half-filled range is not a value: clearing either endpoint clears the form value and
651
+ * emits `null`. The form value is a `yyyy-MM-dd` string pair; `(onDateRangeObjectChange)`
652
+ * emits the same range as a {@link DateRangeEmission} object.
653
+ *
654
+ * @example
655
+ * ```html
656
+ * <iss-ctrl-date-range-picker formControlName="period" (onDateRangeObjectChange)="apply($event)">
657
+ * <label>Period</label>
658
+ * </iss-ctrl-date-range-picker>
659
+ * ```
660
+ *
661
+ * ### Own inputs
662
+ * | Property | Type | Default | Description |
663
+ * | --- | --- | --- | --- |
664
+ * | `minDate` | `Date \| null` | `null` | Earliest selectable date. |
665
+ * | `maxDate` | `Date \| null` | `null` | Latest selectable date. |
666
+ * | `disabledDays` | `number[]` | `[]` | Week days to block, `0` = Sunday … `6` = Saturday. |
667
+ *
668
+ * ### Inherited from {@link ControlBase}
669
+ * `formControlName` · `readonly` · `className` · `(onChange)`
670
+ *
671
+ * ### Outputs
672
+ * - `(onDateRangeObjectChange)` — `DateRangeEmission | null`, the range as an object.
673
+ *
674
+ * Projects `<label>` into the floating label; omit it to render the control without one.
675
+ */
461
676
  class DateRangePickerControl extends ControlBase {
677
+ /**
678
+ * Week days that cannot be selected — `0` is Sunday through `6` for Saturday.
679
+ */
462
680
  disabledDays = input([], ...(ngDevMode ? [{ debugName: "disabledDays" }] : /* istanbul ignore next */ []));
681
+ /**
682
+ * Earliest selectable date.
683
+ */
463
684
  minDate = input(null, ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
685
+ /**
686
+ * Latest selectable date.
687
+ */
464
688
  maxDate = input(null, ...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
689
+ /**
690
+ * Emits the selected range as an object, or `null` while the range is incomplete.
691
+ */
465
692
  onDateRangeObjectChange = output();
693
+ /**
694
+ * The `start`/`end` form group backing the range input. Internal state.
695
+ */
466
696
  range = new FormGroup({
467
697
  start: new FormControl(null),
468
698
  end: new FormControl(null),
@@ -565,9 +795,11 @@ class DateRangePickerControl extends ControlBase {
565
795
  ], usesInheritance: true, ngImport: i0, template: `
566
796
  <mat-form-field floatLabel="auto" class="">
567
797
 
568
- <mat-label class="fs-16 fc-black">
569
- <ng-content select="label"></ng-content>
570
- </mat-label>
798
+ @if (hasLabel()) {
799
+ <mat-label class="fs-16 fc-black">
800
+ <ng-content select="label"></ng-content>
801
+ </mat-label>
802
+ }
571
803
  <mat-date-range-input
572
804
  [formGroup]="range"
573
805
  [rangePicker]="picker"
@@ -577,23 +809,23 @@ class DateRangePickerControl extends ControlBase {
577
809
  >
578
810
  <input
579
811
  matStartDate
580
- formControlName="start"
581
- [readonly]="readonly()"
812
+ formControlName="start"
813
+ [readonly]="readonly()"
582
814
  placeholder="dd/mm/yyyy"
583
- (click)="openPicker(picker)"
815
+ (click)="openPicker(picker)"
584
816
  />
585
817
  <input
586
818
  matEndDate
587
- formControlName="end"
588
- [readonly]="readonly()"
819
+ formControlName="end"
820
+ [readonly]="readonly()"
589
821
  placeholder="dd/mm/yyyy"
590
- (click)="openPicker(picker)"
822
+ (click)="openPicker(picker)"
591
823
  />
592
824
  </mat-date-range-input>
593
825
  @if (range.getRawValue().start || range.getRawValue().end) {
594
826
  <mat-icon matSuffix style="cursor: pointer" (click)="clear($event)">close</mat-icon>
595
827
  }
596
- <mat-datepicker-toggle matSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
828
+ <mat-datepicker-toggle matSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
597
829
  <mat-date-range-picker #picker></mat-date-range-picker>
598
830
 
599
831
  </mat-form-field>
@@ -617,9 +849,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
617
849
  template: `
618
850
  <mat-form-field floatLabel="auto" class="">
619
851
 
620
- <mat-label class="fs-16 fc-black">
621
- <ng-content select="label"></ng-content>
622
- </mat-label>
852
+ @if (hasLabel()) {
853
+ <mat-label class="fs-16 fc-black">
854
+ <ng-content select="label"></ng-content>
855
+ </mat-label>
856
+ }
623
857
  <mat-date-range-input
624
858
  [formGroup]="range"
625
859
  [rangePicker]="picker"
@@ -629,23 +863,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
629
863
  >
630
864
  <input
631
865
  matStartDate
632
- formControlName="start"
633
- [readonly]="readonly()"
866
+ formControlName="start"
867
+ [readonly]="readonly()"
634
868
  placeholder="dd/mm/yyyy"
635
- (click)="openPicker(picker)"
869
+ (click)="openPicker(picker)"
636
870
  />
637
871
  <input
638
872
  matEndDate
639
- formControlName="end"
640
- [readonly]="readonly()"
873
+ formControlName="end"
874
+ [readonly]="readonly()"
641
875
  placeholder="dd/mm/yyyy"
642
- (click)="openPicker(picker)"
876
+ (click)="openPicker(picker)"
643
877
  />
644
878
  </mat-date-range-input>
645
879
  @if (range.getRawValue().start || range.getRawValue().end) {
646
880
  <mat-icon matSuffix style="cursor: pointer" (click)="clear($event)">close</mat-icon>
647
881
  }
648
- <mat-datepicker-toggle matSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
882
+ <mat-datepicker-toggle matSuffix [for]="picker" [disabled]="readonly()"></mat-datepicker-toggle>
649
883
  <mat-date-range-picker #picker></mat-date-range-picker>
650
884
 
651
885
  </mat-form-field>
@@ -653,9 +887,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
653
887
  }]
654
888
  }], propDecorators: { disabledDays: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDays", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], onDateRangeObjectChange: [{ type: i0.Output, args: ["onDateRangeObjectChange"] }] } });
655
889
 
890
+ /**
891
+ * `<iss-ctrl-time-picker>` — time of day, picked from a list generated at a fixed interval.
892
+ *
893
+ * @example
894
+ * ```html
895
+ * <iss-ctrl-time-picker formControlName="startsAt" interval="15min" minTime="08:00" maxTime="17:00">
896
+ * <label>Starts at</label>
897
+ * </iss-ctrl-time-picker>
898
+ * ```
899
+ *
900
+ * ### Own inputs
901
+ * | Property | Type | Default | Description |
902
+ * | --- | --- | --- | --- |
903
+ * | `interval` | `string` | `"30min"` | Step between the offered times. |
904
+ * | `minTime` | `string \| null` | `null` | Earliest offered time, `HH:mm`. |
905
+ * | `maxTime` | `string \| null` | `null` | Latest offered time, `HH:mm`. |
906
+ *
907
+ * ### Inherited from {@link ControlBase}
908
+ * `formControlName` · `readonly` · `className` · `(onChange)`
909
+ *
910
+ * Projects `<label>` into the floating label; omit it to render the control without one.
911
+ */
656
912
  class TimePickerControl extends ControlBase {
913
+ /**
914
+ * Step between the offered times, for example `"15min"` or `"30min"`.
915
+ */
657
916
  interval = input("30min", ...(ngDevMode ? [{ debugName: "interval" }] : /* istanbul ignore next */ []));
917
+ /**
918
+ * Earliest offered time of day, as `HH:mm`.
919
+ */
658
920
  minTime = input(null, ...(ngDevMode ? [{ debugName: "minTime" }] : /* istanbul ignore next */ []));
921
+ /**
922
+ * Latest offered time of day, as `HH:mm`.
923
+ */
659
924
  maxTime = input(null, ...(ngDevMode ? [{ debugName: "maxTime" }] : /* istanbul ignore next */ []));
660
925
  emit(evt) {
661
926
  if (this.readonly()) {
@@ -705,22 +970,24 @@ class TimePickerControl extends ControlBase {
705
970
  { provide: NG_VALIDATORS, useExisting: TimePickerControl, multi: true },
706
971
  ], usesInheritance: true, ngImport: i0, template: `
707
972
  <mat-form-field floatLabel="auto" class="">
708
- <mat-label class="fs-16 fc-black">
709
- <ng-content select="label"></ng-content>
710
- </mat-label>
973
+ @if (hasLabel()) {
974
+ <mat-label class="fs-16 fc-black">
975
+ <ng-content select="label"></ng-content>
976
+ </mat-label>
977
+ }
711
978
  <input
712
979
  matInput
713
980
  [formControl]="ctrl"
714
981
  [matTimepicker]="picker"
715
982
  [matTimepickerMin]="minTime()"
716
- [matTimepickerMax]="maxTime()"
717
- [readonly]="readonly()"
983
+ [matTimepickerMax]="maxTime()"
984
+ [readonly]="readonly()"
718
985
  readonly
719
986
  />
720
987
  @if (ctrl.getRawValue()) {
721
988
  <mat-icon matSuffix style="cursor: pointer" (click)="clear($event)">close</mat-icon>
722
989
  }
723
- <mat-timepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"/>
990
+ <mat-timepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"/>
724
991
  <mat-timepicker (selected)="emit($event)" [interval]="interval()" #picker/>
725
992
 
726
993
  </mat-form-field>
@@ -741,22 +1008,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
741
1008
  ],
742
1009
  template: `
743
1010
  <mat-form-field floatLabel="auto" class="">
744
- <mat-label class="fs-16 fc-black">
745
- <ng-content select="label"></ng-content>
746
- </mat-label>
1011
+ @if (hasLabel()) {
1012
+ <mat-label class="fs-16 fc-black">
1013
+ <ng-content select="label"></ng-content>
1014
+ </mat-label>
1015
+ }
747
1016
  <input
748
1017
  matInput
749
1018
  [formControl]="ctrl"
750
1019
  [matTimepicker]="picker"
751
1020
  [matTimepickerMin]="minTime()"
752
- [matTimepickerMax]="maxTime()"
753
- [readonly]="readonly()"
1021
+ [matTimepickerMax]="maxTime()"
1022
+ [readonly]="readonly()"
754
1023
  readonly
755
1024
  />
756
1025
  @if (ctrl.getRawValue()) {
757
1026
  <mat-icon matSuffix style="cursor: pointer" (click)="clear($event)">close</mat-icon>
758
1027
  }
759
- <mat-timepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"/>
1028
+ <mat-timepicker-toggle matIconSuffix [for]="picker" [disabled]="readonly()"/>
760
1029
  <mat-timepicker (selected)="emit($event)" [interval]="interval()" #picker/>
761
1030
 
762
1031
  </mat-form-field>
@@ -764,15 +1033,57 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
764
1033
  }]
765
1034
  }], propDecorators: { interval: [{ type: i0.Input, args: [{ isSignal: true, alias: "interval", required: false }] }], minTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTime", required: false }] }], maxTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTime", required: false }] }] } });
766
1035
 
1036
+ /**
1037
+ * `<iss-ctrl-datetime-picker>` — a date and a time in a single field.
1038
+ *
1039
+ * Combines the calendar of the date picker with the time list of the time picker; both parts
1040
+ * must be set before a value is emitted.
1041
+ *
1042
+ * @example
1043
+ * ```html
1044
+ * <iss-ctrl-datetime-picker formControlName="scheduledAt" [minDate]="today" minTime="08:00" maxTime="17:00">
1045
+ * <label>Scheduled at</label>
1046
+ * </iss-ctrl-datetime-picker>
1047
+ * ```
1048
+ *
1049
+ * ### Own inputs
1050
+ * | Property | Type | Default | Description |
1051
+ * | --- | --- | --- | --- |
1052
+ * | `minDate` | `Date \| null` | `null` | Earliest selectable date. |
1053
+ * | `maxDate` | `Date \| null` | `null` | Latest selectable date. |
1054
+ * | `minTime` | `string \| null` | `null` | Earliest selectable time, `HH:mm`. |
1055
+ * | `maxTime` | `string \| null` | `null` | Latest selectable time, `HH:mm`. |
1056
+ * | `disabledDays` | `number[]` | `[]` | Week days to block, `0` = Sunday … `6` = Saturday. |
1057
+ *
1058
+ * ### Inherited from {@link ControlBase}
1059
+ * `formControlName` · `readonly` · `className` · `(onChange)`
1060
+ *
1061
+ * Projects `<label>` into the floating label; omit it to render the control without one.
1062
+ */
767
1063
  class DatetimePickerControl extends ControlBase {
768
1064
  datetimeForm = new FormGroup({
769
1065
  date: new FormControl(null),
770
1066
  time: new FormControl(null),
771
1067
  });
1068
+ /**
1069
+ * Week days that cannot be selected — `0` is Sunday through `6` for Saturday.
1070
+ */
772
1071
  disabledDays = input([], ...(ngDevMode ? [{ debugName: "disabledDays" }] : /* istanbul ignore next */ []));
1072
+ /**
1073
+ * Earliest selectable date.
1074
+ */
773
1075
  minDate = input(null, ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
1076
+ /**
1077
+ * Latest selectable date.
1078
+ */
774
1079
  maxDate = input(null, ...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
1080
+ /**
1081
+ * Earliest selectable time of day, as `HH:mm`.
1082
+ */
775
1083
  minTime = input(null, ...(ngDevMode ? [{ debugName: "minTime" }] : /* istanbul ignore next */ []));
1084
+ /**
1085
+ * Latest selectable time of day, as `HH:mm`.
1086
+ */
776
1087
  maxTime = input(null, ...(ngDevMode ? [{ debugName: "maxTime" }] : /* istanbul ignore next */ []));
777
1088
  setDisabledState(isDisabled) {
778
1089
  super.setDisabledState(isDisabled);
@@ -839,7 +1150,7 @@ class DatetimePickerControl extends ControlBase {
839
1150
  { provide: NG_VALIDATORS, useExisting: DatetimePickerControl, multi: true },
840
1151
  ], usesInheritance: true, ngImport: i0, template: `
841
1152
  <form [formGroup]="datetimeForm" class="d-flex flex-row gap-1">
842
- <iss-ctrl-date-picker (focusout)="markAsTouched()" [disabledDays]="disabledDays()" [maxDate]="maxDate()" [minDate]="minDate()" [readonly]="readonly()" formControlName="date" (onChange)="emit()">
1153
+ <iss-ctrl-date-picker (focusout)="markAsTouched()" [disabledDays]="disabledDays()" [maxDate]="maxDate()" [minDate]="minDate()" [readonly]="readonly()" formControlName="date" (onChange)="emit()">
843
1154
  <label>
844
1155
  <ng-content select="label"></ng-content>
845
1156
  </label>
@@ -847,8 +1158,8 @@ class DatetimePickerControl extends ControlBase {
847
1158
  <iss-ctrl-time-picker
848
1159
  (focusout)="markAsTouched()"
849
1160
  [maxTime]="maxTime()"
850
- [minTime]="minTime()"
851
- [readonly]="readonly()"
1161
+ [minTime]="minTime()"
1162
+ [readonly]="readonly()"
852
1163
  formControlName="time"
853
1164
  (onChange)="emit()"
854
1165
  />
@@ -874,7 +1185,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
874
1185
  ],
875
1186
  template: `
876
1187
  <form [formGroup]="datetimeForm" class="d-flex flex-row gap-1">
877
- <iss-ctrl-date-picker (focusout)="markAsTouched()" [disabledDays]="disabledDays()" [maxDate]="maxDate()" [minDate]="minDate()" [readonly]="readonly()" formControlName="date" (onChange)="emit()">
1188
+ <iss-ctrl-date-picker (focusout)="markAsTouched()" [disabledDays]="disabledDays()" [maxDate]="maxDate()" [minDate]="minDate()" [readonly]="readonly()" formControlName="date" (onChange)="emit()">
878
1189
  <label>
879
1190
  <ng-content select="label"></ng-content>
880
1191
  </label>
@@ -882,8 +1193,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
882
1193
  <iss-ctrl-time-picker
883
1194
  (focusout)="markAsTouched()"
884
1195
  [maxTime]="maxTime()"
885
- [minTime]="minTime()"
886
- [readonly]="readonly()"
1196
+ [minTime]="minTime()"
1197
+ [readonly]="readonly()"
887
1198
  formControlName="time"
888
1199
  (onChange)="emit()"
889
1200
  />
@@ -988,12 +1299,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
988
1299
  args: ["drop", ["$event"]]
989
1300
  }] } });
990
1301
 
1302
+ /**
1303
+ * `<iss-ctrl-file-picker>` — attachment upload with a per-file progress and error state.
1304
+ *
1305
+ * Uploading is done by the host: the control emits the picked files and renders whatever is
1306
+ * fed back through `uploadedFiles`, `uploading` and `uploadingError`.
1307
+ *
1308
+ * @example
1309
+ * ```html
1310
+ * <iss-ctrl-file-picker
1311
+ * formControlName="attachments"
1312
+ * [multiple]="true"
1313
+ * accept=".pdf,.png"
1314
+ * [uploading]="uploading()"
1315
+ * [uploadedFiles]="uploaded()"
1316
+ * />
1317
+ * ```
1318
+ *
1319
+ * ### Own inputs
1320
+ * | Property | Type | Default | Description |
1321
+ * | --- | --- | --- | --- |
1322
+ * | `accept` | `string \| undefined` | `undefined` | Accepted extensions or MIME types for the native picker. |
1323
+ * | `showDownloadButton` | `boolean` | `true` | Shows the download action on each attachment. |
1324
+ * | `showDeleteButton` | `boolean` | `true` | Shows the remove action on each attachment. |
1325
+ * | `uploading` | `boolean` | `false` | Renders the in-progress state. |
1326
+ * | `uploadedFiles` | `IssAttachment[]` | `[]` | Files already stored on the server. |
1327
+ * | `uploadingError` | `string \| undefined` | `undefined` | Error message attached to the failed upload. |
1328
+ *
1329
+ * ### Inherited from {@link ControlBase}
1330
+ * `formControlName` · `readonly` · `className` · `(onChange)` · `multiple` · `hints`
1331
+ *
1332
+ * Does not project a label — the field label is rendered by the wrapping `iss-field-*`.
1333
+ */
991
1334
  class FilePickerControl extends ControlBase {
1335
+ /**
1336
+ * Accepted extensions or MIME types, passed straight to the native file input.
1337
+ */
992
1338
  accept = input(...(ngDevMode ? [undefined, { debugName: "accept" }] : /* istanbul ignore next */ []));
1339
+ /**
1340
+ * Shows the download action on each listed attachment.
1341
+ */
993
1342
  showDownloadButton = input(true, ...(ngDevMode ? [{ debugName: "showDownloadButton" }] : /* istanbul ignore next */ []));
1343
+ /**
1344
+ * Shows the remove action on each listed attachment.
1345
+ */
994
1346
  showDeleteButton = input(true, ...(ngDevMode ? [{ debugName: "showDeleteButton" }] : /* istanbul ignore next */ []));
1347
+ /**
1348
+ * Renders the upload-in-progress state; set by the host that performs the upload.
1349
+ */
995
1350
  uploading = input(false, ...(ngDevMode ? [{ debugName: "uploading" }] : /* istanbul ignore next */ []));
1351
+ /**
1352
+ * Attachments already stored on the server, merged into the rendered list.
1353
+ */
996
1354
  uploadedFiles = input([], ...(ngDevMode ? [{ debugName: "uploadedFiles" }] : /* istanbul ignore next */ []));
1355
+ /**
1356
+ * Error message shown on the attachment whose upload failed.
1357
+ */
997
1358
  uploadingError = input(undefined, ...(ngDevMode ? [{ debugName: "uploadingError" }] : /* istanbul ignore next */ []));
998
1359
  filesValue = computed(() => this.#returnAttachmentViewObject(), ...(ngDevMode ? [{ debugName: "filesValue" }] : /* istanbul ignore next */ []));
999
1360
  attachments = signal([], ...(ngDevMode ? [{ debugName: "attachments" }] : /* istanbul ignore next */ []));
@@ -1163,13 +1524,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1163
1524
  `, styles: [".file-uploader{--uploader-height: 150px;--uploader-width: 100%;--uploader-bg: var(--off-white);--uploader-border: 1px dashed var(--dark-gray);--uploader-radius: var(--box-radius);--uploader-padding: 1rem;height:var(--uploader-height);background-color:var(--uploader-bg);border:var(--uploader-border);border-radius:var(--uploader-radius);padding:var(--uploader-padding);text-align:center;cursor:pointer}.file-uploader --input{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:.75rem}\n"] }]
1164
1525
  }], propDecorators: { accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], showDownloadButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDownloadButton", required: false }] }], showDeleteButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDeleteButton", required: false }] }], uploading: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploading", required: false }] }], uploadedFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadedFiles", required: false }] }], uploadingError: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadingError", required: false }] }] } });
1165
1526
 
1527
+ /**
1528
+ * `<iss-ctrl-input>` — single line text input, the base for every scalar text field.
1529
+ *
1530
+ * `type` is forwarded to the native input, so `number`, `email` and `password` variants all
1531
+ * come from this one control.
1532
+ *
1533
+ * @example
1534
+ * ```html
1535
+ * <iss-ctrl-input formControlName="amount" type="number" [min]="0" suffixText="SAR">
1536
+ * <label>Amount</label>
1537
+ * </iss-ctrl-input>
1538
+ * ```
1539
+ *
1540
+ * ### Own inputs
1541
+ * | Property | Type | Default | Description |
1542
+ * | --- | --- | --- | --- |
1543
+ * | `type` | `string` | `"text"` | Native input type: `text`, `number`, `email`, `password`, … |
1544
+ * | `prefixIcon` | `string` | `""` | Icon rendered before the value. |
1545
+ * | `prefixText` | `string` | `""` | Text rendered before the value. |
1546
+ * | `suffixIcon` | `string` | `""` | Icon rendered after the value. |
1547
+ * | `suffixText` | `string` | `""` | Text rendered after the value. |
1548
+ *
1549
+ * ### Inherited from {@link ControlBase}
1550
+ * `formControlName` · `readonly` · `className` · `(onChange)` · `placeholder` · `min` · `max` · `minLength` · `maxLength` · `hints`
1551
+ *
1552
+ * ### Outputs
1553
+ * - `(onPrefixClick)` — `string`, the prefix affix was clicked.
1554
+ * - `(onSuffixClick)` — `string`, the suffix affix was clicked.
1555
+ *
1556
+ * Projects `<label>` into the floating label; omit it to render the control without one.
1557
+ *
1558
+ * Also projects `[issPrefix]` and `[issSuffix]` for fully custom affixes.
1559
+ */
1166
1560
  class InputControl extends ControlBase {
1561
+ /**
1562
+ * Native input type — `text`, `number`, `email`, `password`, and so on.
1563
+ */
1167
1564
  type = input("text", ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
1565
+ /**
1566
+ * Icon name rendered before the value.
1567
+ */
1168
1568
  prefixIcon = input("", ...(ngDevMode ? [{ debugName: "prefixIcon" }] : /* istanbul ignore next */ []));
1569
+ /**
1570
+ * Static text rendered before the value.
1571
+ */
1169
1572
  prefixText = input("", ...(ngDevMode ? [{ debugName: "prefixText" }] : /* istanbul ignore next */ []));
1573
+ /**
1574
+ * Icon name rendered after the value.
1575
+ */
1170
1576
  suffixIcon = input("", ...(ngDevMode ? [{ debugName: "suffixIcon" }] : /* istanbul ignore next */ []));
1577
+ /**
1578
+ * Static text rendered after the value, a unit or currency for example.
1579
+ */
1171
1580
  suffixText = input("", ...(ngDevMode ? [{ debugName: "suffixText" }] : /* istanbul ignore next */ []));
1581
+ /**
1582
+ * Emits when the prefix affix is clicked.
1583
+ */
1172
1584
  onPrefixClick = output();
1585
+ /**
1586
+ * Emits when the suffix affix is clicked.
1587
+ */
1173
1588
  onSuffixClick = output();
1174
1589
  #disabledEffect = effect(() => {
1175
1590
  if (this.disabled()) {
@@ -1194,9 +1609,11 @@ class InputControl extends ControlBase {
1194
1609
  { provide: NG_VALIDATORS, useExisting: InputControl, multi: true }
1195
1610
  ], usesInheritance: true, ngImport: i0, template: `
1196
1611
  <mat-form-field floatLabel="auto" class="">
1197
- <mat-label class="fs-16 fc-black">
1198
- <ng-content select="label"></ng-content>
1199
- </mat-label>
1612
+ @if (hasLabel()) {
1613
+ <mat-label class="fs-16 fc-black">
1614
+ <ng-content select="label"></ng-content>
1615
+ </mat-label>
1616
+ }
1200
1617
  <ng-content select="[issPrefix]"></ng-content>
1201
1618
  <div (click)="emitPrefixClick()" class="cursor-pointer">
1202
1619
  @if (prefixText()) {
@@ -1215,8 +1632,8 @@ class InputControl extends ControlBase {
1215
1632
  [attr.minlength]="minLength()"
1216
1633
  [attr.max]="max()"
1217
1634
  [attr.min]="min()"
1218
- [placeholder]="placeholder()"
1219
- [readonly]="readonly()"
1635
+ [placeholder]="placeholder()"
1636
+ [readonly]="readonly()"
1220
1637
  [type]="type()"
1221
1638
  />
1222
1639
  <ng-content select="[issSuffix]"></ng-content>
@@ -1251,9 +1668,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1251
1668
  ],
1252
1669
  template: `
1253
1670
  <mat-form-field floatLabel="auto" class="">
1254
- <mat-label class="fs-16 fc-black">
1255
- <ng-content select="label"></ng-content>
1256
- </mat-label>
1671
+ @if (hasLabel()) {
1672
+ <mat-label class="fs-16 fc-black">
1673
+ <ng-content select="label"></ng-content>
1674
+ </mat-label>
1675
+ }
1257
1676
  <ng-content select="[issPrefix]"></ng-content>
1258
1677
  <div (click)="emitPrefixClick()" class="cursor-pointer">
1259
1678
  @if (prefixText()) {
@@ -1272,8 +1691,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1272
1691
  [attr.minlength]="minLength()"
1273
1692
  [attr.max]="max()"
1274
1693
  [attr.min]="min()"
1275
- [placeholder]="placeholder()"
1276
- [readonly]="readonly()"
1694
+ [placeholder]="placeholder()"
1695
+ [readonly]="readonly()"
1277
1696
  [type]="type()"
1278
1697
  />
1279
1698
  <ng-content select="[issSuffix]"></ng-content>
@@ -3427,10 +3846,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3427
3846
  args: [{ providedIn: "root" }]
3428
3847
  }] });
3429
3848
 
3849
+ /**
3850
+ * `<iss-ctrl-mobile>` — international phone number with a country selector.
3851
+ *
3852
+ * The number is validated against the selected country and stored in its international form.
3853
+ *
3854
+ * @example
3855
+ * ```html
3856
+ * <iss-ctrl-mobile formControlName="mobile" [preferredCountries]="['SA', 'AE']">
3857
+ * <label>Mobile</label>
3858
+ * </iss-ctrl-mobile>
3859
+ * ```
3860
+ *
3861
+ * ### Own inputs
3862
+ * | Property | Type | Default | Description |
3863
+ * | --- | --- | --- | --- |
3864
+ * | `preferredCountries` | `ISO2[]` | `["SA"]` | Countries pinned to the top of the country list. |
3865
+ *
3866
+ * ### Inherited from {@link ControlBase}
3867
+ * `formControlName` · `readonly` · `className` · `(onChange)`
3868
+ *
3869
+ * Projects `<label>` into the floating label; omit it to render the control without one.
3870
+ */
3430
3871
  class MobileControl extends ControlBase {
3431
3872
  phoneService = inject(Phone);
3432
3873
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
3433
3874
  selectedCountry = signal(DEFAULT_COUNTRY, ...(ngDevMode ? [{ debugName: "selectedCountry" }] : /* istanbul ignore next */ []));
3875
+ /**
3876
+ * ISO-2 country codes pinned to the top of the country list; the first one is preselected.
3877
+ */
3434
3878
  preferredCountries = input(["SA"], ...(ngDevMode ? [{ debugName: "preferredCountries" }] : /* istanbul ignore next */ []));
3435
3879
  searchInput = new FormControl("");
3436
3880
  filteredCountries = computed(() => this.#searchInCountries(), ...(ngDevMode ? [{ debugName: "filteredCountries" }] : /* istanbul ignore next */ []));
@@ -3561,9 +4005,11 @@ class MobileControl extends ControlBase {
3561
4005
  { provide: NG_VALIDATORS, useExisting: MobileControl, multi: true }
3562
4006
  ], usesInheritance: true, ngImport: i0, template: `
3563
4007
  <mat-form-field floatLabel="auto" cdkOverlayOrigin #trigger="cdkOverlayOrigin">
3564
- <mat-label class="fs-16 fc-black">
3565
- <ng-content select="label"></ng-content>
3566
- </mat-label>
4008
+ @if (hasLabel()) {
4009
+ <mat-label class="fs-16 fc-black">
4010
+ <ng-content select="label"></ng-content>
4011
+ </mat-label>
4012
+ }
3567
4013
  <div class="d-inline-flex align-items-center gap-1 country-flag" matPrefix (click)="toggleCountryCodeMenu()">
3568
4014
  <img
3569
4015
  ngSrc="./flags/{{selectedCountry().code.toLowerCase()}}.svg"
@@ -3582,8 +4028,8 @@ class MobileControl extends ControlBase {
3582
4028
  (blur)="markAsTouched()"
3583
4029
  (keydown)="onInput($event)"
3584
4030
  (input)="emit()"
3585
- [formControl]="ctrl"
3586
- [readonly]="readonly()"
4031
+ [formControl]="ctrl"
4032
+ [readonly]="readonly()"
3587
4033
  [placeholder]="selectedCountry().placeholder"
3588
4034
  />
3589
4035
  </mat-form-field>
@@ -3638,9 +4084,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3638
4084
  { provide: NG_VALIDATORS, useExisting: MobileControl, multi: true }
3639
4085
  ], template: `
3640
4086
  <mat-form-field floatLabel="auto" cdkOverlayOrigin #trigger="cdkOverlayOrigin">
3641
- <mat-label class="fs-16 fc-black">
3642
- <ng-content select="label"></ng-content>
3643
- </mat-label>
4087
+ @if (hasLabel()) {
4088
+ <mat-label class="fs-16 fc-black">
4089
+ <ng-content select="label"></ng-content>
4090
+ </mat-label>
4091
+ }
3644
4092
  <div class="d-inline-flex align-items-center gap-1 country-flag" matPrefix (click)="toggleCountryCodeMenu()">
3645
4093
  <img
3646
4094
  ngSrc="./flags/{{selectedCountry().code.toLowerCase()}}.svg"
@@ -3659,8 +4107,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3659
4107
  (blur)="markAsTouched()"
3660
4108
  (keydown)="onInput($event)"
3661
4109
  (input)="emit()"
3662
- [formControl]="ctrl"
3663
- [readonly]="readonly()"
4110
+ [formControl]="ctrl"
4111
+ [readonly]="readonly()"
3664
4112
  [placeholder]="selectedCountry().placeholder"
3665
4113
  />
3666
4114
  </mat-form-field>
@@ -3719,6 +4167,26 @@ const PLATE_LETTERS = [
3719
4167
  { label: { ar: "ي", en: "V" }, value: "V" }
3720
4168
  ];
3721
4169
 
4170
+ /**
4171
+ * `<iss-ctrl-plate-number>` — Saudi vehicle plate, entered as digits and letters in both
4172
+ * Arabic and English.
4173
+ *
4174
+ * Typing into one script fills the matching cell in the other automatically, and letters are
4175
+ * validated against the allowed plate alphabet.
4176
+ *
4177
+ * @example
4178
+ * ```html
4179
+ * <iss-ctrl-plate-number formControlName="plate" [readonly]="false"/>
4180
+ * ```
4181
+ *
4182
+ * ### Own inputs
4183
+ * None — the control is configured entirely through the inherited properties.
4184
+ *
4185
+ * ### Inherited from {@link ControlBase}
4186
+ * `formControlName` · `readonly` · `className` · `(onChange)`
4187
+ *
4188
+ * Does not project a label — the field label is rendered by the wrapping `iss-field-*`.
4189
+ */
3722
4190
  class PlateControl extends ControlBase {
3723
4191
  numbersAr = signal(Array(4).fill(""), ...(ngDevMode ? [{ debugName: "numbersAr" }] : /* istanbul ignore next */ []));
3724
4192
  numbersEn = signal(Array(4).fill(""), ...(ngDevMode ? [{ debugName: "numbersEn" }] : /* istanbul ignore next */ []));
@@ -3951,8 +4419,8 @@ class PlateControl extends ControlBase {
3951
4419
  class="plate-input number-input"
3952
4420
  maxlength="1"
3953
4421
  [attr.data-plate-input]="'num-ar-' + $index"
3954
- [value]="num"
3955
- [readonly]="readonly()"
4422
+ [value]="num"
4423
+ [readonly]="readonly()"
3956
4424
  placeholder="١"
3957
4425
  (keydown)="preventNonDigits($event, 'ar')"
3958
4426
  (keyup)="preventNonDigits($event, 'ar')"
@@ -3968,8 +4436,8 @@ class PlateControl extends ControlBase {
3968
4436
  class="plate-input number-input"
3969
4437
  maxlength="1"
3970
4438
  [attr.data-plate-input]="'num-en-' + $index"
3971
- [value]="num"
3972
- [readonly]="readonly()"
4439
+ [value]="num"
4440
+ [readonly]="readonly()"
3973
4441
  placeholder="1"
3974
4442
  (keydown)="preventNonDigits($event, 'en')"
3975
4443
  (keyup)="preventNonDigits($event, 'en')"
@@ -4000,8 +4468,8 @@ class PlateControl extends ControlBase {
4000
4468
  maxlength="1"
4001
4469
  [attr.data-plate-input]="'let-ar-' + $index"
4002
4470
  [class.invalid]="letterErrors()[$index]"
4003
- [value]="letter"
4004
- [readonly]="readonly()"
4471
+ [value]="letter"
4472
+ [readonly]="readonly()"
4005
4473
  placeholder="س"
4006
4474
  (input)="onLetterInput($index, $event, 'ar')"
4007
4475
  />
@@ -4021,8 +4489,8 @@ class PlateControl extends ControlBase {
4021
4489
  maxlength="1"
4022
4490
  [attr.data-plate-input]="'let-en-' + $index"
4023
4491
  [class.invalid]="letterErrors()[$index]"
4024
- [value]="letter"
4025
- [readonly]="readonly()"
4492
+ [value]="letter"
4493
+ [readonly]="readonly()"
4026
4494
  placeholder="S"
4027
4495
  (input)="onLetterInput($index, $event, 'en')"
4028
4496
  />
@@ -4061,8 +4529,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4061
4529
  class="plate-input number-input"
4062
4530
  maxlength="1"
4063
4531
  [attr.data-plate-input]="'num-ar-' + $index"
4064
- [value]="num"
4065
- [readonly]="readonly()"
4532
+ [value]="num"
4533
+ [readonly]="readonly()"
4066
4534
  placeholder="١"
4067
4535
  (keydown)="preventNonDigits($event, 'ar')"
4068
4536
  (keyup)="preventNonDigits($event, 'ar')"
@@ -4078,8 +4546,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4078
4546
  class="plate-input number-input"
4079
4547
  maxlength="1"
4080
4548
  [attr.data-plate-input]="'num-en-' + $index"
4081
- [value]="num"
4082
- [readonly]="readonly()"
4549
+ [value]="num"
4550
+ [readonly]="readonly()"
4083
4551
  placeholder="1"
4084
4552
  (keydown)="preventNonDigits($event, 'en')"
4085
4553
  (keyup)="preventNonDigits($event, 'en')"
@@ -4110,8 +4578,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4110
4578
  maxlength="1"
4111
4579
  [attr.data-plate-input]="'let-ar-' + $index"
4112
4580
  [class.invalid]="letterErrors()[$index]"
4113
- [value]="letter"
4114
- [readonly]="readonly()"
4581
+ [value]="letter"
4582
+ [readonly]="readonly()"
4115
4583
  placeholder="س"
4116
4584
  (input)="onLetterInput($index, $event, 'ar')"
4117
4585
  />
@@ -4131,8 +4599,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4131
4599
  maxlength="1"
4132
4600
  [attr.data-plate-input]="'let-en-' + $index"
4133
4601
  [class.invalid]="letterErrors()[$index]"
4134
- [value]="letter"
4135
- [readonly]="readonly()"
4602
+ [value]="letter"
4603
+ [readonly]="readonly()"
4136
4604
  placeholder="S"
4137
4605
  (input)="onLetterInput($index, $event, 'en')"
4138
4606
  />
@@ -4156,7 +4624,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4156
4624
  `, styles: [".plate-container{width:600px;height:130px;border:4px solid #1D252D;border-radius:10px;background:#fff;display:flex;box-shadow:0 4px 10px #0003;overflow:hidden;position:relative}.section{display:flex;flex-direction:column;justify-content:center;align-items:center}.numbers-section{flex:2;padding:0 10px}.digit-row{display:flex;justify-content:space-between;width:80%;font-size:38px;line-height:1;color:#1d252d;margin:2px 0}.emblem-section{flex:1.2;padding:10px}.emblem-svg{width:100%;height:100%;max-height:90px}.letters-section{flex:1.8;border-right:2px solid #1D252D;padding:0 10px}.arabic-row{font-family:Noto Sans Arabic,sans-serif;font-size:32px;display:flex;justify-content:space-around;width:100%;margin-bottom:5px;color:#1d252d}.english-row{font-size:38px;display:flex;justify-content:space-around;width:100%;color:#1d252d}.ksa-strip{width:50px;display:flex;flex-direction:column;justify-content:space-between;align-items:center;padding:10px 0;background-color:#fff}.mini-emblem{width:25px;height:auto}.ksa-text{writing-mode:vertical-rl;text-orientation:upright;font-weight:900;font-size:16px;letter-spacing:2px;color:#1d252d;margin-top:auto;margin-bottom:5px}.plate-input{background:transparent;border:none;text-align:center;font-family:inherit;font-size:inherit;font-weight:700;color:#1d252d;width:100%;padding:0;margin:0;outline:none}.plate-input:focus{border-bottom:2px solid #1D252D}.digit-row,.arabic-row,.english-row{display:flex;justify-content:space-between;width:100%}.number-input,.letter-input{flex:1}.plate-input::placeholder{color:#ccc;opacity:1}.input-wrapper{position:relative;display:flex;flex-direction:column;align-items:center;flex:1}.error-tooltip{position:absolute;bottom:-15px;font-size:10px;color:red;white-space:nowrap}.plate-input.invalid{color:red}\n"] }]
4157
4625
  }] });
4158
4626
 
4627
+ /**
4628
+ * `<iss-ctrl-radio>` — one choice out of a fixed set of options.
4629
+ *
4630
+ * @example
4631
+ * ```html
4632
+ * <iss-ctrl-radio formControlName="gender" [options]="genders"/>
4633
+ * ```
4634
+ *
4635
+ * ### Own inputs
4636
+ * | Property | Type | Default | Description |
4637
+ * | --- | --- | --- | --- |
4638
+ * | `options` | `Option[]` | **required** | The selectable choices. |
4639
+ *
4640
+ * ### Inherited from {@link ControlBase}
4641
+ * `formControlName` · `readonly` · `className` · `(onChange)`
4642
+ *
4643
+ * Does not project a label — the field label is rendered by the wrapping `iss-field-*`.
4644
+ */
4159
4645
  class RadioControl extends ControlBase {
4646
+ /**
4647
+ * Selectable choices, each a `{ value, label }` pair. Required.
4648
+ */
4160
4649
  options = input.required(...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
4161
4650
  writeValue(value) {
4162
4651
  if (!value) {
@@ -4182,7 +4671,7 @@ class RadioControl extends ControlBase {
4182
4671
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: RadioControl, isStandalone: true, selector: "iss-ctrl-radio", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
4183
4672
  { provide: NG_VALUE_ACCESSOR, useExisting: RadioControl, multi: true }
4184
4673
  ], usesInheritance: true, ngImport: i0, template: `
4185
- <mat-button-toggle-group [hideSingleSelectionIndicator]="true" [disabled]="disabled() || readonly()">
4674
+ <mat-button-toggle-group [hideSingleSelectionIndicator]="true" [disabled]="disabled() || readonly()">
4186
4675
  @for (option of options(); track option.value) {
4187
4676
  <mat-button-toggle
4188
4677
  [value]="option.value"
@@ -4207,7 +4696,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4207
4696
  { provide: NG_VALUE_ACCESSOR, useExisting: RadioControl, multi: true }
4208
4697
  ],
4209
4698
  template: `
4210
- <mat-button-toggle-group [hideSingleSelectionIndicator]="true" [disabled]="disabled() || readonly()">
4699
+ <mat-button-toggle-group [hideSingleSelectionIndicator]="true" [disabled]="disabled() || readonly()">
4211
4700
  @for (option of options(); track option.value) {
4212
4701
  <mat-button-toggle
4213
4702
  [value]="option.value"
@@ -4221,13 +4710,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4221
4710
  }]
4222
4711
  }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }] } });
4223
4712
 
4713
+ /**
4714
+ * `<iss-ctrl-select>` — dropdown selection, single or multiple, with a search box.
4715
+ *
4716
+ * Typing in the search box emits `(onQueryChange)`, so options can be loaded remotely; set
4717
+ * `loading` while that request is in flight.
4718
+ *
4719
+ * @example
4720
+ * ```html
4721
+ * <iss-ctrl-select
4722
+ * formControlName="city"
4723
+ * [options]="cities()"
4724
+ * [multiple]="false"
4725
+ * [loading]="loading()"
4726
+ * (onQueryChange)="search($event)"
4727
+ * >
4728
+ * <label>City</label>
4729
+ * </iss-ctrl-select>
4730
+ * ```
4731
+ *
4732
+ * ### Own inputs
4733
+ * | Property | Type | Default | Description |
4734
+ * | --- | --- | --- | --- |
4735
+ * | `options` | `Option[]` | **required** | The selectable choices. |
4736
+ * | `height` | `string` | `"150px"` | Max height of the open panel. |
4737
+ * | `loading` | `boolean` | `false` | Shows the loading state inside the panel. |
4738
+ *
4739
+ * ### Inherited from {@link ControlBase}
4740
+ * `formControlName` · `readonly` · `className` · `(onChange)` · `placeholder` · `multiple`
4741
+ *
4742
+ * ### Outputs
4743
+ * - `(onQueryChange)` — `string`, the current search text.
4744
+ *
4745
+ * Projects `<label>` into the floating label; omit it to render the control without one.
4746
+ */
4224
4747
  class SelectControl extends ControlBase {
4225
4748
  selectedOptions = signal(new Map(), ...(ngDevMode ? [{ debugName: "selectedOptions" }] : /* istanbul ignore next */ []));
4749
+ /**
4750
+ * Selectable choices, each a `{ value, label }` pair. Required.
4751
+ */
4226
4752
  options = input.required(...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
4753
+ /**
4754
+ * Maximum height of the open options panel, as a CSS length.
4755
+ */
4227
4756
  height = input("150px", ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
4228
4757
  query = toSignal(this.ctrl.valueChanges);
4229
4758
  filteredOptions = computed(() => this.#filter(this.query()), ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
4759
+ /**
4760
+ * Shows the loading state inside the panel while options are being fetched.
4761
+ */
4230
4762
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
4763
+ /**
4764
+ * Emits the search text so the host can load matching options.
4765
+ */
4231
4766
  onQueryChange = output();
4232
4767
  optionTemplate = contentChild("optionTemplate", ...(ngDevMode ? [{ debugName: "optionTemplate" }] : /* istanbul ignore next */ []));
4233
4768
  cardViewerTemplate = contentChild("cardViewerTemplate", ...(ngDevMode ? [{ debugName: "cardViewerTemplate" }] : /* istanbul ignore next */ []));
@@ -4370,10 +4905,12 @@ class SelectControl extends ControlBase {
4370
4905
  { provide: NG_VALUE_ACCESSOR, useExisting: SelectControl, multi: true },
4371
4906
  ], queries: [{ propertyName: "optionTemplate", first: true, predicate: ["optionTemplate"], descendants: true, isSignal: true }, { propertyName: "cardViewerTemplate", first: true, predicate: ["cardViewerTemplate"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
4372
4907
  <mat-form-field floatLabel="auto" class="">
4373
- <mat-label class="fs-16 fc-black">
4374
- <ng-content select="label"></ng-content>
4375
- </mat-label>
4376
- <input [formControl]="ctrl" [matAutocomplete]="auto" [matChipInputFor]="chipGrid" [placeholder]="placeholder()" [readonly]="readonly()" (blur)="markAsTouched()" class="m-0" matInput/>
4908
+ @if (hasLabel()) {
4909
+ <mat-label class="fs-16 fc-black">
4910
+ <ng-content select="label"></ng-content>
4911
+ </mat-label>
4912
+ }
4913
+ <input [formControl]="ctrl" [matAutocomplete]="auto" [matChipInputFor]="chipGrid" [placeholder]="placeholder()" [readonly]="readonly()" (blur)="markAsTouched()" class="m-0" matInput/>
4377
4914
  @if (!disabled()) {
4378
4915
  @if (selectedOptions().size) {
4379
4916
  <span matSuffix class="sfi sfi-close fs-18 fc-black cursor-pointer" (click)="clearSelection()"></span>
@@ -4421,7 +4958,7 @@ class SelectControl extends ControlBase {
4421
4958
  } @else {
4422
4959
  {{ chip[1].label }}
4423
4960
  }
4424
- <button matChipRemove [disabled]="readonly()" [attr.aria-label]="'remove ' + chip[1].label">
4961
+ <button matChipRemove [disabled]="readonly()" [attr.aria-label]="'remove ' + chip[1].label">
4425
4962
  <ds-icon icon="trash" class="fc-red"></ds-icon>
4426
4963
  </button>
4427
4964
  </mat-chip-row>
@@ -4449,10 +4986,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4449
4986
  { provide: NG_VALUE_ACCESSOR, useExisting: SelectControl, multi: true },
4450
4987
  ], template: `
4451
4988
  <mat-form-field floatLabel="auto" class="">
4452
- <mat-label class="fs-16 fc-black">
4453
- <ng-content select="label"></ng-content>
4454
- </mat-label>
4455
- <input [formControl]="ctrl" [matAutocomplete]="auto" [matChipInputFor]="chipGrid" [placeholder]="placeholder()" [readonly]="readonly()" (blur)="markAsTouched()" class="m-0" matInput/>
4989
+ @if (hasLabel()) {
4990
+ <mat-label class="fs-16 fc-black">
4991
+ <ng-content select="label"></ng-content>
4992
+ </mat-label>
4993
+ }
4994
+ <input [formControl]="ctrl" [matAutocomplete]="auto" [matChipInputFor]="chipGrid" [placeholder]="placeholder()" [readonly]="readonly()" (blur)="markAsTouched()" class="m-0" matInput/>
4456
4995
  @if (!disabled()) {
4457
4996
  @if (selectedOptions().size) {
4458
4997
  <span matSuffix class="sfi sfi-close fs-18 fc-black cursor-pointer" (click)="clearSelection()"></span>
@@ -4500,7 +5039,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4500
5039
  } @else {
4501
5040
  {{ chip[1].label }}
4502
5041
  }
4503
- <button matChipRemove [disabled]="readonly()" [attr.aria-label]="'remove ' + chip[1].label">
5042
+ <button matChipRemove [disabled]="readonly()" [attr.aria-label]="'remove ' + chip[1].label">
4504
5043
  <ds-icon icon="trash" class="fc-red"></ds-icon>
4505
5044
  </button>
4506
5045
  </mat-chip-row>
@@ -4510,6 +5049,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4510
5049
  `, schemas: [CUSTOM_ELEMENTS_SCHEMA] }]
4511
5050
  }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], onQueryChange: [{ type: i0.Output, args: ["onQueryChange"] }], optionTemplate: [{ type: i0.ContentChild, args: ["optionTemplate", { isSignal: true }] }], cardViewerTemplate: [{ type: i0.ContentChild, args: ["cardViewerTemplate", { isSignal: true }] }] } });
4512
5051
 
5052
+ /**
5053
+ * `<iss-ctrl-slide-toggle>` — an on/off switch for a boolean value.
5054
+ *
5055
+ * @example
5056
+ * ```html
5057
+ * <iss-ctrl-slide-toggle formControlName="active" (onChange)="save($event)"/>
5058
+ * ```
5059
+ *
5060
+ * ### Own inputs
5061
+ * None — the control is configured entirely through the inherited properties.
5062
+ *
5063
+ * ### Inherited from {@link ControlBase}
5064
+ * `formControlName` · `readonly` · `className` · `(onChange)`
5065
+ *
5066
+ * Does not project a label — the field label is rendered by the wrapping `iss-field-*`.
5067
+ */
4513
5068
  class SlideToggleControl extends ControlBase {
4514
5069
  onSlideToggleChange(checked) {
4515
5070
  if (this.readonly()) {
@@ -4523,8 +5078,8 @@ class SlideToggleControl extends ControlBase {
4523
5078
  { provide: NG_VALUE_ACCESSOR, useExisting: SlideToggleControl, multi: true }
4524
5079
  ], usesInheritance: true, ngImport: i0, template: `
4525
5080
  <mat-slide-toggle
4526
- class="d-block" [formControl]="ctrl"
4527
- [disabled]="readonly()"
5081
+ class="d-block" [formControl]="ctrl"
5082
+ [disabled]="readonly()"
4528
5083
  (change)="onSlideToggleChange($event.checked)"
4529
5084
  >
4530
5085
  </mat-slide-toggle>
@@ -4540,8 +5095,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4540
5095
  ],
4541
5096
  template: `
4542
5097
  <mat-slide-toggle
4543
- class="d-block" [formControl]="ctrl"
4544
- [disabled]="readonly()"
5098
+ class="d-block" [formControl]="ctrl"
5099
+ [disabled]="readonly()"
4545
5100
  (change)="onSlideToggleChange($event.checked)"
4546
5101
  >
4547
5102
  </mat-slide-toggle>
@@ -4549,6 +5104,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4549
5104
  }]
4550
5105
  }] });
4551
5106
 
5107
+ /**
5108
+ * `<iss-ctrl-textarea>` — multi line free text.
5109
+ *
5110
+ * @example
5111
+ * ```html
5112
+ * <iss-ctrl-textarea formControlName="notes" [maxLength]="500" placeholder="Add a note">
5113
+ * <label>Notes</label>
5114
+ * </iss-ctrl-textarea>
5115
+ * ```
5116
+ *
5117
+ * ### Own inputs
5118
+ * None — the control is configured entirely through the inherited properties.
5119
+ *
5120
+ * ### Inherited from {@link ControlBase}
5121
+ * `formControlName` · `readonly` · `className` · `(onChange)` · `placeholder` · `minLength` · `maxLength` · `hints`
5122
+ *
5123
+ * Projects `<label>` into the floating label; omit it to render the control without one.
5124
+ */
4552
5125
  class TextareaControl extends ControlBase {
4553
5126
  #disabledEffect = effect(() => {
4554
5127
  if (this.disabled()) {
@@ -4562,21 +5135,23 @@ class TextareaControl extends ControlBase {
4562
5135
  this.#disabledEffect.destroy();
4563
5136
  }
4564
5137
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TextareaControl, deps: null, target: i0.ɵɵFactoryTarget.Component });
4565
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: TextareaControl, isStandalone: true, selector: "iss-ctrl-textarea", providers: [
5138
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TextareaControl, isStandalone: true, selector: "iss-ctrl-textarea", providers: [
4566
5139
  { provide: NG_VALUE_ACCESSOR, useExisting: TextareaControl, multi: true },
4567
5140
  { provide: NG_VALIDATORS, useExisting: TextareaControl, multi: true }
4568
5141
  ], usesInheritance: true, ngImport: i0, template: `
4569
5142
  <mat-form-field floatLabel="auto" class="custom-textarea">
4570
- <mat-label class="fs-16 fc-black">
4571
- <ng-content select="label"></ng-content>
4572
- </mat-label>
5143
+ @if (hasLabel()) {
5144
+ <mat-label class="fs-16 fc-black">
5145
+ <ng-content select="label"></ng-content>
5146
+ </mat-label>
5147
+ }
4573
5148
  <textarea
4574
5149
  matInput
4575
5150
  [placeholder]="placeholder()"
4576
5151
  [formControl]="ctrl"
4577
5152
  [attr.maxlength]="maxLength()"
4578
- [attr.minlength]="minLength()"
4579
- [readonly]="readonly()"
5153
+ [attr.minlength]="minLength()"
5154
+ [readonly]="readonly()"
4580
5155
  (input)="emitValue()"
4581
5156
  (focusout)="markAsTouched()"
4582
5157
  >
@@ -4604,16 +5179,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4604
5179
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
4605
5180
  template: `
4606
5181
  <mat-form-field floatLabel="auto" class="custom-textarea">
4607
- <mat-label class="fs-16 fc-black">
4608
- <ng-content select="label"></ng-content>
4609
- </mat-label>
5182
+ @if (hasLabel()) {
5183
+ <mat-label class="fs-16 fc-black">
5184
+ <ng-content select="label"></ng-content>
5185
+ </mat-label>
5186
+ }
4610
5187
  <textarea
4611
5188
  matInput
4612
5189
  [placeholder]="placeholder()"
4613
5190
  [formControl]="ctrl"
4614
5191
  [attr.maxlength]="maxLength()"
4615
- [attr.minlength]="minLength()"
4616
- [readonly]="readonly()"
5192
+ [attr.minlength]="minLength()"
5193
+ [readonly]="readonly()"
4617
5194
  (input)="emitValue()"
4618
5195
  (focusout)="markAsTouched()"
4619
5196
  >
@@ -4624,7 +5201,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4624
5201
  }]
4625
5202
  }] });
4626
5203
 
5204
+ /**
5205
+ * `<iss-ctrl-toggle-button>` — options rendered as a button group instead of a dropdown.
5206
+ *
5207
+ * With `multiple` set, several buttons can be active at once.
5208
+ *
5209
+ * @example
5210
+ * ```html
5211
+ * <iss-ctrl-toggle-button formControlName="priority" [options]="priorities" [multiple]="false"/>
5212
+ * ```
5213
+ *
5214
+ * ### Own inputs
5215
+ * | Property | Type | Default | Description |
5216
+ * | --- | --- | --- | --- |
5217
+ * | `options` | `Option[]` | **required** | The selectable choices. |
5218
+ *
5219
+ * ### Inherited from {@link ControlBase}
5220
+ * `formControlName` · `readonly` · `className` · `(onChange)` · `multiple`
5221
+ *
5222
+ * Does not project a label — the field label is rendered by the wrapping `iss-field-*`.
5223
+ */
4627
5224
  class ToggleButtonControl extends ControlBase {
5225
+ /**
5226
+ * Selectable choices, each a `{ value, label }` pair. Required.
5227
+ */
4628
5228
  options = input.required(...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
4629
5229
  selectedOptions = signal(new Map(), ...(ngDevMode ? [{ debugName: "selectedOptions" }] : /* istanbul ignore next */ []));
4630
5230
  writeValue(value) {
@@ -4705,8 +5305,8 @@ class ToggleButtonControl extends ControlBase {
4705
5305
  { provide: NG_VALUE_ACCESSOR, useExisting: ToggleButtonControl, multi: true }
4706
5306
  ], usesInheritance: true, ngImport: i0, template: `
4707
5307
  <mat-button-toggle-group
4708
- [formControl]="ctrl"
4709
- [disabled]="readonly()"
5308
+ [formControl]="ctrl"
5309
+ [disabled]="readonly()"
4710
5310
  [multiple]=multiple()
4711
5311
  [hideMultipleSelectionIndicator]="true"
4712
5312
  [hideSingleSelectionIndicator]="true"
@@ -4723,8 +5323,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4723
5323
  type: Component,
4724
5324
  args: [{ selector: "iss-ctrl-toggle-button", imports: [MatButtonToggleModule, ReactiveFormsModule], template: `
4725
5325
  <mat-button-toggle-group
4726
- [formControl]="ctrl"
4727
- [disabled]="readonly()"
5326
+ [formControl]="ctrl"
5327
+ [disabled]="readonly()"
4728
5328
  [multiple]=multiple()
4729
5329
  [hideMultipleSelectionIndicator]="true"
4730
5330
  [hideSingleSelectionIndicator]="true"
@@ -4747,32 +5347,131 @@ class FieldAsyncValidation {
4747
5347
  }
4748
5348
  }
4749
5349
 
5350
+ /**
5351
+ * Per-field configuration, reachable as `field.config` and consumed by the `iss-field-*`
5352
+ * components. Every entry is a signal, so it can be changed at runtime by field events.
5353
+ *
5354
+ * Not every key applies to every field — the class doc of each `iss-field-*` component
5355
+ * lists exactly which of these it reads.
5356
+ *
5357
+ * ### Keys by area
5358
+ * - **Common:** `type` · `disabled` · `readonly` · `placeholder` · `suffix` · `hideLabel` · `multiple`
5359
+ * - **Bounds:** `min` · `max` · `minLength` · `maxLength`
5360
+ * - **Dates:** `minDate` · `maxDate` · `dateFilter`
5361
+ * - **Attachments:** `allowedFileSize` · `allowedFileTypes` · `minFilesCount` · `maxFilesCount` · `templateId` · `templateUrl`
5362
+ * - **Users:** `minUsersCount` · `maxUsersCount`
5363
+ * - **Table:** `showInTableColumns` · `tableWithFilter` · `tableWithSort` · `tableWithPagination`
5364
+ *
5365
+ * @example
5366
+ * ```json
5367
+ * { "name": "email", "type": "text_input", "config": { "type": "email", "maxLength": 120 } }
5368
+ * ```
5369
+ */
4750
5370
  class FieldConfig {
5371
+ /**
5372
+ * Native input type for `text_input` (`text`, `email`, `number`, `password`, …).
5373
+ */
4751
5374
  type = signal(undefined, ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
5375
+ /**
5376
+ * Disables the control; the underlying `FormControl` is disabled on init.
5377
+ */
4752
5378
  disabled = signal(undefined, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
5379
+ /**
5380
+ * Shows the value but blocks interaction. Unlike `disabled`, the value is still submitted.
5381
+ */
4753
5382
  readonly = signal(undefined, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
5383
+ /**
5384
+ * Placeholder text shown while the field is empty.
5385
+ */
4754
5386
  placeholder = signal(undefined, ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
5387
+ /**
5388
+ * Text rendered after the value (a unit or currency, for example).
5389
+ */
4755
5390
  suffix = signal(undefined, ...(ngDevMode ? [{ debugName: "suffix" }] : /* istanbul ignore next */ []));
5391
+ /**
5392
+ * Hides the field label without removing it from the accessibility tree.
5393
+ */
4756
5394
  hideLabel = signal(undefined, ...(ngDevMode ? [{ debugName: "hideLabel" }] : /* istanbul ignore next */ []));
5395
+ /**
5396
+ * Allows more than one value — multi select, multi file upload, multi toggle.
5397
+ */
4757
5398
  multiple = signal(undefined, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
5399
+ /**
5400
+ * Minimum number of characters. Source: `config.minLength`.
5401
+ */
4758
5402
  minLength = signal(undefined, ...(ngDevMode ? [{ debugName: "minLength" }] : /* istanbul ignore next */ []));
5403
+ /**
5404
+ * Maximum number of characters. Source: `config.maxLength`.
5405
+ */
4759
5406
  maxLength = signal(undefined, ...(ngDevMode ? [{ debugName: "maxLength" }] : /* istanbul ignore next */ []));
5407
+ /**
5408
+ * Minimum numeric value (also the minimum user count for the user picker).
5409
+ */
4760
5410
  min = signal(undefined, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
5411
+ /**
5412
+ * Maximum numeric value (also the maximum user count for the user picker).
5413
+ */
4761
5414
  max = signal(undefined, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
5415
+ /**
5416
+ * Earliest selectable date for date, datetime and date-range fields.
5417
+ */
4762
5418
  minDate = signal(undefined, ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
5419
+ /**
5420
+ * Latest selectable date for date, datetime and date-range fields.
5421
+ */
4763
5422
  maxDate = signal(undefined, ...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
5423
+ /**
5424
+ * Restricts the calendar to working days. Source: `config.acceptWorkDaysOnly`.
5425
+ */
4764
5426
  dateFilter = signal(undefined, ...(ngDevMode ? [{ debugName: "dateFilter" }] : /* istanbul ignore next */ []));
5427
+ /**
5428
+ * Id of a downloadable template offered next to an attachment field.
5429
+ */
4765
5430
  templateId = signal(undefined, ...(ngDevMode ? [{ debugName: "templateId" }] : /* istanbul ignore next */ []));
5431
+ /**
5432
+ * Direct URL of the downloadable template for an attachment field.
5433
+ */
4766
5434
  templateUrl = signal(undefined, ...(ngDevMode ? [{ debugName: "templateUrl" }] : /* istanbul ignore next */ []));
5435
+ /**
5436
+ * Maximum size per uploaded file. Source: `config.allowedSize`.
5437
+ */
4767
5438
  allowedFileSize = signal(undefined, ...(ngDevMode ? [{ debugName: "allowedFileSize" }] : /* istanbul ignore next */ []));
5439
+ /**
5440
+ * Comma separated list of accepted file extensions or MIME types.
5441
+ */
4768
5442
  allowedFileTypes = signal(undefined, ...(ngDevMode ? [{ debugName: "allowedFileTypes" }] : /* istanbul ignore next */ []));
5443
+ /**
5444
+ * Maximum number of files that may be attached.
5445
+ */
4769
5446
  maxFilesCount = signal(undefined, ...(ngDevMode ? [{ debugName: "maxFilesCount" }] : /* istanbul ignore next */ []));
5447
+ /**
5448
+ * Minimum number of files required.
5449
+ */
4770
5450
  minFilesCount = signal(undefined, ...(ngDevMode ? [{ debugName: "minFilesCount" }] : /* istanbul ignore next */ []));
5451
+ /**
5452
+ * Maximum number of users selectable in a user picker.
5453
+ */
4771
5454
  maxUsersCount = signal(undefined, ...(ngDevMode ? [{ debugName: "maxUsersCount" }] : /* istanbul ignore next */ []));
5455
+ /**
5456
+ * Minimum number of users required in a user picker.
5457
+ */
4772
5458
  minUsersCount = signal(undefined, ...(ngDevMode ? [{ debugName: "minUsersCount" }] : /* istanbul ignore next */ []));
5459
+ /**
5460
+ * Parsed from the field definition but not consumed yet — table columns currently come
5461
+ * from `field.children`.
5462
+ */
4773
5463
  showInTableColumns = signal(undefined, ...(ngDevMode ? [{ debugName: "showInTableColumns" }] : /* istanbul ignore next */ []));
5464
+ /**
5465
+ * Enables the filter row on a `table` field.
5466
+ */
4774
5467
  tableWithFilter = signal(undefined, ...(ngDevMode ? [{ debugName: "tableWithFilter" }] : /* istanbul ignore next */ []));
5468
+ /**
5469
+ * Enables column sorting on a `table` field.
5470
+ */
4775
5471
  tableWithSort = signal(undefined, ...(ngDevMode ? [{ debugName: "tableWithSort" }] : /* istanbul ignore next */ []));
5472
+ /**
5473
+ * Enables the paginator on a `table` field.
5474
+ */
4776
5475
  tableWithPagination = signal(undefined, ...(ngDevMode ? [{ debugName: "tableWithPagination" }] : /* istanbul ignore next */ []));
4777
5476
  constructor(config) {
4778
5477
  this.type.set(config?.type);
@@ -4877,6 +5576,38 @@ class FieldEvent {
4877
5576
  }
4878
5577
  }
4879
5578
 
5579
+ /**
5580
+ * Runtime model of a single form field, built from the JSON definition returned by the API.
5581
+ *
5582
+ * It is what `iss-field-*` components inject through the `FIELD_DATA` token, and the object
5583
+ * field events read from and write to. Signal-valued members can be changed at runtime and
5584
+ * the rendered field reacts immediately.
5585
+ *
5586
+ * ### Properties
5587
+ * | Property | Type | Description |
5588
+ * | --- | --- | --- |
5589
+ * | `id` | `number` | Unique field id. |
5590
+ * | `name` | `string` | Control name inside the form group. |
5591
+ * | `type` | `string` | Key into the `COMPONENTS` index (`text_input`, `dropdown_list`, …). |
5592
+ * | `base` | `string` | Underlying data type of the field. |
5593
+ * | `label()` | `string` | Visible label. |
5594
+ * | `hint()` | `string` | Helper text under the field. |
5595
+ * | `options()` | `Option[]` | Choices for select, radio, checkbox and toggle fields. |
5596
+ * | `api()` | `string` | Endpoint used to load options or lookups. |
5597
+ * | `mode()` | `"edit" \| "view"` | Renders the control or the read-only viewer. |
5598
+ * | `visible()` | `boolean` | Whether the field is rendered at all. |
5599
+ * | `loading()` | `boolean` | Shows the field's own loading state. |
5600
+ * | `config` | `FieldConfig` | Per-type configuration — see {@link FieldConfig}. |
5601
+ * | `validation` | `any` | Synchronous validation rules. |
5602
+ * | `asyncValidation` | `FieldAsyncValidation` | Remote validation rules. |
5603
+ * | `events` | `FieldEvent[]` | Cross-field reactions (show, hide, set value, …). |
5604
+ * | `children` | `IssField[]` | Nested fields, used by table and group fields. |
5605
+ * | `value` / `defaultValue` | `string` | Initial and fallback raw values. |
5606
+ * | `jsonValue` | `any` | Initial resolved value for controls with a rich payload. |
5607
+ * | `ctrlValue()` | `string \| null` | Live raw value of the control. |
5608
+ * | `ctrlJsonValue()` | `any` | Live resolved value (selected options, files, users, …). |
5609
+ * | `response()` / `apiResponse` | `any` | Latest payload returned for this field. |
5610
+ */
4880
5611
  class IssField {
4881
5612
  id;
4882
5613
  name;
@@ -5162,38 +5893,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
5162
5893
  args: [{ providedIn: "root" }]
5163
5894
  }] });
5164
5895
 
5896
+ /**
5897
+ * Maps a field's `type` to the `iss-field-*` component that renders it.
5898
+ *
5899
+ * The outlet looks the field up here and lazy-loads the component, so a `type` that is not
5900
+ * a key of this object renders nothing. Hover a field class for the `config` keys it reads.
5901
+ *
5902
+ * | `type` | Component | Control | Renders |
5903
+ * | --- | --- | --- | --- |
5904
+ * | `text_input` | `InputField` | `iss-ctrl-input` | Single line text, number, email, password. |
5905
+ * | `textarea` | `TextareaField` | `iss-ctrl-textarea` | Multi line free text. |
5906
+ * | `dropdown_list` | `SelectField` | `iss-ctrl-select` | Searchable single/multi select. |
5907
+ * | `toggle_button` | `ToggleButtonField` | `iss-ctrl-toggle-button` | Options as a button group. |
5908
+ * | `checkbox` | `CheckboxField` | `iss-ctrl-checkbox` | Multi choice checkbox list. |
5909
+ * | `radio` | `RadioField` | `iss-ctrl-radio` | Single choice radio list. |
5910
+ * | `date` | `DatePickerField` | `iss-ctrl-date-picker` | A single date. |
5911
+ * | `time` | `TimePickerField` | `iss-ctrl-time-picker` | A time of day. |
5912
+ * | `datetime` | `DatetimePickerField` | `iss-ctrl-datetime-picker` | Date and time together. |
5913
+ * | `date_range` | `DateRangePickerField` | `iss-ctrl-date-range-picker` | A start/end date range. |
5914
+ * | `attachment` | `FilePickerField` | `iss-ctrl-file-picker` | File upload. |
5915
+ * | `userPicker` | `UserPickerField` | `iss-ctrl-select` | Employee lookup. |
5916
+ * | `vehicle_plate` | `PlateField` | `iss-ctrl-plate-number` | Saudi vehicle plate. |
5917
+ * | `enrichment` | `NoteField` | — | Read-only explanatory text. |
5918
+ * | `mobile` | `MobileField` | `iss-ctrl-mobile` | International phone number. |
5919
+ * | `table` | `TableField` | `iss-ctrl-table` | Repeatable rows built from `children`. |
5920
+ * | `chips` | `ChipsField` | `iss-ctrl-chips` | Free text as removable chips. |
5921
+ * | `switch` | `SlideToggleField` | `iss-ctrl-slide-toggle` | Boolean on/off switch. |
5922
+ */
5165
5923
  const COMPONENTS = {
5166
- date: () => Promise.resolve().then(function () { return datePicker_field; }).then((c) => c.DatePickerField),
5167
- datetime: () => Promise.resolve().then(function () { return datetimePicker_field; }).then((c) => c.DatetimePickerField),
5168
- dateRange: () => Promise.resolve().then(function () { return dateRangePicker_field; }).then((c) => c.DateRangePickerField),
5169
- date_range: () => Promise.resolve().then(function () { return dateRangePicker_field; }).then((c) => c.DateRangePickerField),
5170
- select: () => Promise.resolve().then(function () { return select_field; }).then((c) => c.SelectField),
5171
- input: () => Promise.resolve().then(function () { return input_field; }).then((c) => c.InputField),
5172
- text: () => Promise.resolve().then(function () { return input_field; }).then((c) => c.InputField),
5924
+ text_input: () => Promise.resolve().then(function () { return input_field; }).then((c) => c.InputField),
5925
+ textarea: () => Promise.resolve().then(function () { return textarea_field; }).then((c) => c.TextareaField),
5926
+ dropdown_list: () => Promise.resolve().then(function () { return select_field; }).then((c) => c.SelectField),
5927
+ toggle_button: () => Promise.resolve().then(function () { return toggleButton_field; }).then((c) => c.ToggleButtonField),
5173
5928
  checkbox: () => Promise.resolve().then(function () { return checkbox_field; }).then((c) => c.CheckboxField),
5174
- file: () => Promise.resolve().then(function () { return filePicker_field; }).then((c) => c.FilePickerField),
5175
- file2: () => Promise.resolve().then(function () { return filePicker_field; }).then((c) => c.FilePickerField),
5176
5929
  radio: () => Promise.resolve().then(function () { return radio_field; }).then((c) => c.RadioField),
5177
- textarea: () => Promise.resolve().then(function () { return textarea_field; }).then((c) => c.TextareaField),
5178
- chips: () => Promise.resolve().then(function () { return chips_field; }).then((c) => c.ChipsField),
5179
- plate: () => Promise.resolve().then(function () { return plate_field; }).then((c) => c.PlateField),
5180
- note: () => import('./iss-ctrl-note.field-4uLl0oS_.mjs').then((c) => c.NoteField),
5181
- slideToggle: () => Promise.resolve().then(function () { return slideToggle_field; }).then((c) => c.SlideToggleField),
5182
- toggle: () => Promise.resolve().then(function () { return toggleButton_field; }).then((c) => c.ToggleButtonField),
5930
+ date: () => Promise.resolve().then(function () { return datePicker_field; }).then((c) => c.DatePickerField),
5183
5931
  time: () => Promise.resolve().then(function () { return timePicker_field; }).then((c) => c.TimePickerField),
5932
+ datetime: () => Promise.resolve().then(function () { return datetimePicker_field; }).then((c) => c.DatetimePickerField),
5933
+ date_range: () => Promise.resolve().then(function () { return dateRangePicker_field; }).then((c) => c.DateRangePickerField),
5934
+ attachment: () => Promise.resolve().then(function () { return filePicker_field; }).then((c) => c.FilePickerField),
5935
+ userPicker: () => import('./iss-ctrl-user-picker.field-Mqi37i7D.mjs').then((c) => c.UserPickerField),
5936
+ vehicle_plate: () => Promise.resolve().then(function () { return plate_field; }).then((c) => c.PlateField),
5937
+ enrichment: () => import('./iss-ctrl-note.field-onDjqI_X.mjs').then((c) => c.NoteField),
5184
5938
  mobile: () => Promise.resolve().then(function () { return mobile_field; }).then((c) => c.MobileField),
5185
- table: () => import('./iss-ctrl-table.field-kPIwve-M.mjs').then((c) => c.TableField),
5186
- userPicker: () => import('./iss-ctrl-user-picker.field-l-0bW6lP.mjs').then((c) => c.UserPickerField),
5187
- userPicker2: () => import('./iss-ctrl-user-picker.field-l-0bW6lP.mjs').then((c) => c.UserPickerField),
5939
+ table: () => import('./iss-ctrl-table.field-DxwfNXNc.mjs').then((c) => c.TableField),
5940
+ chips: () => Promise.resolve().then(function () { return chips_field; }).then((c) => c.ChipsField),
5941
+ switch: () => Promise.resolve().then(function () { return slideToggle_field; }).then((c) => c.SlideToggleField),
5188
5942
  };
5189
5943
 
5190
5944
  const SERVICES = {
5191
- setValue: () => import('./iss-ctrl-set-value-event-BbEYFBe3.mjs').then((s) => s.SetValueEvent),
5945
+ setValue: () => import('./iss-ctrl-set-value-event-DiHESiPT.mjs').then((s) => s.SetValueEvent),
5192
5946
  show: () => import('./iss-ctrl-show-event-BcRCwAfo.mjs').then((s) => s.ShowEvent),
5193
- load: () => import('./iss-ctrl-load-value-event-DThpI9BA.mjs').then((s) => s.LoadValueEvent),
5194
- loadOptions: () => import('./iss-ctrl-load-options-event-ClX9TiiD.mjs').then((s) => s.LoadOptionsEvent),
5195
- triggerBasedOnJsonValue: () => import('./iss-ctrl-trigger-based-on-json-value-DuLD4SOS.mjs').then((s) => s.TriggerBasedOnJsonValue),
5196
- replaceApiKeyDefaultImpl: () => import('./iss-ctrl-replace-api-keys-BQL9zimJ.mjs').then((s) => s.ReplaceApiKeys),
5947
+ load: () => import('./iss-ctrl-load-value-event-Bu9-rZ6T.mjs').then((s) => s.LoadValueEvent),
5948
+ loadOptions: () => import('./iss-ctrl-load-options-event-CBejHpME.mjs').then((s) => s.LoadOptionsEvent),
5949
+ triggerBasedOnJsonValue: () => import('./iss-ctrl-trigger-based-on-json-value-CprcFCWi.mjs').then((s) => s.TriggerBasedOnJsonValue),
5950
+ replaceApiKeyDefaultImpl: () => import('./iss-ctrl-replace-api-keys-Chwe42Nu.mjs').then((s) => s.ReplaceApiKeys),
5197
5951
  };
5198
5952
 
5199
5953
  // Read-only counterpart of COMPONENTS: the component used to render a field's value
@@ -5308,7 +6062,7 @@ class Outlet {
5308
6062
  #formEngine = inject(FormEngine);
5309
6063
  #loader = inject(Loader);
5310
6064
  #effectRef = effect((onCleanup) => {
5311
- // Dynamic imports cannot be cancelled, but an old result must never replace
6065
+ // Dynamic imports cannot be canceled, but an old result must never replace
5312
6066
  // the components produced for a newer fields input (or a destroyed outlet).
5313
6067
  let active = true;
5314
6068
  onCleanup(() => {
@@ -5738,14 +6492,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
5738
6492
  args: [{ providedIn: "root" }]
5739
6493
  }] });
5740
6494
 
6495
+ /**
6496
+ * Base class for every `iss-field-*` field.
6497
+ *
6498
+ * A field is the form-engine layer around a control: it reads its whole configuration from
6499
+ * the injected {@link IssField} (label, options, config, validation, events), registers its
6500
+ * `FormControl` on the parent `FormGroup` on init and removes it again on destroy, and
6501
+ * switches between the control (`mode() === "edit"`) and the viewer (`mode() === "view"`).
6502
+ *
6503
+ * ### Inputs
6504
+ * | Property | Type | Description |
6505
+ * | --- | --- | --- |
6506
+ * | `issField` | `IssField` | **Required.** The field definition; also provided through the `FIELD_DATA` token. |
6507
+ * | `formReady` | `boolean \| undefined` | Set by the outlet once the whole form exists; gates event wiring. |
6508
+ *
6509
+ * ### Properties available on `field`
6510
+ * `name` · `type` · `base` · `label()` · `hint()` · `options()` · `api()` · `mode()` ·
6511
+ * `visible()` · `loading()` · `value` · `jsonValue` · `defaultValue` · `ctrlValue()` ·
6512
+ * `ctrlJsonValue()` · `events` · `validation` · `asyncValidation` · `children` ·
6513
+ * `response()` · `config` — see {@link IssField} and {@link FieldConfig}.
6514
+ *
6515
+ * Fields are not used directly in templates; the outlet resolves them from the field `type`
6516
+ * through the `COMPONENTS` index.
6517
+ */
5741
6518
  class FieldBase {
6519
+ /**
6520
+ * The field definition rendered by this component. Required.
6521
+ */
5742
6522
  issField = input.required(...(ngDevMode ? [{ debugName: "issField" }] : /* istanbul ignore next */ []));
6523
+ /**
6524
+ * Set by the outlet once every field is registered; field events start only after it turns true.
6525
+ */
5743
6526
  formReady = input(...(ngDevMode ? [undefined, { debugName: "formReady" }] : /* istanbul ignore next */ []));
6527
+ /**
6528
+ * The {@link IssField} for this instance, injected through the `FIELD_DATA` token.
6529
+ */
5744
6530
  field = inject(FIELD_DATA);
5745
6531
  parentFormGroup = inject(ControlContainer);
5746
6532
  formEngine = inject(FormEngine);
5747
6533
  eventHandler = inject(EventHandler);
5748
6534
  destroyRef = inject(DestroyRef);
6535
+ /**
6536
+ * The `FormControl` this field registers on the parent form under `field.name`.
6537
+ */
5749
6538
  ctrl = new FormControl(null);
5750
6539
  ctrlValueChange = toSignal(this.ctrl.valueChanges, { initialValue: this.ctrl.getRawValue() });
5751
6540
  #valueChangeEffectRef = effect(() => {
@@ -5852,6 +6641,34 @@ var input_viewer = /*#__PURE__*/Object.freeze({
5852
6641
  InputViewer: InputViewer
5853
6642
  });
5854
6643
 
6644
+ /**
6645
+ * `<iss-field-input>` — single line text, number, email or password entry.
6646
+ *
6647
+ * Rendered by the outlet for fields of type `text_input`. In `edit` mode it renders
6648
+ * {@link InputControl} plus the validation message; in `view` mode the matching viewer.
6649
+ *
6650
+ * ### Supported `config` keys
6651
+ * | Key | Type | Description |
6652
+ * | --- | --- | --- |
6653
+ * | `type` | `string` | Native input type — `text`, `number`, `email`, `password`, … |
6654
+ * | `placeholder` | `string` | Placeholder shown while empty. |
6655
+ * | `min` | `number` | Minimum numeric value. |
6656
+ * | `max` | `number` | Maximum numeric value. |
6657
+ * | `minLength` | `number` | Minimum number of characters. |
6658
+ * | `maxLength` | `number` | Maximum number of characters. |
6659
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
6660
+ *
6661
+ * ### Other field members used
6662
+ * `label()`
6663
+ *
6664
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
6665
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
6666
+ *
6667
+ * @example
6668
+ * ```json
6669
+ * { "name": "email", "type": "text_input", "label": "Email", "config": { "type": "email", "maxLength": 120 } }
6670
+ * ```
6671
+ */
5855
6672
  class InputField extends FieldBase {
5856
6673
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: InputField, deps: null, target: i0.ɵɵFactoryTarget.Component });
5857
6674
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: InputField, isStandalone: true, selector: "iss-field-input", usesInheritance: true, ngImport: i0, template: `
@@ -5862,8 +6679,8 @@ class InputField extends FieldBase {
5862
6679
  [type]="field.config.type() ?? ''"
5863
6680
  [placeholder]="field.config.placeholder() ?? ''"
5864
6681
  [min]="field.config.min() ?? null"
5865
- [max]="field.config.max() ?? null"
5866
- [readonly]="field.config.readonly() ?? false"
6682
+ [max]="field.config.max() ?? null"
6683
+ [readonly]="field.config.readonly() ?? false"
5867
6684
  [minLength]="field.config.minLength() ?? null"
5868
6685
  [maxLength]="field.config.maxLength() ?? null"
5869
6686
  >
@@ -5895,8 +6712,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
5895
6712
  [type]="field.config.type() ?? ''"
5896
6713
  [placeholder]="field.config.placeholder() ?? ''"
5897
6714
  [min]="field.config.min() ?? null"
5898
- [max]="field.config.max() ?? null"
5899
- [readonly]="field.config.readonly() ?? false"
6715
+ [max]="field.config.max() ?? null"
6716
+ [readonly]="field.config.readonly() ?? false"
5900
6717
  [minLength]="field.config.minLength() ?? null"
5901
6718
  [maxLength]="field.config.maxLength() ?? null"
5902
6719
  >
@@ -5937,12 +6754,36 @@ var textarea_viewer = /*#__PURE__*/Object.freeze({
5937
6754
  TextareaViewer: TextareaViewer
5938
6755
  });
5939
6756
 
6757
+ /**
6758
+ * `<iss-field-textarea>` — multi line free text.
6759
+ *
6760
+ * Rendered by the outlet for fields of type `textarea`. In `edit` mode it renders
6761
+ * {@link TextareaControl} plus the validation message; in `view` mode the matching viewer.
6762
+ *
6763
+ * ### Supported `config` keys
6764
+ * | Key | Type | Description |
6765
+ * | --- | --- | --- |
6766
+ * | `minLength` | `number` | Minimum number of characters. |
6767
+ * | `maxLength` | `number` | Maximum number of characters. |
6768
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
6769
+ *
6770
+ * ### Other field members used
6771
+ * `label()`
6772
+ *
6773
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
6774
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
6775
+ *
6776
+ * @example
6777
+ * ```json
6778
+ * { "name": "notes", "type": "textarea", "label": "Notes", "config": { "maxLength": 500 } }
6779
+ * ```
6780
+ */
5940
6781
  class TextareaField extends FieldBase {
5941
6782
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TextareaField, deps: null, target: i0.ɵɵFactoryTarget.Component });
5942
6783
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TextareaField, isStandalone: true, selector: "iss-field-textarea", usesInheritance: true, ngImport: i0, template: `
5943
6784
  @if (field.visible()) {
5944
6785
  @if (field.mode() === "edit") {
5945
- <iss-ctrl-textarea [formControlName]="field.name" [minLength]="field.config.minLength() ?? null" [maxLength]="field.config.maxLength() ?? null" [readonly]="field.config.readonly() ?? false">
6786
+ <iss-ctrl-textarea [formControlName]="field.name" [minLength]="field.config.minLength() ?? null" [maxLength]="field.config.maxLength() ?? null" [readonly]="field.config.readonly() ?? false">
5946
6787
  <label>{{ field.label() }}</label>
5947
6788
  </iss-ctrl-textarea>
5948
6789
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -5966,7 +6807,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
5966
6807
  template: `
5967
6808
  @if (field.visible()) {
5968
6809
  @if (field.mode() === "edit") {
5969
- <iss-ctrl-textarea [formControlName]="field.name" [minLength]="field.config.minLength() ?? null" [maxLength]="field.config.maxLength() ?? null" [readonly]="field.config.readonly() ?? false">
6810
+ <iss-ctrl-textarea [formControlName]="field.name" [minLength]="field.config.minLength() ?? null" [maxLength]="field.config.maxLength() ?? null" [readonly]="field.config.readonly() ?? false">
5970
6811
  <label>{{ field.label() }}</label>
5971
6812
  </iss-ctrl-textarea>
5972
6813
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -6019,12 +6860,34 @@ var chips_viewer = /*#__PURE__*/Object.freeze({
6019
6860
  ChipsViewer: ChipsViewer
6020
6861
  });
6021
6862
 
6863
+ /**
6864
+ * `<iss-field-chips>` — free text entered as removable chips.
6865
+ *
6866
+ * Rendered by the outlet for fields of type `chips`. In `edit` mode it renders
6867
+ * {@link ChipsControl} plus the validation message; in `view` mode the matching viewer.
6868
+ *
6869
+ * ### Supported `config` keys
6870
+ * | Key | Type | Description |
6871
+ * | --- | --- | --- |
6872
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
6873
+ *
6874
+ * ### Other field members used
6875
+ * `label()`
6876
+ *
6877
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
6878
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
6879
+ *
6880
+ * @example
6881
+ * ```json
6882
+ * { "name": "tags", "type": "chips", "label": "Tags" }
6883
+ * ```
6884
+ */
6022
6885
  class ChipsField extends FieldBase {
6023
6886
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ChipsField, deps: null, target: i0.ɵɵFactoryTarget.Component });
6024
6887
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ChipsField, isStandalone: true, selector: "iss-field-chips", usesInheritance: true, ngImport: i0, template: `
6025
6888
  @if (field.visible()) {
6026
6889
  @if (field.mode() === "edit") {
6027
- <iss-ctrl-chips [formControlName]="field.name" [readonly]="field.config.readonly() ?? false"><label>{{ field.label() }}</label></iss-ctrl-chips>
6890
+ <iss-ctrl-chips [formControlName]="field.name" [readonly]="field.config.readonly() ?? false"><label>{{ field.label() }}</label></iss-ctrl-chips>
6028
6891
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6029
6892
  } @else {
6030
6893
  <iss-viewer-chips [field]="field"/>
@@ -6046,7 +6909,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6046
6909
  template: `
6047
6910
  @if (field.visible()) {
6048
6911
  @if (field.mode() === "edit") {
6049
- <iss-ctrl-chips [formControlName]="field.name" [readonly]="field.config.readonly() ?? false"><label>{{ field.label() }}</label></iss-ctrl-chips>
6912
+ <iss-ctrl-chips [formControlName]="field.name" [readonly]="field.config.readonly() ?? false"><label>{{ field.label() }}</label></iss-ctrl-chips>
6050
6913
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6051
6914
  } @else {
6052
6915
  <iss-viewer-chips [field]="field"/>
@@ -6090,6 +6953,29 @@ var radio_viewer = /*#__PURE__*/Object.freeze({
6090
6953
  RadioViewer: RadioViewer
6091
6954
  });
6092
6955
 
6956
+ /**
6957
+ * `<iss-field-radio>` — one choice out of a fixed set of options.
6958
+ *
6959
+ * Rendered by the outlet for fields of type `radio`. In `edit` mode it renders
6960
+ * {@link RadioControl} plus the validation message; in `view` mode the matching viewer.
6961
+ *
6962
+ * ### Supported `config` keys
6963
+ * | Key | Type | Description |
6964
+ * | --- | --- | --- |
6965
+ * | `hideLabel` | `boolean` | Hides the field label. |
6966
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
6967
+ *
6968
+ * ### Other field members used
6969
+ * `label()` · `options()`
6970
+ *
6971
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
6972
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
6973
+ *
6974
+ * @example
6975
+ * ```json
6976
+ * { "name": "gender", "type": "radio", "label": "Gender", "options": [{ "value": "m", "label": "Male" }] }
6977
+ * ```
6978
+ */
6093
6979
  class RadioField extends FieldBase {
6094
6980
  onChange($event) {
6095
6981
  this.field.ctrlJsonValue.set($event);
@@ -6103,7 +6989,7 @@ class RadioField extends FieldBase {
6103
6989
  }
6104
6990
 
6105
6991
  @if (field.mode() === "edit") {
6106
- <iss-ctrl-radio [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
6992
+ <iss-ctrl-radio [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
6107
6993
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6108
6994
  } @else {
6109
6995
  <iss-viewer-radio [field]="field"/>
@@ -6132,7 +7018,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6132
7018
  }
6133
7019
 
6134
7020
  @if (field.mode() === "edit") {
6135
- <iss-ctrl-radio [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
7021
+ <iss-ctrl-radio [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
6136
7022
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6137
7023
  } @else {
6138
7024
  <iss-viewer-radio [field]="field"/>
@@ -6177,6 +7063,32 @@ var select_viewer = /*#__PURE__*/Object.freeze({
6177
7063
  SelectViewer: SelectViewer
6178
7064
  });
6179
7065
 
7066
+ /**
7067
+ * `<iss-field-select>` — single or multiple selection from a dropdown.
7068
+ *
7069
+ * Rendered by the outlet for fields of type `dropdown_list`. In `edit` mode it renders
7070
+ * {@link SelectControl} plus the validation message; in `view` mode the matching viewer.
7071
+ *
7072
+ * ### Supported `config` keys
7073
+ * | Key | Type | Description |
7074
+ * | --- | --- | --- |
7075
+ * | `multiple` | `boolean` | Allows selecting more than one option. |
7076
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
7077
+ *
7078
+ * ### Other field members used
7079
+ * `label()` · `options()` · `ctrlJsonValue()`
7080
+ *
7081
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
7082
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
7083
+ *
7084
+ * The raw form value holds the selected option values; the resolved options are written
7085
+ * back to `field.ctrlJsonValue`.
7086
+ *
7087
+ * @example
7088
+ * ```json
7089
+ * { "name": "city", "type": "dropdown_list", "label": "City", "options": [{ "value": "1", "label": "Riyadh" }] }
7090
+ * ```
7091
+ */
6180
7092
  class SelectField extends FieldBase {
6181
7093
  onChange($event) {
6182
7094
  this.field.ctrlJsonValue.set($event);
@@ -6185,7 +7097,7 @@ class SelectField extends FieldBase {
6185
7097
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: SelectField, isStandalone: true, selector: "iss-field-select", usesInheritance: true, ngImport: i0, template: `
6186
7098
  @if (field.visible()) {
6187
7099
  @if (field.mode() === "edit") {
6188
- <iss-ctrl-select [formControlName]="field.name" [options]="field.options()" [multiple]="field.config.multiple()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)">
7100
+ <iss-ctrl-select [formControlName]="field.name" [options]="field.options()" [multiple]="field.config.multiple()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)">
6189
7101
  <label>{{ field.label() }}</label>
6190
7102
  </iss-ctrl-select>
6191
7103
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -6209,7 +7121,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6209
7121
  template: `
6210
7122
  @if (field.visible()) {
6211
7123
  @if (field.mode() === "edit") {
6212
- <iss-ctrl-select [formControlName]="field.name" [options]="field.options()" [multiple]="field.config.multiple()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)">
7124
+ <iss-ctrl-select [formControlName]="field.name" [options]="field.options()" [multiple]="field.config.multiple()" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)">
6213
7125
  <label>{{ field.label() }}</label>
6214
7126
  </iss-ctrl-select>
6215
7127
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -6247,6 +7159,28 @@ var mobile_viewer = /*#__PURE__*/Object.freeze({
6247
7159
  MobileViewer: MobileViewer
6248
7160
  });
6249
7161
 
7162
+ /**
7163
+ * `<iss-field-mobile>` — an international phone number with a country selector.
7164
+ *
7165
+ * Rendered by the outlet for fields of the type `mobile`. In `edit` mode it renders
7166
+ * {@link MobileControl} plus the validation message; in `view` mode the matching viewer.
7167
+ *
7168
+ * ### Supported `config` keys
7169
+ * | Key | Type | Description |
7170
+ * | --- | --- | --- |
7171
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
7172
+ *
7173
+ * ### Other field members used
7174
+ * `label()`
7175
+ *
7176
+ * Every field also honors `visible`, `mode`, `validation`, `asyncValidation` and
7177
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
7178
+ *
7179
+ * @example
7180
+ * ```json
7181
+ * { "name": "mobile", "type": "mobile", "label": "Mobile" }
7182
+ * ```
7183
+ */
6250
7184
  class MobileField extends FieldBase {
6251
7185
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: MobileField, deps: null, target: i0.ɵɵFactoryTarget.Component });
6252
7186
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: MobileField, isStandalone: true, selector: "iss-field-mobile", usesInheritance: true, ngImport: i0, template: `
@@ -6320,6 +7254,29 @@ var checkbox_viewer = /*#__PURE__*/Object.freeze({
6320
7254
  CheckboxViewer: CheckboxViewer
6321
7255
  });
6322
7256
 
7257
+ /**
7258
+ * `<iss-field-checkbox>` — a list of checkboxes over a fixed set of options.
7259
+ *
7260
+ * Rendered by the outlet for fields of type `checkbox`. In `edit` mode it renders
7261
+ * {@link CheckboxControl} plus the validation message; in `view` mode the matching viewer.
7262
+ *
7263
+ * ### Supported `config` keys
7264
+ * | Key | Type | Description |
7265
+ * | --- | --- | --- |
7266
+ * | `hideLabel` | `boolean` | Hides the field label. |
7267
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
7268
+ *
7269
+ * ### Other field members used
7270
+ * `label()` · `options()`
7271
+ *
7272
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
7273
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
7274
+ *
7275
+ * @example
7276
+ * ```json
7277
+ * { "name": "days", "type": "checkbox", "label": "Days", "options": [{ "value": "sun", "label": "Sunday" }] }
7278
+ * ```
7279
+ */
6323
7280
  class CheckboxField extends FieldBase {
6324
7281
  updateField($event) {
6325
7282
  this.field.ctrlJsonValue.set($event);
@@ -6328,7 +7285,7 @@ class CheckboxField extends FieldBase {
6328
7285
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: CheckboxField, isStandalone: true, selector: "iss-field-checkbox", usesInheritance: true, ngImport: i0, template: `
6329
7286
  @if (field.visible()) {
6330
7287
  @if (field.mode() === "edit") {
6331
- <iss-ctrl-checkbox [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)">
7288
+ <iss-ctrl-checkbox [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)">
6332
7289
  @if (!field.config.hideLabel()) {
6333
7290
  <label>{{ field.label() }}</label>
6334
7291
  }
@@ -6354,7 +7311,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6354
7311
  template: `
6355
7312
  @if (field.visible()) {
6356
7313
  @if (field.mode() === "edit") {
6357
- <iss-ctrl-checkbox [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)">
7314
+ <iss-ctrl-checkbox [formControlName]="field.name" [options]="field.options()" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)">
6358
7315
  @if (!field.config.hideLabel()) {
6359
7316
  <label>{{ field.label() }}</label>
6360
7317
  }
@@ -6402,6 +7359,30 @@ var toggleButton_viewer = /*#__PURE__*/Object.freeze({
6402
7359
  ToggleButtonViewer: ToggleButtonViewer
6403
7360
  });
6404
7361
 
7362
+ /**
7363
+ * `<iss-field-toggle-button>` — options rendered as a button group.
7364
+ *
7365
+ * Rendered by the outlet for fields of type `toggle_button`. In `edit` mode it renders
7366
+ * {@link ToggleButtonControl} plus the validation message; in `view` mode the matching viewer.
7367
+ *
7368
+ * ### Supported `config` keys
7369
+ * | Key | Type | Description |
7370
+ * | --- | --- | --- |
7371
+ * | `multiple` | `boolean` | Allows more than one active button. |
7372
+ * | `hideLabel` | `boolean` | Hides the field label. |
7373
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
7374
+ *
7375
+ * ### Other field members used
7376
+ * `label()` · `options()`
7377
+ *
7378
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
7379
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
7380
+ *
7381
+ * @example
7382
+ * ```json
7383
+ * { "name": "priority", "type": "toggle_button", "label": "Priority", "options": [{ "value": "high", "label": "High" }] }
7384
+ * ```
7385
+ */
6405
7386
  class ToggleButtonField extends FieldBase {
6406
7387
  onChange($event) {
6407
7388
  this.field.ctrlJsonValue.set($event);
@@ -6415,9 +7396,9 @@ class ToggleButtonField extends FieldBase {
6415
7396
  @if (field.mode() === "edit") {
6416
7397
  <iss-ctrl-toggle-button
6417
7398
  [formControlName]="field.name"
6418
- [options]="field.options()"
6419
- [multiple]="field.config.multiple()"
6420
- [readonly]="field.config.readonly() ?? false"
7399
+ [options]="field.options()"
7400
+ [multiple]="field.config.multiple()"
7401
+ [readonly]="field.config.readonly() ?? false"
6421
7402
  (onChange)="onChange($event)"
6422
7403
  />
6423
7404
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -6447,9 +7428,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6447
7428
  @if (field.mode() === "edit") {
6448
7429
  <iss-ctrl-toggle-button
6449
7430
  [formControlName]="field.name"
6450
- [options]="field.options()"
6451
- [multiple]="field.config.multiple()"
6452
- [readonly]="field.config.readonly() ?? false"
7431
+ [options]="field.options()"
7432
+ [multiple]="field.config.multiple()"
7433
+ [readonly]="field.config.readonly() ?? false"
6453
7434
  (onChange)="onChange($event)"
6454
7435
  />
6455
7436
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -6499,6 +7480,29 @@ var slideToggle_viewer = /*#__PURE__*/Object.freeze({
6499
7480
  SlideToggleViewer: SlideToggleViewer
6500
7481
  });
6501
7482
 
7483
+ /**
7484
+ * `<iss-field-slide-toggle>` — an on/off switch for a boolean value.
7485
+ *
7486
+ * Rendered by the outlet for fields of type `switch`. In `edit` mode it renders
7487
+ * {@link SlideToggleControl} plus the validation message; in `view` mode the matching viewer.
7488
+ *
7489
+ * ### Supported `config` keys
7490
+ * | Key | Type | Description |
7491
+ * | --- | --- | --- |
7492
+ * | `hideLabel` | `boolean` | Hides the field label. |
7493
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
7494
+ *
7495
+ * ### Other field members used
7496
+ * `label()`
7497
+ *
7498
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
7499
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
7500
+ *
7501
+ * @example
7502
+ * ```json
7503
+ * { "name": "active", "type": "switch", "label": "Active" }
7504
+ * ```
7505
+ */
6502
7506
  class SlideToggleField extends FieldBase {
6503
7507
  onChange($event) {
6504
7508
  this.field.ctrlJsonValue.set($event);
@@ -6511,7 +7515,7 @@ class SlideToggleField extends FieldBase {
6511
7515
  }
6512
7516
 
6513
7517
  @if (field.mode() === "edit") {
6514
- <iss-ctrl-slide-toggle [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
7518
+ <iss-ctrl-slide-toggle [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
6515
7519
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6516
7520
  } @else {
6517
7521
  <iss-viewer-slide-toggle [field]="field"/>
@@ -6532,7 +7536,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6532
7536
  }
6533
7537
 
6534
7538
  @if (field.mode() === "edit") {
6535
- <iss-ctrl-slide-toggle [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
7539
+ <iss-ctrl-slide-toggle [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="onChange($event)"/>
6536
7540
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6537
7541
  } @else {
6538
7542
  <iss-viewer-slide-toggle [field]="field"/>
@@ -6724,6 +7728,29 @@ var plate_viewer = /*#__PURE__*/Object.freeze({
6724
7728
  PlateViewer: PlateViewer
6725
7729
  });
6726
7730
 
7731
+ /**
7732
+ * `<iss-field-plate-number>` — a Saudi vehicle plate in Arabic and English.
7733
+ *
7734
+ * Rendered by the outlet for fields of type `vehicle_plate`. In `edit` mode it renders
7735
+ * {@link PlateControl} plus the validation message; in `view` mode the matching viewer.
7736
+ *
7737
+ * ### Supported `config` keys
7738
+ * | Key | Type | Description |
7739
+ * | --- | --- | --- |
7740
+ * | `hideLabel` | `boolean` | Hides the field label. |
7741
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
7742
+ *
7743
+ * ### Other field members used
7744
+ * `label()`
7745
+ *
7746
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
7747
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
7748
+ *
7749
+ * @example
7750
+ * ```json
7751
+ * { "name": "plate", "type": "vehicle_plate", "label": "Plate number" }
7752
+ * ```
7753
+ */
6727
7754
  class PlateField extends FieldBase {
6728
7755
  updateField($event) {
6729
7756
  this.field.ctrlJsonValue.set($event);
@@ -6736,7 +7763,7 @@ class PlateField extends FieldBase {
6736
7763
  }
6737
7764
 
6738
7765
  @if (field.mode() === "edit") {
6739
- <iss-ctrl-plate-number [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)"/>
7766
+ <iss-ctrl-plate-number [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)"/>
6740
7767
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6741
7768
  } @else {
6742
7769
  <iss-viewer-plate [field]="field"/>
@@ -6763,7 +7790,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6763
7790
  }
6764
7791
 
6765
7792
  @if (field.mode() === "edit") {
6766
- <iss-ctrl-plate-number [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)"/>
7793
+ <iss-ctrl-plate-number [formControlName]="field.name" [readonly]="field.config.readonly() ?? false" (onChange)="updateField($event)"/>
6767
7794
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
6768
7795
  } @else {
6769
7796
  <iss-viewer-plate [field]="field"/>
@@ -6997,6 +8024,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
6997
8024
  args: [{ providedIn: "root" }]
6998
8025
  }] });
6999
8026
 
8027
+ /**
8028
+ * `<iss-field-file-picker>` — attachment upload.
8029
+ *
8030
+ * Rendered by the outlet for fields of type `attachment`. In `edit` mode it renders
8031
+ * {@link FilePickerControl} plus the validation message; in `view` mode the matching viewer.
8032
+ *
8033
+ * ### Supported `config` keys
8034
+ * | Key | Type | Description |
8035
+ * | --- | --- | --- |
8036
+ * | `multiple` | `boolean` | Allows attaching more than one file. |
8037
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
8038
+ *
8039
+ * ### Other field members used
8040
+ * `label()` · `value` · `validation` · `ctrlJsonValue()`
8041
+ *
8042
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
8043
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
8044
+ *
8045
+ * The field uploads the picked files itself, stores the returned ids as the control value
8046
+ * and keeps the resolved attachments in `field.ctrlJsonValue`.
8047
+ *
8048
+ * Accepted extensions come from the `fileType` **validation** rule, not from `config`; the
8049
+ * `allowedFileSize`, `allowedFileTypes`, `minFilesCount`, `maxFilesCount`, `templateId` and
8050
+ * `templateUrl` config keys exist on {@link FieldConfig} but are not read here yet.
8051
+ *
8052
+ * @example
8053
+ * ```json
8054
+ * { "name": "attachments", "type": "attachment", "label": "Attachments", "config": { "multiple": true }, "validation": { "fileType": ["pdf", "png"] } }
8055
+ * ```
8056
+ */
7000
8057
  class FilePickerField extends FieldBase {
7001
8058
  picker = new FormControl();
7002
8059
  fileHandlerService = inject(FileHandler);
@@ -7107,8 +8164,8 @@ class FilePickerField extends FieldBase {
7107
8164
  [formControl]="picker"
7108
8165
  [accept]="accept"
7109
8166
  (onChange)="captureFile($event)"
7110
- [multiple]="field.config.multiple()"
7111
- [readonly]="field.config.readonly() ?? false"
8167
+ [multiple]="field.config.multiple()"
8168
+ [readonly]="field.config.readonly() ?? false"
7112
8169
  [uploading]="uploading()"
7113
8170
  [uploadedFiles]="attachments()"
7114
8171
  [uploadingError]="uploadingError()"
@@ -7142,8 +8199,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7142
8199
  [formControl]="picker"
7143
8200
  [accept]="accept"
7144
8201
  (onChange)="captureFile($event)"
7145
- [multiple]="field.config.multiple()"
7146
- [readonly]="field.config.readonly() ?? false"
8202
+ [multiple]="field.config.multiple()"
8203
+ [readonly]="field.config.readonly() ?? false"
7147
8204
  [uploading]="uploading()"
7148
8205
  [uploadedFiles]="attachments()"
7149
8206
  [uploadingError]="uploadingError()"
@@ -7183,6 +8240,28 @@ var timePicker_viewer = /*#__PURE__*/Object.freeze({
7183
8240
  TimePickerViewer: TimePickerViewer
7184
8241
  });
7185
8242
 
8243
+ /**
8244
+ * `<iss-field-time-picker>` — a time of day, picked from a generated list.
8245
+ *
8246
+ * Rendered by the outlet for fields of type `time`. In `edit` mode it renders
8247
+ * {@link TimePickerControl} plus the validation message; in `view` mode the matching viewer.
8248
+ *
8249
+ * ### Supported `config` keys
8250
+ * | Key | Type | Description |
8251
+ * | --- | --- | --- |
8252
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
8253
+ *
8254
+ * ### Other field members used
8255
+ * `label()`
8256
+ *
8257
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
8258
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
8259
+ *
8260
+ * @example
8261
+ * ```json
8262
+ * { "name": "startsAt", "type": "time", "label": "Starts at" }
8263
+ * ```
8264
+ */
7186
8265
  class TimePickerField extends FieldBase {
7187
8266
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TimePickerField, deps: null, target: i0.ɵɵFactoryTarget.Component });
7188
8267
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TimePickerField, isStandalone: true, selector: "iss-field-time-picker", usesInheritance: true, ngImport: i0, template: `
@@ -7250,12 +8329,36 @@ var datePicker_viewer = /*#__PURE__*/Object.freeze({
7250
8329
  DatePickerViewer: DatePickerViewer
7251
8330
  });
7252
8331
 
8332
+ /**
8333
+ * `<iss-field-date-picker>` — a single date, picked from a calendar.
8334
+ *
8335
+ * Rendered by the outlet for fields of type `date`. In `edit` mode it renders
8336
+ * {@link DatePickerControl} plus the validation message; in `view` mode the matching viewer.
8337
+ *
8338
+ * ### Supported `config` keys
8339
+ * | Key | Type | Description |
8340
+ * | --- | --- | --- |
8341
+ * | `minDate` | `Date` | Earliest selectable date. |
8342
+ * | `maxDate` | `Date` | Latest selectable date. |
8343
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
8344
+ *
8345
+ * ### Other field members used
8346
+ * `label()`
8347
+ *
8348
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
8349
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
8350
+ *
8351
+ * @example
8352
+ * ```json
8353
+ * { "name": "startsOn", "type": "date", "label": "Start date", "config": { "minDate": "2026-01-01" } }
8354
+ * ```
8355
+ */
7253
8356
  class DatePickerField extends FieldBase {
7254
8357
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatePickerField, deps: null, target: i0.ɵɵFactoryTarget.Component });
7255
8358
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DatePickerField, isStandalone: true, selector: "iss-field-date-picker", usesInheritance: true, ngImport: i0, template: `
7256
8359
  @if (field.visible()) {
7257
8360
  @if (field.mode() === "edit") {
7258
- <iss-ctrl-date-picker [formControlName]="field.name" [minDate]="field.config.minDate() ?? null" [maxDate]="field.config.maxDate() ?? null" [readonly]="field.config.readonly() ?? false">
8361
+ <iss-ctrl-date-picker [formControlName]="field.name" [minDate]="field.config.minDate() ?? null" [maxDate]="field.config.maxDate() ?? null" [readonly]="field.config.readonly() ?? false">
7259
8362
  <label>{{ field.label() }}</label>
7260
8363
  </iss-ctrl-date-picker>
7261
8364
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -7279,7 +8382,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7279
8382
  template: `
7280
8383
  @if (field.visible()) {
7281
8384
  @if (field.mode() === "edit") {
7282
- <iss-ctrl-date-picker [formControlName]="field.name" [minDate]="field.config.minDate() ?? null" [maxDate]="field.config.maxDate() ?? null" [readonly]="field.config.readonly() ?? false">
8385
+ <iss-ctrl-date-picker [formControlName]="field.name" [minDate]="field.config.minDate() ?? null" [maxDate]="field.config.maxDate() ?? null" [readonly]="field.config.readonly() ?? false">
7283
8386
  <label>{{ field.label() }}</label>
7284
8387
  </iss-ctrl-date-picker>
7285
8388
  <iss-validation-message-viewer [errors]="ctrl.errors" [showMessage]="!ctrl.untouched"/>
@@ -7321,6 +8424,30 @@ var datetimePicker_viewer = /*#__PURE__*/Object.freeze({
7321
8424
  DatePickerTimeViewer: DatePickerTimeViewer
7322
8425
  });
7323
8426
 
8427
+ /**
8428
+ * `<iss-field-datetime-picker>` — a date and a time in one field.
8429
+ *
8430
+ * Rendered by the outlet for fields of type `datetime`. In `edit` mode it renders
8431
+ * {@link DatetimePickerControl} plus the validation message; in `view` mode the matching viewer.
8432
+ *
8433
+ * ### Supported `config` keys
8434
+ * | Key | Type | Description |
8435
+ * | --- | --- | --- |
8436
+ * | `minDate` | `Date` | Earliest selectable date. |
8437
+ * | `maxDate` | `Date` | Latest selectable date. |
8438
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
8439
+ *
8440
+ * ### Other field members used
8441
+ * `label()`
8442
+ *
8443
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
8444
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
8445
+ *
8446
+ * @example
8447
+ * ```json
8448
+ * { "name": "scheduledAt", "type": "datetime", "label": "Scheduled at" }
8449
+ * ```
8450
+ */
7324
8451
  class DatetimePickerField extends FieldBase {
7325
8452
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatetimePickerField, deps: null, target: i0.ɵɵFactoryTarget.Component });
7326
8453
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DatetimePickerField, isStandalone: true, selector: "iss-field-datetime-picker", usesInheritance: true, ngImport: i0, template: `
@@ -7399,6 +8526,32 @@ var dateRangePicker_viewer = /*#__PURE__*/Object.freeze({
7399
8526
  DateRangePickerViewer: DateRangePickerViewer
7400
8527
  });
7401
8528
 
8529
+ /**
8530
+ * `<iss-field-date-range-picker>` — a start and end date in one field.
8531
+ *
8532
+ * Rendered by the outlet for fields of type `date_range`. In `edit` mode it renders
8533
+ * {@link DateRangePickerControl} plus the validation message; in `view` mode the matching viewer.
8534
+ *
8535
+ * ### Supported `config` keys
8536
+ * | Key | Type | Description |
8537
+ * | --- | --- | --- |
8538
+ * | `minDate` | `Date` | Earliest selectable date. |
8539
+ * | `maxDate` | `Date` | Latest selectable date. |
8540
+ * | `readonly` | `boolean` | Shows the value but blocks interaction. |
8541
+ *
8542
+ * ### Other field members used
8543
+ * `label()`
8544
+ *
8545
+ * Every field also honours `visible`, `mode`, `validation`, `asyncValidation` and
8546
+ * `events` — see {@link IssField} for the full model and {@link FieldConfig} for all keys.
8547
+ *
8548
+ * A half-filled range is treated as no value at all.
8549
+ *
8550
+ * @example
8551
+ * ```json
8552
+ * { "name": "period", "type": "date_range", "label": "Period" }
8553
+ * ```
8554
+ */
7402
8555
  class DateRangePickerField extends FieldBase {
7403
8556
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DateRangePickerField, deps: null, target: i0.ɵɵFactoryTarget.Component });
7404
8557
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DateRangePickerField, isStandalone: true, selector: "iss-field-date-range-picker", usesInheritance: true, ngImport: i0, template: `
@@ -7756,5 +8909,5 @@ var time_validator = /*#__PURE__*/Object.freeze({
7756
8909
  * Generated bundle index. Do not edit.
7757
8910
  */
7758
8911
 
7759
- export { PlateViewer as $, TimePickerField as A, DatePickerField as B, ControlBase as C, DatePickerControl as D, Employee as E, FieldBase as F, DatetimePickerField as G, HOST as H, IssField as I, DateRangePickerField as J, InputViewer as K, Loader as L, MobileControl as M, TextareaViewer as N, Outlet as O, PLACEHOLDER_REGEX as P, ChipsViewer as Q, RadioControl as R, SelectControl as S, TextareaControl as T, RadioViewer as U, VIEW_PROVIDER as V, SelectViewer as W, MobileViewer as X, CheckboxViewer as Y, ToggleButtonViewer as Z, SlideToggleViewer as _, ViewerBase as a, AttachmentViewer as a0, TimePickerViewer as a1, DatePickerViewer as a2, DatePickerTimeViewer as a3, DateRangePickerViewer as a4, DEFAULT_COUNTRY as a5, COUNTRIES as a6, DATE_FORMAT_ADAPTER as a7, DATETIME_FORMAT as a8, PLATE_LETTERS as a9, VALIDATION_MESSAGES as aa, COMPONENTS as ab, SERVICES as ac, VALIDATORS as ad, FIELD_DATA as ae, UI_LANGUAGE as af, ATTACHMENT_UPLOAD_URL as ag, ATTACHMENT_UPLOAD_RESPONSE_MAPPER as ah, ATTACHMENT_DOWNLOAD_URL as ai, USER_SEARCH_API as aj, HintsComponent as ak, Droppable as al, ArabicNumberPipe as am, FieldDataInjector as an, PlateLetterPipe as ao, SelectStatusPipe as ap, TranslatePipe as aq, FileHandler as ar, Phone as as, arrayFrom as at, formatFileSize as au, IssValidators as av, FileValidators as aw, TimeValidator as ax, FormEngine as b, ValidationMessageComponent as c, CheckboxControl as d, ChipsControl as e, DateRangePickerControl as f, getPropertyByPath as g, DatetimePickerControl as h, FilePickerControl as i, InputControl as j, PlateControl as k, SlideToggleControl as l, TimePickerControl as m, ToggleButtonControl as n, InputField as o, TextareaField as p, ChipsField as q, replacePlaceholders as r, RadioField as s, SelectField as t, MobileField as u, CheckboxField as v, ToggleButtonField as w, SlideToggleField as x, PlateField as y, FilePickerField as z };
7760
- //# sourceMappingURL=iss-ctrl-iss-ctrl-hz0ibyPg.mjs.map
8912
+ export { PlateViewer as $, TimePickerField as A, DatePickerField as B, ControlBase as C, DatePickerControl as D, Employee as E, FieldBase as F, DatetimePickerField as G, HOST as H, IssField as I, DateRangePickerField as J, InputViewer as K, Loader as L, MobileControl as M, TextareaViewer as N, Outlet as O, PLACEHOLDER_REGEX as P, ChipsViewer as Q, RadioControl as R, SelectControl as S, TextareaControl as T, RadioViewer as U, VIEW_PROVIDER as V, SelectViewer as W, MobileViewer as X, CheckboxViewer as Y, ToggleButtonViewer as Z, SlideToggleViewer as _, ValidationMessageComponent as a, AttachmentViewer as a0, TimePickerViewer as a1, DatePickerViewer as a2, DatePickerTimeViewer as a3, DateRangePickerViewer as a4, DEFAULT_COUNTRY as a5, COUNTRIES as a6, DATE_FORMAT_ADAPTER as a7, DATETIME_FORMAT as a8, PLATE_LETTERS as a9, VALIDATION_MESSAGES as aa, COMPONENTS as ab, SERVICES as ac, VALIDATORS as ad, FIELD_DATA as ae, UI_LANGUAGE as af, ATTACHMENT_UPLOAD_URL as ag, ATTACHMENT_UPLOAD_RESPONSE_MAPPER as ah, ATTACHMENT_DOWNLOAD_URL as ai, USER_SEARCH_API as aj, HintsComponent as ak, Droppable as al, ArabicNumberPipe as am, FieldDataInjector as an, PlateLetterPipe as ao, SelectStatusPipe as ap, TranslatePipe as aq, FileHandler as ar, Phone as as, arrayFrom as at, formatFileSize as au, IssValidators as av, FileValidators as aw, TimeValidator as ax, ViewerBase as b, FormEngine as c, CheckboxControl as d, ChipsControl as e, DateRangePickerControl as f, getPropertyByPath as g, DatetimePickerControl as h, FilePickerControl as i, InputControl as j, PlateControl as k, SlideToggleControl as l, TimePickerControl as m, ToggleButtonControl as n, InputField as o, TextareaField as p, ChipsField as q, replacePlaceholders as r, RadioField as s, SelectField as t, MobileField as u, CheckboxField as v, ToggleButtonField as w, SlideToggleField as x, PlateField as y, FilePickerField as z };
8913
+ //# sourceMappingURL=iss-ctrl-iss-ctrl-WfIqBEcL.mjs.map