@adea-ai/ui 0.95.4 → 0.95.6

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.
@@ -19,23 +19,10 @@ export type SettingsNavigationProps = Omit<TabsListProps, 'appearance' | 'childr
19
19
  value: string;
20
20
  /** Called when the already-selected destination is activated again. */
21
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. */
22
+ /** Reveal the selected row on value changes and window resizes. Defaults to nearest scrolling
23
+ * of the ancestors that expose a scroll affordance; hidden-overflow ancestors never move. */
24
+ revealSelected?: boolean | ((trigger: HTMLButtonElement | undefined) => void); /** Every tab list needs a label independent of its visible group headings. */
25
25
  'aria-label': string;
26
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
27
  export declare function SettingsNavigation(props: SettingsNavigationProps): JSX.Element;
41
28
  //# sourceMappingURL=settings-navigation.d.ts.map
@@ -1 +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"}
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;iGAC6F;IAC7F,cAAc,CAAC,EACX,OAAO,GACP,CAAC,CACC,OAAO,EAAE,iBAAiB,GAAG,SAAS,KACnC,IAAI,CAAC,CAAA,CAAC,8EAA8E;IAC7F,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AA0CD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,eAqFhE"}
@@ -19,6 +19,29 @@ var _tmpl$2 = /*#__PURE__*/ template(`<span class="min-w-0 truncate">`);
19
19
  * `revealSelected={false}` when the surrounding layout does not use an internal
20
20
  * scrolling viewport.
21
21
  */
22
+ /**
23
+ * Reveal by scrolling only the ancestors that expose a scroll affordance
24
+ * (`auto` or `scroll`), by the exact nearest-edge delta. `scrollIntoView` also
25
+ * pans `overflow: hidden` ancestors, which are programmatically scrollable but
26
+ * give the user no way back, so one over-pan left earlier rows permanently
27
+ * clipped outside the viewport with no scroll to recover them (#182).
28
+ */
29
+ function scrollContainerNearest(container, row) {
30
+ const style = window.getComputedStyle(container);
31
+ const box = container.getBoundingClientRect();
32
+ const rowBox = row.getBoundingClientRect();
33
+ if (style.overflowX === "auto" || style.overflowX === "scroll") {
34
+ if (rowBox.left < box.left) container.scrollLeft += rowBox.left - box.left;
35
+ else if (rowBox.right > box.right) container.scrollLeft += rowBox.right - box.right;
36
+ }
37
+ if (style.overflowY === "auto" || style.overflowY === "scroll") {
38
+ if (rowBox.top < box.top) container.scrollTop += rowBox.top - box.top;
39
+ else if (rowBox.bottom > box.bottom) container.scrollTop += rowBox.bottom - box.bottom;
40
+ }
41
+ }
42
+ function revealNearest(row) {
43
+ for (let container = row.parentElement; container; container = container.parentElement) scrollContainerNearest(container, row);
44
+ }
22
45
  function SettingsNavigation(props) {
23
46
  const [local, rest] = splitProps(props, [
24
47
  "class",
@@ -37,10 +60,7 @@ function SettingsNavigation(props) {
37
60
  const revealCurrent = () => {
38
61
  const trigger = triggers.get(value);
39
62
  if (typeof reveal === "function") reveal(trigger);
40
- else trigger?.scrollIntoView({
41
- block: "nearest",
42
- inline: "nearest"
43
- });
63
+ else if (trigger) revealNearest(trigger);
44
64
  };
45
65
  revealCurrent();
46
66
  window.addEventListener("resize", revealCurrent);
@@ -1 +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"}
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","scrollContainerNearest","container","HTMLElement","row","style","window","getComputedStyle","box","getBoundingClientRect","rowBox","overflowX","left","scrollLeft","right","overflowY","top","scrollTop","bottom","revealNearest","parentElement","SettingsNavigation","props","local","rest","triggers","Map","groupIdPrefix","reveal","revealCurrent","get","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 scrolling\n * of the ancestors that expose a scroll affordance; hidden-overflow ancestors never move. */\n revealSelected?:\n | boolean\n | ((\n trigger: HTMLButtonElement | undefined\n ) => void) /** 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 */\n/**\n * Reveal by scrolling only the ancestors that expose a scroll affordance\n * (`auto` or `scroll`), by the exact nearest-edge delta. `scrollIntoView` also\n * pans `overflow: hidden` ancestors, which are programmatically scrollable but\n * give the user no way back, so one over-pan left earlier rows permanently\n * clipped outside the viewport with no scroll to recover them (#182).\n */\nfunction scrollContainerNearest(container: HTMLElement, row: HTMLElement): void {\n const style = window.getComputedStyle(container)\n const box = container.getBoundingClientRect()\n const rowBox = row.getBoundingClientRect()\n if (style.overflowX === 'auto' || style.overflowX === 'scroll') {\n if (rowBox.left < box.left) container.scrollLeft += rowBox.left - box.left\n else if (rowBox.right > box.right) container.scrollLeft += rowBox.right - box.right\n }\n if (style.overflowY === 'auto' || style.overflowY === 'scroll') {\n if (rowBox.top < box.top) container.scrollTop += rowBox.top - box.top\n else if (rowBox.bottom > box.bottom) container.scrollTop += rowBox.bottom - box.bottom\n }\n}\n\nfunction revealNearest(row: HTMLElement): void {\n for (let container = row.parentElement; container; container = container.parentElement) {\n scrollContainerNearest(container, row)\n }\n}\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 if (trigger) revealNearest(trigger)\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":"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"}
@@ -28,9 +28,13 @@ export type SettingsNavigationProps = Omit<
28
28
  value: string
29
29
  /** Called when the already-selected destination is activated again. */
30
30
  onReselect?: (value: string) => void
31
- /** Reveal the selected row on value changes and window resizes. Defaults to nearest scroll. */
32
- revealSelected?: boolean | ((trigger: HTMLButtonElement | undefined) => void)
33
- /** Every tab list needs a label independent of its visible group headings. */
31
+ /** Reveal the selected row on value changes and window resizes. Defaults to nearest scrolling
32
+ * of the ancestors that expose a scroll affordance; hidden-overflow ancestors never move. */
33
+ revealSelected?:
34
+ | boolean
35
+ | ((
36
+ trigger: HTMLButtonElement | undefined
37
+ ) => void) /** Every tab list needs a label independent of its visible group headings. */
34
38
  'aria-label': string
35
39
  }
36
40
 
@@ -47,6 +51,33 @@ export type SettingsNavigationProps = Omit<
47
51
  * `revealSelected={false}` when the surrounding layout does not use an internal
48
52
  * scrolling viewport.
49
53
  */
54
+ /**
55
+ * Reveal by scrolling only the ancestors that expose a scroll affordance
56
+ * (`auto` or `scroll`), by the exact nearest-edge delta. `scrollIntoView` also
57
+ * pans `overflow: hidden` ancestors, which are programmatically scrollable but
58
+ * give the user no way back, so one over-pan left earlier rows permanently
59
+ * clipped outside the viewport with no scroll to recover them (#182).
60
+ */
61
+ function scrollContainerNearest(container: HTMLElement, row: HTMLElement): void {
62
+ const style = window.getComputedStyle(container)
63
+ const box = container.getBoundingClientRect()
64
+ const rowBox = row.getBoundingClientRect()
65
+ if (style.overflowX === 'auto' || style.overflowX === 'scroll') {
66
+ if (rowBox.left < box.left) container.scrollLeft += rowBox.left - box.left
67
+ else if (rowBox.right > box.right) container.scrollLeft += rowBox.right - box.right
68
+ }
69
+ if (style.overflowY === 'auto' || style.overflowY === 'scroll') {
70
+ if (rowBox.top < box.top) container.scrollTop += rowBox.top - box.top
71
+ else if (rowBox.bottom > box.bottom) container.scrollTop += rowBox.bottom - box.bottom
72
+ }
73
+ }
74
+
75
+ function revealNearest(row: HTMLElement): void {
76
+ for (let container = row.parentElement; container; container = container.parentElement) {
77
+ scrollContainerNearest(container, row)
78
+ }
79
+ }
80
+
50
81
  export function SettingsNavigation(props: SettingsNavigationProps) {
51
82
  const [local, rest] = splitProps(props, [
52
83
  'class',
@@ -67,7 +98,7 @@ export function SettingsNavigation(props: SettingsNavigationProps) {
67
98
  const revealCurrent = () => {
68
99
  const trigger = triggers.get(value)
69
100
  if (typeof reveal === 'function') reveal(trigger)
70
- else trigger?.scrollIntoView({ block: 'nearest', inline: 'nearest' })
101
+ else if (trigger) revealNearest(trigger)
71
102
  }
72
103
 
73
104
  revealCurrent()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.95.4",
3
+ "version": "0.95.6",
4
4
  "description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
5
5
  "keywords": [
6
6
  "adea",
@@ -28,9 +28,13 @@ export type SettingsNavigationProps = Omit<
28
28
  value: string
29
29
  /** Called when the already-selected destination is activated again. */
30
30
  onReselect?: (value: string) => void
31
- /** Reveal the selected row on value changes and window resizes. Defaults to nearest scroll. */
32
- revealSelected?: boolean | ((trigger: HTMLButtonElement | undefined) => void)
33
- /** Every tab list needs a label independent of its visible group headings. */
31
+ /** Reveal the selected row on value changes and window resizes. Defaults to nearest scrolling
32
+ * of the ancestors that expose a scroll affordance; hidden-overflow ancestors never move. */
33
+ revealSelected?:
34
+ | boolean
35
+ | ((
36
+ trigger: HTMLButtonElement | undefined
37
+ ) => void) /** Every tab list needs a label independent of its visible group headings. */
34
38
  'aria-label': string
35
39
  }
36
40
 
@@ -47,6 +51,33 @@ export type SettingsNavigationProps = Omit<
47
51
  * `revealSelected={false}` when the surrounding layout does not use an internal
48
52
  * scrolling viewport.
49
53
  */
54
+ /**
55
+ * Reveal by scrolling only the ancestors that expose a scroll affordance
56
+ * (`auto` or `scroll`), by the exact nearest-edge delta. `scrollIntoView` also
57
+ * pans `overflow: hidden` ancestors, which are programmatically scrollable but
58
+ * give the user no way back, so one over-pan left earlier rows permanently
59
+ * clipped outside the viewport with no scroll to recover them (#182).
60
+ */
61
+ function scrollContainerNearest(container: HTMLElement, row: HTMLElement): void {
62
+ const style = window.getComputedStyle(container)
63
+ const box = container.getBoundingClientRect()
64
+ const rowBox = row.getBoundingClientRect()
65
+ if (style.overflowX === 'auto' || style.overflowX === 'scroll') {
66
+ if (rowBox.left < box.left) container.scrollLeft += rowBox.left - box.left
67
+ else if (rowBox.right > box.right) container.scrollLeft += rowBox.right - box.right
68
+ }
69
+ if (style.overflowY === 'auto' || style.overflowY === 'scroll') {
70
+ if (rowBox.top < box.top) container.scrollTop += rowBox.top - box.top
71
+ else if (rowBox.bottom > box.bottom) container.scrollTop += rowBox.bottom - box.bottom
72
+ }
73
+ }
74
+
75
+ function revealNearest(row: HTMLElement): void {
76
+ for (let container = row.parentElement; container; container = container.parentElement) {
77
+ scrollContainerNearest(container, row)
78
+ }
79
+ }
80
+
50
81
  export function SettingsNavigation(props: SettingsNavigationProps) {
51
82
  const [local, rest] = splitProps(props, [
52
83
  'class',
@@ -67,7 +98,7 @@ export function SettingsNavigation(props: SettingsNavigationProps) {
67
98
  const revealCurrent = () => {
68
99
  const trigger = triggers.get(value)
69
100
  if (typeof reveal === 'function') reveal(trigger)
70
- else trigger?.scrollIntoView({ block: 'nearest', inline: 'nearest' })
101
+ else if (trigger) revealNearest(trigger)
71
102
  }
72
103
 
73
104
  revealCurrent()