@cfpb/cfpb-design-system 4.1.0 → 4.2.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.
- package/CHANGELOG.md +36 -1
- package/dist/base/index.css +1 -1
- package/dist/base/index.css.map +2 -2
- package/dist/base/index.js +1 -1
- package/dist/base/index.js.map +1 -1
- package/dist/components/cfpb-buttons/index.css +1 -1
- package/dist/components/cfpb-buttons/index.css.map +2 -2
- package/dist/components/cfpb-buttons/index.js +1 -1
- package/dist/components/cfpb-buttons/index.js.map +1 -1
- package/dist/components/cfpb-expandables/index.css +1 -1
- package/dist/components/cfpb-expandables/index.css.map +2 -2
- package/dist/components/cfpb-expandables/index.js.map +1 -1
- package/dist/components/cfpb-forms/index.css +1 -1
- package/dist/components/cfpb-forms/index.css.map +2 -2
- package/dist/components/cfpb-forms/index.js +1 -1
- package/dist/components/cfpb-forms/index.js.map +1 -1
- package/dist/components/cfpb-layout/index.css +1 -1
- package/dist/components/cfpb-layout/index.css.map +2 -2
- package/dist/components/cfpb-layout/index.js.map +1 -1
- package/dist/components/cfpb-notifications/index.css +1 -1
- package/dist/components/cfpb-notifications/index.css.map +2 -2
- package/dist/components/cfpb-notifications/index.js +1 -1
- package/dist/components/cfpb-notifications/index.js.map +1 -1
- package/dist/components/cfpb-tooltips/index.css +1 -1
- package/dist/components/cfpb-tooltips/index.css.map +2 -2
- package/dist/components/cfpb-tooltips/index.js.map +1 -1
- package/dist/components/cfpb-typography/index.css +1 -1
- package/dist/components/cfpb-typography/index.css.map +2 -2
- package/dist/components/cfpb-typography/index.js +1 -1
- package/dist/components/cfpb-typography/index.js.map +1 -1
- package/dist/elements/cfpb-button/index.js +13 -4
- package/dist/elements/cfpb-button/index.js.map +4 -4
- package/dist/elements/cfpb-file-upload/index.js +4 -4
- package/dist/elements/cfpb-file-upload/index.js.map +4 -4
- package/dist/elements/cfpb-icon-text/index.js +29 -0
- package/dist/elements/cfpb-icon-text/index.js.map +7 -0
- package/dist/elements/cfpb-label/index.js.map +1 -1
- package/dist/elements/cfpb-multiselect/index.js +2 -2
- package/dist/elements/cfpb-multiselect/index.js.map +2 -2
- package/dist/elements/cfpb-pagination/index.js +32 -0
- package/dist/elements/cfpb-pagination/index.js.map +7 -0
- package/dist/elements/cfpb-tag-filter/index.js.map +1 -1
- package/dist/elements/cfpb-tag-topic/index.js +3 -3
- package/dist/elements/cfpb-tag-topic/index.js.map +2 -2
- package/dist/elements/cfpb-utilities/index.js +2 -0
- package/dist/elements/cfpb-utilities/index.js.map +7 -0
- package/dist/elements/index.js +7 -6
- package/dist/elements/index.js.map +4 -4
- package/dist/index.css +1 -1
- package/dist/index.css.map +2 -2
- package/dist/index.js +7 -6
- package/dist/index.js.map +4 -4
- package/package.json +2 -2
- package/src/base/base.scss +14 -26
- package/src/components/cfpb-buttons/button.scss +4 -2
- package/src/components/cfpb-forms/tag.scss +3 -0
- package/src/components/cfpb-pagination/vars.scss +0 -4
- package/src/components/cfpb-typography/link.scss +4 -2
- package/src/components/cfpb-typography/mixins.scss +8 -0
- package/src/elements/cfpb-button/cfpb-button.component.scss +15 -0
- package/src/elements/cfpb-button/index.js +52 -27
- package/src/elements/cfpb-icon-text/cfpb-icon-text.component.scss +59 -0
- package/src/elements/cfpb-icon-text/index.js +150 -0
- package/src/elements/cfpb-label/index.js +4 -3
- package/src/elements/cfpb-pagination/cfpb-pagination.component.scss +72 -0
- package/src/elements/cfpb-pagination/index.js +211 -0
- package/src/elements/cfpb-tag-filter/index.js +1 -0
- package/src/elements/cfpb-tag-topic/cfpb-tag-topic.component.scss +2 -0
- package/src/elements/cfpb-tag-topic/index.js +1 -0
- package/src/elements/cfpb-utilities/i18n-service.js +128 -0
- package/src/elements/cfpb-utilities/i18n-service.spec.js +156 -0
- package/src/elements/cfpb-utilities/index.js +7 -0
- package/src/elements/cfpb-utilities/media-query-service.js +102 -0
- package/src/elements/cfpb-utilities/media-query-service.spec.js +126 -0
- package/src/elements/index.js +1 -0
- package/src/utilities/utilities.scss +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cfpb/cfpb-design-system",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "CFPB's UI framework",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"gitHead": "d9b9862ef0a34a0ca6f4835347ac7f202ed50e3e",
|
|
29
29
|
"type": "module",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@fontsource-variable/source-sans-3": "5.2.
|
|
31
|
+
"@fontsource-variable/source-sans-3": "5.2.9",
|
|
32
32
|
"tippy.js": "6.3.7"
|
|
33
33
|
}
|
|
34
34
|
}
|
package/src/base/base.scss
CHANGED
|
@@ -153,60 +153,48 @@ li {
|
|
|
153
153
|
//
|
|
154
154
|
|
|
155
155
|
a {
|
|
156
|
-
border-width: 0;
|
|
157
|
-
border-style: dotted;
|
|
158
|
-
border-color: $link-underline;
|
|
159
156
|
color: $link-text;
|
|
160
|
-
|
|
157
|
+
|
|
158
|
+
text-decoration-color: $link-underline;
|
|
159
|
+
text-decoration-line: underline;
|
|
160
|
+
text-decoration-thickness: 1px;
|
|
161
|
+
text-decoration-style: dotted;
|
|
162
|
+
text-underline-offset: 4.5px;
|
|
161
163
|
|
|
162
164
|
// Note: The class definitions below are only for use in
|
|
163
165
|
// demonstrating link states. Do not use in production.
|
|
164
166
|
|
|
165
167
|
&:visited,
|
|
166
168
|
&.visited {
|
|
167
|
-
|
|
169
|
+
text-decoration-color: $link-underline-visited;
|
|
168
170
|
color: $link-text-visited;
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
&:hover,
|
|
172
174
|
&.hover {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
text-decoration-style: solid;
|
|
176
|
+
text-decoration-color: $link-underline-hover;
|
|
175
177
|
color: $link-text-hover;
|
|
176
178
|
}
|
|
177
179
|
|
|
178
180
|
&:focus,
|
|
179
181
|
&.focus {
|
|
180
|
-
|
|
182
|
+
text-decoration-style: solid;
|
|
181
183
|
outline: thin dotted;
|
|
182
184
|
outline-offset: 1px;
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
&:active,
|
|
186
188
|
&.active {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
+
text-decoration-style: solid;
|
|
190
|
+
text-decoration-color: $link-underline-active;
|
|
189
191
|
color: $link-text-active;
|
|
190
192
|
}
|
|
191
193
|
}
|
|
192
194
|
|
|
193
|
-
//
|
|
194
|
-
// Underlined links
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
p,
|
|
198
|
-
li,
|
|
199
|
-
dd {
|
|
200
|
-
// Restrict bottom borders to inline text links ...
|
|
201
|
-
|
|
202
|
-
a {
|
|
203
|
-
border-bottom-width: 1px;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
195
|
nav a {
|
|
208
|
-
//
|
|
209
|
-
|
|
196
|
+
// Don't show underlines if they're part of a nav list.
|
|
197
|
+
text-decoration-line: none;
|
|
210
198
|
}
|
|
211
199
|
|
|
212
200
|
//
|
|
@@ -141,7 +141,8 @@ input.a-btn::-moz-focus-inner {
|
|
|
141
141
|
//
|
|
142
142
|
|
|
143
143
|
&--disabled,
|
|
144
|
-
&[disabled]
|
|
144
|
+
&[disabled],
|
|
145
|
+
&[aria-disabled='true'] {
|
|
145
146
|
&,
|
|
146
147
|
&:link,
|
|
147
148
|
&:visited,
|
|
@@ -205,7 +206,8 @@ input.a-btn::-moz-focus-inner {
|
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
&--disabled:has(svg)::before,
|
|
208
|
-
&[disabled]:has(svg)::before
|
|
209
|
+
&[disabled]:has(svg)::before,
|
|
210
|
+
&[aria-disabled='true']:has(svg)::before {
|
|
209
211
|
border-color: $btn-disabled-divider !important;
|
|
210
212
|
}
|
|
211
213
|
|
|
@@ -50,6 +50,8 @@ a.a-tag-filter {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
a.a-tag-filter {
|
|
53
|
+
text-decoration: none;
|
|
54
|
+
|
|
53
55
|
// Colors for :link, :visited, :hover, :focus, :active.
|
|
54
56
|
@include u-link-colors(
|
|
55
57
|
var(--black),
|
|
@@ -101,6 +103,7 @@ a.a-tag-filter {
|
|
|
101
103
|
a.a-tag-topic:hover,
|
|
102
104
|
a.a-tag-topic:focus,
|
|
103
105
|
a.a-tag-topic:active {
|
|
106
|
+
text-decoration: none;
|
|
104
107
|
border-bottom: none;
|
|
105
108
|
outline-offset: 1px;
|
|
106
109
|
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
.a-link {
|
|
5
5
|
border-bottom-width: 0;
|
|
6
|
+
text-decoration-line: none;
|
|
6
7
|
|
|
7
8
|
.a-link__text {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
text-decoration-line: underline;
|
|
10
|
+
text-decoration-style: dotted;
|
|
11
|
+
text-decoration-thickness: 1px;
|
|
10
12
|
|
|
11
13
|
// See https://github.com/cfpb/consumerfinance.gov/pull/8252
|
|
12
14
|
overflow-wrap: break-word;
|
|
@@ -77,9 +77,17 @@
|
|
|
77
77
|
|
|
78
78
|
// Mobile only.
|
|
79
79
|
@include respond-to-max($bp-xs-max) {
|
|
80
|
+
text-decoration: none;
|
|
81
|
+
border-top-style: dotted;
|
|
82
|
+
border-bottom-style: dotted;
|
|
80
83
|
border-top-width: 1px;
|
|
81
84
|
border-bottom-width: 1px;
|
|
82
85
|
|
|
86
|
+
&:hover {
|
|
87
|
+
border-top-style: solid;
|
|
88
|
+
border-bottom-style: solid;
|
|
89
|
+
}
|
|
90
|
+
|
|
83
91
|
// We create a faux focus rectangle in the ::after pseudoelement to better
|
|
84
92
|
// control the positioning of the focus rectangle, which would overwise
|
|
85
93
|
// overlap the top border of the jumplink when it appears in a group.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
@use '@cfpb/cfpb-design-system/src/base' as *;
|
|
2
2
|
@use '@cfpb/cfpb-design-system/src/abstracts' as *;
|
|
3
3
|
@use '@cfpb/cfpb-design-system/src/components/cfpb-buttons/button' as *;
|
|
4
|
+
@use '@cfpb/cfpb-design-system/src/components/cfpb-buttons/button-link' as *;
|
|
4
5
|
|
|
5
6
|
:host {
|
|
6
7
|
// This prevents the child button from having an empty gap after the button.
|
|
@@ -14,3 +15,17 @@
|
|
|
14
15
|
width: 100%;
|
|
15
16
|
}
|
|
16
17
|
}
|
|
18
|
+
|
|
19
|
+
:host([flush-left]) {
|
|
20
|
+
[role='button'] {
|
|
21
|
+
border-top-left-radius: 0;
|
|
22
|
+
border-bottom-left-radius: 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
:host([flush-right]) {
|
|
27
|
+
[role='button'] {
|
|
28
|
+
border-top-right-radius: 0;
|
|
29
|
+
border-bottom-right-radius: 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -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-button.component.scss';
|
|
5
|
+
import { CfpbIconText } from '../cfpb-icon-text';
|
|
4
6
|
|
|
5
7
|
// The variants are different color themes of the button.
|
|
6
8
|
const VALID_VARIANTS = ['primary', 'secondary', 'warning'];
|
|
@@ -19,15 +21,19 @@ export class CfpbButton extends LitElement {
|
|
|
19
21
|
`;
|
|
20
22
|
|
|
21
23
|
/**
|
|
24
|
+
* @property {string} type - The button type: button, submit, or reset.
|
|
22
25
|
* @property {string} href - The URL to link to (makes the button a link).
|
|
23
|
-
* @property {boolean} disabled - Whether
|
|
26
|
+
* @property {boolean} disabled - Whether the button is disabled or not.
|
|
24
27
|
* @property {string} variant - The button variant: secondary and warning.
|
|
25
28
|
* @property {boolean} fullOnMobile - Whether to be width 100% on mobile.
|
|
26
|
-
* @property {
|
|
29
|
+
* @property {boolean} flushLeft - Whether button is not rounded on left.
|
|
30
|
+
* @property {boolean} flushRight - Whether button is not rounded on right.
|
|
31
|
+
* @property {boolean} styleAsLink - Style the button as a link.
|
|
27
32
|
* @returns {object} The map of properties.
|
|
28
33
|
*/
|
|
29
34
|
static get properties() {
|
|
30
35
|
return {
|
|
36
|
+
type: { type: String },
|
|
31
37
|
href: { type: String },
|
|
32
38
|
disabled: { type: Boolean, reflect: true },
|
|
33
39
|
variant: { type: String },
|
|
@@ -36,47 +42,55 @@ export class CfpbButton extends LitElement {
|
|
|
36
42
|
attribute: 'full-on-mobile',
|
|
37
43
|
reflect: true,
|
|
38
44
|
},
|
|
39
|
-
|
|
45
|
+
flushLeft: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
attribute: 'flush-left',
|
|
48
|
+
reflect: true,
|
|
49
|
+
},
|
|
50
|
+
flushRight: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
attribute: 'flush-right',
|
|
53
|
+
reflect: true,
|
|
54
|
+
},
|
|
55
|
+
styleAsLink: {
|
|
56
|
+
type: Boolean,
|
|
57
|
+
attribute: 'style-as-link',
|
|
58
|
+
reflect: true,
|
|
59
|
+
},
|
|
40
60
|
};
|
|
41
61
|
}
|
|
42
62
|
|
|
63
|
+
// DOM references.
|
|
64
|
+
#iconTextDom = createRef();
|
|
65
|
+
|
|
43
66
|
constructor() {
|
|
44
67
|
super();
|
|
45
|
-
this.
|
|
68
|
+
this.type = 'button';
|
|
46
69
|
this.variant = 'primary';
|
|
70
|
+
this.disabled = false;
|
|
47
71
|
this.fullOnMobile = false;
|
|
48
|
-
this.
|
|
72
|
+
this.styleAsLink = false;
|
|
49
73
|
}
|
|
50
74
|
|
|
51
75
|
/**
|
|
52
|
-
*
|
|
76
|
+
* @returns {boolean} True if it has an icon, false otherwise.
|
|
53
77
|
*/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (icon) icon.style.display = 'none';
|
|
78
|
+
hasIcon() {
|
|
79
|
+
return this.#iconTextDom.value?.hasIcon();
|
|
57
80
|
}
|
|
58
81
|
|
|
59
82
|
/**
|
|
60
|
-
*
|
|
83
|
+
* Hide any icon in the slot.
|
|
61
84
|
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (icon) icon.style.display = '';
|
|
85
|
+
hideIcon() {
|
|
86
|
+
this.#iconTextDom.value?.hideIcon();
|
|
65
87
|
}
|
|
66
88
|
|
|
67
89
|
/**
|
|
68
|
-
*
|
|
69
|
-
* @returns {Node} The icon SVG node.
|
|
90
|
+
* Show any icon in the slot, if it was hidden.
|
|
70
91
|
*/
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const nodes = slot.assignedNodes({ flatten: true });
|
|
74
|
-
|
|
75
|
-
for (const node of nodes) {
|
|
76
|
-
if (node.tagName.toLowerCase() === 'svg') {
|
|
77
|
-
return node;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
92
|
+
showIcon() {
|
|
93
|
+
this.#iconTextDom.value?.showIcon();
|
|
80
94
|
}
|
|
81
95
|
|
|
82
96
|
/**
|
|
@@ -103,9 +117,18 @@ export class CfpbButton extends LitElement {
|
|
|
103
117
|
return {
|
|
104
118
|
'a-btn': true,
|
|
105
119
|
[`a-btn--${this.#validVariant}`]: this.#validVariant !== 'primary',
|
|
120
|
+
[`a-btn--link`]: this.styleAsLink === true,
|
|
106
121
|
};
|
|
107
122
|
}
|
|
108
123
|
|
|
124
|
+
#renderTextAndIcon() {
|
|
125
|
+
return html`
|
|
126
|
+
<cfpb-icon-text ${ref(this.#iconTextDom)} ?disabled=${this.disabled}>
|
|
127
|
+
<slot></slot>
|
|
128
|
+
</cfpb-icon-text>
|
|
129
|
+
`;
|
|
130
|
+
}
|
|
131
|
+
|
|
109
132
|
render() {
|
|
110
133
|
const classes = classMap(this.#btnClass);
|
|
111
134
|
|
|
@@ -119,8 +142,8 @@ export class CfpbButton extends LitElement {
|
|
|
119
142
|
aria-disabled=${String(this.disabled)}
|
|
120
143
|
tabindex=${this.disabled ? -1 : 0}
|
|
121
144
|
>
|
|
122
|
-
|
|
123
|
-
|
|
145
|
+
${this.#renderTextAndIcon()}
|
|
146
|
+
</a>
|
|
124
147
|
`;
|
|
125
148
|
}
|
|
126
149
|
|
|
@@ -131,12 +154,14 @@ export class CfpbButton extends LitElement {
|
|
|
131
154
|
?disabled=${this.disabled}
|
|
132
155
|
type=${this.#validType}
|
|
133
156
|
>
|
|
134
|
-
|
|
157
|
+
${this.#renderTextAndIcon()}
|
|
135
158
|
</button>
|
|
136
159
|
`;
|
|
137
160
|
}
|
|
138
161
|
|
|
139
162
|
static init() {
|
|
163
|
+
CfpbIconText.init();
|
|
164
|
+
|
|
140
165
|
window.customElements.get('cfpb-button') ||
|
|
141
166
|
window.customElements.define('cfpb-button', CfpbButton);
|
|
142
167
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
@use 'sass:math';
|
|
2
|
+
@use '@cfpb/cfpb-design-system/src/abstracts' as *;
|
|
3
|
+
|
|
4
|
+
@mixin u-btn-divider() {
|
|
5
|
+
content: '';
|
|
6
|
+
border-left: 1px solid var(--icon-text-divider);
|
|
7
|
+
order: 2;
|
|
8
|
+
place-self: normal;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
:host {
|
|
12
|
+
// Theme variables.
|
|
13
|
+
--icon-text-divider: var(--pacific-60);
|
|
14
|
+
|
|
15
|
+
div {
|
|
16
|
+
// This prevents the child button from having an empty gap after the button.
|
|
17
|
+
display: flex;
|
|
18
|
+
width: fit-content;
|
|
19
|
+
|
|
20
|
+
// Hide SVG by default.
|
|
21
|
+
& ::slotted(svg) {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&.u-has-icon {
|
|
26
|
+
gap: math.div(10px, $btn-font-size) + rem;
|
|
27
|
+
& slot::before {
|
|
28
|
+
@include u-btn-divider;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Show SVG.
|
|
32
|
+
& ::slotted(svg) {
|
|
33
|
+
display: initial;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.u-has-icon--left {
|
|
38
|
+
& ::slotted(svg) {
|
|
39
|
+
order: 1;
|
|
40
|
+
}
|
|
41
|
+
& ::slotted(span) {
|
|
42
|
+
order: 3;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&.u-has-icon--right {
|
|
47
|
+
& ::slotted(svg) {
|
|
48
|
+
order: 3;
|
|
49
|
+
}
|
|
50
|
+
& ::slotted(span) {
|
|
51
|
+
order: 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:host([disabled]) {
|
|
58
|
+
--icon-text-divider: var(--gray-60);
|
|
59
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { html, LitElement, css, unsafeCSS } from 'lit';
|
|
2
|
+
import styles from './cfpb-icon-text.component.scss';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @element cfpb-icon-text
|
|
7
|
+
* @slot - The main content for the text and icon.
|
|
8
|
+
*/
|
|
9
|
+
export class CfpbIconText extends LitElement {
|
|
10
|
+
static styles = css`
|
|
11
|
+
${unsafeCSS(styles)}
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @property {boolean} disabled - Apply disabled styles or not.
|
|
16
|
+
* @returns {object} The map of properties.
|
|
17
|
+
*/
|
|
18
|
+
static get properties() {
|
|
19
|
+
return {
|
|
20
|
+
disabled: { type: Boolean, reflect: true },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// DOM references.
|
|
25
|
+
#svgObserver;
|
|
26
|
+
#iconClasses;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
this.#iconClasses = '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
connectedCallback() {
|
|
34
|
+
super.connectedCallback();
|
|
35
|
+
|
|
36
|
+
this.#svgObserver = new MutationObserver(() => {
|
|
37
|
+
this.#processLightDom();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.#svgObserver.observe(this, {
|
|
41
|
+
childList: true,
|
|
42
|
+
subtree: false,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
disconnectedCallback() {
|
|
47
|
+
super.disconnectedCallback();
|
|
48
|
+
if (this.#svgObserver) {
|
|
49
|
+
this.#svgObserver.disconnect();
|
|
50
|
+
this.#svgObserver = null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#processLightDom() {
|
|
55
|
+
const div = this.shadowRoot.querySelector('div');
|
|
56
|
+
const slot = this.shadowRoot.querySelector('slot');
|
|
57
|
+
const nodes = slot.assignedNodes({ flatten: true });
|
|
58
|
+
|
|
59
|
+
let svgEl = null;
|
|
60
|
+
let spanEl = null;
|
|
61
|
+
|
|
62
|
+
for (const node of nodes) {
|
|
63
|
+
if (
|
|
64
|
+
node.nodeType === Node.TEXT_NODE &&
|
|
65
|
+
node.textContent.trim().length > 0
|
|
66
|
+
) {
|
|
67
|
+
const span = document.createElement('span');
|
|
68
|
+
span.textContent = node.textContent;
|
|
69
|
+
node.replaceWith(span);
|
|
70
|
+
if (!spanEl) spanEl = span;
|
|
71
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
72
|
+
const tag = node.tagName.toLowerCase();
|
|
73
|
+
if (tag === 'svg' && !svgEl) {
|
|
74
|
+
svgEl = node;
|
|
75
|
+
} else if (tag === 'span' && !spanEl) {
|
|
76
|
+
spanEl = node;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (svgEl && spanEl) {
|
|
82
|
+
div.classList.add('u-has-icon');
|
|
83
|
+
if (
|
|
84
|
+
svgEl.compareDocumentPosition(spanEl) & Node.DOCUMENT_POSITION_FOLLOWING
|
|
85
|
+
) {
|
|
86
|
+
div.classList.add('u-has-icon--left');
|
|
87
|
+
} else {
|
|
88
|
+
div.classList.add('u-has-icon--right');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
firstUpdated() {
|
|
94
|
+
this.#processLightDom();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Hide any icon in the slot.
|
|
99
|
+
*/
|
|
100
|
+
hideIcon() {
|
|
101
|
+
const icon = this.#findIconInSlot();
|
|
102
|
+
const div = this.shadowRoot.querySelector('div');
|
|
103
|
+
if (icon) {
|
|
104
|
+
this.#iconClasses = div.className;
|
|
105
|
+
div.className = '';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Show any icon in the slot, if it was hidden.
|
|
111
|
+
*/
|
|
112
|
+
showIcon() {
|
|
113
|
+
const icon = this.#findIconInSlot();
|
|
114
|
+
const div = this.shadowRoot.querySelector('div');
|
|
115
|
+
if (icon) div.className = this.#iconClasses;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @returns {boolean} True if it has an icon, false otherwise.
|
|
120
|
+
*/
|
|
121
|
+
hasIcon() {
|
|
122
|
+
const icon = this.#findIconInSlot();
|
|
123
|
+
if (icon) return true;
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Find the icon SVG in the slot.
|
|
129
|
+
* @returns {Node} The icon SVG node.
|
|
130
|
+
*/
|
|
131
|
+
#findIconInSlot() {
|
|
132
|
+
const slot = this.shadowRoot.querySelector('slot');
|
|
133
|
+
const nodes = slot.assignedNodes({ flatten: true });
|
|
134
|
+
|
|
135
|
+
for (const node of nodes) {
|
|
136
|
+
if (node.tagName && node.tagName.toLowerCase() === 'svg') {
|
|
137
|
+
return node;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
render() {
|
|
143
|
+
return html`<div><slot></slot></div>`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static init() {
|
|
147
|
+
window.customElements.get('cfpb-icon-text') ||
|
|
148
|
+
window.customElements.define('cfpb-icon-text', CfpbIconText);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -4,8 +4,9 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
*
|
|
7
|
-
* @element cfpb-
|
|
8
|
-
* @slot - The
|
|
7
|
+
* @element cfpb-label.
|
|
8
|
+
* @slot label - The content for the label text.
|
|
9
|
+
* @slot helper - The content for the label helper text.
|
|
9
10
|
*/
|
|
10
11
|
export class CfpbLabel extends LitElement {
|
|
11
12
|
static styles = css`
|
|
@@ -14,7 +15,7 @@ export class CfpbLabel extends LitElement {
|
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* @property {string} for - Associate the label with an ID elsewhere.
|
|
17
|
-
* @property {
|
|
18
|
+
* @property {boolean} block - Whether this has block or inline helper text.
|
|
18
19
|
* @returns {object} The map of properties.
|
|
19
20
|
*/
|
|
20
21
|
static get properties() {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
@use 'sass:math';
|
|
2
|
+
@use '@cfpb/cfpb-design-system/src/abstracts' as *;
|
|
3
|
+
@use '@cfpb/cfpb-design-system/src/utilities' as *;
|
|
4
|
+
|
|
5
|
+
:host {
|
|
6
|
+
width: 100%;
|
|
7
|
+
|
|
8
|
+
.cf-icon-svg {
|
|
9
|
+
height: $cf-icon-height;
|
|
10
|
+
vertical-align: text-top;
|
|
11
|
+
fill: currentcolor;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.m-pagination {
|
|
15
|
+
display: grid;
|
|
16
|
+
grid-template-columns: auto 1fr auto;
|
|
17
|
+
grid-template-areas:
|
|
18
|
+
'pag-btn-prev . pag-btn-next'
|
|
19
|
+
'pag-form pag-form pag-form';
|
|
20
|
+
row-gap: math.div(15px, $base-font-size-px) + rem;
|
|
21
|
+
|
|
22
|
+
&__form {
|
|
23
|
+
grid-area: pag-form;
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-flow: wrap;
|
|
26
|
+
place-content: center;
|
|
27
|
+
gap: math.div(10px, $base-font-size-px) + rem;
|
|
28
|
+
|
|
29
|
+
padding: math.div(5px, $base-font-size-px) + rem;
|
|
30
|
+
border-radius: math.div(4px, $base-font-size-px) + rem;
|
|
31
|
+
background: var(--gray-5);
|
|
32
|
+
color: var(--gray);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&__current-page {
|
|
36
|
+
// 45px is a magic number to provide enough room for three digits
|
|
37
|
+
// and the number spinners for type="number" inputs on desktop
|
|
38
|
+
width: math.div(45px, $base-font-size-px) + rem;
|
|
39
|
+
|
|
40
|
+
font-weight: 500;
|
|
41
|
+
text-align: right;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&__label {
|
|
45
|
+
display: contents;
|
|
46
|
+
white-space: nowrap;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&__btn-prev {
|
|
50
|
+
grid-area: pag-btn-prev;
|
|
51
|
+
z-index: 1;
|
|
52
|
+
}
|
|
53
|
+
&__btn-next {
|
|
54
|
+
grid-area: pag-btn-next;
|
|
55
|
+
z-index: 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Tablet and above.
|
|
59
|
+
@include respond-to-min($bp-sm-min) {
|
|
60
|
+
grid-template-areas: 'pag-btn-prev pag-form pag-btn-next';
|
|
61
|
+
|
|
62
|
+
&__btn-prev {
|
|
63
|
+
border-top-right-radius: 0;
|
|
64
|
+
border-bottom-right-radius: 0;
|
|
65
|
+
}
|
|
66
|
+
&__btn-next {
|
|
67
|
+
border-top-left-radius: 0;
|
|
68
|
+
border-bottom-left-radius: 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|