@adea-ai/ui 0.114.0 → 0.115.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/composites/list-row/list-row-control.d.ts +6 -0
- package/dist/components/composites/list-row/list-row-control.d.ts.map +1 -1
- package/dist/components/composites/list-row/list-row-control.js +4 -0
- package/dist/components/composites/list-row/list-row-control.js.map +1 -1
- package/dist/components/composites/tree/index.d.ts +1 -1
- package/dist/components/composites/tree/index.d.ts.map +1 -1
- package/dist/components/composites/tree/index.js +2 -2
- package/dist/components/composites/tree/tree.d.ts +12 -0
- package/dist/components/composites/tree/tree.d.ts.map +1 -1
- package/dist/components/composites/tree/tree.js +27 -2
- package/dist/components/composites/tree/tree.js.map +1 -1
- package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts +7 -0
- package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts.map +1 -1
- package/dist/components/layout/contextual-sidebar/contextual-sidebar.js +25 -6
- package/dist/components/layout/contextual-sidebar/contextual-sidebar.js.map +1 -1
- package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts +6 -0
- package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts.map +1 -1
- package/dist/components/layout/sidebar-nav/sidebar-nav.js +5 -3
- package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
- package/dist/components/layout/top-bar/top-bar.d.ts.map +1 -1
- package/dist/components/layout/top-bar/top-bar.js +3 -3
- package/dist/components/layout/top-bar/top-bar.js.map +1 -1
- package/dist/components/ui/input/input-control.d.ts +7 -1
- package/dist/components/ui/input/input-control.d.ts.map +1 -1
- package/dist/components/ui/input/input-control.js +10 -2
- package/dist/components/ui/input/input-control.js.map +1 -1
- package/dist/components/ui/input/input.d.ts +5 -4
- package/dist/components/ui/input/input.d.ts.map +1 -1
- package/dist/components/ui/input/input.js.map +1 -1
- package/dist/components/ui/modal-dialog/modal-dialog.d.ts +2 -1
- package/dist/components/ui/modal-dialog/modal-dialog.d.ts.map +1 -1
- package/dist/components/ui/modal-dialog/modal-dialog.js +3 -0
- package/dist/components/ui/modal-dialog/modal-dialog.js.map +1 -1
- package/dist/components/ui/resizable/resizable.d.ts.map +1 -1
- package/dist/components/ui/resizable/resizable.js +1 -1
- package/dist/components/ui/resizable/resizable.js.map +1 -1
- package/dist/components/ui/status-chip/status-chip.d.ts +5 -3
- package/dist/components/ui/status-chip/status-chip.d.ts.map +1 -1
- package/dist/components/ui/status-chip/status-chip.js +5 -1
- package/dist/components/ui/status-chip/status-chip.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/r/src/components/composites/list-row/list-row-control.tsx +8 -0
- package/dist/r/src/components/composites/tree/index.ts +1 -1
- package/dist/r/src/components/composites/tree/tree.tsx +31 -1
- package/dist/r/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +23 -4
- package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +25 -2
- package/dist/r/src/components/layout/top-bar/top-bar.tsx +14 -5
- package/dist/r/src/components/ui/input/input-control.tsx +14 -3
- package/dist/r/src/components/ui/input/input.tsx +5 -5
- package/dist/r/src/components/ui/modal-dialog/modal-dialog.tsx +3 -1
- package/dist/r/src/components/ui/resizable/resizable.tsx +4 -3
- package/dist/r/src/components/ui/status-chip/status-chip.tsx +13 -2
- package/dist/r/src/styles/base.css +7 -6
- package/package.json +1 -1
- package/src/components/composites/list-row/list-row-control.tsx +8 -0
- package/src/components/composites/tree/index.ts +1 -1
- package/src/components/composites/tree/tree.tsx +31 -1
- package/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +23 -4
- package/src/components/layout/sidebar-nav/sidebar-nav.tsx +25 -2
- package/src/components/layout/top-bar/top-bar.tsx +14 -5
- package/src/components/ui/input/input-control.tsx +14 -3
- package/src/components/ui/input/input.tsx +5 -5
- package/src/components/ui/modal-dialog/modal-dialog.tsx +3 -1
- package/src/components/ui/resizable/resizable.tsx +4 -3
- package/src/components/ui/status-chip/status-chip.tsx +13 -2
- package/src/styles/base.css +7 -6
|
@@ -12,6 +12,12 @@ export type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicP
|
|
|
12
12
|
trailing?: JSX.Element;
|
|
13
13
|
/** A second line that wraps and grows the row to fit its content. */
|
|
14
14
|
description?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Whether a described row may drop its trailing slot onto its own line when
|
|
17
|
+
* the row gets narrow (the default). Pass `false` for a short, truncating
|
|
18
|
+
* label whose single action must stay beside it.
|
|
19
|
+
*/
|
|
20
|
+
stackTrailing?: boolean;
|
|
15
21
|
/** Native button type; defaults to `button` for button rows. */
|
|
16
22
|
type?: ComponentProps<'button'>['type'];
|
|
17
23
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-row-control.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAInE,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAClF,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oDAAoD;IACpD,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gEAAgE;IAChE,IAAI,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAA;CACxC,CACF,CAAA;AAMD,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"list-row-control.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAInE,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAClF,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oDAAoD;IACpD,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,gEAAgE;IAChE,IAAI,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAA;CACxC,CACF,CAAA;AAMD,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,eA+E7F"}
|
|
@@ -17,6 +17,7 @@ function ListRowControl(props) {
|
|
|
17
17
|
"leading",
|
|
18
18
|
"trailing",
|
|
19
19
|
"description",
|
|
20
|
+
"stackTrailing",
|
|
20
21
|
"type",
|
|
21
22
|
"tabIndex",
|
|
22
23
|
"children"
|
|
@@ -42,6 +43,9 @@ function ListRowControl(props) {
|
|
|
42
43
|
get ["data-description"]() {
|
|
43
44
|
return local.description ? "" : void 0;
|
|
44
45
|
},
|
|
46
|
+
get ["data-stack-trailing"]() {
|
|
47
|
+
return local.stackTrailing === false ? "never" : void 0;
|
|
48
|
+
},
|
|
45
49
|
get ["class"]() {
|
|
46
50
|
return cn("group/row list-row-description flex min-w-0 items-center gap-2.5 rounded-md px-2 text-sm", "transition-colors ease-out outline-none", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle", {
|
|
47
51
|
"h-row-sm": local.dense && !local.description,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-row-control.js","names":["PolymorphicProps","Polymorphic","ComponentProps","JSX","ValidComponent","Show","splitProps","cn","ListRowControlProps","T","class","selected","dense","leading","Element","trailing","description","type","ListRowControlBaseProps","as","ListRowControl","props","local","rest","hasClickHandler","Boolean","onClick","rowAs","_$createComponent","_$mergeProps","_$memo","tabIndex","undefined","aria-current","data-selected","data-description","children","when","_el$","_tmpl$","_$insert","_el$2","_tmpl$4","_el$3","firstChild","_el$4","_el$5","_tmpl$2","_$effect","_$className","_el$6","_tmpl$3","_$createComponent","_$mergeProps","_$memo","_$className"],"sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"sourcesContent":["import type { PolymorphicProps } from '@kobalte/core/polymorphic'\nimport { Polymorphic } from '@kobalte/core/polymorphic'\nimport type { ComponentProps, JSX, ValidComponent } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\nexport type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicProps<\n T,\n {\n class?: string\n /** Marks the row as current. Sets `aria-current` for a link row. */\n selected?: boolean\n /** Draw the row at the compact height. */\n dense?: boolean\n /** Leading slot: an avatar, an icon, a checkbox. */\n leading?: JSX.Element\n /** Trailing slot: a count, a menu trigger, a timestamp. */\n trailing?: JSX.Element\n /** A second line that wraps and grows the row to fit its content. */\n description?: string\n /** Native button type; defaults to `button` for button rows. */\n type?: ComponentProps<'button'>['type']\n }\n>\n\ntype ListRowControlBaseProps<T extends ValidComponent = 'div'> = ListRowControlProps<T> & {\n as?: T\n}\n\n/** A tree-shakeable ListRow renderer without optional tooltip behavior. */\nexport function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowControlProps<T>) {\n const [local, rest] = splitProps(props as ListRowControlBaseProps, [\n 'as',\n 'class',\n 'selected',\n 'dense',\n 'leading',\n 'trailing',\n 'description',\n 'type',\n 'tabIndex',\n 'children',\n ])\n const hasClickHandler = () => Boolean(rest.onClick || rest['on:click'])\n const rowAs = () => (local.as ?? (hasClickHandler() ? 'button' : 'div')) as T\n\n return (\n <Polymorphic\n as={rowAs()}\n type={rowAs() === 'button' ? (local.type ?? 'button') : local.type}\n tabIndex={local.tabIndex ?? (rowAs() === 'button' || rowAs() === 'a' ? 0 : undefined)}\n aria-current={local.selected ? 'true' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-description={local.description ? '' : undefined}\n class={cn(\n 'group/row list-row-description flex min-w-0 items-center gap-2.5 rounded-md px-2 text-sm',\n 'transition-colors ease-out outline-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n 'h-row-sm': local.dense && !local.description,\n 'h-row-md': !local.dense && !local.description,\n },\n {\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n {...(rest as ComponentProps<'div'>)}\n >\n <Show when={local.leading}>\n <span\n data-slot=\"list-row-leading\"\n class=\"flex shrink-0 items-center justify-center [&_svg]:size-4\"\n >\n {local.leading}\n </span>\n </Show>\n <div data-slot=\"list-row-content\" class=\"flex min-w-0 flex-1 items-center gap-2.5\">\n <span data-slot=\"list-row-label\" class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\">{local.children}</span>\n <Show when={local.description}>\n <span\n data-slot=\"list-row-description\"\n class={cn(\n 'text-xs break-words',\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.description}\n </span>\n </Show>\n </span>\n <Show when={local.trailing}>\n <span\n data-slot=\"list-row-trailing\"\n class={cn(\n 'ms-auto flex shrink-0 items-center gap-1',\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.trailing}\n </span>\n </Show>\n </div>\n </Polymorphic>\n )\n}\n"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"list-row-control.js","names":["PolymorphicProps","Polymorphic","ComponentProps","JSX","ValidComponent","Show","splitProps","cn","ListRowControlProps","T","class","selected","dense","leading","Element","trailing","description","stackTrailing","type","ListRowControlBaseProps","as","ListRowControl","props","local","rest","hasClickHandler","Boolean","onClick","rowAs","_$createComponent","_$mergeProps","_$memo","tabIndex","undefined","aria-current","data-selected","data-description","data-stack-trailing","children","when","_el$","_tmpl$","_$insert","_el$2","_tmpl$4","_el$3","firstChild","_el$4","_el$5","_tmpl$2","_$effect","_$className","_el$6","_tmpl$3","_$createComponent","_$mergeProps","_$memo","_$className"],"sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"sourcesContent":["import type { PolymorphicProps } from '@kobalte/core/polymorphic'\nimport { Polymorphic } from '@kobalte/core/polymorphic'\nimport type { ComponentProps, JSX, ValidComponent } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\nexport type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicProps<\n T,\n {\n class?: string\n /** Marks the row as current. Sets `aria-current` for a link row. */\n selected?: boolean\n /** Draw the row at the compact height. */\n dense?: boolean\n /** Leading slot: an avatar, an icon, a checkbox. */\n leading?: JSX.Element\n /** Trailing slot: a count, a menu trigger, a timestamp. */\n trailing?: JSX.Element\n /** A second line that wraps and grows the row to fit its content. */\n description?: string\n /**\n * Whether a described row may drop its trailing slot onto its own line when\n * the row gets narrow (the default). Pass `false` for a short, truncating\n * label whose single action must stay beside it.\n */\n stackTrailing?: boolean\n /** Native button type; defaults to `button` for button rows. */\n type?: ComponentProps<'button'>['type']\n }\n>\n\ntype ListRowControlBaseProps<T extends ValidComponent = 'div'> = ListRowControlProps<T> & {\n as?: T\n}\n\n/** A tree-shakeable ListRow renderer without optional tooltip behavior. */\nexport function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowControlProps<T>) {\n const [local, rest] = splitProps(props as ListRowControlBaseProps, [\n 'as',\n 'class',\n 'selected',\n 'dense',\n 'leading',\n 'trailing',\n 'description',\n 'stackTrailing',\n 'type',\n 'tabIndex',\n 'children',\n ])\n const hasClickHandler = () => Boolean(rest.onClick || rest['on:click'])\n const rowAs = () => (local.as ?? (hasClickHandler() ? 'button' : 'div')) as T\n\n return (\n <Polymorphic\n as={rowAs()}\n type={rowAs() === 'button' ? (local.type ?? 'button') : local.type}\n tabIndex={local.tabIndex ?? (rowAs() === 'button' || rowAs() === 'a' ? 0 : undefined)}\n aria-current={local.selected ? 'true' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-description={local.description ? '' : undefined}\n data-stack-trailing={local.stackTrailing === false ? 'never' : undefined}\n class={cn(\n 'group/row list-row-description flex min-w-0 items-center gap-2.5 rounded-md px-2 text-sm',\n 'transition-colors ease-out outline-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n 'h-row-sm': local.dense && !local.description,\n 'h-row-md': !local.dense && !local.description,\n },\n {\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n {...(rest as ComponentProps<'div'>)}\n >\n <Show when={local.leading}>\n <span\n data-slot=\"list-row-leading\"\n class=\"flex shrink-0 items-center justify-center [&_svg]:size-4\"\n >\n {local.leading}\n </span>\n </Show>\n <div data-slot=\"list-row-content\" class=\"flex min-w-0 flex-1 items-center gap-2.5\">\n <span data-slot=\"list-row-label\" class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\">{local.children}</span>\n <Show when={local.description}>\n <span\n data-slot=\"list-row-description\"\n class={cn(\n 'text-xs break-words',\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.description}\n </span>\n </Show>\n </span>\n <Show when={local.trailing}>\n <span\n data-slot=\"list-row-trailing\"\n class={cn(\n 'ms-auto flex shrink-0 items-center gap-1',\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.trailing}\n </span>\n </Show>\n </div>\n </Polymorphic>\n )\n}\n"],"mappings":";;;;;;;;;;AAoCA,SAAgBqB,eAAiDC,OAA+B;CAC9F,MAAM,CAACC,OAAOC,QAAQlB,WAAWgB,OAAkC;EACjE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAU,CACX;CACD,MAAMG,wBAAwBC,QAAQF,KAAKG,WAAWH,KAAK,WAAW;CACtE,MAAMI,cAAeL,MAAMH,OAAOK,gBAAgB,IAAI,WAAW;CAEjE,OAAAI,gBACG5B,aAAW6B,WAAA;EAAA,IACVV,KAAE;GAAA,OAAEQ,MAAM;EAAC;EAAA,IACXV,OAAI;GAAA,OAAEa,WAAAH,MAAM,MAAM,QAAQ,CAAA,CAAA,IAAIL,MAAML,QAAQ,WAAYK,MAAML;EAAI;EAAA,IAClEc,WAAQ;GAAA,OAAET,MAAMS,aAAaJ,MAAM,MAAM,YAAYA,MAAM,MAAM,MAAM,IAAIK,KAAAA;EAAU;EAAA,KAAA,kBAAA;GAAA,OACvEV,MAAMZ,WAAW,SAASsB,KAAAA;EAAS;EAAA,KAAA,mBAAA;GAAA,OAClCV,MAAMZ,WAAW,KAAKsB,KAAAA;EAAS;EAAA,KAAA,sBAAA;GAAA,OAC5BV,MAAMP,cAAc,KAAKiB,KAAAA;EAAS;EAAA,KAAA,yBAAA;GAAA,OAC/BV,MAAMN,kBAAkB,QAAQ,UAAUgB,KAAAA;EAAS;EAAA,KAAA,WAAA;GAAA,OACjE1B,GACL,4FACA,2CACA,oFACA;IACE,YAAYgB,MAAMX,SAAS,CAACW,MAAMP;IAClC,YAAY,CAACO,MAAMX,SAAS,CAACW,MAAMP;GACrC,GACA;IACE,qCAAqCO,MAAMZ;IAC3C,0BAA0B,CAACY,MAAMZ;GACnC,GACAY,MAAMb,KACR;EAAC;CAAA,GACIc,MAA6B,EAAA,IAAAc,WAAA;EAAA,OAAA,CAAAT,gBAEjCxB,MAAI;GAAA,IAACkC,OAAI;IAAA,OAAEhB,MAAMV;GAAO;GAAA,IAAAyB,WAAA;IAAA,IAAAE,OAAAC,OAAA;IAAAC,OAAAF,YAKpBjB,MAAMV,OAAO;IAAA,OAAA2B;GAAA;EAAA,CAAA,UAAA;GAAA,IAAAG,QAAAC,QAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC;GAAAJ,OAAAK,aAKUxB,MAAMe,QAAQ;GAAAI,OAAAG,OAAAhB,gBACrCxB,MAAI;IAAA,IAACkC,OAAI;KAAA,OAAEhB,MAAMP;IAAW;IAAA,IAAAsB,WAAA;KAAA,IAAAU,QAAAC,QAAA;KAAAP,OAAAM,aAQxBzB,MAAMP,WAAW;KAAAkC,aAAAC,UAAAH,OALXzC,GACL,uBACAgB,MAAMZ,WAAW,oBAAoB,uBACvC,CAAC,CAAA;KAAA,OAAAqC;IAAA;GAAA,CAAA,GAAA,IAAA;GAAAN,OAAAC,OAAAd,gBAMNxB,MAAI;IAAA,IAACkC,OAAI;KAAA,OAAEhB,MAAMR;IAAQ;IAAA,IAAAuB,WAAA;KAAA,IAAAc,QAAAC,QAAA;KAAAX,OAAAU,aAQrB7B,MAAMR,QAAQ;KAAAmC,aAAAC,UAAAC,OALR7C,GACL,4CACAgB,MAAMZ,WAAW,oBAAoB,uBACvC,CAAC,CAAA;KAAA,OAAAyC;IAAA;GAAA,CAAA,GAAA,IAAA;GAAA,OAAAT;EAAA,EAAA,CAAA,CAAA;CAAA,EAAA,CAAA,CAAA;AAQb"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Keyboard-accessible tree rows with virtualization-aware focus handoff. */
|
|
2
|
-
export { Tree, TreeRow, type TreeProps, type TreeRowProps } from './tree';
|
|
2
|
+
export { Tree, TreeRow, TreeRowActions, type TreeProps, type TreeRowProps } from './tree';
|
|
3
3
|
export type { TreeItemDescriptor } from './tree-navigation';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/tree/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/tree/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;AACzF,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Tree, TreeRow } from "./tree.js";
|
|
2
|
-
export { Tree, TreeRow };
|
|
1
|
+
import { Tree, TreeRow, TreeRowActions } from "./tree.js";
|
|
2
|
+
export { Tree, TreeRow, TreeRowActions };
|
|
@@ -60,5 +60,17 @@ export type TreeRowProps = Omit<ComponentProps<'div'>, 'children' | 'role' | 'ta
|
|
|
60
60
|
* runtime callbacks with a shared treeitem and host-owned slots/actions.
|
|
61
61
|
*/
|
|
62
62
|
export declare function TreeRow(props: TreeRowProps): JSX.Element;
|
|
63
|
+
/**
|
|
64
|
+
* TreeRowActions.
|
|
65
|
+
*
|
|
66
|
+
* Row-level commands (rename, copy, delete) that stay out of the way until the
|
|
67
|
+
* row is hovered or holds focus, so a long tree reads as names rather than a
|
|
68
|
+
* wall of buttons. Put it in `TreeRow`'s `trailing` slot beside any status that
|
|
69
|
+
* must stay visible. `pinned` keeps the actions shown, e.g. while a destructive
|
|
70
|
+
* action waits for its confirming second press.
|
|
71
|
+
*/
|
|
72
|
+
export declare function TreeRowActions(props: ComponentProps<'span'> & {
|
|
73
|
+
pinned?: boolean;
|
|
74
|
+
}): JSX.Element;
|
|
63
75
|
export type { TreeItemDescriptor } from './tree-navigation';
|
|
64
76
|
//# sourceMappingURL=tree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/tree/tree.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAYnD,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,mBAAmB,CAAA;AAsB1B,KAAK,kBAAkB,GACnB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAA;AAExD,MAAM,MAAM,SAAS,GAAG,IAAI,CAC1B,cAAc,CAAC,KAAK,CAAC,EACrB,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,iBAAiB,CAClF,GACC,kBAAkB,GAAG;IACnB,0EAA0E;IAC1E,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC3C,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,yEAAyE;IACzE,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAClD,8EAA8E;IAC9E,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/C,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IACjD,4EAA4E;IAC5E,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,sFAAsF;IACtF,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACzD,4DAA4D;IAC5D,aAAa,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAA;IACrC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/tree/tree.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAYnD,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,mBAAmB,CAAA;AAsB1B,KAAK,kBAAkB,GACnB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAA;AAExD,MAAM,MAAM,SAAS,GAAG,IAAI,CAC1B,cAAc,CAAC,KAAK,CAAC,EACrB,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,iBAAiB,CAClF,GACC,kBAAkB,GAAG;IACnB,0EAA0E;IAC1E,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC3C,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,yEAAyE;IACzE,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAClD,8EAA8E;IAC9E,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/C,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IACjD,4EAA4E;IAC5E,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,sFAAsF;IACtF,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACzD,4DAA4D;IAC5D,aAAa,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAA;IACrC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,eA2KpC;AAED,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,cAAc,CAAC,KAAK,CAAC,EACnB,UAAU,GACV,MAAM,GACN,UAAU,GACV,SAAS,GACT,SAAS,GACT,eAAe,GACf,OAAO,GACP,YAAY,GACZ,eAAe,GACf,eAAe,GACf,eAAe,GACf,cAAc,CACjB,GAAG;IACF,IAAI,EAAE,kBAAkB,CAAA;IACxB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG;QAAE,aAAa,EAAE,cAAc,CAAA;KAAE,KAAK,IAAI,CAAA;CAC5F,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,eAsG1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,eAclF;AAsBD,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -8,6 +8,7 @@ var _tmpl$ = /*#__PURE__*/ template(`<div>`);
|
|
|
8
8
|
var _tmpl$2 = /*#__PURE__*/ template(`<div><span class="flex size-3.5 shrink-0 items-center justify-center text-muted-foreground"></span><span class="min-w-0 flex-1 truncate">`);
|
|
9
9
|
var _tmpl$3 = /*#__PURE__*/ template(`<span class="flex size-4 shrink-0 items-center justify-center [&_svg]:size-4">`);
|
|
10
10
|
var _tmpl$4 = /*#__PURE__*/ template(`<span class="ms-auto flex shrink-0 items-center gap-1 text-muted-foreground">`);
|
|
11
|
+
var _tmpl$5 = /*#__PURE__*/ template(`<span data-slot=tree-row-actions>`);
|
|
11
12
|
var TreeContext = createContext();
|
|
12
13
|
function useTreeContext() {
|
|
13
14
|
const tree = useContext(TreeContext);
|
|
@@ -155,7 +156,7 @@ function Tree(props) {
|
|
|
155
156
|
},
|
|
156
157
|
"data-slot": "tree",
|
|
157
158
|
get ["class"]() {
|
|
158
|
-
return cn("flex min-w-0 flex-col", local.class);
|
|
159
|
+
return cn("flex min-w-0 flex-col [overflow-anchor:none]", local.class);
|
|
159
160
|
},
|
|
160
161
|
"onKeyDown": handleKeyDown
|
|
161
162
|
}), false, true);
|
|
@@ -294,6 +295,30 @@ function TreeRow(props) {
|
|
|
294
295
|
return _el$2;
|
|
295
296
|
})();
|
|
296
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* TreeRowActions.
|
|
300
|
+
*
|
|
301
|
+
* Row-level commands (rename, copy, delete) that stay out of the way until the
|
|
302
|
+
* row is hovered or holds focus, so a long tree reads as names rather than a
|
|
303
|
+
* wall of buttons. Put it in `TreeRow`'s `trailing` slot beside any status that
|
|
304
|
+
* must stay visible. `pinned` keeps the actions shown, e.g. while a destructive
|
|
305
|
+
* action waits for its confirming second press.
|
|
306
|
+
*/
|
|
307
|
+
function TreeRowActions(props) {
|
|
308
|
+
const [local, rest] = splitProps(props, ["class", "pinned"]);
|
|
309
|
+
return (() => {
|
|
310
|
+
var _el$7 = _tmpl$5();
|
|
311
|
+
spread(_el$7, mergeProps({
|
|
312
|
+
get ["data-pinned"]() {
|
|
313
|
+
return local.pinned ? "" : void 0;
|
|
314
|
+
},
|
|
315
|
+
get ["class"]() {
|
|
316
|
+
return cn("flex shrink-0 items-center gap-1 opacity-0 transition-opacity ease-out", "group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 data-pinned:opacity-100", local.class);
|
|
317
|
+
}
|
|
318
|
+
}, rest), false, false);
|
|
319
|
+
return _el$7;
|
|
320
|
+
})();
|
|
321
|
+
}
|
|
297
322
|
function isActionTarget(target, currentTarget) {
|
|
298
323
|
if (!(target instanceof Element) || target === currentTarget) return false;
|
|
299
324
|
return Boolean(target.closest("a, button, input, textarea, select, [contenteditable=\"true\"], [role=\"button\"], [data-tree-keyboard-stop]"));
|
|
@@ -306,6 +331,6 @@ function composeRefs(internal, external) {
|
|
|
306
331
|
};
|
|
307
332
|
}
|
|
308
333
|
//#endregion
|
|
309
|
-
export { Tree, TreeRow };
|
|
334
|
+
export { Tree, TreeRow, TreeRowActions };
|
|
310
335
|
|
|
311
336
|
//# sourceMappingURL=tree.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.js","names":["ComponentProps","JSX","ChevronRight","createContext","createEffect","createMemo","createUniqueId","onCleanup","splitProps","useContext","cn","indexTreeItems","treeNavigationAction","TreeItemDescriptor","TreeNavigationIndex","TreeContextValue","idPrefix","activeId","index","register","id","element","HTMLDivElement","unregister","focusItem","noteFocus","activate","event","Event","onActiveIdChange","TreeContext","useTreeContext","tree","Error","TreeAccessibleName","TreeProps","Omit","visibleItems","onExpand","expanded","onActivate","onSelectItem","onRequestReveal","onRowSizeChange","blockSize","selectionMode","children","Element","Tree","props","local","rest","effectiveActiveId","candidate","visible","byId","has","ids","rows","Map","rowIdsByElement","WeakMap","pendingFocusId","requestedRevealId","focusedId","disposed","rowSizeObserver","ResizeObserver","undefined","entries","entry","get","target","borderBoxSize","HTMLElement","offsetHeight","Number","isFinite","disconnect","requestReveal","focusWhenMounted","queueMicrotask","row","document","focus","activeElement","context","set","observe","focusWasInside","Boolean","contains","delete","unobserve","fallbackId","handleKeyDown","EventHandler","KeyboardEvent","defaultPrevented","isActionTarget","currentTarget","action","key","preventDefault","type","_$createComponent","Provider","value","_el$","_tmpl$","_$spread","_$mergeProps","aria-multiselectable","class","_$insert","TreeRowProps","item","selected","leading","trailing","onDoubleClick","MouseEvent","TreeRow","registeredId","setRef","nextId","handleFocus","handleClick","handleDoubleClick","position","positionById","_el$2","_tmpl$2","_el$3","firstChild","_el$4","nextSibling","_ref$","composeRefs","ref","_$use","encodeURIComponent","aria-level","level","aria-expanded","_$memo","expandable","aria-selected","aria-posinset","aria-setsize","setSize","tabIndex","data-tree-id","data-active","data-selected","data-expanded","String","style","Math","max","_c$","_c$2","_el$5","_tmpl$3","_c$3","_el$6","_tmpl$4","EventTarget","closest","internal","external","_$createComponent","_$mergeProps","_$use","_$memo"],"sources":["../../../../src/components/composites/tree/tree.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { ChevronRight } from 'lucide-solid'\nimport {\n createContext,\n createEffect,\n createMemo,\n createUniqueId,\n onCleanup,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n indexTreeItems,\n treeNavigationAction,\n type TreeItemDescriptor,\n type TreeNavigationIndex,\n} from './tree-navigation'\n\ntype TreeContextValue = {\n idPrefix: string\n activeId: () => string | null\n index: () => TreeNavigationIndex\n register: (id: string, element: HTMLDivElement) => void\n unregister: (id: string, element: HTMLDivElement | undefined) => void\n focusItem: (id: string) => void\n noteFocus: (id: string) => void\n activate: (id: string, event: Event) => void\n onActiveIdChange: (id: string) => void\n}\n\nconst TreeContext = createContext<TreeContextValue>()\n\nfunction useTreeContext() {\n const tree = useContext(TreeContext)\n if (!tree) throw new Error('[adea-ui]: TreeRow must be used inside Tree.')\n return tree\n}\n\ntype TreeAccessibleName =\n | { 'aria-label': string; 'aria-labelledby'?: string }\n | { 'aria-label'?: string; 'aria-labelledby': string }\n\nexport type TreeProps = Omit<\n ComponentProps<'div'>,\n 'children' | 'role' | 'tabIndex' | 'onKeyDown' | 'aria-label' | 'aria-labelledby'\n> &\n TreeAccessibleName & {\n /** Complete, ordered projection of currently visible (expanded) items. */\n visibleItems: readonly TreeItemDescriptor[]\n /** The host-owned identity of the row that currently owns roving focus. */\n activeId: string | null\n /** Called when keyboard or pointer navigation changes the active row. */\n onActiveIdChange: (id: string) => void\n /** Called for Left/Right expand and collapse requests. */\n onExpand?: (id: string, expanded: boolean) => void\n /** Called for Enter or pointer activation. Domain action stays host-owned. */\n onActivate?: (id: string, event: Event) => void\n /** Called for Space selection. Selection state stays host-owned. */\n onSelectItem?: (id: string, event: Event) => void\n /** Ask the host window to mount/reveal an item before focus moves to it. */\n onRequestReveal?: (id: string) => void\n /** Report a mounted row's border-box block size in CSS pixels for host range math. */\n onRowSizeChange?: (id: string, blockSize: number) => void\n /** Declares a multi-select tree to assistive technology. */\n selectionMode?: 'single' | 'multiple'\n children?: JSX.Element\n }\n\n/**\n * Tree.\n *\n * Supplies semantic and keyboard behavior for a tree whose host owns the\n * visible projection, filesystem state, row window and domain actions. The\n * mounted children can be a small virtualized window; `visibleItems` remains\n * the complete ordered projection so keyboard movement and sibling positions\n * do not depend on which rows currently exist in the DOM.\n *\n * Kobalte 0.13.14 has no Tree primitive, so this component implements the\n * WAI-ARIA tree row navigation contract and leaves product state to callbacks.\n */\nexport function Tree(props: TreeProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'visibleItems',\n 'activeId',\n 'onActiveIdChange',\n 'onExpand',\n 'onActivate',\n 'onSelectItem',\n 'onRequestReveal',\n 'onRowSizeChange',\n 'selectionMode',\n 'children',\n ])\n\n const index = createMemo(() => indexTreeItems(local.visibleItems))\n const effectiveActiveId = createMemo(() => {\n const candidate = local.activeId\n const visible = index()\n return candidate !== null && visible.byId.has(candidate) ? candidate : (visible.ids[0] ?? null)\n })\n const idPrefix = `tree-${createUniqueId()}`\n const rows = new Map<string, HTMLDivElement>()\n const rowIdsByElement = new WeakMap<HTMLDivElement, string>()\n let pendingFocusId: string | null = null\n let requestedRevealId: string | null = null\n let focusedId: string | null = null\n let disposed = false\n const rowSizeObserver =\n typeof ResizeObserver === 'undefined'\n ? undefined\n : new ResizeObserver((entries) => {\n if (disposed) return\n for (const entry of entries) {\n const id = rowIdsByElement.get(entry.target as HTMLDivElement)\n const blockSize =\n entry.borderBoxSize[0]?.blockSize ?? (entry.target as HTMLElement).offsetHeight\n if (id !== undefined && Number.isFinite(blockSize) && blockSize > 0)\n local.onRowSizeChange?.(id, blockSize)\n }\n })\n\n onCleanup(() => {\n disposed = true\n rowSizeObserver?.disconnect()\n })\n\n const requestReveal = (id: string) => {\n if (requestedRevealId === id) return\n requestedRevealId = id\n local.onRequestReveal?.(id)\n }\n\n const focusWhenMounted = (id: string) => {\n queueMicrotask(() => {\n if (pendingFocusId !== id || effectiveActiveId() !== id) return\n const row = rows.get(id)\n if (!row || typeof document === 'undefined') return\n row.focus()\n if (document.activeElement === row) pendingFocusId = null\n })\n }\n\n const focusItem = (id: string) => {\n pendingFocusId = id\n local.onActiveIdChange(id)\n if (rows.has(id)) requestedRevealId = null\n else requestReveal(id)\n focusWhenMounted(id)\n }\n\n const context: TreeContextValue = {\n idPrefix,\n activeId: effectiveActiveId,\n index,\n register: (id, element) => {\n rows.set(id, element)\n rowIdsByElement.set(element, id)\n rowSizeObserver?.observe(element)\n if (requestedRevealId === id) requestedRevealId = null\n if (pendingFocusId === id) focusWhenMounted(id)\n },\n unregister: (id, element) => {\n if (rows.get(id) !== element) return\n const focusWasInside =\n !disposed &&\n Boolean(\n element && typeof document !== 'undefined' && element.contains(document.activeElement)\n )\n rows.delete(id)\n if (element) {\n rowIdsByElement.delete(element)\n rowSizeObserver?.unobserve(element)\n }\n if (requestedRevealId === id) requestedRevealId = null\n if (focusWasInside) {\n queueMicrotask(() => {\n const fallbackId = effectiveActiveId()\n if (!disposed && fallbackId !== null && pendingFocusId !== fallbackId)\n focusItem(fallbackId)\n })\n }\n },\n focusItem,\n noteFocus: (id) => {\n focusedId = id\n },\n activate: (id, event) => local.onActivate?.(id, event),\n onActiveIdChange: local.onActiveIdChange,\n }\n\n // A filtered or removed active ID falls back to the first visible item. This\n // keeps one treeitem in the sequential tab order while notifying the host.\n createEffect(() => {\n const activeId = effectiveActiveId()\n if (activeId === null) return\n // If a host filter removes the row that had DOM focus, move focus to the\n // same projection fallback that now owns the roving tab stop.\n if (focusedId !== null && !index().byId.has(focusedId) && pendingFocusId !== activeId) {\n focusItem(activeId)\n } else if (local.activeId !== activeId) {\n local.onActiveIdChange(activeId)\n }\n // Preserve the active row in a caller-owned virtual window, including when\n // the pane mounts with its saved active row outside the initial render range.\n if (!rows.has(activeId)) requestReveal(activeId)\n if (pendingFocusId === activeId) focusWhenMounted(activeId)\n })\n\n const handleKeyDown: JSX.EventHandler<HTMLDivElement, KeyboardEvent> = (event) => {\n if (event.defaultPrevented || isActionTarget(event.target, event.currentTarget)) return\n\n const action = treeNavigationAction(index(), effectiveActiveId(), event.key)\n if (!action) return\n event.preventDefault()\n\n switch (action.type) {\n case 'focus':\n focusItem(action.id)\n break\n case 'expand':\n local.onExpand?.(action.id, action.expanded)\n break\n case 'activate':\n local.onActivate?.(action.id, event)\n break\n case 'select':\n local.onSelectItem?.(action.id, event)\n break\n }\n }\n\n return (\n <TreeContext.Provider value={context}>\n <div\n {...rest}\n role=\"tree\"\n aria-multiselectable={local.selectionMode === 'multiple' ? 'true' : undefined}\n data-slot=\"tree\"\n class={cn('flex min-w-0 flex-col', local.class)}\n onKeyDown={handleKeyDown}\n >\n {local.children}\n </div>\n </TreeContext.Provider>\n )\n}\n\nexport type TreeRowProps = Omit<\n ComponentProps<'div'>,\n | 'children'\n | 'role'\n | 'tabIndex'\n | 'onClick'\n | 'onFocus'\n | 'onDoubleClick'\n | 'style'\n | 'aria-level'\n | 'aria-expanded'\n | 'aria-selected'\n | 'aria-posinset'\n | 'aria-setsize'\n> & {\n item: TreeItemDescriptor\n /** Host-owned selection state; omitted for non-selectable trees. */\n selected?: boolean\n leading?: JSX.Element\n trailing?: JSX.Element\n children: JSX.Element\n onDoubleClick?: (id: string, event: MouseEvent & { currentTarget: HTMLDivElement }) => void\n}\n\n/**\n * TreeRow.\n *\n * Keeps the donor's disclosure marker, leading file/folder affordance, primary\n * label and trailing-action hierarchy while replacing the donor's button and\n * runtime callbacks with a shared treeitem and host-owned slots/actions.\n */\nexport function TreeRow(props: TreeRowProps) {\n const tree = useTreeContext()\n const [local, rest] = splitProps(props, [\n 'class',\n 'item',\n 'selected',\n 'leading',\n 'trailing',\n 'children',\n 'onDoubleClick',\n 'ref',\n ])\n\n let row: HTMLDivElement | undefined\n let registeredId: string | undefined\n const id = () => local.item.id\n\n onCleanup(() => tree.unregister(registeredId ?? id(), row))\n\n const setRef = (element: HTMLDivElement) => {\n row = element\n registeredId = id()\n tree.register(registeredId, element)\n }\n\n createEffect(() => {\n const nextId = id()\n if (!row || registeredId === nextId) return\n if (registeredId !== undefined) tree.unregister(registeredId, row)\n registeredId = nextId\n tree.register(nextId, row)\n })\n\n const handleFocus = () => {\n tree.noteFocus(id())\n if (tree.activeId() !== id()) tree.onActiveIdChange(id())\n }\n\n const handleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n tree.focusItem(id())\n tree.activate(id(), event)\n }\n\n const handleDoubleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n local.onDoubleClick?.(id(), event)\n }\n\n const position = () => tree.index().positionById.get(id())\n\n return (\n <div\n {...rest}\n ref={composeRefs(setRef, () => local.ref)}\n id={rest.id ?? `${tree.idPrefix}-item-${encodeURIComponent(id())}`}\n role=\"treeitem\"\n aria-level={local.item.level}\n aria-expanded={local.item.expandable ? (local.item.expanded ? 'true' : 'false') : undefined}\n aria-selected={local.selected === undefined ? undefined : local.selected ? 'true' : 'false'}\n aria-posinset={position()?.position}\n aria-setsize={position()?.setSize}\n tabIndex={tree.activeId() === id() ? 0 : -1}\n data-tree-id={id()}\n data-active={tree.activeId() === id() ? '' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-expanded={local.item.expandable ? String(local.item.expanded) : undefined}\n class={cn(\n 'group/tree-row flex min-h-row-sm w-full min-w-0 items-center gap-1.5 rounded-md pe-1.5 text-left text-sm outline-none transition-colors',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n style={{ 'padding-inline-start': `${6 + Math.max(0, local.item.level - 1) * 12}px` }}\n onFocus={handleFocus}\n onClick={handleClick}\n onDblClick={handleDoubleClick}\n >\n <span class=\"flex size-3.5 shrink-0 items-center justify-center text-muted-foreground\">\n {local.item.expandable ? (\n <ChevronRight\n aria-hidden=\"true\"\n class={cn('size-3.5 transition-transform', local.item.expanded && 'rotate-90')}\n />\n ) : null}\n </span>\n {local.leading ? (\n <span class=\"flex size-4 shrink-0 items-center justify-center [&_svg]:size-4\">\n {local.leading}\n </span>\n ) : null}\n <span class=\"min-w-0 flex-1 truncate\">{local.children}</span>\n {local.trailing ? (\n <span class=\"ms-auto flex shrink-0 items-center gap-1 text-muted-foreground\">\n {local.trailing}\n </span>\n ) : null}\n </div>\n )\n}\n\nfunction isActionTarget(target: EventTarget | null, currentTarget: HTMLElement): boolean {\n if (!(target instanceof Element) || target === currentTarget) return false\n return Boolean(\n target.closest(\n 'a, button, input, textarea, select, [contenteditable=\"true\"], [role=\"button\"], [data-tree-keyboard-stop]'\n )\n )\n}\n\nfunction composeRefs(\n internal: (element: HTMLDivElement) => void,\n external: () => ComponentProps<'div'>['ref']\n): (element: HTMLDivElement) => void {\n return (element) => {\n internal(element)\n const ref = external()\n if (typeof ref === 'function') ref(element)\n }\n}\n\nexport type { TreeItemDescriptor } from './tree-navigation'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tree.js","names":["ComponentProps","JSX","ChevronRight","createContext","createEffect","createMemo","createUniqueId","onCleanup","splitProps","useContext","cn","indexTreeItems","treeNavigationAction","TreeItemDescriptor","TreeNavigationIndex","TreeContextValue","idPrefix","activeId","index","register","id","element","HTMLDivElement","unregister","focusItem","noteFocus","activate","event","Event","onActiveIdChange","TreeContext","useTreeContext","tree","Error","TreeAccessibleName","TreeProps","Omit","visibleItems","onExpand","expanded","onActivate","onSelectItem","onRequestReveal","onRowSizeChange","blockSize","selectionMode","children","Element","Tree","props","local","rest","effectiveActiveId","candidate","visible","byId","has","ids","rows","Map","rowIdsByElement","WeakMap","pendingFocusId","requestedRevealId","focusedId","disposed","rowSizeObserver","ResizeObserver","undefined","entries","entry","get","target","borderBoxSize","HTMLElement","offsetHeight","Number","isFinite","disconnect","requestReveal","focusWhenMounted","queueMicrotask","row","document","focus","activeElement","context","set","observe","focusWasInside","Boolean","contains","delete","unobserve","fallbackId","handleKeyDown","EventHandler","KeyboardEvent","defaultPrevented","isActionTarget","currentTarget","action","key","preventDefault","type","_$createComponent","Provider","value","_el$","_tmpl$","_$spread","_$mergeProps","aria-multiselectable","class","_$insert","TreeRowProps","item","selected","leading","trailing","onDoubleClick","MouseEvent","TreeRow","registeredId","setRef","nextId","handleFocus","handleClick","handleDoubleClick","position","positionById","_el$2","_tmpl$2","_el$3","firstChild","_el$4","nextSibling","_ref$","composeRefs","ref","_$use","encodeURIComponent","aria-level","level","aria-expanded","_$memo","expandable","aria-selected","aria-posinset","aria-setsize","setSize","tabIndex","data-tree-id","data-active","data-selected","data-expanded","String","style","Math","max","_c$","_c$2","_el$5","_tmpl$3","_c$3","_el$6","_tmpl$4","TreeRowActions","pinned","_el$7","_tmpl$5","data-pinned","EventTarget","closest","internal","external","_$createComponent","_$mergeProps","_$use","_$memo"],"sources":["../../../../src/components/composites/tree/tree.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { ChevronRight } from 'lucide-solid'\nimport {\n createContext,\n createEffect,\n createMemo,\n createUniqueId,\n onCleanup,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n indexTreeItems,\n treeNavigationAction,\n type TreeItemDescriptor,\n type TreeNavigationIndex,\n} from './tree-navigation'\n\ntype TreeContextValue = {\n idPrefix: string\n activeId: () => string | null\n index: () => TreeNavigationIndex\n register: (id: string, element: HTMLDivElement) => void\n unregister: (id: string, element: HTMLDivElement | undefined) => void\n focusItem: (id: string) => void\n noteFocus: (id: string) => void\n activate: (id: string, event: Event) => void\n onActiveIdChange: (id: string) => void\n}\n\nconst TreeContext = createContext<TreeContextValue>()\n\nfunction useTreeContext() {\n const tree = useContext(TreeContext)\n if (!tree) throw new Error('[adea-ui]: TreeRow must be used inside Tree.')\n return tree\n}\n\ntype TreeAccessibleName =\n | { 'aria-label': string; 'aria-labelledby'?: string }\n | { 'aria-label'?: string; 'aria-labelledby': string }\n\nexport type TreeProps = Omit<\n ComponentProps<'div'>,\n 'children' | 'role' | 'tabIndex' | 'onKeyDown' | 'aria-label' | 'aria-labelledby'\n> &\n TreeAccessibleName & {\n /** Complete, ordered projection of currently visible (expanded) items. */\n visibleItems: readonly TreeItemDescriptor[]\n /** The host-owned identity of the row that currently owns roving focus. */\n activeId: string | null\n /** Called when keyboard or pointer navigation changes the active row. */\n onActiveIdChange: (id: string) => void\n /** Called for Left/Right expand and collapse requests. */\n onExpand?: (id: string, expanded: boolean) => void\n /** Called for Enter or pointer activation. Domain action stays host-owned. */\n onActivate?: (id: string, event: Event) => void\n /** Called for Space selection. Selection state stays host-owned. */\n onSelectItem?: (id: string, event: Event) => void\n /** Ask the host window to mount/reveal an item before focus moves to it. */\n onRequestReveal?: (id: string) => void\n /** Report a mounted row's border-box block size in CSS pixels for host range math. */\n onRowSizeChange?: (id: string, blockSize: number) => void\n /** Declares a multi-select tree to assistive technology. */\n selectionMode?: 'single' | 'multiple'\n children?: JSX.Element\n }\n\n/**\n * Tree.\n *\n * Supplies semantic and keyboard behavior for a tree whose host owns the\n * visible projection, filesystem state, row window and domain actions. The\n * mounted children can be a small virtualized window; `visibleItems` remains\n * the complete ordered projection so keyboard movement and sibling positions\n * do not depend on which rows currently exist in the DOM.\n *\n * Kobalte 0.13.14 has no Tree primitive, so this component implements the\n * WAI-ARIA tree row navigation contract and leaves product state to callbacks.\n */\nexport function Tree(props: TreeProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'visibleItems',\n 'activeId',\n 'onActiveIdChange',\n 'onExpand',\n 'onActivate',\n 'onSelectItem',\n 'onRequestReveal',\n 'onRowSizeChange',\n 'selectionMode',\n 'children',\n ])\n\n const index = createMemo(() => indexTreeItems(local.visibleItems))\n const effectiveActiveId = createMemo(() => {\n const candidate = local.activeId\n const visible = index()\n return candidate !== null && visible.byId.has(candidate) ? candidate : (visible.ids[0] ?? null)\n })\n const idPrefix = `tree-${createUniqueId()}`\n const rows = new Map<string, HTMLDivElement>()\n const rowIdsByElement = new WeakMap<HTMLDivElement, string>()\n let pendingFocusId: string | null = null\n let requestedRevealId: string | null = null\n let focusedId: string | null = null\n let disposed = false\n const rowSizeObserver =\n typeof ResizeObserver === 'undefined'\n ? undefined\n : new ResizeObserver((entries) => {\n if (disposed) return\n for (const entry of entries) {\n const id = rowIdsByElement.get(entry.target as HTMLDivElement)\n const blockSize =\n entry.borderBoxSize[0]?.blockSize ?? (entry.target as HTMLElement).offsetHeight\n if (id !== undefined && Number.isFinite(blockSize) && blockSize > 0)\n local.onRowSizeChange?.(id, blockSize)\n }\n })\n\n onCleanup(() => {\n disposed = true\n rowSizeObserver?.disconnect()\n })\n\n const requestReveal = (id: string) => {\n if (requestedRevealId === id) return\n requestedRevealId = id\n local.onRequestReveal?.(id)\n }\n\n const focusWhenMounted = (id: string) => {\n queueMicrotask(() => {\n if (pendingFocusId !== id || effectiveActiveId() !== id) return\n const row = rows.get(id)\n if (!row || typeof document === 'undefined') return\n row.focus()\n if (document.activeElement === row) pendingFocusId = null\n })\n }\n\n const focusItem = (id: string) => {\n pendingFocusId = id\n local.onActiveIdChange(id)\n if (rows.has(id)) requestedRevealId = null\n else requestReveal(id)\n focusWhenMounted(id)\n }\n\n const context: TreeContextValue = {\n idPrefix,\n activeId: effectiveActiveId,\n index,\n register: (id, element) => {\n rows.set(id, element)\n rowIdsByElement.set(element, id)\n rowSizeObserver?.observe(element)\n if (requestedRevealId === id) requestedRevealId = null\n if (pendingFocusId === id) focusWhenMounted(id)\n },\n unregister: (id, element) => {\n if (rows.get(id) !== element) return\n const focusWasInside =\n !disposed &&\n Boolean(\n element && typeof document !== 'undefined' && element.contains(document.activeElement)\n )\n rows.delete(id)\n if (element) {\n rowIdsByElement.delete(element)\n rowSizeObserver?.unobserve(element)\n }\n if (requestedRevealId === id) requestedRevealId = null\n if (focusWasInside) {\n queueMicrotask(() => {\n const fallbackId = effectiveActiveId()\n if (!disposed && fallbackId !== null && pendingFocusId !== fallbackId)\n focusItem(fallbackId)\n })\n }\n },\n focusItem,\n noteFocus: (id) => {\n focusedId = id\n },\n activate: (id, event) => local.onActivate?.(id, event),\n onActiveIdChange: local.onActiveIdChange,\n }\n\n // A filtered or removed active ID falls back to the first visible item. This\n // keeps one treeitem in the sequential tab order while notifying the host.\n createEffect(() => {\n const activeId = effectiveActiveId()\n if (activeId === null) return\n // If a host filter removes the row that had DOM focus, move focus to the\n // same projection fallback that now owns the roving tab stop.\n if (focusedId !== null && !index().byId.has(focusedId) && pendingFocusId !== activeId) {\n focusItem(activeId)\n } else if (local.activeId !== activeId) {\n local.onActiveIdChange(activeId)\n }\n // Preserve the active row in a caller-owned virtual window, including when\n // the pane mounts with its saved active row outside the initial render range.\n if (!rows.has(activeId)) requestReveal(activeId)\n if (pendingFocusId === activeId) focusWhenMounted(activeId)\n })\n\n const handleKeyDown: JSX.EventHandler<HTMLDivElement, KeyboardEvent> = (event) => {\n if (event.defaultPrevented || isActionTarget(event.target, event.currentTarget)) return\n\n const action = treeNavigationAction(index(), effectiveActiveId(), event.key)\n if (!action) return\n event.preventDefault()\n\n switch (action.type) {\n case 'focus':\n focusItem(action.id)\n break\n case 'expand':\n local.onExpand?.(action.id, action.expanded)\n break\n case 'activate':\n local.onActivate?.(action.id, event)\n break\n case 'select':\n local.onSelectItem?.(action.id, event)\n break\n }\n }\n\n return (\n <TreeContext.Provider value={context}>\n <div\n {...rest}\n role=\"tree\"\n aria-multiselectable={local.selectionMode === 'multiple' ? 'true' : undefined}\n data-slot=\"tree\"\n class={cn(\n /* A virtualized host remounts rows as it scrolls; scroll anchoring\n would latch onto the focused row and fight the scrollbar. */\n 'flex min-w-0 flex-col [overflow-anchor:none]',\n local.class\n )}\n onKeyDown={handleKeyDown}\n >\n {local.children}\n </div>\n </TreeContext.Provider>\n )\n}\n\nexport type TreeRowProps = Omit<\n ComponentProps<'div'>,\n | 'children'\n | 'role'\n | 'tabIndex'\n | 'onClick'\n | 'onFocus'\n | 'onDoubleClick'\n | 'style'\n | 'aria-level'\n | 'aria-expanded'\n | 'aria-selected'\n | 'aria-posinset'\n | 'aria-setsize'\n> & {\n item: TreeItemDescriptor\n /** Host-owned selection state; omitted for non-selectable trees. */\n selected?: boolean\n leading?: JSX.Element\n trailing?: JSX.Element\n children: JSX.Element\n onDoubleClick?: (id: string, event: MouseEvent & { currentTarget: HTMLDivElement }) => void\n}\n\n/**\n * TreeRow.\n *\n * Keeps the donor's disclosure marker, leading file/folder affordance, primary\n * label and trailing-action hierarchy while replacing the donor's button and\n * runtime callbacks with a shared treeitem and host-owned slots/actions.\n */\nexport function TreeRow(props: TreeRowProps) {\n const tree = useTreeContext()\n const [local, rest] = splitProps(props, [\n 'class',\n 'item',\n 'selected',\n 'leading',\n 'trailing',\n 'children',\n 'onDoubleClick',\n 'ref',\n ])\n\n let row: HTMLDivElement | undefined\n let registeredId: string | undefined\n const id = () => local.item.id\n\n onCleanup(() => tree.unregister(registeredId ?? id(), row))\n\n const setRef = (element: HTMLDivElement) => {\n row = element\n registeredId = id()\n tree.register(registeredId, element)\n }\n\n createEffect(() => {\n const nextId = id()\n if (!row || registeredId === nextId) return\n if (registeredId !== undefined) tree.unregister(registeredId, row)\n registeredId = nextId\n tree.register(nextId, row)\n })\n\n const handleFocus = () => {\n tree.noteFocus(id())\n if (tree.activeId() !== id()) tree.onActiveIdChange(id())\n }\n\n const handleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n tree.focusItem(id())\n tree.activate(id(), event)\n }\n\n const handleDoubleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n local.onDoubleClick?.(id(), event)\n }\n\n const position = () => tree.index().positionById.get(id())\n\n return (\n <div\n {...rest}\n ref={composeRefs(setRef, () => local.ref)}\n id={rest.id ?? `${tree.idPrefix}-item-${encodeURIComponent(id())}`}\n role=\"treeitem\"\n aria-level={local.item.level}\n aria-expanded={local.item.expandable ? (local.item.expanded ? 'true' : 'false') : undefined}\n aria-selected={local.selected === undefined ? undefined : local.selected ? 'true' : 'false'}\n aria-posinset={position()?.position}\n aria-setsize={position()?.setSize}\n tabIndex={tree.activeId() === id() ? 0 : -1}\n data-tree-id={id()}\n data-active={tree.activeId() === id() ? '' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-expanded={local.item.expandable ? String(local.item.expanded) : undefined}\n class={cn(\n 'group/tree-row flex min-h-row-sm w-full min-w-0 items-center gap-1.5 rounded-md pe-1.5 text-left text-sm outline-none transition-colors',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n style={{ 'padding-inline-start': `${6 + Math.max(0, local.item.level - 1) * 12}px` }}\n onFocus={handleFocus}\n onClick={handleClick}\n onDblClick={handleDoubleClick}\n >\n <span class=\"flex size-3.5 shrink-0 items-center justify-center text-muted-foreground\">\n {local.item.expandable ? (\n <ChevronRight\n aria-hidden=\"true\"\n class={cn('size-3.5 transition-transform', local.item.expanded && 'rotate-90')}\n />\n ) : null}\n </span>\n {local.leading ? (\n <span class=\"flex size-4 shrink-0 items-center justify-center [&_svg]:size-4\">\n {local.leading}\n </span>\n ) : null}\n <span class=\"min-w-0 flex-1 truncate\">{local.children}</span>\n {local.trailing ? (\n <span class=\"ms-auto flex shrink-0 items-center gap-1 text-muted-foreground\">\n {local.trailing}\n </span>\n ) : null}\n </div>\n )\n}\n\n/**\n * TreeRowActions.\n *\n * Row-level commands (rename, copy, delete) that stay out of the way until the\n * row is hovered or holds focus, so a long tree reads as names rather than a\n * wall of buttons. Put it in `TreeRow`'s `trailing` slot beside any status that\n * must stay visible. `pinned` keeps the actions shown, e.g. while a destructive\n * action waits for its confirming second press.\n */\nexport function TreeRowActions(props: ComponentProps<'span'> & { pinned?: boolean }) {\n const [local, rest] = splitProps(props, ['class', 'pinned'])\n return (\n <span\n data-slot=\"tree-row-actions\"\n data-pinned={local.pinned ? '' : undefined}\n class={cn(\n 'flex shrink-0 items-center gap-1 opacity-0 transition-opacity ease-out',\n 'group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 data-pinned:opacity-100',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nfunction isActionTarget(target: EventTarget | null, currentTarget: HTMLElement): boolean {\n if (!(target instanceof Element) || target === currentTarget) return false\n return Boolean(\n target.closest(\n 'a, button, input, textarea, select, [contenteditable=\"true\"], [role=\"button\"], [data-tree-keyboard-stop]'\n )\n )\n}\n\nfunction composeRefs(\n internal: (element: HTMLDivElement) => void,\n external: () => ComponentProps<'div'>['ref']\n): (element: HTMLDivElement) => void {\n return (element) => {\n internal(element)\n const ref = external()\n if (typeof ref === 'function') ref(element)\n }\n}\n\nexport type { TreeItemDescriptor } from './tree-navigation'\n"],"mappings":"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"}
|
|
@@ -12,6 +12,13 @@ export type ContextualSidebarProps = {
|
|
|
12
12
|
label: string;
|
|
13
13
|
/** Visible navigation title and mobile dialog title. */
|
|
14
14
|
title: string;
|
|
15
|
+
/**
|
|
16
|
+
* Where the title row shows. `always` (default) draws it on desktop and in
|
|
17
|
+
* the mobile sheet; `mobile` keeps the desktop title for assistive
|
|
18
|
+
* technology only and drops the desktop row, for hosts whose top bar
|
|
19
|
+
* already names the context. A `header` slot keeps the row visible.
|
|
20
|
+
*/
|
|
21
|
+
titleVisibility?: 'always' | 'mobile';
|
|
15
22
|
/** Host-controlled expanded state for the desktop panel and mobile dialog. */
|
|
16
23
|
open: boolean;
|
|
17
24
|
onOpenChange(open: boolean): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextual-sidebar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAe7C,MAAM,MAAM,8BAA8B,GAAG;IAC3C,wEAAwE;IACxE,MAAM,EAAE,OAAO,CAAA;IACf,qFAAqF;IACrF,WAAW,IAAI,WAAW,GAAG,SAAS,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,qDAAqD;IACrD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9E,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACnD,iEAAiE;IACjE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,0EAA0E;IAC1E,OAAO,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,oEAAoE;IACpE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,aAAa,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"contextual-sidebar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAe7C,MAAM,MAAM,8BAA8B,GAAG;IAC3C,wEAAwE;IACxE,MAAM,EAAE,OAAO,CAAA;IACf,qFAAqF;IACrF,WAAW,IAAI,WAAW,GAAG,SAAS,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,qDAAqD;IACrD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACrC,8EAA8E;IAC9E,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9E,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACnD,iEAAiE;IACjE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,0EAA0E;IAC1E,OAAO,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,oEAAoE;IACpE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,aAAa,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,eAmJ9D"}
|
|
@@ -102,6 +102,7 @@ function ContextualSidebar(props) {
|
|
|
102
102
|
},
|
|
103
103
|
get children() {
|
|
104
104
|
return createComponent(PixelResizeHandle, {
|
|
105
|
+
"class": "z-(--z-docked)",
|
|
105
106
|
side: "left",
|
|
106
107
|
get value() {
|
|
107
108
|
return props.width;
|
|
@@ -133,19 +134,37 @@ function ContextualSidebar(props) {
|
|
|
133
134
|
},
|
|
134
135
|
get children() {
|
|
135
136
|
return [
|
|
136
|
-
createComponent(
|
|
137
|
-
get
|
|
138
|
-
return
|
|
137
|
+
createComponent(Show, {
|
|
138
|
+
get when() {
|
|
139
|
+
return mobile || props.titleVisibility !== "mobile" || props.header;
|
|
139
140
|
},
|
|
140
|
-
get
|
|
141
|
-
return
|
|
141
|
+
get fallback() {
|
|
142
|
+
return createComponent(SidebarNavTitle, {
|
|
142
143
|
get as() {
|
|
143
144
|
return props.headingAs ?? "h2";
|
|
144
145
|
},
|
|
146
|
+
"class": "sr-only",
|
|
145
147
|
get children() {
|
|
146
148
|
return props.title;
|
|
147
149
|
}
|
|
148
|
-
})
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
get children() {
|
|
153
|
+
return createComponent(SidebarNavHeader, {
|
|
154
|
+
get ["class"]() {
|
|
155
|
+
return cn(mobile && "pe-12", props.headerClass);
|
|
156
|
+
},
|
|
157
|
+
get children() {
|
|
158
|
+
return [createComponent(SidebarNavTitle, {
|
|
159
|
+
get as() {
|
|
160
|
+
return props.headingAs ?? "h2";
|
|
161
|
+
},
|
|
162
|
+
get children() {
|
|
163
|
+
return props.title;
|
|
164
|
+
}
|
|
165
|
+
}), memo(() => props.header?.(context))];
|
|
166
|
+
}
|
|
167
|
+
});
|
|
149
168
|
}
|
|
150
169
|
}),
|
|
151
170
|
createComponent(SidebarNavContent, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextual-sidebar.js","names":["Accessor","JSX","Show","createSignal","createUniqueId","onCleanup","onMount","cn","SidebarNav","SidebarNavContent","SidebarNavFooter","SidebarNavHeader","SidebarNavTitle","PixelResizeHandle","MobileModule","MobileLoad","error","ContextualSidebarRenderContext","mobile","portalMount","HTMLElement","ContextualSidebarProps","id","label","title","open","onOpenChange","width","minimum","maximum","step","wideViewportAtLoad","resizeLabel","restoreFocusRef","onSidebarElement","element","sidebarClass","sheetClass","headerClass","contentClass","footerClass","headingAs","header","context","Element","content","footer","onWidthChange","onWidthCommit","ContextualSidebar","props","isNarrowViewport","setIsNarrowViewport","mobileLoad","setMobileLoad","mobileRequested","loadMobile","then","module","mobileMount","setMobileMount","connected","mount","isConnected","undefined","media","window","matchMedia","updateViewport","wasNarrow","matches","addEventListener","removeEventListener","renderSidebar","navigationId","_$createComponent","as","aria-label","aria-hidden","inert","data-open","String","ref","node","queueMicrotask","class","children","when","side","value","controls","onChange","onCommit","_$memo","_wide","keyed","loaded","MobileSidebar","_$createComponent","_$memo"],"sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"sourcesContent":["import type { Accessor, JSX } from 'solid-js'\nimport { Show, createSignal, createUniqueId, onCleanup, onMount } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n SidebarNav,\n SidebarNavContent,\n SidebarNavFooter,\n SidebarNavHeader,\n SidebarNavTitle,\n} from '../sidebar-nav/sidebar-nav'\nimport { PixelResizeHandle } from '../pixel-resize-handle/pixel-resize-handle'\n\ntype MobileModule = typeof import('./mobile-contextual-sidebar')\ntype MobileLoad = MobileModule | { error: unknown }\n\nexport type ContextualSidebarRenderContext = {\n /** Whether the slot is being rendered inside the modal mobile sheet. */\n mobile: boolean\n /** Mount nested popovers and menus inside the mobile dialog's accessibility tree. */\n portalMount(): HTMLElement | undefined\n}\n\nexport type ContextualSidebarProps = {\n /** Stable host id prefix; generated when omitted. */\n id?: string\n /** Landmark name shared by the desktop and mobile navigation. */\n label: string\n /** Visible navigation title and mobile dialog title. */\n title: string\n /** Host-controlled expanded state for the desktop panel and mobile dialog. */\n open: boolean\n onOpenChange(open: boolean): void\n /** Current host-owned pixel width, reflected by the resize handle. */\n width: number\n minimum: number\n maximum: number\n step?: number\n /** Pass the host's initial viewport seed to distinguish stale desktop state. */\n wideViewportAtLoad?: boolean\n resizeLabel?: string\n /** Stable external opener used when the modal mobile sheet closes. */\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n /** Called with the nav node so a host can project width onto its layout root. */\n onSidebarElement?: (element: HTMLElement | undefined, mobile: boolean) => void\n /** Host-owned layout classes applied to both nav instances. */\n sidebarClass?: string\n /** Host-owned responsive constraints for the modal sheet. */\n sheetClass?: string\n headerClass?: string\n contentClass?: string\n footerClass?: string\n headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'\n /** Optional action/content slot alongside the shared heading. */\n header?(context: ContextualSidebarRenderContext): JSX.Element\n /** View-specific navigation rows, projects, rooms, files, or sessions. */\n content(context: ContextualSidebarRenderContext): JSX.Element\n /** Optional view-specific footer, such as an archive affordance. */\n footer?(context: ContextualSidebarRenderContext): JSX.Element\n onWidthChange(width: number): void\n onWidthCommit?(width: number): void\n}\n\n/**\n * ContextualSidebar.\n *\n * Shared navigation geometry and interaction policy for an application's\n * contextual sidebar. The host keeps ownership of the actual grid width,\n * persisted preference, open state, and view-specific navigation content.\n */\nexport function ContextualSidebar(props: ContextualSidebarProps) {\n const [isNarrowViewport, setIsNarrowViewport] = createSignal(false)\n const [mobileLoad, setMobileLoad] = createSignal<MobileLoad>()\n let mobileRequested = false\n // Keep the resolved component mounted across viewport changes for Sheet cleanup.\n const loadMobile = () => {\n if (mobileRequested) return\n mobileRequested = true\n // Native module caching shares successful loads without keeping a rejected promise.\n void import('./mobile-contextual-sidebar').then(\n (module) => {\n if (mobileRequested) setMobileLoad(module)\n },\n (error: unknown) => {\n if (mobileRequested) setMobileLoad({ error })\n }\n )\n }\n const [mobileMount, setMobileMount] = createSignal<\n { element: HTMLElement; connected: boolean } | undefined\n >()\n const id = props.id ?? `contextual-sidebar-${createUniqueId()}`\n const resizeLabel = () => props.resizeLabel ?? `Resize ${props.label}`\n const portalMount = () => {\n const mount = mobileMount()\n return mount?.connected && mount.element.isConnected ? mount.element : undefined\n }\n\n onMount(() => {\n const media = window.matchMedia('(max-width: 48rem)')\n const updateViewport = () => {\n const wasNarrow = isNarrowViewport()\n if (media.matches) loadMobile()\n // Close before mounting a modal. A desktop-expanded host state is not\n // mobile intent, and opening the Sheet for one frame can steal focus.\n if (media.matches && !wasNarrow) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n }\n\n // A route can mount after a wide-loaded host crosses into mobile. Clear\n // that stale seed, but preserve a sidebar intentionally opened at a\n // narrow boot viewport.\n if (media.matches) loadMobile()\n if (media.matches && props.wideViewportAtLoad && props.open) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n media.addEventListener('change', updateViewport)\n onCleanup(() => {\n mobileRequested = false\n media.removeEventListener('change', updateViewport)\n })\n })\n\n const renderSidebar = (mobile: boolean) => {\n let element: HTMLElement | undefined\n const context: ContextualSidebarRenderContext = {\n mobile,\n portalMount: () => (mobile ? portalMount() : undefined),\n }\n const navigationId = `${id}-${mobile ? 'mobile' : 'desktop'}`\n\n onCleanup(() => {\n if (mobile && mobileMount()?.element === element) setMobileMount(undefined)\n element = undefined\n props.onSidebarElement?.(undefined, mobile)\n })\n\n return (\n <SidebarNav\n as=\"aside\"\n id={navigationId}\n aria-label={props.label}\n aria-hidden={!mobile && !props.open ? 'true' : undefined}\n inert={!mobile && !props.open}\n data-contextual-sidebar={mobile ? 'mobile' : 'desktop'}\n data-open={mobile ? undefined : String(props.open)}\n ref={(node) => {\n element = node\n if (mobile) {\n setMobileMount({ element: node, connected: node.isConnected })\n queueMicrotask(() => {\n if (node.isConnected && mobileMount()?.element === node)\n setMobileMount({ element: node, connected: true })\n })\n }\n props.onSidebarElement?.(node, mobile)\n }}\n class={cn('relative h-full w-full max-w-full', props.sidebarClass)}\n >\n <Show when={!mobile && props.open}>\n <PixelResizeHandle\n side=\"left\"\n value={props.width}\n minimum={props.minimum}\n maximum={props.maximum}\n step={props.step}\n label={resizeLabel()}\n controls={navigationId}\n onChange={props.onWidthChange}\n onCommit={props.onWidthCommit}\n />\n </Show>\n <Show when={!mobile || mobileMount()?.connected}>\n <SidebarNavHeader class={cn(mobile && 'pe-12', props.headerClass)}>\n <SidebarNavTitle as={props.headingAs ?? 'h2'}>{props.title}</SidebarNavTitle>\n {props.header?.(context)}\n </SidebarNavHeader>\n <SidebarNavContent class={props.contentClass}>{props.content(context)}</SidebarNavContent>\n {props.footer ? (\n <SidebarNavFooter class={props.footerClass}>{props.footer(context)}</SidebarNavFooter>\n ) : null}\n </Show>\n </SidebarNav>\n )\n }\n\n return (\n <>\n <Show when={!isNarrowViewport()}>{(_wide) => renderSidebar(false)}</Show>\n <Show when={mobileLoad()} keyed>\n {(loaded) => {\n if ('error' in loaded) throw loaded.error\n return (\n <loaded.MobileSidebar\n open={isNarrowViewport() && props.open}\n onOpenChange={props.onOpenChange}\n label={props.label}\n sheetClass={props.sheetClass}\n restoreFocusRef={props.restoreFocusRef}\n renderSidebar={() => renderSidebar(true)}\n />\n )\n }}\n </Show>\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"contextual-sidebar.js","names":["Accessor","JSX","Show","createSignal","createUniqueId","onCleanup","onMount","cn","SidebarNav","SidebarNavContent","SidebarNavFooter","SidebarNavHeader","SidebarNavTitle","PixelResizeHandle","MobileModule","MobileLoad","error","ContextualSidebarRenderContext","mobile","portalMount","HTMLElement","ContextualSidebarProps","id","label","title","titleVisibility","open","onOpenChange","width","minimum","maximum","step","wideViewportAtLoad","resizeLabel","restoreFocusRef","onSidebarElement","element","sidebarClass","sheetClass","headerClass","contentClass","footerClass","headingAs","header","context","Element","content","footer","onWidthChange","onWidthCommit","ContextualSidebar","props","isNarrowViewport","setIsNarrowViewport","mobileLoad","setMobileLoad","mobileRequested","loadMobile","then","module","mobileMount","setMobileMount","connected","mount","isConnected","undefined","media","window","matchMedia","updateViewport","wasNarrow","matches","addEventListener","removeEventListener","renderSidebar","navigationId","_$createComponent","as","aria-label","aria-hidden","inert","data-open","String","ref","node","queueMicrotask","class","children","when","side","value","controls","onChange","onCommit","fallback","_$memo","_wide","keyed","loaded","MobileSidebar","_$createComponent","_$memo"],"sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"sourcesContent":["import type { Accessor, JSX } from 'solid-js'\nimport { Show, createSignal, createUniqueId, onCleanup, onMount } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n SidebarNav,\n SidebarNavContent,\n SidebarNavFooter,\n SidebarNavHeader,\n SidebarNavTitle,\n} from '../sidebar-nav/sidebar-nav'\nimport { PixelResizeHandle } from '../pixel-resize-handle/pixel-resize-handle'\n\ntype MobileModule = typeof import('./mobile-contextual-sidebar')\ntype MobileLoad = MobileModule | { error: unknown }\n\nexport type ContextualSidebarRenderContext = {\n /** Whether the slot is being rendered inside the modal mobile sheet. */\n mobile: boolean\n /** Mount nested popovers and menus inside the mobile dialog's accessibility tree. */\n portalMount(): HTMLElement | undefined\n}\n\nexport type ContextualSidebarProps = {\n /** Stable host id prefix; generated when omitted. */\n id?: string\n /** Landmark name shared by the desktop and mobile navigation. */\n label: string\n /** Visible navigation title and mobile dialog title. */\n title: string\n /**\n * Where the title row shows. `always` (default) draws it on desktop and in\n * the mobile sheet; `mobile` keeps the desktop title for assistive\n * technology only and drops the desktop row, for hosts whose top bar\n * already names the context. A `header` slot keeps the row visible.\n */\n titleVisibility?: 'always' | 'mobile'\n /** Host-controlled expanded state for the desktop panel and mobile dialog. */\n open: boolean\n onOpenChange(open: boolean): void\n /** Current host-owned pixel width, reflected by the resize handle. */\n width: number\n minimum: number\n maximum: number\n step?: number\n /** Pass the host's initial viewport seed to distinguish stale desktop state. */\n wideViewportAtLoad?: boolean\n resizeLabel?: string\n /** Stable external opener used when the modal mobile sheet closes. */\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n /** Called with the nav node so a host can project width onto its layout root. */\n onSidebarElement?: (element: HTMLElement | undefined, mobile: boolean) => void\n /** Host-owned layout classes applied to both nav instances. */\n sidebarClass?: string\n /** Host-owned responsive constraints for the modal sheet. */\n sheetClass?: string\n headerClass?: string\n contentClass?: string\n footerClass?: string\n headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'\n /** Optional action/content slot alongside the shared heading. */\n header?(context: ContextualSidebarRenderContext): JSX.Element\n /** View-specific navigation rows, projects, rooms, files, or sessions. */\n content(context: ContextualSidebarRenderContext): JSX.Element\n /** Optional view-specific footer, such as an archive affordance. */\n footer?(context: ContextualSidebarRenderContext): JSX.Element\n onWidthChange(width: number): void\n onWidthCommit?(width: number): void\n}\n\n/**\n * ContextualSidebar.\n *\n * Shared navigation geometry and interaction policy for an application's\n * contextual sidebar. The host keeps ownership of the actual grid width,\n * persisted preference, open state, and view-specific navigation content.\n */\nexport function ContextualSidebar(props: ContextualSidebarProps) {\n const [isNarrowViewport, setIsNarrowViewport] = createSignal(false)\n const [mobileLoad, setMobileLoad] = createSignal<MobileLoad>()\n let mobileRequested = false\n // Keep the resolved component mounted across viewport changes for Sheet cleanup.\n const loadMobile = () => {\n if (mobileRequested) return\n mobileRequested = true\n // Native module caching shares successful loads without keeping a rejected promise.\n void import('./mobile-contextual-sidebar').then(\n (module) => {\n if (mobileRequested) setMobileLoad(module)\n },\n (error: unknown) => {\n if (mobileRequested) setMobileLoad({ error })\n }\n )\n }\n const [mobileMount, setMobileMount] = createSignal<\n { element: HTMLElement; connected: boolean } | undefined\n >()\n const id = props.id ?? `contextual-sidebar-${createUniqueId()}`\n const resizeLabel = () => props.resizeLabel ?? `Resize ${props.label}`\n const portalMount = () => {\n const mount = mobileMount()\n return mount?.connected && mount.element.isConnected ? mount.element : undefined\n }\n\n onMount(() => {\n const media = window.matchMedia('(max-width: 48rem)')\n const updateViewport = () => {\n const wasNarrow = isNarrowViewport()\n if (media.matches) loadMobile()\n // Close before mounting a modal. A desktop-expanded host state is not\n // mobile intent, and opening the Sheet for one frame can steal focus.\n if (media.matches && !wasNarrow) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n }\n\n // A route can mount after a wide-loaded host crosses into mobile. Clear\n // that stale seed, but preserve a sidebar intentionally opened at a\n // narrow boot viewport.\n if (media.matches) loadMobile()\n if (media.matches && props.wideViewportAtLoad && props.open) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n media.addEventListener('change', updateViewport)\n onCleanup(() => {\n mobileRequested = false\n media.removeEventListener('change', updateViewport)\n })\n })\n\n const renderSidebar = (mobile: boolean) => {\n let element: HTMLElement | undefined\n const context: ContextualSidebarRenderContext = {\n mobile,\n portalMount: () => (mobile ? portalMount() : undefined),\n }\n const navigationId = `${id}-${mobile ? 'mobile' : 'desktop'}`\n\n onCleanup(() => {\n if (mobile && mobileMount()?.element === element) setMobileMount(undefined)\n element = undefined\n props.onSidebarElement?.(undefined, mobile)\n })\n\n return (\n <SidebarNav\n as=\"aside\"\n id={navigationId}\n aria-label={props.label}\n aria-hidden={!mobile && !props.open ? 'true' : undefined}\n inert={!mobile && !props.open}\n data-contextual-sidebar={mobile ? 'mobile' : 'desktop'}\n data-open={mobile ? undefined : String(props.open)}\n ref={(node) => {\n element = node\n if (mobile) {\n setMobileMount({ element: node, connected: node.isConnected })\n queueMicrotask(() => {\n if (node.isConnected && mobileMount()?.element === node)\n setMobileMount({ element: node, connected: true })\n })\n }\n props.onSidebarElement?.(node, mobile)\n }}\n class={cn('relative h-full w-full max-w-full', props.sidebarClass)}\n >\n <Show when={!mobile && props.open}>\n <PixelResizeHandle\n // The ruler spans the sidebar as a pointer-events-none overlay; lift\n // it above the neighbouring pane so the edge stays grabbable.\n class=\"z-(--z-docked)\"\n side=\"left\"\n value={props.width}\n minimum={props.minimum}\n maximum={props.maximum}\n step={props.step}\n label={resizeLabel()}\n controls={navigationId}\n onChange={props.onWidthChange}\n onCommit={props.onWidthCommit}\n />\n </Show>\n <Show when={!mobile || mobileMount()?.connected}>\n <Show\n when={mobile || props.titleVisibility !== 'mobile' || props.header}\n fallback={\n <SidebarNavTitle as={props.headingAs ?? 'h2'} class=\"sr-only\">\n {props.title}\n </SidebarNavTitle>\n }\n >\n <SidebarNavHeader class={cn(mobile && 'pe-12', props.headerClass)}>\n <SidebarNavTitle as={props.headingAs ?? 'h2'}>{props.title}</SidebarNavTitle>\n {props.header?.(context)}\n </SidebarNavHeader>\n </Show>\n <SidebarNavContent class={props.contentClass}>{props.content(context)}</SidebarNavContent>\n {props.footer ? (\n <SidebarNavFooter class={props.footerClass}>{props.footer(context)}</SidebarNavFooter>\n ) : null}\n </Show>\n </SidebarNav>\n )\n }\n\n return (\n <>\n <Show when={!isNarrowViewport()}>{(_wide) => renderSidebar(false)}</Show>\n <Show when={mobileLoad()} keyed>\n {(loaded) => {\n if ('error' in loaded) throw loaded.error\n return (\n <loaded.MobileSidebar\n open={isNarrowViewport() && props.open}\n onOpenChange={props.onOpenChange}\n label={props.label}\n sheetClass={props.sheetClass}\n restoreFocusRef={props.restoreFocusRef}\n renderSidebar={() => renderSidebar(true)}\n />\n )\n }}\n </Show>\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -61,6 +61,12 @@ export type SidebarNavSectionProps = ComponentProps<'div'> & {
|
|
|
61
61
|
count?: number;
|
|
62
62
|
/** A control at the trailing edge of the heading row. */
|
|
63
63
|
action?: JSX.Element;
|
|
64
|
+
/**
|
|
65
|
+
* When the trailing action shows. `hover` (default) reveals it on hover or
|
|
66
|
+
* focus; `always` keeps it visible, for a section whose primary action is
|
|
67
|
+
* creating its first item.
|
|
68
|
+
*/
|
|
69
|
+
actionVisibility?: 'hover' | 'always';
|
|
64
70
|
/** Semantic heading element for a host's section hierarchy. */
|
|
65
71
|
headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
66
72
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-nav.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/sidebar-nav/sidebar-nav.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAGjE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAanE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAC9E,CAAC,EACD;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAC1C,CAAA;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,eAgBrF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAS5D;AAED,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CACnF,CAAC,EACD;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CACnB,CAAA;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,eAU/F;AAED,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"sidebar-nav.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/sidebar-nav/sidebar-nav.tsx"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ var _tmpl$3 = /*#__PURE__*/ template(`<div data-slot=sidebar-nav-footer>`);
|
|
|
10
10
|
var _tmpl$4 = /*#__PURE__*/ template(`<span class="min-w-0 flex-1 truncate text-start">`);
|
|
11
11
|
var _tmpl$5 = /*#__PURE__*/ template(`<span class="shrink-0 tabular-nums text-muted-foreground">`);
|
|
12
12
|
var _tmpl$6 = /*#__PURE__*/ template(`<button>`);
|
|
13
|
-
var _tmpl$7 = /*#__PURE__*/ template(`<span
|
|
13
|
+
var _tmpl$7 = /*#__PURE__*/ template(`<span data-slot=sidebar-nav-section-action>`);
|
|
14
14
|
var _tmpl$8 = /*#__PURE__*/ template(`<div class="flex flex-col gap-0.5">`);
|
|
15
15
|
var _tmpl$9 = /*#__PURE__*/ template(`<div data-slot=sidebar-nav-section><div data-slot=sidebar-nav-section-header>`);
|
|
16
16
|
var _tmpl$0 = /*#__PURE__*/ template(`<span data-slot=sidebar-nav-row-actions class="ms-auto flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity ease-out group-hover/sidebar-nav-row:opacity-100 group-focus-within/sidebar-nav-row:opacity-100 has-[[aria-haspopup=menu][aria-expanded=true]]:opacity-100 has-[[aria-haspopup=true][aria-expanded=true]]:opacity-100 [@media(any-pointer:coarse)]:opacity-100">`);
|
|
@@ -68,7 +68,7 @@ function SidebarNavContent(props) {
|
|
|
68
68
|
return (() => {
|
|
69
69
|
var _el$2 = _tmpl$2();
|
|
70
70
|
spread(_el$2, mergeProps({ get ["class"]() {
|
|
71
|
-
return cn("flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2", local.class);
|
|
71
|
+
return cn("flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2 [scrollbar-gutter:stable]", local.class);
|
|
72
72
|
} }, rest), false, false);
|
|
73
73
|
return _el$2;
|
|
74
74
|
})();
|
|
@@ -95,6 +95,7 @@ function SidebarNavSection(props) {
|
|
|
95
95
|
"triggerProps",
|
|
96
96
|
"count",
|
|
97
97
|
"action",
|
|
98
|
+
"actionVisibility",
|
|
98
99
|
"headingAs",
|
|
99
100
|
"children"
|
|
100
101
|
]);
|
|
@@ -184,7 +185,7 @@ function SidebarNavSection(props) {
|
|
|
184
185
|
trigger.onReorder?.(event.key === "ArrowUp" ? "up" : "down");
|
|
185
186
|
},
|
|
186
187
|
get ["class"]() {
|
|
187
|
-
return cn("flex min-w-0 flex-1 items-center gap-1.5 rounded-sm text-2xs font-medium tracking-wide uppercase outline-none transition-colors ease-out hover:text-sidebar-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle [@media(any-pointer:coarse)]:min-h-11", local.active ? "text-foreground" : "text-sidebar-muted-foreground");
|
|
188
|
+
return cn("flex min-w-0 flex-1 items-center gap-1.5 rounded-sm text-2xs font-medium tracking-wide uppercase outline-none transition-colors ease-out hover:text-sidebar-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle [@media(any-pointer:coarse)]:min-h-11", "-my-1.5 py-1.5 [@media(any-pointer:coarse)]:my-0 [@media(any-pointer:coarse)]:py-0", local.active ? "text-foreground" : "text-sidebar-muted-foreground");
|
|
188
189
|
}
|
|
189
190
|
}), false, true);
|
|
190
191
|
insert(_el$8, heading);
|
|
@@ -200,6 +201,7 @@ function SidebarNavSection(props) {
|
|
|
200
201
|
get children() {
|
|
201
202
|
var _el$9 = _tmpl$7();
|
|
202
203
|
insert(_el$9, () => local.action);
|
|
204
|
+
effect(() => className(_el$9, cn("shrink-0", { "opacity-0 transition-opacity ease-out group-hover/section-header:opacity-100 focus-within:opacity-100 [@media(any-pointer:coarse)]:opacity-100": local.actionVisibility !== "always" })));
|
|
203
205
|
return _el$9;
|
|
204
206
|
}
|
|
205
207
|
}), null);
|