@sonic-equipment/ui 260.0.0 → 260.0.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.
@@ -8,6 +8,7 @@ export interface LinkProps {
8
8
  href?: string;
9
9
  hrefLang?: string;
10
10
  id?: string;
11
+ ignoreLocalePrefix?: boolean;
11
12
  isDisabled?: boolean;
12
13
  lang?: string;
13
14
  onClick?: MouseEventHandler<HTMLElement>;
@@ -5,8 +5,8 @@ import clsx from 'clsx';
5
5
  import { useRouteLink } from '../../shared/routing/use-route-link.js';
6
6
  import styles from './link.module.css.js';
7
7
 
8
- const Link = forwardRef(({ children, className: _className, color, hasUnderline, href, hrefLang, id, isDisabled, lang, onClick, onKeyUp, rel, role, route, tabIndex, target, title, ...rest }, ref) => {
9
- const { getRouteLinkProps, RouteLinkElement } = useRouteLink();
8
+ const Link = forwardRef(({ children, className: _className, color, hasUnderline, href, hrefLang, id, ignoreLocalePrefix, isDisabled, lang, onClick, onKeyUp, rel, role, route, tabIndex, target, title, ...rest }, ref) => {
9
+ const { getRouteLinkProps, RouteLinkElement } = useRouteLink(ignoreLocalePrefix);
10
10
  const className = clsx(styles['link'], hasUnderline && styles['has-underline'], color && styles[color], _className);
11
11
  if (href) {
12
12
  return (jsx(RouteLinkElement, { ref: ref, className: className, "data-disabled": isDisabled ? true : undefined, hrefLang: hrefLang, id: id, lang: lang, onClick: onClick, onKeyUp: onKeyUp, rel: rel, role: role, tabIndex: isDisabled ? -1 : tabIndex, target: target, title: title, ...getRouteLinkProps(href, route), ...rest, children: children }));
@@ -2,6 +2,7 @@ import { CountryCode, LanguageCode } from '../intl/types';
2
2
  export interface ConnectedCountryLanguageSelectorProps {
3
3
  className?: string;
4
4
  countries?: CountryCode[];
5
+ currentPath?: string;
5
6
  isOpen?: boolean;
6
7
  selectedCountry?: CountryCode;
7
8
  selectedLanguage?: LanguageCode;
@@ -1,11 +1,13 @@
1
1
  "use client";
2
- import { jsx } from 'react/jsx-runtime';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { useState, useEffect } from 'react';
4
4
  import { useCookie } from '../cookies/use-cookie.js';
5
5
  import { useCountriesLanguages } from '../country-selector/use-countries-languages.js';
6
6
  import { useFormattedMessage } from '../intl/use-formatted-message.js';
7
7
  import { useIntl } from '../intl/use-intl.js';
8
8
  import { useNavigate } from '../shared/routing/use-navigate.js';
9
+ import { useRouter } from '../shared/routing/use-router.js';
10
+ import { environment } from '../shared/utils/environment.js';
9
11
  import { CountryLanguageSelector } from './country-language-selector.js';
10
12
 
11
13
  /* eslint-disable @eslint-react/hooks-extra/no-direct-set-state-in-use-effect */
@@ -28,6 +30,7 @@ function ConnectedCountryLanguageSelector({ className, countries: _countries, is
28
30
  });
29
31
  const [isOpen, setIsOpen] = useState(_isOpen ?? !CLSelectorCookie?.includes('closed=true'));
30
32
  const { countries } = useCountriesLanguages({});
33
+ const router = useRouter();
31
34
  // options for the selector menu
32
35
  const menuOptions = {
33
36
  other: t('Choose your country or region…'),
@@ -65,16 +68,23 @@ function ConnectedCountryLanguageSelector({ className, countries: _countries, is
65
68
  const optionKey = `${languageCode}-${countryCode}`;
66
69
  const optionCountryLabel = `clselector.country.${countryCode}.${languageCode}`;
67
70
  const optionLanguageLabel = `clselector.language.${languageCode}.${languageCode}`;
68
- // add option key/value to menu options
69
- menuOptions[optionKey] = (jsx("span", { lang: languageCode, children: `${t(optionCountryLabel)} - ${t(optionLanguageLabel)}` }));
70
71
  // add option key to group's options
71
72
  options.push(optionKey);
73
+ const { alternativeHrefs, basePathname, pathname } = router.url;
74
+ const path = alternativeHrefs && alternativeHrefs[optionKey]
75
+ ? `/${optionKey}${alternativeHrefs[optionKey]}`
76
+ : pathname.replace(`/${basePathname.split('/')[1]}`, `/${optionKey}`);
77
+ // add option key/value to menu options
78
+ menuOptions[optionKey] =
79
+ environment === 'next-production' ? (jsx("span", { lang: languageCode, children: `${t(optionCountryLabel)} - ${t(optionLanguageLabel)}` })) : (
80
+ // in development, show the path to help identify the correct option
81
+ jsxs("span", { lang: languageCode, children: [`${t(optionCountryLabel)} - ${t(optionLanguageLabel)}`, jsx("code", { style: { fontSize: '12px' }, children: path })] }));
72
82
  // add to option data
73
83
  optionData.push({
74
84
  country: countryCode,
75
85
  key: optionKey,
76
86
  language: languageCode,
77
- path: `/${languageCode}-${countryCode}`,
87
+ path,
78
88
  });
79
89
  });
80
90
  // push new group to groups
@@ -105,7 +115,9 @@ function ConnectedCountryLanguageSelector({ className, countries: _countries, is
105
115
  setIsOpen(false);
106
116
  if (selectedOption === 'other') {
107
117
  setCLSelectorCookie('closed=true');
108
- navigate(pathToCLSelectionList);
118
+ navigate(pathToCLSelectionList, {
119
+ ignoreLocalePrefix: true,
120
+ });
109
121
  }
110
122
  else {
111
123
  const option = optionData.find(option => option.key === selectedOption);
@@ -113,7 +125,7 @@ function ConnectedCountryLanguageSelector({ className, countries: _countries, is
113
125
  return;
114
126
  const { country, language, path } = option;
115
127
  setCLSelectorCookie(`closed=true;language=${language};country=${country}`);
116
- navigate(path);
128
+ navigate(path, { ignoreLocalePrefix: true, reload: true });
117
129
  }
118
130
  };
119
131
  // react to CountryLanguageSelectorButton clicked
@@ -6,6 +6,7 @@ export interface RouteProviderProps {
6
6
  navigate: NavigateFunction;
7
7
  paths: Paths;
8
8
  url: {
9
+ alternativeHrefs?: Record<string, string>;
9
10
  basePathname?: string;
10
11
  href: string;
11
12
  pathname: string;
@@ -1,4 +1,5 @@
1
- export declare function buildHref({ basePathname, href, }: {
1
+ export declare function buildHref({ basePathname, href, ignoreLocalePrefix, }: {
2
2
  basePathname?: string;
3
3
  href: string;
4
+ ignoreLocalePrefix?: boolean;
4
5
  }): string;
@@ -1,7 +1,8 @@
1
- function buildHref({ basePathname, href, }) {
1
+ function buildHref({ basePathname, href, ignoreLocalePrefix, }) {
2
2
  if (!href.startsWith('http') &&
3
3
  basePathname &&
4
4
  basePathname !== '/' &&
5
+ !ignoreLocalePrefix &&
5
6
  !href.startsWith(`/${basePathname}`)) {
6
7
  return `/${basePathname.replace(/^\//, '')}/${href.replace(/^\//, '')}`;
7
8
  }
@@ -24,6 +24,7 @@ export interface RouteContextValue {
24
24
  navigate: NavigateFunction;
25
25
  paths: Paths;
26
26
  url: {
27
+ alternativeHrefs?: Record<string, string>;
27
28
  basePathname?: string;
28
29
  href: string;
29
30
  pathname: string;
@@ -36,6 +37,7 @@ export interface RouteLinkElementProps extends React.HTMLProps<HTMLAnchorElement
36
37
  route?: NavigateOptions;
37
38
  }
38
39
  export interface NavigateOptions {
40
+ ignoreLocalePrefix?: boolean;
39
41
  prefetch?: boolean;
40
42
  reload?: boolean;
41
43
  replace?: boolean;
@@ -1,5 +1,5 @@
1
1
  import { NavigateOptions } from './types';
2
- export declare function useRouteLink(): {
2
+ export declare function useRouteLink(ignoreLocalePrefix?: boolean): {
3
3
  RouteLinkElement: React.ElementType<import("./types").RouteLinkElementProps>;
4
4
  getRouteLinkProps: (href: string, route?: NavigateOptions) => {
5
5
  href: string;
@@ -5,18 +5,18 @@ import { useLocation } from './use-location.js';
5
5
  import { useOnNavigate } from './use-on-navigate.js';
6
6
  import { useRouteLinkElement } from './use-route-link-element.js';
7
7
 
8
- function useRouteLink() {
8
+ function useRouteLink(ignoreLocalePrefix) {
9
9
  const { basePathname } = useLocation();
10
10
  const RouteLinkElement = useRouteLinkElement();
11
11
  const triggerCallbacks = useOnNavigate();
12
12
  const getRouteLinkProps = useCallback((href, route) => {
13
- href = buildHref({ basePathname, href });
13
+ href = buildHref({ basePathname, href, ignoreLocalePrefix });
14
14
  return {
15
15
  href,
16
16
  onNavigate: () => triggerCallbacks(href, route),
17
17
  route,
18
18
  };
19
- }, [basePathname, triggerCallbacks]);
19
+ }, [basePathname, triggerCallbacks, ignoreLocalePrefix]);
20
20
  return {
21
21
  RouteLinkElement,
22
22
  getRouteLinkProps,
@@ -1,61 +1,17 @@
1
- function evaluateCssCalc(expression, options = {}) {
2
- const baseFontSize = options.baseFontSize ?? 16;
3
- const percentBase = options.percentBase ?? 100;
4
- const expr = expression
5
- .replace(/^calc\(/, '')
6
- .replace(/\)$/, '')
7
- .trim();
8
- const tokens = expr.split(/([*+/-])/).map(token => token.trim());
9
- const toPx = (value = '0px') => {
10
- const match = value.match(/^([+-]?[\d.]+)(px|rem|em|%)?$/);
11
- if (!match)
12
- throw new Error(`Unsupported or invalid token: "${value}"`);
13
- const num = Number.parseFloat(match[1] || '0');
14
- const unit = match[2] || 'px';
15
- switch (unit) {
16
- case 'px':
17
- return num;
18
- case 'rem':
19
- case 'em':
20
- return num * baseFontSize;
21
- case '%':
22
- return (num / 100) * percentBase;
23
- default:
24
- throw new Error(`Unsupported unit: ${unit}`);
25
- }
26
- };
27
- // Evaluate left-to-right (no operator precedence)
28
- let result = toPx(tokens[0]);
29
- for (let i = 1; i < tokens.length; i += 2) {
30
- const operator = tokens[i];
31
- const nextValue = toPx(tokens[i + 1]);
32
- switch (operator) {
33
- case '+':
34
- result += nextValue;
35
- break;
36
- case '-':
37
- result -= nextValue;
38
- break;
39
- case '*':
40
- result *= nextValue;
41
- break;
42
- case '/':
43
- result /= nextValue;
44
- break;
45
- default:
46
- throw new Error(`Unsupported operator: ${operator}`);
47
- }
48
- }
49
- return result;
50
- }
51
1
  function getCssPropertyValue(property) {
52
- if (typeof document === 'undefined')
2
+ if (typeof document === 'undefined' || !getComputedStyle)
53
3
  return;
54
- const rawValue = getComputedStyle?.(document.body).getPropertyValue(property);
4
+ const rawValue = getComputedStyle(document.body).getPropertyValue(property);
55
5
  if (!rawValue)
56
6
  return undefined;
57
7
  if (/calc/i.test(rawValue)) {
58
- return `${evaluateCssCalc(rawValue, { baseFontSize: 16, percentBase: 100 })}px`;
8
+ const el = document.createElement('div');
9
+ el.style.cssText = 'position:fixed;visibility:hidden;pointer-events:none';
10
+ el.style.top = rawValue;
11
+ document.body.append(el);
12
+ const px = Number.parseFloat(getComputedStyle(el).top);
13
+ el.remove();
14
+ return Number.isNaN(px) ? undefined : `${px}px`;
59
15
  }
60
16
  if (rawValue && !/\D/.test(rawValue)) {
61
17
  const valueAsNumber = Number.parseFloat(rawValue);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonic-equipment/ui",
3
- "version": "260.0.0",
3
+ "version": "260.0.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "engines": {