@cfpb/cfpb-design-system 4.2.4 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/CHANGELOG.md +186 -1
  2. package/dist/components/cfpb-buttons/index.css +1 -1
  3. package/dist/components/cfpb-buttons/index.css.map +2 -2
  4. package/dist/components/cfpb-buttons/index.js +1 -1
  5. package/dist/components/cfpb-buttons/index.js.map +1 -1
  6. package/dist/components/cfpb-expandables/index.css +1 -1
  7. package/dist/components/cfpb-expandables/index.css.map +2 -2
  8. package/dist/components/cfpb-expandables/index.js +1 -1
  9. package/dist/components/cfpb-expandables/index.js.map +4 -4
  10. package/dist/components/cfpb-forms/index.css +1 -1
  11. package/dist/components/cfpb-forms/index.css.map +2 -2
  12. package/dist/components/cfpb-forms/index.js +1 -1
  13. package/dist/components/cfpb-forms/index.js.map +2 -2
  14. package/dist/components/cfpb-icons/index.css +1 -1
  15. package/dist/components/cfpb-icons/index.css.map +2 -2
  16. package/dist/components/cfpb-icons/index.js +1 -1
  17. package/dist/components/cfpb-icons/index.js.map +1 -1
  18. package/dist/components/cfpb-layout/index.css +1 -1
  19. package/dist/components/cfpb-layout/index.css.map +2 -2
  20. package/dist/components/cfpb-layout/index.js +1 -1
  21. package/dist/components/cfpb-layout/index.js.map +1 -1
  22. package/dist/components/cfpb-notifications/index.css +1 -1
  23. package/dist/components/cfpb-notifications/index.css.map +2 -2
  24. package/dist/components/cfpb-notifications/index.js +1 -1
  25. package/dist/components/cfpb-notifications/index.js.map +1 -1
  26. package/dist/components/cfpb-pagination/index.css +1 -1
  27. package/dist/components/cfpb-pagination/index.css.map +2 -2
  28. package/dist/components/cfpb-pagination/index.js +1 -1
  29. package/dist/components/cfpb-pagination/index.js.map +1 -1
  30. package/dist/components/cfpb-tables/index.css +1 -1
  31. package/dist/components/cfpb-tables/index.css.map +2 -2
  32. package/dist/components/cfpb-tables/index.js +1 -1
  33. package/dist/components/cfpb-tables/index.js.map +1 -1
  34. package/dist/components/cfpb-tooltips/index.css +1 -1
  35. package/dist/components/cfpb-tooltips/index.css.map +2 -2
  36. package/dist/components/cfpb-tooltips/index.js +1 -1
  37. package/dist/components/cfpb-tooltips/index.js.map +1 -1
  38. package/dist/components/cfpb-typography/index.css +1 -1
  39. package/dist/components/cfpb-typography/index.css.map +2 -2
  40. package/dist/components/cfpb-typography/index.js +1 -1
  41. package/dist/components/cfpb-typography/index.js.map +1 -1
  42. package/dist/elements/abstracts/index.js +2 -0
  43. package/dist/elements/abstracts/index.js.map +7 -0
  44. package/dist/elements/base/index.css +3 -0
  45. package/dist/elements/base/index.css.map +7 -0
  46. package/dist/elements/base/index.js +2 -0
  47. package/dist/elements/base/index.js.map +7 -0
  48. package/dist/elements/cfpb-button/index.js +4 -4
  49. package/dist/elements/cfpb-button/index.js.map +3 -3
  50. package/dist/elements/cfpb-checkbox-icon/index.js +29 -0
  51. package/dist/elements/{cfpb-checkbox → cfpb-checkbox-icon}/index.js.map +4 -4
  52. package/dist/elements/cfpb-expandable/index.css +2 -0
  53. package/dist/elements/cfpb-expandable/index.css.map +7 -0
  54. package/dist/elements/cfpb-expandable/index.js +33 -0
  55. package/dist/elements/cfpb-expandable/index.js.map +7 -0
  56. package/dist/elements/cfpb-file-upload/index.js +4 -4
  57. package/dist/elements/cfpb-file-upload/index.js.map +3 -3
  58. package/dist/elements/cfpb-form-alert/index.js +32 -0
  59. package/dist/elements/cfpb-form-alert/index.js.map +7 -0
  60. package/dist/elements/cfpb-form-choice/index.js +12 -3
  61. package/dist/elements/cfpb-form-choice/index.js.map +4 -4
  62. package/dist/elements/cfpb-form-search/index.js +41 -0
  63. package/dist/elements/cfpb-form-search/index.js.map +7 -0
  64. package/dist/elements/cfpb-form-search-input/index.js +41 -0
  65. package/dist/elements/cfpb-form-search-input/index.js.map +7 -0
  66. package/dist/elements/cfpb-icon-text/index.js +3 -3
  67. package/dist/elements/cfpb-icon-text/index.js.map +3 -3
  68. package/dist/elements/cfpb-label/index.js +3 -3
  69. package/dist/elements/cfpb-label/index.js.map +2 -2
  70. package/dist/elements/cfpb-list/index.js +39 -0
  71. package/dist/elements/cfpb-list/index.js.map +7 -0
  72. package/dist/elements/cfpb-list-item/index.js +39 -0
  73. package/dist/elements/cfpb-list-item/index.js.map +7 -0
  74. package/dist/elements/cfpb-multiselect/index.js +13 -4
  75. package/dist/elements/cfpb-multiselect/index.js.map +4 -4
  76. package/dist/elements/cfpb-pagination/index.js +3 -3
  77. package/dist/elements/cfpb-pagination/index.js.map +2 -2
  78. package/dist/elements/cfpb-select/index.css +2 -0
  79. package/dist/elements/cfpb-select/index.css.map +7 -0
  80. package/dist/elements/cfpb-select/index.js +42 -0
  81. package/dist/elements/cfpb-select/index.js.map +7 -0
  82. package/dist/elements/cfpb-select-list/index.js +39 -0
  83. package/dist/elements/cfpb-select-list/index.js.map +7 -0
  84. package/dist/elements/cfpb-tag-filter/index.js +3 -3
  85. package/dist/elements/cfpb-tag-filter/index.js.map +3 -3
  86. package/dist/elements/cfpb-tag-group/index.js +3 -3
  87. package/dist/elements/cfpb-tag-group/index.js.map +4 -4
  88. package/dist/elements/cfpb-tag-topic/index.js +4 -4
  89. package/dist/elements/cfpb-tag-topic/index.js.map +2 -2
  90. package/dist/elements/index.css +2 -0
  91. package/dist/elements/index.css.map +7 -0
  92. package/dist/elements/index.js +7 -6
  93. package/dist/elements/index.js.map +4 -4
  94. package/dist/index.css +1 -1
  95. package/dist/index.css.map +3 -3
  96. package/dist/index.js +7 -6
  97. package/dist/index.js.map +4 -4
  98. package/dist/utilities/index.css +1 -1
  99. package/dist/utilities/index.css.map +2 -2
  100. package/dist/utilities/index.js +1 -1
  101. package/dist/utilities/index.js.map +4 -4
  102. package/package.json +1 -1
  103. package/src/components/cfpb-buttons/button-group.scss +1 -1
  104. package/src/components/cfpb-buttons/button-link.scss +10 -54
  105. package/src/components/cfpb-buttons/button.scss +3 -3
  106. package/src/components/cfpb-buttons/vars.scss +1 -1
  107. package/src/components/cfpb-expandables/expandable-group.scss +1 -1
  108. package/src/components/cfpb-expandables/expandable.js +3 -0
  109. package/src/components/cfpb-expandables/expandable.scss +1 -1
  110. package/src/components/cfpb-expandables/summary.scss +1 -1
  111. package/src/components/cfpb-forms/form-alert.scss +1 -1
  112. package/src/components/cfpb-forms/form-field.scss +6 -6
  113. package/src/components/cfpb-forms/form.scss +1 -1
  114. package/src/components/cfpb-forms/label.scss +2 -2
  115. package/src/components/cfpb-forms/multiselect.js +1 -1
  116. package/src/components/cfpb-forms/multiselect.scss +1 -1
  117. package/src/components/cfpb-forms/range.scss +7 -7
  118. package/src/components/cfpb-forms/search-input.scss +1 -1
  119. package/src/components/cfpb-forms/select.scss +1 -1
  120. package/src/components/cfpb-forms/tag.scss +1 -1
  121. package/src/components/cfpb-forms/text-input.scss +1 -1
  122. package/src/components/cfpb-icons/icon.scss +1 -1
  123. package/src/components/cfpb-layout/card-group.scss +1 -1
  124. package/src/components/cfpb-layout/card.scss +1 -1
  125. package/src/components/cfpb-layout/email-signup.scss +1 -1
  126. package/src/components/cfpb-layout/featured-content-module.scss +1 -1
  127. package/src/components/cfpb-layout/hero.scss +1 -1
  128. package/src/components/cfpb-layout/layout.scss +9 -9
  129. package/src/components/cfpb-layout/well.scss +1 -1
  130. package/src/components/cfpb-notifications/banner.scss +1 -1
  131. package/src/components/cfpb-notifications/notification.scss +1 -1
  132. package/src/components/cfpb-pagination/pagination.scss +1 -1
  133. package/src/components/cfpb-tables/table.scss +1 -1
  134. package/src/components/cfpb-tooltips/tooltip.scss +1 -1
  135. package/src/components/cfpb-typography/date.scss +1 -1
  136. package/src/components/cfpb-typography/list.scss +1 -1
  137. package/src/components/cfpb-typography/meta-header.scss +1 -1
  138. package/src/components/cfpb-typography/mixins.scss +1 -1
  139. package/src/components/cfpb-typography/pull-quote.scss +1 -1
  140. package/src/components/cfpb-typography/slug-header.scss +1 -1
  141. package/src/components/cfpb-typography/tagline.scss +1 -1
  142. package/src/elements/abstracts/custom-props.css +123 -0
  143. package/src/{abstracts → elements/abstracts}/grid-mixins.scss +2 -1
  144. package/src/{abstracts → elements/abstracts}/heading-mixins.scss +1 -0
  145. package/src/{abstracts → elements/abstracts}/index.scss +1 -0
  146. package/src/{abstracts → elements/abstracts}/media-queries.scss +1 -1
  147. package/src/elements/abstracts/sizing-vars.scss +66 -0
  148. package/src/elements/abstracts/vars.css +79 -0
  149. package/src/{base → elements/base}/base.scss +14 -14
  150. package/src/elements/cfpb-button/cfpb-button-group.scss +12 -0
  151. package/src/elements/cfpb-button/cfpb-button-link.scss +103 -0
  152. package/src/elements/cfpb-button/cfpb-button.component.scss +11 -4
  153. package/src/elements/cfpb-button/cfpb-button.scss +218 -0
  154. package/src/elements/cfpb-button/index.js +44 -30
  155. package/src/elements/cfpb-button/vars.css +30 -0
  156. package/src/elements/cfpb-checkbox-icon/cfpb-checkbox-icon.component.scss +88 -0
  157. package/src/elements/cfpb-checkbox-icon/index.js +104 -0
  158. package/src/elements/cfpb-expandable/cfpb-expandable.component.scss +218 -0
  159. package/src/elements/cfpb-expandable/index.js +127 -0
  160. package/src/elements/cfpb-file-upload/cfpb-file-upload.component.scss +2 -2
  161. package/src/elements/cfpb-file-upload/index.js +25 -27
  162. package/src/elements/cfpb-form-alert/cfpb-form-alert.component.scss +36 -0
  163. package/src/elements/cfpb-form-alert/index.js +55 -0
  164. package/src/elements/cfpb-form-choice/cfpb-form-choice.component.scss +42 -81
  165. package/src/elements/cfpb-form-choice/index.js +58 -18
  166. package/src/elements/cfpb-form-search/cfpb-form-search.component.scss +54 -0
  167. package/src/elements/cfpb-form-search/index.js +194 -0
  168. package/src/elements/cfpb-form-search-input/cfpb-form-search-input.component.scss +217 -0
  169. package/src/elements/cfpb-form-search-input/index.js +140 -0
  170. package/src/elements/cfpb-icon-text/cfpb-icon-text.component.scss +33 -39
  171. package/src/elements/cfpb-icon-text/index.js +32 -104
  172. package/src/elements/cfpb-label/cfpb-label.component.scss +2 -2
  173. package/src/elements/cfpb-label/index.js +6 -9
  174. package/src/elements/cfpb-list/cfpb-list.component.scss +34 -0
  175. package/src/elements/cfpb-list/index.js +379 -0
  176. package/src/elements/cfpb-list/index.spec.js +214 -0
  177. package/src/elements/cfpb-list-item/cfpb-list-item.component.scss +69 -0
  178. package/src/elements/cfpb-list-item/index.js +215 -0
  179. package/src/elements/cfpb-pagination/cfpb-pagination.component.scss +2 -7
  180. package/src/elements/cfpb-pagination/index.js +6 -8
  181. package/src/elements/cfpb-select/cfpb-select.component.scss +241 -0
  182. package/src/elements/cfpb-select/index.js +371 -0
  183. package/src/elements/cfpb-select/multiple-select-event-proxy.js +88 -0
  184. package/src/elements/cfpb-select/single-select-event-proxy.js +47 -0
  185. package/src/elements/cfpb-tag-filter/cfpb-tag-filter.component.scss +6 -3
  186. package/src/elements/cfpb-tag-filter/index.js +15 -7
  187. package/src/elements/cfpb-tag-group/cfpb-tag-group.component.scss +2 -2
  188. package/src/elements/cfpb-tag-group/index.js +53 -6
  189. package/src/elements/cfpb-tag-topic/cfpb-tag-topic.component.scss +2 -2
  190. package/src/elements/cfpb-tag-topic/index.js +5 -7
  191. package/src/elements/cfpb-utilities/parse-child-data.js +50 -0
  192. package/src/elements/cfpb-utilities/parse-child-data.spec.js +56 -0
  193. package/src/elements/cfpb-utilities/search-service.js +46 -0
  194. package/src/elements/cfpb-utilities/search-service.spec.js +138 -0
  195. package/src/elements/cfpb-utilities/transition/transition.scss +98 -0
  196. package/src/elements/index.js +7 -1
  197. package/src/index.js +2 -2
  198. package/src/index.scss +14 -2
  199. package/src/tokens/abstracts/custom-props.json +1642 -0
  200. package/src/tokens/abstracts/vars.json +1319 -0
  201. package/src/tokens/cfpb-button/vars.json +436 -0
  202. package/src/utilities/breakpoint-state.js +1 -1
  203. package/src/utilities/transition/max-height-transition.js +74 -0
  204. package/src/utilities/utilities.scss +1 -1
  205. package/dist/elements/cfpb-checkbox/index.js +0 -29
  206. package/src/abstracts/custom-props.scss +0 -175
  207. package/src/abstracts/vars.scss +0 -184
  208. package/src/elements/cfpb-multiselect/cfpb-multiselect.component.scss +0 -225
  209. package/src/elements/cfpb-multiselect/index.js +0 -444
  210. package/src/elements/cfpb-multiselect/multiselect-model.js +0 -288
  211. package/src/elements/cfpb-multiselect/multiselect-model.spec.js +0 -236
  212. /package/src/{abstracts → elements/abstracts}/index.js +0 -0
  213. /package/src/{abstracts → elements/abstracts}/vars-breakpoints.js +0 -0
  214. /package/src/{abstracts → elements/abstracts}/vars-breakpoints.scss +0 -0
  215. /package/src/{base → elements/base}/font.scss +0 -0
  216. /package/src/{base → elements/base}/index.js +0 -0
  217. /package/src/{base → elements/base}/index.scss +0 -0
  218. /package/src/{base → elements/base}/normalize.scss +0 -0
@@ -1,5 +1,5 @@
1
1
  @use 'sass:math';
2
- @use '@cfpb/cfpb-design-system/src/abstracts' as *;
2
+ @use '@cfpb/cfpb-design-system/src/elements/abstracts' as *;
3
3
  @use '@cfpb/cfpb-design-system/src/utilities' as *;
4
4
 
5
5
  :host {
@@ -17,14 +17,7 @@
17
17
  // Private variables.
18
18
  --choice-border-width-addendum: 0;
19
19
 
20
- &--in-list label {
21
- box-sizing: border-box;
22
- padding-top: math.div(5px, $base-font-size-px) + em;
23
- padding-right: 0;
24
- padding-bottom: math.div(5px, $base-font-size-px) + em;
25
- padding-left: math.div(10px, $base-font-size-px) + em;
26
- width: 100%;
27
- }
20
+ width: max-content;
28
21
 
29
22
  .a-label + .a-text-input {
30
23
  margin-top: math.div(5px, $base-font-size-px) + em;
@@ -42,31 +35,6 @@
42
35
 
43
36
  // Wrap long words in narrow form fields to prevent clipping
44
37
  overflow-wrap: anywhere;
45
-
46
- &::before {
47
- display: inline-block;
48
- grid-row-start: 1;
49
- grid-row-end: 3;
50
- border: 1px solid var(--choice-border);
51
- outline: var(--choice-border-width-addendum) solid
52
- var(--choice-border);
53
- height: math.div(18px, $base-font-size-px) + em;
54
- width: math.div(18px, $base-font-size-px) + em;
55
- margin-right: 10px;
56
- background-color: var(--choice-bg);
57
- content: '';
58
- vertical-align: top;
59
-
60
- // Offset so that the checkbox/radio fits within focused area.
61
- position: relative;
62
- top: 1px;
63
- left: 1px;
64
- }
65
-
66
- &:hover::before,
67
- &.hover::before {
68
- border-color: var(--choice-border-hover);
69
- }
70
38
  }
71
39
 
72
40
  .a-checkbox,
@@ -80,23 +48,9 @@
80
48
  }
81
49
 
82
50
  &:disabled {
83
- &:checked + .a-label::before,
84
- &:focus + .a-label::before,
85
- &.focus + .a-label::before,
86
- &:hover + .a-label::before,
87
- &.hover + .a-label::before {
88
- border-color: var(--choice-border);
89
- outline: none;
90
- box-shadow: none; // Applies only to radio buttons.
91
- }
92
-
93
51
  & + .a-label {
94
52
  cursor: not-allowed;
95
53
  color: var(--choice-label-disabled);
96
-
97
- &::before {
98
- outline: none;
99
- }
100
54
  }
101
55
  }
102
56
  }
@@ -127,40 +81,49 @@
127
81
  }
128
82
  }
129
83
 
130
- &--checkbox {
131
- .a-checkbox {
84
+ &--radio {
85
+ input:disabled {
86
+ &:checked + .a-label::before,
132
87
  &:focus + .a-label::before,
133
- &.focus + .a-label::before {
134
- border-color: var(--choice-border-focus);
135
- box-shadow: 0 0 0 1px var(--choice-border-focus);
136
- outline-color: var(--choice-border-focus);
137
- }
138
-
88
+ &.focus + .a-label::before,
139
89
  &:hover + .a-label::before,
140
90
  &.hover + .a-label::before {
141
- border-color: var(--choice-border-hover);
142
- box-shadow: 0 0 0 1px var(--choice-border-hover);
143
- outline-color: var(--choice-border-hover);
91
+ border-color: var(--choice-border);
92
+ outline: none;
93
+ box-shadow: none; // Applies only to radio buttons.
144
94
  }
145
95
 
146
- &:checked + .a-label::before {
147
- --cfpb-background-icon-svg: 'approved';
148
-
149
- background-size: auto $cf-icon-height;
150
- background-repeat: no-repeat;
151
- background-position: center 0;
152
- }
153
- &:disabled:checked + .a-label::before {
154
- // RGB values are CFPB gray (#5a5d61).
155
- // For some reason SVG isn't accepting hex values for the fill.
156
- --cfpb-background-icon-svg: 'approved rgb(90,93,97)';
96
+ & + .a-label {
97
+ &::before {
98
+ outline: none;
99
+ }
157
100
  }
158
101
  }
159
- }
160
102
 
161
- &--radio {
103
+ &:hover::before,
104
+ &.hover::before {
105
+ border-color: var(--choice-border-hover);
106
+ }
107
+
162
108
  .a-label {
163
109
  &::before {
110
+ display: inline-block;
111
+ grid-row-start: 1;
112
+ grid-row-end: 3;
113
+ border: 1px solid var(--choice-border);
114
+ outline: var(--choice-border-width-addendum) solid
115
+ var(--choice-border);
116
+ height: math.div(18px, $base-font-size-px) + em;
117
+ width: math.div(18px, $base-font-size-px) + em;
118
+ margin-right: 10px;
119
+ background-color: var(--choice-bg);
120
+ content: '';
121
+ vertical-align: top;
122
+
123
+ // Offset so that the checkbox/radio fits within focused area.
124
+ position: relative;
125
+ top: 1px;
126
+ left: 1px;
164
127
  border-radius: 50%;
165
128
 
166
129
  /* The rotate is needed to fix a bug in Firefox where radio
@@ -217,27 +180,28 @@
217
180
  }
218
181
 
219
182
  &--lg-target {
183
+ width: 100%;
220
184
  display: block;
221
185
 
222
186
  .a-label {
223
187
  box-sizing: border-box;
224
188
  width: 100%;
225
189
  padding: 15px;
226
- background-color: $form-field-input-lg-target-bg;
190
+ background-color: var(--form-field-input-lg-target-bg);
227
191
  }
228
192
 
229
193
  .a-checkbox,
230
194
  .a-radio {
231
195
  &:checked + .a-label {
232
- background-color: $form-field-input-lg-target-bg-selected;
233
- box-shadow: inset 0 0 0 1px $form-field-input-lg-target-border;
196
+ background-color: var(--form-field-input-lg-target-bg-selected);
197
+ box-shadow: inset 0 0 0 1px var(--form-field-input-lg-target-border);
234
198
  }
235
199
 
236
200
  &:hover + .a-label,
237
201
  &.hover + .a-label,
238
202
  &:focus + .a-label,
239
203
  &.focus + .a-label {
240
- box-shadow: inset 0 0 0 2px $form-field-input-lg-target-border;
204
+ box-shadow: inset 0 0 0 2px var(--form-field-input-lg-target-border);
241
205
  }
242
206
 
243
207
  &:focus + .a-label,
@@ -251,14 +215,11 @@
251
215
  &:hover:disabled + .a-label {
252
216
  color: var(--choice-label-disabled);
253
217
  box-shadow: none;
254
- background-color: $form-field-input-lg-target-bg-disabled;
218
+ background-color: var(--form-field-input-lg-target-bg-disabled);
255
219
  }
256
220
 
257
221
  &:checked:disabled + .a-label {
258
- &,
259
- &::before {
260
- border: 1px solid var(--form-field-border-disabled);
261
- }
222
+ border: 1px solid var(--form-field-border-disabled);
262
223
  }
263
224
  }
264
225
  }
@@ -1,6 +1,8 @@
1
1
  import { html, LitElement, css, unsafeCSS } from 'lit';
2
2
  import { classMap } from 'lit/directives/class-map.js';
3
+ import { ref, createRef } from 'lit/directives/ref.js';
3
4
  import styles from './cfpb-form-choice.component.scss';
5
+ import { CfpbCheckboxIcon } from '../cfpb-checkbox-icon';
4
6
 
5
7
  // The validation states are error, warning, or success.
6
8
  const VALID_VALIDATION = ['error', 'warning', 'success'];
@@ -17,29 +19,27 @@ export class CfpbFormChoice extends LitElement {
17
19
  ${unsafeCSS(styles)}
18
20
  `;
19
21
 
22
+ #checkboxIcon = createRef();
23
+
20
24
  /**
21
25
  * @property {boolean} checked - Whether the choice is checked or not.
22
26
  * @property {boolean} disabled - Whether the choice is disabled or not.
23
27
  * @property {boolean} large - Whether the choice has a large target area.
24
28
  * @property {string} validation - Validation style: error, warning, success.
25
29
  * @property {string} type - Choice type: checkbox or radio.
26
- * @property {string} inlist - Whether the choice appears in a <li> list.
27
30
  * @property {string} name - The name within a form.
28
31
  * @property {string} value - The value to submit within a form.
29
32
  * @returns {object} The map of properties.
30
33
  */
31
- static get properties() {
32
- return {
33
- checked: { type: Boolean, reflect: true },
34
- disabled: { type: Boolean },
35
- large: { type: Boolean },
36
- validation: { type: String },
37
- type: { type: String },
38
- inlist: { type: Boolean, attribute: true },
39
- name: { type: String },
40
- value: { type: String },
41
- };
42
- }
34
+ static properties = {
35
+ checked: { type: Boolean, reflect: true },
36
+ disabled: { type: Boolean },
37
+ large: { type: Boolean },
38
+ validation: { type: String },
39
+ type: { type: String },
40
+ name: { type: String },
41
+ value: { type: String },
42
+ };
43
43
 
44
44
  constructor() {
45
45
  super();
@@ -48,12 +48,12 @@ export class CfpbFormChoice extends LitElement {
48
48
  this.large = false;
49
49
  this.validation = '';
50
50
  this.type = 'checkbox';
51
- this.inlist = false;
52
51
  this.name = '';
53
52
  this.value = '';
54
53
  }
55
54
 
56
- #onChange() {
55
+ #onChange(evt) {
56
+ this.checked = evt.target.checked;
57
57
  this.dispatchEvent(
58
58
  new Event('change', {
59
59
  bubbles: true,
@@ -71,6 +71,26 @@ export class CfpbFormChoice extends LitElement {
71
71
  );
72
72
  }
73
73
 
74
+ #onFocus() {
75
+ if (this.#checkboxIcon.value) {
76
+ this.#checkboxIcon.value.focus();
77
+ }
78
+ }
79
+
80
+ #onBlur() {
81
+ if (this.#checkboxIcon.value) {
82
+ this.#checkboxIcon.value.blur();
83
+ }
84
+ }
85
+
86
+ #onMouseOver() {
87
+ if (this.#checkboxIcon.value) this.#checkboxIcon.value.mouseover();
88
+ }
89
+
90
+ #onMouseLeave() {
91
+ if (this.#checkboxIcon.value) this.#checkboxIcon.value.mouseleave();
92
+ }
93
+
74
94
  focus() {
75
95
  this.shadowRoot.querySelector('input').focus();
76
96
  }
@@ -98,7 +118,6 @@ export class CfpbFormChoice extends LitElement {
98
118
  'm-form-field': true,
99
119
  [`m-form-field--${this.type}`]: true,
100
120
  'm-form-field--lg-target': this.large,
101
- 'm-form-field--in-list': this.inlist,
102
121
  };
103
122
 
104
123
  if (this.#validValidation)
@@ -107,22 +126,41 @@ export class CfpbFormChoice extends LitElement {
107
126
  return classes;
108
127
  }
109
128
 
129
+ #renderCheckbox() {
130
+ return html`
131
+ <cfpb-checkbox-icon
132
+ .checked=${this.checked}
133
+ ?disabled=${this.disabled}
134
+ validation=${this.#validValidation}
135
+ ${ref(this.#checkboxIcon)}
136
+ ></cfpb-checkbox-icon>
137
+ `;
138
+ }
139
+
110
140
  render() {
111
141
  const classes = classMap(this.#baseClass);
112
142
 
113
143
  return html`
114
- <div class="${classes}" ?large=${this.large}>
144
+ <div
145
+ class=${classes}
146
+ ?large=${this.large}
147
+ @mouseover=${this.#onMouseOver}
148
+ @mouseleave=${this.#onMouseLeave}
149
+ >
115
150
  <input
116
151
  class="a-${this.type}"
117
- type="${this.#validType}"
152
+ type=${this.#validType}
118
153
  id="choice-input"
119
154
  ?disabled=${this.disabled}
120
155
  .checked=${this.checked}
121
156
  @change=${this.#onChange}
122
157
  @input=${this.#onInput}
158
+ @focus=${this.#onFocus}
159
+ @blur=${this.#onBlur}
123
160
  aria-invalid=${this.#validValidation === 'error' ? 'true' : 'false'}
124
161
  />
125
162
  <label class="a-label" for="choice-input">
163
+ ${this.type === 'checkbox' ? this.#renderCheckbox() : null}
126
164
  <slot></slot>
127
165
  </label>
128
166
  </div>
@@ -130,6 +168,8 @@ export class CfpbFormChoice extends LitElement {
130
168
  }
131
169
 
132
170
  static init() {
171
+ CfpbCheckboxIcon.init();
172
+
133
173
  window.customElements.get('cfpb-form-choice') ||
134
174
  window.customElements.define('cfpb-form-choice', CfpbFormChoice);
135
175
  }
@@ -0,0 +1,54 @@
1
+ @use 'sass:math';
2
+ @use '@cfpb/cfpb-design-system/src/elements/abstracts' as *;
3
+ @use '@cfpb/cfpb-design-system/src/elements/cfpb-button/cfpb-button' as *;
4
+
5
+ :host {
6
+ // Hide light DOM content.
7
+ ::slotted(ul),
8
+ ::slotted(ol) {
9
+ display: none !important;
10
+ }
11
+
12
+ // This line-height settings is taken from base.scss.
13
+ button {
14
+ line-height: math.div(19px, $base-font-size-px);
15
+ }
16
+
17
+ .o-form-search {
18
+ position: relative;
19
+ display: flex;
20
+ flex-direction: column;
21
+ row-gap: math.div(15px, $base-font-size-px) + rem;
22
+
23
+ // Tablet and above.
24
+ @include respond-to-min($bp-sm-min) {
25
+ flex-direction: row;
26
+ border-left: 0;
27
+ button[type='submit'] {
28
+ border-top-left-radius: 0;
29
+ border-bottom-left-radius: 0;
30
+ flex-basis: 25%;
31
+ }
32
+ }
33
+
34
+ .container {
35
+ position: relative;
36
+ width: 100%;
37
+ }
38
+
39
+ .popup {
40
+ display: none;
41
+ position: absolute;
42
+ top: 34px;
43
+ z-index: 100;
44
+ background: white;
45
+ border: 1px solid var(--pacific);
46
+ border-top: 0;
47
+ width: calc(100% - 2px);
48
+ }
49
+
50
+ .popup.show {
51
+ display: block;
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,194 @@
1
+ import { html, LitElement, css, unsafeCSS } from 'lit';
2
+ import styles from './cfpb-form-search.component.scss';
3
+ import { ref, createRef } from 'lit/directives/ref.js';
4
+ import { CfpbFormSearchInput } from '../cfpb-form-search-input';
5
+ import { SearchService } from '../cfpb-utilities/search-service.js';
6
+ import { CfpbList } from '../cfpb-list';
7
+ import { CfpbFormAlert } from '../cfpb-form-alert';
8
+
9
+ /**
10
+ * @element cfpb-form-search
11
+ */
12
+ export class CfpbFormSearch extends LitElement {
13
+ static styles = css`
14
+ ${unsafeCSS(styles)}
15
+ `;
16
+
17
+ static formAssociated = true;
18
+
19
+ /**
20
+ * @property {boolean} disabled - Whether the choice is disabled or not.
21
+ * @property {string} validation - Validation style: error, warning, success.
22
+ * @property {string} label - The aria-label for the input.
23
+ * @property {string} name - The name within a form.
24
+ * @property {string} value - The value within the input.
25
+ * @property {string} placeholder - The placeholder value.
26
+ * @property {string} maxlength - The maximum characters allowed in the input.
27
+ * @property {string} ariaLabelInput - aria-label for input.
28
+ * @property {string} ariaLabelButton - aria-label for button.
29
+ * @returns {object} The map of properties.
30
+ */
31
+ static get properties() {
32
+ return {
33
+ disabled: { type: Boolean },
34
+ validation: { type: String },
35
+ label: { type: String },
36
+ name: { type: String },
37
+ title: { type: Boolean, attribute: true },
38
+ value: { type: String },
39
+ maxlength: { type: Number },
40
+ placeholder: { type: String },
41
+ ariaLabelInput: { type: String, attribute: 'aria-label-input' },
42
+ ariaLabelButton: { type: String, attribute: 'aria-label-button' },
43
+ searchList: { type: Array },
44
+ };
45
+ }
46
+
47
+ #list = createRef();
48
+ #popup = createRef();
49
+
50
+ #internals;
51
+ #search;
52
+
53
+ constructor() {
54
+ super();
55
+
56
+ this.value = '';
57
+ this.#internals = this.attachInternals();
58
+ this.searchList = [];
59
+ }
60
+
61
+ #onSlotChange(evt) {
62
+ const slot = evt.target;
63
+
64
+ const list = slot
65
+ .assignedNodes({ flatten: true })
66
+ .filter(
67
+ (node) =>
68
+ node.nodeType === Node.ELEMENT_NODE &&
69
+ (node.tagName === 'UL' || node.tagName === 'OL'),
70
+ );
71
+
72
+ if (!list || !list[0]) {
73
+ return;
74
+ }
75
+
76
+ // Extract list items (with their text or link info)
77
+ const items = [...list[0].querySelectorAll('li')].map((li) => {
78
+ const link = li.querySelector('a');
79
+ if (link) {
80
+ return {
81
+ value: link.textContent.trim(),
82
+ href: link.getAttribute('href'),
83
+ };
84
+ }
85
+ return { value: li.textContent.trim() };
86
+ });
87
+
88
+ this.searchList = items;
89
+
90
+ this.#search = new SearchService(
91
+ items.map((item) => {
92
+ return item.value;
93
+ }),
94
+ );
95
+ }
96
+
97
+ #onClear() {
98
+ this.#popup.value.classList.remove('show');
99
+ this.#list.value.showAllItems();
100
+ }
101
+
102
+ #onInput(evt) {
103
+ if (evt.target.value.length > 1) {
104
+ this.#popup.value.classList.add('show');
105
+ if (this.#search) {
106
+ this.#list.value.filterItems(this.#search.search(evt.target.value));
107
+ }
108
+ } else {
109
+ this.#popup.value.classList.remove('show');
110
+ }
111
+
112
+ this.value = evt.target.value;
113
+ }
114
+
115
+ #onBlur() {
116
+ this.#popup.value.classList.remove('show');
117
+ }
118
+
119
+ get isSearchDisabled() {
120
+ return this.disabled || this.isOverMaxLength;
121
+ }
122
+
123
+ get isOverMaxLength() {
124
+ const isOverMax = this.value.length > this.maxlength;
125
+ if (isOverMax) this.validation = 'error';
126
+ else this.validation = '';
127
+ return isOverMax;
128
+ }
129
+
130
+ #onClickSearch(evt) {
131
+ evt.preventDefault();
132
+ if (this.disabled) return;
133
+
134
+ console.log(this.value);
135
+
136
+ if (this.value !== '') {
137
+ this.#internals.setFormValue(this.value);
138
+ this.#internals.form?.requestSubmit();
139
+ }
140
+ }
141
+
142
+ render() {
143
+ return html` <!--Light DOM content-->
144
+ <slot @slotchange=${this.#onSlotChange}></slot>
145
+
146
+ <!--Shadow DOM content-->
147
+ <div class="o-form-search">
148
+ <div class="container">
149
+ <cfpb-form-search-input
150
+ ?name=${this.name}
151
+ ?value=${this.value}
152
+ ?placeholder=${this.placeholder}
153
+ title=${this.title}
154
+ ?maxlength=${this.maxlength}
155
+ aria-label=${this.ariaLabelInput}
156
+ ?validation=${this.validation}
157
+ @clear=${this.#onClear}
158
+ @input=${this.#onInput}
159
+ @blur=${this.#onBlur}
160
+ ></cfpb-form-search-input>
161
+
162
+ <div class="popup" ${ref(this.#popup)}>
163
+ <cfpb-list .childData=${this.searchList} ${ref(this.#list)}>
164
+ </cfpb-list>
165
+ </div>
166
+ </div>
167
+
168
+ <button
169
+ class="a-btn"
170
+ type="submit"
171
+ aria-label="Search for term(s)"
172
+ ?disabled=${this.isSearchDisabled}
173
+ @click=${this.#onClickSearch}
174
+ >
175
+ Search
176
+ </button>
177
+ </div>
178
+
179
+ ${this.isOverMaxLength
180
+ ? html`<cfpb-form-alert validation="error">
181
+ Searches are limited to ${this.maxlength} characters.
182
+ </cfpb-form-alert>`
183
+ : null}`;
184
+ }
185
+
186
+ static init() {
187
+ CfpbFormSearchInput.init();
188
+ CfpbList.init();
189
+ CfpbFormAlert.init();
190
+
191
+ window.customElements.get('cfpb-form-search') ||
192
+ window.customElements.define('cfpb-form-search', CfpbFormSearch);
193
+ }
194
+ }