@adea-ai/ui 0.88.0 → 0.89.2

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 (36) hide show
  1. package/README.md +16 -0
  2. package/dist/components/composites/settings/index.d.ts +2 -0
  3. package/dist/components/composites/settings/index.d.ts.map +1 -1
  4. package/dist/components/composites/settings/index.js +3 -1
  5. package/dist/components/composites/settings/settings-layout.d.ts +28 -0
  6. package/dist/components/composites/settings/settings-layout.d.ts.map +1 -0
  7. package/dist/components/composites/settings/settings-layout.js +62 -0
  8. package/dist/components/composites/settings/settings-layout.js.map +1 -0
  9. package/dist/components/composites/settings/settings-navigation.d.ts +41 -0
  10. package/dist/components/composites/settings/settings-navigation.d.ts.map +1 -0
  11. package/dist/components/composites/settings/settings-navigation.js +102 -0
  12. package/dist/components/composites/settings/settings-navigation.js.map +1 -0
  13. package/dist/components/layout/top-bar/top-bar.d.ts +3 -1
  14. package/dist/components/layout/top-bar/top-bar.d.ts.map +1 -1
  15. package/dist/components/layout/top-bar/top-bar.js +4 -4
  16. package/dist/components/layout/top-bar/top-bar.js.map +1 -1
  17. package/dist/components/ui/tabs/tabs.d.ts.map +1 -1
  18. package/dist/components/ui/tabs/tabs.js +70 -13
  19. package/dist/components/ui/tabs/tabs.js.map +1 -1
  20. package/dist/index.js +3 -1
  21. package/dist/r/registry.json +12 -0
  22. package/dist/r/settings.json +12 -0
  23. package/dist/r/src/components/composites/settings/index.ts +7 -0
  24. package/dist/r/src/components/composites/settings/settings-layout.tsx +65 -0
  25. package/dist/r/src/components/composites/settings/settings-navigation.tsx +135 -0
  26. package/dist/r/src/components/layout/top-bar/top-bar.tsx +9 -5
  27. package/dist/r/src/components/ui/tabs/tabs.tsx +80 -10
  28. package/dist/r/src/styles/base.css +1 -0
  29. package/package.json +2 -1
  30. package/registry.json +12 -0
  31. package/src/components/composites/settings/index.ts +7 -0
  32. package/src/components/composites/settings/settings-layout.tsx +65 -0
  33. package/src/components/composites/settings/settings-navigation.tsx +135 -0
  34. package/src/components/layout/top-bar/top-bar.tsx +9 -5
  35. package/src/components/ui/tabs/tabs.tsx +80 -10
  36. package/src/styles/base.css +1 -0
package/README.md CHANGED
@@ -247,6 +247,16 @@ setSelection({ accent: 'amber' })
247
247
  Two components ship for the settings surface: `AppearancePanel` is the whole
248
248
  appearance view, and `ThemeToggle` is the light/dark switch on its own.
249
249
 
250
+ `SettingsLayout` composes a controlled vertical tab root, grouped `SettingsNavigation`,
251
+ and a scrollable panel viewport. Supply the selected `value`, `onChange`, navigation
252
+ groups, and matching `TabsContent` panels. The host owns URL or preference updates
253
+ and panel content; the layout contracts its rail at narrow widths, reports repeated
254
+ activation through `onReselect`, and reveals the selected row by default. Use
255
+ `SettingsNavigation` directly when you already own the surrounding tabs composition.
256
+ Shared tabs associate panels with custom trigger IDs in browser and server renders;
257
+ an explicit panel `aria-labelledby` takes precedence. Independent tab roots keep
258
+ their associations separate.
259
+
250
260
  ### Avoiding the flash
251
261
 
252
262
  A themed app has to know the appearance before the first paint, or it paints
@@ -716,6 +726,12 @@ composition evidence; bounded runtime projection, storage and production chat
716
726
  integration remain application acceptance gates. Attribution for the selected
717
727
  KiroCrew source contracts is recorded in the issue-specific `NOTICE` entry.
718
728
 
729
+ The shared `TopBar` contracts its middle track on narrow screens. Its side groups
730
+ scroll horizontally when enlarged text makes all controls wider than the viewport;
731
+ keyboard focus reveals each action. Groups opt out of native window dragging.
732
+ Use `TopBarTitle align="center"` for a centered title and layout-only visibility
733
+ classes when a title should yield space to essential controls.
734
+
719
735
  ### Controlled appearance mode
720
736
 
721
737
  `ThemeModeToggle` provides the shared light/dark/system selector for hosts that
@@ -1,2 +1,4 @@
1
1
  export { SettingsField, SettingsPage, SettingsRow, SettingsSection } from './settings';
2
+ export { SettingsLayout, type SettingsLayoutProps } from './settings-layout';
3
+ export { SettingsNavigation, type SettingsNavigationGroup, type SettingsNavigationItem, type SettingsNavigationProps, } from './settings-navigation';
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACtF,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAC5E,OAAO,EACL,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAA"}
@@ -1,2 +1,4 @@
1
1
  import { SettingsField, SettingsPage, SettingsRow, SettingsSection } from "./settings.js";
2
- export { SettingsField, SettingsPage, SettingsRow, SettingsSection };
2
+ import { SettingsNavigation } from "./settings-navigation.js";
3
+ import { SettingsLayout } from "./settings-layout.js";
4
+ export { SettingsField, SettingsLayout, SettingsNavigation, SettingsPage, SettingsRow, SettingsSection };
@@ -0,0 +1,28 @@
1
+ import type { ComponentProps, JSX } from 'solid-js';
2
+ import { Tabs } from '../../ui/tabs';
3
+ import { type SettingsNavigationGroup } from './settings-navigation';
4
+ export type SettingsLayoutProps = Omit<ComponentProps<typeof Tabs>, 'children' | 'orientation' | 'value' | 'defaultValue' | 'onChange'> & {
5
+ /** Grouped navigation entries; the host owns their values and panel content. */
6
+ groups: readonly SettingsNavigationGroup[];
7
+ /** Accessible name for the vertical tab list. */
8
+ 'aria-label': string;
9
+ /** The host-controlled selected destination. */
10
+ value: string;
11
+ /** Updates the host-controlled selected destination. */
12
+ onChange: (value: string) => void;
13
+ /** Called when the already-selected destination is activated again. */
14
+ onReselect?: (value: string) => void;
15
+ /** Reveal the selected row on value changes and window resizes. Defaults to nearest scroll. */
16
+ revealSelected?: boolean | ((trigger: HTMLButtonElement | undefined) => void);
17
+ /** Panels must be rendered as `TabsContent` descendants. */
18
+ children?: JSX.Element;
19
+ };
20
+ /**
21
+ * SettingsLayout.
22
+ *
23
+ * A controlled, vertical settings rail beside its scrollable panel viewport.
24
+ * The host keeps ownership of selection, URL/hash state and panel content.
25
+ * At narrow viewports the rail contracts while both columns remain shrinkable.
26
+ */
27
+ export declare function SettingsLayout(props: SettingsLayoutProps): JSX.Element;
28
+ //# sourceMappingURL=settings-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-layout.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/settings/settings-layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAGnD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAsB,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAExF,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,cAAc,CAAC,OAAO,IAAI,CAAC,EAC3B,UAAU,GAAG,aAAa,GAAG,OAAO,GAAG,cAAc,GAAG,UAAU,CACnE,GAAG;IACF,gFAAgF;IAChF,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAA;IAC1C,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,+FAA+F;IAC/F,cAAc,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,KAAK,IAAI,CAAC,CAAA;IAC7E,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,eA+BxD"}
@@ -0,0 +1,62 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { Tabs } from "../../ui/tabs/tabs.js";
3
+ import { SettingsNavigation } from "./settings-navigation.js";
4
+ import { createComponent, insert, mergeProps, template } from "solid-js/web";
5
+ import { splitProps } from "solid-js";
6
+ //#region src/components/composites/settings/settings-layout.tsx
7
+ var _tmpl$ = /*#__PURE__*/ template(`<div data-slot=settings-layout-panels class="min-h-0 min-w-0 flex-1 overflow-y-auto p-4">`);
8
+ /**
9
+ * SettingsLayout.
10
+ *
11
+ * A controlled, vertical settings rail beside its scrollable panel viewport.
12
+ * The host keeps ownership of selection, URL/hash state and panel content.
13
+ * At narrow viewports the rail contracts while both columns remain shrinkable.
14
+ */
15
+ function SettingsLayout(props) {
16
+ const [local, rest] = splitProps(props, [
17
+ "class",
18
+ "children",
19
+ "groups",
20
+ "aria-label",
21
+ "value",
22
+ "onReselect",
23
+ "revealSelected"
24
+ ]);
25
+ return createComponent(Tabs, mergeProps(rest, {
26
+ orientation: "vertical",
27
+ get value() {
28
+ return local.value;
29
+ },
30
+ get ["class"]() {
31
+ return cn("min-h-0 min-w-0 flex-1 gap-0", local.class);
32
+ },
33
+ get children() {
34
+ return [createComponent(SettingsNavigation, {
35
+ get ["aria-label"]() {
36
+ return local["aria-label"];
37
+ },
38
+ get groups() {
39
+ return local.groups;
40
+ },
41
+ get value() {
42
+ return local.value;
43
+ },
44
+ get onReselect() {
45
+ return local.onReselect;
46
+ },
47
+ get revealSelected() {
48
+ return local.revealSelected;
49
+ },
50
+ "class": "w-24 md:w-sidebar"
51
+ }), (() => {
52
+ var _el$ = _tmpl$();
53
+ insert(_el$, () => local.children);
54
+ return _el$;
55
+ })()];
56
+ }
57
+ }));
58
+ }
59
+ //#endregion
60
+ export { SettingsLayout };
61
+
62
+ //# sourceMappingURL=settings-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-layout.js","names":["ComponentProps","JSX","splitProps","cn","Tabs","SettingsNavigation","SettingsNavigationGroup","SettingsLayoutProps","Omit","groups","value","onChange","onReselect","revealSelected","trigger","HTMLButtonElement","children","Element","SettingsLayout","props","local","rest","_$createComponent","_$mergeProps","orientation","class","aria-label","_el$","_tmpl$","_$insert","_$createComponent","_$mergeProps"],"sources":["../../../../src/components/composites/settings/settings-layout.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Tabs } from '../../ui/tabs'\nimport { SettingsNavigation, type SettingsNavigationGroup } from './settings-navigation'\n\nexport type SettingsLayoutProps = Omit<\n ComponentProps<typeof Tabs>,\n 'children' | 'orientation' | 'value' | 'defaultValue' | 'onChange'\n> & {\n /** Grouped navigation entries; the host owns their values and panel content. */\n groups: readonly SettingsNavigationGroup[]\n /** Accessible name for the vertical tab list. */\n 'aria-label': string\n /** The host-controlled selected destination. */\n value: string\n /** Updates the host-controlled selected destination. */\n onChange: (value: string) => void\n /** Called when the already-selected destination is activated again. */\n onReselect?: (value: string) => void\n /** Reveal the selected row on value changes and window resizes. Defaults to nearest scroll. */\n revealSelected?: boolean | ((trigger: HTMLButtonElement | undefined) => void)\n /** Panels must be rendered as `TabsContent` descendants. */\n children?: JSX.Element\n}\n\n/**\n * SettingsLayout.\n *\n * A controlled, vertical settings rail beside its scrollable panel viewport.\n * The host keeps ownership of selection, URL/hash state and panel content.\n * At narrow viewports the rail contracts while both columns remain shrinkable.\n */\nexport function SettingsLayout(props: SettingsLayoutProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'children',\n 'groups',\n 'aria-label',\n 'value',\n 'onReselect',\n 'revealSelected',\n ])\n\n return (\n <Tabs\n {...rest}\n orientation=\"vertical\"\n value={local.value}\n class={cn('min-h-0 min-w-0 flex-1 gap-0', local.class)}\n >\n <SettingsNavigation\n aria-label={local['aria-label']}\n groups={local.groups}\n value={local.value}\n onReselect={local.onReselect}\n revealSelected={local.revealSelected}\n class=\"w-24 md:w-sidebar\"\n />\n <div data-slot=\"settings-layout-panels\" class=\"min-h-0 min-w-0 flex-1 overflow-y-auto p-4\">\n {local.children}\n </div>\n </Tabs>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;AAiCA,SAAgBkB,eAAeC,OAA4B;CACzD,MAAM,CAACC,OAAOC,QAAQnB,WAAWiB,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;CAAgB,CACjB;CAED,OAAAG,gBACGlB,MAAImB,WACCF,MAAI;EACRG,aAAW;EAAA,IACXd,QAAK;GAAA,OAAEU,MAAMV;EAAK;EAAA,KAAA,WAAA;GAAA,OACXP,GAAG,gCAAgCiB,MAAMK,KAAK;EAAC;EAAA,IAAAT,WAAA;GAAA,OAAA,CAAAM,gBAErDjB,oBAAkB;IAAA,KAAA,gBAAA;KAAA,OACLe,MAAM;IAAa;IAAA,IAC/BX,SAAM;KAAA,OAAEW,MAAMX;IAAM;IAAA,IACpBC,QAAK;KAAA,OAAEU,MAAMV;IAAK;IAAA,IAClBE,aAAU;KAAA,OAAEQ,MAAMR;IAAU;IAAA,IAC5BC,iBAAc;KAAA,OAAEO,MAAMP;IAAc;IAAA,SAAA;GAAA,CAAA,UAAA;IAAA,IAAAc,OAAAC,OAAA;IAAAC,OAAAF,YAInCP,MAAMJ,QAAQ;IAAA,OAAAW;GAAA,EAAA,CAAA,CAAA;EAAA;CAAA,CAAA,CAAA;AAIvB"}
@@ -0,0 +1,41 @@
1
+ import type { JSX } from 'solid-js';
2
+ import { type TabsListProps } from '../../ui/tabs';
3
+ /** One host-owned destination in a settings tab list. Values must be unique. */
4
+ export type SettingsNavigationItem = {
5
+ value: string;
6
+ label: string;
7
+ icon?: JSX.Element;
8
+ disabled?: boolean;
9
+ };
10
+ /** A visible, accessibly named group of settings destinations. */
11
+ export type SettingsNavigationGroup = {
12
+ label: string;
13
+ items: readonly SettingsNavigationItem[];
14
+ };
15
+ export type SettingsNavigationProps = Omit<TabsListProps, 'appearance' | 'children' | 'orientation'> & {
16
+ /** Groups are presentation only; the host owns the tab values and panels. */
17
+ groups: readonly SettingsNavigationGroup[];
18
+ /** The same controlled value supplied to the enclosing `Tabs`. */
19
+ value: string;
20
+ /** Called when the already-selected destination is activated again. */
21
+ onReselect?: (value: string) => void;
22
+ /** Reveal the selected row on value changes and window resizes. Defaults to nearest scroll. */
23
+ revealSelected?: boolean | ((trigger: HTMLButtonElement | undefined) => void);
24
+ /** Every tab list needs a label independent of its visible group headings. */
25
+ 'aria-label': string;
26
+ };
27
+ /**
28
+ * SettingsNavigation.
29
+ *
30
+ * A grouped vertical tab list for sibling settings panels. It composes the
31
+ * shared Tabs behaviour with the shared sidebar row recipe; the host supplies
32
+ * the controlled value, panel content, icons and any persistence or routing.
33
+ * Use ordinary tabs for a short, ungrouped row of view choices.
34
+ *
35
+ * Kobalte owns roving focus, arrow keys, selection and tab/panel ARIA. This
36
+ * component adds no URL, storage or host-specific state. Set
37
+ * `revealSelected={false}` when the surrounding layout does not use an internal
38
+ * scrolling viewport.
39
+ */
40
+ export declare function SettingsNavigation(props: SettingsNavigationProps): JSX.Element;
41
+ //# sourceMappingURL=settings-navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-navigation.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/settings/settings-navigation.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAInC,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAEzE,gFAAgF;AAChF,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,kEAAkE;AAClE,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAA;CACzC,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,aAAa,EACb,YAAY,GAAG,UAAU,GAAG,aAAa,CAC1C,GAAG;IACF,6EAA6E;IAC7E,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAA;IAC1C,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,+FAA+F;IAC/F,cAAc,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,KAAK,IAAI,CAAC,CAAA;IAC7E,8EAA8E;IAC9E,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,eAqFhE"}
@@ -0,0 +1,102 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { TabsList, TabsTrigger } from "../../ui/tabs/tabs.js";
3
+ import { sidebarNavItemClass, sidebarNavItemStateClass } from "../../layout/sidebar-nav/sidebar-nav.js";
4
+ import { createComponent, insert, memo, mergeProps, setAttribute, template } from "solid-js/web";
5
+ import { createEffect, createUniqueId, onCleanup, splitProps } from "solid-js";
6
+ //#region src/components/composites/settings/settings-navigation.tsx
7
+ var _tmpl$ = /*#__PURE__*/ template(`<div role=none data-slot=settings-navigation-group class="flex min-w-0 flex-col gap-0.5"><span class=sr-only></span><span aria-hidden=true class="px-2 py-1.5 text-2xs font-medium tracking-wide text-sidebar-muted-foreground uppercase">`);
8
+ var _tmpl$2 = /*#__PURE__*/ template(`<span class="min-w-0 truncate">`);
9
+ /**
10
+ * SettingsNavigation.
11
+ *
12
+ * A grouped vertical tab list for sibling settings panels. It composes the
13
+ * shared Tabs behaviour with the shared sidebar row recipe; the host supplies
14
+ * the controlled value, panel content, icons and any persistence or routing.
15
+ * Use ordinary tabs for a short, ungrouped row of view choices.
16
+ *
17
+ * Kobalte owns roving focus, arrow keys, selection and tab/panel ARIA. This
18
+ * component adds no URL, storage or host-specific state. Set
19
+ * `revealSelected={false}` when the surrounding layout does not use an internal
20
+ * scrolling viewport.
21
+ */
22
+ function SettingsNavigation(props) {
23
+ const [local, rest] = splitProps(props, [
24
+ "class",
25
+ "aria-label",
26
+ "groups",
27
+ "value",
28
+ "onReselect",
29
+ "revealSelected"
30
+ ]);
31
+ const triggers = /* @__PURE__ */ new Map();
32
+ const groupIdPrefix = `settings-navigation-${createUniqueId()}`;
33
+ createEffect(() => {
34
+ const value = local.value;
35
+ const reveal = local.revealSelected;
36
+ if (reveal === false) return;
37
+ const revealCurrent = () => {
38
+ const trigger = triggers.get(value);
39
+ if (typeof reveal === "function") reveal(trigger);
40
+ else trigger?.scrollIntoView({
41
+ block: "nearest",
42
+ inline: "nearest"
43
+ });
44
+ };
45
+ revealCurrent();
46
+ window.addEventListener("resize", revealCurrent);
47
+ onCleanup(() => window.removeEventListener("resize", revealCurrent));
48
+ });
49
+ return createComponent(TabsList, mergeProps({
50
+ "data-slot": "settings-navigation",
51
+ get ["aria-label"]() {
52
+ return local["aria-label"];
53
+ },
54
+ orientation: "vertical",
55
+ get ["class"]() {
56
+ return cn("flex max-h-full min-h-0 min-w-0 shrink-0 flex-col items-stretch justify-start gap-2 overflow-x-hidden overflow-y-auto px-2 py-2", local.class);
57
+ }
58
+ }, rest, { get children() {
59
+ return local.groups.map((group, groupIndex) => {
60
+ const groupId = `${groupIdPrefix}-group-${groupIndex}`;
61
+ return (() => {
62
+ var _el$ = _tmpl$(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
63
+ setAttribute(_el$2, "id", groupId);
64
+ insert(_el$2, () => group.label);
65
+ insert(_el$3, () => group.label);
66
+ insert(_el$, () => group.items.map((item) => createComponent(TabsTrigger, {
67
+ "data-slot": "settings-navigation-trigger",
68
+ orientation: "vertical",
69
+ "aria-describedby": groupId,
70
+ get value() {
71
+ return item.value;
72
+ },
73
+ get disabled() {
74
+ return item.disabled;
75
+ },
76
+ ref: (element) => {
77
+ if (element) triggers.set(item.value, element);
78
+ else triggers.delete(item.value);
79
+ },
80
+ onClick: () => {
81
+ if (local.value === item.value) local.onReselect?.(item.value);
82
+ },
83
+ get ["class"]() {
84
+ return cn(sidebarNavItemClass, sidebarNavItemStateClass.idle, "h-row-lg w-full justify-start border-0 px-3 py-2 text-left data-[selected]:bg-primary-subtle data-[selected]:text-foreground");
85
+ },
86
+ get children() {
87
+ return [memo(() => item.icon), (() => {
88
+ var _el$4 = _tmpl$2();
89
+ insert(_el$4, () => item.label);
90
+ return _el$4;
91
+ })()];
92
+ }
93
+ })), null);
94
+ return _el$;
95
+ })();
96
+ });
97
+ } }));
98
+ }
99
+ //#endregion
100
+ export { SettingsNavigation };
101
+
102
+ //# sourceMappingURL=settings-navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-navigation.js","names":["JSX","createEffect","createUniqueId","onCleanup","splitProps","cn","sidebarNavItemClass","sidebarNavItemStateClass","TabsList","TabsTrigger","TabsListProps","SettingsNavigationItem","value","label","icon","Element","disabled","SettingsNavigationGroup","items","SettingsNavigationProps","Omit","groups","onReselect","revealSelected","trigger","HTMLButtonElement","SettingsNavigation","props","local","rest","triggers","Map","groupIdPrefix","reveal","revealCurrent","get","scrollIntoView","block","inline","window","addEventListener","removeEventListener","_$createComponent","_$mergeProps","aria-label","orientation","class","children","map","group","groupIndex","groupId","_el$","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_$setAttribute","_$insert","item","ref","element","set","delete","onClick","idle","_$memo","_el$4","_tmpl$2","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/composites/settings/settings-navigation.tsx"],"sourcesContent":["import type { JSX } from 'solid-js'\nimport { createEffect, createUniqueId, onCleanup, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { sidebarNavItemClass, sidebarNavItemStateClass } from '../../layout/sidebar-nav/sidebar-nav'\nimport { TabsList, TabsTrigger, type TabsListProps } from '../../ui/tabs'\n\n/** One host-owned destination in a settings tab list. Values must be unique. */\nexport type SettingsNavigationItem = {\n value: string\n label: string\n icon?: JSX.Element\n disabled?: boolean\n}\n\n/** A visible, accessibly named group of settings destinations. */\nexport type SettingsNavigationGroup = {\n label: string\n items: readonly SettingsNavigationItem[]\n}\n\nexport type SettingsNavigationProps = Omit<\n TabsListProps,\n 'appearance' | 'children' | 'orientation'\n> & {\n /** Groups are presentation only; the host owns the tab values and panels. */\n groups: readonly SettingsNavigationGroup[]\n /** The same controlled value supplied to the enclosing `Tabs`. */\n value: string\n /** Called when the already-selected destination is activated again. */\n onReselect?: (value: string) => void\n /** Reveal the selected row on value changes and window resizes. Defaults to nearest scroll. */\n revealSelected?: boolean | ((trigger: HTMLButtonElement | undefined) => void)\n /** Every tab list needs a label independent of its visible group headings. */\n 'aria-label': string\n}\n\n/**\n * SettingsNavigation.\n *\n * A grouped vertical tab list for sibling settings panels. It composes the\n * shared Tabs behaviour with the shared sidebar row recipe; the host supplies\n * the controlled value, panel content, icons and any persistence or routing.\n * Use ordinary tabs for a short, ungrouped row of view choices.\n *\n * Kobalte owns roving focus, arrow keys, selection and tab/panel ARIA. This\n * component adds no URL, storage or host-specific state. Set\n * `revealSelected={false}` when the surrounding layout does not use an internal\n * scrolling viewport.\n */\nexport function SettingsNavigation(props: SettingsNavigationProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'aria-label',\n 'groups',\n 'value',\n 'onReselect',\n 'revealSelected',\n ])\n const triggers = new Map<string, HTMLButtonElement>()\n const groupIdPrefix = `settings-navigation-${createUniqueId()}`\n\n createEffect(() => {\n const value = local.value\n const reveal = local.revealSelected\n if (reveal === false) return\n\n const revealCurrent = () => {\n const trigger = triggers.get(value)\n if (typeof reveal === 'function') reveal(trigger)\n else trigger?.scrollIntoView({ block: 'nearest', inline: 'nearest' })\n }\n\n revealCurrent()\n window.addEventListener('resize', revealCurrent)\n onCleanup(() => window.removeEventListener('resize', revealCurrent))\n })\n\n return (\n <TabsList\n data-slot=\"settings-navigation\"\n aria-label={local['aria-label']}\n orientation=\"vertical\"\n class={cn(\n 'flex max-h-full min-h-0 min-w-0 shrink-0 flex-col items-stretch justify-start gap-2 overflow-x-hidden overflow-y-auto px-2 py-2',\n local.class\n )}\n {...rest}\n >\n {local.groups.map((group, groupIndex) => {\n const groupId = `${groupIdPrefix}-group-${groupIndex}`\n return (\n <div\n role=\"none\"\n data-slot=\"settings-navigation-group\"\n class=\"flex min-w-0 flex-col gap-0.5\"\n >\n <span id={groupId} class=\"sr-only\">\n {group.label}\n </span>\n <span\n aria-hidden=\"true\"\n class=\"px-2 py-1.5 text-2xs font-medium tracking-wide text-sidebar-muted-foreground uppercase\"\n >\n {group.label}\n </span>\n {group.items.map((item) => (\n <TabsTrigger\n data-slot=\"settings-navigation-trigger\"\n orientation=\"vertical\"\n aria-describedby={groupId}\n value={item.value}\n disabled={item.disabled}\n ref={(element: HTMLButtonElement | undefined) => {\n if (element) triggers.set(item.value, element)\n else triggers.delete(item.value)\n }}\n onClick={() => {\n if (local.value === item.value) local.onReselect?.(item.value)\n }}\n class={cn(\n sidebarNavItemClass,\n sidebarNavItemStateClass.idle,\n 'h-row-lg w-full justify-start border-0 px-3 py-2 text-left data-[selected]:bg-primary-subtle data-[selected]:text-foreground'\n )}\n >\n {item.icon}\n <span class=\"min-w-0 truncate\">{item.label}</span>\n </TabsTrigger>\n ))}\n </div>\n )\n })}\n </TabsList>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB0B,mBAAmBC,OAAgC;CACjE,MAAM,CAACC,OAAOC,QAAQzB,WAAWuB,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;CAAgB,CACjB;CACD,MAAMG,2BAAW,IAAIC,IAA+B;CACpD,MAAMC,gBAAgB,uBAAuB9B,eAAe;CAE5DD,mBAAmB;EACjB,MAAMW,QAAQgB,MAAMhB;EACpB,MAAMqB,SAASL,MAAML;EACrB,IAAIU,WAAW,OAAO;EAEtB,MAAMC,sBAAsB;GAC1B,MAAMV,UAAUM,SAASK,IAAIvB,KAAK;GAClC,IAAI,OAAOqB,WAAW,YAAYA,OAAOT,OAAO;QAC3CA,SAASY,eAAe;IAAEC,OAAO;IAAWC,QAAQ;GAAU,CAAC;EACtE;EAEAJ,cAAc;EACdK,OAAOC,iBAAiB,UAAUN,aAAa;EAC/C/B,gBAAgBoC,OAAOE,oBAAoB,UAAUP,aAAa,CAAC;CACrE,CAAC;CAED,OAAAQ,gBACGlC,UAAQmC,WAAA;EAAA,aAAA;EAAA,KAAA,gBAAA;GAAA,OAEKf,MAAM;EAAa;EAC/BiB,aAAW;EAAA,KAAA,WAAA;GAAA,OACJxC,GACL,mIACAuB,MAAMkB,KACR;EAAC;CAAA,GACGjB,MAAI,EAAA,IAAAkB,WAAA;EAAA,OAEPnB,MAAMP,OAAO2B,KAAKC,OAAOC,eAAe;GACvC,MAAMC,UAAU,GAAGnB,cAAa,SAAUkB;GAC1C,cAAA;IAAA,IAAAE,OAAAC,OAAA,GAAAC,QAAAF,KAAAG,YAAAC,QAAAF,MAAAG;IAAAC,aAAAJ,OAAA,MAMcH,OAAO;IAAAQ,OAAAL,aACdL,MAAMpC,KAAK;IAAA8C,OAAAH,aAMXP,MAAMpC,KAAK;IAAA8C,OAAAP,YAEbH,MAAM/B,MAAM8B,KAAKY,SAAIlB,gBACnBjC,aAAW;KAAA,aAAA;KAEVoC,aAAW;KAAA,oBACOM;KAAO,IACzBvC,QAAK;MAAA,OAAEgD,KAAKhD;KAAK;KAAA,IACjBI,WAAQ;MAAA,OAAE4C,KAAK5C;KAAQ;KAAA6C,MACjBC,YAA2C;MAC/C,IAAIA,SAAShC,SAASiC,IAAIH,KAAKhD,OAAOkD,OAAO;WACxChC,SAASkC,OAAOJ,KAAKhD,KAAK;KACjC;KACAqD,eAAe;MACb,IAAIrC,MAAMhB,UAAUgD,KAAKhD,OAAOgB,MAAMN,aAAasC,KAAKhD,KAAK;KAC/D;KAAC,KAAA,WAAA;MAAA,OACMP,GACLC,qBACAC,yBAAyB2D,MACzB,8HACF;KAAC;KAAA,IAAAnB,WAAA;MAAA,OAAA,CAAAoB,WAEAP,KAAK9C,IAAI,UAAA;OAAA,IAAAsD,QAAAC,QAAA;OAAAV,OAAAS,aACsBR,KAAK/C,KAAK;OAAA,OAAAuD;MAAA,EAAA,CAAA,CAAA;KAAA;IAAA,CAAA,CAE7C,GAAC,IAAA;IAAA,OAAAhB;GAAA,EAAA,CAAA;EAGR,CAAC;CAAC,EAAA,CAAA,CAAA;AAGR"}
@@ -29,7 +29,9 @@ export declare function TopBar(props: TopBarProps): import("solid-js").JSX.Eleme
29
29
  export declare function TopBarSection(props: ComponentProps<'div'> & {
30
30
  align?: 'start' | 'end';
31
31
  }): import("solid-js").JSX.Element;
32
- export declare function TopBarTitle(props: ComponentProps<'div'>): import("solid-js").JSX.Element;
32
+ export declare function TopBarTitle(props: ComponentProps<'div'> & {
33
+ align?: 'start' | 'center';
34
+ }): import("solid-js").JSX.Element;
33
35
  /** A breadcrumb or path readout that yields to the actions when space runs out. */
34
36
  export declare function TopBarBreadcrumb(props: ComponentProps<'div'>): import("solid-js").JSX.Element;
35
37
  export type TopBarSearchProps = ComponentProps<'button'> & {
@@ -1 +1 @@
1
- {"version":3,"file":"top-bar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/top-bar/top-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAI9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG;IACnD,sDAAsD;IACtD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,gDAAgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,kCAuBxC;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAA;CAAE,kCAevF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,kCASvD;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,kCAS5D;AAED,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG;IACzD,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCAyBpD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,kCAqB7E"}
1
+ {"version":3,"file":"top-bar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/top-bar/top-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAI9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG;IACnD,sDAAsD;IACtD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,gDAAgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,kCAuBxC;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAA;CAAE,kCAevF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;CAAE,kCAaxF;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,kCAS5D;AAED,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG;IACzD,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCAyBpD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,kCAqB7E"}
@@ -20,7 +20,7 @@ function TopBar(props) {
20
20
  return (() => {
21
21
  var _el$ = _tmpl$();
22
22
  spread(_el$, mergeProps({ get ["class"]() {
23
- return cn("h-topbar relative z-(--z-sticky) grid shrink-0 grid-cols-[minmax(0,1fr)_clamp(240px,22vw,480px)_minmax(0,1fr)] items-center gap-3 border-b border-border px-3", local.glass && "glass-panel", local.draggable && "window-drag", local.macosInset && "window-inset-macos", local.windowsInset && "window-inset-windows", local.class);
23
+ return cn("h-topbar relative z-(--z-sticky) grid shrink-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-3 border-b border-border bg-card text-card-foreground px-3 md:grid-cols-[minmax(0,1fr)_clamp(240px,22vw,480px)_minmax(0,1fr)]", local.glass && "glass-panel", local.draggable && "window-drag", local.macosInset && "window-inset-macos", local.windowsInset && "window-inset-windows", local.class);
24
24
  } }, rest), false, false);
25
25
  return _el$;
26
26
  })();
@@ -31,17 +31,17 @@ function TopBarSection(props) {
31
31
  return (() => {
32
32
  var _el$2 = _tmpl$2();
33
33
  spread(_el$2, mergeProps({ get ["class"]() {
34
- return cn("flex min-w-0 items-center gap-2 overflow-hidden", local.align === "end" && "justify-end", local.align !== "end" && "justify-start", local.class);
34
+ return cn("window-no-drag flex min-w-0 items-center gap-2 overflow-x-auto overflow-y-hidden", local.align === "end" && "justify-end", local.align !== "end" && "justify-start", local.class);
35
35
  } }, rest), false, false);
36
36
  return _el$2;
37
37
  })();
38
38
  }
39
39
  function TopBarTitle(props) {
40
- const [local, rest] = splitProps(props, ["class"]);
40
+ const [local, rest] = splitProps(props, ["class", "align"]);
41
41
  return (() => {
42
42
  var _el$3 = _tmpl$3();
43
43
  spread(_el$3, mergeProps({ get ["class"]() {
44
- return cn("truncate text-sm font-medium", local.class);
44
+ return cn("truncate text-sm font-medium", local.align === "center" && "text-center", local.class);
45
45
  } }, rest), false, false);
46
46
  return _el$3;
47
47
  })();
@@ -1 +1 @@
1
- {"version":3,"file":"top-bar.js","names":["ComponentProps","Show","splitProps","cn","TopBarProps","draggable","macosInset","windowsInset","glass","TopBar","props","local","rest","_el$","_tmpl$","_$spread","_$mergeProps","class","TopBarSection","align","_el$2","_tmpl$2","TopBarTitle","_el$3","_tmpl$3","TopBarBreadcrumb","_el$4","_tmpl$4","TopBarSearchProps","placeholder","shortcut","TopBarSearch","_el$5","_tmpl$6","_el$6","firstChild","_$insert","_$createComponent","when","children","_el$7","_tmpl$5","TopBarPill","label","_el$8","_tmpl$7","_el$9","_$mergeProps","_$createComponent"],"sources":["../../../../src/components/layout/top-bar/top-bar.tsx"],"sourcesContent":["import type { ComponentProps } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * TopBar.\n *\n * The window's title row and primary toolbar. Three tracks: a leading group, a\n * centred search, and a trailing group. The search is a fixed function of the\n * window width and the two side groups are equal remainders, which is what\n * makes the search *exactly* window-centred by construction — no measurement,\n * no observer, no absolutely-positioned overlay to keep clear of.\n *\n * On a frameless desktop window this row is also the drag region, so it carries\n * `window-drag` and the controls inside it opt back out. `macos-inset` and\n * `windows-inset` reserve the space the native window controls occupy, which is\n * why the row can look off-centre in a frameless window and be correct: it is\n * centred in the space the user can actually see.\n */\nexport type TopBarProps = ComponentProps<'header'> & {\n /** Make the row draggable, for a frameless window. */\n draggable?: boolean\n /** Reserve space for the macOS traffic lights. */\n macosInset?: boolean\n /** Reserve space for the Windows caption buttons. */\n windowsInset?: boolean\n /** Blur the content scrolling under the bar. */\n glass?: boolean\n}\n\nexport function TopBar(props: TopBarProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'draggable',\n 'macosInset',\n 'windowsInset',\n 'glass',\n ])\n\n return (\n <header\n data-slot=\"top-bar\"\n class={cn(\n 'h-topbar relative z-(--z-sticky) grid shrink-0 grid-cols-[minmax(0,1fr)_clamp(240px,22vw,480px)_minmax(0,1fr)] items-center gap-3 border-b border-border px-3',\n local.glass && 'glass-panel',\n local.draggable && 'window-drag',\n local.macosInset && 'window-inset-macos',\n local.windowsInset && 'window-inset-windows',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** A side group. Both sides are equal remainders, which centres the search. */\nexport function TopBarSection(props: ComponentProps<'div'> & { align?: 'start' | 'end' }) {\n const [local, rest] = splitProps(props, ['class', 'align'])\n\n return (\n <div\n data-slot=\"top-bar-section\"\n class={cn(\n 'flex min-w-0 items-center gap-2 overflow-hidden',\n local.align === 'end' && 'justify-end',\n local.align !== 'end' && 'justify-start',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function TopBarTitle(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"top-bar-title\"\n class={cn('truncate text-sm font-medium', local.class)}\n {...rest}\n />\n )\n}\n\n/** A breadcrumb or path readout that yields to the actions when space runs out. */\nexport function TopBarBreadcrumb(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"top-bar-breadcrumb\"\n class={cn('flex min-w-0 items-center gap-1.5 text-sm', local.class)}\n {...rest}\n />\n )\n}\n\nexport type TopBarSearchProps = ComponentProps<'button'> & {\n /** The hint shown inside the field, e.g. \"Search projects and files\". */\n placeholder?: string\n /** The shortcut chip drawn at the trailing edge, e.g. \"⌘K\". */\n shortcut?: string\n}\n\n/**\n * The search affordance in the middle track.\n *\n * It is a button, not an input, and that is deliberate: clicking it opens the\n * command palette, which already owns the input, the ranking and the keyboard\n * handling. A second live input here would be a second source of truth for the\n * same query. It is styled to read as a field because that is what it behaves\n * like from the user's side.\n */\nexport function TopBarSearch(props: TopBarSearchProps) {\n const [local, rest] = splitProps(props, ['class', 'placeholder', 'shortcut'])\n\n return (\n <button\n type=\"button\"\n data-slot=\"top-bar-search\"\n class={cn(\n 'text-muted-foreground flex h-control-md w-full items-center gap-2 rounded-md border border-input px-3 text-sm',\n 'transition-colors ease-out outline-none',\n 'hover:bg-surface-hover hover:text-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'window-no-drag',\n local.class\n )}\n {...rest}\n >\n <span class=\"truncate\">{local.placeholder ?? 'Search'}</span>\n <Show when={local.shortcut}>\n <kbd class=\"bg-muted ms-auto hidden h-5 shrink-0 items-center rounded-sm border border-border px-1.5 font-mono text-2xs sm:flex\">\n {local.shortcut}\n </kbd>\n </Show>\n </button>\n )\n}\n\n/**\n * A labelled top-bar control — the readouts KiroCrew puts in the trailing\n * group. Container queries on the group decide which of these survive a narrow\n * window; a caller marks the cheap-to-drop ones and the group handles the rest.\n */\nexport function TopBarPill(props: ComponentProps<'button'> & { label: string }) {\n const [local, rest] = splitProps(props, ['class', 'label', 'children'])\n\n return (\n <button\n type=\"button\"\n data-slot=\"top-bar-pill\"\n class={cn(\n 'text-muted-foreground inline-flex h-control-sm shrink-0 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium',\n 'transition-colors ease-out outline-none',\n 'hover:border-input hover:text-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'window-no-drag [&_svg]:size-3.5 [&_svg]:shrink-0',\n local.class\n )}\n {...rest}\n >\n {local.children}\n <span>{local.label}</span>\n </button>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"top-bar.js","names":["ComponentProps","Show","splitProps","cn","TopBarProps","draggable","macosInset","windowsInset","glass","TopBar","props","local","rest","_el$","_tmpl$","_$spread","_$mergeProps","class","TopBarSection","align","_el$2","_tmpl$2","TopBarTitle","_el$3","_tmpl$3","TopBarBreadcrumb","_el$4","_tmpl$4","TopBarSearchProps","placeholder","shortcut","TopBarSearch","_el$5","_tmpl$6","_el$6","firstChild","_$insert","_$createComponent","when","children","_el$7","_tmpl$5","TopBarPill","label","_el$8","_tmpl$7","_el$9","_$mergeProps","_$createComponent"],"sources":["../../../../src/components/layout/top-bar/top-bar.tsx"],"sourcesContent":["import type { ComponentProps } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * TopBar.\n *\n * The window's title row and primary toolbar. Three tracks: a leading group, a\n * centred search, and a trailing group. The search is a fixed function of the\n * window width and the two side groups are equal remainders, which is what\n * makes the search *exactly* window-centred by construction — no measurement,\n * no observer, no absolutely-positioned overlay to keep clear of.\n *\n * On a frameless desktop window this row is also the drag region, so it carries\n * `window-drag` and the controls inside it opt back out. `macos-inset` and\n * `windows-inset` reserve the space the native window controls occupy, which is\n * why the row can look off-centre in a frameless window and be correct: it is\n * centred in the space the user can actually see.\n */\nexport type TopBarProps = ComponentProps<'header'> & {\n /** Make the row draggable, for a frameless window. */\n draggable?: boolean\n /** Reserve space for the macOS traffic lights. */\n macosInset?: boolean\n /** Reserve space for the Windows caption buttons. */\n windowsInset?: boolean\n /** Blur the content scrolling under the bar. */\n glass?: boolean\n}\n\nexport function TopBar(props: TopBarProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'draggable',\n 'macosInset',\n 'windowsInset',\n 'glass',\n ])\n\n return (\n <header\n data-slot=\"top-bar\"\n class={cn(\n 'h-topbar relative z-(--z-sticky) grid shrink-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-3 border-b border-border bg-card text-card-foreground px-3 md:grid-cols-[minmax(0,1fr)_clamp(240px,22vw,480px)_minmax(0,1fr)]',\n local.glass && 'glass-panel',\n local.draggable && 'window-drag',\n local.macosInset && 'window-inset-macos',\n local.windowsInset && 'window-inset-windows',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** A side group. Both sides are equal remainders, which centres the search. */\nexport function TopBarSection(props: ComponentProps<'div'> & { align?: 'start' | 'end' }) {\n const [local, rest] = splitProps(props, ['class', 'align'])\n\n return (\n <div\n data-slot=\"top-bar-section\"\n class={cn(\n 'window-no-drag flex min-w-0 items-center gap-2 overflow-x-auto overflow-y-hidden',\n local.align === 'end' && 'justify-end',\n local.align !== 'end' && 'justify-start',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function TopBarTitle(props: ComponentProps<'div'> & { align?: 'start' | 'center' }) {\n const [local, rest] = splitProps(props, ['class', 'align'])\n return (\n <div\n data-slot=\"top-bar-title\"\n class={cn(\n 'truncate text-sm font-medium',\n local.align === 'center' && 'text-center',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** A breadcrumb or path readout that yields to the actions when space runs out. */\nexport function TopBarBreadcrumb(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"top-bar-breadcrumb\"\n class={cn('flex min-w-0 items-center gap-1.5 text-sm', local.class)}\n {...rest}\n />\n )\n}\n\nexport type TopBarSearchProps = ComponentProps<'button'> & {\n /** The hint shown inside the field, e.g. \"Search projects and files\". */\n placeholder?: string\n /** The shortcut chip drawn at the trailing edge, e.g. \"⌘K\". */\n shortcut?: string\n}\n\n/**\n * The search affordance in the middle track.\n *\n * It is a button, not an input, and that is deliberate: clicking it opens the\n * command palette, which already owns the input, the ranking and the keyboard\n * handling. A second live input here would be a second source of truth for the\n * same query. It is styled to read as a field because that is what it behaves\n * like from the user's side.\n */\nexport function TopBarSearch(props: TopBarSearchProps) {\n const [local, rest] = splitProps(props, ['class', 'placeholder', 'shortcut'])\n\n return (\n <button\n type=\"button\"\n data-slot=\"top-bar-search\"\n class={cn(\n 'text-muted-foreground flex h-control-md w-full items-center gap-2 rounded-md border border-input px-3 text-sm',\n 'transition-colors ease-out outline-none',\n 'hover:bg-surface-hover hover:text-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'window-no-drag',\n local.class\n )}\n {...rest}\n >\n <span class=\"truncate\">{local.placeholder ?? 'Search'}</span>\n <Show when={local.shortcut}>\n <kbd class=\"bg-muted ms-auto hidden h-5 shrink-0 items-center rounded-sm border border-border px-1.5 font-mono text-2xs sm:flex\">\n {local.shortcut}\n </kbd>\n </Show>\n </button>\n )\n}\n\n/**\n * A labelled top-bar control — the readouts KiroCrew puts in the trailing\n * group. Container queries on the group decide which of these survive a narrow\n * window; a caller marks the cheap-to-drop ones and the group handles the rest.\n */\nexport function TopBarPill(props: ComponentProps<'button'> & { label: string }) {\n const [local, rest] = splitProps(props, ['class', 'label', 'children'])\n\n return (\n <button\n type=\"button\"\n data-slot=\"top-bar-pill\"\n class={cn(\n 'text-muted-foreground inline-flex h-control-sm shrink-0 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium',\n 'transition-colors ease-out outline-none',\n 'hover:border-input hover:text-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'window-no-drag [&_svg]:size-3.5 [&_svg]:shrink-0',\n local.class\n )}\n {...rest}\n >\n {local.children}\n <span>{local.label}</span>\n </button>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/tabs/tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAI9C;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,kCAQ7D;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG;IACpE,UAAU,CAAC,EAAE,WAAW,GAAG,WAAW,CAAA;CACvC,CAAA;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kCAgB5C;AAED,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,GAAG;IAC1E,UAAU,CAAC,EAAE,WAAW,GAAG,WAAW,CAAA;CACvC,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,kCAoBlD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,kCAG5E"}
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/tabs/tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,UAAU,CAAA;AA2BxD;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,kCAiC7D;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG;IACpE,UAAU,CAAC,EAAE,WAAW,GAAG,WAAW,CAAA;CACvC,CAAA;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kCAgB5C;AAED,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,GAAG;IAC1E,UAAU,CAAC,EAAE,WAAW,GAAG,WAAW,CAAA;CACvC,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,kCA+BlD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,kCAc5E"}
@@ -1,8 +1,14 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { createComponent, mergeProps } from "solid-js/web";
3
- import { splitProps } from "solid-js";
3
+ import { createContext, createRenderEffect, createSignal, createUniqueId, onCleanup, splitProps, useContext } from "solid-js";
4
4
  import { Tabs } from "@kobalte/core/tabs";
5
5
  //#region src/components/ui/tabs/tabs.tsx
6
+ var TabsIdContext = createContext();
7
+ function useTabsId() {
8
+ const tabs = useContext(TabsIdContext);
9
+ if (!tabs) throw new Error("[adea-ui]: Tabs parts must be used within Tabs.");
10
+ return tabs;
11
+ }
6
12
  /**
7
13
  * Tabs.
8
14
  *
@@ -14,10 +20,38 @@ import { Tabs } from "@kobalte/core/tabs";
14
20
  * where a full-width underline would collide with the panel's own header rule.
15
21
  */
16
22
  function Tabs$1(props) {
17
- const [local, rest] = splitProps(props, ["class"]);
18
- return createComponent(Tabs, mergeProps({ get ["class"]() {
19
- return cn("flex flex-col gap-2 data-[orientation=vertical]:flex-row", local.class);
20
- } }, rest));
23
+ const [local, rest] = splitProps(props, ["class", "id"]);
24
+ const generatedId = `tabs-${createUniqueId()}`;
25
+ const id = () => local.id ?? generatedId;
26
+ const [triggerIds, setTriggerIds] = createSignal(/* @__PURE__ */ new Map());
27
+ const tabs = {
28
+ id,
29
+ triggerIds,
30
+ registerTriggerId: (value, triggerId) => {
31
+ setTriggerIds((current) => new Map(current).set(value, triggerId));
32
+ },
33
+ unregisterTriggerId: (value, triggerId) => {
34
+ setTriggerIds((current) => {
35
+ if (current.get(value) !== triggerId) return current;
36
+ const next = new Map(current);
37
+ next.delete(value);
38
+ return next;
39
+ });
40
+ }
41
+ };
42
+ return createComponent(TabsIdContext.Provider, {
43
+ value: tabs,
44
+ get children() {
45
+ return createComponent(Tabs, mergeProps({
46
+ get id() {
47
+ return id();
48
+ },
49
+ get ["class"]() {
50
+ return cn("flex min-h-0 min-w-0 flex-col gap-2 data-[orientation=vertical]:flex-row", local.class);
51
+ }
52
+ }, rest));
53
+ }
54
+ });
21
55
  }
22
56
  function TabsList(props) {
23
57
  const [local, rest] = splitProps(props, ["class", "appearance"]);
@@ -26,16 +60,39 @@ function TabsList(props) {
26
60
  } }, rest));
27
61
  }
28
62
  function TabsTrigger(props) {
29
- const [local, rest] = splitProps(props, ["class", "appearance"]);
30
- return createComponent(Tabs.Trigger, mergeProps({ get ["class"]() {
31
- return cn("inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium", "transition-colors ease-out outline-none select-none", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle", "disabled:pointer-events-none disabled:opacity-50", "text-foreground", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4", local.appearance === "segmented" ? "h-control-sm rounded-md px-control-sm data-[selected]:bg-card data-[selected]:shadow-xs" : "h-control-md -mb-px rounded-none border-b-2 border-transparent px-2 pb-2 data-[selected]:border-primary", local.class);
32
- } }, rest));
63
+ const [local, rest] = splitProps(props, [
64
+ "class",
65
+ "appearance",
66
+ "id"
67
+ ]);
68
+ const tabs = useTabsId();
69
+ const triggerId = () => local.id ?? `${tabs.id()}-trigger-${rest.value}`;
70
+ createRenderEffect(() => {
71
+ const value = rest.value;
72
+ const id = triggerId();
73
+ tabs.registerTriggerId(value, id);
74
+ onCleanup(() => tabs.unregisterTriggerId(value, id));
75
+ });
76
+ return createComponent(Tabs.Trigger, mergeProps({
77
+ get id() {
78
+ return triggerId();
79
+ },
80
+ get ["class"]() {
81
+ return cn("inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium", "transition-colors ease-out outline-none select-none", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle", "disabled:pointer-events-none disabled:opacity-50", "text-foreground", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4", local.appearance === "segmented" ? "h-control-sm rounded-md px-control-sm data-[selected]:bg-card data-[selected]:shadow-xs" : "h-control-md -mb-px rounded-none border-b-2 border-transparent px-2 pb-2 data-[selected]:border-primary", local.class);
82
+ }
83
+ }, rest));
33
84
  }
34
85
  function TabsContent(props) {
35
- const [local, rest] = splitProps(props, ["class"]);
36
- return createComponent(Tabs.Content, mergeProps({ get ["class"]() {
37
- return cn("flex-1 outline-none", local.class);
38
- } }, rest));
86
+ const [local, rest] = splitProps(props, ["class", "aria-labelledby"]);
87
+ const tabs = useTabsId();
88
+ return createComponent(Tabs.Content, mergeProps({
89
+ get ["aria-labelledby"]() {
90
+ return local["aria-labelledby"] ?? tabs.triggerIds().get(rest.value) ?? `${tabs.id()}-trigger-${rest.value}`;
91
+ },
92
+ get ["class"]() {
93
+ return cn("min-h-0 min-w-0 flex-1 outline-none", local.class);
94
+ }
95
+ }, rest));
39
96
  }
40
97
  //#endregion
41
98
  export { Tabs$1 as Tabs, TabsContent, TabsList, TabsTrigger };
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.js","names":["Tabs","KobalteTabs","ComponentProps","splitProps","cn","props","local","rest","_$createComponent","_$mergeProps","class","TabsListProps","List","appearance","TabsList","TabsTriggerProps","Trigger","TabsTrigger","TabsContent","Content","Tabs","_$createComponent","KobalteTabs","_$mergeProps"],"sources":["../../../../src/components/ui/tabs/tabs.tsx"],"sourcesContent":["import { Tabs as KobalteTabs } from '@kobalte/core/tabs'\nimport type { ComponentProps } from 'solid-js'\nimport { splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * Tabs.\n *\n * For switching between sibling views of the *same* subject — a file's code,\n * diff and history. Not for moving between pages: a tab is expected to keep\n * its panel and its scroll position, which a route does not.\n *\n * `appearance=\"segmented\"` gives the joined bar KiroCrew uses inside a pane\n * where a full-width underline would collide with the panel's own header rule.\n */\nexport function Tabs(props: ComponentProps<typeof KobalteTabs>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteTabs\n class={cn('flex flex-col gap-2 data-[orientation=vertical]:flex-row', local.class)}\n {...rest}\n />\n )\n}\n\nexport type TabsListProps = ComponentProps<typeof KobalteTabs.List> & {\n appearance?: 'underline' | 'segmented'\n}\n\nexport function TabsList(props: TabsListProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance'])\n\n return (\n <KobalteTabs.List\n class={cn(\n 'inline-flex w-fit shrink-0 items-center justify-center',\n local.appearance === 'segmented'\n ? 'gap-0.5 rounded-lg bg-surface-hover p-0.5'\n : 'gap-1 rounded-none border-b border-border',\n 'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport type TabsTriggerProps = ComponentProps<typeof KobalteTabs.Trigger> & {\n appearance?: 'underline' | 'segmented'\n}\n\nexport function TabsTrigger(props: TabsTriggerProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance'])\n\n return (\n <KobalteTabs.Trigger\n class={cn(\n 'inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium',\n 'transition-colors ease-out outline-none select-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'disabled:pointer-events-none disabled:opacity-50',\n 'text-foreground',\n '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4',\n local.appearance === 'segmented'\n ? 'h-control-sm rounded-md px-control-sm data-[selected]:bg-card data-[selected]:shadow-xs'\n : 'h-control-md -mb-px rounded-none border-b-2 border-transparent px-2 pb-2 data-[selected]:border-primary',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function TabsContent(props: ComponentProps<typeof KobalteTabs.Content>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteTabs.Content class={cn('flex-1 outline-none', local.class)} {...rest} />\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAgBA,OAAKK,OAA2C;CAC9D,MAAM,CAACC,OAAOC,QAAQJ,WAAWE,OAAO,CAAC,OAAO,CAAC;CACjD,OAAAG,gBACGP,MAAWQ,WAAA,EAAA,KAAA,WAAA;EAAA,OACHL,GAAG,4DAA4DE,MAAMI,KAAK;CAAC,EAAA,GAC9EH,IAAI,CAAA;AAGd;AAMA,SAAgBO,SAAST,OAAsB;CAC7C,MAAM,CAACC,OAAOC,QAAQJ,WAAWE,OAAO,CAAC,SAAS,YAAY,CAAC;CAE/D,OAAAG,gBACGP,KAAYW,MAAIH,WAAA,EAAA,KAAA,WAAA;EAAA,OACRL,GACL,0DACAE,MAAMO,eAAe,cACjB,8CACA,6CACJ,kFACAP,MAAMI,KACR;CAAC,EAAA,GACGH,IAAI,CAAA;AAGd;AAMA,SAAgBU,YAAYZ,OAAyB;CACnD,MAAM,CAACC,OAAOC,QAAQJ,WAAWE,OAAO,CAAC,SAAS,YAAY,CAAC;CAE/D,OAAAG,gBACGP,KAAYe,SAAOP,WAAA,EAAA,KAAA,WAAA;EAAA,OACXL,GACL,kGACA,uDACA,oFACA,oDACA,mBACA,+DACAE,MAAMO,eAAe,cACjB,4FACA,2GACJP,MAAMI,KACR;CAAC,EAAA,GACGH,IAAI,CAAA;AAGd;AAEA,SAAgBW,YAAYb,OAAmD;CAC7E,MAAM,CAACC,OAAOC,QAAQJ,WAAWE,OAAO,CAAC,OAAO,CAAC;CACjD,OAAAG,gBAAQP,KAAYkB,SAAOV,WAAA,EAAA,KAAA,WAAA;EAAA,OAAQL,GAAG,uBAAuBE,MAAMI,KAAK;CAAC,EAAA,GAAMH,IAAI,CAAA;AACrF"}
1
+ {"version":3,"file":"tabs.js","names":["Tabs","KobalteTabs","Accessor","ComponentProps","createContext","createRenderEffect","createSignal","createUniqueId","onCleanup","splitProps","useContext","cn","TabsIdContextValue","id","triggerIds","ReadonlyMap","registerTriggerId","value","unregisterTriggerId","TabsIdContext","useTabsId","tabs","Error","props","local","rest","generatedId","setTriggerIds","Map","triggerId","current","set","get","next","delete","_$createComponent","Provider","children","_$mergeProps","class","TabsListProps","List","appearance","TabsList","TabsTriggerProps","Trigger","TabsTrigger","TabsContent","Content","aria-labelledby","Tabs","_$createComponent","KobalteTabs","_$mergeProps"],"sources":["../../../../src/components/ui/tabs/tabs.tsx"],"sourcesContent":["import { Tabs as KobalteTabs } from '@kobalte/core/tabs'\nimport type { Accessor, ComponentProps } from 'solid-js'\nimport {\n createContext,\n createRenderEffect,\n createSignal,\n createUniqueId,\n onCleanup,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { cn } from '#lib/utils'\n\ntype TabsIdContextValue = {\n id: Accessor<string>\n triggerIds: Accessor<ReadonlyMap<string, string>>\n registerTriggerId: (value: string, id: string) => void\n unregisterTriggerId: (value: string, id: string) => void\n}\n\nconst TabsIdContext = createContext<TabsIdContextValue>()\n\nfunction useTabsId() {\n const tabs = useContext(TabsIdContext)\n if (!tabs) throw new Error('[adea-ui]: Tabs parts must be used within Tabs.')\n return tabs\n}\n\n/**\n * Tabs.\n *\n * For switching between sibling views of the *same* subject — a file's code,\n * diff and history. Not for moving between pages: a tab is expected to keep\n * its panel and its scroll position, which a route does not.\n *\n * `appearance=\"segmented\"` gives the joined bar KiroCrew uses inside a pane\n * where a full-width underline would collide with the panel's own header rule.\n */\nexport function Tabs(props: ComponentProps<typeof KobalteTabs>) {\n const [local, rest] = splitProps(props, ['class', 'id'])\n const generatedId = `tabs-${createUniqueId()}`\n const id = () => local.id ?? generatedId\n const [triggerIds, setTriggerIds] = createSignal<ReadonlyMap<string, string>>(new Map())\n const tabs: TabsIdContextValue = {\n id,\n triggerIds,\n registerTriggerId: (value, triggerId) => {\n setTriggerIds((current) => new Map(current).set(value, triggerId))\n },\n unregisterTriggerId: (value, triggerId) => {\n setTriggerIds((current) => {\n if (current.get(value) !== triggerId) return current\n const next = new Map(current)\n next.delete(value)\n return next\n })\n },\n }\n\n return (\n <TabsIdContext.Provider value={tabs}>\n <KobalteTabs\n id={id()}\n class={cn(\n 'flex min-h-0 min-w-0 flex-col gap-2 data-[orientation=vertical]:flex-row',\n local.class\n )}\n {...rest}\n />\n </TabsIdContext.Provider>\n )\n}\n\nexport type TabsListProps = ComponentProps<typeof KobalteTabs.List> & {\n appearance?: 'underline' | 'segmented'\n}\n\nexport function TabsList(props: TabsListProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance'])\n\n return (\n <KobalteTabs.List\n class={cn(\n 'inline-flex w-fit shrink-0 items-center justify-center',\n local.appearance === 'segmented'\n ? 'gap-0.5 rounded-lg bg-surface-hover p-0.5'\n : 'gap-1 rounded-none border-b border-border',\n 'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport type TabsTriggerProps = ComponentProps<typeof KobalteTabs.Trigger> & {\n appearance?: 'underline' | 'segmented'\n}\n\nexport function TabsTrigger(props: TabsTriggerProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance', 'id'])\n const tabs = useTabsId()\n const triggerId = () => local.id ?? `${tabs.id()}-trigger-${rest.value}`\n\n // Register before panels render, including SSR where createEffect is skipped.\n createRenderEffect(() => {\n const value = rest.value\n const id = triggerId()\n tabs.registerTriggerId(value, id)\n onCleanup(() => tabs.unregisterTriggerId(value, id))\n })\n\n return (\n <KobalteTabs.Trigger\n id={triggerId()}\n class={cn(\n 'inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium',\n 'transition-colors ease-out outline-none select-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'disabled:pointer-events-none disabled:opacity-50',\n 'text-foreground',\n '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4',\n local.appearance === 'segmented'\n ? 'h-control-sm rounded-md px-control-sm data-[selected]:bg-card data-[selected]:shadow-xs'\n : 'h-control-md -mb-px rounded-none border-b-2 border-transparent px-2 pb-2 data-[selected]:border-primary',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function TabsContent(props: ComponentProps<typeof KobalteTabs.Content>) {\n const [local, rest] = splitProps(props, ['class', 'aria-labelledby'])\n const tabs = useTabsId()\n return (\n <KobalteTabs.Content\n aria-labelledby={\n local['aria-labelledby'] ??\n tabs.triggerIds().get(rest.value) ??\n `${tabs.id()}-trigger-${rest.value}`\n }\n class={cn('min-h-0 min-w-0 flex-1 outline-none', local.class)}\n {...rest}\n />\n )\n}\n"],"mappings":";;;;;AAoBA,IAAMmB,gBAAgBf,cAAkC;AAExD,SAASgB,YAAY;CACnB,MAAMC,OAAOX,WAAWS,aAAa;CACrC,IAAI,CAACE,MAAM,MAAM,IAAIC,MAAM,iDAAiD;CAC5E,OAAOD;AACT;;;;;;;;;;;AAYA,SAAgBrB,OAAKuB,OAA2C;CAC9D,MAAM,CAACC,OAAOC,QAAQhB,WAAWc,OAAO,CAAC,SAAS,IAAI,CAAC;CACvD,MAAMG,cAAc,QAAQnB,eAAe;CAC3C,MAAMM,WAAWW,MAAMX,MAAMa;CAC7B,MAAM,CAACZ,YAAYa,iBAAiBrB,6BAA0C,IAAIsB,IAAI,CAAC;CACvF,MAAMP,OAA2B;EAC/BR;EACAC;EACAE,oBAAoBC,OAAOY,cAAc;GACvCF,eAAeG,YAAY,IAAIF,IAAIE,OAAO,CAAC,CAACC,IAAId,OAAOY,SAAS,CAAC;EACnE;EACAX,sBAAsBD,OAAOY,cAAc;GACzCF,eAAeG,YAAY;IACzB,IAAIA,QAAQE,IAAIf,KAAK,MAAMY,WAAW,OAAOC;IAC7C,MAAMG,OAAO,IAAIL,IAAIE,OAAO;IAC5BG,KAAKC,OAAOjB,KAAK;IACjB,OAAOgB;GACT,CAAC;EACH;CACF;CAEA,OAAAE,gBACGhB,cAAciB,UAAQ;EAACnB,OAAOI;EAAI,IAAAgB,WAAA;GAAA,OAAAF,gBAChClC,MAAWqC,WAAA;IAAA,IACVzB,KAAE;KAAA,OAAEA,GAAG;IAAC;IAAA,KAAA,WAAA;KAAA,OACDF,GACL,4EACAa,MAAMe,KACR;IAAC;GAAA,GACGd,IAAI,CAAA;EAAA;CAAA,CAAA;AAIhB;AAMA,SAAgBkB,SAASpB,OAAsB;CAC7C,MAAM,CAACC,OAAOC,QAAQhB,WAAWc,OAAO,CAAC,SAAS,YAAY,CAAC;CAE/D,OAAAY,gBACGlC,KAAYwC,MAAIH,WAAA,EAAA,KAAA,WAAA;EAAA,OACR3B,GACL,0DACAa,MAAMkB,eAAe,cACjB,8CACA,6CACJ,kFACAlB,MAAMe,KACR;CAAC,EAAA,GACGd,IAAI,CAAA;AAGd;AAMA,SAAgBqB,YAAYvB,OAAyB;CACnD,MAAM,CAACC,OAAOC,QAAQhB,WAAWc,OAAO;EAAC;EAAS;EAAc;CAAI,CAAC;CACrE,MAAMF,OAAOD,UAAU;CACvB,MAAMS,kBAAkBL,MAAMX,MAAM,GAAGQ,KAAKR,GAAG,EAAC,WAAYY,KAAKR;CAGjEZ,yBAAyB;EACvB,MAAMY,QAAQQ,KAAKR;EACnB,MAAMJ,KAAKgB,UAAU;EACrBR,KAAKL,kBAAkBC,OAAOJ,EAAE;EAChCL,gBAAgBa,KAAKH,oBAAoBD,OAAOJ,EAAE,CAAC;CACrD,CAAC;CAED,OAAAsB,gBACGlC,KAAY4C,SAAOP,WAAA;EAAA,IAClBzB,KAAE;GAAA,OAAEgB,UAAU;EAAC;EAAA,KAAA,WAAA;GAAA,OACRlB,GACL,kGACA,uDACA,oFACA,oDACA,mBACA,+DACAa,MAAMkB,eAAe,cACjB,4FACA,2GACJlB,MAAMe,KACR;EAAC;CAAA,GACGd,IAAI,CAAA;AAGd;AAEA,SAAgBsB,YAAYxB,OAAmD;CAC7E,MAAM,CAACC,OAAOC,QAAQhB,WAAWc,OAAO,CAAC,SAAS,iBAAiB,CAAC;CACpE,MAAMF,OAAOD,UAAU;CACvB,OAAAe,gBACGlC,KAAY+C,SAAOV,WAAA;EAAA,KAAA,qBAAA;GAAA,OAEhBd,MAAM,sBACNH,KAAKP,WAAW,CAAC,CAACkB,IAAIP,KAAKR,KAAK,KAChC,GAAGI,KAAKR,GAAG,EAAC,WAAYY,KAAKR;EAAO;EAAA,KAAA,WAAA;GAAA,OAE/BN,GAAG,uCAAuCa,MAAMe,KAAK;EAAC;CAAA,GACzDd,IAAI,CAAA;AAGd"}