@cronos-labs/ui 0.8.0 → 0.9.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.
Files changed (40) hide show
  1. package/README.md +60 -16
  2. package/dist/Footer/index.d.ts +7 -38
  3. package/dist/Footer/index.js +9 -63
  4. package/dist/Footer/static.d.ts +16 -0
  5. package/dist/Footer/static.js +11 -0
  6. package/dist/Footer/styles.d.ts +2 -2
  7. package/dist/Footer/styles.js +29 -27
  8. package/dist/Footer/types.d.ts +41 -0
  9. package/dist/Footer/types.js +1 -0
  10. package/dist/Footer/view.d.ts +2 -0
  11. package/dist/Footer/view.js +55 -0
  12. package/dist/Header/NavDropdown.d.ts +1 -1
  13. package/dist/Header/NavDropdown.js +3 -3
  14. package/dist/Header/index.d.ts +7 -56
  15. package/dist/Header/index.js +9 -186
  16. package/dist/Header/static.d.ts +15 -0
  17. package/dist/Header/static.js +11 -0
  18. package/dist/Header/styles.d.ts +4 -1
  19. package/dist/Header/styles.js +27 -4
  20. package/dist/Header/types.d.ts +61 -0
  21. package/dist/Header/types.js +1 -0
  22. package/dist/Header/view.d.ts +2 -0
  23. package/dist/Header/view.js +184 -0
  24. package/dist/LocaleSelector/index.d.ts +8 -9
  25. package/dist/LocaleSelector/index.js +10 -61
  26. package/dist/LocaleSelector/view.d.ts +8 -0
  27. package/dist/LocaleSelector/view.js +59 -0
  28. package/dist/config/eslintConfig.d.ts +17 -0
  29. package/dist/config/eslintConfig.js +52 -23
  30. package/dist/index.d.ts +4 -0
  31. package/dist/index.js +4 -0
  32. package/dist/navigation/context.d.ts +26 -0
  33. package/dist/navigation/context.js +18 -0
  34. package/dist/navigation/router.d.ts +11 -0
  35. package/dist/navigation/router.js +25 -0
  36. package/dist/navigation/static.d.ts +15 -0
  37. package/dist/navigation/static.js +19 -0
  38. package/dist/navigationContent.d.ts +6 -0
  39. package/dist/navigationContent.js +27 -0
  40. package/package.json +2 -1
@@ -1,9 +1,8 @@
1
- interface LocaleSelectorProps {
2
- ariaLabel: string;
3
- forceDocumentNavigation?: boolean;
4
- inlineMenu?: boolean;
5
- menuPlacement?: 'down' | 'up';
6
- onLocaleSelect?: (() => void) | undefined;
7
- }
8
- export declare function LocaleSelector({ ariaLabel, forceDocumentNavigation, inlineMenu, menuPlacement, onLocaleSelect, }: LocaleSelectorProps): React.JSX.Element;
9
- export {};
1
+ import { type LocaleSelectorProps } from './view.js';
2
+ export type { LocaleSelectorProps } from './view.js';
3
+ /**
4
+ * Standalone locale selector for apps with a react-router `<Router>` above it.
5
+ * Inside `Header`/`Footer` the view is rendered directly and shares their
6
+ * navigation location.
7
+ */
8
+ export declare function LocaleSelector(props: LocaleSelectorProps): React.JSX.Element;
@@ -1,62 +1,11 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
3
- import { useLocation, useNavigate } from 'react-router-dom';
4
- import { localeConfig } from '../locale/config.js';
5
- import { useCurrentLocale } from '../locale/hooks.js';
6
- import { setStoredLocalePreference } from '../locale/localePreference.js';
7
- import { buildLocalizedPath, stripLocalePrefix } from '../locale/routes.js';
8
- import { LocaleSelectorButton, LocaleSelectorChevron, LocaleSelectorIcon, LocaleSelectorMenu, LocaleSelectorOption, LocaleSelectorOptionList, LocaleSelectorRoot, LocaleSelectorText, } from './styles.js';
9
- export function LocaleSelector({ ariaLabel, forceDocumentNavigation = false, inlineMenu = false, menuPlacement = 'up', onLocaleSelect, }) {
10
- const [isOpen, setIsOpen] = useState(false);
11
- const selectorRef = useRef(null);
12
- const locale = useCurrentLocale();
13
- const location = useLocation();
14
- const navigate = useNavigate();
15
- const menuId = 'footer-locale-menu';
16
- const currentLocaleLabel = localeConfig.locales[locale].selectorLabel;
17
- const localeOptions = localeConfig.supportedLocales.map((optionLocale) => ({
18
- isCurrent: optionLocale === locale,
19
- label: localeConfig.locales[optionLocale].selectorLabel,
20
- locale: optionLocale,
21
- }));
22
- useEffect(() => {
23
- setIsOpen(false);
24
- }, [location.pathname, location.hash]);
25
- useEffect(() => {
26
- if (!isOpen)
27
- return;
28
- const handlePointerDown = (event) => {
29
- if (event.target instanceof Node && selectorRef.current?.contains(event.target)) {
30
- return;
31
- }
32
- setIsOpen(false);
33
- };
34
- const handleKeyDown = (event) => {
35
- if (event.key === 'Escape') {
36
- setIsOpen(false);
37
- }
38
- };
39
- document.addEventListener('pointerdown', handlePointerDown);
40
- document.addEventListener('keydown', handleKeyDown);
41
- return () => {
42
- document.removeEventListener('pointerdown', handlePointerDown);
43
- document.removeEventListener('keydown', handleKeyDown);
44
- };
45
- }, [isOpen]);
46
- const buildLocaleTarget = (targetLocale) => {
47
- const targetPathname = buildLocalizedPath(stripLocalePrefix(location.pathname), targetLocale);
48
- return `${targetPathname}${location.search}${location.hash}`;
49
- };
50
- const handleLocaleSelect = (targetLocale) => {
51
- const targetHref = buildLocaleTarget(targetLocale);
52
- setStoredLocalePreference(targetLocale);
53
- setIsOpen(false);
54
- onLocaleSelect?.();
55
- if (forceDocumentNavigation) {
56
- window.location.assign(targetHref);
57
- return;
58
- }
59
- void navigate(targetHref);
60
- };
61
- return (_jsxs(LocaleSelectorRoot, { ref: selectorRef, "$inlineMenu": inlineMenu, children: [_jsxs(LocaleSelectorButton, { type: "button", "aria-label": ariaLabel, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": menuId, onClick: () => setIsOpen((currentValue) => !currentValue), children: [_jsx(LocaleSelectorIcon, { "aria-hidden": "true" }), _jsx(LocaleSelectorText, { children: currentLocaleLabel }), _jsx(LocaleSelectorChevron, { "$open": isOpen, "aria-hidden": "true" })] }), isOpen ? (_jsx(LocaleSelectorMenu, { id: menuId, role: "menu", "aria-label": "Language options", "$inline": inlineMenu, "$placement": menuPlacement, children: _jsx(LocaleSelectorOptionList, { children: localeOptions.map((option) => (_jsx(LocaleSelectorOption, { type: "button", role: "menuitemradio", "aria-checked": option.isCurrent, "$active": option.isCurrent, onClick: () => handleLocaleSelect(option.locale), children: _jsx("span", { children: option.label }) }, option.label))) }) })) : null] }));
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { RouterNavigationProvider } from '../navigation/router.js';
3
+ import { LocaleSelectorView } from './view.js';
4
+ /**
5
+ * Standalone locale selector for apps with a react-router `<Router>` above it.
6
+ * Inside `Header`/`Footer` the view is rendered directly and shares their
7
+ * navigation location.
8
+ */
9
+ export function LocaleSelector(props) {
10
+ return (_jsx(RouterNavigationProvider, { children: _jsx(LocaleSelectorView, { ...props }) }));
62
11
  }
@@ -0,0 +1,8 @@
1
+ export interface LocaleSelectorProps {
2
+ ariaLabel: string;
3
+ forceDocumentNavigation?: boolean;
4
+ inlineMenu?: boolean;
5
+ menuPlacement?: 'down' | 'up';
6
+ onLocaleSelect?: (() => void) | undefined;
7
+ }
8
+ export declare function LocaleSelectorView({ ariaLabel, forceDocumentNavigation, inlineMenu, menuPlacement, onLocaleSelect, }: LocaleSelectorProps): React.JSX.Element;
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from 'react';
3
+ import { localeConfig } from '../locale/config.js';
4
+ import { setStoredLocalePreference } from '../locale/localePreference.js';
5
+ import { buildLocalizedPath, stripLocalePrefix } from '../locale/routes.js';
6
+ import { useNavigationLocation } from '../navigation/context.js';
7
+ import { LocaleSelectorButton, LocaleSelectorChevron, LocaleSelectorIcon, LocaleSelectorMenu, LocaleSelectorOption, LocaleSelectorOptionList, LocaleSelectorRoot, LocaleSelectorText, } from './styles.js';
8
+ export function LocaleSelectorView({ ariaLabel, forceDocumentNavigation = false, inlineMenu = false, menuPlacement = 'up', onLocaleSelect, }) {
9
+ const [isOpen, setIsOpen] = useState(false);
10
+ const selectorRef = useRef(null);
11
+ const { locale, pathname, search, hash, navigate } = useNavigationLocation();
12
+ const menuId = useId();
13
+ const currentLocaleLabel = localeConfig.locales[locale].selectorLabel;
14
+ const localeOptions = localeConfig.supportedLocales.map((optionLocale) => ({
15
+ isCurrent: optionLocale === locale,
16
+ label: localeConfig.locales[optionLocale].selectorLabel,
17
+ locale: optionLocale,
18
+ }));
19
+ useEffect(() => {
20
+ setIsOpen(false);
21
+ }, [pathname, hash]);
22
+ useEffect(() => {
23
+ if (!isOpen)
24
+ return;
25
+ const handlePointerDown = (event) => {
26
+ if (event.target instanceof Node && selectorRef.current?.contains(event.target)) {
27
+ return;
28
+ }
29
+ setIsOpen(false);
30
+ };
31
+ const handleKeyDown = (event) => {
32
+ if (event.key === 'Escape') {
33
+ setIsOpen(false);
34
+ }
35
+ };
36
+ document.addEventListener('pointerdown', handlePointerDown);
37
+ document.addEventListener('keydown', handleKeyDown);
38
+ return () => {
39
+ document.removeEventListener('pointerdown', handlePointerDown);
40
+ document.removeEventListener('keydown', handleKeyDown);
41
+ };
42
+ }, [isOpen]);
43
+ const buildLocaleTarget = (targetLocale) => {
44
+ const targetPathname = buildLocalizedPath(stripLocalePrefix(pathname), targetLocale);
45
+ return `${targetPathname}${search}${hash}`;
46
+ };
47
+ const handleLocaleSelect = (targetLocale) => {
48
+ const targetHref = buildLocaleTarget(targetLocale);
49
+ setStoredLocalePreference(targetLocale);
50
+ setIsOpen(false);
51
+ onLocaleSelect?.();
52
+ if (forceDocumentNavigation) {
53
+ window.location.assign(targetHref);
54
+ return;
55
+ }
56
+ navigate(targetHref);
57
+ };
58
+ return (_jsxs(LocaleSelectorRoot, { ref: selectorRef, "$inlineMenu": inlineMenu, children: [_jsxs(LocaleSelectorButton, { type: "button", "aria-label": ariaLabel, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": menuId, onClick: () => setIsOpen((currentValue) => !currentValue), children: [_jsx(LocaleSelectorIcon, { "aria-hidden": "true" }), _jsx(LocaleSelectorText, { children: currentLocaleLabel }), _jsx(LocaleSelectorChevron, { "$open": isOpen, "aria-hidden": "true" })] }), isOpen ? (_jsx(LocaleSelectorMenu, { id: menuId, role: "menu", "aria-label": "Language options", "$inline": inlineMenu, "$placement": menuPlacement, children: _jsx(LocaleSelectorOptionList, { children: localeOptions.map((option) => (_jsx(LocaleSelectorOption, { type: "button", role: "menuitemradio", "aria-checked": option.isCurrent, "$active": option.isCurrent, onClick: () => handleLocaleSelect(option.locale), children: _jsx("span", { children: option.label }) }, option.label))) }) })) : null] }));
59
+ }
@@ -1,6 +1,23 @@
1
1
  export interface ReactEslintConfigOptions {
2
2
  ignores?: string[];
3
+ /**
4
+ * Globs, relative to `tsconfigRootDir`, for files that belong to no
5
+ * tsconfig but should still be linted — config files at the repo root, and
6
+ * build scripts under `scripts/`. typescript-eslint reads this from inside
7
+ * `projectService`, so passing it as a sibling silently does nothing.
8
+ */
3
9
  allowDefaultProject?: string[];
10
+ /**
11
+ * Globs for plain Node files — build scripts, codegen — that should be
12
+ * linted but are not part of the React app: Node globals instead of
13
+ * browser, and no type-aware rules, since they have no types to check and
14
+ * every value reads as `any`. Defaults to none, so a consumer opts in.
15
+ *
16
+ * These are folded into `allowDefaultProject`, which typescript-eslint
17
+ * refuses to match with `**` — use a single-level glob such as
18
+ * `scripts/*.mjs`.
19
+ */
20
+ nodeScripts?: string[];
4
21
  tsconfigRootDir: string;
5
22
  }
6
23
  export declare const createReactEslintConfig: (options: ReactEslintConfigOptions) => import("typescript-eslint").FlatConfig.ConfigArray;
@@ -4,28 +4,57 @@ import tseslint from 'typescript-eslint';
4
4
  import reactHooks from 'eslint-plugin-react-hooks';
5
5
  import reactRefresh from 'eslint-plugin-react-refresh';
6
6
  import eslintConfigPrettier from 'eslint-config-prettier';
7
- export const createReactEslintConfig = (options) => tseslint.config({
8
- ignores: options.ignores ?? ['dist', 'coverage', 'node_modules', 'eslint.config.mjs'],
9
- }, js.configs.recommended, ...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.stylisticTypeChecked, {
10
- languageOptions: {
11
- ecmaVersion: 2023,
12
- globals: {
13
- ...globals.browser,
7
+ export const createReactEslintConfig = (options) => {
8
+ // Node scripts are outside every tsconfig by definition, so they need to be
9
+ // in the default-project allowlist as well as having type-aware rules off.
10
+ // Folding that in here means a consumer names them once.
11
+ const allowDefaultProject = [
12
+ ...(options.allowDefaultProject ?? ['*.{js,mjs,cjs,ts}']),
13
+ ...(options.nodeScripts ?? []),
14
+ ];
15
+ return tseslint.config({
16
+ ignores: options.ignores ?? ['dist', 'coverage', 'node_modules', 'eslint.config.mjs'],
17
+ }, js.configs.recommended, ...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.stylisticTypeChecked, {
18
+ languageOptions: {
19
+ ecmaVersion: 2023,
20
+ globals: {
21
+ ...globals.browser,
22
+ },
23
+ parserOptions: {
24
+ // `allowDefaultProject` is an option *of* the project service, not a
25
+ // sibling of it. Passing `projectService: true` alongside it left
26
+ // the allowlist unread, so any file outside a tsconfig was simply
27
+ // skipped rather than linted.
28
+ projectService: {
29
+ allowDefaultProject,
30
+ },
31
+ tsconfigRootDir: options.tsconfigRootDir,
32
+ },
14
33
  },
15
- parserOptions: {
16
- projectService: true,
17
- allowDefaultProject: options.allowDefaultProject ?? ['*.{js,mjs,cjs,ts}'],
18
- tsconfigRootDir: options.tsconfigRootDir,
34
+ plugins: {
35
+ 'react-hooks': reactHooks,
36
+ 'react-refresh': reactRefresh,
19
37
  },
20
- },
21
- plugins: {
22
- 'react-hooks': reactHooks,
23
- 'react-refresh': reactRefresh,
24
- },
25
- rules: {
26
- ...reactHooks.configs.recommended.rules,
27
- 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
28
- '@typescript-eslint/no-explicit-any': 'error',
29
- '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
30
- },
31
- }, eslintConfigPrettier);
38
+ rules: {
39
+ ...reactHooks.configs.recommended.rules,
40
+ 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
41
+ '@typescript-eslint/no-explicit-any': 'error',
42
+ '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
43
+ },
44
+ },
45
+ // Plain Node files, opted into by the consumer. Type-aware rules are
46
+ // switched off for them with typescript-eslint's own
47
+ // `disableTypeChecked`: a .mjs build script has no types, so every value
48
+ // reads as `any` and the unsafe-* rules fire on correct code.
49
+ ...(options.nodeScripts?.length
50
+ ? [
51
+ {
52
+ files: options.nodeScripts,
53
+ ...tseslint.configs.disableTypeChecked,
54
+ languageOptions: {
55
+ globals: { ...globals.node },
56
+ },
57
+ },
58
+ ]
59
+ : []), eslintConfigPrettier);
60
+ };
package/dist/index.d.ts CHANGED
@@ -11,7 +11,11 @@ export { Seo, type RouteSeoMeta } from './Seo/index.js';
11
11
  export { LocaleSelector } from './LocaleSelector/index.js';
12
12
  export { Header, type HeaderPresentationVariant, type HeaderPresentationState, type HeaderNavChild, type HeaderNavItem, type HeaderContent, type HeaderWaitlistCta, } from './Header/index.js';
13
13
  export { normalizePathname } from './Header/helper.js';
14
+ export { HeaderStatic, type HeaderStaticProps } from './Header/static.js';
14
15
  export { Footer, type FooterLinkItem, type FooterLinkGroup, type FooterLegalLinkItem, type FooterContent, } from './Footer/index.js';
16
+ export { FooterStatic, type FooterStaticProps } from './Footer/static.js';
17
+ export { useNavigationLocation, type NavigationLocation } from './navigation/context.js';
18
+ export { StaticNavigationProvider } from './navigation/static.js';
15
19
  export { navigationContent } from './navigationContent.js';
16
20
  export type { NavigationContent } from './navigationContent.js';
17
21
  export { interpolateMessageTemplate } from './format.js';
package/dist/index.js CHANGED
@@ -9,7 +9,11 @@ export { Seo } from './Seo/index.js';
9
9
  export { LocaleSelector } from './LocaleSelector/index.js';
10
10
  export { Header, } from './Header/index.js';
11
11
  export { normalizePathname } from './Header/helper.js';
12
+ export { HeaderStatic } from './Header/static.js';
12
13
  export { Footer, } from './Footer/index.js';
14
+ export { FooterStatic } from './Footer/static.js';
15
+ export { useNavigationLocation } from './navigation/context.js';
16
+ export { StaticNavigationProvider } from './navigation/static.js';
13
17
  export { navigationContent } from './navigationContent.js';
14
18
  export { interpolateMessageTemplate } from './format.js';
15
19
  export { SectionAnchorNav } from './SectionAnchorNav/index.js';
@@ -0,0 +1,26 @@
1
+ import type { AppLocale } from '../locale/types.js';
2
+ /**
3
+ * The slice of router state the chrome components read: where the page is
4
+ * and how to move it. `Header`, `Footer` and `LocaleSelector` consume it, so
5
+ * the same view code runs under react-router (see ./router.tsx) and on the
6
+ * static Astro sites, which have no router and pass the location as props
7
+ * (see ./static.tsx).
8
+ */
9
+ export interface NavigationLocation {
10
+ locale: AppLocale;
11
+ pathname: string;
12
+ search: string;
13
+ hash: string;
14
+ /** Client-side navigation when a router is present; a document load otherwise. */
15
+ navigate: (to: string) => void;
16
+ }
17
+ export declare const NavigationLocationProvider: import("react").Provider<NavigationLocation | null>;
18
+ /**
19
+ * Reads the current navigation location. Throws outside a provider: a chrome
20
+ * component rendered with neither a router nor explicit location props would
21
+ * otherwise build every href against a guessed locale.
22
+ *
23
+ * @returns the current location and a navigate function
24
+ * @throws {Error} when no `Header`/`Footer` wrapper or `StaticNavigationProvider` is above
25
+ */
26
+ export declare const useNavigationLocation: () => NavigationLocation;
@@ -0,0 +1,18 @@
1
+ import { createContext, useContext } from 'react';
2
+ const NavigationLocationContext = createContext(null);
3
+ export const NavigationLocationProvider = NavigationLocationContext.Provider;
4
+ /**
5
+ * Reads the current navigation location. Throws outside a provider: a chrome
6
+ * component rendered with neither a router nor explicit location props would
7
+ * otherwise build every href against a guessed locale.
8
+ *
9
+ * @returns the current location and a navigate function
10
+ * @throws {Error} when no `Header`/`Footer` wrapper or `StaticNavigationProvider` is above
11
+ */
12
+ export const useNavigationLocation = () => {
13
+ const value = useContext(NavigationLocationContext);
14
+ if (value === null) {
15
+ throw new Error('No navigation location: render <Header>/<Footer> inside a react-router <Router>, or use <HeaderStatic>/<FooterStatic> with explicit locale and pathname.');
16
+ }
17
+ return value;
18
+ };
@@ -0,0 +1,11 @@
1
+ import { type ReactNode } from 'react';
2
+ interface RouterNavigationProviderProps {
3
+ children: ReactNode;
4
+ }
5
+ /**
6
+ * Location backed by react-router. The only module the chrome components
7
+ * reach react-router through, so a consumer that imports the static variants
8
+ * never pulls the router into its bundle.
9
+ */
10
+ export declare function RouterNavigationProvider({ children, }: RouterNavigationProviderProps): React.JSX.Element;
11
+ export {};
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { useLocation, useNavigate } from 'react-router-dom';
4
+ import { useCurrentLocale } from '../locale/hooks.js';
5
+ import { NavigationLocationProvider } from './context.js';
6
+ /**
7
+ * Location backed by react-router. The only module the chrome components
8
+ * reach react-router through, so a consumer that imports the static variants
9
+ * never pulls the router into its bundle.
10
+ */
11
+ export function RouterNavigationProvider({ children, }) {
12
+ const locale = useCurrentLocale();
13
+ const location = useLocation();
14
+ const navigate = useNavigate();
15
+ const value = useMemo(() => ({
16
+ locale,
17
+ pathname: location.pathname,
18
+ search: location.search,
19
+ hash: location.hash,
20
+ navigate: (to) => {
21
+ void navigate(to);
22
+ },
23
+ }), [locale, location.hash, location.pathname, location.search, navigate]);
24
+ return _jsx(NavigationLocationProvider, { value: value, children: children });
25
+ }
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { AppLocale } from '../locale/types.js';
3
+ interface StaticNavigationProviderProps {
4
+ locale: AppLocale;
5
+ pathname: string;
6
+ search?: string | undefined;
7
+ hash?: string | undefined;
8
+ children: ReactNode;
9
+ }
10
+ /**
11
+ * Location for sites without a client router: every navigation is a full
12
+ * document load, so `navigate` is `window.location.assign`.
13
+ */
14
+ export declare function StaticNavigationProvider({ locale, pathname, search, hash, children, }: StaticNavigationProviderProps): React.JSX.Element;
15
+ export {};
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { NavigationLocationProvider } from './context.js';
4
+ /**
5
+ * Location for sites without a client router: every navigation is a full
6
+ * document load, so `navigate` is `window.location.assign`.
7
+ */
8
+ export function StaticNavigationProvider({ locale, pathname, search = '', hash = '', children, }) {
9
+ const value = useMemo(() => ({
10
+ locale,
11
+ pathname,
12
+ search,
13
+ hash,
14
+ navigate: (to) => {
15
+ window.location.assign(to);
16
+ },
17
+ }), [hash, locale, pathname, search]);
18
+ return _jsx(NavigationLocationProvider, { value: value, children: children });
19
+ }
@@ -8,6 +8,12 @@ export interface NavigationContent {
8
8
  joinWaitlist: string;
9
9
  waitlistEmailCta: string;
10
10
  soon: string;
11
+ /** Label of the Cronos Launch entry (a product name; not translated). */
12
+ launch: string;
13
+ /** Label of the Network dropdown. */
14
+ network: string;
15
+ /** Label of the skip-to-content link the Header renders when given. */
16
+ skipToContent: string;
11
17
  localeSelectorAriaLabel: string;
12
18
  };
13
19
  footer: {
@@ -9,6 +9,9 @@ export const navigationContent = {
9
9
  joinWaitlist: 'Join Waitlist',
10
10
  waitlistEmailCta: 'Enter your email to join waitlist',
11
11
  soon: 'Soon',
12
+ launch: 'Launch',
13
+ network: 'Network',
14
+ skipToContent: 'Skip to content',
12
15
  localeSelectorAriaLabel: 'Select language',
13
16
  },
14
17
  footer: {
@@ -70,6 +73,9 @@ export const navigationContent = {
70
73
  joinWaitlist: 'Join Waitlist',
71
74
  waitlistEmailCta: 'Enter your email to join waitlist',
72
75
  soon: 'Soon',
76
+ launch: 'Launch',
77
+ network: 'Network',
78
+ skipToContent: 'Skip to content',
73
79
  localeSelectorAriaLabel: 'Select language',
74
80
  },
75
81
  footer: {
@@ -131,6 +137,9 @@ export const navigationContent = {
131
137
  joinWaitlist: 'Join Waitlist',
132
138
  waitlistEmailCta: 'Enter your email to join waitlist',
133
139
  soon: 'Soon',
140
+ launch: 'Launch',
141
+ network: 'Network',
142
+ skipToContent: 'Skip to content',
134
143
  localeSelectorAriaLabel: 'Select language',
135
144
  },
136
145
  footer: {
@@ -192,6 +201,9 @@ export const navigationContent = {
192
201
  joinWaitlist: 'Join Waitlist',
193
202
  waitlistEmailCta: 'Enter your email to join waitlist',
194
203
  soon: 'Soon',
204
+ launch: 'Launch',
205
+ network: 'Network',
206
+ skipToContent: 'Skip to content',
195
207
  localeSelectorAriaLabel: 'Select language',
196
208
  },
197
209
  footer: {
@@ -253,6 +265,9 @@ export const navigationContent = {
253
265
  joinWaitlist: 'Entrar na lista',
254
266
  waitlistEmailCta: 'Digite seu email para entrar na lista',
255
267
  soon: 'Em breve',
268
+ launch: 'Launch',
269
+ network: 'Rede',
270
+ skipToContent: 'Pular para o conteúdo',
256
271
  localeSelectorAriaLabel: 'Selecionar idioma',
257
272
  },
258
273
  footer: {
@@ -314,6 +329,9 @@ export const navigationContent = {
314
329
  joinWaitlist: 'Gabung Daftar Tunggu',
315
330
  waitlistEmailCta: 'Masukkan email Anda',
316
331
  soon: 'segera',
332
+ launch: 'Launch',
333
+ network: 'Jaringan',
334
+ skipToContent: 'Langsung ke konten',
317
335
  localeSelectorAriaLabel: 'Pilih bahasa',
318
336
  },
319
337
  footer: {
@@ -375,6 +393,9 @@ export const navigationContent = {
375
393
  joinWaitlist: '대기 명단 등록',
376
394
  waitlistEmailCta: '이메일을 입력하세요',
377
395
  soon: '곧 출시',
396
+ launch: 'Launch',
397
+ network: '네트워크',
398
+ skipToContent: '본문으로 건너뛰기',
378
399
  localeSelectorAriaLabel: '언어 선택',
379
400
  },
380
401
  footer: {
@@ -436,6 +457,9 @@ export const navigationContent = {
436
457
  joinWaitlist: 'Únete a la lista de espera',
437
458
  waitlistEmailCta: 'Ingresa tu correo electrónico para unirte a la lista de espera',
438
459
  soon: 'pronto',
460
+ launch: 'Launch',
461
+ network: 'Red',
462
+ skipToContent: 'Saltar al contenido',
439
463
  localeSelectorAriaLabel: 'Seleccionar idioma',
440
464
  },
441
465
  footer: {
@@ -497,6 +521,9 @@ export const navigationContent = {
497
521
  joinWaitlist: 'Tham gia danh sách chờ',
498
522
  waitlistEmailCta: 'Nhập email của bạn',
499
523
  soon: 'sắp ra mắt',
524
+ launch: 'Launch',
525
+ network: 'Mạng',
526
+ skipToContent: 'Chuyển đến nội dung',
500
527
  localeSelectorAriaLabel: 'Chọn ngôn ngữ',
501
528
  },
502
529
  footer: {
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@cronos-labs/ui",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
+ "packageManager": "npm@11.19.0",
4
5
  "description": "Shared Header, Footer, Seo, locale and theme primitives for Cronos web properties.",
5
6
  "license": "UNLICENSED",
6
7
  "type": "module",