fontdue-js 3.9.0 → 3.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -4
- package/dist/__generated__/StoreModalIndexItem_fontCollection.graphql.d.ts +10 -1
- package/dist/__generated__/StoreModalIndexItem_fontCollection.graphql.js +45 -35
- package/dist/__generated__/StoreModalIndexPaginationQuery.graphql.d.ts +1 -1
- package/dist/__generated__/StoreModalIndexPaginationQuery.graphql.js +101 -93
- package/dist/__generated__/StoreModalIndexQuery.graphql.d.ts +3 -1
- package/dist/__generated__/StoreModalIndexQuery.graphql.js +24 -17
- package/dist/__tests__/fontLoader.test.js +33 -1
- package/dist/__tests__/storeModalIndexUnlisted.test.js +71 -0
- package/dist/__tests__/typeTesterTruncate.test.js +71 -1
- package/dist/components/FeatureTester/FeatureTesterCard.js +2 -1
- package/dist/components/StoreModal/StoreModalContainer.js +3 -2
- package/dist/components/StoreModal/StoreModalIndex.js +8 -2
- package/dist/components/StoreModal/StoreModalIndexItem.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalIndexItem.js +26 -8
- package/dist/components/TypeTester/truncate.d.ts +10 -0
- package/dist/components/TypeTester/truncate.js +31 -0
- package/dist/components/TypeTester/useTypeTesterStyler.d.ts +1 -6
- package/dist/components/TypeTester/useTypeTesterStyler.js +22 -15
- package/dist/components/useFontStyle.js +2 -2
- package/dist/fontLoader.d.ts +24 -0
- package/dist/fontLoader.js +35 -0
- package/dist/fontdue.css +19 -14
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
## 3.10.1
|
|
2
|
+
|
|
3
|
+
- Fixed the `TypeTester`, `FeatureTesters`, `CharacterViewer` and `StoreModal` never rendering a font in some Safari versions when its family or style name contains punctuation, such as an apostrophe, or starts with a digit.
|
|
4
|
+
|
|
5
|
+
## 3.10.0
|
|
6
|
+
|
|
7
|
+
- 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.
|
|
8
|
+
- 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.
|
|
9
|
+
- Fixed a type tester with a `truncate` line cap cutting through a line, or showing one line too few, in Safari before 26.1.
|
|
10
|
+
|
|
1
11
|
## 3.9.0
|
|
2
12
|
|
|
3
|
-
- `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.
|
|
13
|
+
- `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.
|
|
4
14
|
- `TestFontsForm` takes `collectionSlug` or `collectionId` (`collection-slug` / `collection-id`, comma-separated for several) to offer just those families, with no checkboxes – for a form on a family’s own page. When preloading, pass the same value to `loadTestFontsFormQuery({ collectionSlug })`; the old options-only call still works.
|
|
5
15
|
|
|
6
16
|
## 3.8.0
|
|
@@ -23,7 +33,7 @@
|
|
|
23
33
|
- A product route takes a collection's slug as well as its ID, so `?store=product/example-sans` works alongside the base64 form. `fontdue-store-route="product/<slug>"` takes a slug now too – previously a slug there either did nothing (if it contained a hyphen) or loaded a broken product page.
|
|
24
34
|
- `TypeTester` and `TypeTesters` take a `truncate` prop, and `<fontdue-type-tester>` and `<fontdue-type-testers>` take a `truncate` attribute, so each tester can cap its paragraph at its own number of lines instead of every tester on a site sharing one value. A per-tester value overrides the `truncate` UI config.
|
|
25
35
|
- Fixed a type tester leaving a blank gap where its variable-axis sliders would go, on a static style or when none of the requested axes are in the font. The toolbar, features panel and dropdown placements were all affected.
|
|
26
|
-
- A numeric `truncate` cap now stays in place while a visitor edits the text, instead of the paragraph jumping to full height on click and back on blur. `truncate: true` is unchanged and still opens to the full paragraph when clicked; pass `{ lines: 20, expandOnFocus: true }` if you want a line count to behave the old way. On the custom elements that object is a second word in the attribute – `truncate="20 expandable"`, or `truncate="20 fixed"` to spell out the default.
|
|
36
|
+
- A numeric `truncate` cap now stays in place while a visitor edits the text, instead of the paragraph jumping to full height on click and back on blur. `truncate: true` is unchanged and still opens to the full paragraph when clicked; pass `{ lines: 20, expandOnFocus: true }` if you want a line count to behave the old way. On the custom elements that object is a second word in the attribute – `truncate="20 expandable"`, or `truncate="20 fixed"` to spell out the default.
|
|
27
37
|
- Fixed a type tester opening at a size outside the range its size slider spans. A seeded size below `typeTester.size.min` (or above `max`) rendered at that size with the slider handle drawn off the end of its track; it is clamped into range now.
|
|
28
38
|
- `NewsletterSignup` and `TestFontsForm` now name which form a submission came from, so Fontdue records each as its own event rather than as a checkout contact step.
|
|
29
39
|
- Fixed the Store Modal’s Checkout button doing nothing on a store using Stripe Tax, and the Cart’s Next button on the billing and licensee steps. Stripe.js now throws “Unable to select session” when asked to validate a form that has no payment in it yet; the address fields are validated on their own in that case, with the same inline errors.
|
|
@@ -41,7 +51,7 @@
|
|
|
41
51
|
## 3.4.1
|
|
42
52
|
|
|
43
53
|
- Fixed the standalone type tester dropping an axis slider when its `variable-settings` starting value is negative. `variable-settings="slnt -11"` was rejected as unparseable, so no slant slider appeared and nothing in the markup explained why. Any axis with a negative range was affected. Extra spaces between an axis and its value are tolerated now too.
|
|
44
|
-
- Fixed the `FeatureTesters` switch knob rendering stretched in Safari 18 and earlier.
|
|
54
|
+
- Fixed the `FeatureTesters` switch knob rendering stretched in Safari 18 and earlier.
|
|
45
55
|
|
|
46
56
|
## 3.4.0
|
|
47
57
|
|
|
@@ -68,7 +78,7 @@
|
|
|
68
78
|
|
|
69
79
|
## 3.2.3
|
|
70
80
|
|
|
71
|
-
- Fixed `TypeTester` text drifting out of alignment. Centred, right-aligned and RTL testers sat off-centre once the font was small enough for the text to flow into columns, and centred testers were slightly off at every size.
|
|
81
|
+
- Fixed `TypeTester` text drifting out of alignment. Centred, right-aligned and RTL testers sat off-centre once the font was small enough for the text to flow into columns, and centred testers were slightly off at every size.
|
|
72
82
|
- The collapsed `FontdueAdminToolbar` pill now carries the Fontdue wordmark — Fontdue, Fontdue · Previewing hidden fonts, Fontdue · Preview expired. If you style the toolbar yourself, `__mark` has left `__button` and the expired suffix is a new `__expired-suffix` span.
|
|
73
83
|
|
|
74
84
|
## 3.2.2
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @generated SignedSource<<
|
|
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<<
|
|
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": "
|
|
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": "
|
|
23
|
+
"name": "name",
|
|
24
24
|
"storageKey": null
|
|
25
|
-
}
|
|
26
|
-
|
|
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": "
|
|
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": "
|
|
37
|
+
"name": "totalStyles",
|
|
46
38
|
"storageKey": null
|
|
47
|
-
},
|
|
48
|
-
|
|
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": "
|
|
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 = "
|
|
100
|
+
node.hash = "46573dcfb540ddfba2e28144704bd554";
|
|
91
101
|
export default node;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @generated SignedSource<<
|
|
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": "
|
|
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<<
|
|
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<<
|
|
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": "
|
|
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": "
|
|
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
|
-
},
|
|
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
|
-
|
|
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
|
-
|
|
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":
|
|
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*/,
|
|
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": [
|
|
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
|
-
},
|
|
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":
|
|
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": "
|
|
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 = "
|
|
375
|
+
node.hash = "13fce0376ef1b098e7f1f34dfdc7dad4";
|
|
369
376
|
export default node;
|
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { selectFontSource } from "../fontLoader.js";
|
|
2
|
+
import { selectFontSource, fontStyleFamily } from "../fontLoader.js";
|
|
3
|
+
describe('fontStyleFamily', () => {
|
|
4
|
+
it('joins family and style unchanged when both are plain identifiers', () => {
|
|
5
|
+
expect(fontStyleFamily('Vain', 'Regular')).toBe('Vain Regular');
|
|
6
|
+
expect(fontStyleFamily('Sweet Lily', 'Bold Italic')).toBe('Sweet Lily Bold Italic');
|
|
7
|
+
});
|
|
8
|
+
it("escapes an apostrophe, which some Safari builds reject in a FontFace family", () => {
|
|
9
|
+
expect(fontStyleFamily("Hell's Gate", 'fairypools')).toBe('Hell_27s Gate fairypools');
|
|
10
|
+
});
|
|
11
|
+
it('escapes other ASCII punctuation instead of dropping it, so names stay distinct', () => {
|
|
12
|
+
expect(fontStyleFamily('A&B', 'Regular')).toBe('A_26B Regular');
|
|
13
|
+
expect(fontStyleFamily('A "B"', 'Regular')).toBe('A _22B_22 Regular');
|
|
14
|
+
expect(fontStyleFamily("Hell's Gate", 'Regular')).not.toBe(fontStyleFamily('Hells Gate', 'Regular'));
|
|
15
|
+
});
|
|
16
|
+
it('prefixes words CSS cannot parse unquoted: leading digits and reserved words', () => {
|
|
17
|
+
expect(fontStyleFamily('0712', 'Regular')).toBe('_0712 Regular');
|
|
18
|
+
expect(fontStyleFamily('Grotesk', '-5 Light')).toBe('Grotesk _-5 Light');
|
|
19
|
+
expect(fontStyleFamily('Initial', 'Bold')).toBe('_Initial Bold');
|
|
20
|
+
expect(fontStyleFamily('Default', 'Regular')).toBe('_Default Regular');
|
|
21
|
+
});
|
|
22
|
+
it('keeps non-ASCII letters, hyphens and underscores, and collapses whitespace', () => {
|
|
23
|
+
expect(fontStyleFamily('Généreuse Sans', 'Extra-Bold_2')).toBe('Généreuse Sans Extra-Bold_2');
|
|
24
|
+
expect(fontStyleFamily(' 游明朝 ', ' W3 ')).toBe('游明朝 W3');
|
|
25
|
+
});
|
|
26
|
+
it('only yields CSS identifiers', () => {
|
|
27
|
+
const names = [fontStyleFamily("Hell's Gate", 'fairypools'), fontStyleFamily('0712', '1'), fontStyleFamily('(Test) / 50%', 'Regular!'), fontStyleFamily('--x', 'y')];
|
|
28
|
+
for (const name of names) {
|
|
29
|
+
for (const word of name.split(' ')) {
|
|
30
|
+
expect(word).toMatch(/^(?:[A-Za-z_\u0080-]|-[A-Za-z_\u0080-])[\w\u0080--]*$/);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
3
35
|
describe('selectFontSource', () => {
|
|
4
36
|
const woff2 = function () {
|
|
5
37
|
let extra = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -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
|
});
|
|
@@ -7,6 +7,7 @@ import { graphql, useFragment } from 'react-relay';
|
|
|
7
7
|
import FontStyle from '../FontStyle/index.js';
|
|
8
8
|
import useFeaturesData from '../TypeTester/useFeaturesData.js';
|
|
9
9
|
import useFeatureTesterAutofit from '../../hooks/useFeatureTesterAutofit.js';
|
|
10
|
+
import { fontStyleFamily } from '../../fontLoader.js';
|
|
10
11
|
import { sensitiveStringsForFeature, computeSensitivityFlags, segmentByFlags } from './highlight.js';
|
|
11
12
|
const fragment = (_FeatureTesterCard_fontStyle.hash && _FeatureTesterCard_fontStyle.hash !== "687d8afca93d615ed0794f963702d082" && console.error("The definition of 'FeatureTesterCard_fontStyle' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _FeatureTesterCard_fontStyle);
|
|
12
13
|
export default function FeatureTesterCard(_ref) {
|
|
@@ -88,7 +89,7 @@ export default function FeatureTesterCard(_ref) {
|
|
|
88
89
|
} = useFeatureTesterAutofit({
|
|
89
90
|
enabled: autofit,
|
|
90
91
|
text: content,
|
|
91
|
-
fontFamily:
|
|
92
|
+
fontFamily: fontStyleFamily(data.cssFamily, data.name),
|
|
92
93
|
feature,
|
|
93
94
|
fontSize: fontSize ?? 72,
|
|
94
95
|
letterSpacing: letterSpacing ?? 0,
|
|
@@ -6,6 +6,7 @@ import { useLazyLoadQuery, graphql } from 'react-relay';
|
|
|
6
6
|
import StoreModalCheckoutContext from './StoreModalCheckoutContext.js';
|
|
7
7
|
import CheckoutSteps from '../Cart/CheckoutSteps.js';
|
|
8
8
|
import useFontStyle from '../useFontStyle.js';
|
|
9
|
+
import { fontStyleFamily } from '../../fontLoader.js';
|
|
9
10
|
import StoreModalLoadingScreen from '../elements/StoreModalLoadingScreen/index.js';
|
|
10
11
|
import ConfigContext from '../ConfigContext.js';
|
|
11
12
|
const getPageTitle = name => {
|
|
@@ -89,8 +90,8 @@ const StoreModalContainer = _ref => {
|
|
|
89
90
|
};
|
|
90
91
|
const [checkoutStep, setCheckoutStep] = useState(CheckoutSteps.Customer);
|
|
91
92
|
const [checkoutError, setCheckoutError] = useState(null);
|
|
92
|
-
const regularName = uiFontStyle ?
|
|
93
|
-
const boldName = uiFontStyleBold ?
|
|
93
|
+
const regularName = uiFontStyle ? fontStyleFamily(uiFontStyle.cssFamily, uiFontStyle.name) : null;
|
|
94
|
+
const boldName = uiFontStyleBold ? fontStyleFamily(uiFontStyleBold.cssFamily, uiFontStyleBold.name) : null;
|
|
94
95
|
return /*#__PURE__*/React.createElement(StoreModalCheckoutContext.Provider, {
|
|
95
96
|
value: {
|
|
96
97
|
checkoutStep,
|
|
@@ -29,7 +29,7 @@ const StoreModalIndex = _ref => {
|
|
|
29
29
|
let {
|
|
30
30
|
prepared
|
|
31
31
|
} = _ref;
|
|
32
|
-
const queryData = usePreloadedQuery((_StoreModalIndexQuery.hash && _StoreModalIndexQuery.hash !== "
|
|
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
|
-
|
|
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 !== "
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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:
|
|
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
|
-
|
|
91
|
-
|
|
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
|
|
130
|
-
//
|
|
131
|
-
// line-height; the negative margins cancel
|
|
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
|
-
...(
|
|
171
|
-
columnCount: 1
|
|
172
|
-
})
|
|
179
|
+
...truncateColumnStyle(columns)
|
|
173
180
|
} : {
|
|
174
181
|
height: 'auto',
|
|
175
182
|
overflow: 'visible',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _useFontStyle_fontStyle from "../__generated__/useFontStyle_fontStyle.graphql.js";
|
|
2
2
|
import { useState, useRef, useEffect } from 'react';
|
|
3
3
|
import { graphql, useFragment } from 'react-relay';
|
|
4
|
-
import { loadFont, isFontLoaded } from '../fontLoader.js';
|
|
4
|
+
import { loadFont, isFontLoaded, fontStyleFamily } from '../fontLoader.js';
|
|
5
5
|
import { ensureMetricFallback, metricFallbackFamily } from '../metricFallback.js';
|
|
6
6
|
const FALLBACK_FAMILY = 'Fallback';
|
|
7
7
|
const useFontStyle = _ref => {
|
|
@@ -9,7 +9,7 @@ const useFontStyle = _ref => {
|
|
|
9
9
|
fontStyle: fontStyleKey
|
|
10
10
|
} = _ref;
|
|
11
11
|
const fontStyle = useFragment((_useFontStyle_fontStyle.hash && _useFontStyle_fontStyle.hash !== "171c546f40909692656c5e143a98d8a3" && console.error("The definition of 'useFontStyle_fontStyle' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _useFontStyle_fontStyle), fontStyleKey ?? null);
|
|
12
|
-
const fontFamily = fontStyle ?
|
|
12
|
+
const fontFamily = fontStyle ? fontStyleFamily(fontStyle.cssFamily, fontStyle.name) : null;
|
|
13
13
|
const sources = fontStyle === null || fontStyle === void 0 ? void 0 : fontStyle.webfontSources;
|
|
14
14
|
const verticalMetrics = fontStyle === null || fontStyle === void 0 ? void 0 : fontStyle.verticalMetrics;
|
|
15
15
|
|
package/dist/fontLoader.d.ts
CHANGED
|
@@ -9,6 +9,30 @@ interface VerticalMetrics {
|
|
|
9
9
|
readonly descender: number;
|
|
10
10
|
readonly lineGap: number | null;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* The family name a font style's FontFace is registered under, and the name
|
|
14
|
+
* CSS must use to render it: `"<cssFamily> <styleName>"`, made safe to parse
|
|
15
|
+
* as an unquoted CSS font-family.
|
|
16
|
+
*
|
|
17
|
+
* Some Safari builds parse the FontFace family argument as CSS, so a name
|
|
18
|
+
* like "Hell's Gate fairypools" (the apostrophe opens an unterminated string)
|
|
19
|
+
* or "0712 Regular" (an identifier can't start with a digit) makes `load()`
|
|
20
|
+
* reject with "SyntaxError: The string did not match the expected pattern."
|
|
21
|
+
* and the style never renders, while Chrome and other WebKit builds take the
|
|
22
|
+
* argument literally. A name that is valid either way works everywhere:
|
|
23
|
+
*
|
|
24
|
+
* - an ASCII character other than a letter, digit, `-` or `_` is escaped as
|
|
25
|
+
* `_<hex code>` (`'` → `_27`), so distinct names stay distinct;
|
|
26
|
+
* - a word starting with a digit, `-<digit>` or `--`, or matching a reserved
|
|
27
|
+
* word, gets a leading `_`.
|
|
28
|
+
*
|
|
29
|
+
* Non-ASCII characters are valid identifier characters and are kept.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* fontStyleFamily("Hell's Gate", 'fairypools') // => 'Hell_27s Gate fairypools'
|
|
33
|
+
* fontStyleFamily('0712', 'Regular') // => '_0712 Regular'
|
|
34
|
+
*/
|
|
35
|
+
export declare function fontStyleFamily(cssFamily: string | null | undefined, styleName: string): string;
|
|
12
36
|
export declare function isFontLoaded(fontFamily: string): boolean;
|
|
13
37
|
export declare function loadFont(fontFamily: string, sources: ReadonlyArray<FontSource | null>, verticalMetrics?: VerticalMetrics | null): Promise<FontFace | null>;
|
|
14
38
|
/**
|
package/dist/fontLoader.js
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
// Words CSS refuses as an unquoted font-family identifier (the CSS-wide
|
|
2
|
+
// keywords plus `default`), compared case-insensitively.
|
|
3
|
+
const RESERVED_FAMILY_WORDS = new Set(['inherit', 'initial', 'unset', 'revert', 'revert-layer', 'default']);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The family name a font style's FontFace is registered under, and the name
|
|
7
|
+
* CSS must use to render it: `"<cssFamily> <styleName>"`, made safe to parse
|
|
8
|
+
* as an unquoted CSS font-family.
|
|
9
|
+
*
|
|
10
|
+
* Some Safari builds parse the FontFace family argument as CSS, so a name
|
|
11
|
+
* like "Hell's Gate fairypools" (the apostrophe opens an unterminated string)
|
|
12
|
+
* or "0712 Regular" (an identifier can't start with a digit) makes `load()`
|
|
13
|
+
* reject with "SyntaxError: The string did not match the expected pattern."
|
|
14
|
+
* and the style never renders, while Chrome and other WebKit builds take the
|
|
15
|
+
* argument literally. A name that is valid either way works everywhere:
|
|
16
|
+
*
|
|
17
|
+
* - an ASCII character other than a letter, digit, `-` or `_` is escaped as
|
|
18
|
+
* `_<hex code>` (`'` → `_27`), so distinct names stay distinct;
|
|
19
|
+
* - a word starting with a digit, `-<digit>` or `--`, or matching a reserved
|
|
20
|
+
* word, gets a leading `_`.
|
|
21
|
+
*
|
|
22
|
+
* Non-ASCII characters are valid identifier characters and are kept.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* fontStyleFamily("Hell's Gate", 'fairypools') // => 'Hell_27s Gate fairypools'
|
|
26
|
+
* fontStyleFamily('0712', 'Regular') // => '_0712 Regular'
|
|
27
|
+
*/
|
|
28
|
+
export function fontStyleFamily(cssFamily, styleName) {
|
|
29
|
+
return `${cssFamily ?? ''} ${styleName}`.split(/\s+/).filter(word => word.length > 0).map(cssIdentifierWord).join(' ');
|
|
30
|
+
}
|
|
31
|
+
function cssIdentifierWord(word) {
|
|
32
|
+
const escaped = word.replace(/[\x00-\x7f]/g, char => /[A-Za-z0-9_-]/.test(char) ? char : `_${char.charCodeAt(0).toString(16)}`);
|
|
33
|
+
const unparseable = /^(?:[0-9]|-[0-9]|--|-$)/.test(escaped);
|
|
34
|
+
return unparseable || RESERVED_FAMILY_WORDS.has(escaped.toLowerCase()) ? `_${escaped}` : escaped;
|
|
35
|
+
}
|
|
1
36
|
const cache = new Map();
|
|
2
37
|
const loaded = new Set();
|
|
3
38
|
export function isFontLoaded(fontFamily) {
|
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,
|
|
1386
|
-
width: var(--checkbox-size,
|
|
1387
|
-
height: var(--checkbox-size,
|
|
1388
|
-
font-size: calc(var(--checkbox-size,
|
|
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,
|
|
1413
|
-
height: var(--checkbox-size,
|
|
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.
|
|
11
|
+
export const version = "3.10.1";
|