@adobe-commerce/elsie 1.6.0-alpha1 → 1.6.0-alpha3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe-commerce/elsie",
3
- "version": "1.6.0-alpha1",
3
+ "version": "1.6.0-alpha3",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "description": "Domain Package SDK",
6
6
  "engines": {
@@ -27,8 +27,8 @@
27
27
  },
28
28
  "devDependencies": {
29
29
  "@adobe-commerce/event-bus": "~1.0.1",
30
- "@adobe-commerce/fetch-graphql": "1.2.0-beta1",
31
- "@adobe-commerce/recaptcha": "1.0.2-beta1",
30
+ "@adobe-commerce/fetch-graphql": "~1.2.0",
31
+ "@adobe-commerce/recaptcha": "~1.0.2",
32
32
  "@adobe-commerce/storefront-design": "~1.0.0",
33
33
  "@dropins/build-tools": "~1.0.1",
34
34
  "preact": "~10.22.1",
@@ -8,7 +8,7 @@
8
8
  *******************************************************************/
9
9
 
10
10
  import '@adobe-commerce/elsie/components/Field/Field.css';
11
- import { classes } from '@adobe-commerce/elsie/lib';
11
+ import { classes, VComponent } from '@adobe-commerce/elsie/lib';
12
12
  import { FunctionComponent, VNode } from 'preact';
13
13
  import { HTMLAttributes } from 'preact/compat';
14
14
 
@@ -36,8 +36,23 @@ export const Field: FunctionComponent<FieldProps> = ({
36
36
  }) => {
37
37
  const id =
38
38
  children?.props?.id ?? `dropin-field-${Math.random().toString(36)}`;
39
- const ChildComponent =
40
- children && typeof children.type !== 'string' ? children.type : null;
39
+
40
+ let fieldContent: VNode | string | null = null;
41
+
42
+ if (children && typeof children !== 'string') {
43
+ fieldContent = (
44
+ <VComponent
45
+ node={children}
46
+ id={id}
47
+ key={children.key}
48
+ disabled={disabled}
49
+ size={size}
50
+ error={!!error}
51
+ success={!!success && !error}
52
+ />
53
+ );
54
+ }
55
+
41
56
 
42
57
  return (
43
58
  <div {...props} className={classes(['dropin-field', className])}>
@@ -55,17 +70,7 @@ export const Field: FunctionComponent<FieldProps> = ({
55
70
  )}
56
71
 
57
72
  <div className={classes(['dropin-field__content'])}>
58
- {ChildComponent && children && (
59
- <ChildComponent
60
- {...children.props}
61
- id={id}
62
- key={children.key}
63
- disabled={disabled}
64
- size={size}
65
- error={!!error}
66
- success={!!success && !error}
67
- />
68
- )}
73
+ {fieldContent}
69
74
  </div>
70
75
 
71
76
  <div
@@ -2,14 +2,14 @@
2
2
  * Copyright 2024 Adobe
3
3
  * All Rights Reserved.
4
4
  *
5
- * NOTICE: Adobe permits you to use, modify, and distribute this
6
- * file in accordance with the terms of the Adobe license agreement
7
- * accompanying it.
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
8
  *******************************************************************/
9
9
 
10
10
  import { FunctionComponent } from 'preact';
11
11
  import { HTMLAttributes, useMemo } from 'preact/compat';
12
- import { classes, getGlobalLocale } from '@adobe-commerce/elsie/lib';
12
+ import { classes, getPriceFormatter } from '@adobe-commerce/elsie/lib';
13
13
  import '@adobe-commerce/elsie/components/Price/Price.css';
14
14
 
15
15
  export interface PriceProps
@@ -39,43 +39,10 @@ export const Price: FunctionComponent<PriceProps> = ({
39
39
  size = 'small',
40
40
  ...props
41
41
  }) => {
42
- // Determine the locale to use: prop locale > global locale > browser locale
43
- const effectiveLocale = useMemo(() => {
44
- if (locale) {
45
- return locale;
46
- }
47
- const globalLocale = getGlobalLocale();
48
- if (globalLocale) {
49
- return globalLocale;
50
- }
51
- // Fallback to browser locale or default
52
- return process.env.LOCALE && process.env.LOCALE !== 'undefined' ? process.env.LOCALE : 'en-US';
53
- }, [locale]);
54
-
55
- const formatter = useMemo(
56
- () => {
57
- const params: Intl.NumberFormatOptions = {
58
- style: 'currency',
59
- currency: currency || 'USD',
60
- // These options are needed to round to whole numbers if that's what you want.
61
- minimumFractionDigits: 2, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
62
- maximumFractionDigits: 2, // (causes 2500.99 to be printed as $2,501)
63
- ...formatOptions,
64
- }
65
- try {
66
- return new Intl.NumberFormat(effectiveLocale, params);
67
- } catch (error) {
68
- console.error(`Error creating Intl.NumberFormat instance for locale ${effectiveLocale}. Falling back to en-US.`, error);
69
- return new Intl.NumberFormat('en-US', params);
70
- }
71
- },
72
- [effectiveLocale, currency, formatOptions]
73
- );
74
-
75
- const formattedAmount = useMemo(
76
- () => formatter.format(amount),
77
- [amount, formatter]
78
- );
42
+ const formattedAmount = useMemo(() => {
43
+ const formatter = getPriceFormatter({ currency, locale, formatOptions });
44
+ return formatter.format(amount);
45
+ }, [amount, currency, locale, formatOptions]);
79
46
 
80
47
  return (
81
48
  <span
@@ -23,6 +23,7 @@ interface Config {
23
23
 
24
24
  // Private state
25
25
  let config: Config | null = null;
26
+ let options: { match?: (key: string) => boolean } | null = null;
26
27
  let rootPath: string | null = null;
27
28
  let rootConfig: ConfigRoot | null = null;
28
29
 
@@ -31,6 +32,7 @@ let rootConfig: ConfigRoot | null = null;
31
32
  */
32
33
  function resetConfig() {
33
34
  config = null;
35
+ options = null;
34
36
  rootPath = null;
35
37
  rootConfig = null;
36
38
  }
@@ -40,7 +42,7 @@ function resetConfig() {
40
42
  * @param {Object} [configObj=config] - The config object.
41
43
  * @returns {string} - The root path.
42
44
  */
43
- function getRootPath(configObj: Config | null = config, options?: { match?: (key: string) => boolean }): string {
45
+ function getRootPath(configObj: Config | null = config, optionsObj: { match?: (key: string) => boolean } | null = options): string {
44
46
  if (!configObj) {
45
47
  console.warn('No config found. Please call initializeConfig() first.');
46
48
  return '/';
@@ -56,7 +58,7 @@ function getRootPath(configObj: Config | null = config, options?: { match?: (key
56
58
  .find(
57
59
  (key) =>
58
60
  window.location.pathname === key ||
59
- (options?.match?.(key) ?? window.location.pathname.startsWith(key))
61
+ (optionsObj?.match?.(key) ?? window.location.pathname.startsWith(key))
60
62
  );
61
63
 
62
64
  return value ?? '/';
@@ -131,9 +133,10 @@ function applyConfigOverrides(
131
133
  * @param {Function} [options.match] - The function to match the path to the config.
132
134
  * @returns {Object} The initialized root configuration
133
135
  */
134
- function initializeConfig(configObj: Config, options?: { match?: (key: string) => boolean }): ConfigRoot {
136
+ function initializeConfig(configObj: Config, optionsObj?: { match?: (key: string) => boolean }): ConfigRoot {
135
137
  config = configObj;
136
- rootPath = getRootPath(config, { match: options?.match });
138
+ options = optionsObj ?? null;
139
+ rootPath = getRootPath(config, { match: optionsObj?.match });
137
140
  rootConfig = applyConfigOverrides(config, rootPath);
138
141
  return rootConfig;
139
142
  }
@@ -0,0 +1,69 @@
1
+ /********************************************************************
2
+ * Copyright 2025 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ import { getGlobalLocale } from '@adobe-commerce/elsie/lib';
11
+
12
+ export interface PriceFormatterOptions {
13
+ currency?: string | null;
14
+ locale?: string;
15
+ formatOptions?: Intl.NumberFormatOptions;
16
+ }
17
+
18
+ /**
19
+ * Determines the effective locale to use for price formatting
20
+ * Priority: prop locale > global locale > browser locale > default 'en-US'
21
+ */
22
+ export function getEffectiveLocale(locale?: string): string {
23
+ if (locale) {
24
+ return locale;
25
+ }
26
+ const globalLocale = getGlobalLocale();
27
+ if (globalLocale) {
28
+ return globalLocale;
29
+ }
30
+ // Fallback to browser locale or default
31
+ return process.env.LOCALE && process.env.LOCALE !== 'undefined' ? process.env.LOCALE : 'en-US';
32
+ }
33
+
34
+ /**
35
+ * Gets an Intl.NumberFormat instance for price formatting
36
+ * Uses getEffectiveLocale internally to determine the best locale
37
+ *
38
+ * @example
39
+ * // Single price formatting
40
+ * const formatter = getPriceFormatter({ currency: 'USD', locale: 'en-US' });
41
+ * const price = formatter.format(10.99); // "$10.99"
42
+ *
43
+ * @example
44
+ * // Bulk price formatting (more efficient)
45
+ * const formatter = getPriceFormatter({ currency: 'EUR', locale: 'fr-FR' });
46
+ * const prices = [10.99, 25.50, 99.99].map(amount => formatter.format(amount));
47
+ */
48
+ export function getPriceFormatter(
49
+ options: PriceFormatterOptions = {}
50
+ ): Intl.NumberFormat {
51
+ const { currency, locale, formatOptions = {} } = options;
52
+ const effectiveLocale = getEffectiveLocale(locale);
53
+
54
+ const params: Intl.NumberFormatOptions = {
55
+ style: 'currency',
56
+ currency: currency || 'USD',
57
+ // These options are needed to round to whole numbers if that's what you want.
58
+ minimumFractionDigits: 2, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
59
+ maximumFractionDigits: 2, // (causes 2500.99 to be printed as $2,501)
60
+ ...formatOptions,
61
+ };
62
+
63
+ try {
64
+ return new Intl.NumberFormat(effectiveLocale, params);
65
+ } catch (error) {
66
+ console.error(`Error creating Intl.NumberFormat instance for locale ${effectiveLocale}. Falling back to en-US.`, error);
67
+ return new Intl.NumberFormat('en-US', params);
68
+ }
69
+ }
package/src/lib/index.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  * Copyright 2024 Adobe
3
3
  * All Rights Reserved.
4
4
  *
5
- * NOTICE: Adobe permits you to use, modify, and distribute this
6
- * file in accordance with the terms of the Adobe license agreement
7
- * accompanying it.
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
8
  *******************************************************************/
9
9
 
10
10
  export * from '@adobe-commerce/elsie/lib/form-values';
@@ -25,3 +25,4 @@ export * from '@adobe-commerce/elsie/lib/is-number';
25
25
  export * from '@adobe-commerce/elsie/lib/deviceUtils';
26
26
  export * from '@adobe-commerce/elsie/lib/get-path-value';
27
27
  export * from '@adobe-commerce/elsie/lib/get-cookie';
28
+ export * from '@adobe-commerce/elsie/lib/get-price-formatter';