@askrjs/themes 0.0.8 → 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 (35) hide show
  1. package/dist/components/_internal/box-layout.js +1 -1
  2. package/dist/components/_internal/jsx.js.map +1 -1
  3. package/dist/components/_internal/layout.js +2 -7
  4. package/dist/components/_internal/layout.js.map +1 -1
  5. package/dist/components/_internal/style.js +25 -1
  6. package/dist/components/_internal/style.js.map +1 -1
  7. package/dist/components/aspect-ratio/aspect-ratio.js +1 -1
  8. package/dist/components/navbar/navbar.js +23 -12
  9. package/dist/components/navbar/navbar.js.map +1 -1
  10. package/dist/components/shell/shell-responsive.js +50 -27
  11. package/dist/components/shell/shell-responsive.js.map +1 -1
  12. package/dist/components/sidebar/sidebar.js +38 -24
  13. package/dist/components/sidebar/sidebar.js.map +1 -1
  14. package/dist/components/spacer/spacer.js +1 -1
  15. package/dist/components/theme/theme.js +47 -10
  16. package/dist/components/theme/theme.js.map +1 -1
  17. package/dist/themes/default/index.css +19 -3
  18. package/package.json +5 -5
  19. package/src/components/_internal/jsx.ts +18 -6
  20. package/src/components/_internal/layout.ts +3 -12
  21. package/src/components/_internal/style.ts +42 -4
  22. package/src/components/navbar/navbar.tsx +32 -17
  23. package/src/components/shell/shell-responsive.tsx +82 -66
  24. package/src/components/sidebar/sidebar.tsx +52 -34
  25. package/src/components/theme/theme.tsx +80 -12
  26. package/src/themes/default/styles/display/avatar.css +7 -1
  27. package/src/themes/default/styles/display/badge.css +2 -1
  28. package/src/themes/default/styles/display/table.css +2 -0
  29. package/src/themes/default/styles/forms/select.css +6 -0
  30. package/src/themes/default/styles/shell/navbar.css +2 -1
  31. package/templates/theme/styles/display/avatar.css +7 -1
  32. package/templates/theme/styles/display/badge.css +2 -1
  33. package/templates/theme/styles/display/table.css +2 -0
  34. package/templates/theme/styles/forms/select.css +6 -0
  35. package/templates/theme/styles/shell/navbar.css +2 -1
@@ -46,28 +46,92 @@ export function isShellPanelChild(child: unknown, panelComponent: unknown): chil
46
46
  return isJsxElement(child) && child.type === panelComponent;
47
47
  }
48
48
 
49
+ function renderShellChildKey(child: unknown, index: number, keyPrefix: string): string {
50
+ return isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`;
51
+ }
52
+
53
+ function keyMissingShellChildren(children: unknown[], keyPrefix: string): unknown[] {
54
+ let keyedChildren: unknown[] | undefined;
55
+
56
+ for (let index = 0; index < children.length; index += 1) {
57
+ const child = children[index];
58
+
59
+ if (isJsxElement(child) && child.key == null) {
60
+ keyedChildren ??= children.slice(0, index);
61
+ keyedChildren.push({
62
+ ...child,
63
+ key: `${keyPrefix}-${index}`,
64
+ });
65
+ continue;
66
+ }
67
+
68
+ keyedChildren?.push(child);
69
+ }
70
+
71
+ return keyedChildren ?? children;
72
+ }
73
+
74
+ function hasPanelProps(
75
+ props: Record<string, unknown> | undefined,
76
+ panelProps: ShellResponsivePanelProps,
77
+ ): boolean {
78
+ return (
79
+ props?.active === panelProps.active &&
80
+ props?.collapseLabel === panelProps.collapseLabel &&
81
+ props?.onClose === panelProps.onClose &&
82
+ props?.open === panelProps.open &&
83
+ props?.panelId === panelProps.panelId
84
+ );
85
+ }
86
+
87
+ function applyShellPanelProps(
88
+ children: unknown[],
89
+ keyPrefix: string,
90
+ panelProps: ShellResponsivePanelProps,
91
+ ): unknown[] {
92
+ let panelChildren: unknown[] | undefined;
93
+
94
+ for (let index = 0; index < children.length; index += 1) {
95
+ const child = children[index];
96
+
97
+ if (!isJsxElement(child)) {
98
+ panelChildren?.push(child);
99
+ continue;
100
+ }
101
+
102
+ const props = child.props as Record<string, unknown> | undefined;
103
+
104
+ if (hasPanelProps(props, panelProps)) {
105
+ panelChildren?.push(child);
106
+ continue;
107
+ }
108
+
109
+ panelChildren ??= children.slice(0, index);
110
+ panelChildren.push({
111
+ ...child,
112
+ key: child.key != null ? child.key : `${keyPrefix}-${index}`,
113
+ props: {
114
+ ...props,
115
+ active: panelProps.active,
116
+ collapseLabel: panelProps.collapseLabel,
117
+ onClose: panelProps.onClose,
118
+ open: panelProps.open,
119
+ panelId: panelProps.panelId,
120
+ },
121
+ });
122
+ }
123
+
124
+ return panelChildren ?? children;
125
+ }
126
+
49
127
  export function renderKeyedShellChildren(children: unknown, keyPrefix: string): JSX.Element {
50
128
  const childList = toChildArray(children);
51
- const needsKeying = childList.some((child) => isJsxElement(child) && child.key == null);
52
- const keyedChildren = needsKeying
53
- ? childList.map((child, index) => {
54
- if (!isJsxElement(child) || child.key != null) {
55
- return child;
56
- }
57
-
58
- return {
59
- ...child,
60
- key: `${keyPrefix}-${index}`,
61
- };
62
- })
63
- : childList;
129
+ const keyedChildren = keyMissingShellChildren(childList, keyPrefix);
64
130
 
65
131
  return (
66
132
  <For
67
133
  each={() => keyedChildren}
68
- by={(child, index) =>
69
- isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`
70
- }
134
+ by={(child, index) => renderShellChildKey(child, index, keyPrefix)}
71
135
  >
72
136
  {(child) => child as never}
73
137
  </For>
@@ -80,60 +144,12 @@ export function renderKeyedShellPanelChildren(
80
144
  panelProps: ShellResponsivePanelProps,
81
145
  ): JSX.Element {
82
146
  const childList = toChildArray(children);
83
- const needsPanelProps = childList.some((child) => {
84
- if (!isJsxElement(child)) {
85
- return false;
86
- }
87
-
88
- const props = child.props as Record<string, unknown> | undefined;
89
-
90
- return (
91
- props?.active !== panelProps.active ||
92
- props?.collapseLabel !== panelProps.collapseLabel ||
93
- props?.onClose !== panelProps.onClose ||
94
- props?.open !== panelProps.open ||
95
- props?.panelId !== panelProps.panelId
96
- );
97
- });
98
- const keyedChildren = needsPanelProps
99
- ? childList.map((child, index) => {
100
- if (!isJsxElement(child)) {
101
- return child;
102
- }
103
-
104
- const props = child.props as Record<string, unknown> | undefined;
105
-
106
- if (
107
- props?.active === panelProps.active &&
108
- props?.collapseLabel === panelProps.collapseLabel &&
109
- props?.onClose === panelProps.onClose &&
110
- props?.open === panelProps.open &&
111
- props?.panelId === panelProps.panelId
112
- ) {
113
- return child;
114
- }
115
-
116
- return {
117
- ...child,
118
- key: child.key != null ? child.key : `${keyPrefix}-${index}`,
119
- props: {
120
- ...props,
121
- active: panelProps.active,
122
- collapseLabel: panelProps.collapseLabel,
123
- onClose: panelProps.onClose,
124
- open: panelProps.open,
125
- panelId: panelProps.panelId,
126
- },
127
- };
128
- })
129
- : childList;
147
+ const keyedChildren = applyShellPanelProps(childList, keyPrefix, panelProps);
130
148
 
131
149
  return (
132
150
  <For
133
151
  each={() => keyedChildren}
134
- by={(child, index) =>
135
- isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`
136
- }
152
+ by={(child, index) => renderShellChildKey(child, index, keyPrefix)}
137
153
  >
138
154
  {(child) => child as never}
139
155
  </For>
@@ -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,12 +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);
89
95
  const currentTheme = themeState();
90
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
+ }
109
+
91
110
  const setTheme = (nextTheme: ThemeName) => {
92
111
  themeState.set(nextTheme);
93
112
  writeStoredTheme(storageKey, nextTheme);
113
+ explicitRootThemeOwner = providerId;
114
+ rootThemeRevision += 1;
94
115
  syncThemeRoot(nextTheme);
95
116
  };
96
117
 
@@ -103,14 +124,15 @@ export function ThemeProvider(props: ThemeProviderProps): JSX.Element {
103
124
 
104
125
  return (
105
126
  <ThemeContext.Scope value={value}>
106
- <ThemeRootSync theme={currentTheme} />
127
+ <ThemeRootSync providerId={providerId} theme={currentTheme} />
107
128
  <div data-slot="theme-provider">{children}</div>
108
129
  </ThemeContext.Scope>
109
130
  );
110
131
  }
111
132
 
112
- function ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {
113
- const { theme } = props;
133
+ function ThemeRootSync(props: { providerId: symbol; theme: ThemeName }): JSX.Element | null {
134
+ const { providerId, theme } = props;
135
+ const expectedRootThemeRevision = rootThemeRevision;
114
136
 
115
137
  resource(
116
138
  ({ signal }: { signal: AbortSignal }) => {
@@ -121,7 +143,11 @@ function ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {
121
143
 
122
144
  const timeoutId = window.setTimeout(() => {
123
145
  if (!signal.aborted) {
124
- syncThemeRoot(theme);
146
+ syncThemeRoot(theme, {
147
+ expectedRevision: expectedRootThemeRevision,
148
+ passive: true,
149
+ providerId,
150
+ });
125
151
  }
126
152
  }, 0);
127
153
 
@@ -144,20 +170,23 @@ function ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {
144
170
  export function ThemePicker(props: ThemePickerProps): JSX.Element {
145
171
  const theme = useTheme();
146
172
  const { themes = theme.themes, label = "Theme", ...rest } = props;
173
+ const currentTheme = theme.theme();
147
174
 
148
175
  return (
149
176
  <select
150
177
  {...rest}
151
178
  aria-label={rest["aria-label"] ?? label}
152
179
  data-slot="theme-picker"
153
- value={theme.theme()}
180
+ value={currentTheme}
154
181
  onChange={(event: Event) => {
155
- const target = event.currentTarget as HTMLSelectElement;
156
- theme.setTheme(target.value as ThemeName);
182
+ const target = getThemePickerTarget(event);
183
+ if (target) {
184
+ theme.setTheme(target.value as ThemeName);
185
+ }
157
186
  }}
158
187
  >
159
188
  {themes.map((option) => (
160
- <option key={option.value} value={option.value}>
189
+ <option key={option.value} value={option.value} selected={option.value === currentTheme}>
161
190
  {option.label}
162
191
  </option>
163
192
  ))}
@@ -165,6 +194,23 @@ export function ThemePicker(props: ThemePickerProps): JSX.Element {
165
194
  );
166
195
  }
167
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
+
168
214
  export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
169
215
  const theme = useTheme();
170
216
  const {
@@ -199,7 +245,9 @@ export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
199
245
  data-next-theme={nextTheme}
200
246
  onPress={(event) => {
201
247
  onPress?.(event);
202
- if (!event.defaultPrevented) theme.setTheme(nextTheme);
248
+ if (!event.defaultPrevented && !Object.is(nextTheme, currentTheme)) {
249
+ theme.setTheme(nextTheme);
250
+ }
203
251
  }}
204
252
  >
205
253
  <span data-slot="theme-toggle-content">{content}</span>
@@ -255,13 +303,32 @@ function cloneThemeToggleIcon(icon: unknown): unknown {
255
303
  };
256
304
  }
257
305
 
258
- 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 {
259
310
  if (typeof document === "undefined") {
260
311
  return;
261
312
  }
262
313
 
263
314
  const html = document.documentElement;
264
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
+
265
332
  if (themeChoice == null) {
266
333
  html.removeAttribute("data-theme");
267
334
  html.removeAttribute("data-theme-choice");
@@ -280,7 +347,8 @@ function syncThemeRoot(themeChoice: ThemeName | null | undefined): void {
280
347
  function readStoredTheme(storageKey: string): ThemeName | undefined {
281
348
  if (typeof window === "undefined") return undefined;
282
349
  try {
283
- return (window.localStorage.getItem(storageKey) as ThemeName | null) ?? undefined;
350
+ const storedTheme = window.localStorage.getItem(storageKey);
351
+ return storedTheme ? (storedTheme as ThemeName) : undefined;
284
352
  } catch {
285
353
  return undefined;
286
354
  }
@@ -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
  ) {
@@ -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
  ) {