typography-controller 1.1.0 → 1.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/dist/react/react-wrapper.js +50 -268
- package/dist/web/typography-controller.js +48 -266
- package/dist/web/typography-controller.umd.cjs +4 -244
- package/package.json +1 -1
- package/src/typography-controller.css +113 -0
- package/src/typography-controller.html +69 -0
- package/src/typography-controller.js +86 -253
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
font-family: system-ui, sans-serif;
|
|
4
|
+
max-width: 420px;
|
|
5
|
+
padding: 18px 20px;
|
|
6
|
+
border-radius: 18px;
|
|
7
|
+
background: rgba(255, 255, 255, 0.65);
|
|
8
|
+
border: 1px solid rgba(0, 0, 0, 0.08);
|
|
9
|
+
backdrop-filter: blur(14px);
|
|
10
|
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
|
|
11
|
+
color: #0f172a;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.header {
|
|
15
|
+
display: flex;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
align-items: baseline;
|
|
18
|
+
margin-bottom: 14px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.title {
|
|
22
|
+
font-size: 14px;
|
|
23
|
+
font-weight: 600;
|
|
24
|
+
letter-spacing: 0.08em;
|
|
25
|
+
text-transform: uppercase;
|
|
26
|
+
color: #475569;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.badge {
|
|
30
|
+
font-size: 11px;
|
|
31
|
+
padding: 3px 8px;
|
|
32
|
+
border-radius: 999px;
|
|
33
|
+
background: rgba(59, 130, 246, 0.12);
|
|
34
|
+
color: #1d4ed8;
|
|
35
|
+
border: 1px solid rgba(59, 130, 246, 0.35);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.group {
|
|
39
|
+
margin-bottom: 14px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.label-row {
|
|
43
|
+
display: flex;
|
|
44
|
+
justify-content: space-between;
|
|
45
|
+
align-items: center;
|
|
46
|
+
margin-bottom: 6px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
label {
|
|
50
|
+
font-size: 12px;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
color: #0f172a;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.value {
|
|
56
|
+
font-size: 11px;
|
|
57
|
+
color: #64748b;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
input[type="range"] {
|
|
61
|
+
-webkit-appearance: none;
|
|
62
|
+
width: 100%;
|
|
63
|
+
height: 6px;
|
|
64
|
+
border-radius: 999px;
|
|
65
|
+
background: linear-gradient(90deg, #3b82f6, #60a5fa);
|
|
66
|
+
outline: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
input[type="range"]::-webkit-slider-thumb {
|
|
70
|
+
-webkit-appearance: none;
|
|
71
|
+
height: 18px;
|
|
72
|
+
width: 18px;
|
|
73
|
+
border-radius: 50%;
|
|
74
|
+
background: white;
|
|
75
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
76
|
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
|
|
77
|
+
cursor: pointer;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
select {
|
|
81
|
+
width: 100%;
|
|
82
|
+
padding: 6px 8px;
|
|
83
|
+
border-radius: 8px;
|
|
84
|
+
border: 1px solid rgba(148, 163, 184, 0.7);
|
|
85
|
+
background: rgba(255, 255, 255, 0.9);
|
|
86
|
+
font-size: 12px;
|
|
87
|
+
color: #0f172a;
|
|
88
|
+
outline: none;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
select:focus {
|
|
92
|
+
outline: none;
|
|
93
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
|
|
94
|
+
border-radius: 999px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
input[type="range"]:focus {
|
|
98
|
+
outline: none;
|
|
99
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
|
|
100
|
+
border-radius: 999px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
input[type="range"]:focus::-webkit-slider-thumb {
|
|
104
|
+
box-shadow:
|
|
105
|
+
0 0 0 4px rgba(37, 99, 235, 0.35),
|
|
106
|
+
0 4px 10px rgba(0, 0, 0, 0.25);
|
|
107
|
+
border-color: #2563eb;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
input[type="range"]:hover::-webkit-slider-thumb {
|
|
111
|
+
transform: scale(1.05);
|
|
112
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
113
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<div class="header">
|
|
2
|
+
<h2 class="title" id="controllerTitle">Typography controls</h2>
|
|
3
|
+
<span class="badge">v1.3.0</span>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div aria-live="polite" class="sr-only" id="liveRegion"></div>
|
|
7
|
+
|
|
8
|
+
<div class="group" id="groupFontSize" role="group" aria-labelledby="labelFontSize">
|
|
9
|
+
<div class="label-row">
|
|
10
|
+
<label id="labelFontSize" for="fontSize">Font size</label>
|
|
11
|
+
<span class="value" id="fontSizeValue" aria-hidden="true"></span>
|
|
12
|
+
</div>
|
|
13
|
+
<input type="range" id="fontSize" min="12" max="60" value="24"
|
|
14
|
+
aria-valuemin="12" aria-valuemax="60" aria-valuenow="24"
|
|
15
|
+
aria-labelledby="labelFontSize">
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="group" id="groupLetterSpacing" role="group" aria-labelledby="labelLetterSpacing">
|
|
19
|
+
<div class="label-row">
|
|
20
|
+
<label id="labelLetterSpacing" for="letterSpacing">Letter spacing</label>
|
|
21
|
+
<span class="value" id="letterSpacingValue" aria-hidden="true"></span>
|
|
22
|
+
</div>
|
|
23
|
+
<input type="range" id="letterSpacing" min="0" max="20" value="0"
|
|
24
|
+
aria-valuemin="0" aria-valuemax="20" aria-valuenow="0"
|
|
25
|
+
aria-labelledby="labelLetterSpacing">
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="group" id="groupWordSpacing" role="group" aria-labelledby="labelWordSpacing">
|
|
29
|
+
<div class="label-row">
|
|
30
|
+
<label id="labelWordSpacing" for="wordSpacing">Word spacing</label>
|
|
31
|
+
<span class="value" id="wordSpacingValue" aria-hidden="true"></span>
|
|
32
|
+
</div>
|
|
33
|
+
<input type="range" id="wordSpacing" min="0" max="40" value="0"
|
|
34
|
+
aria-valuemin="0" aria-valuemax="40" aria-valuenow="0"
|
|
35
|
+
aria-labelledby="labelWordSpacing">
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div class="group" id="groupLineHeight" role="group" aria-labelledby="labelLineHeight">
|
|
39
|
+
<div class="label-row">
|
|
40
|
+
<label id="labelLineHeight" for="lineHeight">Line height</label>
|
|
41
|
+
<span class="value" id="lineHeightValue" aria-hidden="true"></span>
|
|
42
|
+
</div>
|
|
43
|
+
<input type="range" id="lineHeight" min="1" max="3" step="0.1" value="1.5"
|
|
44
|
+
aria-valuemin="1" aria-valuemax="3" aria-valuenow="1.5"
|
|
45
|
+
aria-labelledby="labelLineHeight">
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="group" id="groupContrast" role="group" aria-labelledby="labelContrast">
|
|
49
|
+
<div class="label-row">
|
|
50
|
+
<label id="labelContrast" for="contrast">Contrast</label>
|
|
51
|
+
<span class="value" id="contrastValue" aria-hidden="true"></span>
|
|
52
|
+
</div>
|
|
53
|
+
<input type="range" id="contrast" min="50" max="200" value="100"
|
|
54
|
+
aria-valuemin="50" aria-valuemax="200" aria-valuenow="100"
|
|
55
|
+
aria-labelledby="labelContrast">
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="group" id="groupFontFamily" role="group" aria-labelledby="labelFontFamily">
|
|
59
|
+
<div class="label-row">
|
|
60
|
+
<label id="labelFontFamily" for="fontFamily">Font family</label>
|
|
61
|
+
</div>
|
|
62
|
+
<select id="fontFamily" aria-labelledby="labelFontFamily">
|
|
63
|
+
<option value="system-ui, sans-serif">System</option>
|
|
64
|
+
<option value="Georgia, serif">Serif</option>
|
|
65
|
+
<option value="'Courier New', monospace">Monospace</option>
|
|
66
|
+
<option value="Verdana, sans-serif">Verdana</option>
|
|
67
|
+
<option value="inherit">Inherit</option>
|
|
68
|
+
</select>
|
|
69
|
+
</div>
|
|
@@ -1,286 +1,63 @@
|
|
|
1
|
-
import { TypographyState } from "./TypographyState.js";
|
|
2
|
-
|
|
3
1
|
class TypographyController extends HTMLElement {
|
|
4
2
|
constructor() {
|
|
5
3
|
super();
|
|
6
4
|
this.attachShadow({ mode: "open" });
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
async connectedCallback() {
|
|
8
|
+
// 1. Load external HTML + CSS
|
|
9
|
+
const [html, css] = await Promise.all([
|
|
10
|
+
fetch("../src//typography-controller.html").then(r => r.text()),
|
|
11
|
+
fetch("../src/typography-controller.css").then(r => r.text())
|
|
12
|
+
]);
|
|
7
13
|
|
|
14
|
+
// 2. Inject into shadow DOM
|
|
8
15
|
this.shadowRoot.innerHTML = `
|
|
9
|
-
<style>
|
|
10
|
-
|
|
11
|
-
display: block;
|
|
12
|
-
font-family: system-ui, sans-serif;
|
|
13
|
-
max-width: 420px;
|
|
14
|
-
padding: 18px 20px;
|
|
15
|
-
border-radius: 18px;
|
|
16
|
-
background: rgba(255, 255, 255, 0.65);
|
|
17
|
-
border: 1px solid rgba(0, 0, 0, 0.08);
|
|
18
|
-
backdrop-filter: blur(14px);
|
|
19
|
-
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
|
|
20
|
-
color: #0f172a;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.header {
|
|
24
|
-
display: flex;
|
|
25
|
-
justify-content: space-between;
|
|
26
|
-
align-items: baseline;
|
|
27
|
-
margin-bottom: 14px;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.title {
|
|
31
|
-
font-size: 14px;
|
|
32
|
-
font-weight: 600;
|
|
33
|
-
letter-spacing: 0.08em;
|
|
34
|
-
text-transform: uppercase;
|
|
35
|
-
color: #475569;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.badge {
|
|
39
|
-
font-size: 11px;
|
|
40
|
-
padding: 3px 8px;
|
|
41
|
-
border-radius: 999px;
|
|
42
|
-
background: rgba(59, 130, 246, 0.12);
|
|
43
|
-
color: #1d4ed8;
|
|
44
|
-
border: 1px solid rgba(59, 130, 246, 0.35);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.group {
|
|
48
|
-
margin-bottom: 14px;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.label-row {
|
|
52
|
-
display: flex;
|
|
53
|
-
justify-content: space-between;
|
|
54
|
-
align-items: center;
|
|
55
|
-
margin-bottom: 6px;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
label {
|
|
59
|
-
font-size: 12px;
|
|
60
|
-
font-weight: 600;
|
|
61
|
-
color: #0f172a;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.value {
|
|
65
|
-
font-size: 11px;
|
|
66
|
-
color: #64748b;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
input[type="range"] {
|
|
70
|
-
-webkit-appearance: none;
|
|
71
|
-
width: 100%;
|
|
72
|
-
height: 6px;
|
|
73
|
-
border-radius: 999px;
|
|
74
|
-
background: linear-gradient(90deg, #3b82f6, #60a5fa);
|
|
75
|
-
outline: none;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
input[type="range"]::-webkit-slider-thumb {
|
|
79
|
-
-webkit-appearance: none;
|
|
80
|
-
height: 18px;
|
|
81
|
-
width: 18px;
|
|
82
|
-
border-radius: 50%;
|
|
83
|
-
background: white;
|
|
84
|
-
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
85
|
-
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
|
|
86
|
-
cursor: pointer;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
select {
|
|
90
|
-
width: 100%;
|
|
91
|
-
padding: 6px 8px;
|
|
92
|
-
border-radius: 8px;
|
|
93
|
-
border: 1px solid rgba(148, 163, 184, 0.7);
|
|
94
|
-
background: rgba(255, 255, 255, 0.9);
|
|
95
|
-
font-size: 12px;
|
|
96
|
-
color: #0f172a;
|
|
97
|
-
outline: none;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
select:focus {
|
|
101
|
-
outline: none;
|
|
102
|
-
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
|
|
103
|
-
border-radius: 999px;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/* Highlight the track when focused */
|
|
107
|
-
input[type="range"]:focus {
|
|
108
|
-
outline: none;
|
|
109
|
-
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
|
|
110
|
-
border-radius: 999px;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/* Glow effect on the thumb when focused */
|
|
114
|
-
input[type="range"]:focus::-webkit-slider-thumb {
|
|
115
|
-
box-shadow:
|
|
116
|
-
0 0 0 4px rgba(37, 99, 235, 0.35),
|
|
117
|
-
0 4px 10px rgba(0, 0, 0, 0.25);
|
|
118
|
-
border-color: #2563eb;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/* Firefox thumb focus */
|
|
122
|
-
input[type="range"]::-moz-range-thumb:focus {
|
|
123
|
-
box-shadow:
|
|
124
|
-
0 0 0 4px rgba(37, 99, 235, 0.35),
|
|
125
|
-
0 4px 10px rgba(0, 0, 0, 0.25);
|
|
126
|
-
border-color: #2563eb;
|
|
127
|
-
}
|
|
128
|
-
input[type="range"]:hover::-webkit-slider-thumb {
|
|
129
|
-
transform: scale(1.05);
|
|
130
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
131
|
-
}
|
|
132
|
-
</style>
|
|
133
|
-
|
|
134
|
-
<div class="header">
|
|
135
|
-
<h2 class="title" id="controllerTitle">Typography Controls</h2>
|
|
136
|
-
<span class="badge">v1.0.0</span>
|
|
137
|
-
</div>
|
|
138
|
-
|
|
139
|
-
<!-- Live region for announcements -->
|
|
140
|
-
<div aria-live="polite" class="sr-only" id="liveRegion"></div>
|
|
141
|
-
|
|
142
|
-
<div class="group" id="groupFontSize" role="group" aria-labelledby="labelFontSize">
|
|
143
|
-
<div class="label-row">
|
|
144
|
-
<label id="labelFontSize" for="fontSize">Font size</label>
|
|
145
|
-
<span class="value" id="fontSizeValue" aria-hidden="true"></span>
|
|
146
|
-
</div>
|
|
147
|
-
|
|
148
|
-
<input
|
|
149
|
-
type="range"
|
|
150
|
-
id="fontSize"
|
|
151
|
-
min="12"
|
|
152
|
-
max="60"
|
|
153
|
-
value="24"
|
|
154
|
-
aria-valuemin="12"
|
|
155
|
-
aria-valuemax="60"
|
|
156
|
-
aria-valuenow="24"
|
|
157
|
-
aria-labelledby="labelFontSize"
|
|
158
|
-
>
|
|
159
|
-
</div>
|
|
160
|
-
|
|
161
|
-
<div class="group" id="groupLetterSpacing" role="group" aria-labelledby="labelLetterSpacing">
|
|
162
|
-
<div class="label-row">
|
|
163
|
-
<label id="labelLetterSpacing" for="letterSpacing">Letter spacing</label>
|
|
164
|
-
<span class="value" id="letterSpacingValue" aria-hidden="true"></span>
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<input
|
|
168
|
-
type="range"
|
|
169
|
-
id="letterSpacing"
|
|
170
|
-
min="0"
|
|
171
|
-
max="20"
|
|
172
|
-
value="0"
|
|
173
|
-
aria-valuemin="0"
|
|
174
|
-
aria-valuemax="20"
|
|
175
|
-
aria-valuenow="0"
|
|
176
|
-
aria-labelledby="labelLetterSpacing"
|
|
177
|
-
>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<div class="group" id="groupWordSpacing" role="group" aria-labelledby="labelWordSpacing">
|
|
181
|
-
<div class="label-row">
|
|
182
|
-
<label id="labelWordSpacing" for="wordSpacing">Word spacing</label>
|
|
183
|
-
<span class="value" id="wordSpacingValue" aria-hidden="true"></span>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
<input
|
|
187
|
-
type="range"
|
|
188
|
-
id="wordSpacing"
|
|
189
|
-
min="0"
|
|
190
|
-
max="40"
|
|
191
|
-
value="0"
|
|
192
|
-
aria-valuemin="0"
|
|
193
|
-
aria-valuemax="40"
|
|
194
|
-
aria-valuenow="0"
|
|
195
|
-
aria-labelledby="labelWordSpacing"
|
|
196
|
-
>
|
|
197
|
-
</div>
|
|
198
|
-
|
|
199
|
-
<div class="group" id="groupLineHeight" role="group" aria-labelledby="labelLineHeight">
|
|
200
|
-
<div class="label-row">
|
|
201
|
-
<label id="labelLineHeight" for="lineHeight">Line height</label>
|
|
202
|
-
<span class="value" id="lineHeightValue" aria-hidden="true"></span>
|
|
203
|
-
</div>
|
|
204
|
-
|
|
205
|
-
<input
|
|
206
|
-
type="range"
|
|
207
|
-
id="lineHeight"
|
|
208
|
-
min="1"
|
|
209
|
-
max="3"
|
|
210
|
-
step="0.1"
|
|
211
|
-
value="1.5"
|
|
212
|
-
aria-valuemin="1"
|
|
213
|
-
aria-valuemax="3"
|
|
214
|
-
aria-valuenow="1.5"
|
|
215
|
-
aria-labelledby="labelLineHeight"
|
|
216
|
-
>
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
<div class="group" id="groupContrast" role="group" aria-labelledby="labelContrast">
|
|
220
|
-
<div class="label-row">
|
|
221
|
-
<label id="labelContrast" for="contrast">Contrast</label>
|
|
222
|
-
<span class="value" id="contrastValue" aria-hidden="true"></span>
|
|
223
|
-
</div>
|
|
224
|
-
|
|
225
|
-
<input
|
|
226
|
-
type="range"
|
|
227
|
-
id="contrast"
|
|
228
|
-
min="50"
|
|
229
|
-
max="200"
|
|
230
|
-
value="100"
|
|
231
|
-
aria-valuemin="50"
|
|
232
|
-
aria-valuemax="200"
|
|
233
|
-
aria-valuenow="100"
|
|
234
|
-
aria-labelledby="labelContrast"
|
|
235
|
-
>
|
|
236
|
-
</div>
|
|
237
|
-
|
|
238
|
-
<div class="group" id="groupFontFamily" role="group" aria-labelledby="labelFontFamily">
|
|
239
|
-
<div class="label-row">
|
|
240
|
-
<label id="labelFontFamily" for="fontFamily">Font family</label>
|
|
241
|
-
</div>
|
|
242
|
-
|
|
243
|
-
<select id="fontFamily" aria-labelledby="labelFontFamily">
|
|
244
|
-
<option value="system-ui, sans-serif">System</option>
|
|
245
|
-
<option value="Georgia, serif">Serif</option>
|
|
246
|
-
<option value="'Courier New', monospace">Monospace</option>
|
|
247
|
-
<option value="Verdana, sans-serif">Verdana</option>
|
|
248
|
-
<option value="inherit">Inherit</option>
|
|
249
|
-
</select>
|
|
250
|
-
</div>
|
|
16
|
+
<style>${css}</style>
|
|
17
|
+
${html}
|
|
251
18
|
`;
|
|
252
|
-
}
|
|
253
19
|
|
|
254
|
-
|
|
20
|
+
// 3. Now safe to query elements
|
|
255
21
|
this.targetSelector = this.getAttribute("target");
|
|
256
22
|
|
|
257
|
-
//
|
|
23
|
+
// Feature toggles
|
|
258
24
|
this.toggleGroup("#groupLetterSpacing", !this.hasAttribute("hide-letter-spacing"));
|
|
259
25
|
this.toggleGroup("#groupWordSpacing", !this.hasAttribute("hide-word-spacing"));
|
|
260
26
|
this.toggleGroup("#groupLineHeight", !this.hasAttribute("hide-line-height"));
|
|
261
27
|
this.toggleGroup("#groupContrast", !this.hasAttribute("hide-contrast"));
|
|
28
|
+
this.toggleGroup("#groupFamily", !this.hasAttribute("hide-font-family"));
|
|
262
29
|
|
|
263
|
-
// Query
|
|
30
|
+
// Query sliders
|
|
264
31
|
this.fontSize = this.shadowRoot.querySelector("#fontSize");
|
|
265
32
|
this.letterSpacing = this.shadowRoot.querySelector("#letterSpacing");
|
|
266
33
|
this.wordSpacing = this.shadowRoot.querySelector("#wordSpacing");
|
|
267
34
|
this.lineHeight = this.shadowRoot.querySelector("#lineHeight");
|
|
268
35
|
this.contrast = this.shadowRoot.querySelector("#contrast");
|
|
269
36
|
this.fontFamily = this.shadowRoot.querySelector("#fontFamily");
|
|
270
|
-
|
|
37
|
+
|
|
38
|
+
// Auto-detect font family
|
|
271
39
|
const target = this.targetElement;
|
|
272
40
|
if (target) {
|
|
273
41
|
const computed = getComputedStyle(target).fontFamily;
|
|
274
42
|
this.fontFamily.value = computed;
|
|
275
43
|
}
|
|
276
44
|
|
|
277
|
-
|
|
45
|
+
// Query value labels
|
|
278
46
|
this.fontSizeValue = this.shadowRoot.querySelector("#fontSizeValue");
|
|
279
47
|
this.letterSpacingValue = this.shadowRoot.querySelector("#letterSpacingValue");
|
|
280
48
|
this.wordSpacingValue = this.shadowRoot.querySelector("#wordSpacingValue");
|
|
281
49
|
this.lineHeightValue = this.shadowRoot.querySelector("#lineHeightValue");
|
|
282
50
|
this.contrastValue = this.shadowRoot.querySelector("#contrastValue");
|
|
283
51
|
|
|
52
|
+
// 4. Bind value ranges
|
|
53
|
+
this.applyRange(this.fontSize, "font-size-min", "font-size-max");
|
|
54
|
+
this.applyRange(this.letterSpacing, "letter-spacing-min", "letter-spacing-max");
|
|
55
|
+
this.applyRange(this.wordSpacing, "word-spacing-min", "word-spacing-max");
|
|
56
|
+
this.applyRange(this.lineHeight, "line-height-min", "line-height-max");
|
|
57
|
+
this.applyRange(this.contrast, "contrast-min", "contrast-max");
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
// Event handler
|
|
284
61
|
const updateAndEmit = () => {
|
|
285
62
|
this.update();
|
|
286
63
|
this.dispatchEvent(
|
|
@@ -292,6 +69,7 @@ class TypographyController extends HTMLElement {
|
|
|
292
69
|
);
|
|
293
70
|
};
|
|
294
71
|
|
|
72
|
+
// Bind events
|
|
295
73
|
this.fontSize.addEventListener("input", updateAndEmit);
|
|
296
74
|
this.letterSpacing.addEventListener("input", updateAndEmit);
|
|
297
75
|
this.wordSpacing.addEventListener("input", updateAndEmit);
|
|
@@ -299,6 +77,14 @@ class TypographyController extends HTMLElement {
|
|
|
299
77
|
this.contrast.addEventListener("input", updateAndEmit);
|
|
300
78
|
this.fontFamily.addEventListener("change", updateAndEmit);
|
|
301
79
|
|
|
80
|
+
this.bindSlider(this.fontSize, this.fontSizeValue, "Font size");
|
|
81
|
+
this.bindSlider(this.letterSpacing, this.letterSpacingValue, "Letter spacing");
|
|
82
|
+
this.bindSlider(this.wordSpacing, this.wordSpacingValue, "Word spacing");
|
|
83
|
+
this.bindSlider(this.lineHeight, this.lineHeightValue, "Line height");
|
|
84
|
+
this.bindSlider(this.contrast, this.contrastValue, "Contrast");
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
// Initial update
|
|
302
88
|
this.update();
|
|
303
89
|
}
|
|
304
90
|
|
|
@@ -341,13 +127,14 @@ class TypographyController extends HTMLElement {
|
|
|
341
127
|
}
|
|
342
128
|
|
|
343
129
|
setValues(values = {}) {
|
|
344
|
-
|
|
345
130
|
if (values.fontSize !== undefined) this.fontSize.value = values.fontSize;
|
|
346
131
|
if (values.letterSpacing !== undefined) this.letterSpacing.value = values.letterSpacing;
|
|
347
132
|
if (values.wordSpacing !== undefined) this.wordSpacing.value = values.wordSpacing;
|
|
348
133
|
if (values.lineHeight !== undefined) this.lineHeight.value = values.lineHeight;
|
|
349
134
|
if (values.contrast !== undefined) this.contrast.value = values.contrast;
|
|
135
|
+
|
|
350
136
|
if (values.fontFamily !== undefined) {
|
|
137
|
+
const target = this.targetElement;
|
|
351
138
|
if (values.fontFamily === "inherit" && target) {
|
|
352
139
|
const computed = getComputedStyle(target).fontFamily;
|
|
353
140
|
this.fontFamily.value = computed;
|
|
@@ -356,7 +143,6 @@ class TypographyController extends HTMLElement {
|
|
|
356
143
|
}
|
|
357
144
|
}
|
|
358
145
|
|
|
359
|
-
|
|
360
146
|
this.update();
|
|
361
147
|
}
|
|
362
148
|
|
|
@@ -388,7 +174,54 @@ class TypographyController extends HTMLElement {
|
|
|
388
174
|
? this.removeAttribute("hide-contrast")
|
|
389
175
|
: this.setAttribute("hide-contrast", "");
|
|
390
176
|
}
|
|
177
|
+
if (features.fontFamily !== undefined) {
|
|
178
|
+
this.toggleGroup("#groupFontFamily", features.fontFamily);
|
|
179
|
+
features.fontFamily
|
|
180
|
+
? this.removeAttribute("hide-font-family")
|
|
181
|
+
: this.setAttribute("hide-font-family", "");
|
|
182
|
+
}
|
|
391
183
|
}
|
|
184
|
+
|
|
185
|
+
bindSlider(slider, valueEl, labelText) {
|
|
186
|
+
// Initialize visible value
|
|
187
|
+
valueEl.textContent = slider.value;
|
|
188
|
+
|
|
189
|
+
slider.addEventListener("input", () => {
|
|
190
|
+
const val = slider.value;
|
|
191
|
+
|
|
192
|
+
// Update visible value
|
|
193
|
+
valueEl.textContent = val;
|
|
194
|
+
|
|
195
|
+
// Update ARIA so NVDA knows the value changed
|
|
196
|
+
slider.setAttribute("aria-valuenow", val);
|
|
197
|
+
|
|
198
|
+
// Emit your existing event
|
|
199
|
+
this.update();
|
|
200
|
+
this.dispatchEvent(
|
|
201
|
+
new CustomEvent("change", {
|
|
202
|
+
detail: this.getValues(),
|
|
203
|
+
bubbles: true,
|
|
204
|
+
composed: true
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
applyRange(slider, attrMin, attrMax) {
|
|
211
|
+
const min = this.getAttribute(attrMin);
|
|
212
|
+
const max = this.getAttribute(attrMax);
|
|
213
|
+
|
|
214
|
+
if (min !== null) {
|
|
215
|
+
slider.min = min;
|
|
216
|
+
slider.setAttribute("aria-valuemin", min);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (max !== null) {
|
|
220
|
+
slider.max = max;
|
|
221
|
+
slider.setAttribute("aria-valuemax", max);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
392
225
|
}
|
|
393
226
|
|
|
394
|
-
customElements.define("typography-controller", TypographyController);
|
|
227
|
+
customElements.define("typography-controller", TypographyController);
|