@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.
- package/dist/buttons/link/link.d.ts +1 -0
- package/dist/buttons/link/link.js +2 -2
- package/dist/country-language-selector/connected-country-language-selector.d.ts +1 -0
- package/dist/country-language-selector/connected-country-language-selector.js +18 -6
- package/dist/shared/routing/route-provider.d.ts +1 -0
- package/dist/shared/routing/route-utils.d.ts +2 -1
- package/dist/shared/routing/route-utils.js +2 -1
- package/dist/shared/routing/types.d.ts +2 -0
- package/dist/shared/routing/use-route-link.d.ts +1 -1
- package/dist/shared/routing/use-route-link.js +3 -3
- package/dist/shared/utils/css.js +9 -53
- package/package.json +1 -1
|
@@ -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
|
|
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
|
|
@@ -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,
|
package/dist/shared/utils/css.js
CHANGED
|
@@ -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
|
|
4
|
+
const rawValue = getComputedStyle(document.body).getPropertyValue(property);
|
|
55
5
|
if (!rawValue)
|
|
56
6
|
return undefined;
|
|
57
7
|
if (/calc/i.test(rawValue)) {
|
|
58
|
-
|
|
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);
|