fontdue-js 3.4.0 → 3.4.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 +5 -0
- package/dist/__tests__/parseVariableSettings.test.js +73 -0
- package/dist/components/TypeTester/TypeTesterStandaloneElement.js +1 -18
- package/dist/components/TypeTester/parseVariableSettings.d.ts +21 -0
- package/dist/components/TypeTester/parseVariableSettings.js +41 -0
- package/dist/fontdue.css +2 -1
- package/dist/relay/environment.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## 3.4.1
|
|
2
|
+
|
|
3
|
+
- 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.
|
|
4
|
+
- Fixed the `FeatureTesters` switch knob rendering stretched in Safari 18 and earlier. The fix is in `dist/fontdue.css`.
|
|
5
|
+
|
|
1
6
|
## 3.4.0
|
|
2
7
|
|
|
3
8
|
- Added new `openTypeFeatures.interactionStyle: 'dropdown'` for type testers. The features button opens a compact single-column overlay instead of the panel.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { parseVariableSettings } from '../components/TypeTester/parseVariableSettings.js';
|
|
3
|
+
describe('parseVariableSettings', () => {
|
|
4
|
+
let warn;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
7
|
+
});
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
warn.mockRestore();
|
|
10
|
+
});
|
|
11
|
+
it('returns null when the attribute is absent or empty', () => {
|
|
12
|
+
expect(parseVariableSettings(undefined)).toBeNull();
|
|
13
|
+
expect(parseVariableSettings(null)).toBeNull();
|
|
14
|
+
expect(parseVariableSettings('')).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
it('parses integer and decimal values', () => {
|
|
17
|
+
expect(parseVariableSettings('wdth 1000, ital 0.5')).toEqual([{
|
|
18
|
+
axis: 'wdth',
|
|
19
|
+
value: 1000
|
|
20
|
+
}, {
|
|
21
|
+
axis: 'ital',
|
|
22
|
+
value: 0.5
|
|
23
|
+
}]);
|
|
24
|
+
expect(warn).not.toHaveBeenCalled();
|
|
25
|
+
});
|
|
26
|
+
it('parses negative values, so axes like slnt keep their slider', () => {
|
|
27
|
+
expect(parseVariableSettings('slnt -11')).toEqual([{
|
|
28
|
+
axis: 'slnt',
|
|
29
|
+
value: -11
|
|
30
|
+
}]);
|
|
31
|
+
expect(parseVariableSettings('slnt -11.0')).toEqual([{
|
|
32
|
+
axis: 'slnt',
|
|
33
|
+
value: -11
|
|
34
|
+
}]);
|
|
35
|
+
expect(parseVariableSettings('ital -0.5')).toEqual([{
|
|
36
|
+
axis: 'ital',
|
|
37
|
+
value: -0.5
|
|
38
|
+
}]);
|
|
39
|
+
expect(warn).not.toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
it('keeps the sibling axes of a negative setting', () => {
|
|
42
|
+
// Regression for FD-1137: a single unparsed setting used to be dropped, and
|
|
43
|
+
// with it the slider for that axis, leaving adjacent testers inconsistent.
|
|
44
|
+
expect(parseVariableSettings('slnt -11.0, wdth 50.0, wght 300.0')).toEqual([{
|
|
45
|
+
axis: 'slnt',
|
|
46
|
+
value: -11
|
|
47
|
+
}, {
|
|
48
|
+
axis: 'wdth',
|
|
49
|
+
value: 50
|
|
50
|
+
}, {
|
|
51
|
+
axis: 'wght',
|
|
52
|
+
value: 300
|
|
53
|
+
}]);
|
|
54
|
+
expect(warn).not.toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
it('tolerates whitespace around the separator and between axis and value', () => {
|
|
57
|
+
expect(parseVariableSettings(' wght 300 , slnt -11 ')).toEqual([{
|
|
58
|
+
axis: 'wght',
|
|
59
|
+
value: 300
|
|
60
|
+
}, {
|
|
61
|
+
axis: 'slnt',
|
|
62
|
+
value: -11
|
|
63
|
+
}]);
|
|
64
|
+
expect(warn).not.toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
it('warns about and drops malformed settings, keeping the valid ones', () => {
|
|
67
|
+
expect(parseVariableSettings('wght 300, nonsense, wdth abc, slnt -')).toEqual([{
|
|
68
|
+
axis: 'wght',
|
|
69
|
+
value: 300
|
|
70
|
+
}]);
|
|
71
|
+
expect(warn).toHaveBeenCalledTimes(3);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import TypeTesterStandalone from './TypeTesterStandalone.js';
|
|
4
|
-
import {
|
|
4
|
+
import { parseVariableSettings } from './parseVariableSettings.js';
|
|
5
5
|
const isAlignment = str => {
|
|
6
6
|
return str === 'left' || str === 'center' || str === 'right';
|
|
7
7
|
};
|
|
@@ -14,23 +14,6 @@ const parseBool = input => input === 'true' ? true : false;
|
|
|
14
14
|
// `axes="wght, opsz"` behaves the same as `axes="wght,opsz"` and a trailing
|
|
15
15
|
// comma doesn't produce a bogus empty entry.
|
|
16
16
|
const splitList = input => (input === null || input === void 0 ? void 0 : input.split(',').map(token => token.trim()).filter(Boolean)) ?? [];
|
|
17
|
-
|
|
18
|
-
// parse a string like "wdth 1000, ital 0.5" into
|
|
19
|
-
// [{ axis: "wdth", value: 1000 }, { axis: "ital", value: 0.5 }]
|
|
20
|
-
function parseVariableSettings(input) {
|
|
21
|
-
if (!input) return null;
|
|
22
|
-
return input.split(/\s*,\s*/).map(settingString => {
|
|
23
|
-
const m = settingString.match(/^([A-Za-z0-9]{4}) (\d+(?:\.\d+)?)$/);
|
|
24
|
-
if (m && m.length > 2) {
|
|
25
|
-
return {
|
|
26
|
-
axis: m[1],
|
|
27
|
-
value: parseFloat(m[2])
|
|
28
|
-
};
|
|
29
|
-
} else {
|
|
30
|
-
console.warn(`fontdue-type-tester failed to parse variable-settings value: "${settingString}", ignoring`);
|
|
31
|
-
}
|
|
32
|
-
}).filter(notEmpty);
|
|
33
|
-
}
|
|
34
17
|
export const TypeTesterStandaloneElement = _ref => {
|
|
35
18
|
let {
|
|
36
19
|
lineHeight,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the `variable-settings` attribute of `<fontdue-type-tester>` into the
|
|
3
|
+
* axis/value pairs the tester expects.
|
|
4
|
+
*
|
|
5
|
+
* Whitespace around the commas and between an axis and its value is ignored, so
|
|
6
|
+
* `"wdth 1000,ital 0.5"` and `"wdth 1000, ital 0.5"` are equivalent, and a
|
|
7
|
+
* trailing comma is tolerated. Settings that don't parse are warned about and
|
|
8
|
+
* skipped, leaving their siblings intact.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* parseVariableSettings('wdth 1000, ital 0.5')
|
|
12
|
+
* // => [{ axis: 'wdth', value: 1000 }, { axis: 'ital', value: 0.5 }]
|
|
13
|
+
*
|
|
14
|
+
* parseVariableSettings('slnt -11.0')
|
|
15
|
+
* // => [{ axis: 'slnt', value: -11 }]
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseVariableSettings(input: string | null | undefined): {
|
|
18
|
+
axis: string;
|
|
19
|
+
value: number;
|
|
20
|
+
}[] | null;
|
|
21
|
+
export default parseVariableSettings;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { notEmpty } from '../../utils.js';
|
|
2
|
+
|
|
3
|
+
// Value group allows a leading minus: several registered OpenType axes are
|
|
4
|
+
// conventionally negative (`slnt` runs about -20 to 0, `ital` can too), and a
|
|
5
|
+
// custom axis can have any range. A setting that fails to parse is dropped, and
|
|
6
|
+
// TypeTesterVariableAxes only renders a slider for an axis that has a value, so
|
|
7
|
+
// rejecting a sign used to make the slider vanish with nothing in the markup to
|
|
8
|
+
// explain it.
|
|
9
|
+
const SETTING = /^([A-Za-z0-9]{4})\s+(-?\d+(?:\.\d+)?)$/;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Parse the `variable-settings` attribute of `<fontdue-type-tester>` into the
|
|
13
|
+
* axis/value pairs the tester expects.
|
|
14
|
+
*
|
|
15
|
+
* Whitespace around the commas and between an axis and its value is ignored, so
|
|
16
|
+
* `"wdth 1000,ital 0.5"` and `"wdth 1000, ital 0.5"` are equivalent, and a
|
|
17
|
+
* trailing comma is tolerated. Settings that don't parse are warned about and
|
|
18
|
+
* skipped, leaving their siblings intact.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* parseVariableSettings('wdth 1000, ital 0.5')
|
|
22
|
+
* // => [{ axis: 'wdth', value: 1000 }, { axis: 'ital', value: 0.5 }]
|
|
23
|
+
*
|
|
24
|
+
* parseVariableSettings('slnt -11.0')
|
|
25
|
+
* // => [{ axis: 'slnt', value: -11 }]
|
|
26
|
+
*/
|
|
27
|
+
export function parseVariableSettings(input) {
|
|
28
|
+
if (!input) return null;
|
|
29
|
+
return input.split(',').map(settingString => settingString.trim()).filter(Boolean).map(settingString => {
|
|
30
|
+
const m = settingString.match(SETTING);
|
|
31
|
+
if (m && m.length > 2) {
|
|
32
|
+
return {
|
|
33
|
+
axis: m[1],
|
|
34
|
+
value: parseFloat(m[2])
|
|
35
|
+
};
|
|
36
|
+
} else {
|
|
37
|
+
console.warn(`fontdue-type-tester failed to parse variable-settings value: "${settingString}", ignoring`);
|
|
38
|
+
}
|
|
39
|
+
}).filter(notEmpty);
|
|
40
|
+
}
|
|
41
|
+
export default parseVariableSettings;
|
package/dist/fontdue.css
CHANGED
|
@@ -963,6 +963,7 @@ fontdue-feature-testers {
|
|
|
963
963
|
--_sw-knob: var(--fontdue-feature-tester-switch-knob, var(--primary_background_color, canvas));
|
|
964
964
|
--_sw-track: var(--fontdue-feature-tester-switch-track, transparent);
|
|
965
965
|
--_sw-travel: calc(var(--_sw-w) - var(--_sw-h));
|
|
966
|
+
--_sw-knob-inset-right: calc(var(--_sw-w) - var(--_sw-h) + var(--_sw-p));
|
|
966
967
|
position: relative;
|
|
967
968
|
box-sizing: border-box;
|
|
968
969
|
width: var(--_sw-w);
|
|
@@ -980,7 +981,7 @@ fontdue-feature-testers {
|
|
|
980
981
|
top: var(--_sw-p);
|
|
981
982
|
left: var(--_sw-p);
|
|
982
983
|
bottom: var(--_sw-p);
|
|
983
|
-
|
|
984
|
+
right: var(--_sw-knob-inset-right);
|
|
984
985
|
border: var(--_sw-b) solid var(--_sw-color);
|
|
985
986
|
border-radius: var(--_sw-r);
|
|
986
987
|
background: transparent;
|
|
@@ -8,7 +8,7 @@ import { NODE_ACCESS_HEADER } from '../nodeAccess.js';
|
|
|
8
8
|
// (defineVersionPlugin in .babelrc.cjs) with the literal package.json#version.
|
|
9
9
|
// Exported so UI (the admin toolbar) can surface it without re-reading the
|
|
10
10
|
// build-time global in a 'use client' module.
|
|
11
|
-
export const version = "3.4.
|
|
11
|
+
export const version = "3.4.1";
|
|
12
12
|
const IS_SERVER = typeof window === typeof undefined;
|
|
13
13
|
|
|
14
14
|
// Opt server fetches into Next's data cache only in production; dev stays
|