@askrjs/themes 0.0.11 → 0.0.13
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 +5 -5
- package/THEMING.md +2 -2
- package/dist/components/_internal/block-layout.d.ts +1 -2
- package/dist/components/_internal/block-layout.js +1 -3
- package/dist/components/_internal/block-layout.js.map +1 -1
- package/dist/components/_internal/classes.js +0 -2
- package/dist/components/_internal/jsx.js +9 -3
- package/dist/components/_internal/jsx.js.map +1 -1
- package/dist/components/_internal/merge-props.js +0 -2
- package/dist/components/_internal/pathname.js +0 -2
- package/dist/components/_internal/style.js +0 -2
- package/dist/components/alert/alert.d.ts +1 -3
- package/dist/components/alert/alert.js +0 -2
- package/dist/components/alert/alert.js.map +1 -1
- package/dist/components/alert/alert.types.d.ts +1 -3
- package/dist/components/alert/index.d.ts +2 -1
- package/dist/components/aside/aside.d.ts +1 -3
- package/dist/components/aside/aside.js +0 -2
- package/dist/components/aside/aside.types.d.ts +2 -2
- package/dist/components/aside/index.d.ts +2 -1
- package/dist/components/aspect-ratio/aspect-ratio.d.ts +1 -3
- package/dist/components/aspect-ratio/aspect-ratio.js +2 -6
- package/dist/components/aspect-ratio/aspect-ratio.js.map +1 -1
- package/dist/components/aspect-ratio/aspect-ratio.types.d.ts +1 -3
- package/dist/components/aspect-ratio/index.d.ts +2 -1
- package/dist/components/badge/badge.d.ts +1 -3
- package/dist/components/badge/badge.js +2 -6
- package/dist/components/badge/badge.js.map +1 -1
- package/dist/components/badge/badge.types.d.ts +1 -3
- package/dist/components/badge/index.d.ts +2 -1
- package/dist/components/block/block.d.ts +1 -3
- package/dist/components/block/block.js +2 -6
- package/dist/components/block/block.js.map +1 -1
- package/dist/components/block/block.types.d.ts +2 -4
- package/dist/components/block/index.d.ts +2 -1
- package/dist/components/brand/brand.d.ts +1 -3
- package/dist/components/brand/brand.js +4 -7
- package/dist/components/brand/brand.js.map +1 -1
- package/dist/components/brand/brand.types.d.ts +1 -3
- package/dist/components/brand/index.d.ts +2 -1
- package/dist/components/button-group/button-group.d.ts +1 -3
- package/dist/components/button-group/button-group.js +0 -2
- package/dist/components/button-group/button-group.js.map +1 -1
- package/dist/components/button-group/button-group.types.d.ts +1 -3
- package/dist/components/button-group/index.d.ts +2 -1
- package/dist/components/card/card.d.ts +1 -3
- package/dist/components/card/card.js +0 -2
- package/dist/components/card/card.types.d.ts +1 -3
- package/dist/components/card/index.d.ts +2 -1
- package/dist/components/catalog.d.ts +1 -3
- package/dist/components/catalog.js +2 -3
- package/dist/components/catalog.js.map +1 -1
- package/dist/components/close/close.d.ts +1 -3
- package/dist/components/close/close.js +0 -2
- package/dist/components/close/close.types.d.ts +1 -3
- package/dist/components/close/index.d.ts +2 -1
- package/dist/components/container/container.d.ts +1 -3
- package/dist/components/container/container.js +0 -2
- package/dist/components/container/container.types.d.ts +2 -2
- package/dist/components/container/index.d.ts +2 -1
- package/dist/components/empty-state/empty-state.d.ts +1 -3
- package/dist/components/empty-state/empty-state.js +0 -2
- package/dist/components/empty-state/empty-state.types.d.ts +2 -2
- package/dist/components/empty-state/index.d.ts +2 -1
- package/dist/components/field/field.d.ts +1 -3
- package/dist/components/field/field.js +0 -2
- package/dist/components/field/field.types.d.ts +1 -3
- package/dist/components/field/index.d.ts +2 -1
- package/dist/components/footer/footer.d.ts +1 -3
- package/dist/components/footer/footer.js +0 -2
- package/dist/components/footer/footer.types.d.ts +2 -3
- package/dist/components/footer/index.d.ts +2 -1
- package/dist/components/grid/grid.d.ts +1 -3
- package/dist/components/grid/grid.js +2 -7
- package/dist/components/grid/grid.js.map +1 -1
- package/dist/components/grid/grid.types.d.ts +1 -3
- package/dist/components/grid/index.d.ts +2 -1
- package/dist/components/header/header.d.ts +1 -3
- package/dist/components/header/header.js +0 -2
- package/dist/components/header/header.types.d.ts +2 -2
- package/dist/components/header/index.d.ts +2 -1
- package/dist/components/input-group/index.d.ts +2 -1
- package/dist/components/input-group/input-group.d.ts +1 -3
- package/dist/components/input-group/input-group.js +2 -6
- package/dist/components/input-group/input-group.js.map +1 -1
- package/dist/components/input-group/input-group.types.d.ts +1 -3
- package/dist/components/main/index.d.ts +2 -1
- package/dist/components/main/main.d.ts +1 -3
- package/dist/components/main/main.js +0 -2
- package/dist/components/main/main.types.d.ts +2 -2
- package/dist/components/nav/index.d.ts +2 -1
- package/dist/components/nav/nav.d.ts +1 -3
- package/dist/components/nav/nav.js +22 -17
- package/dist/components/nav/nav.js.map +1 -1
- package/dist/components/nav/nav.types.d.ts +1 -3
- package/dist/components/navbar/index.d.ts +3 -1
- package/dist/components/navbar/navbar.d.ts +1 -3
- package/dist/components/navbar/navbar.js +9 -10
- package/dist/components/navbar/navbar.js.map +1 -1
- package/dist/components/navbar/navbar.types.d.ts +2 -3
- package/dist/components/overlays/dropdown-content.d.ts +1 -3
- package/dist/components/overlays/dropdown-content.js +0 -2
- package/dist/components/page/index.d.ts +2 -1
- package/dist/components/page/page.d.ts +1 -3
- package/dist/components/page/page.js +0 -2
- package/dist/components/page/page.types.d.ts +2 -2
- package/dist/components/page-header/index.d.ts +2 -1
- package/dist/components/page-header/page-header.d.ts +1 -3
- package/dist/components/page-header/page-header.js +0 -2
- package/dist/components/page-header/page-header.types.d.ts +2 -2
- package/dist/components/section/index.d.ts +2 -1
- package/dist/components/section/section.d.ts +1 -3
- package/dist/components/section/section.js +0 -2
- package/dist/components/section/section.types.d.ts +2 -2
- package/dist/components/separator/index.d.ts +2 -1
- package/dist/components/separator/separator.d.ts +1 -3
- package/dist/components/separator/separator.js +2 -6
- package/dist/components/separator/separator.js.map +1 -1
- package/dist/components/separator/separator.types.d.ts +1 -3
- package/dist/components/sidebar/index.d.ts +2 -1
- package/dist/components/sidebar/sidebar.d.ts +2 -4
- package/dist/components/sidebar/sidebar.js +5 -10
- package/dist/components/sidebar/sidebar.js.map +1 -1
- package/dist/components/sidebar/sidebar.types.d.ts +2 -2
- package/dist/components/skeleton/index.d.ts +2 -1
- package/dist/components/skeleton/skeleton.d.ts +1 -3
- package/dist/components/skeleton/skeleton.js +8 -10
- package/dist/components/skeleton/skeleton.js.map +1 -1
- package/dist/components/skeleton/skeleton.types.d.ts +1 -3
- package/dist/components/spinner/index.d.ts +2 -1
- package/dist/components/spinner/spinner.d.ts +1 -3
- package/dist/components/spinner/spinner.js +0 -2
- package/dist/components/spinner/spinner.types.d.ts +1 -3
- package/dist/components/stat/index.d.ts +2 -1
- package/dist/components/stat/stat.d.ts +1 -3
- package/dist/components/stat/stat.js +0 -2
- package/dist/components/stat/stat.types.d.ts +1 -3
- package/dist/components/text/index.d.ts +2 -1
- package/dist/components/text/text.d.ts +1 -3
- package/dist/components/text/text.js +2 -7
- package/dist/components/text/text.js.map +1 -1
- package/dist/components/text/text.types.d.ts +1 -3
- package/dist/components/theme/index.d.ts +2 -1
- package/dist/components/theme/theme.d.ts +5 -7
- package/dist/components/theme/theme.js +102 -72
- package/dist/components/theme/theme.js.map +1 -1
- package/dist/components/toolbar/index.d.ts +2 -1
- package/dist/components/toolbar/toolbar.d.ts +1 -3
- package/dist/components/toolbar/toolbar.js +0 -2
- package/dist/components/toolbar/toolbar.types.d.ts +2 -2
- package/dist/components.d.ts +34 -4
- package/dist/components.js +4 -4
- package/dist/controls.d.ts +4 -0
- package/dist/core.d.ts +18 -2
- package/dist/navs.d.ts +1 -0
- package/dist/overlays.d.ts +2 -2
- package/dist/overlays.js +2 -2
- package/dist/surfaces.d.ts +8 -0
- package/dist/theme.d.ts +3 -2
- package/dist/theme.js +2 -2
- package/dist/themes/default/index.css +3 -3
- package/package.json +39 -16
- package/src/components/_internal/jsx.ts +11 -0
- package/src/components/alert/alert.tsx +1 -1
- package/src/components/aspect-ratio/aspect-ratio.tsx +2 -1
- package/src/components/badge/badge.tsx +2 -1
- package/src/components/block/block.tsx +2 -2
- package/src/components/brand/brand.tsx +3 -3
- package/src/components/button-group/button-group.tsx +1 -1
- package/src/components/catalog.tsx +3 -1
- package/src/components/grid/grid.tsx +2 -2
- package/src/components/input-group/input-group.tsx +3 -2
- package/src/components/nav/nav.tsx +25 -19
- package/src/components/navbar/navbar.tsx +22 -14
- package/src/components/separator/separator.tsx +2 -1
- package/src/components/sidebar/index.ts +1 -1
- package/src/components/sidebar/sidebar.tsx +7 -7
- package/src/components/skeleton/skeleton.tsx +8 -10
- package/src/components/text/text.tsx +2 -2
- package/src/components/theme/index.ts +4 -4
- package/src/components/theme/theme.tsx +135 -99
- package/src/components.ts +4 -4
- package/src/overlays.ts +3 -3
- package/src/theme.ts +4 -4
- package/src/themes/default/styles/display/coverage.css +1 -1
- package/src/themes/default/styles/overlays/toast.css +1 -1
- package/src/themes/default/styles/shell/sidebar.css +1 -1
- package/templates/theme/styles/display/coverage.css +1 -1
- package/templates/theme/styles/overlays/toast.css +1 -1
- package/templates/theme/styles/shell/sidebar.css +1 -1
|
@@ -6,6 +6,7 @@ import { DropdownContent } from "../overlays/dropdown-content";
|
|
|
6
6
|
import type { NavBrandProps, NavDropdownProps, NavGroupProps, NavbarProps } from "./navbar.types";
|
|
7
7
|
|
|
8
8
|
const ASKR_FRAGMENT = Symbol.for("askr.fragment");
|
|
9
|
+
const LayoutBlock = Block as (props: Record<string, unknown>) => JSX.Element;
|
|
9
10
|
|
|
10
11
|
function flattenNavbarChildren(children: unknown): unknown[] {
|
|
11
12
|
return toChildArray(children).flatMap((child) => {
|
|
@@ -45,7 +46,7 @@ export function Navbar(props: NavbarProps): JSX.Element {
|
|
|
45
46
|
|
|
46
47
|
if (!collapseAt) {
|
|
47
48
|
return (
|
|
48
|
-
<
|
|
49
|
+
<LayoutBlock
|
|
49
50
|
as="nav"
|
|
50
51
|
direction="row"
|
|
51
52
|
align="center"
|
|
@@ -55,7 +56,7 @@ export function Navbar(props: NavbarProps): JSX.Element {
|
|
|
55
56
|
data-slot="navbar"
|
|
56
57
|
>
|
|
57
58
|
{children}
|
|
58
|
-
</
|
|
59
|
+
</LayoutBlock>
|
|
59
60
|
);
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -64,9 +65,9 @@ export function Navbar(props: NavbarProps): JSX.Element {
|
|
|
64
65
|
const navChildren = navbarChildren.filter((child) => !isNavBrandChild(child));
|
|
65
66
|
const hasNavContent = hasRenderableChildren(navChildren);
|
|
66
67
|
const content = (
|
|
67
|
-
<
|
|
68
|
+
<LayoutBlock direction="row" align="center" gap="md" width="full" data-slot="navbar-content">
|
|
68
69
|
{navChildren}
|
|
69
|
-
</
|
|
70
|
+
</LayoutBlock>
|
|
70
71
|
);
|
|
71
72
|
const collapse = hasNavContent ? (
|
|
72
73
|
<details data-slot="navbar-collapse">
|
|
@@ -79,7 +80,7 @@ export function Navbar(props: NavbarProps): JSX.Element {
|
|
|
79
80
|
) : null;
|
|
80
81
|
|
|
81
82
|
return (
|
|
82
|
-
<
|
|
83
|
+
<LayoutBlock
|
|
83
84
|
as="nav"
|
|
84
85
|
direction="row"
|
|
85
86
|
align="center"
|
|
@@ -90,7 +91,7 @@ export function Navbar(props: NavbarProps): JSX.Element {
|
|
|
90
91
|
data-slot="navbar"
|
|
91
92
|
>
|
|
92
93
|
{[...brandChildren, collapse]}
|
|
93
|
-
</
|
|
94
|
+
</LayoutBlock>
|
|
94
95
|
);
|
|
95
96
|
}
|
|
96
97
|
|
|
@@ -98,9 +99,16 @@ export function NavBrand(props: NavBrandProps): JSX.Element {
|
|
|
98
99
|
const { children, ...rest } = props;
|
|
99
100
|
|
|
100
101
|
return (
|
|
101
|
-
<
|
|
102
|
+
<LayoutBlock
|
|
103
|
+
direction="row"
|
|
104
|
+
align="center"
|
|
105
|
+
gap="sm"
|
|
106
|
+
shrink={false}
|
|
107
|
+
{...rest}
|
|
108
|
+
data-slot="nav-brand"
|
|
109
|
+
>
|
|
102
110
|
{children}
|
|
103
|
-
</
|
|
111
|
+
</LayoutBlock>
|
|
104
112
|
);
|
|
105
113
|
}
|
|
106
114
|
|
|
@@ -108,12 +116,12 @@ export function NavGroup(props: NavGroupProps): JSX.Element {
|
|
|
108
116
|
const { align, children, label, title = label, ...rest } = props;
|
|
109
117
|
|
|
110
118
|
return (
|
|
111
|
-
<
|
|
119
|
+
<LayoutBlock align={align} gap="sm" {...rest} data-align={align} data-slot="nav-group">
|
|
112
120
|
{title !== undefined ? <div data-slot="nav-group-label">{title}</div> : null}
|
|
113
|
-
<
|
|
121
|
+
<LayoutBlock gap="xs" data-slot="nav-group-body">
|
|
114
122
|
{children}
|
|
115
|
-
</
|
|
116
|
-
</
|
|
123
|
+
</LayoutBlock>
|
|
124
|
+
</LayoutBlock>
|
|
117
125
|
);
|
|
118
126
|
}
|
|
119
127
|
|
|
@@ -121,7 +129,7 @@ export function NavDropdown(props: NavDropdownProps): JSX.Element {
|
|
|
121
129
|
const { align = "end", children, label, side = "bottom", sideOffset = 6, ...rest } = props;
|
|
122
130
|
|
|
123
131
|
return (
|
|
124
|
-
<
|
|
132
|
+
<LayoutBlock direction="row" align="center" data-slot="nav-dropdown">
|
|
125
133
|
<Dropdown {...rest}>
|
|
126
134
|
<DropdownTrigger class={classes("nav-item")} data-slot="nav-dropdown-trigger">
|
|
127
135
|
{label}
|
|
@@ -136,6 +144,6 @@ export function NavDropdown(props: NavDropdownProps): JSX.Element {
|
|
|
136
144
|
{children}
|
|
137
145
|
</DropdownContent>
|
|
138
146
|
</Dropdown>
|
|
139
|
-
</
|
|
147
|
+
</LayoutBlock>
|
|
140
148
|
);
|
|
141
149
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Slot } from "@askrjs/askr/foundations";
|
|
2
2
|
import { mergeProps } from "../_internal/merge-props";
|
|
3
|
+
import { intrinsicElement } from "../_internal/jsx";
|
|
3
4
|
import type { SeparatorAsChildProps, SeparatorNativeProps } from "./separator.types";
|
|
4
5
|
|
|
5
6
|
export function Separator(props: SeparatorNativeProps): JSX.Element;
|
|
@@ -19,5 +20,5 @@ export function Separator(props: SeparatorNativeProps | SeparatorAsChildProps) {
|
|
|
19
20
|
return <Slot asChild {...finalProps} children={children} />;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
return
|
|
23
|
+
return intrinsicElement("div", finalProps, children);
|
|
23
24
|
}
|
|
@@ -2,6 +2,7 @@ import { Slot } from "@askrjs/askr/foundations";
|
|
|
2
2
|
import { Block } from "../block";
|
|
3
3
|
import { classes } from "../_internal/classes";
|
|
4
4
|
import { mergeProps } from "../_internal/merge-props";
|
|
5
|
+
import { intrinsicElement } from "../_internal/jsx";
|
|
5
6
|
import type {
|
|
6
7
|
SidebarButtonProps,
|
|
7
8
|
SidebarPartProps,
|
|
@@ -25,7 +26,6 @@ function sidebarPart(
|
|
|
25
26
|
element: keyof JSX.IntrinsicElements = "div",
|
|
26
27
|
): JSX.Element {
|
|
27
28
|
const { as, asChild, children, class: className, ...rest } = props;
|
|
28
|
-
const Element = (as ?? element) as "div";
|
|
29
29
|
const finalProps = mergeProps(rest, {
|
|
30
30
|
class: className,
|
|
31
31
|
"data-slot": slot,
|
|
@@ -35,7 +35,7 @@ function sidebarPart(
|
|
|
35
35
|
return <Slot asChild {...finalProps} children={children as JSX.Element} />;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
return
|
|
38
|
+
return intrinsicElement(String(as ?? element), finalProps, children);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export function Sidebar(props: SidebarProps): JSX.Element {
|
|
@@ -69,8 +69,8 @@ export function Sidebar(props: SidebarProps): JSX.Element {
|
|
|
69
69
|
);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export function
|
|
73
|
-
return sidebarPart(props, "sidebar-
|
|
72
|
+
export function SidebarScope(props: SidebarPartProps): JSX.Element {
|
|
73
|
+
return sidebarPart(props, "sidebar-scope");
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export function SidebarInset(props: SidebarPartProps): JSX.Element {
|
|
@@ -136,7 +136,7 @@ export function SidebarMenuButton(props: SidebarButtonProps): JSX.Element {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
return (
|
|
139
|
-
<button type={type} {...finalProps}>
|
|
139
|
+
<button type={type as "button" | "submit" | "reset" | undefined} {...finalProps}>
|
|
140
140
|
{children}
|
|
141
141
|
</button>
|
|
142
142
|
);
|
|
@@ -146,7 +146,7 @@ export function SidebarMenuAction(props: SidebarButtonProps): JSX.Element {
|
|
|
146
146
|
const { children, class: className, tooltip, tooltipSide, type = "button", ...rest } = props;
|
|
147
147
|
return (
|
|
148
148
|
<button
|
|
149
|
-
type={type}
|
|
149
|
+
type={type as "button" | "submit" | "reset" | undefined}
|
|
150
150
|
{...mergeProps(rest, {
|
|
151
151
|
class: classes(className),
|
|
152
152
|
"data-slot": "sidebar-menu-action",
|
|
@@ -170,7 +170,7 @@ export function SidebarTrigger(props: SidebarButtonProps): JSX.Element {
|
|
|
170
170
|
const { children, class: className, tooltip, tooltipSide, type = "button", ...rest } = props;
|
|
171
171
|
return (
|
|
172
172
|
<button
|
|
173
|
-
type={type}
|
|
173
|
+
type={type as "button" | "submit" | "reset" | undefined}
|
|
174
174
|
{...mergeProps(rest, {
|
|
175
175
|
class: classes("btn btn-ghost btn-icon", className),
|
|
176
176
|
"data-slot": "sidebar-trigger",
|
|
@@ -2,6 +2,7 @@ import { Slot } from "@askrjs/askr/foundations";
|
|
|
2
2
|
import { mergeLayoutStyles } from "../_internal/block-layout";
|
|
3
3
|
import { classes } from "../_internal/classes";
|
|
4
4
|
import { mergeProps } from "../_internal/merge-props";
|
|
5
|
+
import { intrinsicElement } from "../_internal/jsx";
|
|
5
6
|
import { styleDeclarationsToClass } from "../_internal/style";
|
|
6
7
|
import type { SkeletonAsChildProps, SkeletonProps } from "./skeleton.types";
|
|
7
8
|
|
|
@@ -28,15 +29,12 @@ export function Skeleton(props: SkeletonProps | SkeletonAsChildProps) {
|
|
|
28
29
|
className?: unknown;
|
|
29
30
|
style?: unknown;
|
|
30
31
|
};
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
style,
|
|
38
|
-
),
|
|
39
|
-
);
|
|
32
|
+
const dimensions: Record<string, string | number> = {};
|
|
33
|
+
const blockSize = resolveSkeletonDimension(height);
|
|
34
|
+
const inlineSize = resolveSkeletonDimension(width);
|
|
35
|
+
if (blockSize !== undefined) dimensions.blockSize = blockSize;
|
|
36
|
+
if (inlineSize !== undefined) dimensions.inlineSize = inlineSize;
|
|
37
|
+
const layoutClass = styleDeclarationsToClass(mergeLayoutStyles(dimensions, style));
|
|
40
38
|
const finalProps = mergeProps(rest, {
|
|
41
39
|
ref,
|
|
42
40
|
class: classes(classProp, className, layoutClass),
|
|
@@ -49,5 +47,5 @@ export function Skeleton(props: SkeletonProps | SkeletonAsChildProps) {
|
|
|
49
47
|
return <Slot asChild {...finalProps} children={children} />;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
return
|
|
50
|
+
return intrinsicElement("div", finalProps, children);
|
|
53
51
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { classes } from "../_internal/classes";
|
|
2
2
|
import { mergeProps } from "../_internal/merge-props";
|
|
3
|
+
import { intrinsicElement } from "../_internal/jsx";
|
|
3
4
|
import type { TextElement, TextProps } from "./text.types";
|
|
4
5
|
|
|
5
6
|
const DEFAULT_ELEMENT = "p";
|
|
@@ -34,6 +35,5 @@ export function Text<TElement extends TextElement = "p">(props: TextProps<TEleme
|
|
|
34
35
|
"data-truncate": truncate ? "true" : undefined,
|
|
35
36
|
});
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
return <Element {...finalProps}>{children}</Element>;
|
|
38
|
+
return intrinsicElement(as ?? DEFAULT_ELEMENT, finalProps, children);
|
|
39
39
|
}
|
|
@@ -3,17 +3,17 @@ export {
|
|
|
3
3
|
CAT_THEME_OPTIONS,
|
|
4
4
|
DEFAULT_THEME_OPTIONS,
|
|
5
5
|
ThemePicker,
|
|
6
|
-
|
|
6
|
+
ThemeScope,
|
|
7
7
|
ThemeToggle,
|
|
8
|
-
|
|
8
|
+
theme,
|
|
9
9
|
} from "./theme";
|
|
10
10
|
export type {
|
|
11
11
|
CatThemeName,
|
|
12
|
-
|
|
12
|
+
ThemeScopeValue,
|
|
13
13
|
ThemeName,
|
|
14
14
|
ThemeOption,
|
|
15
15
|
ThemePickerProps,
|
|
16
|
-
|
|
16
|
+
ThemeScopeProps,
|
|
17
17
|
ThemeToggleProps,
|
|
18
18
|
ThemeToggleRenderContext,
|
|
19
19
|
} from "./theme";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineScope, getSignal, readScope, state } from "@askrjs/askr";
|
|
2
2
|
import type { JSXElement } from "@askrjs/askr/foundations/structures";
|
|
3
|
-
import { resource } from "@askrjs/askr/resources";
|
|
4
3
|
import { Button } from "@askrjs/ui";
|
|
5
4
|
import type { ButtonNativeProps, PressEvent } from "@askrjs/ui";
|
|
6
5
|
|
|
@@ -14,14 +13,14 @@ export type ThemeOption = {
|
|
|
14
13
|
label: string;
|
|
15
14
|
};
|
|
16
15
|
|
|
17
|
-
export type
|
|
16
|
+
export type ThemeScopeValue = {
|
|
18
17
|
theme: () => ThemeName;
|
|
19
18
|
setTheme: (theme: ThemeName) => void;
|
|
20
19
|
themes: readonly ThemeOption[];
|
|
21
20
|
storageKey: string;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
|
-
export type
|
|
23
|
+
export type ThemeScopeProps = {
|
|
25
24
|
children?: unknown;
|
|
26
25
|
defaultTheme?: ThemeName;
|
|
27
26
|
themes?: readonly ThemeOption[];
|
|
@@ -67,23 +66,26 @@ export const CAT_THEME_OPTIONS: readonly ThemeOption[] = [
|
|
|
67
66
|
const DEFAULT_STORAGE_KEY = "askr-theme";
|
|
68
67
|
const STATIC_CHILDREN = Symbol.for("askr.static-children");
|
|
69
68
|
const STATIC_CHILD_SLOTS_CACHE = Symbol.for("__askrStaticChildSlots");
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
type ThemeCoordinator = ReturnType<typeof createThemeCoordinator>;
|
|
70
|
+
type InternalThemeScopeValue = ThemeScopeValue & {
|
|
71
|
+
readonly coordinator: ThemeCoordinator | null;
|
|
72
|
+
readonly depth: number;
|
|
73
|
+
};
|
|
74
74
|
|
|
75
|
-
const
|
|
75
|
+
const ThemeScopeContext = defineScope<InternalThemeScopeValue>({
|
|
76
76
|
theme: () => "system",
|
|
77
77
|
setTheme: () => undefined,
|
|
78
78
|
themes: DEFAULT_THEME_OPTIONS,
|
|
79
79
|
storageKey: DEFAULT_STORAGE_KEY,
|
|
80
|
+
coordinator: null,
|
|
81
|
+
depth: -1,
|
|
80
82
|
});
|
|
81
83
|
|
|
82
|
-
export function
|
|
83
|
-
return
|
|
84
|
+
export function theme(): ThemeScopeValue {
|
|
85
|
+
return readScope(ThemeScopeContext);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
export function
|
|
88
|
+
export function ThemeScope(props: ThemeScopeProps): JSX.Element {
|
|
87
89
|
const {
|
|
88
90
|
children,
|
|
89
91
|
defaultTheme = "system",
|
|
@@ -91,88 +93,142 @@ export function ThemeProvider(props: ThemeProviderProps): JSX.Element {
|
|
|
91
93
|
storageKey = DEFAULT_STORAGE_KEY,
|
|
92
94
|
} = props;
|
|
93
95
|
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
96
|
+
const scopeId = state<symbol>(Symbol("ThemeScope"))();
|
|
97
|
+
const scopeSignal = getSignal();
|
|
98
|
+
// The first render must be identical on the server and in the browser.
|
|
99
|
+
// Browser persistence is adopted from the committed root ref, after Askr's
|
|
100
|
+
// hydration verifier has accepted the server markup.
|
|
101
|
+
const themeState = state<ThemeName>(defaultTheme);
|
|
102
|
+
const persistenceAdoption = state({ complete: false })();
|
|
97
103
|
const currentTheme = themeState();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
() => {
|
|
104
|
-
if (explicitRootThemeOwner === providerId) {
|
|
105
|
-
explicitRootThemeOwner = undefined;
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
{ once: true },
|
|
109
|
-
);
|
|
110
|
-
}
|
|
104
|
+
const parentScope = readScope(ThemeScopeContext);
|
|
105
|
+
const ownedCoordinator = state<ThemeCoordinator>(createThemeCoordinator())();
|
|
106
|
+
const coordinator = parentScope.coordinator ?? ownedCoordinator;
|
|
107
|
+
const scopeDepth = parentScope.depth + 1;
|
|
108
|
+
coordinator.register(scopeId, scopeDepth, currentTheme, scopeSignal);
|
|
111
109
|
|
|
112
110
|
const setTheme = (nextTheme: ThemeName) => {
|
|
113
111
|
themeState.set(nextTheme);
|
|
114
112
|
writeStoredTheme(storageKey, nextTheme);
|
|
115
|
-
|
|
116
|
-
rootThemeRevision += 1;
|
|
117
|
-
syncThemeRoot(nextTheme);
|
|
113
|
+
coordinator.activate(scopeId, nextTheme);
|
|
118
114
|
};
|
|
119
115
|
|
|
120
|
-
const value:
|
|
116
|
+
const value: InternalThemeScopeValue = {
|
|
121
117
|
theme: themeState,
|
|
122
118
|
setTheme,
|
|
123
119
|
themes,
|
|
124
120
|
storageKey,
|
|
121
|
+
coordinator,
|
|
122
|
+
depth: scopeDepth,
|
|
125
123
|
};
|
|
126
124
|
|
|
127
125
|
return (
|
|
128
|
-
<
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
<ThemeScopeContext value={value}>
|
|
127
|
+
<div
|
|
128
|
+
data-slot="theme-scope"
|
|
129
|
+
ref={
|
|
130
|
+
parentScope.coordinator === null
|
|
131
|
+
? (element: HTMLElement | null) => {
|
|
132
|
+
coordinator.attach(element);
|
|
133
|
+
if (!element || persistenceAdoption.complete) return;
|
|
134
|
+
persistenceAdoption.complete = true;
|
|
135
|
+
const storedTheme = readStoredTheme(storageKey);
|
|
136
|
+
if (storedTheme && storedTheme !== themeState()) {
|
|
137
|
+
themeState.set(storedTheme);
|
|
138
|
+
coordinator.activate(scopeId, storedTheme);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
: undefined
|
|
142
|
+
}
|
|
143
|
+
>
|
|
144
|
+
{children}
|
|
145
|
+
</div>
|
|
146
|
+
</ThemeScopeContext>
|
|
132
147
|
);
|
|
133
148
|
}
|
|
134
149
|
|
|
135
|
-
function
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
150
|
+
function createThemeCoordinator() {
|
|
151
|
+
const scopes = new Map<
|
|
152
|
+
symbol,
|
|
153
|
+
{
|
|
154
|
+
depth: number;
|
|
155
|
+
sequence: number;
|
|
156
|
+
theme: ThemeName;
|
|
157
|
+
signal: AbortSignal;
|
|
158
|
+
}
|
|
159
|
+
>();
|
|
160
|
+
let nextSequence = 0;
|
|
161
|
+
let explicitOwner: symbol | undefined;
|
|
162
|
+
let root: Node | null = null;
|
|
163
|
+
let scheduled = false;
|
|
164
|
+
|
|
165
|
+
const target = (): HTMLElement | null => {
|
|
166
|
+
if (root?.nodeType === 9) return (root as Document).documentElement;
|
|
167
|
+
if (root && "host" in root) return (root as ShadowRoot).host as HTMLElement;
|
|
168
|
+
return typeof document === "undefined" ? null : document.documentElement;
|
|
169
|
+
};
|
|
170
|
+
const syncActive = (): void => {
|
|
171
|
+
if (explicitOwner !== undefined) return;
|
|
172
|
+
let candidate: { depth: number; sequence: number; theme: ThemeName } | undefined;
|
|
173
|
+
for (const scope of scopes.values()) {
|
|
174
|
+
if (
|
|
175
|
+
!candidate ||
|
|
176
|
+
scope.depth > candidate.depth ||
|
|
177
|
+
(scope.depth === candidate.depth && scope.sequence > candidate.sequence)
|
|
178
|
+
) {
|
|
179
|
+
candidate = scope;
|
|
144
180
|
}
|
|
181
|
+
}
|
|
182
|
+
if (candidate) syncThemeTarget(target(), candidate.theme);
|
|
183
|
+
};
|
|
184
|
+
const schedule = (): void => {
|
|
185
|
+
if (typeof document === "undefined" || scheduled) return;
|
|
186
|
+
scheduled = true;
|
|
187
|
+
setTimeout(() => {
|
|
188
|
+
scheduled = false;
|
|
189
|
+
syncActive();
|
|
190
|
+
}, 0);
|
|
191
|
+
};
|
|
145
192
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
passive: true,
|
|
151
|
-
providerId,
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}, 0);
|
|
155
|
-
|
|
156
|
-
signal.addEventListener(
|
|
157
|
-
"abort",
|
|
158
|
-
() => {
|
|
159
|
-
window.clearTimeout(timeoutId);
|
|
160
|
-
},
|
|
161
|
-
{ once: true },
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
return null;
|
|
193
|
+
return Object.freeze({
|
|
194
|
+
attach(element: HTMLElement | null) {
|
|
195
|
+
if (element) root = element.getRootNode();
|
|
196
|
+
schedule();
|
|
165
197
|
},
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
198
|
+
register(id: symbol, depth: number, themeName: ThemeName, signal: AbortSignal) {
|
|
199
|
+
const existing = scopes.get(id);
|
|
200
|
+
scopes.set(id, {
|
|
201
|
+
depth,
|
|
202
|
+
sequence: existing?.sequence ?? nextSequence++,
|
|
203
|
+
theme: themeName,
|
|
204
|
+
signal,
|
|
205
|
+
});
|
|
206
|
+
if (!existing) {
|
|
207
|
+
signal.addEventListener(
|
|
208
|
+
"abort",
|
|
209
|
+
() => {
|
|
210
|
+
scopes.delete(id);
|
|
211
|
+
if (explicitOwner === id) explicitOwner = undefined;
|
|
212
|
+
schedule();
|
|
213
|
+
},
|
|
214
|
+
{ once: true },
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
schedule();
|
|
218
|
+
},
|
|
219
|
+
activate(id: symbol, themeName: ThemeName) {
|
|
220
|
+
const scope = scopes.get(id);
|
|
221
|
+
if (scope) scope.theme = themeName;
|
|
222
|
+
explicitOwner = id;
|
|
223
|
+
syncThemeTarget(target(), themeName);
|
|
224
|
+
},
|
|
225
|
+
});
|
|
170
226
|
}
|
|
171
227
|
|
|
172
228
|
export function ThemePicker(props: ThemePickerProps): JSX.Element {
|
|
173
|
-
const
|
|
174
|
-
const { themes =
|
|
175
|
-
const currentTheme =
|
|
229
|
+
const activeTheme = theme();
|
|
230
|
+
const { themes = activeTheme.themes, label = "Theme", ...rest } = props;
|
|
231
|
+
const currentTheme = activeTheme.theme();
|
|
176
232
|
|
|
177
233
|
return (
|
|
178
234
|
<select
|
|
@@ -183,7 +239,7 @@ export function ThemePicker(props: ThemePickerProps): JSX.Element {
|
|
|
183
239
|
onChange={(event: Event) => {
|
|
184
240
|
const target = getThemePickerTarget(event);
|
|
185
241
|
if (target) {
|
|
186
|
-
|
|
242
|
+
activeTheme.setTheme(target.value as ThemeName);
|
|
187
243
|
}
|
|
188
244
|
}}
|
|
189
245
|
>
|
|
@@ -214,7 +270,7 @@ function getThemePickerTarget(event: Event): HTMLSelectElement | null {
|
|
|
214
270
|
}
|
|
215
271
|
|
|
216
272
|
export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
|
|
217
|
-
const
|
|
273
|
+
const activeTheme = theme();
|
|
218
274
|
const {
|
|
219
275
|
children,
|
|
220
276
|
lightIcon,
|
|
@@ -225,7 +281,7 @@ export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
|
|
|
225
281
|
...rest
|
|
226
282
|
} = props;
|
|
227
283
|
|
|
228
|
-
const currentTheme =
|
|
284
|
+
const currentTheme = activeTheme.theme();
|
|
229
285
|
const nextTheme = getNextTheme(currentTheme, themes, getResolvedSystemTheme());
|
|
230
286
|
const renderContext = { theme: currentTheme, nextTheme };
|
|
231
287
|
const ariaLabel = (rest as Record<string, unknown>)["aria-label"];
|
|
@@ -254,7 +310,7 @@ export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
|
|
|
254
310
|
onPress={(event) => {
|
|
255
311
|
onPress?.(event);
|
|
256
312
|
if (!event.defaultPrevented && !Object.is(nextTheme, currentTheme)) {
|
|
257
|
-
|
|
313
|
+
activeTheme.setTheme(nextTheme);
|
|
258
314
|
}
|
|
259
315
|
}}
|
|
260
316
|
>
|
|
@@ -348,7 +404,7 @@ function isJSXElement(value: unknown): value is JSXElement {
|
|
|
348
404
|
function cloneThemeToggleIcon(icon: unknown, key?: string): unknown {
|
|
349
405
|
if (Array.isArray(icon)) {
|
|
350
406
|
const clonedChildren = icon.map((child) => cloneThemeToggleIcon(child));
|
|
351
|
-
if ((icon as Record<symbol, unknown>)[STATIC_CHILDREN] === true) {
|
|
407
|
+
if ((icon as unknown as Record<symbol, unknown>)[STATIC_CHILDREN] === true) {
|
|
352
408
|
Object.defineProperty(clonedChildren, STATIC_CHILDREN, {
|
|
353
409
|
value: true,
|
|
354
410
|
configurable: true,
|
|
@@ -377,31 +433,11 @@ function cloneThemeToggleIcon(icon: unknown, key?: string): unknown {
|
|
|
377
433
|
return clonedIcon;
|
|
378
434
|
}
|
|
379
435
|
|
|
380
|
-
function
|
|
436
|
+
function syncThemeTarget(
|
|
437
|
+
html: HTMLElement | null,
|
|
381
438
|
themeChoice: ThemeName | null | undefined,
|
|
382
|
-
options?: { expectedRevision?: number; passive?: boolean; providerId?: symbol },
|
|
383
439
|
): void {
|
|
384
|
-
if (
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
const html = document.documentElement;
|
|
389
|
-
|
|
390
|
-
if (
|
|
391
|
-
options?.passive &&
|
|
392
|
-
options.expectedRevision !== undefined &&
|
|
393
|
-
options.expectedRevision !== rootThemeRevision
|
|
394
|
-
) {
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (
|
|
399
|
-
options?.passive &&
|
|
400
|
-
explicitRootThemeOwner !== undefined &&
|
|
401
|
-
explicitRootThemeOwner !== options.providerId
|
|
402
|
-
) {
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
440
|
+
if (!html) return;
|
|
405
441
|
|
|
406
442
|
if (themeChoice == null) {
|
|
407
443
|
html.removeAttribute("data-theme");
|
package/src/components.ts
CHANGED
|
@@ -141,7 +141,7 @@ export {
|
|
|
141
141
|
ToastAction,
|
|
142
142
|
ToastClose,
|
|
143
143
|
ToastDescription,
|
|
144
|
-
|
|
144
|
+
ToastHost,
|
|
145
145
|
ToastTitle,
|
|
146
146
|
ToastViewport,
|
|
147
147
|
Toggle,
|
|
@@ -240,7 +240,7 @@ export {
|
|
|
240
240
|
SidebarMenuBadge,
|
|
241
241
|
SidebarMenuButton,
|
|
242
242
|
SidebarMenuItem,
|
|
243
|
-
|
|
243
|
+
SidebarScope,
|
|
244
244
|
SidebarRail,
|
|
245
245
|
SidebarTrigger,
|
|
246
246
|
} from "./components/sidebar";
|
|
@@ -254,9 +254,9 @@ export {
|
|
|
254
254
|
CAT_THEME_OPTIONS,
|
|
255
255
|
DEFAULT_THEME_OPTIONS,
|
|
256
256
|
ThemePicker,
|
|
257
|
-
|
|
257
|
+
ThemeScope,
|
|
258
258
|
ThemeToggle,
|
|
259
|
-
|
|
259
|
+
theme,
|
|
260
260
|
} from "./components/theme";
|
|
261
261
|
export * from "./components/catalog";
|
|
262
262
|
|
package/src/overlays.ts
CHANGED
|
@@ -34,7 +34,7 @@ export {
|
|
|
34
34
|
ToastAction,
|
|
35
35
|
ToastClose,
|
|
36
36
|
ToastDescription,
|
|
37
|
-
|
|
37
|
+
ToastHost,
|
|
38
38
|
ToastTitle,
|
|
39
39
|
ToastViewport,
|
|
40
40
|
Tooltip,
|
|
@@ -115,8 +115,8 @@ export type {
|
|
|
115
115
|
ToastDescriptionProps,
|
|
116
116
|
ToastOwnProps,
|
|
117
117
|
ToastProps,
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
ToastHostOwnProps,
|
|
119
|
+
ToastHostProps,
|
|
120
120
|
ToastTitleAsChildProps,
|
|
121
121
|
ToastTitleProps,
|
|
122
122
|
ToastViewportAsChildProps,
|
package/src/theme.ts
CHANGED
|
@@ -5,17 +5,17 @@ export {
|
|
|
5
5
|
CAT_THEME_OPTIONS,
|
|
6
6
|
DEFAULT_THEME_OPTIONS,
|
|
7
7
|
ThemePicker,
|
|
8
|
-
|
|
8
|
+
ThemeScope,
|
|
9
9
|
ThemeToggle,
|
|
10
|
-
|
|
10
|
+
theme,
|
|
11
11
|
} from "./components/theme";
|
|
12
12
|
export type {
|
|
13
13
|
CatThemeName,
|
|
14
|
-
|
|
14
|
+
ThemeScopeValue,
|
|
15
15
|
ThemeName,
|
|
16
16
|
ThemeOption,
|
|
17
17
|
ThemePickerProps,
|
|
18
|
-
|
|
18
|
+
ThemeScopeProps,
|
|
19
19
|
ThemeToggleProps,
|
|
20
20
|
ThemeToggleRenderContext,
|
|
21
21
|
} from "./components/theme";
|