@askrjs/themes 0.0.7 → 0.0.9

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.
Files changed (51) hide show
  1. package/THEMING.md +5 -1
  2. package/dist/components/_internal/box-layout.js +1 -1
  3. package/dist/components/_internal/classes.js.map +1 -1
  4. package/dist/components/_internal/jsx.js.map +1 -1
  5. package/dist/components/_internal/layout.js +2 -7
  6. package/dist/components/_internal/layout.js.map +1 -1
  7. package/dist/components/_internal/style.js +25 -1
  8. package/dist/components/_internal/style.js.map +1 -1
  9. package/dist/components/aspect-ratio/aspect-ratio.js +1 -1
  10. package/dist/components/block/block.js.map +1 -1
  11. package/dist/components/container/container.js.map +1 -1
  12. package/dist/components/flex/flex.js.map +1 -1
  13. package/dist/components/nav/nav.js.map +1 -1
  14. package/dist/components/navbar/navbar-panel.js +10 -16
  15. package/dist/components/navbar/navbar-panel.js.map +1 -1
  16. package/dist/components/navbar/navbar.js +23 -12
  17. package/dist/components/navbar/navbar.js.map +1 -1
  18. package/dist/components/section/section.js.map +1 -1
  19. package/dist/components/shell/shell-responsive.js +51 -20
  20. package/dist/components/shell/shell-responsive.js.map +1 -1
  21. package/dist/components/sidebar/sidebar-panel.js +14 -24
  22. package/dist/components/sidebar/sidebar-panel.js.map +1 -1
  23. package/dist/components/sidebar/sidebar.js +38 -24
  24. package/dist/components/sidebar/sidebar.js.map +1 -1
  25. package/dist/components/spacer/spacer.js +1 -1
  26. package/dist/components/spacer/spacer.js.map +1 -1
  27. package/dist/components/theme/theme.js +55 -13
  28. package/dist/components/theme/theme.js.map +1 -1
  29. package/dist/themes/default/index.css +35 -3
  30. package/package.json +11 -10
  31. package/src/components/_internal/jsx.ts +18 -6
  32. package/src/components/_internal/layout.ts +3 -12
  33. package/src/components/_internal/style.ts +42 -4
  34. package/src/components/navbar/navbar-panel.tsx +11 -16
  35. package/src/components/navbar/navbar.tsx +32 -17
  36. package/src/components/shell/shell-responsive.tsx +79 -29
  37. package/src/components/sidebar/sidebar-panel.tsx +15 -24
  38. package/src/components/sidebar/sidebar.tsx +52 -34
  39. package/src/components/theme/theme.tsx +88 -16
  40. package/src/themes/default/styles/actions/button.css +16 -0
  41. package/src/themes/default/styles/display/avatar.css +7 -1
  42. package/src/themes/default/styles/display/badge.css +2 -1
  43. package/src/themes/default/styles/display/table.css +2 -0
  44. package/src/themes/default/styles/forms/select.css +6 -0
  45. package/src/themes/default/styles/shell/navbar.css +2 -1
  46. package/templates/theme/styles/actions/button.css +16 -0
  47. package/templates/theme/styles/display/avatar.css +7 -1
  48. package/templates/theme/styles/display/badge.css +2 -1
  49. package/templates/theme/styles/display/table.css +2 -0
  50. package/templates/theme/styles/forms/select.css +6 -0
  51. package/templates/theme/styles/shell/navbar.css +2 -1
@@ -3,6 +3,19 @@ import { renderShellPanel } from "../shell/shell-panel";
3
3
  import { SidebarResponsiveContext } from "./sidebar.context";
4
4
  import type { SidebarPanelProps } from "./sidebar.types";
5
5
 
6
+ const DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT = {
7
+ active: () => false,
8
+ collapseLabel: () => "Menu",
9
+ closePanel: () => undefined,
10
+ iconCollapsed: () => false,
11
+ isRailCollapsible: () => false,
12
+ orientation: () => "vertical" as const,
13
+ panelId: () => undefined,
14
+ panelOpen: () => false,
15
+ togglePanel: () => undefined,
16
+ toggleRail: () => undefined,
17
+ };
18
+
6
19
  export function SidebarPanel(props: SidebarPanelProps): JSX.Element | null {
7
20
  const {
8
21
  active: activeProp,
@@ -27,32 +40,10 @@ export function SidebarPanel(props: SidebarPanelProps): JSX.Element | null {
27
40
  try {
28
41
  return readContext(SidebarResponsiveContext);
29
42
  } catch {
30
- return {
31
- active: () => false,
32
- collapseLabel: () => "Menu",
33
- closePanel: () => undefined,
34
- iconCollapsed: () => false,
35
- isRailCollapsible: () => false,
36
- orientation: () => "vertical" as const,
37
- panelId: () => undefined,
38
- panelOpen: () => false,
39
- togglePanel: () => undefined,
40
- toggleRail: () => undefined,
41
- };
43
+ return DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;
42
44
  }
43
45
  })()
44
- : {
45
- active: () => false,
46
- collapseLabel: () => "Menu",
47
- closePanel: () => undefined,
48
- iconCollapsed: () => false,
49
- isRailCollapsible: () => false,
50
- orientation: () => "vertical" as const,
51
- panelId: () => undefined,
52
- panelOpen: () => false,
53
- togglePanel: () => undefined,
54
- toggleRail: () => undefined,
55
- };
46
+ : DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;
56
47
  const active = activeProp ?? responsive.active();
57
48
  const open = openProp ?? responsive.panelOpen();
58
49
  const panelId = panelIdProp ?? responsive.panelId();
@@ -19,7 +19,10 @@ import type { CollapseIconPlacement } from "../shell/shell-nav.types";
19
19
 
20
20
  type SidebarChildren = {
21
21
  brand?: unknown;
22
- items: unknown[];
22
+ drawerItems: unknown[];
23
+ drawerSourceItems: unknown[];
24
+ explicitPanelItems: unknown[];
25
+ toggle?: SidebarToggleConfig;
23
26
  };
24
27
 
25
28
  type SidebarToggleConfig = {
@@ -27,38 +30,49 @@ type SidebarToggleConfig = {
27
30
  expandedIcon?: unknown;
28
31
  };
29
32
 
33
+ function isSidebarToggleChild(child: unknown): boolean {
34
+ return isJsxElement(child) && child.type === SidebarToggle;
35
+ }
36
+
30
37
  function splitSidebarChildren(children: unknown[]): SidebarChildren {
31
- const brandIndex = children.findIndex((child) => isJsxElement(child) && child.type === NavBrand);
38
+ const explicitPanelItems: unknown[] = [];
39
+ const drawerSourceItems: unknown[] = [];
40
+ let drawerItems: unknown[] | undefined;
41
+ let brand: unknown;
42
+ let hasBrand = false;
43
+ let hasToggle = false;
44
+ let toggle: SidebarToggleConfig | undefined;
32
45
 
33
- if (brandIndex === -1) {
34
- return { items: children };
35
- }
46
+ for (const child of children) {
47
+ if (isShellPanelChild(child, SidebarPanel)) {
48
+ explicitPanelItems.push(child);
49
+ continue;
50
+ }
36
51
 
37
- return {
38
- brand: children[brandIndex],
39
- items: children.filter((_, index) => index !== brandIndex),
40
- };
41
- }
52
+ if (!hasToggle && isSidebarToggleChild(child)) {
53
+ hasToggle = true;
54
+ toggle = (child as { props?: SidebarToggleConfig } | undefined)?.props;
55
+ continue;
56
+ }
42
57
 
43
- function isSidebarToggleChild(child: unknown): boolean {
44
- return isJsxElement(child) && child.type === SidebarToggle;
45
- }
58
+ drawerSourceItems.push(child);
46
59
 
47
- function splitSidebarToggle(children: unknown[]): {
48
- items: unknown[];
49
- toggle?: SidebarToggleConfig;
50
- } {
51
- const toggleIndex = children.findIndex((child) => isSidebarToggleChild(child));
60
+ if (!hasBrand && isJsxElement(child) && child.type === NavBrand) {
61
+ brand = child;
62
+ hasBrand = true;
63
+ drawerItems ??= drawerSourceItems.slice(0, drawerSourceItems.length - 1);
64
+ continue;
65
+ }
52
66
 
53
- if (toggleIndex === -1) {
54
- return { items: children };
67
+ drawerItems?.push(child);
55
68
  }
56
69
 
57
- const toggleChild = children[toggleIndex] as { props?: SidebarToggleConfig } | undefined;
58
-
59
70
  return {
60
- items: children.filter((_, index) => index !== toggleIndex),
61
- toggle: toggleChild?.props,
71
+ brand: hasBrand ? brand : undefined,
72
+ drawerItems: drawerItems ?? drawerSourceItems,
73
+ drawerSourceItems,
74
+ explicitPanelItems,
75
+ toggle,
62
76
  };
63
77
  }
64
78
 
@@ -152,8 +166,7 @@ export function Sidebar(props: SidebarProps): JSX.Element {
152
166
  const effectiveCollapseLabel =
153
167
  collapseLabel ?? (typeof ariaLabel === "string" ? ariaLabel : undefined) ?? "Menu";
154
168
  const childItems = toChildArray(children);
155
- const explicitPanelItems = childItems.filter((child) => isShellPanelChild(child, SidebarPanel));
156
- const contentItems = childItems.filter((child) => !isShellPanelChild(child, SidebarPanel));
169
+ const sidebarChildren = splitSidebarChildren(childItems);
157
170
  const isResponsive = breakpoint !== undefined;
158
171
  const responsiveCollapsedState = state(isResponsive ? isSidebarCollapsed(breakpoint) : false);
159
172
  const drawerOpenState = state(false);
@@ -202,10 +215,11 @@ export function Sidebar(props: SidebarProps): JSX.Element {
202
215
 
203
216
  setRailCollapsed(!isRailCollapsed);
204
217
  };
205
- const { items: drawerSourceItems, toggle: railToggleConfig } = splitSidebarToggle(contentItems);
206
- const { brand: drawerBrand, items: drawerItems } = splitSidebarChildren(drawerSourceItems);
207
- const desktopChildren = renderKeyedShellChildren(drawerSourceItems, "sidebar-desktop");
208
- const drawerChildren = renderKeyedShellChildren(drawerItems, "sidebar-drawer");
218
+ const desktopChildren = renderKeyedShellChildren(
219
+ sidebarChildren.drawerSourceItems,
220
+ "sidebar-desktop",
221
+ );
222
+ const drawerChildren = renderKeyedShellChildren(sidebarChildren.drawerItems, "sidebar-drawer");
209
223
 
210
224
  const contextValue = {
211
225
  active: () => isResponsive,
@@ -227,12 +241,16 @@ export function Sidebar(props: SidebarProps): JSX.Element {
227
241
  panelId,
228
242
  };
229
243
  const panels =
230
- explicitPanelItems.length > 0 ? (
231
- renderKeyedShellPanelChildren(explicitPanelItems, "sidebar-panel", panelContext)
244
+ sidebarChildren.explicitPanelItems.length > 0 ? (
245
+ renderKeyedShellPanelChildren(
246
+ sidebarChildren.explicitPanelItems,
247
+ "sidebar-panel",
248
+ panelContext,
249
+ )
232
250
  ) : isResponsive ? (
233
251
  <SidebarPanel
234
252
  active={isResponsive}
235
- brand={drawerBrand}
253
+ brand={sidebarChildren.brand}
236
254
  collapseLabel={effectiveCollapseLabel}
237
255
  onClose={closeDrawer}
238
256
  onClick={closeDrawerOnNavActivation}
@@ -305,7 +323,7 @@ export function Sidebar(props: SidebarProps): JSX.Element {
305
323
  {renderSidebarRailContents(
306
324
  effectiveCollapseLabel,
307
325
  isRailCollapsed,
308
- railToggleConfig,
326
+ sidebarChildren.toggle,
309
327
  )}
310
328
  </button>
311
329
  </div>
@@ -1,4 +1,4 @@
1
- import { defineContext, readContext, state } from "@askrjs/askr";
1
+ import { defineContext, getSignal, readContext, state } from "@askrjs/askr";
2
2
  import type { JSXElement } from "@askrjs/askr/foundations/structures";
3
3
  import { resource } from "@askrjs/askr/resources";
4
4
  import { Button } from "@askrjs/ui";
@@ -65,6 +65,10 @@ export const CAT_THEME_OPTIONS: readonly ThemeOption[] = [
65
65
  ];
66
66
 
67
67
  const DEFAULT_STORAGE_KEY = "askr-theme";
68
+ // Passive mount sync should not overwrite a newer user/provider-initiated change.
69
+ let rootThemeRevision = 0;
70
+ let explicitRootThemeOwner: symbol | undefined;
71
+ const registeredProviderSignals = new WeakSet<AbortSignal>();
68
72
 
69
73
  const ThemeContext = defineContext<ThemeContextValue>({
70
74
  theme: () => "system",
@@ -85,11 +89,29 @@ export function ThemeProvider(props: ThemeProviderProps): JSX.Element {
85
89
  storageKey = DEFAULT_STORAGE_KEY,
86
90
  } = props;
87
91
 
92
+ const providerId = state<symbol>(Symbol("ThemeProvider"))();
93
+ const providerSignal = getSignal();
88
94
  const themeState = state<ThemeName>(readStoredTheme(storageKey) ?? defaultTheme);
95
+ const currentTheme = themeState();
96
+
97
+ if (!registeredProviderSignals.has(providerSignal)) {
98
+ registeredProviderSignals.add(providerSignal);
99
+ providerSignal.addEventListener(
100
+ "abort",
101
+ () => {
102
+ if (explicitRootThemeOwner === providerId) {
103
+ explicitRootThemeOwner = undefined;
104
+ }
105
+ },
106
+ { once: true },
107
+ );
108
+ }
89
109
 
90
110
  const setTheme = (nextTheme: ThemeName) => {
91
111
  themeState.set(nextTheme);
92
112
  writeStoredTheme(storageKey, nextTheme);
113
+ explicitRootThemeOwner = providerId;
114
+ rootThemeRevision += 1;
93
115
  syncThemeRoot(nextTheme);
94
116
  };
95
117
 
@@ -100,18 +122,17 @@ export function ThemeProvider(props: ThemeProviderProps): JSX.Element {
100
122
  storageKey,
101
123
  };
102
124
 
103
- const currentTheme = themeState();
104
-
105
125
  return (
106
126
  <ThemeContext.Scope value={value}>
107
- <ThemeRootSync theme={currentTheme} />
127
+ <ThemeRootSync providerId={providerId} theme={currentTheme} />
108
128
  <div data-slot="theme-provider">{children}</div>
109
129
  </ThemeContext.Scope>
110
130
  );
111
131
  }
112
132
 
113
- function ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {
114
- const { theme } = props;
133
+ function ThemeRootSync(props: { providerId: symbol; theme: ThemeName }): JSX.Element | null {
134
+ const { providerId, theme } = props;
135
+ const expectedRootThemeRevision = rootThemeRevision;
115
136
 
116
137
  resource(
117
138
  ({ signal }: { signal: AbortSignal }) => {
@@ -122,7 +143,11 @@ function ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {
122
143
 
123
144
  const timeoutId = window.setTimeout(() => {
124
145
  if (!signal.aborted) {
125
- syncThemeRoot(theme);
146
+ syncThemeRoot(theme, {
147
+ expectedRevision: expectedRootThemeRevision,
148
+ passive: true,
149
+ providerId,
150
+ });
126
151
  }
127
152
  }, 0);
128
153
 
@@ -145,20 +170,23 @@ function ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {
145
170
  export function ThemePicker(props: ThemePickerProps): JSX.Element {
146
171
  const theme = useTheme();
147
172
  const { themes = theme.themes, label = "Theme", ...rest } = props;
173
+ const currentTheme = theme.theme();
148
174
 
149
175
  return (
150
176
  <select
151
177
  {...rest}
152
178
  aria-label={rest["aria-label"] ?? label}
153
179
  data-slot="theme-picker"
154
- value={theme.theme()}
180
+ value={currentTheme}
155
181
  onChange={(event: Event) => {
156
- const target = event.currentTarget as HTMLSelectElement;
157
- theme.setTheme(target.value as ThemeName);
182
+ const target = getThemePickerTarget(event);
183
+ if (target) {
184
+ theme.setTheme(target.value as ThemeName);
185
+ }
158
186
  }}
159
187
  >
160
188
  {themes.map((option) => (
161
- <option key={option.value} value={option.value}>
189
+ <option key={option.value} value={option.value} selected={option.value === currentTheme}>
162
190
  {option.label}
163
191
  </option>
164
192
  ))}
@@ -166,6 +194,23 @@ export function ThemePicker(props: ThemePickerProps): JSX.Element {
166
194
  );
167
195
  }
168
196
 
197
+ function getThemePickerTarget(event: Event): HTMLSelectElement | null {
198
+ if (typeof HTMLSelectElement === "undefined") {
199
+ return null;
200
+ }
201
+
202
+ const path = typeof event.composedPath === "function" ? event.composedPath() : [];
203
+ const candidates = [event.target, event.currentTarget, ...path];
204
+
205
+ for (const candidate of candidates) {
206
+ if (candidate instanceof HTMLSelectElement) {
207
+ return candidate;
208
+ }
209
+ }
210
+
211
+ return null;
212
+ }
213
+
169
214
  export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
170
215
  const theme = useTheme();
171
216
  const {
@@ -200,10 +245,12 @@ export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
200
245
  data-next-theme={nextTheme}
201
246
  onPress={(event) => {
202
247
  onPress?.(event);
203
- if (!event.defaultPrevented) theme.setTheme(nextTheme);
248
+ if (!event.defaultPrevented && !Object.is(nextTheme, currentTheme)) {
249
+ theme.setTheme(nextTheme);
250
+ }
204
251
  }}
205
252
  >
206
- {content}
253
+ <span data-slot="theme-toggle-content">{content}</span>
207
254
  </Button>
208
255
  );
209
256
  }
@@ -245,19 +292,43 @@ function isJSXElement(value: unknown): value is JSXElement {
245
292
  function cloneThemeToggleIcon(icon: unknown): unknown {
246
293
  if (!isJSXElement(icon)) return icon;
247
294
 
295
+ const props = icon.props as Record<string, unknown> | undefined;
296
+ if (!props || Object.keys(props).length === 0) {
297
+ return icon;
298
+ }
299
+
248
300
  return {
249
301
  ...icon,
250
- props: { ...(icon.props as Record<string, unknown> | undefined) },
302
+ props: { ...props },
251
303
  };
252
304
  }
253
305
 
254
- function syncThemeRoot(themeChoice: ThemeName | null | undefined): void {
306
+ function syncThemeRoot(
307
+ themeChoice: ThemeName | null | undefined,
308
+ options?: { expectedRevision?: number; passive?: boolean; providerId?: symbol },
309
+ ): void {
255
310
  if (typeof document === "undefined") {
256
311
  return;
257
312
  }
258
313
 
259
314
  const html = document.documentElement;
260
315
 
316
+ if (
317
+ options?.passive &&
318
+ options.expectedRevision !== undefined &&
319
+ options.expectedRevision !== rootThemeRevision
320
+ ) {
321
+ return;
322
+ }
323
+
324
+ if (
325
+ options?.passive &&
326
+ explicitRootThemeOwner !== undefined &&
327
+ explicitRootThemeOwner !== options.providerId
328
+ ) {
329
+ return;
330
+ }
331
+
261
332
  if (themeChoice == null) {
262
333
  html.removeAttribute("data-theme");
263
334
  html.removeAttribute("data-theme-choice");
@@ -276,7 +347,8 @@ function syncThemeRoot(themeChoice: ThemeName | null | undefined): void {
276
347
  function readStoredTheme(storageKey: string): ThemeName | undefined {
277
348
  if (typeof window === "undefined") return undefined;
278
349
  try {
279
- return (window.localStorage.getItem(storageKey) as ThemeName | null) ?? undefined;
350
+ const storedTheme = window.localStorage.getItem(storageKey);
351
+ return storedTheme ? (storedTheme as ThemeName) : undefined;
280
352
  } catch {
281
353
  return undefined;
282
354
  }
@@ -35,6 +35,22 @@
35
35
  opacity var(--ak-duration-fast) var(--ak-ease-standard);
36
36
  }
37
37
 
38
+ :where([data-slot="theme-toggle-content"]) {
39
+ --_ak-theme-toggle-icon-size: var(--ak-theme-toggle-icon-size, var(--ak-icon-size, 1em));
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ flex: none;
44
+ min-inline-size: 0;
45
+ }
46
+
47
+ :where([data-slot="theme-toggle-content"]) > :where([data-slot="icon"], svg) {
48
+ flex: none;
49
+ inline-size: var(--_ak-theme-toggle-icon-size);
50
+ block-size: var(--_ak-theme-toggle-icon-size);
51
+ color: currentColor;
52
+ }
53
+
38
54
  :where(.btn) > :where([data-slot="icon"], svg),
39
55
  :where([data-slot="button"]) > :where([data-slot="icon"], svg) {
40
56
  flex: none;
@@ -19,12 +19,18 @@
19
19
  }
20
20
 
21
21
  :where(.avatar-fallback, [data-slot="avatar-fallback"]) {
22
+ box-sizing: border-box;
22
23
  display: inline-grid;
23
24
  place-items: center;
24
25
  inline-size: 100%;
25
26
  block-size: 100%;
27
+ min-inline-size: 0;
28
+ max-inline-size: 100%;
26
29
  font-size: var(--ak-font-size-sm);
27
30
  font-weight: var(--ak-font-weight-semibold);
28
31
  line-height: 1;
29
- overflow-wrap: anywhere;
32
+ overflow: hidden;
33
+ overflow-wrap: normal;
34
+ text-overflow: ellipsis;
35
+ white-space: nowrap;
30
36
  }
@@ -15,7 +15,8 @@
15
15
  font-weight: var(--ak-font-weight-semibold);
16
16
  line-height: 1;
17
17
  letter-spacing: 0;
18
- overflow-wrap: anywhere;
18
+ overflow-wrap: normal;
19
+ word-break: normal;
19
20
  }
20
21
 
21
22
  :where(.badge, [data-slot="badge"]) > :where([data-slot="icon"]) {
@@ -57,7 +57,9 @@
57
57
  color: var(--ak-color-text-muted);
58
58
  font-weight: var(--ak-font-weight-semibold);
59
59
  letter-spacing: 0.04em;
60
+ overflow-wrap: normal;
60
61
  text-transform: uppercase;
62
+ word-break: normal;
61
63
  white-space: normal;
62
64
  }
63
65
 
@@ -125,16 +125,22 @@
125
125
  }
126
126
 
127
127
  :where(.select-item, [data-slot="select-item"]) {
128
+ appearance: none;
128
129
  display: flex;
129
130
  align-items: center;
131
+ inline-size: 100%;
130
132
  min-height: var(--ak-density-control-height-md);
131
133
  padding: 0 var(--ak-density-control-padding-x-md);
134
+ border: 0;
132
135
  border-radius: var(--ak-radius-md);
136
+ background: transparent;
133
137
  color: var(--ak-color-text);
134
138
  cursor: pointer;
139
+ font-family: inherit;
135
140
  font-size: var(--ak-font-size-sm);
136
141
  font-weight: var(--ak-font-weight-medium);
137
142
  overflow-wrap: anywhere;
143
+ text-align: start;
138
144
  transition:
139
145
  background var(--ak-duration-fast) var(--ak-ease-standard),
140
146
  color var(--ak-duration-fast) var(--ak-ease-standard);
@@ -1,6 +1,7 @@
1
1
  @layer components {
2
2
  :where(.navbar, [data-slot="navbar"]) {
3
3
  position: relative;
4
+ container-type: inline-size;
4
5
  display: flex;
5
6
  flex-direction: column;
6
7
  align-items: stretch;
@@ -157,7 +158,7 @@
157
158
  min-inline-size: 0;
158
159
  }
159
160
 
160
- @media (min-width: 48rem) {
161
+ @container (min-width: 48rem) {
161
162
  :where(.navbar-shell, [data-slot="navbar-shell"]):has(
162
163
  > :where(.navbar-group[data-align="center"], [data-slot="navbar-group"][data-align="center"])
163
164
  ) {
@@ -35,6 +35,22 @@
35
35
  opacity var(--ak-duration-fast) var(--ak-ease-standard);
36
36
  }
37
37
 
38
+ :where([data-slot="theme-toggle-content"]) {
39
+ --_ak-theme-toggle-icon-size: var(--ak-theme-toggle-icon-size, var(--ak-icon-size, 1em));
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ flex: none;
44
+ min-inline-size: 0;
45
+ }
46
+
47
+ :where([data-slot="theme-toggle-content"]) > :where([data-slot="icon"], svg) {
48
+ flex: none;
49
+ inline-size: var(--_ak-theme-toggle-icon-size);
50
+ block-size: var(--_ak-theme-toggle-icon-size);
51
+ color: currentColor;
52
+ }
53
+
38
54
  :where(.btn) > :where([data-slot="icon"], svg),
39
55
  :where([data-slot="button"]) > :where([data-slot="icon"], svg) {
40
56
  flex: none;
@@ -19,12 +19,18 @@
19
19
  }
20
20
 
21
21
  :where(.avatar-fallback, [data-slot="avatar-fallback"]) {
22
+ box-sizing: border-box;
22
23
  display: inline-grid;
23
24
  place-items: center;
24
25
  inline-size: 100%;
25
26
  block-size: 100%;
27
+ min-inline-size: 0;
28
+ max-inline-size: 100%;
26
29
  font-size: var(--ak-font-size-sm);
27
30
  font-weight: var(--ak-font-weight-semibold);
28
31
  line-height: 1;
29
- overflow-wrap: anywhere;
32
+ overflow: hidden;
33
+ overflow-wrap: normal;
34
+ text-overflow: ellipsis;
35
+ white-space: nowrap;
30
36
  }
@@ -15,7 +15,8 @@
15
15
  font-weight: var(--ak-font-weight-semibold);
16
16
  line-height: 1;
17
17
  letter-spacing: 0;
18
- overflow-wrap: anywhere;
18
+ overflow-wrap: normal;
19
+ word-break: normal;
19
20
  }
20
21
 
21
22
  :where(.badge, [data-slot="badge"]) > :where([data-slot="icon"]) {
@@ -57,7 +57,9 @@
57
57
  color: var(--ak-color-text-muted);
58
58
  font-weight: var(--ak-font-weight-semibold);
59
59
  letter-spacing: 0.04em;
60
+ overflow-wrap: normal;
60
61
  text-transform: uppercase;
62
+ word-break: normal;
61
63
  white-space: normal;
62
64
  }
63
65
 
@@ -125,16 +125,22 @@
125
125
  }
126
126
 
127
127
  :where(.select-item, [data-slot="select-item"]) {
128
+ appearance: none;
128
129
  display: flex;
129
130
  align-items: center;
131
+ inline-size: 100%;
130
132
  min-height: var(--ak-density-control-height-md);
131
133
  padding: 0 var(--ak-density-control-padding-x-md);
134
+ border: 0;
132
135
  border-radius: var(--ak-radius-md);
136
+ background: transparent;
133
137
  color: var(--ak-color-text);
134
138
  cursor: pointer;
139
+ font-family: inherit;
135
140
  font-size: var(--ak-font-size-sm);
136
141
  font-weight: var(--ak-font-weight-medium);
137
142
  overflow-wrap: anywhere;
143
+ text-align: start;
138
144
  transition:
139
145
  background var(--ak-duration-fast) var(--ak-ease-standard),
140
146
  color var(--ak-duration-fast) var(--ak-ease-standard);
@@ -1,6 +1,7 @@
1
1
  @layer components {
2
2
  :where(.navbar, [data-slot="navbar"]) {
3
3
  position: relative;
4
+ container-type: inline-size;
4
5
  display: flex;
5
6
  flex-direction: column;
6
7
  align-items: stretch;
@@ -157,7 +158,7 @@
157
158
  min-inline-size: 0;
158
159
  }
159
160
 
160
- @media (min-width: 48rem) {
161
+ @container (min-width: 48rem) {
161
162
  :where(.navbar-shell, [data-slot="navbar-shell"]):has(
162
163
  > :where(.navbar-group[data-align="center"], [data-slot="navbar-group"][data-align="center"])
163
164
  ) {