@dbcdk/react-components 0.0.174 → 0.0.176
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/README.md +17 -18
- package/dist/components/filter-field/FilterField.module.css +2 -2
- package/dist/components/forms/file-upload/FileUpload.module.css +3 -3
- package/dist/components/forms/form-select/FormSelect.module.css +1 -1
- package/dist/components/forms/input/Input.module.css +8 -8
- package/dist/components/forms/text-area/Textarea.module.css +2 -1
- package/dist/components/nav-bar/NavBar.module.css +1 -1
- package/dist/components/theme-button/ThemeButton.cjs +4 -15
- package/dist/components/theme-button/ThemeButton.d.ts +3 -4
- package/dist/components/theme-button/ThemeButton.js +4 -15
- package/dist/components/theme-script/ThemeScript.cjs +23 -16
- package/dist/components/theme-script/ThemeScript.d.ts +2 -6
- package/dist/components/theme-script/ThemeScript.js +24 -17
- package/dist/hooks/usePersistentState.cjs +6 -1
- package/dist/hooks/usePersistentState.d.ts +1 -1
- package/dist/hooks/usePersistentState.js +6 -1
- package/dist/hooks/useTheme.cjs +33 -96
- package/dist/hooks/useTheme.d.ts +3 -10
- package/dist/hooks/useTheme.js +34 -97
- package/dist/styles/themes/apply-product-theme.cjs +20 -0
- package/dist/styles/themes/apply-product-theme.d.ts +3 -0
- package/dist/styles/themes/apply-product-theme.js +18 -0
- package/dist/styles/themes/dbc/colors.css +2 -1
- package/dist/styles/themes/product-theme-tokens.cjs +39 -0
- package/dist/styles/themes/product-theme-tokens.d.ts +3 -0
- package/dist/styles/themes/product-theme-tokens.js +37 -0
- package/dist/styles/themes/product-themes.cjs +143 -0
- package/dist/styles/themes/product-themes.d.ts +11 -0
- package/dist/styles/themes/product-themes.js +140 -0
- package/dist/styles/themes/types.cjs +3 -2
- package/dist/styles/themes/types.d.ts +1 -13
- package/dist/styles/themes/types.js +3 -2
- package/dist/utils/sessionStorage.utils.cjs +53 -0
- package/dist/utils/sessionStorage.utils.d.ts +19 -0
- package/dist/utils/sessionStorage.utils.js +49 -0
- package/package.json +1 -1
- package/dist/styles/themes/filmstriben/theme.css +0 -55
- package/dist/themes/filmstriben.css +0 -4
- package/dist/types/assets.d.cjs +0 -2
- package/dist/types/assets.d.js +0 -1
package/README.md
CHANGED
|
@@ -44,35 +44,30 @@ import '@dbcdk/react-components/styles.css'
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
### 3) Add
|
|
47
|
+
### 3) Add `ThemeScript` in your root layout (Next.js example)
|
|
48
48
|
|
|
49
|
-
The library
|
|
50
|
-
|
|
49
|
+
The library's shared CSS foundation is still imported normally, but
|
|
50
|
+
product-theme switching is handled by `ThemeScript` + `useTheme()`.
|
|
51
|
+
`ThemeScript` restores the persisted color scheme and product theme before
|
|
52
|
+
paint, so the app avoids a flash of the wrong theme on first load.
|
|
51
53
|
|
|
52
54
|
```tsx
|
|
53
55
|
import { ReactNode } from 'react'
|
|
54
|
-
import { cookies } from 'next/headers'
|
|
55
56
|
|
|
56
|
-
import {
|
|
57
|
+
import { ThemeScript } from '@dbcdk/react-components'
|
|
57
58
|
import '@dbcdk/react-components/styles.css'
|
|
59
|
+
import '@dbcdk/react-components/themes/dbc.css'
|
|
58
60
|
|
|
59
|
-
export default
|
|
60
|
-
const cookieStore = await cookies()
|
|
61
|
-
const themeId = cookieStore.get('dbc_theme')?.value || 'light'
|
|
62
|
-
|
|
61
|
+
export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
|
|
63
62
|
return (
|
|
64
63
|
<html lang="da">
|
|
65
|
-
<head>
|
|
66
|
-
<link id={LINK_ID} rel="stylesheet" href={`/themes/${themeId}.css`} />
|
|
67
|
-
</head>
|
|
64
|
+
<head><ThemeScript defaultTheme="dbc" /></head>
|
|
68
65
|
<body>{children}</body>
|
|
69
66
|
</html>
|
|
70
67
|
)
|
|
71
68
|
}
|
|
72
69
|
```
|
|
73
70
|
|
|
74
|
-
> Theme files are expected to be served from `/themes/<theme>.css`.
|
|
75
|
-
|
|
76
71
|
---
|
|
77
72
|
|
|
78
73
|
### 4) Switching theme in your application
|
|
@@ -86,19 +81,23 @@ import { AppHeader, Button, useTheme } from '@dbcdk/react-components'
|
|
|
86
81
|
import { Moon, Sun } from 'lucide-react'
|
|
87
82
|
|
|
88
83
|
export default function Header() {
|
|
89
|
-
const { theme, switchTheme } = useTheme()
|
|
84
|
+
const { theme, switchTheme } = useTheme({ defaultTheme: 'dbc' })
|
|
90
85
|
|
|
91
86
|
return (
|
|
92
87
|
<AppHeader>
|
|
93
|
-
<Button
|
|
94
|
-
|
|
88
|
+
<Button
|
|
89
|
+
variant="outlined"
|
|
90
|
+
onClick={() => switchTheme(theme === 'dbc' ? 'filmstriben' : 'dbc')}
|
|
91
|
+
>
|
|
92
|
+
{theme === 'dbc' ? <Moon /> : <Sun />}
|
|
95
93
|
</Button>
|
|
96
94
|
</AppHeader>
|
|
97
95
|
)
|
|
98
96
|
}
|
|
99
97
|
```
|
|
100
98
|
|
|
101
|
-
The hook updates
|
|
99
|
+
The hook updates `data-product-theme`, applies the selected product theme's
|
|
100
|
+
token overrides, and persists the selection.
|
|
102
101
|
|
|
103
102
|
---
|
|
104
103
|
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
z-index: 1;
|
|
168
168
|
color: var(--color-fg-default);
|
|
169
169
|
background: color-mix(in srgb, var(--color-bg-hover-subtle) 55%, transparent);
|
|
170
|
-
box-shadow: inset 0 0 0 1px var(--color-
|
|
170
|
+
box-shadow: inset 0 0 0 1px var(--color-field-focus);
|
|
171
171
|
outline: none;
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
.valueWrapper:focus-within {
|
|
201
|
-
box-shadow: inset 0 0 0 1px var(--color-
|
|
201
|
+
box-shadow: inset 0 0 0 1px var(--color-field-focus);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
.invalid .valueWrapper:focus-within {
|
|
@@ -26,15 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
.dropzone:hover:not(.disabled) {
|
|
28
28
|
background-color: var(--color-bg-selected);
|
|
29
|
-
border-color: var(--color-
|
|
29
|
+
border-color: var(--color-field-focus);
|
|
30
30
|
color: var(--color-fg-default);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
.dragging {
|
|
34
34
|
background-color: var(--color-bg-selected);
|
|
35
|
-
border-color: var(--color-
|
|
35
|
+
border-color: var(--color-field-focus);
|
|
36
36
|
color: var(--color-fg-default);
|
|
37
|
-
box-shadow: inset 0 0 0 1px var(--color-
|
|
37
|
+
box-shadow: inset 0 0 0 1px var(--color-field-focus);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
.hasError {
|
|
@@ -106,8 +106,8 @@
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
.outlined:focus-within:not([aria-disabled='true']) {
|
|
109
|
-
border-color: var(--color-
|
|
110
|
-
box-shadow: inset 0 0 0 1px var(--color-
|
|
109
|
+
border-color: var(--color-field-focus);
|
|
110
|
+
box-shadow: inset 0 0 0 1px var(--color-field-focus);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
.surface {
|
|
@@ -122,8 +122,8 @@
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
.surface:focus-within:not([aria-disabled='true']) {
|
|
125
|
-
border-color: var(--color-
|
|
126
|
-
box-shadow: inset 0 0 0 1px var(--color-
|
|
125
|
+
border-color: var(--color-field-focus);
|
|
126
|
+
box-shadow: inset 0 0 0 1px var(--color-field-focus);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/* Old filled/tinted behavior, now renamed subtle */
|
|
@@ -138,8 +138,8 @@
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
.subtle:focus-within:not([aria-disabled='true']) {
|
|
141
|
-
border-color: var(--color-
|
|
142
|
-
box-shadow: inset 0 0 0 1px var(--color-
|
|
141
|
+
border-color: var(--color-field-focus);
|
|
142
|
+
box-shadow: inset 0 0 0 1px var(--color-field-focus);
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
.embedded {
|
|
@@ -176,11 +176,11 @@
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
.standalone:focus-within:not([aria-disabled='true']) {
|
|
179
|
-
border-color: var(--color-
|
|
179
|
+
border-color: var(--color-field-focus);
|
|
180
180
|
box-shadow:
|
|
181
181
|
var(--shadow-xs),
|
|
182
182
|
var(--shadow-md),
|
|
183
|
-
inset 0 0 0 1px var(--color-
|
|
183
|
+
inset 0 0 0 1px var(--color-field-focus);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
/* Ghost field for use inside/near AppHeader — only meaningful there */
|
|
@@ -9,11 +9,8 @@ var Popover = require('../../components/popover/Popover');
|
|
|
9
9
|
var useTheme = require('../../hooks/useTheme');
|
|
10
10
|
var types = require('../../styles/themes/types');
|
|
11
11
|
|
|
12
|
-
function ThemeMenuSection({ themes
|
|
13
|
-
const { theme, switchTheme } = useTheme.useTheme({
|
|
14
|
-
defaultTheme: themes[0],
|
|
15
|
-
hrefs
|
|
16
|
-
});
|
|
12
|
+
function ThemeMenuSection({ themes }) {
|
|
13
|
+
const { theme, switchTheme } = useTheme.useTheme({ defaultTheme: themes[0] });
|
|
17
14
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
18
15
|
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Header, { children: "Tema" }),
|
|
19
16
|
themes.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -29,16 +26,8 @@ function ThemeMenuSection({ themes, hrefs }) {
|
|
|
29
26
|
))
|
|
30
27
|
] });
|
|
31
28
|
}
|
|
32
|
-
function ThemeButton({
|
|
33
|
-
themes
|
|
34
|
-
hrefs,
|
|
35
|
-
size,
|
|
36
|
-
variant = "outlined"
|
|
37
|
-
}) {
|
|
38
|
-
const { theme, switchTheme } = useTheme.useTheme({
|
|
39
|
-
defaultTheme: themes[0],
|
|
40
|
-
hrefs
|
|
41
|
-
});
|
|
29
|
+
function ThemeButton({ themes, size, variant = "outlined" }) {
|
|
30
|
+
const { theme, switchTheme } = useTheme.useTheme({ defaultTheme: themes[0] });
|
|
42
31
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43
32
|
Popover.Popover,
|
|
44
33
|
{
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { JSX } from 'react';
|
|
2
2
|
import type { ButtonSize, ButtonVariant } from '../../components/button/Button';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ThemeId } from '../../hooks/useTheme';
|
|
4
4
|
export interface ThemeMenuSectionProps {
|
|
5
5
|
/** Every theme to offer as an option. The first entry is treated as the default. */
|
|
6
6
|
themes: readonly ThemeId[];
|
|
7
|
-
hrefs?: ThemeHrefs;
|
|
8
7
|
}
|
|
9
8
|
export interface ThemeButtonProps extends ThemeMenuSectionProps {
|
|
10
9
|
size?: ButtonSize;
|
|
11
10
|
variant?: ButtonVariant;
|
|
12
11
|
}
|
|
13
|
-
export declare function ThemeMenuSection({ themes
|
|
14
|
-
export declare function ThemeButton({ themes,
|
|
12
|
+
export declare function ThemeMenuSection({ themes }: ThemeMenuSectionProps): JSX.Element;
|
|
13
|
+
export declare function ThemeButton({ themes, size, variant }: ThemeButtonProps): JSX.Element;
|
|
@@ -7,11 +7,8 @@ import { Popover } from '../../components/popover/Popover';
|
|
|
7
7
|
import { useTheme } from '../../hooks/useTheme';
|
|
8
8
|
import { THEME_LABELS } from '../../styles/themes/types';
|
|
9
9
|
|
|
10
|
-
function ThemeMenuSection({ themes
|
|
11
|
-
const { theme, switchTheme } = useTheme({
|
|
12
|
-
defaultTheme: themes[0],
|
|
13
|
-
hrefs
|
|
14
|
-
});
|
|
10
|
+
function ThemeMenuSection({ themes }) {
|
|
11
|
+
const { theme, switchTheme } = useTheme({ defaultTheme: themes[0] });
|
|
15
12
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16
13
|
/* @__PURE__ */ jsx(Menu.Header, { children: "Tema" }),
|
|
17
14
|
themes.map((id) => /* @__PURE__ */ jsx(
|
|
@@ -27,16 +24,8 @@ function ThemeMenuSection({ themes, hrefs }) {
|
|
|
27
24
|
))
|
|
28
25
|
] });
|
|
29
26
|
}
|
|
30
|
-
function ThemeButton({
|
|
31
|
-
themes
|
|
32
|
-
hrefs,
|
|
33
|
-
size,
|
|
34
|
-
variant = "outlined"
|
|
35
|
-
}) {
|
|
36
|
-
const { theme, switchTheme } = useTheme({
|
|
37
|
-
defaultTheme: themes[0],
|
|
38
|
-
hrefs
|
|
39
|
-
});
|
|
27
|
+
function ThemeButton({ themes, size, variant = "outlined" }) {
|
|
28
|
+
const { theme, switchTheme } = useTheme({ defaultTheme: themes[0] });
|
|
40
29
|
return /* @__PURE__ */ jsx(
|
|
41
30
|
Popover,
|
|
42
31
|
{
|
|
@@ -1,30 +1,39 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var productThemes = require('../../styles/themes/product-themes');
|
|
4
5
|
var colorScheme_constants = require('../../utils/color-scheme.constants');
|
|
5
6
|
var theme_constants = require('../../utils/theme.constants');
|
|
6
7
|
|
|
7
|
-
function buildInitScript(defaultColorScheme,
|
|
8
|
-
const
|
|
9
|
-
for (const [id, href] of Object.entries(hrefs)) {
|
|
10
|
-
if (id !== defaultTheme && href) hrefById[id] = href;
|
|
11
|
-
}
|
|
8
|
+
function buildInitScript(defaultColorScheme, defaultTheme, storageKey) {
|
|
9
|
+
const productThemes$1 = JSON.stringify(productThemes.PRODUCT_THEMES);
|
|
12
10
|
const themeBlock = defaultTheme === void 0 ? "" : `try{
|
|
13
11
|
var THEME_KEY=${JSON.stringify(storageKey)};
|
|
14
12
|
var THEME_DEFAULT=${JSON.stringify(defaultTheme)};
|
|
15
|
-
var
|
|
16
|
-
var LINK_ID=${JSON.stringify(linkId)};
|
|
13
|
+
var PRODUCT_THEMES=${productThemes$1};
|
|
17
14
|
var resolvedTheme=getCookie(THEME_KEY);
|
|
18
15
|
if(!resolvedTheme){try{resolvedTheme=localStorage.getItem(THEME_KEY)}catch(e){}}
|
|
19
16
|
if(!resolvedTheme)resolvedTheme=THEME_DEFAULT;
|
|
20
|
-
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
function applyProductTheme(themeId, scheme){
|
|
18
|
+
var target=document.documentElement;
|
|
19
|
+
var definition=PRODUCT_THEMES[themeId]||{};
|
|
20
|
+
var tokens={};
|
|
21
|
+
var source=scheme==='dark'?definition.dark:definition.light;
|
|
22
|
+
if(definition.base){for(var baseKey in definition.base){tokens[baseKey]=definition.base[baseKey];}}
|
|
23
|
+
if(source){for(var sourceKey in source){tokens[sourceKey]=source[sourceKey];}}
|
|
24
|
+
var knownThemeIds=Object.keys(PRODUCT_THEMES);
|
|
25
|
+
for(var i=0;i<knownThemeIds.length;i++){
|
|
26
|
+
var knownDefinition=PRODUCT_THEMES[knownThemeIds[i]]||{};
|
|
27
|
+
for(var sectionIndex=0;sectionIndex<3;sectionIndex++){
|
|
28
|
+
var section=sectionIndex===0?knownDefinition.base:sectionIndex===1?knownDefinition.light:knownDefinition.dark;
|
|
29
|
+
if(!section)continue;
|
|
30
|
+
for(var clearKey in section){target.style.removeProperty(clearKey);}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for(var token in tokens){target.style.setProperty(token,tokens[token]);}
|
|
26
34
|
}
|
|
27
35
|
document.documentElement.dataset.productTheme=resolvedTheme;
|
|
36
|
+
applyProductTheme(resolvedTheme, document.documentElement.dataset.theme);
|
|
28
37
|
}catch(e){}`;
|
|
29
38
|
return `(function(){
|
|
30
39
|
function getCookie(name){var m=document.cookie.match(new RegExp('(?:^|; )'+name+'=([^;]*)'));return m?decodeURIComponent(m[1]):null}
|
|
@@ -43,15 +52,13 @@ function buildInitScript(defaultColorScheme, hrefs, defaultTheme, linkId, storag
|
|
|
43
52
|
function ThemeScript({
|
|
44
53
|
defaultColorScheme = "system",
|
|
45
54
|
defaultTheme,
|
|
46
|
-
hrefs = {},
|
|
47
|
-
linkId = theme_constants.THEME_LINK_ID,
|
|
48
55
|
storageKey = theme_constants.THEME_STORAGE_KEY
|
|
49
56
|
}) {
|
|
50
57
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
51
58
|
"script",
|
|
52
59
|
{
|
|
53
60
|
dangerouslySetInnerHTML: {
|
|
54
|
-
__html: buildInitScript(defaultColorScheme,
|
|
61
|
+
__html: buildInitScript(defaultColorScheme, defaultTheme, storageKey)
|
|
55
62
|
}
|
|
56
63
|
}
|
|
57
64
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ThemeId } from '../../styles/themes/types';
|
|
2
2
|
import type { ColorScheme } from '../../utils/color-scheme.constants';
|
|
3
3
|
export interface ThemeScriptProps {
|
|
4
4
|
/** Color scheme applied when nothing is stored yet. Defaults to 'system'. */
|
|
@@ -9,10 +9,6 @@ export interface ThemeScriptProps {
|
|
|
9
9
|
* `data-product-theme` handling happens at all in that case.
|
|
10
10
|
*/
|
|
11
11
|
defaultTheme?: ThemeId;
|
|
12
|
-
/** Per-theme CSS URL, for any theme not already loaded some other way. */
|
|
13
|
-
hrefs?: ThemeHrefs;
|
|
14
|
-
/** DOM id for the `<link>` this script (and useTheme) manage. */
|
|
15
|
-
linkId?: string;
|
|
16
12
|
storageKey?: string;
|
|
17
13
|
}
|
|
18
14
|
/**
|
|
@@ -45,4 +41,4 @@ export interface ThemeScriptProps {
|
|
|
45
41
|
* </Head>
|
|
46
42
|
* ```
|
|
47
43
|
*/
|
|
48
|
-
export declare function ThemeScript({ defaultColorScheme, defaultTheme,
|
|
44
|
+
export declare function ThemeScript({ defaultColorScheme, defaultTheme, storageKey, }: ThemeScriptProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { PRODUCT_THEMES } from '../../styles/themes/product-themes';
|
|
2
3
|
import { COLOR_SCHEME_STORAGE_KEY, COLOR_SCHEMES } from '../../utils/color-scheme.constants';
|
|
3
|
-
import {
|
|
4
|
+
import { THEME_STORAGE_KEY } from '../../utils/theme.constants';
|
|
4
5
|
|
|
5
|
-
function buildInitScript(defaultColorScheme,
|
|
6
|
-
const
|
|
7
|
-
for (const [id, href] of Object.entries(hrefs)) {
|
|
8
|
-
if (id !== defaultTheme && href) hrefById[id] = href;
|
|
9
|
-
}
|
|
6
|
+
function buildInitScript(defaultColorScheme, defaultTheme, storageKey) {
|
|
7
|
+
const productThemes = JSON.stringify(PRODUCT_THEMES);
|
|
10
8
|
const themeBlock = defaultTheme === void 0 ? "" : `try{
|
|
11
9
|
var THEME_KEY=${JSON.stringify(storageKey)};
|
|
12
10
|
var THEME_DEFAULT=${JSON.stringify(defaultTheme)};
|
|
13
|
-
var
|
|
14
|
-
var LINK_ID=${JSON.stringify(linkId)};
|
|
11
|
+
var PRODUCT_THEMES=${productThemes};
|
|
15
12
|
var resolvedTheme=getCookie(THEME_KEY);
|
|
16
13
|
if(!resolvedTheme){try{resolvedTheme=localStorage.getItem(THEME_KEY)}catch(e){}}
|
|
17
14
|
if(!resolvedTheme)resolvedTheme=THEME_DEFAULT;
|
|
18
|
-
|
|
19
|
-
var
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
function applyProductTheme(themeId, scheme){
|
|
16
|
+
var target=document.documentElement;
|
|
17
|
+
var definition=PRODUCT_THEMES[themeId]||{};
|
|
18
|
+
var tokens={};
|
|
19
|
+
var source=scheme==='dark'?definition.dark:definition.light;
|
|
20
|
+
if(definition.base){for(var baseKey in definition.base){tokens[baseKey]=definition.base[baseKey];}}
|
|
21
|
+
if(source){for(var sourceKey in source){tokens[sourceKey]=source[sourceKey];}}
|
|
22
|
+
var knownThemeIds=Object.keys(PRODUCT_THEMES);
|
|
23
|
+
for(var i=0;i<knownThemeIds.length;i++){
|
|
24
|
+
var knownDefinition=PRODUCT_THEMES[knownThemeIds[i]]||{};
|
|
25
|
+
for(var sectionIndex=0;sectionIndex<3;sectionIndex++){
|
|
26
|
+
var section=sectionIndex===0?knownDefinition.base:sectionIndex===1?knownDefinition.light:knownDefinition.dark;
|
|
27
|
+
if(!section)continue;
|
|
28
|
+
for(var clearKey in section){target.style.removeProperty(clearKey);}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for(var token in tokens){target.style.setProperty(token,tokens[token]);}
|
|
24
32
|
}
|
|
25
33
|
document.documentElement.dataset.productTheme=resolvedTheme;
|
|
34
|
+
applyProductTheme(resolvedTheme, document.documentElement.dataset.theme);
|
|
26
35
|
}catch(e){}`;
|
|
27
36
|
return `(function(){
|
|
28
37
|
function getCookie(name){var m=document.cookie.match(new RegExp('(?:^|; )'+name+'=([^;]*)'));return m?decodeURIComponent(m[1]):null}
|
|
@@ -41,15 +50,13 @@ function buildInitScript(defaultColorScheme, hrefs, defaultTheme, linkId, storag
|
|
|
41
50
|
function ThemeScript({
|
|
42
51
|
defaultColorScheme = "system",
|
|
43
52
|
defaultTheme,
|
|
44
|
-
hrefs = {},
|
|
45
|
-
linkId = THEME_LINK_ID,
|
|
46
53
|
storageKey = THEME_STORAGE_KEY
|
|
47
54
|
}) {
|
|
48
55
|
return /* @__PURE__ */ jsx(
|
|
49
56
|
"script",
|
|
50
57
|
{
|
|
51
58
|
dangerouslySetInnerHTML: {
|
|
52
|
-
__html: buildInitScript(defaultColorScheme,
|
|
59
|
+
__html: buildInitScript(defaultColorScheme, defaultTheme, storageKey)
|
|
53
60
|
}
|
|
54
61
|
}
|
|
55
62
|
);
|
|
@@ -4,13 +4,18 @@
|
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var cookie_utils = require('../utils/cookie.utils');
|
|
6
6
|
var localStorage_utils = require('../utils/localStorage.utils');
|
|
7
|
+
var sessionStorage_utils = require('../utils/sessionStorage.utils');
|
|
7
8
|
|
|
8
9
|
function readStorage(storage, key) {
|
|
9
|
-
|
|
10
|
+
if (storage === "cookie") return cookie_utils.readCookie(key);
|
|
11
|
+
if (storage === "sessionStorage") return sessionStorage_utils.readSessionStorage(key);
|
|
12
|
+
return localStorage_utils.readLocalStorage(key);
|
|
10
13
|
}
|
|
11
14
|
function writeStorage(storage, key, value, maxAgeSeconds) {
|
|
12
15
|
if (storage === "cookie") {
|
|
13
16
|
cookie_utils.writeCookie(key, value, maxAgeSeconds);
|
|
17
|
+
} else if (storage === "sessionStorage") {
|
|
18
|
+
sessionStorage_utils.writeSessionStorage(key, value);
|
|
14
19
|
} else {
|
|
15
20
|
localStorage_utils.writeLocalStorage(key, value);
|
|
16
21
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Dispatch, SetStateAction } from 'react';
|
|
2
|
-
export type PersistentStateStorage = 'localStorage' | 'cookie';
|
|
2
|
+
export type PersistentStateStorage = 'localStorage' | 'sessionStorage' | 'cookie';
|
|
3
3
|
/**
|
|
4
4
|
* 'effect' (default): the stored value is read in a useEffect after mount,
|
|
5
5
|
* so `value` starts as `initialValue` on every render — including the
|
|
@@ -2,13 +2,18 @@
|
|
|
2
2
|
import { useRef, useState, useEffect } from 'react';
|
|
3
3
|
import { readCookie, writeCookie } from '../utils/cookie.utils';
|
|
4
4
|
import { readLocalStorage, writeLocalStorage } from '../utils/localStorage.utils';
|
|
5
|
+
import { readSessionStorage, writeSessionStorage } from '../utils/sessionStorage.utils';
|
|
5
6
|
|
|
6
7
|
function readStorage(storage, key) {
|
|
7
|
-
|
|
8
|
+
if (storage === "cookie") return readCookie(key);
|
|
9
|
+
if (storage === "sessionStorage") return readSessionStorage(key);
|
|
10
|
+
return readLocalStorage(key);
|
|
8
11
|
}
|
|
9
12
|
function writeStorage(storage, key, value, maxAgeSeconds) {
|
|
10
13
|
if (storage === "cookie") {
|
|
11
14
|
writeCookie(key, value, maxAgeSeconds);
|
|
15
|
+
} else if (storage === "sessionStorage") {
|
|
16
|
+
writeSessionStorage(key, value);
|
|
12
17
|
} else {
|
|
13
18
|
writeLocalStorage(key, value);
|
|
14
19
|
}
|
package/dist/hooks/useTheme.cjs
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var applyProductTheme = require('../styles/themes/apply-product-theme');
|
|
5
6
|
var cookie_utils = require('../utils/cookie.utils');
|
|
6
7
|
var localStorage_utils = require('../utils/localStorage.utils');
|
|
7
8
|
var theme_constants = require('../utils/theme.constants');
|
|
8
9
|
|
|
9
|
-
const PRELOAD_ID_PREFIX = "dbc-theme-preload-";
|
|
10
10
|
function persistTheme(storageKey, id) {
|
|
11
11
|
localStorage_utils.writeLocalStorage(storageKey, id);
|
|
12
12
|
cookie_utils.writeCookie(storageKey, id);
|
|
@@ -14,47 +14,16 @@ function persistTheme(storageKey, id) {
|
|
|
14
14
|
function getDomTheme() {
|
|
15
15
|
return document.documentElement.dataset.productTheme;
|
|
16
16
|
}
|
|
17
|
+
function getDomColorScheme() {
|
|
18
|
+
return document.documentElement.dataset.theme;
|
|
19
|
+
}
|
|
17
20
|
function applyTheme(id) {
|
|
18
21
|
document.documentElement.dataset.productTheme = id;
|
|
19
|
-
|
|
20
|
-
function findLink(linkId) {
|
|
21
|
-
return document.getElementById(linkId);
|
|
22
|
-
}
|
|
23
|
-
function findPreloadLink(id) {
|
|
24
|
-
return document.getElementById(`${PRELOAD_ID_PREFIX}${id}`);
|
|
25
|
-
}
|
|
26
|
-
function ensureStylesheet(id, href, linkId, onReady) {
|
|
27
|
-
var _a;
|
|
28
|
-
if (!href) {
|
|
29
|
-
onReady();
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const active = findLink(linkId);
|
|
33
|
-
if (active && active.getAttribute("href") === href && active.rel === "stylesheet") {
|
|
34
|
-
onReady();
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const preload = findPreloadLink(id);
|
|
38
|
-
const link = (_a = active != null ? active : preload) != null ? _a : document.createElement("link");
|
|
39
|
-
const wasConnected = link.isConnected;
|
|
40
|
-
link.id = linkId;
|
|
41
|
-
link.rel = "stylesheet";
|
|
42
|
-
link.removeAttribute("as");
|
|
43
|
-
link.href = href;
|
|
44
|
-
if (preload && preload !== link) preload.remove();
|
|
45
|
-
let settled = false;
|
|
46
|
-
const finish = () => {
|
|
47
|
-
if (settled) return;
|
|
48
|
-
settled = true;
|
|
49
|
-
onReady();
|
|
50
|
-
};
|
|
51
|
-
link.addEventListener("load", finish, { once: true });
|
|
52
|
-
link.addEventListener("error", finish, { once: true });
|
|
53
|
-
if (!wasConnected) document.head.appendChild(link);
|
|
22
|
+
applyProductTheme.applyProductTheme(id, getDomColorScheme());
|
|
54
23
|
}
|
|
55
24
|
let currentTheme = null;
|
|
56
25
|
let resolved = false;
|
|
57
|
-
let
|
|
26
|
+
let observerAttached = false;
|
|
58
27
|
const listeners = /* @__PURE__ */ new Set();
|
|
59
28
|
function notify() {
|
|
60
29
|
listeners.forEach((listener) => listener());
|
|
@@ -80,75 +49,43 @@ function resolveInitialTheme(storageKey, defaultTheme) {
|
|
|
80
49
|
if (fromStorage) return fromStorage;
|
|
81
50
|
return defaultTheme;
|
|
82
51
|
}
|
|
83
|
-
function ensureResolved(
|
|
52
|
+
function ensureResolved(defaultTheme, storageKey) {
|
|
84
53
|
if (resolved) return;
|
|
85
54
|
resolved = true;
|
|
86
55
|
const value = resolveInitialTheme(storageKey, defaultTheme);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
notify();
|
|
92
|
-
};
|
|
93
|
-
if (value === defaultTheme) {
|
|
94
|
-
finish();
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
ensureStylesheet(value, hrefs[value], linkId, finish);
|
|
56
|
+
applyTheme(value);
|
|
57
|
+
persistTheme(storageKey, value);
|
|
58
|
+
currentTheme = value;
|
|
59
|
+
notify();
|
|
98
60
|
}
|
|
99
|
-
function
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
link.rel = "preload";
|
|
111
|
-
link.as = "style";
|
|
112
|
-
link.href = href;
|
|
113
|
-
document.head.appendChild(link);
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
const requestIdle = window.requestIdleCallback;
|
|
117
|
-
if (typeof requestIdle === "function") {
|
|
118
|
-
requestIdle(run);
|
|
119
|
-
} else {
|
|
120
|
-
setTimeout(run, 1);
|
|
121
|
-
}
|
|
61
|
+
function ensureColorSchemeObserver() {
|
|
62
|
+
if (observerAttached) return;
|
|
63
|
+
observerAttached = true;
|
|
64
|
+
const observer = new MutationObserver(() => {
|
|
65
|
+
if (!currentTheme) return;
|
|
66
|
+
applyProductTheme.applyProductTheme(currentTheme, getDomColorScheme());
|
|
67
|
+
});
|
|
68
|
+
observer.observe(document.documentElement, {
|
|
69
|
+
attributes: true,
|
|
70
|
+
attributeFilter: ["data-theme"]
|
|
71
|
+
});
|
|
122
72
|
}
|
|
123
|
-
function switchThemeInternal(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
notify();
|
|
130
|
-
};
|
|
131
|
-
if (id === defaultTheme) {
|
|
132
|
-
finish();
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
ensureStylesheet(id, hrefs[id], linkId, finish);
|
|
73
|
+
function switchThemeInternal(storageKey, id) {
|
|
74
|
+
applyTheme(id);
|
|
75
|
+
persistTheme(storageKey, id);
|
|
76
|
+
currentTheme = id;
|
|
77
|
+
resolved = true;
|
|
78
|
+
notify();
|
|
136
79
|
}
|
|
137
80
|
function useTheme(options) {
|
|
138
|
-
const {
|
|
139
|
-
defaultTheme,
|
|
140
|
-
hrefs = {},
|
|
141
|
-
linkId = theme_constants.THEME_LINK_ID,
|
|
142
|
-
preloadOthers = true,
|
|
143
|
-
storageKey = theme_constants.THEME_STORAGE_KEY
|
|
144
|
-
} = options;
|
|
81
|
+
const { defaultTheme, storageKey = theme_constants.THEME_STORAGE_KEY } = options;
|
|
145
82
|
react.useEffect(() => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}, []);
|
|
83
|
+
ensureColorSchemeObserver();
|
|
84
|
+
ensureResolved(defaultTheme, storageKey);
|
|
85
|
+
}, [defaultTheme, storageKey]);
|
|
149
86
|
const theme = react.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
150
87
|
function switchTheme(id) {
|
|
151
|
-
switchThemeInternal(
|
|
88
|
+
switchThemeInternal(storageKey, id);
|
|
152
89
|
}
|
|
153
90
|
return { theme, switchTheme };
|
|
154
91
|
}
|