fontdue-js 2.24.0 → 2.25.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 CHANGED
@@ -1,3 +1,8 @@
1
+ ## 2.25.0
2
+
3
+ - Added `storeModal.hideAllCollections` config option (default `false`). When `true`, the store modal skips the "All collections" landing page — the modal opens directly to the cart route, the cart button always opens the cart regardless of item count, the empty-cart "Continue shopping" button closes the modal, and the product/checkout back button becomes "Close" when there's no history. Useful for stores that drive purchases from "Add to Cart" buttons on product pages.
4
+ - Improved the empty-cart layout: added a "Your cart is empty." message and the modal now collapses to its default 800px width when empty (instead of staying at the wider cart width).
5
+
1
6
  ## 2.24.0
2
7
 
3
8
  - The cart's licensee picker now reads its button labels and per-option descriptions from tenant settings, so admins can rename "Yourself" / "Your client" and add explainer text without a code change.
@@ -12,6 +12,7 @@ var _react = _interopRequireWildcard(require("react"));
12
12
  var _reactRedux = require("react-redux");
13
13
  var _reactRelay = require("react-relay");
14
14
  var _ComponentsContext = _interopRequireDefault(require("../ComponentsContext"));
15
+ var _ConfigContext = _interopRequireDefault(require("../ConfigContext"));
15
16
  var _Icons = require("../Icons");
16
17
  var _useSerializablePreloadedQuery = _interopRequireDefault(require("../../relay/useSerializablePreloadedQuery"));
17
18
  var _Price = _interopRequireWildcard(require("../Price"));
@@ -40,6 +41,9 @@ function CartButtonComponent(_ref) {
40
41
  const orderData = (0, _reactRelay.useFragment)((_CartButton_order2.default.hash && _CartButton_order2.default.hash !== "26a092d7efb579c98adda18413349b3b" && console.error("The definition of 'CartButton_order' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _CartButton_order2.default), orderKey);
41
42
  const [count, setCount] = (0, _react.useState)(0);
42
43
  const dispatch = (0, _reactRedux.useDispatch)();
44
+ const {
45
+ storeModal: storeModalConfig
46
+ } = (0, _react.useContext)(_ConfigContext.default);
43
47
  const formatSuffix = (0, _react.useCallback)(() => {
44
48
  if (!suffix) return null;
45
49
 
@@ -77,14 +81,14 @@ function CartButtonComponent(_ref) {
77
81
  return nodes.length > 0 ? nodes : null;
78
82
  }, [suffix, count, orderData === null || orderData === void 0 ? void 0 : orderData.subtotal]);
79
83
  const handleClick = (0, _react.useCallback)(() => {
80
- if (count > 0) {
84
+ if (count > 0 || storeModalConfig.hideAllCollections) {
81
85
  dispatch({
82
86
  type: 'STORE_MODAL_REPLACE',
83
87
  route: 'cart'
84
88
  });
85
89
  }
86
90
  dispatch(openCart());
87
- }, [count, dispatch]);
91
+ }, [count, dispatch, storeModalConfig.hideAllCollections]);
88
92
  (0, _react.useEffect)(() => {
89
93
  // set count only on the client, because on the server it's always gonna be zero
90
94
  setCount(cartButtonCount(orderData));
@@ -90,6 +90,7 @@ export declare const makeConfig: (config?: Config) => {
90
90
  indexLayout: "styled-aa" | "styled-font-names";
91
91
  indexExcludeTags: string[] | undefined;
92
92
  productLicensesPosition: "top" | "bottom";
93
+ hideAllCollections: boolean;
93
94
  };
94
95
  stripe: {
95
96
  appearance: Appearance | null;
@@ -161,6 +162,7 @@ declare const _default: React.Context<{
161
162
  indexLayout: "styled-aa" | "styled-font-names";
162
163
  indexExcludeTags: string[] | undefined;
163
164
  productLicensesPosition: "top" | "bottom";
165
+ hideAllCollections: boolean;
164
166
  };
165
167
  stripe: {
166
168
  appearance: Appearance | null;
@@ -59,7 +59,7 @@ const makeTypeTesterConfig = config => {
59
59
  };
60
60
  };
61
61
  const makeConfig = config => {
62
- var _config$form, _config$storeModal, _config$storeModal2, _config$storeModal3, _config$stripe, _config$tracking, _config$tracking2, _config$tracking3, _config$tracking4;
62
+ var _config$form, _config$storeModal, _config$storeModal2, _config$storeModal3, _config$storeModal4, _config$stripe, _config$tracking, _config$tracking2, _config$tracking3, _config$tracking4;
63
63
  return {
64
64
  typeTester: makeTypeTesterConfig(config === null || config === void 0 ? void 0 : config.typeTester),
65
65
  form: {
@@ -68,7 +68,8 @@ const makeConfig = config => {
68
68
  storeModal: {
69
69
  indexLayout: (config === null || config === void 0 ? void 0 : (_config$storeModal = config.storeModal) === null || _config$storeModal === void 0 ? void 0 : _config$storeModal.indexLayout) ?? 'styled-aa',
70
70
  indexExcludeTags: config === null || config === void 0 ? void 0 : (_config$storeModal2 = config.storeModal) === null || _config$storeModal2 === void 0 ? void 0 : _config$storeModal2.indexExcludeTags,
71
- productLicensesPosition: (config === null || config === void 0 ? void 0 : (_config$storeModal3 = config.storeModal) === null || _config$storeModal3 === void 0 ? void 0 : _config$storeModal3.productLicensesPosition) ?? 'top'
71
+ productLicensesPosition: (config === null || config === void 0 ? void 0 : (_config$storeModal3 = config.storeModal) === null || _config$storeModal3 === void 0 ? void 0 : _config$storeModal3.productLicensesPosition) ?? 'top',
72
+ hideAllCollections: (config === null || config === void 0 ? void 0 : (_config$storeModal4 = config.storeModal) === null || _config$storeModal4 === void 0 ? void 0 : _config$storeModal4.hideAllCollections) ?? false
72
73
  },
73
74
  stripe: {
74
75
  appearance: (config === null || config === void 0 ? void 0 : (_config$stripe = config.stripe) === null || _config$stripe === void 0 ? void 0 : _config$stripe.appearance) ?? null
@@ -31,8 +31,14 @@ const getPageTitle = name => {
31
31
  return 'Review';
32
32
  }
33
33
  };
34
- const getBackLink = (history, currentRoute) => {
35
- if (currentRoute !== 'index' && history.length === 0) return 'All collections';
34
+ const getBackLink = (history, currentRoute, hideAllCollections) => {
35
+ if (history.length === 0) {
36
+ if (hideAllCollections) {
37
+ return currentRoute === 'cart' ? null : 'Close';
38
+ }
39
+ if (currentRoute !== 'index') return 'All collections';
40
+ return null;
41
+ }
36
42
  const previous = history[history.length - 1];
37
43
  if (!previous) return null;
38
44
  return getPageTitle(previous.name);
@@ -61,17 +67,23 @@ const StoreModalContainer = _ref => {
61
67
  }, [dispatch]);
62
68
  const currentRoute = (0, _reactRedux.useSelector)(state => state.storeModalRoute.name);
63
69
  const history = (0, _reactRedux.useSelector)(state => state.storeModalHistory);
64
- const link = getBackLink(history, currentRoute);
65
70
  const config = (0, _react.useContext)(_ConfigContext.default);
71
+ const link = getBackLink(history, currentRoute, config.storeModal.hideAllCollections);
66
72
  const handleBack = () => {
67
73
  if (history.length === 0) {
68
- dispatch({
69
- type: 'STORE_MODAL_REPLACE',
70
- route: 'index',
71
- variables: {
72
- excludeTags: config.storeModal.indexExcludeTags
73
- }
74
- });
74
+ if (config.storeModal.hideAllCollections) {
75
+ dispatch({
76
+ type: 'CLOSE_CART'
77
+ });
78
+ } else {
79
+ dispatch({
80
+ type: 'STORE_MODAL_REPLACE',
81
+ route: 'index',
82
+ variables: {
83
+ excludeTags: config.storeModal.indexExcludeTags
84
+ }
85
+ });
86
+ }
75
87
  } else {
76
88
  dispatch({
77
89
  type: 'STORE_MODAL_BACK'
@@ -2,4 +2,5 @@ export interface StoreModalConfig {
2
2
  indexLayout?: 'styled-aa' | 'styled-font-names';
3
3
  indexExcludeTags?: string[] | undefined;
4
4
  productLicensesPosition?: 'bottom' | 'top';
5
+ hideAllCollections?: boolean;
5
6
  }
@@ -14,16 +14,30 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
14
14
  const EmptyCart = () => {
15
15
  const dispatch = (0, _reactRedux.useDispatch)();
16
16
  const config = (0, _react.useContext)(_ConfigContext.default);
17
+ const {
18
+ hideAllCollections
19
+ } = config.storeModal;
20
+ const handleContinueShopping = () => {
21
+ if (hideAllCollections) {
22
+ dispatch({
23
+ type: 'CLOSE_CART'
24
+ });
25
+ } else {
26
+ dispatch({
27
+ type: 'STORE_MODAL_NAVIGATE',
28
+ route: 'index',
29
+ variables: {
30
+ excludeTags: config.storeModal.indexExcludeTags
31
+ }
32
+ });
33
+ }
34
+ };
17
35
  return /*#__PURE__*/_react.default.createElement("div", {
18
36
  className: "empty-cart__container"
19
- }, /*#__PURE__*/_react.default.createElement(_Button.default, {
20
- onClick: () => dispatch({
21
- type: 'STORE_MODAL_NAVIGATE',
22
- route: 'index',
23
- variables: {
24
- excludeTags: config.storeModal.indexExcludeTags
25
- }
26
- })
37
+ }, /*#__PURE__*/_react.default.createElement("p", {
38
+ className: "empty-cart__message"
39
+ }, "Your cart is empty."), /*#__PURE__*/_react.default.createElement(_Button.default, {
40
+ onClick: handleContinueShopping
27
41
  }, "Continue shopping"));
28
42
  };
29
43
  var _default = EmptyCart;
package/dist/fontdue.css CHANGED
@@ -1272,6 +1272,17 @@ body[data-fontdue-store-modal=open] {
1272
1272
  grid-column: 1/span 2;
1273
1273
  }
1274
1274
 
1275
+ .store-modal__cart__items {
1276
+ --gutter: 20px;
1277
+ }
1278
+ @media (min-width: 900px) {
1279
+ .store-modal__cart__items {
1280
+ display: grid;
1281
+ grid-template-columns: [name] 300fr [licenses] 700fr [price] minmax(80px, auto) [end];
1282
+ column-gap: var(--gutter);
1283
+ }
1284
+ }
1285
+
1275
1286
  .store-modal__cart__button {
1276
1287
  background: none;
1277
1288
  color: inherit;
@@ -1780,6 +1791,12 @@ body[data-fontdue-store-modal=open] {
1780
1791
  font-size: 20px;
1781
1792
  }
1782
1793
 
1794
+ .store-modal__page__body:has(> .store-modal__index-item__button) {
1795
+ display: grid;
1796
+ grid-template-columns: auto 1fr auto;
1797
+ column-gap: 16px;
1798
+ }
1799
+
1783
1800
  .store-modal__index-item__button {
1784
1801
  background: none;
1785
1802
  color: inherit;
@@ -1803,24 +1820,19 @@ body[data-fontdue-store-modal=open] {
1803
1820
  width: 100%;
1804
1821
  border: 1px solid var(--secondary_text_color);
1805
1822
  padding: 20px;
1806
- display: flex;
1823
+ display: grid;
1824
+ grid-template-columns: subgrid;
1825
+ grid-column: 1/-1;
1807
1826
  align-items: center;
1808
1827
  margin-bottom: 20px;
1809
1828
  }
1810
1829
 
1811
1830
  .store-modal__index-item__text-container {
1812
- display: block;
1813
- vertical-align: baseline;
1831
+ display: contents;
1814
1832
  }
1815
1833
 
1816
1834
  .store-modal__index-item__aa {
1817
1835
  font-size: 60px;
1818
- margin-right: 16px;
1819
- display: inline-block;
1820
- }
1821
-
1822
- .store-modal__index-item__description {
1823
- display: inline-block;
1824
1836
  }
1825
1837
 
1826
1838
  .store-modal__index-item__name {
@@ -1828,10 +1840,23 @@ body[data-fontdue-store-modal=open] {
1828
1840
  line-height: 30px;
1829
1841
  }
1830
1842
 
1831
- .store-modal__index-item__buy {
1832
- margin-left: auto;
1843
+ @media (max-width: 899px) {
1844
+ .store-modal__page__body:has(> .store-modal__index-item__button) {
1845
+ display: block;
1846
+ }
1847
+ .store-modal__index-item__button {
1848
+ display: flex;
1849
+ align-items: last baseline;
1850
+ }
1851
+ .store-modal__index-item__text-container,
1852
+ .store-modal__index-item__aa,
1853
+ .store-modal__index-item__description {
1854
+ display: block;
1855
+ }
1856
+ .store-modal__index-item__buy {
1857
+ margin-left: auto;
1858
+ }
1833
1859
  }
1834
-
1835
1860
  .store-modal__license-selection__container[data-disabled=true] {
1836
1861
  opacity: 0.2;
1837
1862
  pointer-events: none;
@@ -2347,9 +2372,32 @@ body[data-fontdue-store-modal=open] {
2347
2372
  font-size: 20px;
2348
2373
  }
2349
2374
 
2375
+ @media (max-width: 899px) {
2376
+ .store-modal__family__bundle-button .store-modal__style-button__container {
2377
+ flex-wrap: wrap;
2378
+ }
2379
+ .store-modal__family__bundle-button .store-modal__style-button__feature-glyphs {
2380
+ flex: 0 0 100%;
2381
+ }
2382
+ .store-modal__family__bundle-button .store-modal__style-button__style-name {
2383
+ flex: 1 1 0;
2384
+ min-width: 0;
2385
+ }
2386
+ .store-modal__family__bundle-button .store-modal__style-button__price {
2387
+ align-self: flex-end;
2388
+ }
2389
+ }
2390
+ .empty-cart__container {
2391
+ padding: 40px 0;
2392
+ }
2393
+
2350
2394
  .empty-cart__message {
2351
2395
  font-size: 20px;
2352
- margin-bottom: 60px;
2396
+ margin: 0 0 32px;
2397
+ }
2398
+
2399
+ [data-route=cart]:has(.empty-cart__container) .store-modal__container__container {
2400
+ max-width: 800px;
2353
2401
  }
2354
2402
 
2355
2403
  .cart-additions__form {
@@ -2496,7 +2544,6 @@ body[data-fontdue-store-modal=open] {
2496
2544
  padding-right: var(--StoreModalPageContainer-padding);
2497
2545
  padding-bottom: 40px;
2498
2546
  line-height: 20px;
2499
- --gutter: 20px;
2500
2547
  }
2501
2548
  .cart-item + .cart-item {
2502
2549
  border-top: 1px solid var(--horizontal_rule_color);
@@ -2519,9 +2566,8 @@ body[data-fontdue-store-modal=open] {
2519
2566
  .cart-item {
2520
2567
  display: grid;
2521
2568
  align-items: baseline;
2522
- grid-template-columns: 300fr 700fr 80px;
2523
- grid-template-areas: "name licenses price";
2524
- grid-column-gap: var(--gutter);
2569
+ grid-template-columns: subgrid;
2570
+ grid-column: 1/-1;
2525
2571
  padding-bottom: 30px;
2526
2572
  margin-bottom: 0;
2527
2573
  }
package/dist/reducer.js CHANGED
@@ -269,6 +269,14 @@ const reducer = (state, action) => {
269
269
  };
270
270
  function createDefaultStore(config) {
271
271
  const configValue = (0, _ConfigContext.makeConfig)(config);
272
+ const initialRoute = configValue.storeModal.hideAllCollections ? {
273
+ name: 'cart'
274
+ } : {
275
+ name: 'index',
276
+ variables: {
277
+ excludeTags: configValue.storeModal.indexExcludeTags
278
+ }
279
+ };
272
280
  return (0, _redux.createStore)(reducer, {
273
281
  selectedSkuIds: {},
274
282
  // { [skuId]: Boolean }
@@ -279,12 +287,7 @@ function createDefaultStore(config) {
279
287
  skuPrices: {},
280
288
  collectionSkus: {},
281
289
  fetchedCollectionIds: [],
282
- storeModalRoute: {
283
- name: 'index',
284
- variables: {
285
- excludeTags: configValue.storeModal.indexExcludeTags
286
- }
287
- },
290
+ storeModalRoute: initialRoute,
288
291
  storeModalHistory: [],
289
292
  orderVariableSelections: [],
290
293
  licenseeIsBillingIdentity: null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fontdue-js",
3
- "version": "2.24.0",
3
+ "version": "2.25.0",
4
4
  "scripts": {
5
5
  "build": "npm run relay && run-p build-js build-css build-ts",
6
6
  "build-js": "babel src --out-dir dist --extensions .ts,.tsx,.js,.jsx",