@canonical/react-components 2.8.0 → 2.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.
- package/dist/components/SidePanel/SidePanel.d.ts +2 -2
- package/dist/components/SidePanel/SidePanel.js +3 -3
- package/dist/components/SidePanel/SidePanel.stories.d.ts +1 -0
- package/dist/components/SidePanel/SidePanel.stories.js +19 -8
- package/dist/components/ThemeSwitcher/ThemeSwitcher.d.ts +19 -0
- package/dist/components/ThemeSwitcher/ThemeSwitcher.js +72 -0
- package/dist/components/ThemeSwitcher/ThemeSwitcher.stories.d.ts +6 -0
- package/dist/components/ThemeSwitcher/ThemeSwitcher.stories.js +16 -0
- package/dist/components/ThemeSwitcher/ThemeSwitcher.test.d.ts +1 -0
- package/dist/components/ThemeSwitcher/index.d.ts +1 -0
- package/dist/components/ThemeSwitcher/index.js +32 -0
- package/dist/esm/components/SidePanel/SidePanel.d.ts +2 -2
- package/dist/esm/components/SidePanel/SidePanel.js +3 -3
- package/dist/esm/components/SidePanel/SidePanel.stories.d.ts +1 -0
- package/dist/esm/components/SidePanel/SidePanel.stories.js +18 -7
- package/dist/esm/components/ThemeSwitcher/ThemeSwitcher.d.ts +19 -0
- package/dist/esm/components/ThemeSwitcher/ThemeSwitcher.js +62 -0
- package/dist/esm/components/ThemeSwitcher/ThemeSwitcher.stories.d.ts +6 -0
- package/dist/esm/components/ThemeSwitcher/ThemeSwitcher.stories.js +9 -0
- package/dist/esm/components/ThemeSwitcher/ThemeSwitcher.test.d.ts +1 -0
- package/dist/esm/components/ThemeSwitcher/index.d.ts +1 -0
- package/dist/esm/components/ThemeSwitcher/index.js +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +29 -0
- package/package.json +2 -2
|
@@ -39,9 +39,9 @@ export type Props = {
|
|
|
39
39
|
*/
|
|
40
40
|
pinned?: boolean;
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Width of the side panel, available options are wide and narrow and the default.
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
width?: "wide" | "narrow" | "";
|
|
45
45
|
};
|
|
46
46
|
type SidePanelComponents = FC<Props> & {
|
|
47
47
|
Header: FC<PropsWithChildren & HeaderProps>;
|
|
@@ -69,7 +69,7 @@ const SidePanelComponent = _ref => {
|
|
|
69
69
|
loading = false,
|
|
70
70
|
overlay,
|
|
71
71
|
pinned,
|
|
72
|
-
|
|
72
|
+
width = "",
|
|
73
73
|
parentId = "l-application"
|
|
74
74
|
} = _ref;
|
|
75
75
|
const container = document.getElementById(parentId) || document.body;
|
|
@@ -79,8 +79,8 @@ const SidePanelComponent = _ref => {
|
|
|
79
79
|
}),
|
|
80
80
|
"aria-label": "Side panel",
|
|
81
81
|
pinned: pinned,
|
|
82
|
-
narrow:
|
|
83
|
-
wide: wide
|
|
82
|
+
narrow: width === "narrow",
|
|
83
|
+
wide: width === "wide"
|
|
84
84
|
}, loading ? /*#__PURE__*/_react.default.createElement("div", {
|
|
85
85
|
className: "loading"
|
|
86
86
|
}, /*#__PURE__*/_react.default.createElement(_Spinner.default, null)) : hasError ? /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = exports.Wide = exports.Pinned = exports.Loading = exports.Error = exports.Default = void 0;
|
|
6
|
+
exports.default = exports.Wide = exports.Pinned = exports.Narrow = exports.Loading = exports.Error = exports.Default = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _SidePanel = _interopRequireDefault(require("./SidePanel"));
|
|
9
9
|
var _Button = _interopRequireDefault(require("../Button"));
|
|
@@ -25,7 +25,6 @@ const meta = {
|
|
|
25
25
|
var _el$parentElement, _wrapper$parentElemen;
|
|
26
26
|
const wrapper = el === null || el === void 0 || (_el$parentElement = el.parentElement) === null || _el$parentElement === void 0 || (_el$parentElement = _el$parentElement.parentElement) === null || _el$parentElement === void 0 ? void 0 : _el$parentElement.parentElement;
|
|
27
27
|
const parent = wrapper === null || wrapper === void 0 || (_wrapper$parentElemen = wrapper.parentElement) === null || _wrapper$parentElemen === void 0 || (_wrapper$parentElemen = _wrapper$parentElemen.parentElement) === null || _wrapper$parentElemen === void 0 ? void 0 : _wrapper$parentElemen.parentElement;
|
|
28
|
-
console.log(wrapper);
|
|
29
28
|
if (wrapper) {
|
|
30
29
|
wrapper.style.setProperty("border", "0", "important");
|
|
31
30
|
}
|
|
@@ -75,7 +74,7 @@ const StoryExample = args => {
|
|
|
75
74
|
hasError: args.hasError,
|
|
76
75
|
parentId: parentId,
|
|
77
76
|
pinned: args.pinned,
|
|
78
|
-
|
|
77
|
+
width: args.width,
|
|
79
78
|
className: "u-no-padding--top u-no-padding--bottom"
|
|
80
79
|
}, /*#__PURE__*/_react.default.createElement(_SidePanel.default.Sticky, null, /*#__PURE__*/_react.default.createElement(_SidePanel.default.Header, null, /*#__PURE__*/_react.default.createElement(_SidePanel.default.HeaderTitle, null, "Edit panel"), /*#__PURE__*/_react.default.createElement(_SidePanel.default.HeaderControls, null, /*#__PURE__*/_react.default.createElement(_Button.default, {
|
|
81
80
|
appearance: "base",
|
|
@@ -106,7 +105,7 @@ const Default = exports.Default = {
|
|
|
106
105
|
pinned: false,
|
|
107
106
|
loading: false,
|
|
108
107
|
overlay: true,
|
|
109
|
-
|
|
108
|
+
width: ""
|
|
110
109
|
},
|
|
111
110
|
render: StoryExample
|
|
112
111
|
};
|
|
@@ -118,7 +117,7 @@ const Pinned = exports.Pinned = {
|
|
|
118
117
|
pinned: true,
|
|
119
118
|
loading: false,
|
|
120
119
|
overlay: false,
|
|
121
|
-
|
|
120
|
+
width: ""
|
|
122
121
|
},
|
|
123
122
|
render: StoryExample,
|
|
124
123
|
parameters: {
|
|
@@ -135,7 +134,7 @@ const Loading = exports.Loading = {
|
|
|
135
134
|
pinned: false,
|
|
136
135
|
loading: true,
|
|
137
136
|
overlay: true,
|
|
138
|
-
|
|
137
|
+
width: ""
|
|
139
138
|
},
|
|
140
139
|
render: StoryExample
|
|
141
140
|
};
|
|
@@ -147,7 +146,19 @@ const Error = exports.Error = {
|
|
|
147
146
|
pinned: false,
|
|
148
147
|
loading: false,
|
|
149
148
|
overlay: true,
|
|
150
|
-
|
|
149
|
+
width: ""
|
|
150
|
+
},
|
|
151
|
+
render: StoryExample
|
|
152
|
+
};
|
|
153
|
+
const Narrow = exports.Narrow = {
|
|
154
|
+
args: {
|
|
155
|
+
className: "",
|
|
156
|
+
hasError: false,
|
|
157
|
+
parentId: "l-application-narrow",
|
|
158
|
+
pinned: false,
|
|
159
|
+
loading: false,
|
|
160
|
+
overlay: true,
|
|
161
|
+
width: "narrow"
|
|
151
162
|
},
|
|
152
163
|
render: StoryExample
|
|
153
164
|
};
|
|
@@ -159,7 +170,7 @@ const Wide = exports.Wide = {
|
|
|
159
170
|
pinned: false,
|
|
160
171
|
loading: false,
|
|
161
172
|
overlay: true,
|
|
162
|
-
|
|
173
|
+
width: "wide"
|
|
163
174
|
},
|
|
164
175
|
render: StoryExample
|
|
165
176
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FC } from "react";
|
|
2
|
+
export declare const loadTheme: () => string;
|
|
3
|
+
export declare const isDarkTheme: (theme: string) => boolean;
|
|
4
|
+
export declare const applyTheme: (theme: string) => void;
|
|
5
|
+
/**
|
|
6
|
+
* This is a [React](https://reactjs.org/) component for the [Vanilla framework](https://docs.vanillaframework.io).
|
|
7
|
+
*
|
|
8
|
+
* The ThemeSwitcher component allows users to switch between different themes: dark, light, and system. It saves the selected theme in local storage and applies it to the document body. You can use it in user settings.
|
|
9
|
+
*
|
|
10
|
+
* In your root component, call the exported functions `loadTheme` and `applyTheme`, such as in the example below:
|
|
11
|
+
* ```
|
|
12
|
+
* useEffect(() => {
|
|
13
|
+
* const theme = loadTheme();
|
|
14
|
+
* applyTheme(theme);
|
|
15
|
+
* }, []);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare const ThemeSwitcher: FC;
|
|
19
|
+
export default ThemeSwitcher;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.loadTheme = exports.isDarkTheme = exports.default = exports.applyTheme = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
9
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
10
|
+
const LOCAL_STORAGE_KEY = "theme";
|
|
11
|
+
const THEME_SYSTEM = "system";
|
|
12
|
+
const THEME_DARK = "dark";
|
|
13
|
+
const THEME_LIGHT = "light";
|
|
14
|
+
const loadTheme = () => {
|
|
15
|
+
const saved = localStorage.getItem(LOCAL_STORAGE_KEY);
|
|
16
|
+
return saved || THEME_SYSTEM;
|
|
17
|
+
};
|
|
18
|
+
exports.loadTheme = loadTheme;
|
|
19
|
+
const saveTheme = theme => {
|
|
20
|
+
localStorage.setItem(LOCAL_STORAGE_KEY, theme);
|
|
21
|
+
};
|
|
22
|
+
const isDarkTheme = theme => {
|
|
23
|
+
if (theme === THEME_SYSTEM) {
|
|
24
|
+
return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
25
|
+
}
|
|
26
|
+
return theme === THEME_DARK;
|
|
27
|
+
};
|
|
28
|
+
exports.isDarkTheme = isDarkTheme;
|
|
29
|
+
const applyTheme = theme => {
|
|
30
|
+
if (isDarkTheme(theme)) {
|
|
31
|
+
document.body.classList.add("is-dark");
|
|
32
|
+
} else {
|
|
33
|
+
document.body.classList.remove("is-dark");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* This is a [React](https://reactjs.org/) component for the [Vanilla framework](https://docs.vanillaframework.io).
|
|
39
|
+
*
|
|
40
|
+
* The ThemeSwitcher component allows users to switch between different themes: dark, light, and system. It saves the selected theme in local storage and applies it to the document body. You can use it in user settings.
|
|
41
|
+
*
|
|
42
|
+
* In your root component, call the exported functions `loadTheme` and `applyTheme`, such as in the example below:
|
|
43
|
+
* ```
|
|
44
|
+
* useEffect(() => {
|
|
45
|
+
* const theme = loadTheme();
|
|
46
|
+
* applyTheme(theme);
|
|
47
|
+
* }, []);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
exports.applyTheme = applyTheme;
|
|
51
|
+
const ThemeSwitcher = () => {
|
|
52
|
+
const [activeTheme, setActiveTheme] = (0, _react.useState)(loadTheme());
|
|
53
|
+
const themeButton = theme => {
|
|
54
|
+
return /*#__PURE__*/_react.default.createElement("button", {
|
|
55
|
+
className: "p-segmented-control__button",
|
|
56
|
+
type: "button",
|
|
57
|
+
"aria-selected": activeTheme === theme ? "true" : "false",
|
|
58
|
+
onClick: () => {
|
|
59
|
+
saveTheme(theme);
|
|
60
|
+
setActiveTheme(theme);
|
|
61
|
+
applyTheme(theme);
|
|
62
|
+
}
|
|
63
|
+
}, theme);
|
|
64
|
+
};
|
|
65
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
66
|
+
className: "p-segmented-control"
|
|
67
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
68
|
+
className: "p-segmented-control__list",
|
|
69
|
+
"aria-label": "Theme switcher"
|
|
70
|
+
}, themeButton(THEME_DARK), themeButton(THEME_LIGHT), themeButton(THEME_SYSTEM)));
|
|
71
|
+
};
|
|
72
|
+
var _default = exports.default = ThemeSwitcher;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.Default = void 0;
|
|
7
|
+
var _ThemeSwitcher = _interopRequireDefault(require("./ThemeSwitcher"));
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
|
+
const meta = {
|
|
10
|
+
component: _ThemeSwitcher.default,
|
|
11
|
+
tags: ["autodocs"]
|
|
12
|
+
};
|
|
13
|
+
var _default = exports.default = meta;
|
|
14
|
+
const Default = exports.Default = {
|
|
15
|
+
name: "Default"
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, loadTheme, isDarkTheme, applyTheme } from "./ThemeSwitcher";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "applyTheme", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _ThemeSwitcher.applyTheme;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "default", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _ThemeSwitcher.default;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "isDarkTheme", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _ThemeSwitcher.isDarkTheme;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "loadTheme", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _ThemeSwitcher.loadTheme;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
var _ThemeSwitcher = _interopRequireWildcard(require("./ThemeSwitcher"));
|
|
31
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
32
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -39,9 +39,9 @@ export type Props = {
|
|
|
39
39
|
*/
|
|
40
40
|
pinned?: boolean;
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Width of the side panel, available options are wide and narrow and the default.
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
width?: "wide" | "narrow" | "";
|
|
45
45
|
};
|
|
46
46
|
type SidePanelComponents = FC<Props> & {
|
|
47
47
|
Header: FC<PropsWithChildren & HeaderProps>;
|
|
@@ -63,7 +63,7 @@ var SidePanelComponent = _ref => {
|
|
|
63
63
|
loading = false,
|
|
64
64
|
overlay,
|
|
65
65
|
pinned,
|
|
66
|
-
|
|
66
|
+
width = "",
|
|
67
67
|
parentId = "l-application"
|
|
68
68
|
} = _ref;
|
|
69
69
|
var container = document.getElementById(parentId) || document.body;
|
|
@@ -73,8 +73,8 @@ var SidePanelComponent = _ref => {
|
|
|
73
73
|
}),
|
|
74
74
|
"aria-label": "Side panel",
|
|
75
75
|
pinned: pinned,
|
|
76
|
-
narrow:
|
|
77
|
-
wide: wide
|
|
76
|
+
narrow: width === "narrow",
|
|
77
|
+
wide: width === "wide"
|
|
78
78
|
}, loading ? /*#__PURE__*/React.createElement("div", {
|
|
79
79
|
className: "loading"
|
|
80
80
|
}, /*#__PURE__*/React.createElement(Spinner, null)) : hasError ? /*#__PURE__*/React.createElement("div", {
|
|
@@ -16,7 +16,6 @@ var meta = {
|
|
|
16
16
|
var _el$parentElement, _wrapper$parentElemen;
|
|
17
17
|
var wrapper = el === null || el === void 0 || (_el$parentElement = el.parentElement) === null || _el$parentElement === void 0 || (_el$parentElement = _el$parentElement.parentElement) === null || _el$parentElement === void 0 ? void 0 : _el$parentElement.parentElement;
|
|
18
18
|
var parent = wrapper === null || wrapper === void 0 || (_wrapper$parentElemen = wrapper.parentElement) === null || _wrapper$parentElemen === void 0 || (_wrapper$parentElemen = _wrapper$parentElemen.parentElement) === null || _wrapper$parentElemen === void 0 ? void 0 : _wrapper$parentElemen.parentElement;
|
|
19
|
-
console.log(wrapper);
|
|
20
19
|
if (wrapper) {
|
|
21
20
|
wrapper.style.setProperty("border", "0", "important");
|
|
22
21
|
}
|
|
@@ -66,7 +65,7 @@ var StoryExample = args => {
|
|
|
66
65
|
hasError: args.hasError,
|
|
67
66
|
parentId: parentId,
|
|
68
67
|
pinned: args.pinned,
|
|
69
|
-
|
|
68
|
+
width: args.width,
|
|
70
69
|
className: "u-no-padding--top u-no-padding--bottom"
|
|
71
70
|
}, /*#__PURE__*/React.createElement(SidePanel.Sticky, null, /*#__PURE__*/React.createElement(SidePanel.Header, null, /*#__PURE__*/React.createElement(SidePanel.HeaderTitle, null, "Edit panel"), /*#__PURE__*/React.createElement(SidePanel.HeaderControls, null, /*#__PURE__*/React.createElement(Button, {
|
|
72
71
|
appearance: "base",
|
|
@@ -97,7 +96,7 @@ export var Default = {
|
|
|
97
96
|
pinned: false,
|
|
98
97
|
loading: false,
|
|
99
98
|
overlay: true,
|
|
100
|
-
|
|
99
|
+
width: ""
|
|
101
100
|
},
|
|
102
101
|
render: StoryExample
|
|
103
102
|
};
|
|
@@ -109,7 +108,7 @@ export var Pinned = {
|
|
|
109
108
|
pinned: true,
|
|
110
109
|
loading: false,
|
|
111
110
|
overlay: false,
|
|
112
|
-
|
|
111
|
+
width: ""
|
|
113
112
|
},
|
|
114
113
|
render: StoryExample,
|
|
115
114
|
parameters: {
|
|
@@ -126,7 +125,7 @@ export var Loading = {
|
|
|
126
125
|
pinned: false,
|
|
127
126
|
loading: true,
|
|
128
127
|
overlay: true,
|
|
129
|
-
|
|
128
|
+
width: ""
|
|
130
129
|
},
|
|
131
130
|
render: StoryExample
|
|
132
131
|
};
|
|
@@ -138,7 +137,19 @@ export var Error = {
|
|
|
138
137
|
pinned: false,
|
|
139
138
|
loading: false,
|
|
140
139
|
overlay: true,
|
|
141
|
-
|
|
140
|
+
width: ""
|
|
141
|
+
},
|
|
142
|
+
render: StoryExample
|
|
143
|
+
};
|
|
144
|
+
export var Narrow = {
|
|
145
|
+
args: {
|
|
146
|
+
className: "",
|
|
147
|
+
hasError: false,
|
|
148
|
+
parentId: "l-application-narrow",
|
|
149
|
+
pinned: false,
|
|
150
|
+
loading: false,
|
|
151
|
+
overlay: true,
|
|
152
|
+
width: "narrow"
|
|
142
153
|
},
|
|
143
154
|
render: StoryExample
|
|
144
155
|
};
|
|
@@ -150,7 +161,7 @@ export var Wide = {
|
|
|
150
161
|
pinned: false,
|
|
151
162
|
loading: false,
|
|
152
163
|
overlay: true,
|
|
153
|
-
|
|
164
|
+
width: "wide"
|
|
154
165
|
},
|
|
155
166
|
render: StoryExample
|
|
156
167
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FC } from "react";
|
|
2
|
+
export declare const loadTheme: () => string;
|
|
3
|
+
export declare const isDarkTheme: (theme: string) => boolean;
|
|
4
|
+
export declare const applyTheme: (theme: string) => void;
|
|
5
|
+
/**
|
|
6
|
+
* This is a [React](https://reactjs.org/) component for the [Vanilla framework](https://docs.vanillaframework.io).
|
|
7
|
+
*
|
|
8
|
+
* The ThemeSwitcher component allows users to switch between different themes: dark, light, and system. It saves the selected theme in local storage and applies it to the document body. You can use it in user settings.
|
|
9
|
+
*
|
|
10
|
+
* In your root component, call the exported functions `loadTheme` and `applyTheme`, such as in the example below:
|
|
11
|
+
* ```
|
|
12
|
+
* useEffect(() => {
|
|
13
|
+
* const theme = loadTheme();
|
|
14
|
+
* applyTheme(theme);
|
|
15
|
+
* }, []);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare const ThemeSwitcher: FC;
|
|
19
|
+
export default ThemeSwitcher;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
var LOCAL_STORAGE_KEY = "theme";
|
|
4
|
+
var THEME_SYSTEM = "system";
|
|
5
|
+
var THEME_DARK = "dark";
|
|
6
|
+
var THEME_LIGHT = "light";
|
|
7
|
+
export var loadTheme = () => {
|
|
8
|
+
var saved = localStorage.getItem(LOCAL_STORAGE_KEY);
|
|
9
|
+
return saved || THEME_SYSTEM;
|
|
10
|
+
};
|
|
11
|
+
var saveTheme = theme => {
|
|
12
|
+
localStorage.setItem(LOCAL_STORAGE_KEY, theme);
|
|
13
|
+
};
|
|
14
|
+
export var isDarkTheme = theme => {
|
|
15
|
+
if (theme === THEME_SYSTEM) {
|
|
16
|
+
return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
17
|
+
}
|
|
18
|
+
return theme === THEME_DARK;
|
|
19
|
+
};
|
|
20
|
+
export var applyTheme = theme => {
|
|
21
|
+
if (isDarkTheme(theme)) {
|
|
22
|
+
document.body.classList.add("is-dark");
|
|
23
|
+
} else {
|
|
24
|
+
document.body.classList.remove("is-dark");
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* This is a [React](https://reactjs.org/) component for the [Vanilla framework](https://docs.vanillaframework.io).
|
|
30
|
+
*
|
|
31
|
+
* The ThemeSwitcher component allows users to switch between different themes: dark, light, and system. It saves the selected theme in local storage and applies it to the document body. You can use it in user settings.
|
|
32
|
+
*
|
|
33
|
+
* In your root component, call the exported functions `loadTheme` and `applyTheme`, such as in the example below:
|
|
34
|
+
* ```
|
|
35
|
+
* useEffect(() => {
|
|
36
|
+
* const theme = loadTheme();
|
|
37
|
+
* applyTheme(theme);
|
|
38
|
+
* }, []);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
var ThemeSwitcher = () => {
|
|
42
|
+
var [activeTheme, setActiveTheme] = useState(loadTheme());
|
|
43
|
+
var themeButton = theme => {
|
|
44
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
45
|
+
className: "p-segmented-control__button",
|
|
46
|
+
type: "button",
|
|
47
|
+
"aria-selected": activeTheme === theme ? "true" : "false",
|
|
48
|
+
onClick: () => {
|
|
49
|
+
saveTheme(theme);
|
|
50
|
+
setActiveTheme(theme);
|
|
51
|
+
applyTheme(theme);
|
|
52
|
+
}
|
|
53
|
+
}, theme);
|
|
54
|
+
};
|
|
55
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
56
|
+
className: "p-segmented-control"
|
|
57
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
58
|
+
className: "p-segmented-control__list",
|
|
59
|
+
"aria-label": "Theme switcher"
|
|
60
|
+
}, themeButton(THEME_DARK), themeButton(THEME_LIGHT), themeButton(THEME_SYSTEM)));
|
|
61
|
+
};
|
|
62
|
+
export default ThemeSwitcher;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, loadTheme, isDarkTheme, applyTheme } from "./ThemeSwitcher";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, loadTheme, isDarkTheme, applyTheme } from "./ThemeSwitcher";
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ export { default as TableHeader } from "./components/TableHeader";
|
|
|
66
66
|
export { default as TableRow } from "./components/TableRow";
|
|
67
67
|
export { default as Tabs } from "./components/Tabs";
|
|
68
68
|
export { default as Textarea } from "./components/Textarea";
|
|
69
|
+
export { default as ThemeSwitcher, loadTheme, isDarkTheme, applyTheme, } from "./components/ThemeSwitcher";
|
|
69
70
|
export { ToastNotification, ToastNotificationList, ToastNotificationProvider, useToastNotification, } from "./components/Notifications";
|
|
70
71
|
export { default as Tooltip } from "./components/Tooltip";
|
|
71
72
|
export { default as TablePagination } from "./components/TablePagination";
|
package/dist/esm/index.js
CHANGED
|
@@ -66,6 +66,7 @@ export { default as TableHeader } from "./components/TableHeader";
|
|
|
66
66
|
export { default as TableRow } from "./components/TableRow";
|
|
67
67
|
export { default as Tabs } from "./components/Tabs";
|
|
68
68
|
export { default as Textarea } from "./components/Textarea";
|
|
69
|
+
export { default as ThemeSwitcher, loadTheme, isDarkTheme, applyTheme } from "./components/ThemeSwitcher";
|
|
69
70
|
export { ToastNotification, ToastNotificationList, ToastNotificationProvider, useToastNotification } from "./components/Notifications";
|
|
70
71
|
export { default as Tooltip } from "./components/Tooltip";
|
|
71
72
|
export { default as TablePagination } from "./components/TablePagination";
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ export { default as TableHeader } from "./components/TableHeader";
|
|
|
66
66
|
export { default as TableRow } from "./components/TableRow";
|
|
67
67
|
export { default as Tabs } from "./components/Tabs";
|
|
68
68
|
export { default as Textarea } from "./components/Textarea";
|
|
69
|
+
export { default as ThemeSwitcher, loadTheme, isDarkTheme, applyTheme, } from "./components/ThemeSwitcher";
|
|
69
70
|
export { ToastNotification, ToastNotificationList, ToastNotificationProvider, useToastNotification, } from "./components/Notifications";
|
|
70
71
|
export { default as Tooltip } from "./components/Tooltip";
|
|
71
72
|
export { default as TablePagination } from "./components/TablePagination";
|
package/dist/index.js
CHANGED
|
@@ -87,6 +87,10 @@ var _exportNames = {
|
|
|
87
87
|
TableRow: true,
|
|
88
88
|
Tabs: true,
|
|
89
89
|
Textarea: true,
|
|
90
|
+
ThemeSwitcher: true,
|
|
91
|
+
loadTheme: true,
|
|
92
|
+
isDarkTheme: true,
|
|
93
|
+
applyTheme: true,
|
|
90
94
|
Tooltip: true,
|
|
91
95
|
TablePagination: true,
|
|
92
96
|
TablePaginationControls: true,
|
|
@@ -568,6 +572,12 @@ Object.defineProperty(exports, "Theme", {
|
|
|
568
572
|
return _enums.Theme;
|
|
569
573
|
}
|
|
570
574
|
});
|
|
575
|
+
Object.defineProperty(exports, "ThemeSwitcher", {
|
|
576
|
+
enumerable: true,
|
|
577
|
+
get: function () {
|
|
578
|
+
return _ThemeSwitcher.default;
|
|
579
|
+
}
|
|
580
|
+
});
|
|
571
581
|
Object.defineProperty(exports, "ToastNotification", {
|
|
572
582
|
enumerable: true,
|
|
573
583
|
get: function () {
|
|
@@ -592,6 +602,12 @@ Object.defineProperty(exports, "Tooltip", {
|
|
|
592
602
|
return _Tooltip.default;
|
|
593
603
|
}
|
|
594
604
|
});
|
|
605
|
+
Object.defineProperty(exports, "applyTheme", {
|
|
606
|
+
enumerable: true,
|
|
607
|
+
get: function () {
|
|
608
|
+
return _ThemeSwitcher.applyTheme;
|
|
609
|
+
}
|
|
610
|
+
});
|
|
595
611
|
Object.defineProperty(exports, "createEventQueue", {
|
|
596
612
|
enumerable: true,
|
|
597
613
|
get: function () {
|
|
@@ -610,6 +626,12 @@ Object.defineProperty(exports, "info", {
|
|
|
610
626
|
return _NotificationProvider.info;
|
|
611
627
|
}
|
|
612
628
|
});
|
|
629
|
+
Object.defineProperty(exports, "isDarkTheme", {
|
|
630
|
+
enumerable: true,
|
|
631
|
+
get: function () {
|
|
632
|
+
return _ThemeSwitcher.isDarkTheme;
|
|
633
|
+
}
|
|
634
|
+
});
|
|
613
635
|
Object.defineProperty(exports, "isNavigationAnchor", {
|
|
614
636
|
enumerable: true,
|
|
615
637
|
get: function () {
|
|
@@ -622,6 +644,12 @@ Object.defineProperty(exports, "isNavigationButton", {
|
|
|
622
644
|
return _utils.isNavigationButton;
|
|
623
645
|
}
|
|
624
646
|
});
|
|
647
|
+
Object.defineProperty(exports, "loadTheme", {
|
|
648
|
+
enumerable: true,
|
|
649
|
+
get: function () {
|
|
650
|
+
return _ThemeSwitcher.loadTheme;
|
|
651
|
+
}
|
|
652
|
+
});
|
|
625
653
|
Object.defineProperty(exports, "queue", {
|
|
626
654
|
enumerable: true,
|
|
627
655
|
get: function () {
|
|
@@ -791,6 +819,7 @@ var _TableHeader = _interopRequireDefault(require("./components/TableHeader"));
|
|
|
791
819
|
var _TableRow = _interopRequireDefault(require("./components/TableRow"));
|
|
792
820
|
var _Tabs = _interopRequireDefault(require("./components/Tabs"));
|
|
793
821
|
var _Textarea = _interopRequireDefault(require("./components/Textarea"));
|
|
822
|
+
var _ThemeSwitcher = _interopRequireWildcard(require("./components/ThemeSwitcher"));
|
|
794
823
|
var _Tooltip = _interopRequireDefault(require("./components/Tooltip"));
|
|
795
824
|
var _TablePagination = _interopRequireDefault(require("./components/TablePagination"));
|
|
796
825
|
var _TablePaginationControls = _interopRequireDefault(require("./components/TablePagination/TablePaginationControls"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonical/react-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"author": {
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"tsc-alias": "1.8.10",
|
|
94
94
|
"typescript": "5.7.3",
|
|
95
95
|
"typescript-eslint": "8.24.1",
|
|
96
|
-
"vanilla-framework": "4.
|
|
96
|
+
"vanilla-framework": "4.26.0",
|
|
97
97
|
"wait-on": "8.0.2",
|
|
98
98
|
"webpack": "5.98.0"
|
|
99
99
|
},
|