fontdue-js 3.0.1 → 3.0.3
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 +8 -0
- package/dist/__tests__/glyphMatch.test.js +123 -0
- package/dist/components/CartButton/index.js +1 -1
- package/dist/components/CharacterViewer/glyphMatch.d.ts +29 -0
- package/dist/components/CharacterViewer/glyphMatch.js +56 -0
- package/dist/components/CharacterViewer/index.js +19 -65
- package/dist/components/StoreModal/StoreModalStyleButton.js +5 -4
- package/dist/components/elements/StoreModalStyleButton/index.js +2 -2
- package/dist/corsError.js +1 -1
- package/dist/fontdue.css +11 -1
- package/dist/relay/environment.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 3.0.3
|
|
2
|
+
|
|
3
|
+
- Fixed misaligned style names in `StoreModal`. The feature-glyphs preview is no longer rendered when a style has nothing to show — a variable font with no named instances, or a non-variable style with no representative glyph for its languages — so its empty wrapper no longer indents the style name and rows in a family now line up.
|
|
4
|
+
|
|
5
|
+
## 3.0.2
|
|
6
|
+
|
|
7
|
+
- Fixed the `CharacterViewer` dropping character groups that have no OpenType feature (such as Uppercase, Lowercase, and Punctuation). The glyph matcher now treats an empty feature list, `null`, and `undefined` as the same “no feature” state, so a featureless group matches whether the API returns `[]` or `null` for it.
|
|
8
|
+
|
|
1
9
|
## 3.0.1
|
|
2
10
|
|
|
3
11
|
- Fixed analytics tracking and consent events posting to the wrong address in non-Next.js frameworks. In Vite-based setups (Astro, React Router 7, TanStack Start) that configure the Fontdue URL through `PUBLIC_FONTDUE_URL` / `VITE_FONTDUE_URL` and pass a `preloadedQuery` to `<FontdueProvider>` (rather than an explicit `url` prop), the page-view and consent requests went to a relative `/api/track/page` on the site’s own origin instead of the configured Fontdue server. They now resolve the Fontdue URL the same way GraphQL requests do. Next.js sites were unaffected.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { compareGlyphs, flattenCharacterList } from "../components/CharacterViewer/glyphMatch.js";
|
|
3
|
+
describe('compareGlyphs', () => {
|
|
4
|
+
it('treats an empty feature array and null as the same "no feature" state', () => {
|
|
5
|
+
// The regression: glyph groups save base sets as `[]`, but the font's
|
|
6
|
+
// glyphNames report base glyphs with `null`. These must match.
|
|
7
|
+
expect(compareGlyphs({
|
|
8
|
+
string: 'a',
|
|
9
|
+
features: []
|
|
10
|
+
}, {
|
|
11
|
+
string: 'a',
|
|
12
|
+
features: null
|
|
13
|
+
})).toBe(true);
|
|
14
|
+
expect(compareGlyphs({
|
|
15
|
+
string: 'a',
|
|
16
|
+
features: null
|
|
17
|
+
}, {
|
|
18
|
+
string: 'a',
|
|
19
|
+
features: []
|
|
20
|
+
})).toBe(true);
|
|
21
|
+
expect(compareGlyphs({
|
|
22
|
+
string: 'a',
|
|
23
|
+
features: undefined
|
|
24
|
+
}, {
|
|
25
|
+
string: 'a',
|
|
26
|
+
features: []
|
|
27
|
+
})).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it('matches identical single features', () => {
|
|
30
|
+
expect(compareGlyphs({
|
|
31
|
+
string: 'a',
|
|
32
|
+
features: ['ss01']
|
|
33
|
+
}, {
|
|
34
|
+
string: 'a',
|
|
35
|
+
features: ['ss01']
|
|
36
|
+
})).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('does not match a feature-bearing set against a base glyph', () => {
|
|
39
|
+
expect(compareGlyphs({
|
|
40
|
+
string: 'a',
|
|
41
|
+
features: ['ss01']
|
|
42
|
+
}, {
|
|
43
|
+
string: 'a',
|
|
44
|
+
features: null
|
|
45
|
+
})).toBe(false);
|
|
46
|
+
expect(compareGlyphs({
|
|
47
|
+
string: 'a',
|
|
48
|
+
features: ['ss01']
|
|
49
|
+
}, {
|
|
50
|
+
string: 'a',
|
|
51
|
+
features: []
|
|
52
|
+
})).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
it('does not match different features or different strings', () => {
|
|
55
|
+
expect(compareGlyphs({
|
|
56
|
+
string: 'a',
|
|
57
|
+
features: ['ss01']
|
|
58
|
+
}, {
|
|
59
|
+
string: 'a',
|
|
60
|
+
features: ['ss02']
|
|
61
|
+
})).toBe(false);
|
|
62
|
+
expect(compareGlyphs({
|
|
63
|
+
string: 'a',
|
|
64
|
+
features: []
|
|
65
|
+
}, {
|
|
66
|
+
string: 'b',
|
|
67
|
+
features: []
|
|
68
|
+
})).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('flattenCharacterList', () => {
|
|
72
|
+
// glyphNames as the backend reports them: base glyphs carry `features: null`.
|
|
73
|
+
const glyphNames = [{
|
|
74
|
+
characters: 'a',
|
|
75
|
+
features: null
|
|
76
|
+
}, {
|
|
77
|
+
characters: 'b',
|
|
78
|
+
features: null
|
|
79
|
+
}, {
|
|
80
|
+
characters: 'c',
|
|
81
|
+
features: null
|
|
82
|
+
}, {
|
|
83
|
+
characters: 'a',
|
|
84
|
+
features: ['ss01']
|
|
85
|
+
}];
|
|
86
|
+
it('keeps a no-feature range whose glyphs exist as base glyphs (the storefront regression)', () => {
|
|
87
|
+
const result = flattenCharacterList({
|
|
88
|
+
characters: [{
|
|
89
|
+
__typename: 'CharacterRange',
|
|
90
|
+
first: 'a',
|
|
91
|
+
last: 'c'
|
|
92
|
+
}],
|
|
93
|
+
features: [] // saved by the editor as an empty array
|
|
94
|
+
}, glyphNames);
|
|
95
|
+
// Previously this returned [] (every char dropped) and the group vanished.
|
|
96
|
+
expect(result === null || result === void 0 ? void 0 : result.characters).toEqual(['a', 'b', 'c']);
|
|
97
|
+
});
|
|
98
|
+
it('drops characters the font does not contain', () => {
|
|
99
|
+
const result = flattenCharacterList({
|
|
100
|
+
characters: [{
|
|
101
|
+
__typename: 'CharacterRange',
|
|
102
|
+
first: 'a',
|
|
103
|
+
last: 'd'
|
|
104
|
+
}],
|
|
105
|
+
features: []
|
|
106
|
+
}, glyphNames);
|
|
107
|
+
expect(result === null || result === void 0 ? void 0 : result.characters).toEqual(['a', 'b', 'c']); // 'd' is not in the font
|
|
108
|
+
});
|
|
109
|
+
it('matches feature sets only against glyphs reachable via that feature', () => {
|
|
110
|
+
const result = flattenCharacterList({
|
|
111
|
+
characters: [{
|
|
112
|
+
__typename: 'CharacterString',
|
|
113
|
+
string: 'a'
|
|
114
|
+
}, {
|
|
115
|
+
__typename: 'CharacterString',
|
|
116
|
+
string: 'b'
|
|
117
|
+
}],
|
|
118
|
+
features: ['ss01']
|
|
119
|
+
}, glyphNames);
|
|
120
|
+
// Only 'a' has an ss01 form; 'b' does not.
|
|
121
|
+
expect(result === null || result === void 0 ? void 0 : result.characters).toEqual(['a']);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface Glyph {
|
|
2
|
+
string: string;
|
|
3
|
+
features?: readonly string[] | null;
|
|
4
|
+
}
|
|
5
|
+
export type CharacterRange = {
|
|
6
|
+
__typename: 'CharacterRange';
|
|
7
|
+
first: string;
|
|
8
|
+
last: string;
|
|
9
|
+
};
|
|
10
|
+
export type CharacterString = {
|
|
11
|
+
__typename: 'CharacterString';
|
|
12
|
+
string: string;
|
|
13
|
+
};
|
|
14
|
+
export type CharacterItem = CharacterRange | CharacterString | {
|
|
15
|
+
__typename: '%other';
|
|
16
|
+
};
|
|
17
|
+
export declare function charCode(c: string): number;
|
|
18
|
+
export declare function fromCharCode(code: number): string;
|
|
19
|
+
export declare function compareGlyphs(a: Glyph | undefined, b: Glyph | undefined): boolean;
|
|
20
|
+
export declare function flattenCharacterList(charSet: {
|
|
21
|
+
characters: readonly CharacterItem[] | null;
|
|
22
|
+
features: readonly string[] | null;
|
|
23
|
+
} | null, glyphNames: readonly {
|
|
24
|
+
characters: string;
|
|
25
|
+
features: readonly string[] | null;
|
|
26
|
+
}[] | null): {
|
|
27
|
+
characters: string[];
|
|
28
|
+
features?: readonly string[] | null;
|
|
29
|
+
} | null;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Glyph matching for the character viewer.
|
|
2
|
+
//
|
|
3
|
+
// A glyph group's character set is matched against the font's `glyphNames` so
|
|
4
|
+
// only characters the font actually contains are rendered. The subtle part is
|
|
5
|
+
// the OpenType `features` array: a base glyph ("no feature") is expressed as
|
|
6
|
+
// `null` in `glyphNames` (and in the backend's auto-generated default groups),
|
|
7
|
+
// but the glyph-group editor saves base sets with an empty array `[]`. These
|
|
8
|
+
// must be treated as the same "no features" state — otherwise every no-feature
|
|
9
|
+
// group (Uppercase, Lowercase, Punctuation, …) renders empty and is dropped.
|
|
10
|
+
|
|
11
|
+
export function charCode(c) {
|
|
12
|
+
return c.codePointAt(0) ?? 0;
|
|
13
|
+
}
|
|
14
|
+
export function fromCharCode(code) {
|
|
15
|
+
return String.fromCodePoint(code);
|
|
16
|
+
}
|
|
17
|
+
export function compareGlyphs(a, b) {
|
|
18
|
+
if (!a || !b) return false;
|
|
19
|
+
if (a.string !== b.string) return false;
|
|
20
|
+
// Normalize missing/empty features to a single representation. Comparing the
|
|
21
|
+
// raw arrays' lengths treated `[]` (length 0) and `null`/`undefined` (no
|
|
22
|
+
// length) as different, so a base group saved as `[]` never matched a base
|
|
23
|
+
// glyph reported as `null` and the group disappeared on the storefront.
|
|
24
|
+
const fa = a.features ?? [];
|
|
25
|
+
const fb = b.features ?? [];
|
|
26
|
+
if (fa.length !== fb.length) return false;
|
|
27
|
+
return fa.every(feature => fb.includes(feature));
|
|
28
|
+
}
|
|
29
|
+
export function flattenCharacterList(charSet, glyphNames) {
|
|
30
|
+
if (!glyphNames || !charSet || !charSet.characters) return null;
|
|
31
|
+
return {
|
|
32
|
+
features: charSet.features,
|
|
33
|
+
characters: charSet.characters.reduce((acc, item) => {
|
|
34
|
+
if (item.__typename === 'CharacterString') {
|
|
35
|
+
acc.push(item.string);
|
|
36
|
+
} else if (item.__typename === 'CharacterRange') {
|
|
37
|
+
for (let code = charCode(item.first); code <= charCode(item.last); code++) {
|
|
38
|
+
acc.push(fromCharCode(code));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return acc;
|
|
42
|
+
}, []).filter(string => glyphNames.some(_ref => {
|
|
43
|
+
let {
|
|
44
|
+
characters,
|
|
45
|
+
features
|
|
46
|
+
} = _ref;
|
|
47
|
+
return compareGlyphs({
|
|
48
|
+
string,
|
|
49
|
+
features: charSet.features
|
|
50
|
+
}, {
|
|
51
|
+
string: characters,
|
|
52
|
+
features
|
|
53
|
+
});
|
|
54
|
+
}))
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -22,6 +22,7 @@ import CharacterViewerStyleRefetchQueryNode from '../../__generated__/CharacterV
|
|
|
22
22
|
import { EnsureFontdueContext } from '../FontdueContextProvider/index.js';
|
|
23
23
|
import ConfigContext from '../ConfigContext.js';
|
|
24
24
|
import { unicodeNamesUrl } from '../../data/unicodeNamesUrl.js';
|
|
25
|
+
import { compareGlyphs, flattenCharacterList } from './glyphMatch.js';
|
|
25
26
|
function useSize() {
|
|
26
27
|
const ref = useRef(null);
|
|
27
28
|
const [size, setSize] = React.useState();
|
|
@@ -99,53 +100,6 @@ function useUnicodeData() {
|
|
|
99
100
|
}, [url]);
|
|
100
101
|
return data;
|
|
101
102
|
}
|
|
102
|
-
function compareGlyphs(a, b) {
|
|
103
|
-
var _a$features, _b$features;
|
|
104
|
-
if (!a || !b) return false;
|
|
105
|
-
if (a.string !== b.string) return false;
|
|
106
|
-
if (((_a$features = a.features) === null || _a$features === void 0 ? void 0 : _a$features.length) !== ((_b$features = b.features) === null || _b$features === void 0 ? void 0 : _b$features.length)) return false;
|
|
107
|
-
if (a.features && b.features) {
|
|
108
|
-
return a.features.every(feature => {
|
|
109
|
-
var _b$features2;
|
|
110
|
-
return (_b$features2 = b.features) === null || _b$features2 === void 0 ? void 0 : _b$features2.includes(feature);
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
return true;
|
|
114
|
-
}
|
|
115
|
-
function charCode(c) {
|
|
116
|
-
return c.codePointAt(0) ?? 0;
|
|
117
|
-
}
|
|
118
|
-
function fromCharCode(code) {
|
|
119
|
-
return String.fromCodePoint(code);
|
|
120
|
-
}
|
|
121
|
-
function flattenCharacterList(charSet, glyphNames) {
|
|
122
|
-
if (!glyphNames || !charSet || !charSet.characters) return null;
|
|
123
|
-
return {
|
|
124
|
-
features: charSet.features,
|
|
125
|
-
characters: charSet.characters.reduce((acc, item) => {
|
|
126
|
-
if (item.__typename === 'CharacterString') {
|
|
127
|
-
acc.push(item.string);
|
|
128
|
-
} else if (item.__typename === 'CharacterRange') {
|
|
129
|
-
for (let code = charCode(item.first); code <= charCode(item.last); code++) {
|
|
130
|
-
acc.push(fromCharCode(code));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return acc;
|
|
134
|
-
}, []).filter(string => glyphNames.some(_ref2 => {
|
|
135
|
-
let {
|
|
136
|
-
characters,
|
|
137
|
-
features
|
|
138
|
-
} = _ref2;
|
|
139
|
-
return compareGlyphs({
|
|
140
|
-
string,
|
|
141
|
-
features: charSet.features
|
|
142
|
-
}, {
|
|
143
|
-
string: characters,
|
|
144
|
-
features
|
|
145
|
-
});
|
|
146
|
-
}))
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
103
|
_CharacterViewer_family.hash && _CharacterViewer_family.hash !== "162b1a99fe187b20ee8560018cd5b3ce" && console.error("The definition of 'CharacterViewer_family' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _CharacterViewer_family;
|
|
150
104
|
function areCombiningChars(input) {
|
|
151
105
|
for (const char of input) {
|
|
@@ -170,10 +124,10 @@ function hasUnsupportedPositionalFeatures(features) {
|
|
|
170
124
|
if (!features) return false;
|
|
171
125
|
return features.some(f => UNSUPPORTED_POSITIONAL_FEATURES.includes(f));
|
|
172
126
|
}
|
|
173
|
-
function CharacterViewerComponent(
|
|
127
|
+
function CharacterViewerComponent(_ref2) {
|
|
174
128
|
let {
|
|
175
129
|
collection: collectionKey
|
|
176
|
-
} =
|
|
130
|
+
} = _ref2;
|
|
177
131
|
const collection = useFragment((_CharacterViewer_collection.hash && _CharacterViewer_collection.hash !== "c2116c3c2c795e5306c3a2a0ecd60137" && console.error("The definition of 'CharacterViewer_collection' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _CharacterViewer_collection), collectionKey);
|
|
178
132
|
const [fontStyle, refetchFontStyle] = useRefetchableFragment((_CharacterViewer_style.hash && _CharacterViewer_style.hash !== "8cbf3328030930b88b3ec3601aaf7c45" && console.error("The definition of 'CharacterViewer_style' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _CharacterViewer_style), collection.featureStyle);
|
|
179
133
|
let families = [];
|
|
@@ -221,11 +175,11 @@ function CharacterViewerComponent(_ref3) {
|
|
|
221
175
|
const visibleGlyph = activeGlyph ?? selectedGlyph;
|
|
222
176
|
const getGlyphName = useCallback(glyph => {
|
|
223
177
|
var _fontStyle$glyphNames, _fontStyle$glyphNames2;
|
|
224
|
-
return (fontStyle === null || fontStyle === void 0 ? void 0 : (_fontStyle$glyphNames = fontStyle.glyphNames) === null || _fontStyle$glyphNames === void 0 ? void 0 : (_fontStyle$glyphNames2 = _fontStyle$glyphNames.find(
|
|
178
|
+
return (fontStyle === null || fontStyle === void 0 ? void 0 : (_fontStyle$glyphNames = fontStyle.glyphNames) === null || _fontStyle$glyphNames === void 0 ? void 0 : (_fontStyle$glyphNames2 = _fontStyle$glyphNames.find(_ref3 => {
|
|
225
179
|
let {
|
|
226
180
|
characters,
|
|
227
181
|
features
|
|
228
|
-
} =
|
|
182
|
+
} = _ref3;
|
|
229
183
|
return compareGlyphs(glyph, {
|
|
230
184
|
string: characters,
|
|
231
185
|
features
|
|
@@ -310,12 +264,12 @@ function CharacterViewerComponent(_ref3) {
|
|
|
310
264
|
threshold > 0 && visible.some(v => Math.abs(v.position - line.position) < threshold) ? visible : [...visible, line], []);
|
|
311
265
|
const groups = useMemo(() => {
|
|
312
266
|
var _collection$glyphGrou;
|
|
313
|
-
return (_collection$glyphGrou = collection.glyphGroups) === null || _collection$glyphGrou === void 0 ? void 0 : _collection$glyphGrou.map(
|
|
267
|
+
return (_collection$glyphGrou = collection.glyphGroups) === null || _collection$glyphGrou === void 0 ? void 0 : _collection$glyphGrou.map(_ref4 => {
|
|
314
268
|
var _characterSets$filter;
|
|
315
269
|
let {
|
|
316
270
|
name,
|
|
317
271
|
characterSets
|
|
318
|
-
} =
|
|
272
|
+
} = _ref4;
|
|
319
273
|
return {
|
|
320
274
|
name,
|
|
321
275
|
characterSets: characterSets
|
|
@@ -388,11 +342,11 @@ function CharacterViewerComponent(_ref3) {
|
|
|
388
342
|
style: cellWidth ? {
|
|
389
343
|
'--cell-width': `${cellWidth}px`
|
|
390
344
|
} : undefined
|
|
391
|
-
}, groups === null || groups === void 0 ? void 0 : groups.map((
|
|
345
|
+
}, groups === null || groups === void 0 ? void 0 : groups.map((_ref5, i) => {
|
|
392
346
|
let {
|
|
393
347
|
name,
|
|
394
348
|
characterSets
|
|
395
|
-
} =
|
|
349
|
+
} = _ref5;
|
|
396
350
|
return /*#__PURE__*/React.createElement("div", {
|
|
397
351
|
className: "character-viewer__block",
|
|
398
352
|
key: i,
|
|
@@ -438,10 +392,10 @@ export async function loadCharacterViewerQuery(variables, options) {
|
|
|
438
392
|
}
|
|
439
393
|
throw new Error('loadCharacterViewerQuery expected either collectionId or collectionSlug');
|
|
440
394
|
}
|
|
441
|
-
function CharacterViewerIdQueryRenderer(
|
|
395
|
+
function CharacterViewerIdQueryRenderer(_ref6) {
|
|
442
396
|
let {
|
|
443
397
|
collectionId
|
|
444
|
-
} =
|
|
398
|
+
} = _ref6;
|
|
445
399
|
const data = useLazyLoadQuery(idQuery, {
|
|
446
400
|
collectionId
|
|
447
401
|
});
|
|
@@ -450,11 +404,11 @@ function CharacterViewerIdQueryRenderer(_ref7) {
|
|
|
450
404
|
collection: data.node
|
|
451
405
|
});
|
|
452
406
|
}
|
|
453
|
-
export function CharacterViewerPreloadedIDQueryRenderer(
|
|
407
|
+
export function CharacterViewerPreloadedIDQueryRenderer(_ref7) {
|
|
454
408
|
let {
|
|
455
409
|
preloadedQuery,
|
|
456
410
|
...rest
|
|
457
|
-
} =
|
|
411
|
+
} = _ref7;
|
|
458
412
|
// The query node lets the hook commit the payload into the store, so
|
|
459
413
|
// usePreloadedQuery resolves synchronously during SSR instead of
|
|
460
414
|
// refetching (the response cache only exists in the browser).
|
|
@@ -465,11 +419,11 @@ export function CharacterViewerPreloadedIDQueryRenderer(_ref8) {
|
|
|
465
419
|
collection: data.node
|
|
466
420
|
}));
|
|
467
421
|
}
|
|
468
|
-
function CharacterViewerSlugQueryRenderer(
|
|
422
|
+
function CharacterViewerSlugQueryRenderer(_ref8) {
|
|
469
423
|
var _data$viewer, _data$viewer$slug;
|
|
470
424
|
let {
|
|
471
425
|
collectionSlug
|
|
472
|
-
} =
|
|
426
|
+
} = _ref8;
|
|
473
427
|
const data = useLazyLoadQuery(slugQuery, {
|
|
474
428
|
collectionSlug
|
|
475
429
|
});
|
|
@@ -479,12 +433,12 @@ function CharacterViewerSlugQueryRenderer(_ref9) {
|
|
|
479
433
|
collection: collection
|
|
480
434
|
});
|
|
481
435
|
}
|
|
482
|
-
export function CharacterViewerPreloadedSlugQueryRenderer(
|
|
436
|
+
export function CharacterViewerPreloadedSlugQueryRenderer(_ref9) {
|
|
483
437
|
var _data$viewer2, _data$viewer2$slug;
|
|
484
438
|
let {
|
|
485
439
|
preloadedQuery,
|
|
486
440
|
...rest
|
|
487
|
-
} =
|
|
441
|
+
} = _ref9;
|
|
488
442
|
// The query node lets the hook commit the payload into the store, so
|
|
489
443
|
// usePreloadedQuery resolves synchronously during SSR instead of
|
|
490
444
|
// refetching (the response cache only exists in the browser).
|
|
@@ -496,11 +450,11 @@ export function CharacterViewerPreloadedSlugQueryRenderer(_ref10) {
|
|
|
496
450
|
collection: collection
|
|
497
451
|
}));
|
|
498
452
|
}
|
|
499
|
-
function CharacterViewerPreloadedRenderer(
|
|
453
|
+
function CharacterViewerPreloadedRenderer(_ref10) {
|
|
500
454
|
let {
|
|
501
455
|
preloadedQuery,
|
|
502
456
|
...rest
|
|
503
|
-
} =
|
|
457
|
+
} = _ref10;
|
|
504
458
|
if (preloadedQuery.params.name === 'CharacterViewerIDQuery') {
|
|
505
459
|
return /*#__PURE__*/React.createElement(CharacterViewerPreloadedIDQueryRenderer, _extends({
|
|
506
460
|
preloadedQuery: preloadedQuery
|
|
@@ -11,7 +11,7 @@ import StoreModalStyleButtonElement from '../elements/StoreModalStyleButton/inde
|
|
|
11
11
|
import { getFeatureGlyphs, variableInstanceCSS } from '../../utils.js';
|
|
12
12
|
const THIN_SPACE = '\u2009';
|
|
13
13
|
export default function StoreModalStyleButton(_ref) {
|
|
14
|
-
var _fontStyle$variableIn;
|
|
14
|
+
var _fontStyle$variableIn, _fontStyle$variableIn2;
|
|
15
15
|
let {
|
|
16
16
|
fontStyle: fontStyleKey,
|
|
17
17
|
onSelectSku,
|
|
@@ -24,17 +24,18 @@ export default function StoreModalStyleButton(_ref) {
|
|
|
24
24
|
if (!fontStyle.sku) return;
|
|
25
25
|
onSelectSku(fontStyle.sku.id, !selected);
|
|
26
26
|
};
|
|
27
|
+
const hasFeatureGlyphs = isVariableFont ? Boolean((_fontStyle$variableIn = fontStyle.variableInstances) === null || _fontStyle$variableIn === void 0 ? void 0 : _fontStyle$variableIn.length) : getFeatureGlyphs(fontStyle.supportedLanguages) != null;
|
|
27
28
|
return /*#__PURE__*/React.createElement(StoreModalStyleButtonElement, _extends({}, rest, {
|
|
28
29
|
onClick: fontStyle.sku ? handleSelect : undefined,
|
|
29
30
|
selected: selected
|
|
30
31
|
}), {
|
|
31
|
-
featureGlyphs: /*#__PURE__*/React.createElement(FontStyle, {
|
|
32
|
+
featureGlyphs: hasFeatureGlyphs ? /*#__PURE__*/React.createElement(FontStyle, {
|
|
32
33
|
fontStyle: fontStyle,
|
|
33
34
|
Component: "span"
|
|
34
|
-
}, isVariableFont ? (_fontStyle$
|
|
35
|
+
}, isVariableFont ? (_fontStyle$variableIn2 = fontStyle.variableInstances) === null || _fontStyle$variableIn2 === void 0 ? void 0 : _fontStyle$variableIn2.map((instance, i) => /*#__PURE__*/React.createElement("span", {
|
|
35
36
|
key: instance.name,
|
|
36
37
|
style: variableInstanceCSS(instance)
|
|
37
|
-
}, i !== 0 && THIN_SPACE, getFeatureGlyphs(fontStyle.supportedLanguages))) : getFeatureGlyphs(fontStyle.supportedLanguages)),
|
|
38
|
+
}, i !== 0 && THIN_SPACE, getFeatureGlyphs(fontStyle.supportedLanguages))) : getFeatureGlyphs(fontStyle.supportedLanguages)) : null,
|
|
38
39
|
// for variable fonts, only show the name of the style if there are
|
|
39
40
|
// multiple styles
|
|
40
41
|
name: isVariableFont ? fontStyle.sku ? fontStyle.name : undefined : fontStyle.name,
|
|
@@ -17,9 +17,9 @@ const StoreModalStyleButton = _ref => {
|
|
|
17
17
|
"data-clickable": Boolean(rest.onClick)
|
|
18
18
|
}), /*#__PURE__*/React.createElement("div", {
|
|
19
19
|
className: "store-modal__style-button__container"
|
|
20
|
-
}, /*#__PURE__*/React.createElement("span", {
|
|
20
|
+
}, featureGlyphs && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
|
|
21
21
|
className: "store-modal__style-button__feature-glyphs"
|
|
22
|
-
}, featureGlyphs), ' ', /*#__PURE__*/React.createElement("span", {
|
|
22
|
+
}, featureGlyphs), ' '), /*#__PURE__*/React.createElement("span", {
|
|
23
23
|
className: "store-modal__style-button__style-name"
|
|
24
24
|
}, name), selected ? /*#__PURE__*/React.createElement("div", {
|
|
25
25
|
className: "store-modal__style-button__checked"
|
package/dist/corsError.js
CHANGED
|
@@ -51,7 +51,7 @@ async function isCorsBlocked(fetchUrl) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
function publishConnectionError(origin, fetchUrl) {
|
|
54
|
-
console.error(`[Fontdue] Cross-origin request to ${fetchUrl} was blocked.\n\n` + `Your website (${origin}) is most likely not listed as an allowed ` + `origin in your Fontdue settings.\n\n` + `To fix this:\n` + `1. Log in to your Fontdue dashboard\n` + `2. Go to Settings
|
|
54
|
+
console.error(`[Fontdue] Cross-origin request to ${fetchUrl} was blocked.\n\n` + `Your website (${origin}) is most likely not listed as an allowed ` + `origin in your Fontdue settings.\n\n` + `To fix this:\n` + `1. Log in to your Fontdue dashboard\n` + `2. Go to Settings \u2192 Integration\n` + `3. Add "${origin}" to the "Cross-origin API access" field\n` + `4. Save \u2014 this page will reload automatically\n\n` + `If "${origin}" is already listed, the connection may be failing for ` + `another reason (a network problem or a temporary Fontdue outage).`);
|
|
55
55
|
|
|
56
56
|
// Surface the connection status as a compact, toolbar-styled widget (red
|
|
57
57
|
// button + alert glyph) rather than the old full-screen modal. It mounts in
|
package/dist/fontdue.css
CHANGED
|
@@ -397,11 +397,20 @@ div[data-component=TypeTesters] {
|
|
|
397
397
|
width: 100%;
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
+
fontdue-type-testers,
|
|
401
|
+
fontdue-type-tester {
|
|
402
|
+
display: block;
|
|
403
|
+
max-width: 100%;
|
|
404
|
+
min-width: 0;
|
|
405
|
+
}
|
|
406
|
+
|
|
400
407
|
.type-tester {
|
|
401
408
|
margin-bottom: 20px;
|
|
402
409
|
font-size: 1rem;
|
|
403
410
|
border-top: 1px solid var(--horizontal_rule_color);
|
|
404
411
|
color: var(--primary_text_color);
|
|
412
|
+
min-width: 0;
|
|
413
|
+
max-width: 100%;
|
|
405
414
|
}
|
|
406
415
|
@media (max-width: 899px) {
|
|
407
416
|
.type-tester {
|
|
@@ -586,7 +595,7 @@ div[data-component=TypeTesters] {
|
|
|
586
595
|
cursor: pointer;
|
|
587
596
|
}
|
|
588
597
|
.type-tester__slider__handle {
|
|
589
|
-
background-color: var(--primary_background_color);
|
|
598
|
+
background-color: var(--primary_background_color, canvas);
|
|
590
599
|
border: 1px solid currentcolor;
|
|
591
600
|
border-radius: 50%;
|
|
592
601
|
height: 15px;
|
|
@@ -1728,6 +1737,7 @@ input:checked + .checkbox__icon {
|
|
|
1728
1737
|
padding-left: 0;
|
|
1729
1738
|
padding-right: 0;
|
|
1730
1739
|
box-shadow: none;
|
|
1740
|
+
background: transparent;
|
|
1731
1741
|
}
|
|
1732
1742
|
|
|
1733
1743
|
.store-modal__family-button__container {
|
|
@@ -7,7 +7,7 @@ import { PREVIEW_HEADER, hasPreviewMarkerCookie } from '../preview/constants.js'
|
|
|
7
7
|
// (defineVersionPlugin in .babelrc.cjs) with the literal package.json#version.
|
|
8
8
|
// Exported so UI (the admin toolbar) can surface it without re-reading the
|
|
9
9
|
// build-time global in a 'use client' module.
|
|
10
|
-
export const version = "3.0.
|
|
10
|
+
export const version = "3.0.3";
|
|
11
11
|
const IS_SERVER = typeof window === typeof undefined;
|
|
12
12
|
|
|
13
13
|
// Opt server fetches into Next's data cache only in production; dev stays
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fontdue-js",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "npm run relay && run-p build-js build-css build-ts",
|
|
@@ -123,9 +123,9 @@
|
|
|
123
123
|
"react-server": "./dist/components/TypeTesters/index.server.js",
|
|
124
124
|
"default": "./dist/components/TypeTesters/index.js"
|
|
125
125
|
},
|
|
126
|
+
"./useAutofit": "./dist/hooks/useAutofit.js",
|
|
126
127
|
"./useConsent": "./dist/components/useConsent.js",
|
|
127
128
|
"./useFont": "./dist/components/useFont.js",
|
|
128
|
-
"./useFontStyle": "./dist/components/useFont.js"
|
|
129
|
-
"./useAutofit": "./dist/hooks/useAutofit.js"
|
|
129
|
+
"./useFontStyle": "./dist/components/useFont.js"
|
|
130
130
|
}
|
|
131
131
|
}
|