fontdue-js 2.24.0 → 2.25.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 CHANGED
@@ -1,3 +1,13 @@
1
+ ## 2.25.1
2
+
3
+ - Fixed an error in the `TypeTester` style/family select that could occur in rare cases with typefaces detected without any language support.
4
+ - Fixed the `Checkbox` and `CheckboxChecked` icons rendering with uneven, asymmetric edges at fractional sizes.
5
+
6
+ ## 2.25.0
7
+
8
+ - 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.
9
+ - 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).
10
+
1
11
  ## 2.24.0
2
12
 
3
13
  - 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
@@ -11,14 +11,16 @@ const Checkbox = () => /*#__PURE__*/_react.default.createElement("span", {
11
11
  "data-label": "Checkbox"
12
12
  }, /*#__PURE__*/_react.default.createElement("svg", {
13
13
  xmlns: "http://www.w3.org/2000/svg",
14
- x: "0",
15
- y: "0",
16
- enableBackground: "new 0 0 16 16",
17
- version: "1.1",
18
- viewBox: "2 2 12 12",
19
- xmlSpace: "preserve"
20
- }, /*#__PURE__*/_react.default.createElement("path", {
21
- d: "M2 2v12h12V2H2zm11 11H3V3h10v10z"
14
+ viewBox: "0 0 12 12",
15
+ shapeRendering: "crispEdges",
16
+ overflow: "visible"
17
+ }, /*#__PURE__*/_react.default.createElement("rect", {
18
+ x: "0.5",
19
+ y: "0.5",
20
+ width: "11",
21
+ height: "11",
22
+ fill: "none",
23
+ stroke: "currentColor"
22
24
  })));
23
25
  var _default = Checkbox;
24
26
  exports.default = _default;
@@ -10,15 +10,14 @@ const CheckboxChecked = () => /*#__PURE__*/_react.default.createElement("span",
10
10
  className: "icon",
11
11
  "data-label": "CheckboxChecked"
12
12
  }, /*#__PURE__*/_react.default.createElement("svg", {
13
- width: 16,
14
- height: 16,
15
- viewBox: "2 2 12 12",
16
- fill: "none",
13
+ viewBox: "0 0 12 12",
14
+ shapeRendering: "crispEdges",
15
+ overflow: "visible",
17
16
  xmlns: "http://www.w3.org/2000/svg"
18
17
  }, /*#__PURE__*/_react.default.createElement("path", {
19
18
  fillRule: "evenodd",
20
19
  clipRule: "evenodd",
21
- d: "M2 14V2h12v12H2zm5.078-1.715l5.338-8.008-.832-.554-4.662 6.992-2.568-2.569-.708.708 3.432 3.43z"
20
+ d: "M0 12V0h12v12H0zm5.078-1.715l5.338-8.008-.832-.554-4.662 6.992-2.568-2.569-.708.708 3.432 3.43z"
22
21
  })));
23
22
  var _default = CheckboxChecked;
24
23
  exports.default = _default;
@@ -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
  }
@@ -95,7 +95,7 @@ function TypeTesterStyleSelectData(_ref) {
95
95
  });
96
96
  }, [familyData, fontStyle]);
97
97
  const instance = variableSettings ? (_fontStyle$variableIn = fontStyle.variableInstances) === null || _fontStyle$variableIn === void 0 ? void 0 : _fontStyle$variableIn.find(instance => (0, _utils.compareVariableSettings)(instance, variableSettings)) : null;
98
- return config.selectable && familyData ? /*#__PURE__*/_react.default.createElement(_TypeTesterStyleSelect.default, {
98
+ return config.selectable && familyData !== null && familyData !== void 0 && familyData.length ? /*#__PURE__*/_react.default.createElement(_TypeTesterStyleSelect.default, {
99
99
  families: familyData,
100
100
  selectedFontStyleId: fontStyle.id,
101
101
  onSelectFontStyleValue: onSelectFontStyleValue,
@@ -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,32 +2544,40 @@ 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);
2503
- padding-top: 40px;
2504
2550
  }
2505
- @media (max-width: 899px) {
2551
+ @media (max-width: 1199px) {
2506
2552
  .cart-item {
2507
2553
  display: grid;
2508
2554
  grid-template-columns: 1fr auto;
2509
2555
  column-gap: 20px;
2556
+ row-gap: 20px;
2510
2557
  align-items: baseline;
2511
2558
  }
2512
2559
  }
2513
- @media (max-width: 899px) {
2514
- > div:has(> .cart-item__licenses) {
2560
+ @media (max-width: 1199px) {
2561
+ .cart-item > div:has(> .cart-item__licenses) {
2515
2562
  grid-column: 1/-1;
2516
2563
  }
2517
2564
  }
2565
+ @media (min-width: 1200px) {
2566
+ .cart-item > div:has(> .cart-item__licenses) {
2567
+ grid-column: name/end;
2568
+ }
2569
+ }
2518
2570
  @media (min-width: 900px) {
2571
+ .cart-item {
2572
+ grid-column: 1/-1;
2573
+ }
2574
+ }
2575
+ @media (min-width: 1200px) {
2519
2576
  .cart-item {
2520
2577
  display: grid;
2521
2578
  align-items: baseline;
2522
- grid-template-columns: 300fr 700fr 80px;
2523
- grid-template-areas: "name licenses price";
2524
- grid-column-gap: var(--gutter);
2579
+ grid-template-columns: subgrid;
2580
+ row-gap: 20px;
2525
2581
  padding-bottom: 30px;
2526
2582
  margin-bottom: 0;
2527
2583
  }
@@ -2544,12 +2600,17 @@ body[data-fontdue-store-modal=open] {
2544
2600
  .cart-item__label {
2545
2601
  color: var(--styles-count-color, var(--secondary_text_color));
2546
2602
  }
2547
- @media (max-width: 899px) {
2603
+ @media (max-width: 1199px) {
2548
2604
  .cart-item__product {
2549
2605
  grid-column: 1;
2550
2606
  margin-bottom: 20px;
2551
2607
  }
2552
2608
  }
2609
+ @media (min-width: 1200px) {
2610
+ .cart-item__product {
2611
+ grid-column: name/price;
2612
+ }
2613
+ }
2553
2614
  .cart-item__name {
2554
2615
  font-size: 1em;
2555
2616
  margin-top: 30px; /* line up to the baseline of next column */
@@ -2570,9 +2631,8 @@ body[data-fontdue-store-modal=open] {
2570
2631
  align-items: flex-start;
2571
2632
  gap: 20px;
2572
2633
  padding-top: 20px;
2573
- padding-bottom: 20px;
2574
2634
  }
2575
- .cart-item:first-child .cart-item__license:first-child {
2635
+ .cart-item__license:first-child {
2576
2636
  padding-top: 0;
2577
2637
  }
2578
2638
  @media (pointer: fine) {
@@ -2604,9 +2664,6 @@ body[data-fontdue-store-modal=open] {
2604
2664
  .cart-item__license__delete-button .icon {
2605
2665
  font-size: 16px;
2606
2666
  }
2607
- .cart-item__license + .cart-item__license {
2608
- border-top: 1px solid var(--horizontal_rule_color);
2609
- }
2610
2667
  .cart-item__license-wrapper {
2611
2668
  flex: 1;
2612
2669
  }
@@ -2713,15 +2770,17 @@ body[data-fontdue-store-modal=open] {
2713
2770
  .cart-item__license-variable__loading {
2714
2771
  padding: 10px;
2715
2772
  }
2716
- @media (max-width: 899px) {
2773
+ @media (max-width: 1199px) {
2717
2774
  .cart-item__price {
2718
2775
  grid-column: 2;
2719
2776
  grid-row: 1;
2720
2777
  text-align: right;
2721
2778
  }
2722
2779
  }
2723
- @media (min-width: 900px) {
2780
+ @media (min-width: 1200px) {
2724
2781
  .cart-item__price {
2782
+ grid-column: price/end;
2783
+ grid-row: 1;
2725
2784
  display: initial;
2726
2785
  margin-top: 30px;
2727
2786
  text-align: right;
@@ -2734,9 +2793,9 @@ body[data-fontdue-store-modal=open] {
2734
2793
  padding-top: 16px;
2735
2794
  color: var(--additional-license-color, var(--secondary_text_color));
2736
2795
  }
2737
- @media (min-width: 900px) {
2796
+ @media (min-width: 1200px) {
2738
2797
  .cart-item__additional-licenses {
2739
- grid-column-start: licenses;
2798
+ grid-column: name/end;
2740
2799
  padding-top: 10px;
2741
2800
  padding-bottom: 5px;
2742
2801
  }
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.1",
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",