fontdue-js 3.9.0 → 3.10.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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## 3.10.0
2
+
3
+ - The `StoreModal`’s browse page leaves out an unlisted family, and lists an unlisted superfamily’s families in its place, each opening the superfamily’s page. Unlisted font packs are left out of the browse page too.
4
+ - Checkboxes are 20px by default, down from 40px on the `TestFontsForm`, `NewsletterSignup` and license agreement checkboxes. Set `--checkbox-size: 40px` and `--checkbox-margin: 20px` to keep the larger box.
5
+ - Fixed a type tester with a `truncate` line cap cutting through a line, or showing one line too few, in Safari before 26.1. The checkbox size and this fix ship as stylesheet rules, so take `dist/fontdue.css` from this version alongside the JS.
6
+
1
7
  ## 3.9.0
2
8
 
3
9
  - `TestFontsForm` can let the visitor choose which families to download. With *Customer’s choice* set under *Settings → Test fonts* – or `testFonts: { familySelection: "choice" }` in the config, or the `familySelection` prop (`family-selection` on `<fontdue-test-fonts-form>`) – the form lists the families with a checkbox each plus *Select all*, and the download holds only the ticked ones. Ships new stylesheet rules, so take `dist/fontdue.css` from this version alongside the JS.
@@ -1,14 +1,22 @@
1
1
  /**
2
- * @generated SignedSource<<9634241d4df0b0b783ac8e970e99b739>>
2
+ * @generated SignedSource<<82fd75aeba65ed2ecef2a5bb7ff865dc>>
3
3
  * @lightSyntaxTransform
4
4
  * @nogrep
5
5
  */
6
6
  import { ReaderFragment } from 'relay-runtime';
7
+ export type Visibility = "HIDDEN" | "UNLISTED" | "VISIBLE" | "%future added value";
7
8
  import { FragmentRefs } from "relay-runtime";
8
9
  export type StoreModalIndexItem_fontCollection$data = {
9
10
  readonly children: ReadonlyArray<{
11
+ readonly featureStyle: {
12
+ readonly supportedLanguages: ReadonlyArray<string> | null;
13
+ readonly " $fragmentSpreads": FragmentRefs<"FontStyle_fontStyle">;
14
+ } | null;
15
+ readonly id: string;
10
16
  readonly isVariableFont: boolean;
17
+ readonly name: string;
11
18
  readonly totalStyles: number | null;
19
+ readonly visibility: Visibility;
12
20
  }> | null;
13
21
  readonly collectionType: string;
14
22
  readonly featureStyle: {
@@ -19,6 +27,7 @@ export type StoreModalIndexItem_fontCollection$data = {
19
27
  readonly isVariableFont: boolean;
20
28
  readonly name: string;
21
29
  readonly totalStyles: number | null;
30
+ readonly visibility: Visibility;
22
31
  readonly " $fragmentSpreads": FragmentRefs<"useTotalStyles_fontCollection">;
23
32
  readonly " $fragmentType": "StoreModalIndexItem_fontCollection";
24
33
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @generated SignedSource<<9634241d4df0b0b783ac8e970e99b739>>
2
+ * @generated SignedSource<<82fd75aeba65ed2ecef2a5bb7ff865dc>>
3
3
  * @lightSyntaxTransform
4
4
  * @nogrep
5
5
  */
@@ -13,57 +13,38 @@ const node = function () {
13
13
  "alias": null,
14
14
  "args": null,
15
15
  "kind": "ScalarField",
16
- "name": "totalStyles",
16
+ "name": "id",
17
17
  "storageKey": null
18
18
  },
19
19
  v1 = {
20
20
  "alias": null,
21
21
  "args": null,
22
22
  "kind": "ScalarField",
23
- "name": "isVariableFont",
23
+ "name": "name",
24
24
  "storageKey": null
25
- };
26
- return {
27
- "argumentDefinitions": [],
28
- "kind": "Fragment",
29
- "metadata": null,
30
- "name": "StoreModalIndexItem_fontCollection",
31
- "selections": [{
32
- "args": null,
33
- "kind": "FragmentSpread",
34
- "name": "useTotalStyles_fontCollection"
35
- }, {
25
+ },
26
+ v2 = {
36
27
  "alias": null,
37
28
  "args": null,
38
29
  "kind": "ScalarField",
39
- "name": "id",
30
+ "name": "visibility",
40
31
  "storageKey": null
41
- }, {
32
+ },
33
+ v3 = {
42
34
  "alias": null,
43
35
  "args": null,
44
36
  "kind": "ScalarField",
45
- "name": "name",
37
+ "name": "totalStyles",
46
38
  "storageKey": null
47
- }, v0 /*: any*/, v1 /*: any*/, {
48
- "alias": null,
49
- "args": [{
50
- "kind": "Literal",
51
- "name": "collectionTypes",
52
- "value": ["FAMILY"]
53
- }],
54
- "concreteType": "FontCollection",
55
- "kind": "LinkedField",
56
- "name": "children",
57
- "plural": true,
58
- "selections": [v1 /*: any*/, v0 /*: any*/],
59
- "storageKey": "children(collectionTypes:[\"FAMILY\"])"
60
- }, {
39
+ },
40
+ v4 = {
61
41
  "alias": null,
62
42
  "args": null,
63
43
  "kind": "ScalarField",
64
- "name": "collectionType",
44
+ "name": "isVariableFont",
65
45
  "storageKey": null
66
- }, {
46
+ },
47
+ v5 = {
67
48
  "alias": null,
68
49
  "args": null,
69
50
  "concreteType": "FontStyle",
@@ -82,10 +63,39 @@ const node = function () {
82
63
  "storageKey": null
83
64
  }],
84
65
  "storageKey": null
85
- }],
66
+ };
67
+ return {
68
+ "argumentDefinitions": [],
69
+ "kind": "Fragment",
70
+ "metadata": null,
71
+ "name": "StoreModalIndexItem_fontCollection",
72
+ "selections": [{
73
+ "args": null,
74
+ "kind": "FragmentSpread",
75
+ "name": "useTotalStyles_fontCollection"
76
+ }, v0 /*: any*/, v1 /*: any*/, v2 /*: any*/, v3 /*: any*/, v4 /*: any*/, {
77
+ "alias": null,
78
+ "args": [{
79
+ "kind": "Literal",
80
+ "name": "collectionTypes",
81
+ "value": ["FAMILY"]
82
+ }],
83
+ "concreteType": "FontCollection",
84
+ "kind": "LinkedField",
85
+ "name": "children",
86
+ "plural": true,
87
+ "selections": [v0 /*: any*/, v1 /*: any*/, v2 /*: any*/, v4 /*: any*/, v3 /*: any*/, v5 /*: any*/],
88
+ "storageKey": "children(collectionTypes:[\"FAMILY\"])"
89
+ }, {
90
+ "alias": null,
91
+ "args": null,
92
+ "kind": "ScalarField",
93
+ "name": "collectionType",
94
+ "storageKey": null
95
+ }, v5 /*: any*/],
86
96
  "type": "FontCollection",
87
97
  "abstractKey": null
88
98
  };
89
99
  }();
90
- node.hash = "8a990fad8dc50c9f00b391902e9bc482";
100
+ node.hash = "46573dcfb540ddfba2e28144704bd554";
91
101
  export default node;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @generated SignedSource<<b1b0a9eafb6bdfcac8c3a24fa8fe27cc>>
2
+ * @generated SignedSource<<b055d86d719cd9b0a3437468710929c0>>
3
3
  * @lightSyntaxTransform
4
4
  * @nogrep
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @generated SignedSource<<b1b0a9eafb6bdfcac8c3a24fa8fe27cc>>
2
+ * @generated SignedSource<<b055d86d719cd9b0a3437468710929c0>>
3
3
  * @lightSyntaxTransform
4
4
  * @nogrep
5
5
  */
@@ -67,6 +67,101 @@ const node = function () {
67
67
  "kind": "ScalarField",
68
68
  "name": "name",
69
69
  "storageKey": null
70
+ },
71
+ v7 = {
72
+ "alias": null,
73
+ "args": null,
74
+ "kind": "ScalarField",
75
+ "name": "visibility",
76
+ "storageKey": null
77
+ },
78
+ v8 = {
79
+ "alias": null,
80
+ "args": null,
81
+ "concreteType": "FontStyle",
82
+ "kind": "LinkedField",
83
+ "name": "featureStyle",
84
+ "plural": false,
85
+ "selections": [{
86
+ "alias": null,
87
+ "args": null,
88
+ "kind": "ScalarField",
89
+ "name": "cssFamily",
90
+ "storageKey": null
91
+ }, v6 /*: any*/, {
92
+ "alias": null,
93
+ "args": null,
94
+ "concreteType": "WebfontSource",
95
+ "kind": "LinkedField",
96
+ "name": "webfontSources",
97
+ "plural": true,
98
+ "selections": [{
99
+ "alias": null,
100
+ "args": null,
101
+ "kind": "ScalarField",
102
+ "name": "url",
103
+ "storageKey": null
104
+ }, {
105
+ "alias": null,
106
+ "args": null,
107
+ "kind": "ScalarField",
108
+ "name": "format",
109
+ "storageKey": null
110
+ }, {
111
+ "alias": null,
112
+ "args": null,
113
+ "kind": "ScalarField",
114
+ "name": "tech",
115
+ "storageKey": null
116
+ }],
117
+ "storageKey": null
118
+ }, {
119
+ "alias": null,
120
+ "args": null,
121
+ "concreteType": "VerticalMetrics",
122
+ "kind": "LinkedField",
123
+ "name": "verticalMetrics",
124
+ "plural": false,
125
+ "selections": [{
126
+ "alias": null,
127
+ "args": null,
128
+ "kind": "ScalarField",
129
+ "name": "unitsPerEm",
130
+ "storageKey": null
131
+ }, {
132
+ "alias": null,
133
+ "args": null,
134
+ "kind": "ScalarField",
135
+ "name": "ascender",
136
+ "storageKey": null
137
+ }, {
138
+ "alias": null,
139
+ "args": null,
140
+ "kind": "ScalarField",
141
+ "name": "descender",
142
+ "storageKey": null
143
+ }, {
144
+ "alias": null,
145
+ "args": null,
146
+ "kind": "ScalarField",
147
+ "name": "lineGap",
148
+ "storageKey": null
149
+ }, {
150
+ "alias": null,
151
+ "args": null,
152
+ "kind": "ScalarField",
153
+ "name": "avgCharWidth",
154
+ "storageKey": null
155
+ }],
156
+ "storageKey": null
157
+ }, {
158
+ "alias": null,
159
+ "args": null,
160
+ "kind": "ScalarField",
161
+ "name": "supportedLanguages",
162
+ "storageKey": null
163
+ }, v3 /*: any*/],
164
+ "storageKey": null
70
165
  };
71
166
  return {
72
167
  "fragment": {
@@ -143,102 +238,15 @@ const node = function () {
143
238
  "kind": "LinkedField",
144
239
  "name": "children",
145
240
  "plural": true,
146
- "selections": [v4 /*: any*/, v5 /*: any*/, v3 /*: any*/],
241
+ "selections": [v4 /*: any*/, v5 /*: any*/, v3 /*: any*/, v6 /*: any*/, v7 /*: any*/, v8 /*: any*/],
147
242
  "storageKey": "children(collectionTypes:[\"FAMILY\"])"
148
- }, v6 /*: any*/, {
243
+ }, v6 /*: any*/, v7 /*: any*/, {
149
244
  "alias": null,
150
245
  "args": null,
151
246
  "kind": "ScalarField",
152
247
  "name": "collectionType",
153
248
  "storageKey": null
154
- }, {
155
- "alias": null,
156
- "args": null,
157
- "concreteType": "FontStyle",
158
- "kind": "LinkedField",
159
- "name": "featureStyle",
160
- "plural": false,
161
- "selections": [{
162
- "alias": null,
163
- "args": null,
164
- "kind": "ScalarField",
165
- "name": "cssFamily",
166
- "storageKey": null
167
- }, v6 /*: any*/, {
168
- "alias": null,
169
- "args": null,
170
- "concreteType": "WebfontSource",
171
- "kind": "LinkedField",
172
- "name": "webfontSources",
173
- "plural": true,
174
- "selections": [{
175
- "alias": null,
176
- "args": null,
177
- "kind": "ScalarField",
178
- "name": "url",
179
- "storageKey": null
180
- }, {
181
- "alias": null,
182
- "args": null,
183
- "kind": "ScalarField",
184
- "name": "format",
185
- "storageKey": null
186
- }, {
187
- "alias": null,
188
- "args": null,
189
- "kind": "ScalarField",
190
- "name": "tech",
191
- "storageKey": null
192
- }],
193
- "storageKey": null
194
- }, {
195
- "alias": null,
196
- "args": null,
197
- "concreteType": "VerticalMetrics",
198
- "kind": "LinkedField",
199
- "name": "verticalMetrics",
200
- "plural": false,
201
- "selections": [{
202
- "alias": null,
203
- "args": null,
204
- "kind": "ScalarField",
205
- "name": "unitsPerEm",
206
- "storageKey": null
207
- }, {
208
- "alias": null,
209
- "args": null,
210
- "kind": "ScalarField",
211
- "name": "ascender",
212
- "storageKey": null
213
- }, {
214
- "alias": null,
215
- "args": null,
216
- "kind": "ScalarField",
217
- "name": "descender",
218
- "storageKey": null
219
- }, {
220
- "alias": null,
221
- "args": null,
222
- "kind": "ScalarField",
223
- "name": "lineGap",
224
- "storageKey": null
225
- }, {
226
- "alias": null,
227
- "args": null,
228
- "kind": "ScalarField",
229
- "name": "avgCharWidth",
230
- "storageKey": null
231
- }],
232
- "storageKey": null
233
- }, {
234
- "alias": null,
235
- "args": null,
236
- "kind": "ScalarField",
237
- "name": "supportedLanguages",
238
- "storageKey": null
239
- }, v3 /*: any*/],
240
- "storageKey": null
241
- }, {
249
+ }, v8 /*: any*/, {
242
250
  "alias": null,
243
251
  "args": null,
244
252
  "kind": "ScalarField",
@@ -290,12 +298,12 @@ const node = function () {
290
298
  }]
291
299
  },
292
300
  "params": {
293
- "cacheID": "822799800d507e869328896c0b5a1845",
301
+ "cacheID": "cf465f13ec74bf1c500a9104871c2cd5",
294
302
  "id": null,
295
303
  "metadata": {},
296
304
  "name": "StoreModalIndexPaginationQuery",
297
305
  "operationKind": "query",
298
- "text": "query StoreModalIndexPaginationQuery(\n $count: Int = 25\n $cursor: String = null\n $excludeTags: [String!] = null\n) {\n viewer {\n ...StoreModalIndex_viewer_3217ho\n id\n }\n}\n\nfragment FontStyle_fontStyle on FontStyle {\n ...useFontStyle_fontStyle\n}\n\nfragment StoreModalIndexItem_fontCollection on FontCollection {\n ...useTotalStyles_fontCollection\n id\n name\n totalStyles\n isVariableFont\n children(collectionTypes: [FAMILY]) {\n isVariableFont\n totalStyles\n id\n }\n collectionType\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n}\n\nfragment StoreModalIndex_viewer_3217ho on Viewer {\n rootCollections: fontCollections(onlyRoots: true, first: $count, after: $cursor, excludeTags: $excludeTags) {\n edges {\n node {\n id\n ...StoreModalIndexItem_fontCollection\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment useFontStyle_fontStyle on FontStyle {\n cssFamily\n name\n webfontSources {\n url\n format\n tech\n }\n verticalMetrics {\n unitsPerEm\n ascender\n descender\n lineGap\n avgCharWidth\n }\n}\n\nfragment useTotalStyles_fontCollection on FontCollection {\n isVariableFont\n totalStyles\n children(collectionTypes: [FAMILY]) {\n isVariableFont\n totalStyles\n id\n }\n}\n"
306
+ "text": "query StoreModalIndexPaginationQuery(\n $count: Int = 25\n $cursor: String = null\n $excludeTags: [String!] = null\n) {\n viewer {\n ...StoreModalIndex_viewer_3217ho\n id\n }\n}\n\nfragment FontStyle_fontStyle on FontStyle {\n ...useFontStyle_fontStyle\n}\n\nfragment StoreModalIndexItem_fontCollection on FontCollection {\n ...useTotalStyles_fontCollection\n id\n name\n visibility\n totalStyles\n isVariableFont\n children(collectionTypes: [FAMILY]) {\n id\n name\n visibility\n isVariableFont\n totalStyles\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n }\n collectionType\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n}\n\nfragment StoreModalIndex_viewer_3217ho on Viewer {\n rootCollections: fontCollections(onlyRoots: true, first: $count, after: $cursor, excludeTags: $excludeTags) {\n edges {\n node {\n id\n ...StoreModalIndexItem_fontCollection\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment useFontStyle_fontStyle on FontStyle {\n cssFamily\n name\n webfontSources {\n url\n format\n tech\n }\n verticalMetrics {\n unitsPerEm\n ascender\n descender\n lineGap\n avgCharWidth\n }\n}\n\nfragment useTotalStyles_fontCollection on FontCollection {\n isVariableFont\n totalStyles\n children(collectionTypes: [FAMILY]) {\n isVariableFont\n totalStyles\n id\n }\n}\n"
299
307
  }
300
308
  };
301
309
  }();
@@ -1,10 +1,11 @@
1
1
  /**
2
- * @generated SignedSource<<5499691b7a86b4a28f1caa8d610d54fe>>
2
+ * @generated SignedSource<<c20392d6b43531f66af4e1a04ca5bc39>>
3
3
  * @lightSyntaxTransform
4
4
  * @nogrep
5
5
  */
6
6
  import { ConcreteRequest } from 'relay-runtime';
7
7
  import { FragmentRefs } from "relay-runtime";
8
+ export type Visibility = "HIDDEN" | "UNLISTED" | "VISIBLE" | "%future added value";
8
9
  export type StoreModalIndexQuery$variables = {
9
10
  count?: number | null;
10
11
  cursor?: string | null;
@@ -16,6 +17,7 @@ export type StoreModalIndexQuery$data = {
16
17
  readonly edges: ReadonlyArray<{
17
18
  readonly node: {
18
19
  readonly id: string;
20
+ readonly visibility: Visibility;
19
21
  readonly " $fragmentSpreads": FragmentRefs<"StoreModalIndexPackItem_fontPack">;
20
22
  } | null;
21
23
  } | null> | null;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @generated SignedSource<<5499691b7a86b4a28f1caa8d610d54fe>>
2
+ * @generated SignedSource<<c20392d6b43531f66af4e1a04ca5bc39>>
3
3
  * @lightSyntaxTransform
4
4
  * @nogrep
5
5
  */
@@ -45,17 +45,24 @@ const node = function () {
45
45
  "alias": null,
46
46
  "args": null,
47
47
  "kind": "ScalarField",
48
- "name": "name",
48
+ "name": "visibility",
49
49
  "storageKey": null
50
50
  },
51
51
  v7 = {
52
52
  "alias": null,
53
53
  "args": null,
54
54
  "kind": "ScalarField",
55
- "name": "totalStyles",
55
+ "name": "name",
56
56
  "storageKey": null
57
57
  },
58
58
  v8 = {
59
+ "alias": null,
60
+ "args": null,
61
+ "kind": "ScalarField",
62
+ "name": "totalStyles",
63
+ "storageKey": null
64
+ },
65
+ v9 = {
59
66
  "alias": null,
60
67
  "args": null,
61
68
  "concreteType": "FontStyle",
@@ -68,7 +75,7 @@ const node = function () {
68
75
  "kind": "ScalarField",
69
76
  "name": "cssFamily",
70
77
  "storageKey": null
71
- }, v6 /*: any*/, {
78
+ }, v7 /*: any*/, {
72
79
  "alias": null,
73
80
  "args": null,
74
81
  "concreteType": "WebfontSource",
@@ -143,7 +150,7 @@ const node = function () {
143
150
  }, v5 /*: any*/],
144
151
  "storageKey": null
145
152
  },
146
- v9 = [{
153
+ v10 = [{
147
154
  "kind": "Variable",
148
155
  "name": "after",
149
156
  "variableName": "cursor"
@@ -156,7 +163,7 @@ const node = function () {
156
163
  "name": "onlyRoots",
157
164
  "value": true
158
165
  }],
159
- v10 = {
166
+ v11 = {
160
167
  "alias": null,
161
168
  "args": null,
162
169
  "kind": "ScalarField",
@@ -197,7 +204,7 @@ const node = function () {
197
204
  "kind": "LinkedField",
198
205
  "name": "node",
199
206
  "plural": false,
200
- "selections": [v5 /*: any*/, {
207
+ "selections": [v5 /*: any*/, v6 /*: any*/, {
201
208
  "args": null,
202
209
  "kind": "FragmentSpread",
203
210
  "name": "StoreModalIndexPackItem_fontPack"
@@ -258,7 +265,7 @@ const node = function () {
258
265
  "kind": "LinkedField",
259
266
  "name": "node",
260
267
  "plural": false,
261
- "selections": [v5 /*: any*/, v6 /*: any*/, v7 /*: any*/, v8 /*: any*/],
268
+ "selections": [v5 /*: any*/, v6 /*: any*/, v7 /*: any*/, v8 /*: any*/, v9 /*: any*/],
262
269
  "storageKey": null
263
270
  }],
264
271
  "storageKey": null
@@ -266,7 +273,7 @@ const node = function () {
266
273
  "storageKey": null
267
274
  }, {
268
275
  "alias": "rootCollections",
269
- "args": v9 /*: any*/,
276
+ "args": v10 /*: any*/,
270
277
  "concreteType": "FontCollectionConnection",
271
278
  "kind": "LinkedField",
272
279
  "name": "fontCollections",
@@ -285,7 +292,7 @@ const node = function () {
285
292
  "kind": "LinkedField",
286
293
  "name": "node",
287
294
  "plural": false,
288
- "selections": [v5 /*: any*/, v10 /*: any*/, v7 /*: any*/, {
295
+ "selections": [v5 /*: any*/, v11 /*: any*/, v8 /*: any*/, {
289
296
  "alias": null,
290
297
  "args": [{
291
298
  "kind": "Literal",
@@ -296,15 +303,15 @@ const node = function () {
296
303
  "kind": "LinkedField",
297
304
  "name": "children",
298
305
  "plural": true,
299
- "selections": [v10 /*: any*/, v7 /*: any*/, v5 /*: any*/],
306
+ "selections": [v11 /*: any*/, v8 /*: any*/, v5 /*: any*/, v7 /*: any*/, v6 /*: any*/, v9 /*: any*/],
300
307
  "storageKey": "children(collectionTypes:[\"FAMILY\"])"
301
- }, v6 /*: any*/, {
308
+ }, v7 /*: any*/, v6 /*: any*/, {
302
309
  "alias": null,
303
310
  "args": null,
304
311
  "kind": "ScalarField",
305
312
  "name": "collectionType",
306
313
  "storageKey": null
307
- }, v8 /*: any*/, {
314
+ }, v9 /*: any*/, {
308
315
  "alias": null,
309
316
  "args": null,
310
317
  "kind": "ScalarField",
@@ -345,7 +352,7 @@ const node = function () {
345
352
  "storageKey": null
346
353
  }, {
347
354
  "alias": "rootCollections",
348
- "args": v9 /*: any*/,
355
+ "args": v10 /*: any*/,
349
356
  "filters": ["onlyRoots", "excludeTags"],
350
357
  "handle": "connection",
351
358
  "key": "StoreModalIndex_rootCollections",
@@ -356,14 +363,14 @@ const node = function () {
356
363
  }]
357
364
  },
358
365
  "params": {
359
- "cacheID": "fc6c3c60269ac58d7204476de4bae67b",
366
+ "cacheID": "176244d6e8b7a3a3ac4e184b362e4e85",
360
367
  "id": null,
361
368
  "metadata": {},
362
369
  "name": "StoreModalIndexQuery",
363
370
  "operationKind": "query",
364
- "text": "query StoreModalIndexQuery(\n $excludeTags: [String!]\n $count: Int = 25\n $cursor: String\n) {\n viewer {\n fontPacks(first: 9999, excludeTags: $excludeTags) {\n edges {\n node {\n id\n ...StoreModalIndexPackItem_fontPack\n }\n }\n }\n ...StoreModalIndex_viewer_3217ho\n id\n }\n}\n\nfragment FontStyle_fontStyle on FontStyle {\n ...useFontStyle_fontStyle\n}\n\nfragment StoreModalIndexItem_fontCollection on FontCollection {\n ...useTotalStyles_fontCollection\n id\n name\n totalStyles\n isVariableFont\n children(collectionTypes: [FAMILY]) {\n isVariableFont\n totalStyles\n id\n }\n collectionType\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n}\n\nfragment StoreModalIndexPackItem_fontPack on FontPack {\n id\n name\n totalStyles\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n}\n\nfragment StoreModalIndex_viewer_3217ho on Viewer {\n rootCollections: fontCollections(onlyRoots: true, first: $count, after: $cursor, excludeTags: $excludeTags) {\n edges {\n node {\n id\n ...StoreModalIndexItem_fontCollection\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment useFontStyle_fontStyle on FontStyle {\n cssFamily\n name\n webfontSources {\n url\n format\n tech\n }\n verticalMetrics {\n unitsPerEm\n ascender\n descender\n lineGap\n avgCharWidth\n }\n}\n\nfragment useTotalStyles_fontCollection on FontCollection {\n isVariableFont\n totalStyles\n children(collectionTypes: [FAMILY]) {\n isVariableFont\n totalStyles\n id\n }\n}\n"
371
+ "text": "query StoreModalIndexQuery(\n $excludeTags: [String!]\n $count: Int = 25\n $cursor: String\n) {\n viewer {\n fontPacks(first: 9999, excludeTags: $excludeTags) {\n edges {\n node {\n id\n visibility\n ...StoreModalIndexPackItem_fontPack\n }\n }\n }\n ...StoreModalIndex_viewer_3217ho\n id\n }\n}\n\nfragment FontStyle_fontStyle on FontStyle {\n ...useFontStyle_fontStyle\n}\n\nfragment StoreModalIndexItem_fontCollection on FontCollection {\n ...useTotalStyles_fontCollection\n id\n name\n visibility\n totalStyles\n isVariableFont\n children(collectionTypes: [FAMILY]) {\n id\n name\n visibility\n isVariableFont\n totalStyles\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n }\n collectionType\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n}\n\nfragment StoreModalIndexPackItem_fontPack on FontPack {\n id\n name\n totalStyles\n featureStyle {\n ...FontStyle_fontStyle\n supportedLanguages\n id\n }\n}\n\nfragment StoreModalIndex_viewer_3217ho on Viewer {\n rootCollections: fontCollections(onlyRoots: true, first: $count, after: $cursor, excludeTags: $excludeTags) {\n edges {\n node {\n id\n ...StoreModalIndexItem_fontCollection\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment useFontStyle_fontStyle on FontStyle {\n cssFamily\n name\n webfontSources {\n url\n format\n tech\n }\n verticalMetrics {\n unitsPerEm\n ascender\n descender\n lineGap\n avgCharWidth\n }\n}\n\nfragment useTotalStyles_fontCollection on FontCollection {\n isVariableFont\n totalStyles\n children(collectionTypes: [FAMILY]) {\n isVariableFont\n totalStyles\n id\n }\n}\n"
365
372
  }
366
373
  };
367
374
  }();
368
- node.hash = "cea53722e4ce3c40a68997218f7e979f";
375
+ node.hash = "13fce0376ef1b098e7f1f34dfdc7dad4";
369
376
  export default node;
@@ -0,0 +1,71 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ // The index lists root collections. An unlisted one isn't offered on its own
4
+ // (FD-1239): an unlisted family drops out, and an unlisted superfamily is
5
+ // replaced by its listed families, each opening the superfamily's page so a
6
+ // selection there still upgrades to it.
7
+
8
+ import React from 'react';
9
+ import { renderToStaticMarkup } from 'react-dom/server';
10
+ import { describe, expect, it, vi } from 'vitest';
11
+
12
+ // The fragment reader hands back the data it was given.
13
+ vi.mock('react-relay', () => ({
14
+ graphql: () => null,
15
+ useFragment: (_fragment, key) => key
16
+ }));
17
+
18
+ // Each entry renders what it links to, so the markup shows the navigation.
19
+ vi.mock('../components/StoreModal/StoreModalIndexEntry.js', () => ({
20
+ default: _ref => {
21
+ let {
22
+ productId,
23
+ name,
24
+ label
25
+ } = _ref;
26
+ return /*#__PURE__*/React.createElement("li", {
27
+ "data-product": productId
28
+ }, name, " (", label, ")");
29
+ }
30
+ }));
31
+ import StoreModalIndexItem from '../components/StoreModal/StoreModalIndexItem.js';
32
+ const family = function (name, visibility) {
33
+ let totalStyles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 4;
34
+ let isVariableFont = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
35
+ return {
36
+ id: `collection:${name}`,
37
+ name,
38
+ visibility,
39
+ collectionType: 'FAMILY',
40
+ isVariableFont,
41
+ totalStyles,
42
+ featureStyle: null,
43
+ children: []
44
+ };
45
+ };
46
+ const superfamily = (visibility, children) => ({
47
+ id: 'collection:Super',
48
+ name: 'Super',
49
+ visibility,
50
+ collectionType: 'SUPERFAMILY',
51
+ isVariableFont: false,
52
+ totalStyles: 10,
53
+ featureStyle: null,
54
+ children
55
+ });
56
+ const markup = collection => renderToStaticMarkup( /*#__PURE__*/React.createElement(StoreModalIndexItem, {
57
+ collection: collection
58
+ }));
59
+ describe('StoreModalIndexItem visibility', () => {
60
+ it('lists a visible superfamily as one entry', () => {
61
+ const html = markup(superfamily('VISIBLE', [family('Sans', 'VISIBLE')]));
62
+ expect(html).toBe('<li data-product="collection:Super">Super (10 styles)</li>');
63
+ });
64
+ it('leaves out an unlisted root family', () => {
65
+ expect(markup(family('Sans', 'UNLISTED'))).toBe('');
66
+ });
67
+ it('replaces an unlisted superfamily with its listed families, each opening the superfamily', () => {
68
+ const html = markup(superfamily('UNLISTED', [family('Sans', 'VISIBLE'), family('Serif', 'VISIBLE', 6), family('Sans Variable', 'UNLISTED', 2, true), family('Mono Variable', 'VISIBLE', 1, true)]));
69
+ expect(html).toBe('<li data-product="collection:Super">Sans (4 styles)</li>' + '<li data-product="collection:Super">Serif (6 styles)</li>' + '<li data-product="collection:Super">Mono Variable (1 variable font)</li>');
70
+ });
71
+ });
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi, afterEach } from 'vitest';
2
- import { normalizeTruncate, parseTruncateAttribute, shouldTruncate } from "../components/TypeTester/truncate.js";
2
+ import { normalizeTruncate, parseTruncateAttribute, shouldTruncate, truncateColumnStyle } from "../components/TypeTester/truncate.js";
3
3
  import { mergeConfig } from "../components/ConfigContext.js";
4
4
  describe('normalizeTruncate', () => {
5
5
  it('is off when unset or false', () => {
@@ -215,4 +215,74 @@ describe('mergeConfig with the object truncate form', () => {
215
215
  });
216
216
  expect((_merged$typeTester2 = merged.typeTester) === null || _merged$typeTester2 === void 0 ? void 0 : _merged$typeTester2.truncate).toBe(20);
217
217
  });
218
+ });
219
+
220
+ // The stylesheet carries the column-width that WebKit before Safari 26.1 needs
221
+ // to build a single column (FD-191); these pin what the inline style leaves
222
+ // for it to reach, and what it must never touch.
223
+ describe('truncateColumnStyle', () => {
224
+ it('is the bare single column with columns off', () => {
225
+ expect(truncateColumnStyle(false)).toEqual({
226
+ columnCount: 1
227
+ });
228
+ });
229
+ it('writes configured columns as they are', () => {
230
+ expect(truncateColumnStyle({
231
+ count: 3,
232
+ width: '20ch',
233
+ gap: '1em'
234
+ })).toEqual({
235
+ columnCount: 3,
236
+ columnWidth: '20ch',
237
+ columnGap: '1em'
238
+ });
239
+ expect(truncateColumnStyle({
240
+ count: 'auto',
241
+ width: '40ch',
242
+ gap: '1em'
243
+ })).toEqual({
244
+ columnCount: 'auto',
245
+ columnWidth: '40ch',
246
+ columnGap: '1em'
247
+ });
248
+ });
249
+ it('leaves the width off a configured single column with an auto width', () => {
250
+ expect(truncateColumnStyle({
251
+ count: 1,
252
+ width: 'auto',
253
+ gap: '1em'
254
+ })).toEqual({
255
+ columnCount: 1,
256
+ columnGap: '1em'
257
+ });
258
+ });
259
+
260
+ // A script-tag config is untyped JSON, so the count can arrive as a string
261
+ // and the width as an empty string.
262
+ it('reads a loosely typed single column the same way', () => {
263
+ const loose = {
264
+ count: '1',
265
+ width: '',
266
+ gap: '1em'
267
+ };
268
+ expect(truncateColumnStyle(loose)).toEqual({
269
+ columnCount: 1,
270
+ columnGap: '1em'
271
+ });
272
+ });
273
+
274
+ // With `column-count: auto` a 1px column-width would mean one column per
275
+ // pixel, so an auto count keeps its inline auto width, which the stylesheet
276
+ // cannot override.
277
+ it('keeps the auto width of an auto column count', () => {
278
+ expect(truncateColumnStyle({
279
+ count: 'auto',
280
+ width: 'auto',
281
+ gap: '1em'
282
+ })).toEqual({
283
+ columnCount: 'auto',
284
+ columnWidth: 'auto',
285
+ columnGap: '1em'
286
+ });
287
+ });
218
288
  });
@@ -29,7 +29,7 @@ const StoreModalIndex = _ref => {
29
29
  let {
30
30
  prepared
31
31
  } = _ref;
32
- const queryData = usePreloadedQuery((_StoreModalIndexQuery.hash && _StoreModalIndexQuery.hash !== "cea53722e4ce3c40a68997218f7e979f" && console.error("The definition of 'StoreModalIndexQuery' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _StoreModalIndexQuery), prepared.indexQuery);
32
+ const queryData = usePreloadedQuery((_StoreModalIndexQuery.hash && _StoreModalIndexQuery.hash !== "13fce0376ef1b098e7f1f34dfdc7dad4" && console.error("The definition of 'StoreModalIndexQuery' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _StoreModalIndexQuery), prepared.indexQuery);
33
33
 
34
34
  // The query type only carries the fragment spread, not its data type, so
35
35
  // both sides are named explicitly for `data` to be typed.
@@ -53,7 +53,13 @@ const StoreModalIndex = _ref => {
53
53
  rootRef: scrollContainer,
54
54
  rootMargin: LOAD_MORE_MARGIN
55
55
  });
56
- const packEdges = ((_queryData$viewer = queryData.viewer) === null || _queryData$viewer === void 0 ? void 0 : (_queryData$viewer$fon = _queryData$viewer.fontPacks) === null || _queryData$viewer$fon === void 0 ? void 0 : _queryData$viewer$fon.edges) ?? [];
56
+
57
+ // An unlisted pack is sold through its own Buy Button or page, not offered
58
+ // in the index; the API returns it so a site can build that page.
59
+ const packEdges = (((_queryData$viewer = queryData.viewer) === null || _queryData$viewer === void 0 ? void 0 : (_queryData$viewer$fon = _queryData$viewer.fontPacks) === null || _queryData$viewer$fon === void 0 ? void 0 : _queryData$viewer$fon.edges) ?? []).filter(edge => {
60
+ var _edge$node;
61
+ return (edge === null || edge === void 0 ? void 0 : (_edge$node = edge.node) === null || _edge$node === void 0 ? void 0 : _edge$node.visibility) !== 'UNLISTED';
62
+ });
57
63
  const edges = (data === null || data === void 0 ? void 0 : (_data$rootCollections = data.rootCollections) === null || _data$rootCollections === void 0 ? void 0 : _data$rootCollections.edges) ?? [];
58
64
  return /*#__PURE__*/React.createElement(StoreModalPageContainer, null, {
59
65
  body: /*#__PURE__*/React.createElement(React.Fragment, null, packEdges.map(edge => /*#__PURE__*/React.createElement(StoreModalIndexPackItem, {
@@ -3,5 +3,5 @@ import { StoreModalIndexItem_fontCollection$key } from '__generated__/StoreModal
3
3
  interface StoreModalIndexItem_props {
4
4
  collection: StoreModalIndexItem_fontCollection$key;
5
5
  }
6
- declare const StoreModalIndexItem: ({ collection }: StoreModalIndexItem_props) => React.JSX.Element;
6
+ declare const StoreModalIndexItem: ({ collection }: StoreModalIndexItem_props) => React.JSX.Element | null;
7
7
  export default StoreModalIndexItem;
@@ -4,29 +4,47 @@ import { graphql, useFragment } from 'react-relay';
4
4
  import StoreModalIndexEntry from './StoreModalIndexEntry.js';
5
5
  import useTotalStyles from '../useTotalStyles.js';
6
6
  import { pluralize } from '../../utils.js';
7
+ const styleLabel = (totalStyles, variableFonts) => {
8
+ const label = [];
9
+ if (totalStyles > 0) label.push(pluralize(totalStyles, 'style'));
10
+ if (variableFonts > 0) label.push(pluralize(variableFonts, 'variable font'));
11
+ return label.join(', ');
12
+ };
13
+
14
+ // One root collection on the index page. An unlisted collection isn't offered
15
+ // on its own (FD-1239), so it has no entry of its own here either: an unlisted
16
+ // family drops out, and an unlisted superfamily is replaced by its listed
17
+ // families. Those still open the superfamily's page, where selecting them
18
+ // upgrades to the superfamily.
7
19
  const StoreModalIndexItem = _ref => {
8
20
  let {
9
21
  collection
10
22
  } = _ref;
11
- const data = useFragment((_StoreModalIndexItem_fontCollection.hash && _StoreModalIndexItem_fontCollection.hash !== "8a990fad8dc50c9f00b391902e9bc482" && console.error("The definition of 'StoreModalIndexItem_fontCollection' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _StoreModalIndexItem_fontCollection), collection);
23
+ const data = useFragment((_StoreModalIndexItem_fontCollection.hash && _StoreModalIndexItem_fontCollection.hash !== "46573dcfb540ddfba2e28144704bd554" && console.error("The definition of 'StoreModalIndexItem_fontCollection' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _StoreModalIndexItem_fontCollection), collection);
12
24
  const {
13
25
  totalStyles,
14
26
  variableFonts
15
27
  } = useTotalStyles({
16
28
  fontCollection: data
17
29
  });
18
- let label = [];
19
- if (totalStyles > 0) {
20
- label.push(pluralize(totalStyles, 'style'));
21
- }
22
- if (variableFonts > 0) {
23
- label.push(pluralize(variableFonts, 'variable font'));
30
+ if (data.visibility === 'UNLISTED') {
31
+ if (data.collectionType === 'FAMILY') return null;
32
+ return /*#__PURE__*/React.createElement(React.Fragment, null, (data.children ?? []).filter(family => family.visibility !== 'UNLISTED').map(family => {
33
+ const styles = family.totalStyles ?? 0;
34
+ return /*#__PURE__*/React.createElement(StoreModalIndexEntry, {
35
+ key: family.id,
36
+ productId: data.id,
37
+ name: family.name,
38
+ featureStyle: family.featureStyle,
39
+ label: family.isVariableFont ? styleLabel(0, styles) : styleLabel(styles, 0)
40
+ });
41
+ }));
24
42
  }
25
43
  return /*#__PURE__*/React.createElement(StoreModalIndexEntry, {
26
44
  productId: data.id,
27
45
  name: data.name,
28
46
  featureStyle: data.featureStyle,
29
- label: label.join(', ')
47
+ label: styleLabel(totalStyles, variableFonts)
30
48
  });
31
49
  };
32
50
  export default StoreModalIndexItem;
@@ -10,3 +10,13 @@ export interface ResolvedTruncate {
10
10
  export declare const normalizeTruncate: (value?: TruncateOption) => ResolvedTruncate;
11
11
  export declare const shouldTruncate: ({ lines, expandOnFocus }: ResolvedTruncate, focused: boolean) => boolean;
12
12
  export declare const parseTruncateAttribute: (input: string | undefined, elementName: string) => TruncateOption | undefined;
13
+ export type ColumnsConfig = false | {
14
+ count: 'auto' | number;
15
+ width: string;
16
+ gap: string;
17
+ };
18
+ export declare const truncateColumnStyle: (columns: ColumnsConfig) => {
19
+ columnCount: "auto" | number;
20
+ columnWidth?: string;
21
+ columnGap?: string;
22
+ };
@@ -92,4 +92,35 @@ export const parseTruncateAttribute = (input, elementName) => {
92
92
  lines,
93
93
  expandOnFocus
94
94
  };
95
+ };
96
+ // The column declarations of a capped paragraph. Truncation lays the paragraph
97
+ // out as a single column whose overflow flows sideways, into clipped columns.
98
+ // With columns off that is a bare `column-count: 1`; WebKit before Safari 26.1
99
+ // builds no column for it, so the stylesheet adds the column-width those builds
100
+ // need (`[data-truncated]` in _type-tester.scss, FD-191). A configured single
101
+ // column with an auto width is written without its width for the same reason,
102
+ // so the stylesheet can reach it; the count is read loosely because a
103
+ // script-tag config arrives untyped. Everything else is written as configured,
104
+ // and an auto count keeps its auto width: 1px there would mean one column per
105
+ // pixel.
106
+ export const truncateColumnStyle = columns => {
107
+ if (!columns) return {
108
+ columnCount: 1
109
+ };
110
+ const {
111
+ count,
112
+ width,
113
+ gap
114
+ } = columns;
115
+ if (Number(count) === 1 && (!width || width === 'auto')) {
116
+ return {
117
+ columnCount: 1,
118
+ columnGap: gap
119
+ };
120
+ }
121
+ return {
122
+ columnCount: count,
123
+ columnWidth: width,
124
+ columnGap: gap
125
+ };
95
126
  };
@@ -2,12 +2,7 @@ import { EditorState } from 'draft-js';
2
2
  import { Alignment } from './types.js';
3
3
  import { VariableSettings } from '../../utils.js';
4
4
  import { VerticalMetrics } from '../useFontStyle.js';
5
- import { TruncateOption } from './truncate.js';
6
- export type ColumnsConfig = false | {
7
- count: 'auto' | number;
8
- width: string;
9
- gap: string;
10
- };
5
+ import { ColumnsConfig, TruncateOption } from './truncate.js';
11
6
  export interface UseTypeTesterStylerProps {
12
7
  autofit: boolean;
13
8
  autofitOnChange: boolean;
@@ -1,7 +1,7 @@
1
1
  import "../../global-shim.js";
2
2
  import { useLayoutEffect } from 'react';
3
3
  import useAutofit from '../../hooks/useAutofit.js';
4
- import { normalizeTruncate, shouldTruncate as resolveShouldTruncate } from './truncate.js';
4
+ import { normalizeTruncate, shouldTruncate as resolveShouldTruncate, truncateColumnStyle } from './truncate.js';
5
5
  const useTypeTesterStyler = _ref => {
6
6
  let {
7
7
  size,
@@ -86,12 +86,9 @@ const useTypeTesterStyler = _ref => {
86
86
  // is what lets the metric padding reveal descenders/ascenders cleanly, and it
87
87
  // means a multi-column tester (e.g. a 3-column specimen) truncates to
88
88
  // `truncateLines` lines *per column*. When truncating with columns disabled we
89
- // still establish a single column so the clipped overflow behaves the same way.
90
- const columnStyle = columns ? {
91
- columnCount: columns.count,
92
- columnWidth: columns.width,
93
- columnGap: columns.gap
94
- } : undefined;
89
+ // still establish a single column so the clipped overflow behaves the same way
90
+ // (truncateColumnStyle; WebKit before Safari 26.1 needs a stylesheet nudge to
91
+ // build that column, see `[data-truncated]` in _type-tester.scss, FD-191).
95
92
 
96
93
  // Outside truncation the columns apply to Draft's `[data-contents]` block
97
94
  // (via _type-tester.scss), which shrink-wraps — on the full-width container,
@@ -126,23 +123,35 @@ const useTypeTesterStyler = _ref => {
126
123
  // out to N lines of whitespace. Columns send the clipped overflow
127
124
  // sideways (into off-screen columns) rather than below, so the last
128
125
  // visible line of every column is never partially covered by the next
129
- // one. That lets the symmetric `lineOverflowEm` padding fully reveal the
130
- // first line's ascenders/accents and the last line's descenders at any
131
- // line-height; the negative margins cancel that padding in layout so a
126
+ // one. That lets a `lineOverflowEm` allowance above the first line and
127
+ // below the last fully reveal ascenders/accents and descenders at any
128
+ // line-height; the negative margins cancel both in layout so a
132
129
  // collapsed paragraph still occupies exactly its line count.
133
130
  //
131
+ // Where the two allowances go depends on the engine, so the stylesheet
132
+ // places them from the custom property below (`[data-truncated]` in
133
+ // _type-tester.scss); nothing here writes a padding inline, so those
134
+ // rules win. Chromium and Firefox fit a line into a column by its line
135
+ // box, so the column must span exactly N line boxes and the allowances
136
+ // are this box's own top and bottom padding, outside the column.
137
+ // WebKit fits a line by its inline box extent (the font's ascent plus
138
+ // descent): the Nth line would overhang such a column and move to the
139
+ // hidden one, and a line pushed into a later column gets a strut that
140
+ // starts it one allowance down. So for WebKit both allowances are
141
+ // padding on Draft's content block, inside the column, and every
142
+ // column holds the same N lines (FD-191).
143
+ //
134
144
  // Everything is in `em` so it tracks the rendered font-size (including
135
145
  // the mobile `--type-tester--adjustment`); the `+ 2px` is slack that
136
146
  // keeps sub-pixel rounding from dropping the Nth line (the extra never
137
147
  // reveals line N+1 because that line is clipped out to the side).
138
148
  boxSizing: 'border-box',
139
149
  maxHeight: `calc(${truncateLines * lineHeight + 2 * lineOverflowEm}em + 2px)`,
140
- paddingTop: `${lineOverflowEm}em`,
141
- paddingBottom: `${lineOverflowEm}em`,
142
150
  paddingLeft: sideBearing,
143
151
  paddingRight: sideBearing,
144
152
  marginTop: `${-lineOverflowEm}em`,
145
153
  marginBottom: `${-lineOverflowEm}em`,
154
+ '--type-tester--line-overflow': `${lineOverflowEm}em`,
146
155
  // `clip`, not `hidden`, once the cap outlives focus. A hidden box is
147
156
  // still a scroll container, so the browser scrolls it to chase a
148
157
  // caret past line N, and the offset is unrecoverable because there is
@@ -167,9 +176,7 @@ const useTypeTesterStyler = _ref => {
167
176
  columnFill: 'auto',
168
177
  widows: 1,
169
178
  orphans: 1,
170
- ...(columnStyle ?? {
171
- columnCount: 1
172
- })
179
+ ...truncateColumnStyle(columns)
173
180
  } : {
174
181
  height: 'auto',
175
182
  overflow: 'visible',
package/dist/fontdue.css CHANGED
@@ -182,10 +182,6 @@
182
182
  .test-fonts__checkbox-field label p {
183
183
  margin: 0;
184
184
  }
185
- .test-fonts__families {
186
- --checkbox-size: 20px;
187
- --checkbox-margin: 10px;
188
- }
189
185
  .test-fonts__families .test-fonts__checkbox-field {
190
186
  margin-bottom: 10px;
191
187
  }
@@ -728,8 +724,6 @@ fontdue-type-tester {
728
724
  }
729
725
  .type-tester__features__button {
730
726
  display: flex;
731
- --checkbox-size: 20px;
732
- --checkbox-margin: 10px;
733
727
  }
734
728
  .type-tester__features[data-selection-style=checkbox] .type-tester__features__button {
735
729
  margin-bottom: 5px;
@@ -896,6 +890,19 @@ fontdue-type-tester {
896
890
  }
897
891
  .type-tester__text__container[data-truncated] {
898
892
  overflow: hidden;
893
+ padding-top: var(--type-tester--line-overflow, 0);
894
+ padding-bottom: var(--type-tester--line-overflow, 0);
895
+ }
896
+ @supports (font: -apple-system-body) or (-webkit-hyphenate-limit-lines: 1) {
897
+ .type-tester__text__container[data-truncated] {
898
+ column-width: 1px;
899
+ padding-top: 0;
900
+ padding-bottom: 0;
901
+ }
902
+ .type-tester__text__container[data-truncated] [data-contents=true] {
903
+ padding-top: var(--type-tester--line-overflow, 0);
904
+ padding-bottom: var(--type-tester--line-overflow, 0);
905
+ }
899
906
  }
900
907
  .type-tester__text__container [data-contents=true] {
901
908
  column-count: var(--type-tester--column-count, auto);
@@ -1300,8 +1307,6 @@ fontdue-feature-testers {
1300
1307
  grid-template-columns: max-content auto;
1301
1308
  grid-column-gap: 20px;
1302
1309
  line-height: 1.6;
1303
- --checkbox-size: 20px;
1304
- --checkbox-margin: 10px;
1305
1310
  }
1306
1311
  .character-viewer__monitor__details > span {
1307
1312
  white-space: nowrap;
@@ -1382,10 +1387,10 @@ fontdue-feature-testers {
1382
1387
  .checkbox {
1383
1388
  position: relative;
1384
1389
  flex-shrink: 0;
1385
- margin-right: var(--checkbox-margin, 20px);
1386
- width: var(--checkbox-size, 40px);
1387
- height: var(--checkbox-size, 40px);
1388
- font-size: calc(var(--checkbox-size, 40px) * 0.8);
1390
+ margin-right: var(--checkbox-margin, 10px);
1391
+ width: var(--checkbox-size, 20px);
1392
+ height: var(--checkbox-size, 20px);
1393
+ font-size: calc(var(--checkbox-size, 20px) * 0.8);
1389
1394
  }
1390
1395
  .checkbox input {
1391
1396
  background: none;
@@ -1409,8 +1414,8 @@ fontdue-feature-testers {
1409
1414
  .checkbox input {
1410
1415
  -webkit-appearance: none;
1411
1416
  vertical-align: top;
1412
- width: var(--checkbox-size, 40px);
1413
- height: var(--checkbox-size, 40px);
1417
+ width: var(--checkbox-size, 20px);
1418
+ height: var(--checkbox-size, 20px);
1414
1419
  border: 1px solid var(--checkbox-color, currentcolor);
1415
1420
  }
1416
1421
  .checkbox__icon {
package/dist/version.js CHANGED
@@ -8,4 +8,4 @@
8
8
  // (Fontage.ClientVersions) to spot sites that need to upgrade before a
9
9
  // feature that depends on a newer client can work for them.
10
10
  export const CLIENT_VERSION_HEADER = 'fontdue-client-version';
11
- export const version = "3.9.0";
11
+ export const version = "3.10.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fontdue-js",
3
- "version": "3.9.0",
3
+ "version": "3.10.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "npm run relay && run-p build-js build-css build-ts",