fontdue-js 3.12.1 → 3.14.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 +10 -0
- package/dist/__generated__/StoreModalFamily_collection.graphql.d.ts +2 -1
- package/dist/__generated__/StoreModalFamily_collection.graphql.js +14 -4
- package/dist/__generated__/StoreModalProductQuery.graphql.d.ts +1 -1
- package/dist/__generated__/StoreModalProductQuery.graphql.js +11 -7
- package/dist/__generated__/StoreModalProductRefetchQuery.graphql.d.ts +1 -1
- package/dist/__generated__/StoreModalProductRefetchQuery.graphql.js +11 -7
- package/dist/__generated__/StoreModalProductSlugQuery.graphql.d.ts +1 -1
- package/dist/__generated__/StoreModalProductSlugQuery.graphql.js +11 -7
- package/dist/__generated__/productState_Query.graphql.d.ts +1 -29
- package/dist/__generated__/productState_Query.graphql.js +15 -30
- package/dist/__generated__/productState_collection.graphql.d.ts +1 -1
- package/dist/__generated__/productState_collection.graphql.js +8 -4
- package/dist/__generated__/productState_fontPack.graphql.d.ts +1 -1
- package/dist/__generated__/productState_fontPack.graphql.js +7 -3
- package/dist/__generated__/productState_node.graphql.d.ts +1 -29
- package/dist/__generated__/productState_node.graphql.js +8 -22
- package/dist/__tests__/bundleSelectionOrder.test.js +0 -1
- package/dist/__tests__/collectionBundleSelection.test.js +31 -6
- package/dist/__tests__/storeModalBundlePairs.test.js +142 -0
- package/dist/components/Root/productState.js +7 -33
- package/dist/components/StoreModal/StoreModalFamily.d.ts +3 -0
- package/dist/components/StoreModal/StoreModalFamily.js +20 -6
- package/dist/components/elements/StoreModalFamily/index.d.ts +1 -1
- package/dist/components/elements/StoreModalFamily/index.js +6 -3
- package/dist/fontdue.css +35 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/__generated__/productState_collectionBundle.graphql.d.ts +0 -41
- package/dist/__generated__/productState_collectionBundle.graphql.js +0 -81
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @generated SignedSource<<
|
|
2
|
+
* @generated SignedSource<<7112b01c24002ecc9175f687500a7e12>>
|
|
3
3
|
* @lightSyntaxTransform
|
|
4
4
|
* @nogrep
|
|
5
5
|
*/
|
|
@@ -60,13 +60,17 @@ const node = function () {
|
|
|
60
60
|
},
|
|
61
61
|
v4 = {
|
|
62
62
|
"alias": null,
|
|
63
|
-
"args":
|
|
63
|
+
"args": [{
|
|
64
|
+
"kind": "Literal",
|
|
65
|
+
"name": "acrossFamilies",
|
|
66
|
+
"value": true
|
|
67
|
+
}],
|
|
64
68
|
"concreteType": "Bundle",
|
|
65
69
|
"kind": "LinkedField",
|
|
66
70
|
"name": "bundles",
|
|
67
71
|
"plural": true,
|
|
68
72
|
"selections": [v0 /*: any*/, v1 /*: any*/, v2 /*: any*/, v3 /*: any*/],
|
|
69
|
-
"storageKey":
|
|
73
|
+
"storageKey": "bundles(acrossFamilies:true)"
|
|
70
74
|
};
|
|
71
75
|
return {
|
|
72
76
|
"argumentDefinitions": [],
|
|
@@ -76,24 +80,6 @@ const node = function () {
|
|
|
76
80
|
},
|
|
77
81
|
"name": "productState_node",
|
|
78
82
|
"selections": [v0 /*: any*/, v1 /*: any*/, v2 /*: any*/, v3 /*: any*/, v4 /*: any*/, {
|
|
79
|
-
"alias": null,
|
|
80
|
-
"args": null,
|
|
81
|
-
"concreteType": "CollectionBundle",
|
|
82
|
-
"kind": "LinkedField",
|
|
83
|
-
"name": "collectionBundles",
|
|
84
|
-
"plural": true,
|
|
85
|
-
"selections": [v0 /*: any*/, v1 /*: any*/, v2 /*: any*/, {
|
|
86
|
-
"alias": null,
|
|
87
|
-
"args": null,
|
|
88
|
-
"concreteType": "FontCollection",
|
|
89
|
-
"kind": "LinkedField",
|
|
90
|
-
"name": "memberCollections",
|
|
91
|
-
"plural": true,
|
|
92
|
-
"selections": [v0 /*: any*/, v2 /*: any*/, v3 /*: any*/],
|
|
93
|
-
"storageKey": null
|
|
94
|
-
}],
|
|
95
|
-
"storageKey": null
|
|
96
|
-
}, {
|
|
97
83
|
"alias": null,
|
|
98
84
|
"args": [{
|
|
99
85
|
"kind": "Literal",
|
|
@@ -111,5 +97,5 @@ const node = function () {
|
|
|
111
97
|
"abstractKey": null
|
|
112
98
|
};
|
|
113
99
|
}();
|
|
114
|
-
node.hash = "
|
|
100
|
+
node.hash = "aab1ef07e0192a0d22a4c300084d9d05";
|
|
115
101
|
export default node;
|
|
@@ -506,6 +506,16 @@ describe('POPULATE_PRODUCT_STATE', () => {
|
|
|
506
506
|
fontStyles: [style('vf1', null)],
|
|
507
507
|
bundles: []
|
|
508
508
|
};
|
|
509
|
+
const display = {
|
|
510
|
+
id: 'display',
|
|
511
|
+
name: 'Display',
|
|
512
|
+
sku: sku('display-sku', 500),
|
|
513
|
+
fontStyles: [style('d1', 'sd1')],
|
|
514
|
+
bundles: []
|
|
515
|
+
};
|
|
516
|
+
// The superfamily's own bundles, read with `bundles(acrossFamilies: true)`:
|
|
517
|
+
// whole families (what collection bundles were), and styles from two
|
|
518
|
+
// families. The server expands a family member into its styles.
|
|
509
519
|
const superfamily = {
|
|
510
520
|
node: {
|
|
511
521
|
__typename: 'FontCollection',
|
|
@@ -513,14 +523,18 @@ describe('POPULATE_PRODUCT_STATE', () => {
|
|
|
513
523
|
name: 'Thunder',
|
|
514
524
|
sku: sku('super-sku', 750),
|
|
515
525
|
fontStyles: [],
|
|
516
|
-
bundles: [
|
|
517
|
-
collectionBundles: [{
|
|
526
|
+
bundles: [{
|
|
518
527
|
id: 'text-bundle',
|
|
519
528
|
name: 'Text + Variable',
|
|
520
529
|
sku: sku('text-bundle-sku', 500),
|
|
521
|
-
|
|
530
|
+
fontStyles: [...textFamily.fontStyles, ...textVariable.fontStyles]
|
|
531
|
+
}, {
|
|
532
|
+
id: 'regulars',
|
|
533
|
+
name: 'Regulars',
|
|
534
|
+
sku: sku('regulars-sku', 60),
|
|
535
|
+
fontStyles: [style('f1', 's1'), style('d1', 'sd1')]
|
|
522
536
|
}],
|
|
523
|
-
children: [textFamily, textVariable]
|
|
537
|
+
children: [textFamily, textVariable, display]
|
|
524
538
|
}
|
|
525
539
|
};
|
|
526
540
|
it('records the styles every SKU grants', () => {
|
|
@@ -529,14 +543,25 @@ describe('POPULATE_PRODUCT_STATE', () => {
|
|
|
529
543
|
data: superfamily
|
|
530
544
|
});
|
|
531
545
|
expect(state.skuStyleIds).toEqual({
|
|
532
|
-
'super-sku': ['f1', 'f2', 'vf1'],
|
|
546
|
+
'super-sku': ['f1', 'f2', 'vf1', 'd1'],
|
|
533
547
|
'text-bundle-sku': ['f1', 'f2', 'vf1'],
|
|
548
|
+
'regulars-sku': ['f1', 'd1'],
|
|
534
549
|
'text-sku': ['f1', 'f2'],
|
|
535
550
|
'text-var-sku': ['vf1'],
|
|
551
|
+
'display-sku': ['d1'],
|
|
536
552
|
'upright-sku': ['f1'],
|
|
537
553
|
s1: ['f1'],
|
|
538
|
-
s2: ['f2']
|
|
554
|
+
s2: ['f2'],
|
|
555
|
+
sd1: ['d1']
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
it('rolls styles from two families up to a superfamily bundle', () => {
|
|
559
|
+
const loaded = reducer(makeState(), {
|
|
560
|
+
type: 'POPULATE_PRODUCT_STATE',
|
|
561
|
+
data: superfamily
|
|
539
562
|
});
|
|
563
|
+
const state = select(select(loaded, 's1'), 'sd1');
|
|
564
|
+
expect(selected(state)).toEqual(['regulars-sku']);
|
|
540
565
|
});
|
|
541
566
|
it('prices a SKU picked before its product loaded once it has', () => {
|
|
542
567
|
const picked = select(makeState(), 'text-sku');
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
|
|
3
|
+
// Bundles sit side by side when their names make a pair ("Thin" directly
|
|
4
|
+
// followed by "Thin Italic"), the way a style sits beside its italic.
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
8
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
9
|
+
const {
|
|
10
|
+
stateRef
|
|
11
|
+
} = vi.hoisted(() => ({
|
|
12
|
+
stateRef: {
|
|
13
|
+
current: null
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
// The fragment reader hands back the data it was given; the redux selector
|
|
18
|
+
// runs against a default store's state.
|
|
19
|
+
vi.mock('react-relay', () => ({
|
|
20
|
+
graphql: () => null,
|
|
21
|
+
fetchQuery: vi.fn(),
|
|
22
|
+
useFragment: (_fragment, key) => key
|
|
23
|
+
}));
|
|
24
|
+
vi.mock('react-redux', async importOriginal => ({
|
|
25
|
+
...(await importOriginal()),
|
|
26
|
+
useSelector: selector => selector(stateRef.current)
|
|
27
|
+
}));
|
|
28
|
+
import StoreModalFamily, { bundlesGrouped } from '../components/StoreModal/StoreModalFamily.js';
|
|
29
|
+
import { createDefaultStore } from '../reducer.js';
|
|
30
|
+
const grouped = function () {
|
|
31
|
+
for (var _len = arguments.length, names = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
32
|
+
names[_key] = arguments[_key];
|
|
33
|
+
}
|
|
34
|
+
return bundlesGrouped(names.map(name => ({
|
|
35
|
+
name
|
|
36
|
+
}))).map(group => group.map(_ref => {
|
|
37
|
+
let {
|
|
38
|
+
name
|
|
39
|
+
} = _ref;
|
|
40
|
+
return name;
|
|
41
|
+
}));
|
|
42
|
+
};
|
|
43
|
+
describe('bundlesGrouped', () => {
|
|
44
|
+
it('pairs a bundle with a direct successor that repeats its name plus a suffix', () => {
|
|
45
|
+
expect(grouped('Thin', 'Thin Italic', 'Light', 'Light Oblique')).toEqual([['Thin', 'Thin Italic'], ['Light', 'Light Oblique']]);
|
|
46
|
+
});
|
|
47
|
+
it('accepts any suffix, not only italics', () => {
|
|
48
|
+
expect(grouped('Text', 'Text Alternates')).toEqual([['Text', 'Text Alternates']]);
|
|
49
|
+
});
|
|
50
|
+
it('only looks at the direct successor', () => {
|
|
51
|
+
expect(grouped('Thin', 'Light', 'Thin Italic')).toEqual([['Thin'], ['Light'], ['Thin Italic']]);
|
|
52
|
+
});
|
|
53
|
+
it('keeps exactly two: a third bundle with the same name splits them all', () => {
|
|
54
|
+
expect(grouped('Text', 'Text Italic', 'Text Oblique')).toEqual([['Text'], ['Text Italic'], ['Text Oblique']]);
|
|
55
|
+
});
|
|
56
|
+
it('wants a whole word, so a longer word is not a suffix', () => {
|
|
57
|
+
expect(grouped('Thin', 'Thinner')).toEqual([['Thin'], ['Thinner']]);
|
|
58
|
+
});
|
|
59
|
+
it('does not pair by order alone: the italic has to come second', () => {
|
|
60
|
+
expect(grouped('Thin Italic', 'Thin')).toEqual([['Thin Italic'], ['Thin']]);
|
|
61
|
+
});
|
|
62
|
+
it('ignores stray spaces around a name', () => {
|
|
63
|
+
expect(grouped('Semibold ', 'Semibold Italic')).toEqual([['Semibold ', 'Semibold Italic']]);
|
|
64
|
+
});
|
|
65
|
+
it('never pairs on an empty name', () => {
|
|
66
|
+
expect(grouped('', 'Thin')).toEqual([[''], ['Thin']]);
|
|
67
|
+
});
|
|
68
|
+
it('handles a missing list', () => {
|
|
69
|
+
expect(bundlesGrouped(null)).toEqual([]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
const money = amount => ({
|
|
73
|
+
amount,
|
|
74
|
+
currency: 'EUR'
|
|
75
|
+
});
|
|
76
|
+
const style = name => ({
|
|
77
|
+
id: `style:${name}`,
|
|
78
|
+
name,
|
|
79
|
+
supportedLanguages: ['en'],
|
|
80
|
+
variableInstances: [],
|
|
81
|
+
sku: {
|
|
82
|
+
id: `sku:style:${name}`,
|
|
83
|
+
price: money(4000)
|
|
84
|
+
},
|
|
85
|
+
cssFamily: 'Matex',
|
|
86
|
+
cssWeight: '400',
|
|
87
|
+
cssStretch: 'normal',
|
|
88
|
+
cssStyle: 'normal'
|
|
89
|
+
});
|
|
90
|
+
const bundle = function (name) {
|
|
91
|
+
let visibility = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'VISIBLE';
|
|
92
|
+
return {
|
|
93
|
+
id: `bundle:${name}`,
|
|
94
|
+
name,
|
|
95
|
+
visibility,
|
|
96
|
+
sku: {
|
|
97
|
+
id: `sku:bundle:${name}`,
|
|
98
|
+
price: money(26000)
|
|
99
|
+
},
|
|
100
|
+
fontStyles: [style(name)]
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
const collection = bundles => ({
|
|
104
|
+
__typename: 'FontCollection',
|
|
105
|
+
id: 'collection:matex',
|
|
106
|
+
name: 'HAL Matex',
|
|
107
|
+
collectionType: 'superfamily',
|
|
108
|
+
isVariableFont: false,
|
|
109
|
+
sku: {
|
|
110
|
+
id: 'sku:matex',
|
|
111
|
+
price: money(138667)
|
|
112
|
+
},
|
|
113
|
+
totalStyles: 60,
|
|
114
|
+
totalStylesPrice: money(138667),
|
|
115
|
+
featureStyle: null,
|
|
116
|
+
fontStyles: [],
|
|
117
|
+
bundles
|
|
118
|
+
});
|
|
119
|
+
describe('StoreModalFamily bundle rows', () => {
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
stateRef.current = createDefaultStore(undefined).getState();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Bundle names, row by row.
|
|
125
|
+
const rows = bundles => {
|
|
126
|
+
const container = document.createElement('div');
|
|
127
|
+
container.innerHTML = renderToStaticMarkup( /*#__PURE__*/React.createElement(StoreModalFamily, {
|
|
128
|
+
collection: collection(bundles),
|
|
129
|
+
onSelect: () => {}
|
|
130
|
+
}));
|
|
131
|
+
return Array.from(container.querySelectorAll('.store-modal__family__group')).map(group => Array.from(group.querySelectorAll('.store-modal__family__bundle-button')).map(button => {
|
|
132
|
+
var _button$querySelector;
|
|
133
|
+
return (_button$querySelector = button.querySelector('.store-modal__style-button__style-name')) === null || _button$querySelector === void 0 ? void 0 : _button$querySelector.textContent;
|
|
134
|
+
}));
|
|
135
|
+
};
|
|
136
|
+
it('puts a pair on one row and leaves every other bundle on its own', () => {
|
|
137
|
+
expect(rows([bundle('Thin'), bundle('Thin Italic'), bundle('Complete')])).toEqual([['Thin', 'Thin Italic'], ['Complete']]);
|
|
138
|
+
});
|
|
139
|
+
it('pairs what is listed: an unlisted bundle between two names has no button', () => {
|
|
140
|
+
expect(rows([bundle('Thin'), bundle('Secret', 'UNLISTED'), bundle('Thin Italic')])).toEqual([['Thin', 'Thin Italic']]);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import _productState_Query from "../../__generated__/productState_Query.graphql.js";
|
|
2
2
|
import _productState_fontPack from "../../__generated__/productState_fontPack.graphql.js";
|
|
3
3
|
import _productState_node from "../../__generated__/productState_node.graphql.js";
|
|
4
|
-
import _productState_collectionBundle from "../../__generated__/productState_collectionBundle.graphql.js";
|
|
5
4
|
import _productState_bundle from "../../__generated__/productState_bundle.graphql.js";
|
|
6
5
|
import _productState_collection from "../../__generated__/productState_collection.graphql.js";
|
|
7
6
|
import _productState_sku from "../../__generated__/productState_sku.graphql.js";
|
|
8
7
|
import { fetchQuery, graphql } from 'react-relay';
|
|
9
8
|
import { notEmpty } from '../../utils.js';
|
|
10
9
|
_productState_sku.hash && _productState_sku.hash !== "2cee6ddddc85699f0c90e2607c0634ef" && console.error("The definition of 'productState_sku' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _productState_sku;
|
|
11
|
-
_productState_collection.hash && _productState_collection.hash !== "
|
|
10
|
+
_productState_collection.hash && _productState_collection.hash !== "5ad23bbf68581f27e769ebb0cda70f8e" && console.error("The definition of 'productState_collection' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _productState_collection;
|
|
12
11
|
_productState_bundle.hash && _productState_bundle.hash !== "fa38bbc9f2062a727da4f5062b362054" && console.error("The definition of 'productState_bundle' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _productState_bundle;
|
|
13
|
-
|
|
14
|
-
_productState_node.hash && _productState_node.hash !== "a1e172db45ca550a254819d877497d12" && console.error("The definition of 'productState_node' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _productState_node;
|
|
12
|
+
_productState_node.hash && _productState_node.hash !== "aab1ef07e0192a0d22a4c300084d9d05" && console.error("The definition of 'productState_node' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _productState_node;
|
|
15
13
|
|
|
16
14
|
// A pack is one SKU that grants every style in `fontStyles`. Its collection
|
|
17
15
|
// members (a family or a superfamily with its families) are fetched in the
|
|
@@ -41,37 +39,21 @@ const allSkus = function (collection) {
|
|
|
41
39
|
var _collection$bundles;
|
|
42
40
|
bundleSkus = (collection === null || collection === void 0 ? void 0 : (_collection$bundles = collection.bundles) === null || _collection$bundles === void 0 ? void 0 : _collection$bundles.flatMap(bundle => allSkus(bundle, includeCollections, includeFontStyles))) ?? [];
|
|
43
41
|
}
|
|
44
|
-
let collectionBundleSkus = [];
|
|
45
|
-
if ('collectionBundles' in collection && collection.collectionBundles) {
|
|
46
|
-
collectionBundleSkus = collection.collectionBundles.flatMap(collBundle => allSkus(collBundle, includeCollections, includeFontStyles));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// For collection bundles, get SKUs from member collections
|
|
50
|
-
let memberCollectionSkus = [];
|
|
51
|
-
if ('memberCollections' in collection && collection.memberCollections) {
|
|
52
|
-
memberCollectionSkus = collection.memberCollections.flatMap(member => {
|
|
53
|
-
var _member$fontStyles;
|
|
54
|
-
return [includeCollections ? member.sku : null, ...(includeFontStyles ? ((_member$fontStyles = member.fontStyles) === null || _member$fontStyles === void 0 ? void 0 : _member$fontStyles.map(style => style.sku)) ?? [] : [])];
|
|
55
|
-
}).filter(notEmpty);
|
|
56
|
-
}
|
|
57
42
|
let childrenSkus = [];
|
|
58
43
|
if ('children' in collection) {
|
|
59
44
|
var _collection$children;
|
|
60
45
|
childrenSkus = ((_collection$children = collection.children) === null || _collection$children === void 0 ? void 0 : _collection$children.flatMap(child => allSkus(child, includeCollections, includeFontStyles))) ?? [];
|
|
61
46
|
}
|
|
62
|
-
return [includeCollections ? collection === null || collection === void 0 ? void 0 : collection.sku : null, ...(includeFontStyles && 'fontStyles' in collection ? (collection === null || collection === void 0 ? void 0 : (_collection$fontStyle = collection.fontStyles) === null || _collection$fontStyle === void 0 ? void 0 : _collection$fontStyle.map(style => style.sku)) ?? [] : []), ...bundleSkus, ...
|
|
47
|
+
return [includeCollections ? collection === null || collection === void 0 ? void 0 : collection.sku : null, ...(includeFontStyles && 'fontStyles' in collection ? (collection === null || collection === void 0 ? void 0 : (_collection$fontStyle = collection.fontStyles) === null || _collection$fontStyle === void 0 ? void 0 : _collection$fontStyle.map(style => style.sku)) ?? [] : []), ...bundleSkus, ...childrenSkus].filter(notEmpty);
|
|
63
48
|
};
|
|
64
49
|
|
|
65
50
|
// The styles each SKU grants, by SKU id: a style's SKU grants that style, a
|
|
66
|
-
// bundle its styles
|
|
67
|
-
// and a
|
|
51
|
+
// bundle its styles (a whole-family member expanded to the family's styles), a
|
|
52
|
+
// family its styles and a superfamily its families' styles. This is all the
|
|
68
53
|
// selection needs to price any combination of them (see selection.ts).
|
|
69
54
|
|
|
70
55
|
const styleIdsOf = collection => {
|
|
71
56
|
var _collection$fontStyle2, _collection$children2;
|
|
72
|
-
if ('memberCollections' in collection && collection.memberCollections) {
|
|
73
|
-
return collection.memberCollections.flatMap(member => member.fontStyles.map(s => s.id));
|
|
74
|
-
}
|
|
75
57
|
const own = 'fontStyles' in collection ? ((_collection$fontStyle2 = collection.fontStyles) === null || _collection$fontStyle2 === void 0 ? void 0 : _collection$fontStyle2.map(s => s.id)) ?? [] : [];
|
|
76
58
|
const children = 'children' in collection ? ((_collection$children2 = collection.children) === null || _collection$children2 === void 0 ? void 0 : _collection$children2.flatMap(child => {
|
|
77
59
|
var _child$fontStyles;
|
|
@@ -83,8 +65,7 @@ const flattenSkuStyleIds = collection => {
|
|
|
83
65
|
var _collection$sku;
|
|
84
66
|
const result = {};
|
|
85
67
|
const add = (skuId, styleIds) => {
|
|
86
|
-
// A
|
|
87
|
-
// a collection bundle member) says nothing about what it grants.
|
|
68
|
+
// A SKU that lists no styles says nothing about what it grants.
|
|
88
69
|
if (skuId && styleIds.length > 0) result[skuId] = styleIds;
|
|
89
70
|
};
|
|
90
71
|
const addStyles = fontStyles => {
|
|
@@ -95,14 +76,7 @@ const flattenSkuStyleIds = collection => {
|
|
|
95
76
|
};
|
|
96
77
|
add((_collection$sku = collection.sku) === null || _collection$sku === void 0 ? void 0 : _collection$sku.id, styleIdsOf(collection));
|
|
97
78
|
if ('fontStyles' in collection) addStyles(collection.fontStyles);
|
|
98
|
-
|
|
99
|
-
for (const member of collection.memberCollections ?? []) {
|
|
100
|
-
var _member$sku;
|
|
101
|
-
add((_member$sku = member.sku) === null || _member$sku === void 0 ? void 0 : _member$sku.id, member.fontStyles.map(s => s.id));
|
|
102
|
-
addStyles(member.fontStyles);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
const nested = [...('bundles' in collection ? collection.bundles ?? [] : []), ...('collectionBundles' in collection ? collection.collectionBundles ?? [] : []), ...('children' in collection ? collection.children ?? [] : [])];
|
|
79
|
+
const nested = [...('bundles' in collection ? collection.bundles ?? [] : []), ...('children' in collection ? collection.children ?? [] : [])];
|
|
106
80
|
for (const child of nested) Object.assign(result, flattenSkuStyleIds(child));
|
|
107
81
|
return result;
|
|
108
82
|
};
|
|
@@ -12,5 +12,8 @@ interface GroupableStyle {
|
|
|
12
12
|
cssStyle: string | null;
|
|
13
13
|
}
|
|
14
14
|
export declare function stylesGrouped<T extends GroupableStyle>(fontStyles: ReadonlyArray<T> | null | undefined): ReadonlyArray<ReadonlyArray<T>>;
|
|
15
|
+
export declare function bundlesGrouped<T extends {
|
|
16
|
+
name: string;
|
|
17
|
+
}>(bundles: ReadonlyArray<T> | null | undefined): ReadonlyArray<ReadonlyArray<T>>;
|
|
15
18
|
export default function StoreModalFamily({ collection: collectionKey, onSelect, title, }: StoreModalFamilyProps): React.JSX.Element | null;
|
|
16
19
|
export {};
|
|
@@ -33,6 +33,16 @@ export function stylesGrouped(fontStyles) {
|
|
|
33
33
|
return slantedCount === 1 ? [chunk] : chunk.map(style => [style]);
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
// Pairs a bundle with its direct successor when that one's name repeats it plus
|
|
38
|
+
// a suffix ("Thin" then "Thin Italic"), so the two render side by side like a
|
|
39
|
+
// style beside its italic. Names are all there is to go on: a bundle's styles
|
|
40
|
+
// can come from several families. As with styles, only exactly two stay paired.
|
|
41
|
+
export function bundlesGrouped(bundles) {
|
|
42
|
+
if (!bundles) return [];
|
|
43
|
+
const chunks = chunkConsecutiveBy(bundles, (left, right) => right.name.trim().startsWith(`${left.name.trim()} `));
|
|
44
|
+
return chunks.flatMap(chunk => chunk.length === 2 ? [chunk] : chunk.map(b => [b]));
|
|
45
|
+
}
|
|
36
46
|
export default function StoreModalFamily(_ref) {
|
|
37
47
|
var _collection$bundles;
|
|
38
48
|
let {
|
|
@@ -40,22 +50,26 @@ export default function StoreModalFamily(_ref) {
|
|
|
40
50
|
onSelect,
|
|
41
51
|
title
|
|
42
52
|
} = _ref;
|
|
43
|
-
const collection = useFragment((_StoreModalFamily_collection.hash && _StoreModalFamily_collection.hash !== "
|
|
53
|
+
const collection = useFragment((_StoreModalFamily_collection.hash && _StoreModalFamily_collection.hash !== "ed59465ca68bf3d3278773a671ddefb3" && console.error("The definition of 'StoreModalFamily_collection' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _StoreModalFamily_collection), collectionKey);
|
|
44
54
|
const fontStyles = useMemo(() => stylesGrouped(collection.fontStyles), [collection]);
|
|
45
|
-
|
|
55
|
+
// An unlisted bundle gets no button, but its price still applies as an
|
|
56
|
+
// upgrade: the product state reads every bundle.
|
|
57
|
+
const listedBundles = (_collection$bundles = collection.bundles) === null || _collection$bundles === void 0 ? void 0 : _collection$bundles.filter(bundle => bundle.visibility !== 'UNLISTED');
|
|
58
|
+
|
|
59
|
+
// A superfamily sold only through its families has nothing of its own to
|
|
60
|
+
// show – unless one of its bundles, across its families, has a button.
|
|
61
|
+
if ((fontStyles === null || fontStyles === void 0 ? void 0 : fontStyles.length) === 0 && collection.collectionType === 'superfamily' && !collection.sku && !(listedBundles !== null && listedBundles !== void 0 && listedBundles.length)) return null;
|
|
46
62
|
return /*#__PURE__*/React.createElement(FamilyElement, null, {
|
|
47
63
|
title,
|
|
48
64
|
familyButton: /*#__PURE__*/React.createElement(FamilyButton, {
|
|
49
65
|
collection: collection,
|
|
50
66
|
onSelectSku: onSelect
|
|
51
67
|
}),
|
|
52
|
-
|
|
53
|
-
// upgrade: the product state reads every bundle.
|
|
54
|
-
bundles: collection === null || collection === void 0 ? void 0 : (_collection$bundles = collection.bundles) === null || _collection$bundles === void 0 ? void 0 : _collection$bundles.filter(bundle => bundle.visibility !== 'UNLISTED').map(bundle => /*#__PURE__*/React.createElement(StoreModalBundleButton, {
|
|
68
|
+
bundleGroups: bundlesGrouped(listedBundles).map(group => group.map(bundle => /*#__PURE__*/React.createElement(StoreModalBundleButton, {
|
|
55
69
|
key: bundle.id,
|
|
56
70
|
bundle: bundle,
|
|
57
71
|
onSelectSku: onSelect
|
|
58
|
-
})),
|
|
72
|
+
}))),
|
|
59
73
|
styleGroups: fontStyles.map(group => group.map(fontStyle => /*#__PURE__*/React.createElement(StyleButton, {
|
|
60
74
|
key: fontStyle.id,
|
|
61
75
|
fontStyle: fontStyle,
|
|
@@ -3,7 +3,7 @@ interface StoreModalFamilyProps {
|
|
|
3
3
|
children: {
|
|
4
4
|
title: React.ReactNode;
|
|
5
5
|
familyButton?: React.ReactElement<any> | null;
|
|
6
|
-
|
|
6
|
+
bundleGroups?: React.ReactElement<any>[][] | null;
|
|
7
7
|
styleGroups?: React.ReactElement<any>[][] | null;
|
|
8
8
|
};
|
|
9
9
|
}
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
const StoreModalFamily = _ref => {
|
|
3
3
|
let {
|
|
4
4
|
children: {
|
|
5
|
-
|
|
5
|
+
bundleGroups,
|
|
6
6
|
familyButton,
|
|
7
7
|
styleGroups,
|
|
8
8
|
title
|
|
@@ -14,9 +14,12 @@ const StoreModalFamily = _ref => {
|
|
|
14
14
|
className: "store-modal__family__title"
|
|
15
15
|
}, title), familyButton && /*#__PURE__*/React.cloneElement(familyButton, {
|
|
16
16
|
className: 'store-modal__family__family-button'
|
|
17
|
-
}),
|
|
17
|
+
}), bundleGroups === null || bundleGroups === void 0 ? void 0 : bundleGroups.map((group, i) => /*#__PURE__*/React.createElement("div", {
|
|
18
|
+
className: "store-modal__family__group",
|
|
19
|
+
key: i
|
|
20
|
+
}, group.map(bundleButton => /*#__PURE__*/React.cloneElement(bundleButton, {
|
|
18
21
|
className: 'store-modal__family__bundle-button'
|
|
19
|
-
})), styleGroups === null || styleGroups === void 0 ? void 0 : styleGroups.map((group, i) => /*#__PURE__*/React.createElement("div", {
|
|
22
|
+
})))), styleGroups === null || styleGroups === void 0 ? void 0 : styleGroups.map((group, i) => /*#__PURE__*/React.createElement("div", {
|
|
20
23
|
className: "store-modal__family__group",
|
|
21
24
|
key: i
|
|
22
25
|
}, group.map(styleButton => /*#__PURE__*/React.cloneElement(styleButton, {
|
package/dist/fontdue.css
CHANGED
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
display: block;
|
|
128
128
|
width: 1em;
|
|
129
129
|
height: 1em;
|
|
130
|
+
max-width: none;
|
|
130
131
|
fill: currentColor;
|
|
131
132
|
}
|
|
132
133
|
|
|
@@ -1784,6 +1785,7 @@ input:checked + .checkbox__icon {
|
|
|
1784
1785
|
|
|
1785
1786
|
.store-modal__container__buttons {
|
|
1786
1787
|
text-align: right;
|
|
1788
|
+
white-space: nowrap;
|
|
1787
1789
|
}
|
|
1788
1790
|
|
|
1789
1791
|
.store-modal__container__back-button {
|
|
@@ -2136,6 +2138,14 @@ input:checked + .checkbox__icon {
|
|
|
2136
2138
|
font-size: 60px;
|
|
2137
2139
|
}
|
|
2138
2140
|
|
|
2141
|
+
.store-modal__index-item__description:first-child {
|
|
2142
|
+
grid-column: 1/-2;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
.store-modal__index-item__buy {
|
|
2146
|
+
grid-column: -2/-1;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2139
2149
|
.store-modal__index-item__name {
|
|
2140
2150
|
font-size: 20px;
|
|
2141
2151
|
line-height: 30px;
|
|
@@ -2693,6 +2703,31 @@ input:checked + .checkbox__icon {
|
|
|
2693
2703
|
.store-modal__family__bundle-button .store-modal__style-button__price {
|
|
2694
2704
|
align-self: flex-end;
|
|
2695
2705
|
}
|
|
2706
|
+
.store-modal__family__bundle-button .store-modal__style-button__checked {
|
|
2707
|
+
height: 1lh;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
.store-modal__family__bundle-button {
|
|
2711
|
+
container-type: inline-size;
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
@container (max-width: 480px) {
|
|
2715
|
+
.store-modal__family__bundle-button .store-modal__style-button__container {
|
|
2716
|
+
flex-wrap: wrap;
|
|
2717
|
+
}
|
|
2718
|
+
.store-modal__family__bundle-button .store-modal__style-button__feature-glyphs {
|
|
2719
|
+
flex: 0 0 100%;
|
|
2720
|
+
}
|
|
2721
|
+
.store-modal__family__bundle-button .store-modal__style-button__style-name {
|
|
2722
|
+
flex: 1 1 0;
|
|
2723
|
+
min-width: 0;
|
|
2724
|
+
}
|
|
2725
|
+
.store-modal__family__bundle-button .store-modal__style-button__price {
|
|
2726
|
+
align-self: flex-end;
|
|
2727
|
+
}
|
|
2728
|
+
.store-modal__family__bundle-button .store-modal__style-button__checked {
|
|
2729
|
+
height: 1lh;
|
|
2730
|
+
}
|
|
2696
2731
|
}
|
|
2697
2732
|
body[data-fontdue-store-modal=open] {
|
|
2698
2733
|
overflow: hidden;
|
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.14.0";
|
package/package.json
CHANGED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @generated SignedSource<<c1a8446af3677d58e3851338c54cf16e>>
|
|
3
|
-
* @lightSyntaxTransform
|
|
4
|
-
* @nogrep
|
|
5
|
-
*/
|
|
6
|
-
import { ReaderFragment } from 'relay-runtime';
|
|
7
|
-
import { FragmentRefs } from "relay-runtime";
|
|
8
|
-
export type productState_collectionBundle$data = {
|
|
9
|
-
readonly id: string;
|
|
10
|
-
readonly memberCollections: ReadonlyArray<{
|
|
11
|
-
readonly fontStyles: ReadonlyArray<{
|
|
12
|
-
readonly id: string;
|
|
13
|
-
readonly sku: {
|
|
14
|
-
readonly id: string;
|
|
15
|
-
readonly price: {
|
|
16
|
-
readonly amount: number;
|
|
17
|
-
};
|
|
18
|
-
} | null;
|
|
19
|
-
}>;
|
|
20
|
-
readonly id: string;
|
|
21
|
-
readonly sku: {
|
|
22
|
-
readonly id: string;
|
|
23
|
-
readonly price: {
|
|
24
|
-
readonly amount: number;
|
|
25
|
-
};
|
|
26
|
-
} | null;
|
|
27
|
-
}> | null;
|
|
28
|
-
readonly name: string;
|
|
29
|
-
readonly sku: {
|
|
30
|
-
readonly id: string;
|
|
31
|
-
readonly price: {
|
|
32
|
-
readonly amount: number;
|
|
33
|
-
};
|
|
34
|
-
} | null;
|
|
35
|
-
};
|
|
36
|
-
export type productState_collectionBundle$key = {
|
|
37
|
-
readonly " $data"?: productState_collectionBundle$data;
|
|
38
|
-
readonly " $fragmentSpreads": FragmentRefs<"productState_collectionBundle">;
|
|
39
|
-
};
|
|
40
|
-
declare const node: ReaderFragment;
|
|
41
|
-
export default node;
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @generated SignedSource<<c1a8446af3677d58e3851338c54cf16e>>
|
|
3
|
-
* @lightSyntaxTransform
|
|
4
|
-
* @nogrep
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/* tslint:disable */
|
|
8
|
-
/* eslint-disable */
|
|
9
|
-
// @ts-nocheck
|
|
10
|
-
|
|
11
|
-
const node = function () {
|
|
12
|
-
var v0 = {
|
|
13
|
-
"alias": null,
|
|
14
|
-
"args": null,
|
|
15
|
-
"kind": "ScalarField",
|
|
16
|
-
"name": "id",
|
|
17
|
-
"storageKey": null
|
|
18
|
-
},
|
|
19
|
-
v1 = {
|
|
20
|
-
"alias": null,
|
|
21
|
-
"args": null,
|
|
22
|
-
"concreteType": "Sku",
|
|
23
|
-
"kind": "LinkedField",
|
|
24
|
-
"name": "sku",
|
|
25
|
-
"plural": false,
|
|
26
|
-
"selections": [v0 /*: any*/, {
|
|
27
|
-
"alias": null,
|
|
28
|
-
"args": null,
|
|
29
|
-
"concreteType": "Money",
|
|
30
|
-
"kind": "LinkedField",
|
|
31
|
-
"name": "price",
|
|
32
|
-
"plural": false,
|
|
33
|
-
"selections": [{
|
|
34
|
-
"alias": null,
|
|
35
|
-
"args": null,
|
|
36
|
-
"kind": "ScalarField",
|
|
37
|
-
"name": "amount",
|
|
38
|
-
"storageKey": null
|
|
39
|
-
}],
|
|
40
|
-
"storageKey": null
|
|
41
|
-
}],
|
|
42
|
-
"storageKey": null
|
|
43
|
-
};
|
|
44
|
-
return {
|
|
45
|
-
"argumentDefinitions": [],
|
|
46
|
-
"kind": "Fragment",
|
|
47
|
-
"metadata": {
|
|
48
|
-
"mask": false
|
|
49
|
-
},
|
|
50
|
-
"name": "productState_collectionBundle",
|
|
51
|
-
"selections": [v0 /*: any*/, {
|
|
52
|
-
"alias": null,
|
|
53
|
-
"args": null,
|
|
54
|
-
"kind": "ScalarField",
|
|
55
|
-
"name": "name",
|
|
56
|
-
"storageKey": null
|
|
57
|
-
}, v1 /*: any*/, {
|
|
58
|
-
"alias": null,
|
|
59
|
-
"args": null,
|
|
60
|
-
"concreteType": "FontCollection",
|
|
61
|
-
"kind": "LinkedField",
|
|
62
|
-
"name": "memberCollections",
|
|
63
|
-
"plural": true,
|
|
64
|
-
"selections": [v0 /*: any*/, v1 /*: any*/, {
|
|
65
|
-
"alias": null,
|
|
66
|
-
"args": null,
|
|
67
|
-
"concreteType": "FontStyle",
|
|
68
|
-
"kind": "LinkedField",
|
|
69
|
-
"name": "fontStyles",
|
|
70
|
-
"plural": true,
|
|
71
|
-
"selections": [v0 /*: any*/, v1 /*: any*/],
|
|
72
|
-
"storageKey": null
|
|
73
|
-
}],
|
|
74
|
-
"storageKey": null
|
|
75
|
-
}],
|
|
76
|
-
"type": "CollectionBundle",
|
|
77
|
-
"abstractKey": null
|
|
78
|
-
};
|
|
79
|
-
}();
|
|
80
|
-
node.hash = "6744aa8f57d14b0111a0c49f488d7b03";
|
|
81
|
-
export default node;
|