fontdue-js 3.10.0 → 3.11.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 +13 -5
- package/dist/__generated__/TestFontsForm_Query.graphql.d.ts +6 -1
- package/dist/__generated__/TestFontsForm_Query.graphql.js +25 -9
- package/dist/__tests__/fontLoader.test.js +33 -1
- package/dist/__tests__/testFontsFamilyChoice.test.js +74 -1
- package/dist/components/ConfigContext.d.ts +4 -0
- package/dist/components/ConfigContext.js +3 -2
- package/dist/components/FeatureTester/FeatureTesterCard.js +2 -1
- package/dist/components/StoreModal/StoreModalContainer.js +3 -2
- package/dist/components/TestFontsForm/TestFontsFormElement.d.ts +2 -1
- package/dist/components/TestFontsForm/TestFontsFormElement.js +3 -0
- package/dist/components/TestFontsForm/familyGroups.d.ts +16 -0
- package/dist/components/TestFontsForm/familyGroups.js +34 -0
- package/dist/components/TestFontsForm/index.d.ts +2 -1
- package/dist/components/TestFontsForm/index.js +51 -21
- package/dist/components/useFontStyle.js +2 -2
- package/dist/fontLoader.d.ts +26 -0
- package/dist/fontLoader.js +37 -0
- package/dist/fontdue.css +3 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
## 3.11.0
|
|
2
|
+
|
|
3
|
+
- `TestFontsForm` can group its family checkboxes by superfamily. With *Family list* set to *Grouped by superfamily* under *Settings → Test fonts* – or `testFonts: { familyGrouping: "superfamily" }` in the config, or the `familyGrouping` prop (`family-grouping` on `<fontdue-test-fonts-form>`) – each superfamily gets a checkbox that ticks all of its families, listed beneath it in `.test-fonts__family-group__families`.
|
|
4
|
+
|
|
5
|
+
## 3.10.1
|
|
6
|
+
|
|
7
|
+
- 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.
|
|
8
|
+
|
|
1
9
|
## 3.10.0
|
|
2
10
|
|
|
3
11
|
- 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
12
|
- 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.
|
|
13
|
+
- Fixed a type tester with a `truncate` line cap cutting through a line, or showing one line too few, in Safari before 26.1.
|
|
6
14
|
|
|
7
15
|
## 3.9.0
|
|
8
16
|
|
|
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.
|
|
17
|
+
- `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.
|
|
10
18
|
- `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.
|
|
11
19
|
|
|
12
20
|
## 3.8.0
|
|
@@ -29,7 +37,7 @@
|
|
|
29
37
|
- 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.
|
|
30
38
|
- `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.
|
|
31
39
|
- 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.
|
|
32
|
-
- 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.
|
|
40
|
+
- 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.
|
|
33
41
|
- 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.
|
|
34
42
|
- `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.
|
|
35
43
|
- 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.
|
|
@@ -47,7 +55,7 @@
|
|
|
47
55
|
## 3.4.1
|
|
48
56
|
|
|
49
57
|
- 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.
|
|
50
|
-
- Fixed the `FeatureTesters` switch knob rendering stretched in Safari 18 and earlier.
|
|
58
|
+
- Fixed the `FeatureTesters` switch knob rendering stretched in Safari 18 and earlier.
|
|
51
59
|
|
|
52
60
|
## 3.4.0
|
|
53
61
|
|
|
@@ -74,7 +82,7 @@
|
|
|
74
82
|
|
|
75
83
|
## 3.2.3
|
|
76
84
|
|
|
77
|
-
- 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.
|
|
85
|
+
- 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.
|
|
78
86
|
- 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.
|
|
79
87
|
|
|
80
88
|
## 3.2.2
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @generated SignedSource<<
|
|
2
|
+
* @generated SignedSource<<0a0e4ebec2aeeb79d7f6e04437e7b7cc>>
|
|
3
3
|
* @lightSyntaxTransform
|
|
4
4
|
* @nogrep
|
|
5
5
|
*/
|
|
@@ -12,6 +12,7 @@ export type TestFontsForm_Query$data = {
|
|
|
12
12
|
readonly viewer: {
|
|
13
13
|
readonly fontdueConfig: {
|
|
14
14
|
readonly testFonts: {
|
|
15
|
+
readonly familyGrouping: string;
|
|
15
16
|
readonly familySelection: string;
|
|
16
17
|
};
|
|
17
18
|
} | null;
|
|
@@ -26,6 +27,10 @@ export type TestFontsForm_Query$data = {
|
|
|
26
27
|
readonly families: ReadonlyArray<{
|
|
27
28
|
readonly id: string;
|
|
28
29
|
readonly name: string;
|
|
30
|
+
readonly parent: {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly name: string;
|
|
33
|
+
} | null;
|
|
29
34
|
}>;
|
|
30
35
|
} | null;
|
|
31
36
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @generated SignedSource<<
|
|
2
|
+
* @generated SignedSource<<0a0e4ebec2aeeb79d7f6e04437e7b7cc>>
|
|
3
3
|
* @lightSyntaxTransform
|
|
4
4
|
* @nogrep
|
|
5
5
|
*/
|
|
@@ -77,6 +77,12 @@ const node = function () {
|
|
|
77
77
|
"kind": "ScalarField",
|
|
78
78
|
"name": "familySelection",
|
|
79
79
|
"storageKey": null
|
|
80
|
+
}, {
|
|
81
|
+
"alias": null,
|
|
82
|
+
"args": null,
|
|
83
|
+
"kind": "ScalarField",
|
|
84
|
+
"name": "familyGrouping",
|
|
85
|
+
"storageKey": null
|
|
80
86
|
}],
|
|
81
87
|
"storageKey": null
|
|
82
88
|
}],
|
|
@@ -90,6 +96,13 @@ const node = function () {
|
|
|
90
96
|
"storageKey": null
|
|
91
97
|
},
|
|
92
98
|
v5 = {
|
|
99
|
+
"alias": null,
|
|
100
|
+
"args": null,
|
|
101
|
+
"kind": "ScalarField",
|
|
102
|
+
"name": "name",
|
|
103
|
+
"storageKey": null
|
|
104
|
+
},
|
|
105
|
+
v6 = {
|
|
93
106
|
"alias": null,
|
|
94
107
|
"args": [{
|
|
95
108
|
"kind": "Variable",
|
|
@@ -117,11 +130,14 @@ const node = function () {
|
|
|
117
130
|
"kind": "LinkedField",
|
|
118
131
|
"name": "families",
|
|
119
132
|
"plural": true,
|
|
120
|
-
"selections": [v4 /*: any*/, {
|
|
133
|
+
"selections": [v4 /*: any*/, v5 /*: any*/, {
|
|
121
134
|
"alias": null,
|
|
122
135
|
"args": null,
|
|
123
|
-
"
|
|
124
|
-
"
|
|
136
|
+
"concreteType": "FontCollection",
|
|
137
|
+
"kind": "LinkedField",
|
|
138
|
+
"name": "parent",
|
|
139
|
+
"plural": false,
|
|
140
|
+
"selections": [v4 /*: any*/, v5 /*: any*/],
|
|
125
141
|
"storageKey": null
|
|
126
142
|
}],
|
|
127
143
|
"storageKey": null
|
|
@@ -141,7 +157,7 @@ const node = function () {
|
|
|
141
157
|
"kind": "LinkedField",
|
|
142
158
|
"name": "viewer",
|
|
143
159
|
"plural": false,
|
|
144
|
-
"selections": [v2 /*: any*/, v3 /*: any*/,
|
|
160
|
+
"selections": [v2 /*: any*/, v3 /*: any*/, v6 /*: any*/],
|
|
145
161
|
"storageKey": null
|
|
146
162
|
}],
|
|
147
163
|
"type": "RootQueryType",
|
|
@@ -159,19 +175,19 @@ const node = function () {
|
|
|
159
175
|
"kind": "LinkedField",
|
|
160
176
|
"name": "viewer",
|
|
161
177
|
"plural": false,
|
|
162
|
-
"selections": [v2 /*: any*/, v3 /*: any*/,
|
|
178
|
+
"selections": [v2 /*: any*/, v3 /*: any*/, v6 /*: any*/, v4 /*: any*/],
|
|
163
179
|
"storageKey": null
|
|
164
180
|
}]
|
|
165
181
|
},
|
|
166
182
|
"params": {
|
|
167
|
-
"cacheID": "
|
|
183
|
+
"cacheID": "f0d8dba45eec4868101fe71af251133a",
|
|
168
184
|
"id": null,
|
|
169
185
|
"metadata": {},
|
|
170
186
|
"name": "TestFontsForm_Query",
|
|
171
187
|
"operationKind": "query",
|
|
172
|
-
"text": "query TestFontsForm_Query(\n $collectionIds: [ID!]\n $collectionSlugs: [String!]\n) {\n viewer {\n settings {\n eulaAgreementLabel(format: HTML)\n newsletterOptInLabel(format: HTML)\n recaptchaEnabled\n recaptchaSiteKey\n }\n fontdueConfig {\n testFonts {\n familySelection\n }\n }\n testFonts(collectionIds: $collectionIds, collectionSlugs: $collectionSlugs) {\n archiveUrl\n families {\n id\n name\n }\n }\n id\n }\n}\n"
|
|
188
|
+
"text": "query TestFontsForm_Query(\n $collectionIds: [ID!]\n $collectionSlugs: [String!]\n) {\n viewer {\n settings {\n eulaAgreementLabel(format: HTML)\n newsletterOptInLabel(format: HTML)\n recaptchaEnabled\n recaptchaSiteKey\n }\n fontdueConfig {\n testFonts {\n familySelection\n familyGrouping\n }\n }\n testFonts(collectionIds: $collectionIds, collectionSlugs: $collectionSlugs) {\n archiveUrl\n families {\n id\n name\n parent {\n id\n name\n }\n }\n }\n id\n }\n}\n"
|
|
173
189
|
}
|
|
174
190
|
};
|
|
175
191
|
}();
|
|
176
|
-
node.hash = "
|
|
192
|
+
node.hash = "9ef2c42a7043469fec07a31649623766";
|
|
177
193
|
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] : {};
|
|
@@ -51,6 +51,7 @@ const families = [{
|
|
|
51
51
|
}];
|
|
52
52
|
const viewer = function (familySelection) {
|
|
53
53
|
let list = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : families;
|
|
54
|
+
let familyGrouping = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'flat';
|
|
54
55
|
return {
|
|
55
56
|
viewer: {
|
|
56
57
|
settings: {
|
|
@@ -61,7 +62,8 @@ const viewer = function (familySelection) {
|
|
|
61
62
|
},
|
|
62
63
|
fontdueConfig: {
|
|
63
64
|
testFonts: {
|
|
64
|
-
familySelection
|
|
65
|
+
familySelection,
|
|
66
|
+
familyGrouping
|
|
65
67
|
}
|
|
66
68
|
},
|
|
67
69
|
testFonts: {
|
|
@@ -147,4 +149,75 @@ describe('TestFontsForm family choice', () => {
|
|
|
147
149
|
expect(container.querySelector('form')).toBeNull();
|
|
148
150
|
expect(container.textContent).toContain('Test fonts aren’t available for this family.');
|
|
149
151
|
});
|
|
152
|
+
});
|
|
153
|
+
describe('TestFontsForm family grouping', () => {
|
|
154
|
+
const sans = {
|
|
155
|
+
id: 'U3VwZXI6MQ==',
|
|
156
|
+
name: 'Example'
|
|
157
|
+
};
|
|
158
|
+
const grouped = [{
|
|
159
|
+
id: 'RmFtaWx5OjE=',
|
|
160
|
+
name: 'Example Sans',
|
|
161
|
+
parent: sans
|
|
162
|
+
}, {
|
|
163
|
+
id: 'RmFtaWx5OjI=',
|
|
164
|
+
name: 'Solo',
|
|
165
|
+
parent: null
|
|
166
|
+
}, {
|
|
167
|
+
id: 'RmFtaWx5OjM=',
|
|
168
|
+
name: 'Example Serif',
|
|
169
|
+
parent: sans
|
|
170
|
+
},
|
|
171
|
+
// The only family offered from its superfamily: listed on its own.
|
|
172
|
+
{
|
|
173
|
+
id: 'RmFtaWx5OjQ=',
|
|
174
|
+
name: 'Lonely',
|
|
175
|
+
parent: {
|
|
176
|
+
id: 'U3VwZXI6Mg==',
|
|
177
|
+
name: 'Lonely Super'
|
|
178
|
+
}
|
|
179
|
+
}];
|
|
180
|
+
const superfamilyBoxes = () => [...container.querySelectorAll('.test-fonts__superfamily input')];
|
|
181
|
+
it('lists the families flat by default', () => {
|
|
182
|
+
queryRef.data = viewer('choice', grouped);
|
|
183
|
+
render();
|
|
184
|
+
expect(superfamilyBoxes()).toHaveLength(0);
|
|
185
|
+
expect(familyCheckboxes().map(box => box.value)).toEqual(grouped.map(f => f.id));
|
|
186
|
+
});
|
|
187
|
+
it('groups families under their superfamily, which ticks them all', () => {
|
|
188
|
+
queryRef.data = viewer('choice', grouped, 'superfamily');
|
|
189
|
+
render();
|
|
190
|
+
expect(superfamilyBoxes()).toHaveLength(1);
|
|
191
|
+
const group = container.querySelector('.test-fonts__family-group');
|
|
192
|
+
expect(group.textContent).toContain('Example');
|
|
193
|
+
expect([...group.querySelectorAll('.test-fonts__family input')].map(b => b.value)).toEqual(['RmFtaWx5OjE=', 'RmFtaWx5OjM=']);
|
|
194
|
+
// The group sits where its first family fell; the rest keep their order.
|
|
195
|
+
expect(familyCheckboxes().map(box => box.value)).toEqual(['RmFtaWx5OjE=', 'RmFtaWx5OjM=', 'RmFtaWx5OjI=', 'RmFtaWx5OjQ=']);
|
|
196
|
+
expect(container.textContent).not.toContain('Lonely Super');
|
|
197
|
+
act(() => superfamilyBoxes()[0].click());
|
|
198
|
+
expect(hiddenIds()).toEqual(['RmFtaWx5OjE=', 'RmFtaWx5OjM=']);
|
|
199
|
+
expect(superfamilyBoxes()[0].checked).toBe(true);
|
|
200
|
+
|
|
201
|
+
// Unticking one family leaves the superfamily unticked.
|
|
202
|
+
act(() => familyCheckboxes()[1].click());
|
|
203
|
+
expect(hiddenIds()).toEqual(['RmFtaWx5OjE=']);
|
|
204
|
+
expect(superfamilyBoxes()[0].checked).toBe(false);
|
|
205
|
+
act(() => superfamilyBoxes()[0].click());
|
|
206
|
+
act(() => superfamilyBoxes()[0].click());
|
|
207
|
+
expect(hiddenIds()).toEqual([]);
|
|
208
|
+
});
|
|
209
|
+
it('lets the prop and code config override the dashboard grouping', () => {
|
|
210
|
+
queryRef.data = viewer('choice', grouped, 'superfamily');
|
|
211
|
+
render({}, {
|
|
212
|
+
testFonts: {
|
|
213
|
+
familyGrouping: 'flat'
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
expect(superfamilyBoxes()).toHaveLength(0);
|
|
217
|
+
queryRef.data = viewer('choice', grouped);
|
|
218
|
+
render({
|
|
219
|
+
familyGrouping: 'superfamily'
|
|
220
|
+
});
|
|
221
|
+
expect(superfamilyBoxes()).toHaveLength(1);
|
|
222
|
+
});
|
|
150
223
|
});
|
|
@@ -29,8 +29,10 @@ interface PreviewConfig {
|
|
|
29
29
|
clientSide?: boolean;
|
|
30
30
|
}
|
|
31
31
|
export type TestFontsFamilySelection = 'all' | 'choice';
|
|
32
|
+
export type TestFontsFamilyGrouping = 'flat' | 'superfamily';
|
|
32
33
|
interface TestFontsConfig {
|
|
33
34
|
familySelection?: TestFontsFamilySelection;
|
|
35
|
+
familyGrouping?: TestFontsFamilyGrouping;
|
|
34
36
|
}
|
|
35
37
|
export interface Config {
|
|
36
38
|
form?: FormConfig;
|
|
@@ -101,6 +103,7 @@ export declare const makeConfig: (config?: Config) => {
|
|
|
101
103
|
};
|
|
102
104
|
testFonts: {
|
|
103
105
|
familySelection: TestFontsFamilySelection | undefined;
|
|
106
|
+
familyGrouping: TestFontsFamilyGrouping | undefined;
|
|
104
107
|
};
|
|
105
108
|
storeModal: {
|
|
106
109
|
indexLayout: "styled-aa" | "styled-font-names";
|
|
@@ -182,6 +185,7 @@ declare const _default: React.Context<{
|
|
|
182
185
|
};
|
|
183
186
|
testFonts: {
|
|
184
187
|
familySelection: TestFontsFamilySelection | undefined;
|
|
188
|
+
familyGrouping: TestFontsFamilyGrouping | undefined;
|
|
185
189
|
};
|
|
186
190
|
storeModal: {
|
|
187
191
|
indexLayout: "styled-aa" | "styled-font-names";
|
|
@@ -88,7 +88,7 @@ export const mergeConfig = (base, override) => {
|
|
|
88
88
|
return deepMerge(base, override);
|
|
89
89
|
};
|
|
90
90
|
export const makeConfig = config => {
|
|
91
|
-
var _config$form, _config$testFonts, _config$storeModal, _config$storeModal2, _config$storeModal3, _config$storeModal4, _config$stripe, _config$tracking, _config$tracking2, _config$tracking3, _config$tracking4, _config$preview, _config$preview2, _config$preview3;
|
|
91
|
+
var _config$form, _config$testFonts, _config$testFonts2, _config$storeModal, _config$storeModal2, _config$storeModal3, _config$storeModal4, _config$stripe, _config$tracking, _config$tracking2, _config$tracking3, _config$tracking4, _config$preview, _config$preview2, _config$preview3;
|
|
92
92
|
return {
|
|
93
93
|
typeTester: makeTypeTesterConfig(config === null || config === void 0 ? void 0 : config.typeTester),
|
|
94
94
|
form: {
|
|
@@ -98,7 +98,8 @@ export const makeConfig = config => {
|
|
|
98
98
|
// Deliberately no default: the form falls back to the dashboard setting
|
|
99
99
|
// it reads in its own query (the npm path never merges server config
|
|
100
100
|
// into `children`'s context – see ServerConfigProvider).
|
|
101
|
-
familySelection: config === null || config === void 0 ? void 0 : (_config$testFonts = config.testFonts) === null || _config$testFonts === void 0 ? void 0 : _config$testFonts.familySelection
|
|
101
|
+
familySelection: config === null || config === void 0 ? void 0 : (_config$testFonts = config.testFonts) === null || _config$testFonts === void 0 ? void 0 : _config$testFonts.familySelection,
|
|
102
|
+
familyGrouping: config === null || config === void 0 ? void 0 : (_config$testFonts2 = config.testFonts) === null || _config$testFonts2 === void 0 ? void 0 : _config$testFonts2.familyGrouping
|
|
102
103
|
},
|
|
103
104
|
storeModal: {
|
|
104
105
|
indexLayout: (config === null || config === void 0 ? void 0 : (_config$storeModal = config.storeModal) === null || _config$storeModal === void 0 ? void 0 : _config$storeModal.indexLayout) ?? 'styled-aa',
|
|
@@ -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,
|
|
@@ -6,6 +6,7 @@ interface TestFontsFormElement_props {
|
|
|
6
6
|
collectionId?: string;
|
|
7
7
|
collectionSlug?: string;
|
|
8
8
|
familySelection?: string;
|
|
9
|
+
familyGrouping?: string;
|
|
9
10
|
}
|
|
10
|
-
declare const TestFontsFormElement: ({ familySelection, ...props }: TestFontsFormElement_props) => React.JSX.Element;
|
|
11
|
+
declare const TestFontsFormElement: ({ familySelection, familyGrouping, ...props }: TestFontsFormElement_props) => React.JSX.Element;
|
|
11
12
|
export default TestFontsFormElement;
|
|
@@ -2,12 +2,15 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import TestFontsFormFetcher from './index.js';
|
|
4
4
|
const FAMILY_SELECTIONS = ['all', 'choice'];
|
|
5
|
+
const FAMILY_GROUPINGS = ['flat', 'superfamily'];
|
|
5
6
|
const TestFontsFormElement = _ref => {
|
|
6
7
|
let {
|
|
7
8
|
familySelection,
|
|
9
|
+
familyGrouping,
|
|
8
10
|
...props
|
|
9
11
|
} = _ref;
|
|
10
12
|
return /*#__PURE__*/React.createElement(TestFontsFormFetcher, _extends({}, props, {
|
|
13
|
+
familyGrouping: familyGrouping && FAMILY_GROUPINGS.includes(familyGrouping) ? familyGrouping : undefined,
|
|
11
14
|
familySelection: familySelection && FAMILY_SELECTIONS.includes(familySelection) ? familySelection : undefined,
|
|
12
15
|
newsletterCheckboxChecked: props.newsletterCheckboxChecked === 'true' ? true : false
|
|
13
16
|
}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TestFontsFamilyGrouping } from '../ConfigContext.js';
|
|
2
|
+
interface Superfamily {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly name: string | null | undefined;
|
|
5
|
+
}
|
|
6
|
+
export interface TestFontsFamily {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly name: string | null | undefined;
|
|
9
|
+
readonly parent?: Superfamily | null;
|
|
10
|
+
}
|
|
11
|
+
export interface FamilyGroup<Family extends TestFontsFamily> {
|
|
12
|
+
superfamily: Superfamily | null;
|
|
13
|
+
families: Family[];
|
|
14
|
+
}
|
|
15
|
+
export declare function groupFamilies<Family extends TestFontsFamily>(families: readonly Family[], grouping: TestFontsFamilyGrouping): FamilyGroup<Family>[];
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// One row of the family checkboxes: a lone family (`superfamily` null), or a
|
|
2
|
+
// superfamily with its families nested beneath it.
|
|
3
|
+
|
|
4
|
+
// Lays the families out for the form's checkboxes, keeping their order: flat
|
|
5
|
+
// lists each family on its own; 'superfamily' gathers families under their
|
|
6
|
+
// superfamily, placed where its first family falls. A superfamily with only one
|
|
7
|
+
// family to offer adds nothing over that family, so the family stands alone.
|
|
8
|
+
export function groupFamilies(families, grouping) {
|
|
9
|
+
const alone = family => ({
|
|
10
|
+
superfamily: null,
|
|
11
|
+
families: [family]
|
|
12
|
+
});
|
|
13
|
+
if (grouping !== 'superfamily') return families.map(alone);
|
|
14
|
+
const groups = [];
|
|
15
|
+
const bySuperfamily = new Map();
|
|
16
|
+
for (const family of families) {
|
|
17
|
+
const superfamily = family.parent;
|
|
18
|
+
if (!superfamily) {
|
|
19
|
+
groups.push(alone(family));
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
let group = bySuperfamily.get(superfamily.id);
|
|
23
|
+
if (!group) {
|
|
24
|
+
group = {
|
|
25
|
+
superfamily,
|
|
26
|
+
families: []
|
|
27
|
+
};
|
|
28
|
+
bySuperfamily.set(superfamily.id, group);
|
|
29
|
+
groups.push(group);
|
|
30
|
+
}
|
|
31
|
+
group.families.push(family);
|
|
32
|
+
}
|
|
33
|
+
return groups.map(group => group.families.length > 1 ? group : alone(group.families[0]));
|
|
34
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { TestFontsForm_Query } from '../../__generated__/TestFontsForm_Query.graphql.js';
|
|
3
3
|
import { SerializablePreloadedQuery, type LoadQueryOptions } from '../../relay/loadSerializableQuery.js';
|
|
4
|
-
import { Config, TestFontsFamilySelection } from '../ConfigContext.js';
|
|
4
|
+
import { Config, TestFontsFamilyGrouping, TestFontsFamilySelection } from '../ConfigContext.js';
|
|
5
5
|
import { TestFontsFormCollectionProps } from './variables.js';
|
|
6
6
|
export interface TestFontsForm_props extends TestFontsFormCollectionProps {
|
|
7
7
|
agreementLabel?: string;
|
|
8
8
|
downloadLabel?: string;
|
|
9
9
|
newsletterCheckboxChecked?: boolean;
|
|
10
10
|
familySelection?: TestFontsFamilySelection;
|
|
11
|
+
familyGrouping?: TestFontsFamilyGrouping;
|
|
11
12
|
}
|
|
12
13
|
export type TestFontsFormPreloadedQuery = SerializablePreloadedQuery<TestFontsForm_Query>;
|
|
13
14
|
export type LoadTestFontsFormQueryVariables = TestFontsFormCollectionProps;
|
|
@@ -18,6 +18,7 @@ import useSerializablePreloadedQuery from '../../relay/useSerializablePreloadedQ
|
|
|
18
18
|
import { EnsureFontdueContext, LazyQueryBoundary } from '../FontdueContextProvider/index.js';
|
|
19
19
|
import ConfigContext from '../ConfigContext.js';
|
|
20
20
|
import { testFontsFormQueryVariables } from './variables.js';
|
|
21
|
+
import { groupFamilies } from './familyGroups.js';
|
|
21
22
|
import { useRecaptchaTimeout, isRecaptchaScriptLoaded, RECAPTCHA_UNAVAILABLE_MESSAGE } from '../../hooks/useRecaptchaTimeout.js';
|
|
22
23
|
const updateCustomerMutation = (_TestFontsFormUpdateCustomerMutation.hash && _TestFontsFormUpdateCustomerMutation.hash !== "ba56958399f0893bd667ff02c33a6975" && console.error("The definition of 'TestFontsFormUpdateCustomerMutation' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _TestFontsFormUpdateCustomerMutation);
|
|
23
24
|
// The archive endpoint's family filter: `collection_ids[]` narrows the ZIP to
|
|
@@ -41,7 +42,7 @@ const TestFontsDownloading = _ref => {
|
|
|
41
42
|
}, "here"), ".")));
|
|
42
43
|
};
|
|
43
44
|
const TestFontsFormComponent = _ref2 => {
|
|
44
|
-
var _data$viewer$testFont, _data$viewer$fontdueC, _data$viewer$settings, _data$viewer$settings2, _data$viewer$testFont2;
|
|
45
|
+
var _data$viewer$testFont, _data$viewer$fontdueC, _data$viewer$fontdueC2, _data$viewer$settings, _data$viewer$settings2, _data$viewer$testFont2;
|
|
45
46
|
let {
|
|
46
47
|
data,
|
|
47
48
|
agreementLabel,
|
|
@@ -49,7 +50,8 @@ const TestFontsFormComponent = _ref2 => {
|
|
|
49
50
|
newsletterCheckboxChecked = false,
|
|
50
51
|
collectionId,
|
|
51
52
|
collectionSlug,
|
|
52
|
-
familySelection: familySelectionProp
|
|
53
|
+
familySelection: familySelectionProp,
|
|
54
|
+
familyGrouping: familyGroupingProp
|
|
53
55
|
} = _ref2;
|
|
54
56
|
const [email, setEmail] = useState('');
|
|
55
57
|
const [name, setName] = useState('');
|
|
@@ -82,11 +84,30 @@ const TestFontsFormComponent = _ref2 => {
|
|
|
82
84
|
// This form's prop, then code config (which, on the script-tag path, already
|
|
83
85
|
// has the dashboard setting merged beneath it), then the dashboard setting.
|
|
84
86
|
const familySelection = familySelectionProp ?? config.testFonts.familySelection ?? ((_data$viewer$fontdueC = data.viewer.fontdueConfig) === null || _data$viewer$fontdueC === void 0 ? void 0 : _data$viewer$fontdueC.testFonts.familySelection) ?? 'all';
|
|
87
|
+
// Resolved the same way as the family selection.
|
|
88
|
+
const familyGrouping = familyGroupingProp ?? config.testFonts.familyGrouping ?? ((_data$viewer$fontdueC2 = data.viewer.fontdueConfig) === null || _data$viewer$fontdueC2 === void 0 ? void 0 : _data$viewer$fontdueC2.testFonts.familyGrouping) ?? 'flat';
|
|
85
89
|
// One family leaves nothing to choose.
|
|
86
90
|
const choosing = !limited && familySelection === 'choice' && families.length > 1;
|
|
87
91
|
const downloadIds = limited ? families.map(family => family.id) : choosing ? families.map(family => family.id).filter(id => chosenIds.includes(id)) : [];
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
|
|
93
|
+
// Ticks or unticks families – one, or a superfamily's.
|
|
94
|
+
const toggleFamilies = (toggled, checked) => setChosenIds(ids => [...ids.filter(id => !toggled.includes(id)), ...(checked ? toggled : [])]);
|
|
95
|
+
const allChosen = list => list.every(family => chosenIds.includes(family.id));
|
|
96
|
+
const familyGroups = groupFamilies(families, familyGrouping);
|
|
97
|
+
const familyField = family => {
|
|
98
|
+
const fieldId = `${idPrefix}-family-${families.indexOf(family)}`;
|
|
99
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
100
|
+
className: "test-fonts__checkbox-field test-fonts__family",
|
|
101
|
+
key: family.id
|
|
102
|
+
}, /*#__PURE__*/React.createElement(Checkbox, {
|
|
103
|
+
id: fieldId,
|
|
104
|
+
value: family.id,
|
|
105
|
+
checked: chosenIds.includes(family.id),
|
|
106
|
+
onChange: event => toggleFamilies([family.id], event.target.checked)
|
|
107
|
+
}), /*#__PURE__*/React.createElement("label", {
|
|
108
|
+
htmlFor: fieldId
|
|
109
|
+
}, family.name));
|
|
110
|
+
};
|
|
90
111
|
const recaptchaEnabled = ((_data$viewer$settings = data.viewer.settings) === null || _data$viewer$settings === void 0 ? void 0 : _data$viewer$settings.recaptchaEnabled) ?? false;
|
|
91
112
|
const recaptchaSiteKey = (_data$viewer$settings2 = data.viewer.settings) === null || _data$viewer$settings2 === void 0 ? void 0 : _data$viewer$settings2.recaptchaSiteKey;
|
|
92
113
|
const submitForm = useCallback(token => {
|
|
@@ -212,21 +233,30 @@ const TestFontsFormComponent = _ref2 => {
|
|
|
212
233
|
className: "test-fonts__checkbox-field test-fonts__families__all"
|
|
213
234
|
}, /*#__PURE__*/React.createElement(Checkbox, {
|
|
214
235
|
id: `${idPrefix}-families-all`,
|
|
215
|
-
checked: allChosen,
|
|
236
|
+
checked: allChosen(families),
|
|
216
237
|
onChange: event => setChosenIds(event.target.checked ? families.map(family => family.id) : [])
|
|
217
238
|
}), /*#__PURE__*/React.createElement("label", {
|
|
218
239
|
htmlFor: `${idPrefix}-families-all`
|
|
219
|
-
}, "Select all")),
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
240
|
+
}, "Select all")), familyGroups.map((_ref4, groupIndex) => {
|
|
241
|
+
let {
|
|
242
|
+
superfamily,
|
|
243
|
+
families: grouped
|
|
244
|
+
} = _ref4;
|
|
245
|
+
return superfamily ? /*#__PURE__*/React.createElement("div", {
|
|
246
|
+
className: "test-fonts__family-group",
|
|
247
|
+
key: superfamily.id
|
|
248
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
249
|
+
className: "test-fonts__checkbox-field test-fonts__superfamily"
|
|
250
|
+
}, /*#__PURE__*/React.createElement(Checkbox, {
|
|
251
|
+
id: `${idPrefix}-superfamily-${groupIndex}`,
|
|
252
|
+
checked: allChosen(grouped),
|
|
253
|
+
onChange: event => toggleFamilies(grouped.map(family => family.id), event.target.checked)
|
|
254
|
+
}), /*#__PURE__*/React.createElement("label", {
|
|
255
|
+
htmlFor: `${idPrefix}-superfamily-${groupIndex}`
|
|
256
|
+
}, superfamily.name)), /*#__PURE__*/React.createElement("div", {
|
|
257
|
+
className: "test-fonts__family-group__families"
|
|
258
|
+
}, grouped.map(familyField))) : familyField(grouped[0]);
|
|
259
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
230
260
|
className: "test-fonts__section"
|
|
231
261
|
}, /*#__PURE__*/React.createElement(TextField, {
|
|
232
262
|
label: "Name *",
|
|
@@ -289,7 +319,7 @@ const TestFontsFormComponent = _ref2 => {
|
|
|
289
319
|
value: id
|
|
290
320
|
}))));
|
|
291
321
|
};
|
|
292
|
-
const query = (_TestFontsForm_Query.hash && _TestFontsForm_Query.hash !== "
|
|
322
|
+
const query = (_TestFontsForm_Query.hash && _TestFontsForm_Query.hash !== "9ef2c42a7043469fec07a31649623766" && console.error("The definition of 'TestFontsForm_Query' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _TestFontsForm_Query);
|
|
293
323
|
// Pass the same `collectionId` / `collectionSlug` as the form's props.
|
|
294
324
|
export async function loadTestFontsFormQuery(variables, options) {
|
|
295
325
|
// Before the collection variables existed this took `options` alone.
|
|
@@ -298,11 +328,11 @@ export async function loadTestFontsFormQuery(variables, options) {
|
|
|
298
328
|
}
|
|
299
329
|
return loadSerializableQuery(TestFontsFormQueryNode, testFontsFormQueryVariables(variables ?? {}), options);
|
|
300
330
|
}
|
|
301
|
-
export function TestFontsFormPreloadedQueryRenderer(
|
|
331
|
+
export function TestFontsFormPreloadedQueryRenderer(_ref5) {
|
|
302
332
|
let {
|
|
303
333
|
preloadedQuery,
|
|
304
334
|
...rest
|
|
305
|
-
} =
|
|
335
|
+
} = _ref5;
|
|
306
336
|
// The query node lets the hook commit the payload into the store, so
|
|
307
337
|
// usePreloadedQuery resolves synchronously during SSR instead of
|
|
308
338
|
// refetching (the response cache only exists in the browser).
|
|
@@ -322,11 +352,11 @@ function TestFontsFormLazyQueryRenderer(props) {
|
|
|
322
352
|
// (server-side preload path) or fetches lazily on mount. `EnsureFontdueContext`
|
|
323
353
|
// only self-wraps with `FontdueContextProvider` when no parent Fontdue
|
|
324
354
|
// context is present, seeding it with `config`.
|
|
325
|
-
export default function TestFontsForm(
|
|
355
|
+
export default function TestFontsForm(_ref6) {
|
|
326
356
|
let {
|
|
327
357
|
config,
|
|
328
358
|
...props
|
|
329
|
-
} =
|
|
359
|
+
} = _ref6;
|
|
330
360
|
return /*#__PURE__*/React.createElement(EnsureFontdueContext, {
|
|
331
361
|
config: config
|
|
332
362
|
}, props.preloadedQuery ? /*#__PURE__*/React.createElement(TestFontsFormPreloadedQueryRenderer, _extends({}, props, {
|
|
@@ -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,32 @@ 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
|
+
* Safari 26.0.x (macOS Tahoe / iOS 26 before their point updates) parses the
|
|
18
|
+
* FontFace family argument as CSS, so a name like "Hell's Gate fairypools"
|
|
19
|
+
* (the apostrophe opens an unterminated string) or "0712 Regular" (an
|
|
20
|
+
* identifier can't start with a digit) makes `load()` reject with
|
|
21
|
+
* "SyntaxError: The string did not match the expected pattern." and the style
|
|
22
|
+
* never renders. Chrome and other Safari builds (17.3, 18.4, 26.4+, 27.0 were
|
|
23
|
+
* checked) take the argument literally. A name that is valid either way
|
|
24
|
+
* works everywhere:
|
|
25
|
+
*
|
|
26
|
+
* - an ASCII character other than a letter, digit, `-` or `_` is escaped as
|
|
27
|
+
* `_<hex code>` (`'` → `_27`), so distinct names stay distinct;
|
|
28
|
+
* - a word starting with a digit, `-<digit>` or `--`, or matching a reserved
|
|
29
|
+
* word, gets a leading `_`.
|
|
30
|
+
*
|
|
31
|
+
* Non-ASCII characters are valid identifier characters and are kept.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* fontStyleFamily("Hell's Gate", 'fairypools') // => 'Hell_27s Gate fairypools'
|
|
35
|
+
* fontStyleFamily('0712', 'Regular') // => '_0712 Regular'
|
|
36
|
+
*/
|
|
37
|
+
export declare function fontStyleFamily(cssFamily: string | null | undefined, styleName: string): string;
|
|
12
38
|
export declare function isFontLoaded(fontFamily: string): boolean;
|
|
13
39
|
export declare function loadFont(fontFamily: string, sources: ReadonlyArray<FontSource | null>, verticalMetrics?: VerticalMetrics | null): Promise<FontFace | null>;
|
|
14
40
|
/**
|
package/dist/fontLoader.js
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
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
|
+
* Safari 26.0.x (macOS Tahoe / iOS 26 before their point updates) parses the
|
|
11
|
+
* FontFace family argument as CSS, so a name like "Hell's Gate fairypools"
|
|
12
|
+
* (the apostrophe opens an unterminated string) or "0712 Regular" (an
|
|
13
|
+
* identifier can't start with a digit) makes `load()` reject with
|
|
14
|
+
* "SyntaxError: The string did not match the expected pattern." and the style
|
|
15
|
+
* never renders. Chrome and other Safari builds (17.3, 18.4, 26.4+, 27.0 were
|
|
16
|
+
* checked) take the argument literally. A name that is valid either way
|
|
17
|
+
* works everywhere:
|
|
18
|
+
*
|
|
19
|
+
* - an ASCII character other than a letter, digit, `-` or `_` is escaped as
|
|
20
|
+
* `_<hex code>` (`'` → `_27`), so distinct names stay distinct;
|
|
21
|
+
* - a word starting with a digit, `-<digit>` or `--`, or matching a reserved
|
|
22
|
+
* word, gets a leading `_`.
|
|
23
|
+
*
|
|
24
|
+
* Non-ASCII characters are valid identifier characters and are kept.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* fontStyleFamily("Hell's Gate", 'fairypools') // => 'Hell_27s Gate fairypools'
|
|
28
|
+
* fontStyleFamily('0712', 'Regular') // => '_0712 Regular'
|
|
29
|
+
*/
|
|
30
|
+
export function fontStyleFamily(cssFamily, styleName) {
|
|
31
|
+
return `${cssFamily ?? ''} ${styleName}`.split(/\s+/).filter(word => word.length > 0).map(cssIdentifierWord).join(' ');
|
|
32
|
+
}
|
|
33
|
+
function cssIdentifierWord(word) {
|
|
34
|
+
const escaped = word.replace(/[\x00-\x7f]/g, char => /[A-Za-z0-9_-]/.test(char) ? char : `_${char.charCodeAt(0).toString(16)}`);
|
|
35
|
+
const unparseable = /^(?:[0-9]|-[0-9]|--|-$)/.test(escaped);
|
|
36
|
+
return unparseable || RESERVED_FAMILY_WORDS.has(escaped.toLowerCase()) ? `_${escaped}` : escaped;
|
|
37
|
+
}
|
|
1
38
|
const cache = new Map();
|
|
2
39
|
const loaded = new Set();
|
|
3
40
|
export function isFontLoaded(fontFamily) {
|
package/dist/fontdue.css
CHANGED
|
@@ -185,6 +185,9 @@
|
|
|
185
185
|
.test-fonts__families .test-fonts__checkbox-field {
|
|
186
186
|
margin-bottom: 10px;
|
|
187
187
|
}
|
|
188
|
+
.test-fonts__family-group__families {
|
|
189
|
+
padding-left: calc(var(--checkbox-size, 20px) + var(--checkbox-margin, 10px));
|
|
190
|
+
}
|
|
188
191
|
.test-fonts__agreement[data-highlighted=true] {
|
|
189
192
|
color: red;
|
|
190
193
|
}
|
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.11.0";
|