@material/web 1.0.1 → 1.0.2-nightly.8eb1f30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/all.d.ts +2 -0
  2. package/all.js +2 -0
  3. package/all.js.map +1 -1
  4. package/button/elevated-button.js +5 -1
  5. package/button/elevated-button.js.map +1 -1
  6. package/button/internal/_elevation.scss +32 -32
  7. package/button/internal/_icon.scss +22 -23
  8. package/button/internal/_outlined-button.scss +21 -19
  9. package/button/internal/_shared.scss +84 -77
  10. package/button/internal/_touch-target.scss +4 -0
  11. package/button/internal/button.d.ts +7 -11
  12. package/button/internal/button.js +52 -38
  13. package/button/internal/button.js.map +1 -1
  14. package/button/internal/elevated-button.d.ts +1 -1
  15. package/button/internal/elevated-button.js +1 -1
  16. package/button/internal/elevated-button.js.map +1 -1
  17. package/button/internal/filled-button.d.ts +1 -1
  18. package/button/internal/filled-button.js +1 -1
  19. package/button/internal/filled-button.js.map +1 -1
  20. package/button/internal/filled-tonal-button.d.ts +1 -1
  21. package/button/internal/filled-tonal-button.js +1 -1
  22. package/button/internal/filled-tonal-button.js.map +1 -1
  23. package/button/internal/outlined-button.d.ts +1 -1
  24. package/button/internal/outlined-button.js +2 -2
  25. package/button/internal/outlined-button.js.map +1 -1
  26. package/button/internal/outlined-styles.css.js +1 -1
  27. package/button/internal/outlined-styles.css.js.map +1 -1
  28. package/button/internal/shared-elevation-styles.css.js +1 -1
  29. package/button/internal/shared-elevation-styles.css.js.map +1 -1
  30. package/button/internal/shared-styles.css.js +1 -1
  31. package/button/internal/shared-styles.css.js.map +1 -1
  32. package/checkbox/internal/checkbox.d.ts +18 -25
  33. package/checkbox/internal/checkbox.js +43 -74
  34. package/checkbox/internal/checkbox.js.map +1 -1
  35. package/chips/filter-chip.js +5 -1
  36. package/chips/filter-chip.js.map +1 -1
  37. package/chips/harness.js.map +1 -1
  38. package/chips/input-chip.js +6 -1
  39. package/chips/input-chip.js.map +1 -1
  40. package/chips/internal/assist-chip.js +8 -4
  41. package/chips/internal/assist-chip.js.map +1 -1
  42. package/chips/internal/chip-set.js +6 -4
  43. package/chips/internal/chip-set.js.map +1 -1
  44. package/chips/internal/chip.d.ts +3 -0
  45. package/chips/internal/chip.js +7 -5
  46. package/chips/internal/chip.js.map +1 -1
  47. package/chips/internal/filter-chip.d.ts +2 -0
  48. package/chips/internal/filter-chip.js +11 -5
  49. package/chips/internal/filter-chip.js.map +1 -1
  50. package/chips/internal/input-chip.d.ts +2 -0
  51. package/chips/internal/input-chip.js +10 -4
  52. package/chips/internal/input-chip.js.map +1 -1
  53. package/chips/internal/multi-action-chip.js.map +1 -1
  54. package/chips/internal/trailing-icons.d.ts +1 -1
  55. package/chips/internal/trailing-icons.js +6 -5
  56. package/chips/internal/trailing-icons.js.map +1 -1
  57. package/common.d.ts +2 -0
  58. package/common.js +2 -0
  59. package/common.js.map +1 -1
  60. package/dialog/harness.js +1 -2
  61. package/dialog/harness.js.map +1 -1
  62. package/dialog/internal/_dialog.scss +1 -1
  63. package/dialog/internal/animations.js +14 -12
  64. package/dialog/internal/animations.js.map +1 -1
  65. package/dialog/internal/dialog-styles.css.js +1 -1
  66. package/dialog/internal/dialog-styles.css.js.map +1 -1
  67. package/dialog/internal/dialog.d.ts +6 -6
  68. package/dialog/internal/dialog.js +24 -24
  69. package/dialog/internal/dialog.js.map +1 -1
  70. package/fab/harness.js.map +1 -1
  71. package/fab/internal/fab.js.map +1 -1
  72. package/fab/internal/shared.js +10 -11
  73. package/fab/internal/shared.js.map +1 -1
  74. package/field/harness.js.map +1 -1
  75. package/field/internal/_content.scss +185 -174
  76. package/field/internal/_filled-field.scss +147 -136
  77. package/field/internal/_label.scss +83 -72
  78. package/field/internal/_outlined-field.scss +276 -262
  79. package/field/internal/_supporting-text.scss +53 -42
  80. package/field/internal/field.js +26 -22
  81. package/field/internal/field.js.map +1 -1
  82. package/field/internal/filled-styles.css.js +1 -1
  83. package/field/internal/filled-styles.css.js.map +1 -1
  84. package/field/internal/outlined-styles.css.js +1 -1
  85. package/field/internal/outlined-styles.css.js.map +1 -1
  86. package/field/internal/shared-styles.css.js +1 -1
  87. package/field/internal/shared-styles.css.js.map +1 -1
  88. package/focus/internal/focus-ring.d.ts +2 -0
  89. package/focus/internal/focus-ring.js +3 -3
  90. package/focus/internal/focus-ring.js.map +1 -1
  91. package/icon/internal/_icon.scss +7 -4
  92. package/icon/internal/icon-styles.css.js +1 -1
  93. package/icon/internal/icon-styles.css.js.map +1 -1
  94. package/iconbutton/internal/icon-button.d.ts +9 -4
  95. package/iconbutton/internal/icon-button.js +35 -22
  96. package/iconbutton/internal/icon-button.js.map +1 -1
  97. package/internal/aria/aria.d.ts +4 -26
  98. package/internal/aria/aria.js +10 -28
  99. package/internal/aria/aria.js.map +1 -1
  100. package/internal/aria/delegate.js +2 -2
  101. package/internal/aria/delegate.js.map +1 -1
  102. package/internal/controller/attachable-controller.js +3 -5
  103. package/internal/controller/attachable-controller.js.map +1 -1
  104. package/internal/controller/form-submitter.d.ts +3 -5
  105. package/internal/controller/form-submitter.js +5 -7
  106. package/internal/controller/form-submitter.js.map +1 -1
  107. package/internal/controller/is-rtl.js +2 -2
  108. package/internal/controller/is-rtl.js.map +1 -1
  109. package/internal/controller/string-converter.js +1 -1
  110. package/internal/controller/string-converter.js.map +1 -1
  111. package/internal/motion/animation.js.map +1 -1
  112. package/labs/behaviors/element-internals.d.ts +45 -0
  113. package/labs/behaviors/element-internals.js +50 -0
  114. package/labs/behaviors/element-internals.js.map +1 -0
  115. package/labs/behaviors/focusable.d.ts +39 -0
  116. package/labs/behaviors/focusable.js +82 -0
  117. package/labs/behaviors/focusable.js.map +1 -0
  118. package/labs/behaviors/form-associated.d.ts +199 -0
  119. package/labs/behaviors/form-associated.js +155 -0
  120. package/labs/behaviors/form-associated.js.map +1 -0
  121. package/labs/behaviors/mixin.d.ts +54 -0
  122. package/labs/behaviors/mixin.js +7 -0
  123. package/labs/behaviors/mixin.js.map +1 -0
  124. package/labs/behaviors/validators/checkbox-validator.d.ts +32 -0
  125. package/labs/behaviors/validators/checkbox-validator.js +32 -0
  126. package/labs/behaviors/validators/checkbox-validator.js.map +1 -0
  127. package/labs/behaviors/validators/validator.d.ts +92 -0
  128. package/labs/behaviors/validators/validator.js +73 -0
  129. package/labs/behaviors/validators/validator.js.map +1 -0
  130. package/labs/card/_elevated-card.scss +6 -0
  131. package/labs/card/_filled-card.scss +6 -0
  132. package/labs/card/_outlined-card.scss +6 -0
  133. package/labs/card/elevated-card.d.ts +18 -0
  134. package/labs/card/elevated-card.js +21 -0
  135. package/labs/card/elevated-card.js.map +1 -0
  136. package/labs/card/filled-card.d.ts +18 -0
  137. package/labs/card/filled-card.js +21 -0
  138. package/labs/card/filled-card.js.map +1 -0
  139. package/labs/card/internal/_elevated-card.scss +35 -0
  140. package/labs/card/internal/_filled-card.scss +35 -0
  141. package/labs/card/internal/_outlined-card.scss +39 -0
  142. package/labs/card/internal/_shared.scss +40 -0
  143. package/labs/card/internal/card.d.ts +13 -0
  144. package/labs/card/internal/card.js +20 -0
  145. package/labs/card/internal/card.js.map +1 -0
  146. package/labs/card/internal/elevated-styles.css.js +9 -0
  147. package/labs/card/internal/elevated-styles.css.js.map +1 -0
  148. package/labs/card/internal/elevated-styles.scss +10 -0
  149. package/labs/card/internal/filled-styles.css.js +9 -0
  150. package/labs/card/internal/filled-styles.css.js.map +1 -0
  151. package/labs/card/internal/filled-styles.scss +10 -0
  152. package/labs/card/internal/outlined-styles.css.js +9 -0
  153. package/labs/card/internal/outlined-styles.css.js.map +1 -0
  154. package/labs/card/internal/outlined-styles.scss +10 -0
  155. package/labs/card/internal/shared-styles.css.js +9 -0
  156. package/labs/card/internal/shared-styles.css.js.map +1 -0
  157. package/labs/card/internal/shared-styles.scss +10 -0
  158. package/labs/card/outlined-card.d.ts +18 -0
  159. package/labs/card/outlined-card.js +21 -0
  160. package/labs/card/outlined-card.js.map +1 -0
  161. package/labs/item/internal/item.js +8 -8
  162. package/labs/item/internal/item.js.map +1 -1
  163. package/labs/navigationbar/internal/constants.js.map +1 -1
  164. package/labs/navigationbar/internal/navigation-bar.d.ts +3 -0
  165. package/labs/navigationbar/internal/navigation-bar.js +18 -11
  166. package/labs/navigationbar/internal/navigation-bar.js.map +1 -1
  167. package/labs/navigationdrawer/internal/navigation-drawer-modal.d.ts +3 -0
  168. package/labs/navigationdrawer/internal/navigation-drawer-modal.js +10 -3
  169. package/labs/navigationdrawer/internal/navigation-drawer-modal.js.map +1 -1
  170. package/labs/navigationdrawer/internal/navigation-drawer.d.ts +3 -0
  171. package/labs/navigationdrawer/internal/navigation-drawer.js +8 -1
  172. package/labs/navigationdrawer/internal/navigation-drawer.js.map +1 -1
  173. package/labs/navigationtab/harness.js.map +1 -1
  174. package/labs/navigationtab/internal/navigation-tab.d.ts +6 -0
  175. package/labs/navigationtab/internal/navigation-tab.js +43 -27
  176. package/labs/navigationtab/internal/navigation-tab.js.map +1 -1
  177. package/labs/navigationtab/internal/state.js.map +1 -1
  178. package/labs/segmentedbutton/internal/segmented-button.d.ts +3 -0
  179. package/labs/segmentedbutton/internal/segmented-button.js +26 -12
  180. package/labs/segmentedbutton/internal/segmented-button.js.map +1 -1
  181. package/labs/segmentedbuttonset/internal/segmented-button-set.d.ts +5 -0
  182. package/labs/segmentedbuttonset/internal/segmented-button-set.js +14 -9
  183. package/labs/segmentedbuttonset/internal/segmented-button-set.js.map +1 -1
  184. package/list/harness.d.ts +1 -1
  185. package/list/harness.js.map +1 -1
  186. package/list/internal/list-controller.d.ts +1 -1
  187. package/list/internal/list-controller.js +7 -3
  188. package/list/internal/list-controller.js.map +1 -1
  189. package/list/internal/list-navigation-helpers.js.map +1 -1
  190. package/list/internal/list.d.ts +2 -2
  191. package/list/internal/list.js +8 -6
  192. package/list/internal/list.js.map +1 -1
  193. package/list/internal/listitem/harness.d.ts +1 -1
  194. package/list/internal/listitem/harness.js.map +1 -1
  195. package/list/internal/listitem/list-item.d.ts +3 -2
  196. package/list/internal/listitem/list-item.js +19 -20
  197. package/list/internal/listitem/list-item.js.map +1 -1
  198. package/list/list-item.d.ts +4 -12
  199. package/list/list-item.js +4 -12
  200. package/list/list-item.js.map +1 -1
  201. package/menu/harness.js.map +1 -1
  202. package/menu/internal/_menu.scss +12 -1
  203. package/menu/internal/controllers/menuItemController.js +9 -4
  204. package/menu/internal/controllers/menuItemController.js.map +1 -1
  205. package/menu/internal/controllers/shared.d.ts +9 -1
  206. package/menu/internal/controllers/shared.js +4 -4
  207. package/menu/internal/controllers/shared.js.map +1 -1
  208. package/menu/internal/controllers/surfacePositionController.d.ts +15 -2
  209. package/menu/internal/controllers/surfacePositionController.js +124 -54
  210. package/menu/internal/controllers/surfacePositionController.js.map +1 -1
  211. package/menu/internal/controllers/typeaheadController.js +19 -14
  212. package/menu/internal/controllers/typeaheadController.js.map +1 -1
  213. package/menu/internal/menu-styles.css.js +1 -1
  214. package/menu/internal/menu-styles.css.js.map +1 -1
  215. package/menu/internal/menu.d.ts +43 -12
  216. package/menu/internal/menu.js +124 -57
  217. package/menu/internal/menu.js.map +1 -1
  218. package/menu/internal/menuitem/harness.js.map +1 -1
  219. package/menu/internal/menuitem/menu-item.d.ts +3 -2
  220. package/menu/internal/menuitem/menu-item.js +18 -19
  221. package/menu/internal/menuitem/menu-item.js.map +1 -1
  222. package/menu/internal/submenu/sub-menu.d.ts +8 -8
  223. package/menu/internal/submenu/sub-menu.js +31 -22
  224. package/menu/internal/submenu/sub-menu.js.map +1 -1
  225. package/menu/internal/types.js.map +1 -1
  226. package/package.json +1 -1
  227. package/progress/internal/_circular-progress.scss +2 -2
  228. package/progress/internal/_linear-progress.scss +1 -1
  229. package/progress/internal/circular-progress-styles.css.js +1 -1
  230. package/progress/internal/circular-progress-styles.css.js.map +1 -1
  231. package/progress/internal/circular-progress.js +11 -10
  232. package/progress/internal/circular-progress.js.map +1 -1
  233. package/progress/internal/linear-progress-styles.css.js +1 -1
  234. package/progress/internal/linear-progress-styles.css.js.map +1 -1
  235. package/progress/internal/linear-progress.d.ts +1 -1
  236. package/progress/internal/linear-progress.js +3 -3
  237. package/progress/internal/linear-progress.js.map +1 -1
  238. package/progress/internal/progress.js +4 -2
  239. package/progress/internal/progress.js.map +1 -1
  240. package/radio/internal/radio.d.ts +11 -27
  241. package/radio/internal/radio.js +30 -54
  242. package/radio/internal/radio.js.map +1 -1
  243. package/radio/internal/single-selection-controller.js +1 -1
  244. package/radio/internal/single-selection-controller.js.map +1 -1
  245. package/ripple/internal/ripple.js +14 -9
  246. package/ripple/internal/ripple.js.map +1 -1
  247. package/select/filled-select.js +1 -2
  248. package/select/filled-select.js.map +1 -1
  249. package/select/harness.js +1 -1
  250. package/select/harness.js.map +1 -1
  251. package/select/internal/select.d.ts +25 -34
  252. package/select/internal/select.js +101 -91
  253. package/select/internal/select.js.map +1 -1
  254. package/select/internal/selectoption/select-option.d.ts +8 -6
  255. package/select/internal/selectoption/select-option.js +23 -22
  256. package/select/internal/selectoption/select-option.js.map +1 -1
  257. package/select/internal/selectoption/selectOptionController.js +1 -1
  258. package/select/internal/selectoption/selectOptionController.js.map +1 -1
  259. package/select/outlined-select.js +1 -2
  260. package/select/outlined-select.js.map +1 -1
  261. package/slider/harness.js +5 -5
  262. package/slider/harness.js.map +1 -1
  263. package/slider/internal/slider.d.ts +16 -25
  264. package/slider/internal/slider.js +110 -114
  265. package/slider/internal/slider.js.map +1 -1
  266. package/switch/internal/switch.d.ts +11 -27
  267. package/switch/internal/switch.js +40 -80
  268. package/switch/internal/switch.js.map +1 -1
  269. package/tabs/harness.js +3 -3
  270. package/tabs/harness.js.map +1 -1
  271. package/tabs/internal/_tab.scss +27 -35
  272. package/tabs/internal/primary-tab.d.ts +0 -2
  273. package/tabs/internal/tab-styles.css.js +1 -1
  274. package/tabs/internal/tab-styles.css.js.map +1 -1
  275. package/tabs/internal/tab.d.ts +4 -5
  276. package/tabs/internal/tab.js +34 -22
  277. package/tabs/internal/tab.js.map +1 -1
  278. package/tabs/internal/tabs.d.ts +6 -2
  279. package/tabs/internal/tabs.js +18 -11
  280. package/tabs/internal/tabs.js.map +1 -1
  281. package/textfield/filled-text-field.js +1 -2
  282. package/textfield/filled-text-field.js.map +1 -1
  283. package/textfield/harness.js +3 -2
  284. package/textfield/harness.js.map +1 -1
  285. package/textfield/internal/text-field.d.ts +26 -18
  286. package/textfield/internal/text-field.js +81 -58
  287. package/textfield/internal/text-field.js.map +1 -1
  288. package/textfield/outlined-text-field.js +1 -2
  289. package/textfield/outlined-text-field.js.map +1 -1
  290. package/tokens/_index.scss +3 -0
  291. package/tokens/_md-comp-elevated-card.scss +63 -0
  292. package/tokens/_md-comp-filled-card.scss +63 -0
  293. package/tokens/_md-comp-icon.scss +2 -0
  294. package/tokens/_md-comp-outlined-card.scss +69 -0
  295. package/tokens/_md-comp-test-table.scss +1 -0
  296. package/internal/controller/element-internals.d.ts +0 -35
  297. package/internal/controller/element-internals.js +0 -24
  298. package/internal/controller/element-internals.js.map +0 -1
  299. package/select/internal/filled-forced-colors-styles.css.js +0 -9
  300. package/select/internal/filled-forced-colors-styles.css.js.map +0 -1
  301. package/select/internal/filled-forced-colors-styles.scss +0 -29
  302. package/select/internal/outlined-forced-colors-styles.css.js +0 -9
  303. package/select/internal/outlined-forced-colors-styles.css.js.map +0 -1
  304. package/select/internal/outlined-forced-colors-styles.scss +0 -29
  305. package/textfield/internal/filled-forced-colors-styles.css.js +0 -9
  306. package/textfield/internal/filled-forced-colors-styles.css.js.map +0 -1
  307. package/textfield/internal/filled-forced-colors-styles.scss +0 -29
  308. package/textfield/internal/outlined-forced-colors-styles.css.js +0 -9
  309. package/textfield/internal/outlined-forced-colors-styles.css.js.map +0 -1
  310. package/textfield/internal/outlined-forced-colors-styles.scss +0 -29
  311. /package/{select/internal/filled-forced-colors-styles.css.d.ts → labs/card/internal/elevated-styles.css.d.ts} +0 -0
  312. /package/{select/internal/outlined-forced-colors-styles.css.d.ts → labs/card/internal/filled-styles.css.d.ts} +0 -0
  313. /package/{textfield/internal/filled-forced-colors-styles.css.d.ts → labs/card/internal/outlined-styles.css.d.ts} +0 -0
  314. /package/{textfield/internal/outlined-forced-colors-styles.css.d.ts → labs/card/internal/shared-styles.css.d.ts} +0 -0
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { LitElement } from 'lit';
7
+ import { WithElementInternals } from './element-internals.js';
8
+ import { MixinBase, MixinReturn } from './mixin.js';
9
+ /**
10
+ * A form-associated element.
11
+ *
12
+ * IMPORTANT: Requires declares for lit-analyzer
13
+ * @example
14
+ * ```ts
15
+ * const base = mixinFormAssociated(mixinElementInternals(LitElement));
16
+ * class MyControl extends base {
17
+ * // Writable mixin properties for lit-html binding, needed for lit-analyzer
18
+ * declare disabled: boolean;
19
+ * declare name: string;
20
+ * }
21
+ * ```
22
+ */
23
+ export interface FormAssociated {
24
+ /**
25
+ * The associated form element with which this element's value will submit.
26
+ */
27
+ readonly form: HTMLFormElement | null;
28
+ /**
29
+ * The labels this element is associated with.
30
+ */
31
+ readonly labels: NodeList;
32
+ /**
33
+ * The HTML name to use in form submission.
34
+ */
35
+ name: string;
36
+ /**
37
+ * Whether or not the element is disabled.
38
+ */
39
+ disabled: boolean;
40
+ /**
41
+ * Gets the current form value of a component.
42
+ *
43
+ * @return The current form value.
44
+ */
45
+ [getFormValue](): FormValue | null;
46
+ /**
47
+ * Gets the current form state of a component. Defaults to the component's
48
+ * `[formValue]`.
49
+ *
50
+ * Use this when the state of an element is different from its value, such as
51
+ * checkboxes (internal boolean state and a user string value).
52
+ *
53
+ * @return The current form state, defaults to the form value.
54
+ */
55
+ [getFormState](): FormValue | null;
56
+ /**
57
+ * A callback for when a form component should be disabled or enabled. This
58
+ * can be called in a variety of situations, such as disabled `<fieldset>`s.
59
+ *
60
+ * @param disabled Whether or not the form control should be disabled.
61
+ */
62
+ formDisabledCallback(disabled: boolean): void;
63
+ /**
64
+ * A callback for when the form requests to reset its value. Typically, the
65
+ * default value that is reset is represented in the attribute of an element.
66
+ *
67
+ * This means the attribute used for the value should not update as the value
68
+ * changes. For example, a checkbox should not change its default `checked`
69
+ * attribute when selected. Ensure form values do not reflect.
70
+ */
71
+ formResetCallback(): void;
72
+ /**
73
+ * A callback for when the form restores the state of a component. For
74
+ * example, when a page is reloaded or forms are autofilled.
75
+ *
76
+ * @param state The state to restore, or null to reset the form control's
77
+ * value.
78
+ * @param reason The reason state was restored, either `'restore'` or
79
+ * `'autocomplete'`.
80
+ */
81
+ formStateRestoreCallback(state: FormRestoreState | null, reason: FormRestoreReason): void;
82
+ /**
83
+ * An optional callback for when the associated form changes.
84
+ *
85
+ * @param form The new associated form, or `null` if there is none.
86
+ */
87
+ formAssociatedCallback?(form: HTMLFormElement | null): void;
88
+ }
89
+ /**
90
+ * The constructor of a `FormAssociated` element.
91
+ */
92
+ export interface FormAssociatedConstructor {
93
+ /**
94
+ * Indicates that an element is participating in form association.
95
+ */
96
+ readonly formAssociated: true;
97
+ }
98
+ /**
99
+ * A symbol property to retrieve the form value for an element.
100
+ */
101
+ export declare const getFormValue: unique symbol;
102
+ /**
103
+ * A symbol property to retrieve the form state for an element.
104
+ */
105
+ export declare const getFormState: unique symbol;
106
+ /**
107
+ * Mixes in form-associated behavior for a class. This allows an element to add
108
+ * values to `<form>` elements.
109
+ *
110
+ * Implementing classes should provide a `[formValue]` to return the current
111
+ * value of the element, as well as reset and restore callbacks.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * const base = mixinFormAssociated(mixinElementInternals(LitElement));
116
+ *
117
+ * class MyControl extends base {
118
+ * \@property()
119
+ * value = '';
120
+ *
121
+ * override [getFormValue]() {
122
+ * return this.value;
123
+ * }
124
+ *
125
+ * override formResetCallback() {
126
+ * const defaultValue = this.getAttribute('value');
127
+ * this.value = defaultValue;
128
+ * }
129
+ *
130
+ * override formStateRestoreCallback(state: string) {
131
+ * this.value = state;
132
+ * }
133
+ * }
134
+ * ```
135
+ *
136
+ * Elements may optionally provide a `[formState]` if their values do not
137
+ * represent the state of the component.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * const base = mixinFormAssociated(mixinElementInternals(LitElement));
142
+ *
143
+ * class MyCheckbox extends base {
144
+ * \@property()
145
+ * value = 'on';
146
+ *
147
+ * \@property({type: Boolean})
148
+ * checked = false;
149
+ *
150
+ * override [getFormValue]() {
151
+ * return this.checked ? this.value : null;
152
+ * }
153
+ *
154
+ * override [getFormState]() {
155
+ * return String(this.checked);
156
+ * }
157
+ *
158
+ * override formResetCallback() {
159
+ * const defaultValue = this.hasAttribute('checked');
160
+ * this.checked = defaultValue;
161
+ * }
162
+ *
163
+ * override formStateRestoreCallback(state: string) {
164
+ * this.checked = Boolean(state);
165
+ * }
166
+ * }
167
+ * ```
168
+ *
169
+ * IMPORTANT: Requires declares for lit-analyzer
170
+ * @example
171
+ * ```ts
172
+ * const base = mixinFormAssociated(mixinElementInternals(LitElement));
173
+ * class MyControl extends base {
174
+ * // Writable mixin properties for lit-html binding, needed for lit-analyzer
175
+ * declare disabled: boolean;
176
+ * declare name: string;
177
+ * }
178
+ * ```
179
+ *
180
+ * @param base The class to mix functionality into. The base class must use
181
+ * `mixinElementInternals()`.
182
+ * @return The provided class with `FormAssociated` mixed in.
183
+ */
184
+ export declare function mixinFormAssociated<T extends MixinBase<LitElement & WithElementInternals>>(base: T): MixinReturn<T & FormAssociatedConstructor, FormAssociated>;
185
+ /**
186
+ * A value that can be provided for form submission and state.
187
+ */
188
+ export type FormValue = File | string | FormData;
189
+ /**
190
+ * A value to be restored for a component's form value. If a component's form
191
+ * state is a `FormData` object, its entry list of name and values will be
192
+ * provided.
193
+ */
194
+ export type FormRestoreState = File | string | Array<[string, FormDataEntryValue]>;
195
+ /**
196
+ * The reason a form component is being restored for, either `'restore'` for
197
+ * browser restoration or `'autocomplete'` for restoring user values.
198
+ */
199
+ export type FormRestoreReason = 'restore' | 'autocomplete';
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { __decorate } from "tslib";
7
+ import { property } from 'lit/decorators.js';
8
+ import { internals } from './element-internals.js';
9
+ /**
10
+ * A symbol property to retrieve the form value for an element.
11
+ */
12
+ export const getFormValue = Symbol('getFormValue');
13
+ /**
14
+ * A symbol property to retrieve the form state for an element.
15
+ */
16
+ export const getFormState = Symbol('getFormState');
17
+ /**
18
+ * Mixes in form-associated behavior for a class. This allows an element to add
19
+ * values to `<form>` elements.
20
+ *
21
+ * Implementing classes should provide a `[formValue]` to return the current
22
+ * value of the element, as well as reset and restore callbacks.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const base = mixinFormAssociated(mixinElementInternals(LitElement));
27
+ *
28
+ * class MyControl extends base {
29
+ * \@property()
30
+ * value = '';
31
+ *
32
+ * override [getFormValue]() {
33
+ * return this.value;
34
+ * }
35
+ *
36
+ * override formResetCallback() {
37
+ * const defaultValue = this.getAttribute('value');
38
+ * this.value = defaultValue;
39
+ * }
40
+ *
41
+ * override formStateRestoreCallback(state: string) {
42
+ * this.value = state;
43
+ * }
44
+ * }
45
+ * ```
46
+ *
47
+ * Elements may optionally provide a `[formState]` if their values do not
48
+ * represent the state of the component.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const base = mixinFormAssociated(mixinElementInternals(LitElement));
53
+ *
54
+ * class MyCheckbox extends base {
55
+ * \@property()
56
+ * value = 'on';
57
+ *
58
+ * \@property({type: Boolean})
59
+ * checked = false;
60
+ *
61
+ * override [getFormValue]() {
62
+ * return this.checked ? this.value : null;
63
+ * }
64
+ *
65
+ * override [getFormState]() {
66
+ * return String(this.checked);
67
+ * }
68
+ *
69
+ * override formResetCallback() {
70
+ * const defaultValue = this.hasAttribute('checked');
71
+ * this.checked = defaultValue;
72
+ * }
73
+ *
74
+ * override formStateRestoreCallback(state: string) {
75
+ * this.checked = Boolean(state);
76
+ * }
77
+ * }
78
+ * ```
79
+ *
80
+ * IMPORTANT: Requires declares for lit-analyzer
81
+ * @example
82
+ * ```ts
83
+ * const base = mixinFormAssociated(mixinElementInternals(LitElement));
84
+ * class MyControl extends base {
85
+ * // Writable mixin properties for lit-html binding, needed for lit-analyzer
86
+ * declare disabled: boolean;
87
+ * declare name: string;
88
+ * }
89
+ * ```
90
+ *
91
+ * @param base The class to mix functionality into. The base class must use
92
+ * `mixinElementInternals()`.
93
+ * @return The provided class with `FormAssociated` mixed in.
94
+ */
95
+ export function mixinFormAssociated(base) {
96
+ class FormAssociatedElement extends base {
97
+ get form() {
98
+ return this[internals].form;
99
+ }
100
+ get labels() {
101
+ return this[internals].labels;
102
+ }
103
+ // name attribute must be set synchronously
104
+ get name() {
105
+ return this.getAttribute('name') ?? '';
106
+ }
107
+ set name(name) {
108
+ const prev = this.name;
109
+ // Setting name to null or empty string does not remove the attribute.
110
+ this.setAttribute('name', name);
111
+ // Explicit requestUpdate needed for Lit 2.0
112
+ this.requestUpdate('name', prev);
113
+ }
114
+ // disabled attribute must be set synchronously
115
+ get disabled() {
116
+ return this.hasAttribute('disabled');
117
+ }
118
+ set disabled(disabled) {
119
+ const prev = this.disabled;
120
+ this.toggleAttribute('disabled', disabled);
121
+ // Explicit requestUpdate needed for Lit 2.0
122
+ this.requestUpdate('disabled', prev);
123
+ }
124
+ requestUpdate(name, oldValue, options) {
125
+ super.requestUpdate(name, oldValue, options);
126
+ // If any properties change, update the form value, which may have changed
127
+ // as well.
128
+ // Update the form value synchronously in `requestUpdate()` rather than
129
+ // `update()` or `updated()`, which are async. This is necessary to ensure
130
+ // that form data is updated in time for synchronous event listeners.
131
+ this[internals].setFormValue(this[getFormValue](), this[getFormState]());
132
+ }
133
+ [getFormValue]() {
134
+ // Closure does not allow abstract symbol members, so a default
135
+ // implementation is needed.
136
+ throw new Error('Implement [getFormValue]');
137
+ }
138
+ [getFormState]() {
139
+ return this[getFormValue]();
140
+ }
141
+ formDisabledCallback(disabled) {
142
+ this.disabled = disabled;
143
+ }
144
+ }
145
+ /** @nocollapse */
146
+ FormAssociatedElement.formAssociated = true;
147
+ __decorate([
148
+ property({ reflect: true })
149
+ ], FormAssociatedElement.prototype, "name", null);
150
+ __decorate([
151
+ property({ type: Boolean, reflect: true })
152
+ ], FormAssociatedElement.prototype, "disabled", null);
153
+ return FormAssociatedElement;
154
+ }
155
+ //# sourceMappingURL=form-associated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-associated.js","sourceRoot":"","sources":["form-associated.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;AAGH,OAAO,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAC,SAAS,EAAuB,MAAM,wBAAwB,CAAC;AA0GvE;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AAEnD;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6EG;AACH,MAAM,UAAU,mBAAmB,CAEjC,IAAO;IACP,MAAe,qBAAsB,SAAQ,IAAI;QAI/C,IAAI,IAAI;YACN,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;QAC9B,CAAC;QAED,IAAI,MAAM;YACR,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;QAChC,CAAC;QAED,2CAA2C;QAE3C,IAAI,IAAI;YACN,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACzC,CAAC;QACD,IAAI,IAAI,CAAC,IAAY;YACnB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACvB,sEAAsE;YACtE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAChC,4CAA4C;YAC5C,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC;QAED,+CAA+C;QAE/C,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,QAAQ,CAAC,QAAiB;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC3B,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC3C,4CAA4C;YAC5C,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC;QAEQ,aAAa,CACpB,IAAkB,EAClB,QAAkB,EAClB,OAA6B;YAE7B,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC7C,0EAA0E;YAC1E,WAAW;YACX,uEAAuE;YACvE,0EAA0E;YAC1E,qEAAqE;YACrE,IAAI,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,CAAC,YAAY,CAAC;YACZ,+DAA+D;YAC/D,4BAA4B;YAC5B,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QAED,CAAC,YAAY,CAAC;YACZ,OAAO,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,CAAC;QAED,oBAAoB,CAAC,QAAiB;YACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC3B,CAAC;;IA9DD,kBAAkB;IACF,oCAAc,GAAG,IAAI,CAAC;IAYtC;QADC,QAAQ,CAAC,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC;qDAGzB;IAWD;QADC,QAAQ,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC;yDAGxC;IA4CH,OAAO,qBAAqB,CAAC;AAC/B,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {LitElement, PropertyDeclaration} from 'lit';\nimport {property} from 'lit/decorators.js';\n\nimport {internals, WithElementInternals} from './element-internals.js';\nimport {MixinBase, MixinReturn} from './mixin.js';\n\n/**\n * A form-associated element.\n *\n * IMPORTANT: Requires declares for lit-analyzer\n * @example\n * ```ts\n * const base = mixinFormAssociated(mixinElementInternals(LitElement));\n * class MyControl extends base {\n * // Writable mixin properties for lit-html binding, needed for lit-analyzer\n * declare disabled: boolean;\n * declare name: string;\n * }\n * ```\n */\nexport interface FormAssociated {\n /**\n * The associated form element with which this element's value will submit.\n */\n readonly form: HTMLFormElement | null;\n\n /**\n * The labels this element is associated with.\n */\n readonly labels: NodeList;\n\n /**\n * The HTML name to use in form submission.\n */\n name: string;\n\n /**\n * Whether or not the element is disabled.\n */\n disabled: boolean;\n\n /**\n * Gets the current form value of a component.\n *\n * @return The current form value.\n */\n [getFormValue](): FormValue | null;\n\n /**\n * Gets the current form state of a component. Defaults to the component's\n * `[formValue]`.\n *\n * Use this when the state of an element is different from its value, such as\n * checkboxes (internal boolean state and a user string value).\n *\n * @return The current form state, defaults to the form value.\n */\n [getFormState](): FormValue | null;\n\n /**\n * A callback for when a form component should be disabled or enabled. This\n * can be called in a variety of situations, such as disabled `<fieldset>`s.\n *\n * @param disabled Whether or not the form control should be disabled.\n */\n formDisabledCallback(disabled: boolean): void;\n\n /**\n * A callback for when the form requests to reset its value. Typically, the\n * default value that is reset is represented in the attribute of an element.\n *\n * This means the attribute used for the value should not update as the value\n * changes. For example, a checkbox should not change its default `checked`\n * attribute when selected. Ensure form values do not reflect.\n */\n formResetCallback(): void;\n\n /**\n * A callback for when the form restores the state of a component. For\n * example, when a page is reloaded or forms are autofilled.\n *\n * @param state The state to restore, or null to reset the form control's\n * value.\n * @param reason The reason state was restored, either `'restore'` or\n * `'autocomplete'`.\n */\n formStateRestoreCallback(\n state: FormRestoreState | null,\n reason: FormRestoreReason,\n ): void;\n\n /**\n * An optional callback for when the associated form changes.\n *\n * @param form The new associated form, or `null` if there is none.\n */\n formAssociatedCallback?(form: HTMLFormElement | null): void;\n}\n\n/**\n * The constructor of a `FormAssociated` element.\n */\nexport interface FormAssociatedConstructor {\n /**\n * Indicates that an element is participating in form association.\n */\n readonly formAssociated: true;\n}\n\n/**\n * A symbol property to retrieve the form value for an element.\n */\nexport const getFormValue = Symbol('getFormValue');\n\n/**\n * A symbol property to retrieve the form state for an element.\n */\nexport const getFormState = Symbol('getFormState');\n\n/**\n * Mixes in form-associated behavior for a class. This allows an element to add\n * values to `<form>` elements.\n *\n * Implementing classes should provide a `[formValue]` to return the current\n * value of the element, as well as reset and restore callbacks.\n *\n * @example\n * ```ts\n * const base = mixinFormAssociated(mixinElementInternals(LitElement));\n *\n * class MyControl extends base {\n * \\@property()\n * value = '';\n *\n * override [getFormValue]() {\n * return this.value;\n * }\n *\n * override formResetCallback() {\n * const defaultValue = this.getAttribute('value');\n * this.value = defaultValue;\n * }\n *\n * override formStateRestoreCallback(state: string) {\n * this.value = state;\n * }\n * }\n * ```\n *\n * Elements may optionally provide a `[formState]` if their values do not\n * represent the state of the component.\n *\n * @example\n * ```ts\n * const base = mixinFormAssociated(mixinElementInternals(LitElement));\n *\n * class MyCheckbox extends base {\n * \\@property()\n * value = 'on';\n *\n * \\@property({type: Boolean})\n * checked = false;\n *\n * override [getFormValue]() {\n * return this.checked ? this.value : null;\n * }\n *\n * override [getFormState]() {\n * return String(this.checked);\n * }\n *\n * override formResetCallback() {\n * const defaultValue = this.hasAttribute('checked');\n * this.checked = defaultValue;\n * }\n *\n * override formStateRestoreCallback(state: string) {\n * this.checked = Boolean(state);\n * }\n * }\n * ```\n *\n * IMPORTANT: Requires declares for lit-analyzer\n * @example\n * ```ts\n * const base = mixinFormAssociated(mixinElementInternals(LitElement));\n * class MyControl extends base {\n * // Writable mixin properties for lit-html binding, needed for lit-analyzer\n * declare disabled: boolean;\n * declare name: string;\n * }\n * ```\n *\n * @param base The class to mix functionality into. The base class must use\n * `mixinElementInternals()`.\n * @return The provided class with `FormAssociated` mixed in.\n */\nexport function mixinFormAssociated<\n T extends MixinBase<LitElement & WithElementInternals>,\n>(base: T): MixinReturn<T & FormAssociatedConstructor, FormAssociated> {\n abstract class FormAssociatedElement extends base implements FormAssociated {\n /** @nocollapse */\n static readonly formAssociated = true;\n\n get form() {\n return this[internals].form;\n }\n\n get labels() {\n return this[internals].labels;\n }\n\n // name attribute must be set synchronously\n @property({reflect: true})\n get name() {\n return this.getAttribute('name') ?? '';\n }\n set name(name: string) {\n const prev = this.name;\n // Setting name to null or empty string does not remove the attribute.\n this.setAttribute('name', name);\n // Explicit requestUpdate needed for Lit 2.0\n this.requestUpdate('name', prev);\n }\n\n // disabled attribute must be set synchronously\n @property({type: Boolean, reflect: true})\n get disabled() {\n return this.hasAttribute('disabled');\n }\n set disabled(disabled: boolean) {\n const prev = this.disabled;\n this.toggleAttribute('disabled', disabled);\n // Explicit requestUpdate needed for Lit 2.0\n this.requestUpdate('disabled', prev);\n }\n\n override requestUpdate(\n name?: PropertyKey,\n oldValue?: unknown,\n options?: PropertyDeclaration,\n ) {\n super.requestUpdate(name, oldValue, options);\n // If any properties change, update the form value, which may have changed\n // as well.\n // Update the form value synchronously in `requestUpdate()` rather than\n // `update()` or `updated()`, which are async. This is necessary to ensure\n // that form data is updated in time for synchronous event listeners.\n this[internals].setFormValue(this[getFormValue](), this[getFormState]());\n }\n\n [getFormValue](): FormValue | null {\n // Closure does not allow abstract symbol members, so a default\n // implementation is needed.\n throw new Error('Implement [getFormValue]');\n }\n\n [getFormState](): FormValue | null {\n return this[getFormValue]();\n }\n\n formDisabledCallback(disabled: boolean) {\n this.disabled = disabled;\n }\n\n abstract formResetCallback(): void;\n\n abstract formStateRestoreCallback(\n state: FormRestoreState | null,\n reason: FormRestoreReason,\n ): void;\n }\n\n return FormAssociatedElement;\n}\n\n/**\n * A value that can be provided for form submission and state.\n */\nexport type FormValue = File | string | FormData;\n\n/**\n * A value to be restored for a component's form value. If a component's form\n * state is a `FormData` object, its entry list of name and values will be\n * provided.\n */\nexport type FormRestoreState =\n | File\n | string\n | Array<[string, FormDataEntryValue]>;\n\n/**\n * The reason a form component is being restored for, either `'restore'` for\n * browser restoration or `'autocomplete'` for restoring user values.\n */\nexport type FormRestoreReason = 'restore' | 'autocomplete';\n"]}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * The base class for a mixin with an optional expected base class type.
8
+ *
9
+ * @template ExpectedBase Optional expected base class type, such as
10
+ * `LitElement`.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * interface Foo {
15
+ * isFoo: boolean;
16
+ * }
17
+ *
18
+ * function mixinFoo<T extends MixinBase>(base: T): MixinReturn<T, Foo> {
19
+ * // Mixins must be `abstract`
20
+ * abstract class FooImpl extends base implements Foo {
21
+ * isFoo = true;
22
+ * }
23
+ *
24
+ * return FooImpl;
25
+ * }
26
+ * ```
27
+ */
28
+ export type MixinBase<ExpectedBase = object> = abstract new (...args: any[]) => ExpectedBase;
29
+ /**
30
+ * The return value of a mixin.
31
+ *
32
+ * @template MixinBase The generic that extends `MixinBase` used for the mixin's
33
+ * base class argument.
34
+ * @template MixinClass Optional interface of fuctionality that was mixed in.
35
+ * Omit if no additional APIs were added (such as purely overriding base
36
+ * class functionality).
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * interface Foo {
41
+ * isFoo: boolean;
42
+ * }
43
+ *
44
+ * // Mixins must be `abstract`
45
+ * function mixinFoo<T extends MixinBase>(base: T): MixinReturn<T, Foo> {
46
+ * abstract class FooImpl extends base implements Foo {
47
+ * isFoo = true;
48
+ * }
49
+ *
50
+ * return FooImpl;
51
+ * }
52
+ * ```
53
+ */
54
+ export type MixinReturn<MixinBase, MixinClass = object> = (abstract new (...args: any[]) => MixinClass) & MixinBase;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=mixin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixin.js","sourceRoot":"","sources":["mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * The base class for a mixin with an optional expected base class type.\n *\n * @template ExpectedBase Optional expected base class type, such as\n * `LitElement`.\n *\n * @example\n * ```ts\n * interface Foo {\n * isFoo: boolean;\n * }\n *\n * function mixinFoo<T extends MixinBase>(base: T): MixinReturn<T, Foo> {\n * // Mixins must be `abstract`\n * abstract class FooImpl extends base implements Foo {\n * isFoo = true;\n * }\n *\n * return FooImpl;\n * }\n * ```\n */\nexport type MixinBase<ExpectedBase = object> = abstract new (\n // Mixins must have a constructor with `...args: any[]`\n // tslint:disable-next-line:no-any\n ...args: any[]\n) => ExpectedBase;\n\n/**\n * The return value of a mixin.\n *\n * @template MixinBase The generic that extends `MixinBase` used for the mixin's\n * base class argument.\n * @template MixinClass Optional interface of fuctionality that was mixed in.\n * Omit if no additional APIs were added (such as purely overriding base\n * class functionality).\n *\n * @example\n * ```ts\n * interface Foo {\n * isFoo: boolean;\n * }\n *\n * // Mixins must be `abstract`\n * function mixinFoo<T extends MixinBase>(base: T): MixinReturn<T, Foo> {\n * abstract class FooImpl extends base implements Foo {\n * isFoo = true;\n * }\n *\n * return FooImpl;\n * }\n * ```\n */\nexport type MixinReturn<MixinBase, MixinClass = object> =\n // Mixins must have a constructor with `...args: any[]`\n // tslint:disable-next-line:no-any\n (abstract new (...args: any[]) => MixinClass) & MixinBase;\n"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Validator } from './validator.js';
7
+ /**
8
+ * Constraint validation properties for a checkbox.
9
+ */
10
+ export interface CheckboxState {
11
+ /**
12
+ * Whether the checkbox is checked.
13
+ */
14
+ checked: boolean;
15
+ /**
16
+ * Whether the checkbox is required.
17
+ */
18
+ required: boolean;
19
+ }
20
+ /**
21
+ * A validator that provides constraint validation that emulates
22
+ * `<input type="checkbox">` validation.
23
+ */
24
+ export declare class CheckboxValidator extends Validator<CheckboxState> {
25
+ private checkboxControl?;
26
+ protected computeValidity(state: CheckboxState): {
27
+ validity: ValidityState;
28
+ validationMessage: string;
29
+ };
30
+ protected equals(prev: CheckboxState, next: CheckboxState): boolean;
31
+ protected copy({ checked, required }: CheckboxState): CheckboxState;
32
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Validator } from './validator.js';
7
+ /**
8
+ * A validator that provides constraint validation that emulates
9
+ * `<input type="checkbox">` validation.
10
+ */
11
+ export class CheckboxValidator extends Validator {
12
+ computeValidity(state) {
13
+ if (!this.checkboxControl) {
14
+ // Lazily create the platform input
15
+ this.checkboxControl = document.createElement('input');
16
+ this.checkboxControl.type = 'checkbox';
17
+ }
18
+ this.checkboxControl.checked = state.checked;
19
+ this.checkboxControl.required = state.required;
20
+ return {
21
+ validity: this.checkboxControl.validity,
22
+ validationMessage: this.checkboxControl.validationMessage,
23
+ };
24
+ }
25
+ equals(prev, next) {
26
+ return prev.checked === next.checked && prev.required === next.required;
27
+ }
28
+ copy({ checked, required }) {
29
+ return { checked, required };
30
+ }
31
+ }
32
+ //# sourceMappingURL=checkbox-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkbox-validator.js","sourceRoot":"","sources":["checkbox-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAiBzC;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,SAAwB;IAG1C,eAAe,CAAC,KAAoB;QACrD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;YACzB,mCAAmC;YACnC,IAAI,CAAC,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,UAAU,CAAC;SACxC;QAED,IAAI,CAAC,eAAe,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC7C,IAAI,CAAC,eAAe,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/C,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ;YACvC,iBAAiB,EAAE,IAAI,CAAC,eAAe,CAAC,iBAAiB;SAC1D,CAAC;IACJ,CAAC;IAEkB,MAAM,CAAC,IAAmB,EAAE,IAAmB;QAChE,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,CAAC;IAC1E,CAAC;IAEkB,IAAI,CAAC,EAAC,OAAO,EAAE,QAAQ,EAAgB;QACxD,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAC,CAAC;IAC7B,CAAC;CACF","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {Validator} from './validator.js';\n\n/**\n * Constraint validation properties for a checkbox.\n */\nexport interface CheckboxState {\n /**\n * Whether the checkbox is checked.\n */\n checked: boolean;\n\n /**\n * Whether the checkbox is required.\n */\n required: boolean;\n}\n\n/**\n * A validator that provides constraint validation that emulates\n * `<input type=\"checkbox\">` validation.\n */\nexport class CheckboxValidator extends Validator<CheckboxState> {\n private checkboxControl?: HTMLInputElement;\n\n protected override computeValidity(state: CheckboxState) {\n if (!this.checkboxControl) {\n // Lazily create the platform input\n this.checkboxControl = document.createElement('input');\n this.checkboxControl.type = 'checkbox';\n }\n\n this.checkboxControl.checked = state.checked;\n this.checkboxControl.required = state.required;\n return {\n validity: this.checkboxControl.validity,\n validationMessage: this.checkboxControl.validationMessage,\n };\n }\n\n protected override equals(prev: CheckboxState, next: CheckboxState) {\n return prev.checked === next.checked && prev.required === next.required;\n }\n\n protected override copy({checked, required}: CheckboxState): CheckboxState {\n return {checked, required};\n }\n}\n"]}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * A class that computes and caches `ValidityStateFlags` for a component with
8
+ * a given `State` interface.
9
+ *
10
+ * Cached performance before computing validity is important since constraint
11
+ * validation must be checked frequently and synchronously when properties
12
+ * change.
13
+ *
14
+ * @template State The expected interface of properties relevant to constraint
15
+ * validation.
16
+ */
17
+ export declare abstract class Validator<State> {
18
+ private readonly getCurrentState;
19
+ /**
20
+ * The previous state, used to determine if state changed and validation needs
21
+ * to be re-computed.
22
+ */
23
+ private prevState?;
24
+ /**
25
+ * The current validity state and message. This is cached and returns if
26
+ * constraint validation state does not change.
27
+ */
28
+ private currentValidity;
29
+ /**
30
+ * Creates a new validator.
31
+ *
32
+ * @param getCurrentState A callback that returns the current state of
33
+ * constraint validation-related properties.
34
+ */
35
+ constructor(getCurrentState: () => State);
36
+ /**
37
+ * Returns the current `ValidityStateFlags` and validation message for the
38
+ * validator.
39
+ *
40
+ * If the constraint validation state has not changed, this will return a
41
+ * cached result. This is important since `getValidity()` can be called
42
+ * frequently in response to synchronous property changes.
43
+ *
44
+ * @return The current validity and validation message.
45
+ */
46
+ getValidity(): ValidityAndMessage;
47
+ /**
48
+ * Computes the `ValidityStateFlags` and validation message for a given set
49
+ * of constraint validation properties.
50
+ *
51
+ * Implementations can use platform elements like `<input>` and `<select>` to
52
+ * sync state and compute validation along with i18n'd messages. This function
53
+ * may be expensive, and is only called when state changes.
54
+ *
55
+ * @param state The new state of constraint validation properties.
56
+ * @return An object containing a `validity` property with
57
+ * `ValidityStateFlags` and a `validationMessage` property.
58
+ */
59
+ protected abstract computeValidity(state: State): ValidityAndMessage;
60
+ /**
61
+ * Checks if two states are equal. This is used to check against cached state
62
+ * to see if validity needs to be re-computed.
63
+ *
64
+ * @param prev The previous state.
65
+ * @param next The next state.
66
+ * @return True if the states are equal, or false if not.
67
+ */
68
+ protected abstract equals(prev: State, next: State): boolean;
69
+ /**
70
+ * Creates a copy of a state. This is used to cache state and check if it
71
+ * changes.
72
+ *
73
+ * @param state The state to copy.
74
+ * @return A copy of the state.
75
+ */
76
+ protected abstract copy(state: State): State;
77
+ }
78
+ /**
79
+ * An object containing `ValidityStateFlags` and a corresponding validation
80
+ * message.
81
+ */
82
+ export interface ValidityAndMessage {
83
+ /**
84
+ * Validity flags.
85
+ */
86
+ validity: ValidityStateFlags;
87
+ /**
88
+ * The validation message for the associated flags. It may not be an empty
89
+ * string if any of the validity flags are `true`.
90
+ */
91
+ validationMessage: string;
92
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * A class that computes and caches `ValidityStateFlags` for a component with
8
+ * a given `State` interface.
9
+ *
10
+ * Cached performance before computing validity is important since constraint
11
+ * validation must be checked frequently and synchronously when properties
12
+ * change.
13
+ *
14
+ * @template State The expected interface of properties relevant to constraint
15
+ * validation.
16
+ */
17
+ export class Validator {
18
+ /**
19
+ * Creates a new validator.
20
+ *
21
+ * @param getCurrentState A callback that returns the current state of
22
+ * constraint validation-related properties.
23
+ */
24
+ constructor(getCurrentState) {
25
+ this.getCurrentState = getCurrentState;
26
+ /**
27
+ * The current validity state and message. This is cached and returns if
28
+ * constraint validation state does not change.
29
+ */
30
+ this.currentValidity = {
31
+ validity: {},
32
+ validationMessage: '',
33
+ };
34
+ }
35
+ /**
36
+ * Returns the current `ValidityStateFlags` and validation message for the
37
+ * validator.
38
+ *
39
+ * If the constraint validation state has not changed, this will return a
40
+ * cached result. This is important since `getValidity()` can be called
41
+ * frequently in response to synchronous property changes.
42
+ *
43
+ * @return The current validity and validation message.
44
+ */
45
+ getValidity() {
46
+ const state = this.getCurrentState();
47
+ const hasStateChanged = !this.prevState || !this.equals(this.prevState, state);
48
+ if (!hasStateChanged) {
49
+ return this.currentValidity;
50
+ }
51
+ const { validity, validationMessage } = this.computeValidity(state);
52
+ this.prevState = this.copy(state);
53
+ this.currentValidity = {
54
+ validationMessage,
55
+ validity: {
56
+ // Change any `ValidityState` instances into `ValidityStateFlags` since
57
+ // `ValidityState` cannot be easily `{...spread}`.
58
+ badInput: validity.badInput,
59
+ customError: validity.customError,
60
+ patternMismatch: validity.patternMismatch,
61
+ rangeOverflow: validity.rangeOverflow,
62
+ rangeUnderflow: validity.rangeUnderflow,
63
+ stepMismatch: validity.stepMismatch,
64
+ tooLong: validity.tooLong,
65
+ tooShort: validity.tooShort,
66
+ typeMismatch: validity.typeMismatch,
67
+ valueMissing: validity.valueMissing,
68
+ },
69
+ };
70
+ return this.currentValidity;
71
+ }
72
+ }
73
+ //# sourceMappingURL=validator.js.map