@cavebatsofware/riposte-pickers 0.1.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.
- package/LICENSE +674 -0
- package/README.md +214 -0
- package/dist/chunk-6FAEMGAR.js +93 -0
- package/dist/chunk-6FAEMGAR.js.map +1 -0
- package/dist/chunk-6OZDKKEP.cjs +95 -0
- package/dist/chunk-6OZDKKEP.cjs.map +1 -0
- package/dist/chunk-7JL223UJ.cjs +84 -0
- package/dist/chunk-7JL223UJ.cjs.map +1 -0
- package/dist/chunk-A4OVAXLP.js +261 -0
- package/dist/chunk-A4OVAXLP.js.map +1 -0
- package/dist/chunk-ATS6MI5Q.js +3 -0
- package/dist/chunk-ATS6MI5Q.js.map +1 -0
- package/dist/chunk-GDYHLOSQ.cjs +268 -0
- package/dist/chunk-GDYHLOSQ.cjs.map +1 -0
- package/dist/chunk-IWUGV7HL.js +113 -0
- package/dist/chunk-IWUGV7HL.js.map +1 -0
- package/dist/chunk-LIGL56YJ.cjs +116 -0
- package/dist/chunk-LIGL56YJ.cjs.map +1 -0
- package/dist/chunk-U73YJG4C.cjs +4 -0
- package/dist/chunk-U73YJG4C.cjs.map +1 -0
- package/dist/chunk-XWM3AYYR.js +82 -0
- package/dist/chunk-XWM3AYYR.js.map +1 -0
- package/dist/i18n/index.cjs +192 -0
- package/dist/i18n/index.cjs.map +1 -0
- package/dist/i18n/index.d.cts +156 -0
- package/dist/i18n/index.d.ts +156 -0
- package/dist/i18n/index.js +189 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.cjs +52 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/language.cjs +18 -0
- package/dist/language.cjs.map +1 -0
- package/dist/language.d.cts +39 -0
- package/dist/language.d.ts +39 -0
- package/dist/language.js +5 -0
- package/dist/language.js.map +1 -0
- package/dist/shared.cjs +18 -0
- package/dist/shared.cjs.map +1 -0
- package/dist/shared.d.cts +29 -0
- package/dist/shared.d.ts +29 -0
- package/dist/shared.js +5 -0
- package/dist/shared.js.map +1 -0
- package/dist/theme.cjs +33 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.cts +54 -0
- package/dist/theme.d.ts +54 -0
- package/dist/theme.js +4 -0
- package/dist/theme.js.map +1 -0
- package/package.json +97 -0
- package/styles/index.css +3 -0
- package/styles/language.css +89 -0
- package/styles/palette.css +614 -0
- package/styles/picker.css +139 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface Language {
|
|
4
|
+
/** Base language code (no region subtag), e.g. `en`. Passed to i18next. */
|
|
5
|
+
code: string;
|
|
6
|
+
/**
|
|
7
|
+
* Display name written in the language's own script (e.g. `Deutsch`,
|
|
8
|
+
* `中文`). Shown verbatim in the list so a reader recognizes their own
|
|
9
|
+
* language without a translation chain.
|
|
10
|
+
*/
|
|
11
|
+
nativeName: string;
|
|
12
|
+
}
|
|
13
|
+
declare const DEFAULT_LANGUAGES: Language[];
|
|
14
|
+
|
|
15
|
+
interface LanguagePickerProps {
|
|
16
|
+
/**
|
|
17
|
+
* `popover` (default): a globe-icon button in a header that opens a
|
|
18
|
+
* dropdown of languages. `inline`: the list rendered directly, for use
|
|
19
|
+
* inside a drawer.
|
|
20
|
+
*/
|
|
21
|
+
variant?: "popover" | "inline";
|
|
22
|
+
/**
|
|
23
|
+
* i18next namespace holding the `language.*` keys. Defaults to `common`.
|
|
24
|
+
* Merge the package's `languageResources` into this namespace.
|
|
25
|
+
*/
|
|
26
|
+
namespace?: string;
|
|
27
|
+
/** Catalog of selectable languages. Defaults to the bundled five. */
|
|
28
|
+
languages?: Language[];
|
|
29
|
+
/**
|
|
30
|
+
* Optional side effect fired after a successful switch, e.g. persisting the
|
|
31
|
+
* choice server-side. Receives the chosen base code. Rejections are caught
|
|
32
|
+
* so they never undo the local switch; handle errors inside the callback if
|
|
33
|
+
* you need to surface them.
|
|
34
|
+
*/
|
|
35
|
+
onChange?: (code: string) => void | Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
declare function LanguagePicker({ variant, namespace, languages, onChange, }: LanguagePickerProps): React.JSX.Element;
|
|
38
|
+
|
|
39
|
+
export { DEFAULT_LANGUAGES, type Language, LanguagePicker, type LanguagePickerProps };
|
package/dist/language.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"language.js"}
|
package/dist/shared.cjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('./chunk-U73YJG4C.cjs');
|
|
4
|
+
var chunk7JL223UJ_cjs = require('./chunk-7JL223UJ.cjs');
|
|
5
|
+
var chunk6OZDKKEP_cjs = require('./chunk-6OZDKKEP.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, "useRovingFocus", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function () { return chunk7JL223UJ_cjs.useRovingFocus_default; }
|
|
12
|
+
});
|
|
13
|
+
Object.defineProperty(exports, "PopoverPicker", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return chunk6OZDKKEP_cjs.PopoverPicker; }
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=shared.cjs.map
|
|
18
|
+
//# sourceMappingURL=shared.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"shared.cjs"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React__default, { RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
interface PopoverPickerProps {
|
|
4
|
+
variant?: "popover" | "inline";
|
|
5
|
+
open: boolean;
|
|
6
|
+
onOpenChange: (v: boolean) => void;
|
|
7
|
+
className: string;
|
|
8
|
+
toggleAriaLabel: string;
|
|
9
|
+
toggleIcon: React__default.ReactNode;
|
|
10
|
+
popoverAriaLabel: string;
|
|
11
|
+
popoverRef?: React__default.Ref<HTMLDivElement> | null;
|
|
12
|
+
inlineRef?: React__default.Ref<HTMLDivElement> | null;
|
|
13
|
+
children: React__default.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
declare function PopoverPicker({ variant, open, onOpenChange, className, toggleAriaLabel, toggleIcon, popoverAriaLabel, popoverRef, inlineRef, children, }: PopoverPickerProps): React__default.JSX.Element;
|
|
16
|
+
|
|
17
|
+
interface RovingFocusOptions {
|
|
18
|
+
/** CSS selector for the navigable items. Defaults to the ARIA menu roles. */
|
|
19
|
+
selector?: string;
|
|
20
|
+
/** Arrow-key axis. Defaults to vertical. */
|
|
21
|
+
orientation?: "vertical" | "horizontal";
|
|
22
|
+
/** Wrap from the last item back to the first (and vice versa). Default true. */
|
|
23
|
+
wrap?: boolean;
|
|
24
|
+
/** Move DOM focus into the list on activation. Default true. */
|
|
25
|
+
autoFocus?: boolean;
|
|
26
|
+
}
|
|
27
|
+
declare function useRovingFocus(containerRef: RefObject<HTMLElement | null>, active: boolean, { selector, orientation, wrap, autoFocus, }?: RovingFocusOptions): void;
|
|
28
|
+
|
|
29
|
+
export { PopoverPicker, type PopoverPickerProps, type RovingFocusOptions, useRovingFocus };
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React__default, { RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
interface PopoverPickerProps {
|
|
4
|
+
variant?: "popover" | "inline";
|
|
5
|
+
open: boolean;
|
|
6
|
+
onOpenChange: (v: boolean) => void;
|
|
7
|
+
className: string;
|
|
8
|
+
toggleAriaLabel: string;
|
|
9
|
+
toggleIcon: React__default.ReactNode;
|
|
10
|
+
popoverAriaLabel: string;
|
|
11
|
+
popoverRef?: React__default.Ref<HTMLDivElement> | null;
|
|
12
|
+
inlineRef?: React__default.Ref<HTMLDivElement> | null;
|
|
13
|
+
children: React__default.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
declare function PopoverPicker({ variant, open, onOpenChange, className, toggleAriaLabel, toggleIcon, popoverAriaLabel, popoverRef, inlineRef, children, }: PopoverPickerProps): React__default.JSX.Element;
|
|
16
|
+
|
|
17
|
+
interface RovingFocusOptions {
|
|
18
|
+
/** CSS selector for the navigable items. Defaults to the ARIA menu roles. */
|
|
19
|
+
selector?: string;
|
|
20
|
+
/** Arrow-key axis. Defaults to vertical. */
|
|
21
|
+
orientation?: "vertical" | "horizontal";
|
|
22
|
+
/** Wrap from the last item back to the first (and vice versa). Default true. */
|
|
23
|
+
wrap?: boolean;
|
|
24
|
+
/** Move DOM focus into the list on activation. Default true. */
|
|
25
|
+
autoFocus?: boolean;
|
|
26
|
+
}
|
|
27
|
+
declare function useRovingFocus(containerRef: RefObject<HTMLElement | null>, active: boolean, { selector, orientation, wrap, autoFocus, }?: RovingFocusOptions): void;
|
|
28
|
+
|
|
29
|
+
export { PopoverPicker, type PopoverPickerProps, type RovingFocusOptions, useRovingFocus };
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"shared.js"}
|
package/dist/theme.cjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkGDYHLOSQ_cjs = require('./chunk-GDYHLOSQ.cjs');
|
|
4
|
+
require('./chunk-6OZDKKEP.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(exports, "COLORWAYS", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return chunkGDYHLOSQ_cjs.COLORWAYS; }
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_COLORWAY", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkGDYHLOSQ_cjs.DEFAULT_COLORWAY; }
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(exports, "DEFAULT_STORAGE_KEY", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return chunkGDYHLOSQ_cjs.DEFAULT_STORAGE_KEY; }
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(exports, "ThemePicker", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return chunkGDYHLOSQ_cjs.ThemePicker; }
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "ThemeProvider", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () { return chunkGDYHLOSQ_cjs.ThemeProvider; }
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports, "useTheme", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get: function () { return chunkGDYHLOSQ_cjs.useTheme; }
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=theme.cjs.map
|
|
33
|
+
//# sourceMappingURL=theme.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"theme.cjs"}
|
package/dist/theme.d.cts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface Colorway {
|
|
5
|
+
/** Stable id; must match a `[data-theme="<id>"]` block in your CSS. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Fallback display label (i18n catalog labels take precedence in the UI). */
|
|
8
|
+
label: string;
|
|
9
|
+
/** CSS `background` value for the picker swatch (color or gradient). */
|
|
10
|
+
swatch: string;
|
|
11
|
+
}
|
|
12
|
+
type ThemeMode = "light" | "dark";
|
|
13
|
+
interface ThemeContextValue {
|
|
14
|
+
/** Resolved theme id of record, e.g. `forest` or `forest-dark`. */
|
|
15
|
+
theme: string;
|
|
16
|
+
/** Set the theme by id; ignored if the id is not in the catalog. */
|
|
17
|
+
setTheme: (id: string) => void;
|
|
18
|
+
/** The active catalog. */
|
|
19
|
+
colorways: Colorway[];
|
|
20
|
+
/** Derived light/dark mode for the current theme. */
|
|
21
|
+
mode: ThemeMode;
|
|
22
|
+
/** Flip just the mode, keeping the current colorway. */
|
|
23
|
+
setMode: (mode: ThemeMode) => void;
|
|
24
|
+
}
|
|
25
|
+
declare const COLORWAYS: Colorway[];
|
|
26
|
+
declare const DEFAULT_COLORWAY = "forest";
|
|
27
|
+
declare const DEFAULT_STORAGE_KEY = "rs_theme_v1";
|
|
28
|
+
declare function useTheme(): ThemeContextValue;
|
|
29
|
+
interface ThemeProviderProps {
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
/** Colorway catalog. Defaults to the bundled riposte `COLORWAYS`. */
|
|
32
|
+
colorways?: Colorway[];
|
|
33
|
+
/** Colorway used when no choice is stored. Defaults to `forest`. */
|
|
34
|
+
defaultColorway?: string;
|
|
35
|
+
/** localStorage key for the persisted choice. Defaults to `rs_theme_v1`. */
|
|
36
|
+
storageKey?: string;
|
|
37
|
+
}
|
|
38
|
+
declare function ThemeProvider({ children, colorways, defaultColorway, storageKey, }: ThemeProviderProps): React.JSX.Element;
|
|
39
|
+
|
|
40
|
+
interface ThemePickerProps {
|
|
41
|
+
/**
|
|
42
|
+
* `popover` (default): round icon button in a header that opens a popover
|
|
43
|
+
* grid. `inline`: the grid rendered directly, for use inside a drawer.
|
|
44
|
+
*/
|
|
45
|
+
variant?: "popover" | "inline";
|
|
46
|
+
/**
|
|
47
|
+
* i18next namespace holding the `theme.*` keys. Defaults to `common`.
|
|
48
|
+
* Merge the package's `themeResources` into this namespace.
|
|
49
|
+
*/
|
|
50
|
+
namespace?: string;
|
|
51
|
+
}
|
|
52
|
+
declare function ThemePicker({ variant, namespace }: ThemePickerProps): React.JSX.Element;
|
|
53
|
+
|
|
54
|
+
export { COLORWAYS, type Colorway, DEFAULT_COLORWAY, DEFAULT_STORAGE_KEY, type ThemeContextValue, type ThemeMode, ThemePicker, type ThemePickerProps, ThemeProvider, type ThemeProviderProps, useTheme };
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface Colorway {
|
|
5
|
+
/** Stable id; must match a `[data-theme="<id>"]` block in your CSS. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Fallback display label (i18n catalog labels take precedence in the UI). */
|
|
8
|
+
label: string;
|
|
9
|
+
/** CSS `background` value for the picker swatch (color or gradient). */
|
|
10
|
+
swatch: string;
|
|
11
|
+
}
|
|
12
|
+
type ThemeMode = "light" | "dark";
|
|
13
|
+
interface ThemeContextValue {
|
|
14
|
+
/** Resolved theme id of record, e.g. `forest` or `forest-dark`. */
|
|
15
|
+
theme: string;
|
|
16
|
+
/** Set the theme by id; ignored if the id is not in the catalog. */
|
|
17
|
+
setTheme: (id: string) => void;
|
|
18
|
+
/** The active catalog. */
|
|
19
|
+
colorways: Colorway[];
|
|
20
|
+
/** Derived light/dark mode for the current theme. */
|
|
21
|
+
mode: ThemeMode;
|
|
22
|
+
/** Flip just the mode, keeping the current colorway. */
|
|
23
|
+
setMode: (mode: ThemeMode) => void;
|
|
24
|
+
}
|
|
25
|
+
declare const COLORWAYS: Colorway[];
|
|
26
|
+
declare const DEFAULT_COLORWAY = "forest";
|
|
27
|
+
declare const DEFAULT_STORAGE_KEY = "rs_theme_v1";
|
|
28
|
+
declare function useTheme(): ThemeContextValue;
|
|
29
|
+
interface ThemeProviderProps {
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
/** Colorway catalog. Defaults to the bundled riposte `COLORWAYS`. */
|
|
32
|
+
colorways?: Colorway[];
|
|
33
|
+
/** Colorway used when no choice is stored. Defaults to `forest`. */
|
|
34
|
+
defaultColorway?: string;
|
|
35
|
+
/** localStorage key for the persisted choice. Defaults to `rs_theme_v1`. */
|
|
36
|
+
storageKey?: string;
|
|
37
|
+
}
|
|
38
|
+
declare function ThemeProvider({ children, colorways, defaultColorway, storageKey, }: ThemeProviderProps): React.JSX.Element;
|
|
39
|
+
|
|
40
|
+
interface ThemePickerProps {
|
|
41
|
+
/**
|
|
42
|
+
* `popover` (default): round icon button in a header that opens a popover
|
|
43
|
+
* grid. `inline`: the grid rendered directly, for use inside a drawer.
|
|
44
|
+
*/
|
|
45
|
+
variant?: "popover" | "inline";
|
|
46
|
+
/**
|
|
47
|
+
* i18next namespace holding the `theme.*` keys. Defaults to `common`.
|
|
48
|
+
* Merge the package's `themeResources` into this namespace.
|
|
49
|
+
*/
|
|
50
|
+
namespace?: string;
|
|
51
|
+
}
|
|
52
|
+
declare function ThemePicker({ variant, namespace }: ThemePickerProps): React.JSX.Element;
|
|
53
|
+
|
|
54
|
+
export { COLORWAYS, type Colorway, DEFAULT_COLORWAY, DEFAULT_STORAGE_KEY, type ThemeContextValue, type ThemeMode, ThemePicker, type ThemePickerProps, ThemeProvider, type ThemeProviderProps, useTheme };
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"theme.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cavebatsofware/riposte-pickers",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Accessible React theme and language pickers sharing one popover/roving-focus chassis, with a localStorage-backed theme engine. Extracted from riposte-social.",
|
|
5
|
+
"license": "GPL-3.0-only",
|
|
6
|
+
"author": "Grant DeFayette <grant@cavebatsofware.com>",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/cavebatsofware/riposte-pickers.git"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": [
|
|
13
|
+
"*.css"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"styles"
|
|
18
|
+
],
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/index.d.cts",
|
|
27
|
+
"default": "./dist/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./theme": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/theme.d.ts",
|
|
33
|
+
"default": "./dist/theme.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/theme.d.cts",
|
|
37
|
+
"default": "./dist/theme.cjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./language": {
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/language.d.ts",
|
|
43
|
+
"default": "./dist/language.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/language.d.cts",
|
|
47
|
+
"default": "./dist/language.cjs"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"./shared": {
|
|
51
|
+
"import": {
|
|
52
|
+
"types": "./dist/shared.d.ts",
|
|
53
|
+
"default": "./dist/shared.js"
|
|
54
|
+
},
|
|
55
|
+
"require": {
|
|
56
|
+
"types": "./dist/shared.d.cts",
|
|
57
|
+
"default": "./dist/shared.cjs"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"./i18n": {
|
|
61
|
+
"import": {
|
|
62
|
+
"types": "./dist/i18n/index.d.ts",
|
|
63
|
+
"default": "./dist/i18n/index.js"
|
|
64
|
+
},
|
|
65
|
+
"require": {
|
|
66
|
+
"types": "./dist/i18n/index.d.cts",
|
|
67
|
+
"default": "./dist/i18n/index.cjs"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"./styles": "./styles/index.css",
|
|
71
|
+
"./styles/palette.css": "./styles/palette.css",
|
|
72
|
+
"./styles/picker.css": "./styles/picker.css",
|
|
73
|
+
"./styles/language.css": "./styles/language.css"
|
|
74
|
+
},
|
|
75
|
+
"main": "./dist/index.cjs",
|
|
76
|
+
"module": "./dist/index.js",
|
|
77
|
+
"types": "./dist/index.d.ts",
|
|
78
|
+
"scripts": {
|
|
79
|
+
"build": "tsup",
|
|
80
|
+
"typecheck": "tsc --noEmit",
|
|
81
|
+
"prepublishOnly": "bun run build"
|
|
82
|
+
},
|
|
83
|
+
"peerDependencies": {
|
|
84
|
+
"react": ">=18",
|
|
85
|
+
"react-dom": ">=18",
|
|
86
|
+
"react-i18next": ">=13"
|
|
87
|
+
},
|
|
88
|
+
"devDependencies": {
|
|
89
|
+
"@types/react": "^19.0.0",
|
|
90
|
+
"@types/react-dom": "^19.0.0",
|
|
91
|
+
"react": "^19.0.0",
|
|
92
|
+
"react-dom": "^19.0.0",
|
|
93
|
+
"react-i18next": "^17.0.0",
|
|
94
|
+
"tsup": "^8.3.0",
|
|
95
|
+
"typescript": "^5.6.0"
|
|
96
|
+
}
|
|
97
|
+
}
|
package/styles/index.css
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
Language picker
|
|
3
|
+
Globe-icon toggle that opens a list of supported languages, parallel to the
|
|
4
|
+
theme picker and meant for a header slot. The active language gets a check;
|
|
5
|
+
native names render in their own scripts (中文, etc.) so users recognize
|
|
6
|
+
their language at a glance without a translation chain. Consumes the shared
|
|
7
|
+
design tokens from palette.css.
|
|
8
|
+
========================================================================== */
|
|
9
|
+
.language-picker {
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.language-picker-toggle {
|
|
14
|
+
width: 44px;
|
|
15
|
+
height: 44px;
|
|
16
|
+
border-radius: 999px;
|
|
17
|
+
background-color: var(--color-surface);
|
|
18
|
+
border: 1px solid var(--color-border);
|
|
19
|
+
color: var(--color-text);
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
box-shadow: var(--shadow-popover);
|
|
25
|
+
transition: background-color 0.15s, color 0.15s;
|
|
26
|
+
}
|
|
27
|
+
.language-picker-toggle:hover {
|
|
28
|
+
color: var(--color-primary);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.language-picker-popover {
|
|
32
|
+
position: absolute;
|
|
33
|
+
top: calc(100% + var(--spacing-2));
|
|
34
|
+
right: 0;
|
|
35
|
+
background-color: var(--color-surface);
|
|
36
|
+
border: 1px solid var(--color-border);
|
|
37
|
+
border-radius: var(--radius-md);
|
|
38
|
+
padding: var(--spacing-2);
|
|
39
|
+
min-width: 200px;
|
|
40
|
+
box-shadow: var(--shadow-popover);
|
|
41
|
+
z-index: 35;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.language-picker-title {
|
|
45
|
+
font-size: var(--font-size-xs);
|
|
46
|
+
text-transform: uppercase;
|
|
47
|
+
letter-spacing: 0.08em;
|
|
48
|
+
color: var(--color-muted);
|
|
49
|
+
margin-bottom: var(--spacing-2);
|
|
50
|
+
padding: 0 var(--spacing-2);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.language-picker-list {
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
gap: 2px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.language-picker-item {
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: space-between;
|
|
63
|
+
gap: var(--spacing-2);
|
|
64
|
+
padding: var(--spacing-2) var(--spacing-3);
|
|
65
|
+
background: transparent;
|
|
66
|
+
border: none;
|
|
67
|
+
border-radius: var(--radius-sm);
|
|
68
|
+
color: var(--color-text);
|
|
69
|
+
font-family: inherit;
|
|
70
|
+
font-size: var(--font-size-sm);
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
text-align: left;
|
|
73
|
+
}
|
|
74
|
+
.language-picker-item:hover {
|
|
75
|
+
background: var(--color-overlay);
|
|
76
|
+
}
|
|
77
|
+
.language-picker-item.active {
|
|
78
|
+
font-weight: 600;
|
|
79
|
+
color: var(--color-primary);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.language-picker-name {
|
|
83
|
+
flex: 1 1 auto;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.language-picker-check {
|
|
87
|
+
flex: 0 0 auto;
|
|
88
|
+
color: var(--color-primary);
|
|
89
|
+
}
|