@canonical/react-components 2.8.1 → 2.10.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/CustomLayout/CustomLayout.d.ts +22 -0
- package/dist/components/CustomLayout/CustomLayout.js +26 -0
- package/dist/components/CustomLayout/CustomLayout.stories.d.ts +7 -0
- package/dist/components/CustomLayout/CustomLayout.stories.js +28 -0
- package/dist/components/CustomLayout/CustomLayout.test.d.ts +1 -0
- package/dist/components/CustomLayout/index.d.ts +2 -0
- package/dist/components/CustomLayout/index.js +13 -0
- package/dist/components/Spinner/Spinner.d.ts +7 -1
- package/dist/components/Spinner/Spinner.js +6 -2
- 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/CustomLayout/CustomLayout.d.ts +22 -0
- package/dist/esm/components/CustomLayout/CustomLayout.js +19 -0
- package/dist/esm/components/CustomLayout/CustomLayout.stories.d.ts +7 -0
- package/dist/esm/components/CustomLayout/CustomLayout.stories.js +21 -0
- package/dist/esm/components/CustomLayout/CustomLayout.test.d.ts +1 -0
- package/dist/esm/components/CustomLayout/index.d.ts +2 -0
- package/dist/esm/components/CustomLayout/index.js +1 -0
- package/dist/esm/components/Spinner/Spinner.d.ts +7 -1
- package/dist/esm/components/Spinner/Spinner.js +8 -4
- 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 +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +37 -0
- package/package.json +2 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { HTMLProps, ReactNode } from "react";
|
|
3
|
+
export type Props = {
|
|
4
|
+
/**
|
|
5
|
+
* This prop can be used to replace the header area of the panel when the default implementation is not sufficient.
|
|
6
|
+
*/
|
|
7
|
+
header?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* The main content.
|
|
10
|
+
*/
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Classes to apply to the main content.
|
|
14
|
+
*/
|
|
15
|
+
mainClassName?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Classes to apply to the main area.
|
|
18
|
+
*/
|
|
19
|
+
contentClassName?: string;
|
|
20
|
+
} & HTMLProps<HTMLDivElement>;
|
|
21
|
+
declare const CustomLayout: ({ header, children, mainClassName, contentClassName, }: Props) => React.JSX.Element;
|
|
22
|
+
export default CustomLayout;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _ApplicationLayout = require("../ApplicationLayout");
|
|
9
|
+
var _Panel = _interopRequireDefault(require("../Panel"));
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
const CustomLayout = _ref => {
|
|
12
|
+
let {
|
|
13
|
+
header,
|
|
14
|
+
children,
|
|
15
|
+
mainClassName,
|
|
16
|
+
contentClassName
|
|
17
|
+
} = _ref;
|
|
18
|
+
return /*#__PURE__*/_react.default.createElement(_ApplicationLayout.AppMain, {
|
|
19
|
+
className: mainClassName,
|
|
20
|
+
id: "main-content"
|
|
21
|
+
}, /*#__PURE__*/_react.default.createElement(_Panel.default, {
|
|
22
|
+
contentClassName: contentClassName,
|
|
23
|
+
header: header
|
|
24
|
+
}, children));
|
|
25
|
+
};
|
|
26
|
+
var _default = exports.default = CustomLayout;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import CustomLayout from "./CustomLayout";
|
|
3
|
+
declare const meta: Meta<typeof CustomLayout>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof CustomLayout>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Content: Story;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.Default = exports.Content = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _Panel = _interopRequireDefault(require("../Panel"));
|
|
9
|
+
var _CustomLayout = _interopRequireDefault(require("./CustomLayout"));
|
|
10
|
+
var _AppMain = _interopRequireDefault(require("../ApplicationLayout/AppMain"));
|
|
11
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
+
const meta = {
|
|
13
|
+
component: _CustomLayout.default,
|
|
14
|
+
tags: ["autodocs"]
|
|
15
|
+
};
|
|
16
|
+
var _default = exports.default = meta;
|
|
17
|
+
const Default = exports.Default = {
|
|
18
|
+
args: {
|
|
19
|
+
children: "CustomLayout"
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const Content = exports.Content = {
|
|
23
|
+
render: () => {
|
|
24
|
+
return /*#__PURE__*/_react.default.createElement(_AppMain.default, {
|
|
25
|
+
id: "main-content"
|
|
26
|
+
}, /*#__PURE__*/_react.default.createElement(_Panel.default, null, "test"));
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "default", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _CustomLayout.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _CustomLayout = _interopRequireDefault(require("./CustomLayout"));
|
|
13
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -21,9 +21,15 @@ export type Props = {
|
|
|
21
21
|
* The politeness setting of the spinner alert.
|
|
22
22
|
*/
|
|
23
23
|
ariaLive?: "assertive" | "off" | "polite";
|
|
24
|
+
/**
|
|
25
|
+
* Whether the Loader is replacing the main component in the application layout.
|
|
26
|
+
* In that case, the loader has to be wrapped with a main panel of the application
|
|
27
|
+
* layout. This is important for the mobile view. This prop enables the wrapping.
|
|
28
|
+
*/
|
|
29
|
+
isMainComponent?: boolean;
|
|
24
30
|
} & HTMLProps<HTMLSpanElement>;
|
|
25
31
|
/**
|
|
26
32
|
* This is a [React](https://reactjs.org/) component for the Vanilla [Spin](https://docs.vanillaframework.io/settings/animation-settings/#spin) animation.
|
|
27
33
|
*/
|
|
28
|
-
declare const Spinner: ({ className, text, isLight, ariaLive, role, ...props }: Props) => React.JSX.Element;
|
|
34
|
+
declare const Spinner: ({ className, text, isLight, ariaLive, role, isMainComponent, ...props }: Props) => React.JSX.Element;
|
|
29
35
|
export default Spinner;
|
|
@@ -7,6 +7,7 @@ exports.default = void 0;
|
|
|
7
7
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
8
8
|
var _react = _interopRequireDefault(require("react"));
|
|
9
9
|
var _classnames = _interopRequireDefault(require("classnames"));
|
|
10
|
+
var _CustomLayout = _interopRequireDefault(require("../CustomLayout"));
|
|
10
11
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
12
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
12
13
|
/**
|
|
@@ -19,9 +20,10 @@ const Spinner = _ref => {
|
|
|
19
20
|
isLight = false,
|
|
20
21
|
ariaLive = "polite",
|
|
21
22
|
role = "alert",
|
|
23
|
+
isMainComponent = false,
|
|
22
24
|
...props
|
|
23
25
|
} = _ref;
|
|
24
|
-
|
|
26
|
+
const loader = /*#__PURE__*/_react.default.createElement("span", _extends({}, props, {
|
|
25
27
|
className: (0, _classnames.default)(className, "p-text--default"),
|
|
26
28
|
role: role,
|
|
27
29
|
"aria-live": ariaLive
|
|
@@ -30,11 +32,13 @@ const Spinner = _ref => {
|
|
|
30
32
|
"is-light": isLight
|
|
31
33
|
})
|
|
32
34
|
}, text ? "" : "Loading"), text && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "\u2002", /*#__PURE__*/_react.default.createElement("span", null, text)));
|
|
35
|
+
return isMainComponent ? /*#__PURE__*/_react.default.createElement(_CustomLayout.default, null, loader) : loader;
|
|
33
36
|
};
|
|
34
37
|
Spinner.propTypes = {
|
|
35
38
|
isLight: _propTypes.default.bool,
|
|
36
39
|
text: _propTypes.default.string,
|
|
37
40
|
role: _propTypes.default.string,
|
|
38
|
-
ariaLive: _propTypes.default.oneOf(["assertive", "off", "polite"])
|
|
41
|
+
ariaLive: _propTypes.default.oneOf(["assertive", "off", "polite"]),
|
|
42
|
+
isMainComponent: _propTypes.default.bool
|
|
39
43
|
};
|
|
40
44
|
var _default = exports.default = Spinner;
|
|
@@ -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; }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { HTMLProps, ReactNode } from "react";
|
|
3
|
+
export type Props = {
|
|
4
|
+
/**
|
|
5
|
+
* This prop can be used to replace the header area of the panel when the default implementation is not sufficient.
|
|
6
|
+
*/
|
|
7
|
+
header?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* The main content.
|
|
10
|
+
*/
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Classes to apply to the main content.
|
|
14
|
+
*/
|
|
15
|
+
mainClassName?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Classes to apply to the main area.
|
|
18
|
+
*/
|
|
19
|
+
contentClassName?: string;
|
|
20
|
+
} & HTMLProps<HTMLDivElement>;
|
|
21
|
+
declare const CustomLayout: ({ header, children, mainClassName, contentClassName, }: Props) => React.JSX.Element;
|
|
22
|
+
export default CustomLayout;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { AppMain } from "../ApplicationLayout";
|
|
3
|
+
import Panel from "../Panel";
|
|
4
|
+
var CustomLayout = _ref => {
|
|
5
|
+
var {
|
|
6
|
+
header,
|
|
7
|
+
children,
|
|
8
|
+
mainClassName,
|
|
9
|
+
contentClassName
|
|
10
|
+
} = _ref;
|
|
11
|
+
return /*#__PURE__*/React.createElement(AppMain, {
|
|
12
|
+
className: mainClassName,
|
|
13
|
+
id: "main-content"
|
|
14
|
+
}, /*#__PURE__*/React.createElement(Panel, {
|
|
15
|
+
contentClassName: contentClassName,
|
|
16
|
+
header: header
|
|
17
|
+
}, children));
|
|
18
|
+
};
|
|
19
|
+
export default CustomLayout;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import CustomLayout from "./CustomLayout";
|
|
3
|
+
declare const meta: Meta<typeof CustomLayout>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof CustomLayout>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Content: Story;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Panel from "../Panel";
|
|
3
|
+
import CustomLayout from "./CustomLayout";
|
|
4
|
+
import AppMain from "../ApplicationLayout/AppMain";
|
|
5
|
+
var meta = {
|
|
6
|
+
component: CustomLayout,
|
|
7
|
+
tags: ["autodocs"]
|
|
8
|
+
};
|
|
9
|
+
export default meta;
|
|
10
|
+
export var Default = {
|
|
11
|
+
args: {
|
|
12
|
+
children: "CustomLayout"
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export var Content = {
|
|
16
|
+
render: () => {
|
|
17
|
+
return /*#__PURE__*/React.createElement(AppMain, {
|
|
18
|
+
id: "main-content"
|
|
19
|
+
}, /*#__PURE__*/React.createElement(Panel, null, "test"));
|
|
20
|
+
}
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./CustomLayout";
|
|
@@ -21,9 +21,15 @@ export type Props = {
|
|
|
21
21
|
* The politeness setting of the spinner alert.
|
|
22
22
|
*/
|
|
23
23
|
ariaLive?: "assertive" | "off" | "polite";
|
|
24
|
+
/**
|
|
25
|
+
* Whether the Loader is replacing the main component in the application layout.
|
|
26
|
+
* In that case, the loader has to be wrapped with a main panel of the application
|
|
27
|
+
* layout. This is important for the mobile view. This prop enables the wrapping.
|
|
28
|
+
*/
|
|
29
|
+
isMainComponent?: boolean;
|
|
24
30
|
} & HTMLProps<HTMLSpanElement>;
|
|
25
31
|
/**
|
|
26
32
|
* This is a [React](https://reactjs.org/) component for the Vanilla [Spin](https://docs.vanillaframework.io/settings/animation-settings/#spin) animation.
|
|
27
33
|
*/
|
|
28
|
-
declare const Spinner: ({ className, text, isLight, ariaLive, role, ...props }: Props) => React.JSX.Element;
|
|
34
|
+
declare const Spinner: ({ className, text, isLight, ariaLive, role, isMainComponent, ...props }: Props) => React.JSX.Element;
|
|
29
35
|
export default Spinner;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import _pt from "prop-types";
|
|
2
|
-
var _excluded = ["className", "text", "isLight", "ariaLive", "role"];
|
|
2
|
+
var _excluded = ["className", "text", "isLight", "ariaLive", "role", "isMainComponent"];
|
|
3
3
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
4
4
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
5
5
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
6
6
|
import React from "react";
|
|
7
7
|
import classNames from "classnames";
|
|
8
|
+
import CustomLayout from "../CustomLayout";
|
|
8
9
|
/**
|
|
9
10
|
* This is a [React](https://reactjs.org/) component for the Vanilla [Spin](https://docs.vanillaframework.io/settings/animation-settings/#spin) animation.
|
|
10
11
|
*/
|
|
@@ -14,10 +15,11 @@ var Spinner = _ref => {
|
|
|
14
15
|
text,
|
|
15
16
|
isLight = false,
|
|
16
17
|
ariaLive = "polite",
|
|
17
|
-
role = "alert"
|
|
18
|
+
role = "alert",
|
|
19
|
+
isMainComponent = false
|
|
18
20
|
} = _ref,
|
|
19
21
|
props = _objectWithoutProperties(_ref, _excluded);
|
|
20
|
-
|
|
22
|
+
var loader = /*#__PURE__*/React.createElement("span", _extends({}, props, {
|
|
21
23
|
className: classNames(className, "p-text--default"),
|
|
22
24
|
role: role,
|
|
23
25
|
"aria-live": ariaLive
|
|
@@ -26,11 +28,13 @@ var Spinner = _ref => {
|
|
|
26
28
|
"is-light": isLight
|
|
27
29
|
})
|
|
28
30
|
}, text ? "" : "Loading"), text && /*#__PURE__*/React.createElement(React.Fragment, null, "\u2002", /*#__PURE__*/React.createElement("span", null, text)));
|
|
31
|
+
return isMainComponent ? /*#__PURE__*/React.createElement(CustomLayout, null, loader) : loader;
|
|
29
32
|
};
|
|
30
33
|
Spinner.propTypes = {
|
|
31
34
|
isLight: _pt.bool,
|
|
32
35
|
text: _pt.string,
|
|
33
36
|
role: _pt.string,
|
|
34
|
-
ariaLive: _pt.oneOf(["assertive", "off", "polite"])
|
|
37
|
+
ariaLive: _pt.oneOf(["assertive", "off", "polite"]),
|
|
38
|
+
isMainComponent: _pt.bool
|
|
35
39
|
};
|
|
36
40
|
export default Spinner;
|
|
@@ -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,10 +66,12 @@ 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";
|
|
72
73
|
export { default as TablePaginationControls } from "./components/TablePagination/TablePaginationControls";
|
|
74
|
+
export { default as CustomLayout } from "./components/CustomLayout";
|
|
73
75
|
export { default as CustomSelect } from "./components/CustomSelect";
|
|
74
76
|
export type { AccordionProps } from "./components/Accordion";
|
|
75
77
|
export type { ActionButtonProps } from "./components/ActionButton";
|
package/dist/esm/index.js
CHANGED
|
@@ -66,10 +66,12 @@ 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";
|
|
72
73
|
export { default as TablePaginationControls } from "./components/TablePagination/TablePaginationControls";
|
|
74
|
+
export { default as CustomLayout } from "./components/CustomLayout";
|
|
73
75
|
export { default as CustomSelect } from "./components/CustomSelect";
|
|
74
76
|
export { useOnClickOutside, useClickOutside, useId, useListener, useOnEscapePressed, usePagination, usePrevious, usePrefersReducedMotion, useThrottle, useWindowFitment } from "./hooks";
|
|
75
77
|
export { isNavigationAnchor, isNavigationButton } from "./utils";
|
package/dist/index.d.ts
CHANGED
|
@@ -66,10 +66,12 @@ 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";
|
|
72
73
|
export { default as TablePaginationControls } from "./components/TablePagination/TablePaginationControls";
|
|
74
|
+
export { default as CustomLayout } from "./components/CustomLayout";
|
|
73
75
|
export { default as CustomSelect } from "./components/CustomSelect";
|
|
74
76
|
export type { AccordionProps } from "./components/Accordion";
|
|
75
77
|
export type { ActionButtonProps } from "./components/ActionButton";
|
package/dist/index.js
CHANGED
|
@@ -87,9 +87,14 @@ 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,
|
|
97
|
+
CustomLayout: true,
|
|
93
98
|
CustomSelect: true,
|
|
94
99
|
useOnClickOutside: true,
|
|
95
100
|
useClickOutside: true,
|
|
@@ -244,6 +249,12 @@ Object.defineProperty(exports, "ContextualMenu", {
|
|
|
244
249
|
return _ContextualMenu.default;
|
|
245
250
|
}
|
|
246
251
|
});
|
|
252
|
+
Object.defineProperty(exports, "CustomLayout", {
|
|
253
|
+
enumerable: true,
|
|
254
|
+
get: function () {
|
|
255
|
+
return _CustomLayout.default;
|
|
256
|
+
}
|
|
257
|
+
});
|
|
247
258
|
Object.defineProperty(exports, "CustomSelect", {
|
|
248
259
|
enumerable: true,
|
|
249
260
|
get: function () {
|
|
@@ -568,6 +579,12 @@ Object.defineProperty(exports, "Theme", {
|
|
|
568
579
|
return _enums.Theme;
|
|
569
580
|
}
|
|
570
581
|
});
|
|
582
|
+
Object.defineProperty(exports, "ThemeSwitcher", {
|
|
583
|
+
enumerable: true,
|
|
584
|
+
get: function () {
|
|
585
|
+
return _ThemeSwitcher.default;
|
|
586
|
+
}
|
|
587
|
+
});
|
|
571
588
|
Object.defineProperty(exports, "ToastNotification", {
|
|
572
589
|
enumerable: true,
|
|
573
590
|
get: function () {
|
|
@@ -592,6 +609,12 @@ Object.defineProperty(exports, "Tooltip", {
|
|
|
592
609
|
return _Tooltip.default;
|
|
593
610
|
}
|
|
594
611
|
});
|
|
612
|
+
Object.defineProperty(exports, "applyTheme", {
|
|
613
|
+
enumerable: true,
|
|
614
|
+
get: function () {
|
|
615
|
+
return _ThemeSwitcher.applyTheme;
|
|
616
|
+
}
|
|
617
|
+
});
|
|
595
618
|
Object.defineProperty(exports, "createEventQueue", {
|
|
596
619
|
enumerable: true,
|
|
597
620
|
get: function () {
|
|
@@ -610,6 +633,12 @@ Object.defineProperty(exports, "info", {
|
|
|
610
633
|
return _NotificationProvider.info;
|
|
611
634
|
}
|
|
612
635
|
});
|
|
636
|
+
Object.defineProperty(exports, "isDarkTheme", {
|
|
637
|
+
enumerable: true,
|
|
638
|
+
get: function () {
|
|
639
|
+
return _ThemeSwitcher.isDarkTheme;
|
|
640
|
+
}
|
|
641
|
+
});
|
|
613
642
|
Object.defineProperty(exports, "isNavigationAnchor", {
|
|
614
643
|
enumerable: true,
|
|
615
644
|
get: function () {
|
|
@@ -622,6 +651,12 @@ Object.defineProperty(exports, "isNavigationButton", {
|
|
|
622
651
|
return _utils.isNavigationButton;
|
|
623
652
|
}
|
|
624
653
|
});
|
|
654
|
+
Object.defineProperty(exports, "loadTheme", {
|
|
655
|
+
enumerable: true,
|
|
656
|
+
get: function () {
|
|
657
|
+
return _ThemeSwitcher.loadTheme;
|
|
658
|
+
}
|
|
659
|
+
});
|
|
625
660
|
Object.defineProperty(exports, "queue", {
|
|
626
661
|
enumerable: true,
|
|
627
662
|
get: function () {
|
|
@@ -791,9 +826,11 @@ var _TableHeader = _interopRequireDefault(require("./components/TableHeader"));
|
|
|
791
826
|
var _TableRow = _interopRequireDefault(require("./components/TableRow"));
|
|
792
827
|
var _Tabs = _interopRequireDefault(require("./components/Tabs"));
|
|
793
828
|
var _Textarea = _interopRequireDefault(require("./components/Textarea"));
|
|
829
|
+
var _ThemeSwitcher = _interopRequireWildcard(require("./components/ThemeSwitcher"));
|
|
794
830
|
var _Tooltip = _interopRequireDefault(require("./components/Tooltip"));
|
|
795
831
|
var _TablePagination = _interopRequireDefault(require("./components/TablePagination"));
|
|
796
832
|
var _TablePaginationControls = _interopRequireDefault(require("./components/TablePagination/TablePaginationControls"));
|
|
833
|
+
var _CustomLayout = _interopRequireDefault(require("./components/CustomLayout"));
|
|
797
834
|
var _CustomSelect = _interopRequireDefault(require("./components/CustomSelect"));
|
|
798
835
|
var _hooks = require("./hooks");
|
|
799
836
|
var _utils = require("./utils");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonical/react-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.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.1",
|
|
97
97
|
"wait-on": "8.0.2",
|
|
98
98
|
"webpack": "5.98.0"
|
|
99
99
|
},
|