@ai-matrx/design-system 0.86.335 → 0.86.336

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/item.d.cts CHANGED
@@ -168,8 +168,6 @@ interface ItemMenuProps {
168
168
  * the rename input instead of back to the kebab. Desktop only.
169
169
  */
170
170
  onCloseAutoFocus?: ((event: Event) => void) | undefined;
171
- /** Min width of the dropdown content. Default "12rem". */
172
- contentMinWidth?: string | undefined;
173
171
  /** Force presentation. Default: useIsMobile(). For demos/tests. */
174
172
  presentation?: "auto" | "dropdown" | "drawer" | undefined;
175
173
  }
@@ -336,7 +334,7 @@ declare function resolveItemMenuConfig(input: ItemMenuConfigInput): ItemMenuConf
336
334
 
337
335
  declare function ItemRow({ label, secondaryLabel, secondaryShare, subtitle, actions, leadingControl, disclosure, reserveDisclosure, leading, trailing, trailingOnHover, active, disabled, href, onOpen, openInPlace, menu, rename, size, indent, kebabAriaLabel, disableContextMenu, sourceFeature, surfaceName, entity, className, }: ItemRowProps): react.JSX.Element;
338
336
 
339
- declare function ItemMenu({ config, children, align, side, open: openProp, onOpenChange, onCloseAutoFocus, contentMinWidth, presentation, }: ItemMenuProps): react.JSX.Element;
337
+ declare function ItemMenu({ config, children, align, side, open: openProp, onOpenChange, onCloseAutoFocus, presentation, }: ItemMenuProps): react.JSX.Element;
340
338
  declare namespace ItemMenu {
341
339
  var routeHeaderMenu: true;
342
340
  }
package/dist/item.d.ts CHANGED
@@ -168,8 +168,6 @@ interface ItemMenuProps {
168
168
  * the rename input instead of back to the kebab. Desktop only.
169
169
  */
170
170
  onCloseAutoFocus?: ((event: Event) => void) | undefined;
171
- /** Min width of the dropdown content. Default "12rem". */
172
- contentMinWidth?: string | undefined;
173
171
  /** Force presentation. Default: useIsMobile(). For demos/tests. */
174
172
  presentation?: "auto" | "dropdown" | "drawer" | undefined;
175
173
  }
@@ -336,7 +334,7 @@ declare function resolveItemMenuConfig(input: ItemMenuConfigInput): ItemMenuConf
336
334
 
337
335
  declare function ItemRow({ label, secondaryLabel, secondaryShare, subtitle, actions, leadingControl, disclosure, reserveDisclosure, leading, trailing, trailingOnHover, active, disabled, href, onOpen, openInPlace, menu, rename, size, indent, kebabAriaLabel, disableContextMenu, sourceFeature, surfaceName, entity, className, }: ItemRowProps): react.JSX.Element;
338
336
 
339
- declare function ItemMenu({ config, children, align, side, open: openProp, onOpenChange, onCloseAutoFocus, contentMinWidth, presentation, }: ItemMenuProps): react.JSX.Element;
337
+ declare function ItemMenu({ config, children, align, side, open: openProp, onOpenChange, onCloseAutoFocus, presentation, }: ItemMenuProps): react.JSX.Element;
340
338
  declare namespace ItemMenu {
341
339
  var routeHeaderMenu: true;
342
340
  }
package/dist/item.js CHANGED
@@ -12,8 +12,17 @@ import {
12
12
  runCommand,
13
13
  runToggle,
14
14
  useItemMenuHost
15
- } from "./chunk-4CO5STZU.js";
15
+ } from "./chunk-WZC3K7SO.js";
16
16
  import "./chunk-J6637L6D.js";
17
+ import {
18
+ MenuLookContent,
19
+ MenuLookItem,
20
+ MenuLookLabel,
21
+ MenuLookSeparator,
22
+ MenuLookSub,
23
+ MenuLookSubContent,
24
+ MenuLookSubTrigger
25
+ } from "./chunk-L5OACQXS.js";
17
26
  import "./chunk-HEFTQUJ5.js";
18
27
  import "./chunk-K4XCB576.js";
19
28
  import {
@@ -34,19 +43,13 @@ import "./chunk-NDTDBBMM.js";
34
43
  import "./chunk-LEPD6TV7.js";
35
44
  import "./chunk-KPZX2M2C.js";
36
45
  import "./chunk-WFBPCMPF.js";
46
+ import "./chunk-OPF265PU.js";
37
47
  import "./chunk-QOEKPR37.js";
38
48
  import "./chunk-BD77DHUO.js";
39
49
  import "./chunk-BKCJUFD3.js";
40
50
  import "./chunk-MOZRIHJF.js";
41
51
  import {
42
52
  DropdownMenu,
43
- DropdownMenuContent,
44
- DropdownMenuItem,
45
- DropdownMenuLabel,
46
- DropdownMenuSeparator,
47
- DropdownMenuSub,
48
- DropdownMenuSubContent,
49
- DropdownMenuSubTrigger,
50
53
  DropdownMenuTrigger
51
54
  } from "./chunk-X6ZRHJQP.js";
52
55
  import "./chunk-BNXNIN2S.js";
@@ -62,6 +65,7 @@ import "./chunk-XIUVUL2Y.js";
62
65
  import {
63
66
  ChevronRightIcon,
64
67
  MoreHorizontalIcon,
68
+ PanelLeftIcon,
65
69
  PlusIcon,
66
70
  SearchIcon
67
71
  } from "./chunk-YCUFQCJW.js";
@@ -128,16 +132,16 @@ function ProductSidebarTop({
128
132
  disableContextMenu: true
129
133
  }
130
134
  ) }) }),
131
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-56", children: [
135
+ /* @__PURE__ */ jsxs(MenuLookContent, { align: "start", "data-sidebar-more-menu": "", children: [
132
136
  more.map((p) => /* @__PURE__ */ jsx(PlaceMenuItem, { place: p, onOpen: open }, p.id)),
133
137
  groups.map((g, i) => /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": g.label, children: [
134
- more.length > 0 || i > 0 ? /* @__PURE__ */ jsx(DropdownMenuSeparator, {}) : null,
135
- g.label ? /* @__PURE__ */ jsx(DropdownMenuLabel, { children: g.label }) : null,
138
+ more.length > 0 || i > 0 ? /* @__PURE__ */ jsx(MenuLookSeparator, {}) : null,
139
+ g.label ? /* @__PURE__ */ jsx(MenuLookLabel, { children: g.label }) : null,
136
140
  g.places.map((p) => /* @__PURE__ */ jsx(PlaceMenuItem, { place: p, onOpen: open }, p.id))
137
141
  ] }, g.id)),
138
142
  onEditSidebar ? /* @__PURE__ */ jsxs(Fragment, { children: [
139
- more.length > 0 || groups.length > 0 ? /* @__PURE__ */ jsx(DropdownMenuSeparator, {}) : null,
140
- /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: onEditSidebar, children: "Edit sidebar\u2026" })
143
+ more.length > 0 || groups.length > 0 ? /* @__PURE__ */ jsx(MenuLookSeparator, {}) : null,
144
+ /* @__PURE__ */ jsx(MenuLookItem, { icon: /* @__PURE__ */ jsx(PanelLeftIcon, {}), label: "Edit sidebar\u2026", onSelect: onEditSidebar })
141
145
  ] }) : null
142
146
  ] })
143
147
  ] }) : null
@@ -181,7 +185,7 @@ function PlaceRow({
181
185
  disableContextMenu: true
182
186
  }
183
187
  ) }) }),
184
- /* @__PURE__ */ jsx(DropdownMenuContent, { side: "right", align: "start", className: "w-56", children: /* @__PURE__ */ jsx(FlyoutItems, { place, onOpen: (p) => onOpen ? onOpen(p) : goTo(p) }) })
188
+ /* @__PURE__ */ jsx(MenuLookContent, { side: "right", align: "start", "data-sidebar-place-menu": place.id, children: /* @__PURE__ */ jsx(FlyoutItems, { place, onOpen: (p) => onOpen ? onOpen(p) : goTo(p) }) })
185
189
  ] });
186
190
  }
187
191
  return /* @__PURE__ */ jsx("div", { "data-sidebar-place": place.id, children: /* @__PURE__ */ jsx(
@@ -203,36 +207,24 @@ function FlyoutItems({ place, onOpen }) {
203
207
  const Icon = place.icon;
204
208
  return /* @__PURE__ */ jsxs(Fragment, { children: [
205
209
  place.href ? /* @__PURE__ */ jsxs(Fragment, { children: [
206
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => onOpen({ ...place, children: void 0 }), children: [
207
- /* @__PURE__ */ jsx(Icon, { className: "size-4" }),
208
- place.label
209
- ] }),
210
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {})
210
+ /* @__PURE__ */ jsx(MenuLookItem, { icon: /* @__PURE__ */ jsx(Icon, {}), label: place.label, onSelect: () => onOpen({ ...place, children: void 0 }) }),
211
+ /* @__PURE__ */ jsx(MenuLookSeparator, {})
211
212
  ] }) : null,
212
213
  (place.children ?? []).map((c) => {
213
214
  const CIcon = c.icon;
214
- return /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => onOpen(c), children: [
215
- /* @__PURE__ */ jsx(CIcon, { className: "size-4" }),
216
- c.label
217
- ] }, c.id);
215
+ return /* @__PURE__ */ jsx(MenuLookItem, { icon: /* @__PURE__ */ jsx(CIcon, {}), label: c.label, onSelect: () => onOpen(c) }, c.id);
218
216
  })
219
217
  ] });
220
218
  }
221
219
  function PlaceMenuItem({ place, onOpen }) {
222
220
  const Icon = place.icon;
223
221
  if (place.children && place.children.length > 0) {
224
- return /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
225
- /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [
226
- /* @__PURE__ */ jsx(Icon, { className: "size-4" }),
227
- place.label
228
- ] }),
229
- /* @__PURE__ */ jsx(DropdownMenuSubContent, { className: "w-56", children: /* @__PURE__ */ jsx(FlyoutItems, { place, onOpen }) })
222
+ return /* @__PURE__ */ jsxs(MenuLookSub, { children: [
223
+ /* @__PURE__ */ jsx(MenuLookSubTrigger, { icon: /* @__PURE__ */ jsx(Icon, {}), label: place.label, "data-sidebar-more-place": place.id }),
224
+ /* @__PURE__ */ jsx(MenuLookSubContent, { children: /* @__PURE__ */ jsx(FlyoutItems, { place, onOpen }) })
230
225
  ] });
231
226
  }
232
- return /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => onOpen(place), children: [
233
- /* @__PURE__ */ jsx(Icon, { className: "size-4" }),
234
- place.label
235
- ] });
227
+ return /* @__PURE__ */ jsx(MenuLookItem, { icon: /* @__PURE__ */ jsx(Icon, {}), label: place.label, onSelect: () => onOpen(place), "data-sidebar-more-place": place.id });
236
228
  }
237
229
  function goTo(place) {
238
230
  if (place.href && typeof window !== "undefined") window.location.assign(place.href);
package/dist/item.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/item/ProductSidebarTop.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * THE TOP OF EVERY PRODUCT SIDEBAR (Arman, 2026-10-22: \"This is a very important missing thing that\n * we have to establish or our system will fail.\" — common-docs projects/app-frame/VISION.md).\n *\n * Extracted from the conversation sidebar's top (`@ai-matrx/chat` ConversationSidebar, approved\n * 2026-10-22), so every product sidebar — the web frame, desktop, the extension — has ONE shape and\n * ONE component:\n *\n * [status] optional one line (a refusal, a notice); absent = no band\n * (+) New optional\n * Agents › the chosen related places, in order\n * Workflows › a place with `children` opens a flyout of them; else it opens\n * Scheduled ›\n * … More every other place, the host's extra groups, \"Edit sidebar…\"\n * [children] optional (the conversation sidebar's one row of filter buttons)\n * ( Search ) the LIST's own search, last: directly above the host's list\n *\n * THE LIST'S SEARCH SITS WITH THE LIST (Arman, 2026-10-23: \"move the chat search to be above the\n * actual chats so it's not confused with the other things\"): it filters the rows below it, so it is\n * the last thing in the top, under the places and the filter row — never among the top actions.\n *\n * ONE LEFT EDGE (Arman, 2026-10-23): the Search glyph, every row's icon and the host's list below\n * share one left edge, 16px in from the column (this component's 8px padding + the row's 8px); a\n * place's `›` and every other chevron sit on the RIGHT. The modes (Chat, Work…) are never here —\n * they live in the page header.\n *\n * ONE SEARCH DOOR (Arman, 2026-10-23: \"You cannot have a search icon and also a searchbar\"): a\n * sidebar whose top row carries a search icon (the web frame's Go to) passes no `search` — that icon\n * finds every place and page this field used to. The field is only a list's own filter.\n *\n * The product's own list sits below, outside this component. WHICH places sit above More is a\n * layered knob (system → organization → person) the HOST reads and writes; this component only\n * draws `chosen` and calls `onEditSidebar`. `SidebarPlacesChooser` is the \"Above More\" section of\n * the host's Edit sidebar dialog (`SidebarEditDialog` is the dialog's chrome).\n */\n\nimport type { ComponentType, KeyboardEvent, ReactNode } from \"react\";\nimport {\n ChevronRightIcon as ChevronRight,\n MoreHorizontalIcon as MoreHorizontal,\n PlusIcon as Plus,\n SearchIcon as Search,\n} from \"../icons\";\nimport { Button } from \"../button\";\nimport { Checkbox } from \"../checkbox\";\nimport { cn } from \"../cn\";\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from \"../dialog\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"../dropdown-menu\";\nimport { InputWithPrefix } from \"../input\";\nimport { ItemRow } from \"./ItemRow\";\n\n/** One related place a product sidebar can offer (another product, a page, a list). */\nexport interface SidebarPlace {\n /** Stable id: what the layered \"above More\" knob stores. */\n id: string;\n label: string;\n icon: ComponentType<{ className?: string }>;\n /** Its address. Set it and the row is a real link (cmd/ctrl/middle-click opens a new tab). */\n href?: string | undefined;\n /** A sub-list: the row opens a flyout of these (the place itself first) instead of navigating. */\n children?: readonly SidebarPlace[] | undefined;\n}\n\n/** An extra group at the end of More (a product's own other pages, under its name). */\nexport interface SidebarMoreGroup {\n id: string;\n label?: string | undefined;\n places: readonly SidebarPlace[];\n}\n\nexport interface ProductSidebarTopSearch {\n value: string;\n onChange: (value: string) => void;\n /** Screen-reader name (\"Search conversations\"). */\n ariaLabel: string;\n placeholder?: string | undefined;\n}\n\nexport interface ProductSidebarTopProps {\n /** Above Search: one status line (a refusal, a notice). Render it only when it has something to say. */\n status?: ReactNode;\n search?: ProductSidebarTopSearch | undefined;\n /** \"New\" row; absent = none. */\n newItem?: { label?: string | undefined; href?: string | undefined; onOpen?: (() => void) | undefined } | undefined;\n /** Every related place, in order. */\n places: readonly SidebarPlace[];\n /** Ids shown above More, in this order (unknown ids are skipped). */\n chosen: readonly string[];\n /** A place was opened (plain click). Absent + `href` = the link navigates. */\n onOpenPlace?: ((place: SidebarPlace) => void) | undefined;\n /** Extra groups at the end of More, before \"Edit sidebar…\". */\n moreGroups?: readonly SidebarMoreGroup[] | undefined;\n /** \"Edit sidebar…\" in More; absent = not offered. */\n onEditSidebar?: (() => void) | undefined;\n /** Below the rows: the conversation sidebar's bucket toggles. */\n children?: ReactNode;\n /** The right-click menu's feature tag on every row. */\n sourceFeature: string;\n className?: string | undefined;\n}\n\n/** Places above More, in `chosen` order; the rest in `places` order. */\nexport function splitSidebarPlaces(\n places: readonly SidebarPlace[],\n chosen: readonly string[],\n): { above: SidebarPlace[]; more: SidebarPlace[] } {\n const byId = new Map(places.map((p) => [p.id, p]));\n const above = chosen.map((id) => byId.get(id)).filter((p): p is SidebarPlace => p != null);\n const aboveIds = new Set(above.map((p) => p.id));\n return { above, more: places.filter((p) => !aboveIds.has(p.id)) };\n}\n\nexport function ProductSidebarTop({\n status,\n search,\n newItem,\n places,\n chosen,\n onOpenPlace,\n moreGroups,\n onEditSidebar,\n children,\n sourceFeature,\n className,\n}: ProductSidebarTopProps) {\n const { above, more } = splitSidebarPlaces(places, chosen);\n const groups = (moreGroups ?? []).filter((g) => g.places.length > 0);\n const open = (place: SidebarPlace) => onOpenPlace?.(place);\n\n const onSearchKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (search && e.key === \"Escape\" && search.value) {\n e.preventDefault();\n search.onChange(\"\");\n }\n };\n\n return (\n <div data-product-sidebar-top=\"\" className={cn(\"flex shrink-0 flex-col gap-1 px-2 pb-1 pt-2\", className)}>\n {status}\n <div className=\"flex flex-col\">\n {newItem ? (\n <ItemRow\n size=\"sm\"\n label={newItem.label ?? \"New\"}\n leading={<Plus className=\"size-4\" />}\n href={newItem.href}\n openInPlace={newItem.href ? true : undefined}\n onOpen={newItem.onOpen}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n ) : null}\n {above.map((p) => (\n <PlaceRow key={p.id} place={p} onOpen={onOpenPlace ? open : undefined} sourceFeature={sourceFeature} chevron />\n ))}\n {more.length > 0 || groups.length > 0 || onEditSidebar ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <div data-sidebar-more-trigger=\"\">\n <ItemRow\n size=\"sm\"\n label=\"More\"\n leading={<MoreHorizontal className=\"size-4\" />}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n {more.map((p) => (\n <PlaceMenuItem key={p.id} place={p} onOpen={open} />\n ))}\n {groups.map((g, i) => (\n <div key={g.id} role=\"group\" aria-label={g.label}>\n {more.length > 0 || i > 0 ? <DropdownMenuSeparator /> : null}\n {g.label ? <DropdownMenuLabel>{g.label}</DropdownMenuLabel> : null}\n {g.places.map((p) => (\n <PlaceMenuItem key={p.id} place={p} onOpen={open} />\n ))}\n </div>\n ))}\n {onEditSidebar ? (\n <>\n {more.length > 0 || groups.length > 0 ? <DropdownMenuSeparator /> : null}\n <DropdownMenuItem onSelect={onEditSidebar}>Edit sidebar…</DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n\n {children}\n\n {search ? (\n <InputWithPrefix\n prefix={<Search className=\"size-4\" />}\n prefixInset=\"edge\"\n value={search.value}\n onChange={(e) => search.onChange(e.target.value)}\n onKeyDown={onSearchKeyDown}\n placeholder={search.placeholder ?? \"Search\"}\n aria-label={search.ariaLabel}\n className=\"h-8\"\n wrapperClassName=\"mt-1\"\n data-product-sidebar-search=\"\"\n />\n ) : null}\n </div>\n );\n}\n\n/** A place above More: a link row, or a flyout of its sub-list. */\nfunction PlaceRow({\n place,\n onOpen,\n sourceFeature,\n chevron,\n}: {\n place: SidebarPlace;\n onOpen: ((place: SidebarPlace) => void) | undefined;\n sourceFeature: string;\n chevron?: boolean;\n}) {\n const Icon = place.icon;\n const trailing = chevron ? <ChevronRight className=\"size-4 text-muted-foreground\" /> : undefined;\n if (place.children && place.children.length > 0) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <div data-sidebar-place={place.id} data-sidebar-place-flyout=\"\">\n <ItemRow\n size=\"sm\"\n label={place.label}\n leading={<Icon className=\"size-4\" />}\n trailing={trailing}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"right\" align=\"start\" className=\"w-56\">\n <FlyoutItems place={place} onOpen={(p) => (onOpen ? onOpen(p) : goTo(p))} />\n </DropdownMenuContent>\n </DropdownMenu>\n );\n }\n return (\n <div data-sidebar-place={place.id}>\n <ItemRow\n size=\"sm\"\n label={place.label}\n leading={<Icon className=\"size-4\" />}\n trailing={trailing}\n href={place.href}\n openInPlace={place.href && onOpen ? true : undefined}\n onOpen={onOpen ? () => onOpen(place) : undefined}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n </div>\n );\n}\n\n/** The place itself first, then its sub-list. */\nfunction FlyoutItems({ place, onOpen }: { place: SidebarPlace; onOpen: (place: SidebarPlace) => void }) {\n const Icon = place.icon;\n return (\n <>\n {place.href ? (\n <>\n <DropdownMenuItem onSelect={() => onOpen({ ...place, children: undefined })}>\n <Icon className=\"size-4\" />\n {place.label}\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n </>\n ) : null}\n {(place.children ?? []).map((c) => {\n const CIcon = c.icon;\n return (\n <DropdownMenuItem key={c.id} onSelect={() => onOpen(c)}>\n <CIcon className=\"size-4\" />\n {c.label}\n </DropdownMenuItem>\n );\n })}\n </>\n );\n}\n\nfunction PlaceMenuItem({ place, onOpen }: { place: SidebarPlace; onOpen: (place: SidebarPlace) => void }) {\n const Icon = place.icon;\n if (place.children && place.children.length > 0) {\n return (\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n <Icon className=\"size-4\" />\n {place.label}\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"w-56\">\n <FlyoutItems place={place} onOpen={onOpen} />\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n );\n }\n return (\n <DropdownMenuItem onSelect={() => onOpen(place)}>\n <Icon className=\"size-4\" />\n {place.label}\n </DropdownMenuItem>\n );\n}\n\n/** No host handler: a place with an address is a plain navigation. */\nfunction goTo(place: SidebarPlace) {\n if (place.href && typeof window !== \"undefined\") window.location.assign(place.href);\n}\n\n/** \"Above More\": which places sit above More (the host saves it on its layered knob). */\nexport function SidebarPlacesChooser({\n places,\n chosen,\n onChange,\n title = \"Above More\",\n}: {\n places: readonly SidebarPlace[];\n chosen: readonly string[];\n /** The next chosen ids, in `places` order. */\n onChange: (next: string[]) => void;\n title?: string;\n}) {\n const flip = (id: string) =>\n onChange(places.filter((p) => (p.id === id ? !chosen.includes(id) : chosen.includes(p.id))).map((p) => p.id));\n return (\n <section className=\"flex flex-col gap-1\" data-sidebar-places-chooser=\"\">\n <span className=\"text-sm font-medium text-foreground\">{title}</span>\n {places.map((p) => {\n const Icon = p.icon;\n return (\n <label key={p.id} className=\"flex h-8 cursor-pointer items-center gap-2 rounded-md px-1 text-sm hover:bg-muted\">\n <Checkbox size=\"sm\" checked={chosen.includes(p.id)} onCheckedChange={() => flip(p.id)} />\n <Icon className=\"size-4 text-muted-foreground\" />\n <span className=\"text-foreground\">{p.label}</span>\n </label>\n );\n })}\n </section>\n );\n}\n\n/** The Edit sidebar dialog's chrome: title, the host's sections, a refusal line, Cancel / Save. */\nexport function SidebarEditDialog({\n open,\n onOpenChange,\n onSave,\n refusal,\n saveLabel = \"Save as my default\",\n children,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onSave: () => void;\n /** Why the last save was refused; shown in the dialog. */\n refusal?: string | null | undefined;\n saveLabel?: string;\n children: ReactNode;\n}) {\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent size=\"sm\" onOpenAutoFocus={(e) => e.preventDefault()}>\n <DialogHeader>\n <DialogTitle>Edit sidebar</DialogTitle>\n </DialogHeader>\n <div className=\"flex flex-col gap-4\">\n {children}\n <div className=\"h-5 truncate text-sm text-destructive\" role=\"status\">\n {refusal ?? \"\"}\n </div>\n </div>\n <DialogFooter>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={onSave}>{saveLabel}</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/item/ProductSidebarTop.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * THE TOP OF EVERY PRODUCT SIDEBAR (Arman, 2026-10-22: \"This is a very important missing thing that\n * we have to establish or our system will fail.\" — common-docs projects/app-frame/VISION.md).\n *\n * Extracted from the conversation sidebar's top (`@ai-matrx/chat` ConversationSidebar, approved\n * 2026-10-22), so every product sidebar — the web frame, desktop, the extension — has ONE shape and\n * ONE component:\n *\n * [status] optional one line (a refusal, a notice); absent = no band\n * (+) New optional\n * Agents › the chosen related places, in order\n * Workflows › a place with `children` opens a flyout of them; else it opens\n * Scheduled ›\n * … More every other place, the host's extra groups, \"Edit sidebar…\"\n * [children] optional (the conversation sidebar's one row of filter buttons)\n * ( Search ) the LIST's own search, last: directly above the host's list\n *\n * THE LIST'S SEARCH SITS WITH THE LIST (Arman, 2026-10-23: \"move the chat search to be above the\n * actual chats so it's not confused with the other things\"): it filters the rows below it, so it is\n * the last thing in the top, under the places and the filter row — never among the top actions.\n *\n * ONE LEFT EDGE (Arman, 2026-10-23): the Search glyph, every row's icon and the host's list below\n * share one left edge, 16px in from the column (this component's 8px padding + the row's 8px); a\n * place's `›` and every other chevron sit on the RIGHT. The modes (Chat, Work…) are never here —\n * they live in the page header.\n *\n * ONE SEARCH DOOR (Arman, 2026-10-23: \"You cannot have a search icon and also a searchbar\"): a\n * sidebar whose top row carries a search icon (the web frame's Go to) passes no `search` — that icon\n * finds every place and page this field used to. The field is only a list's own filter.\n *\n * The product's own list sits below, outside this component. WHICH places sit above More is a\n * layered knob (system → organization → person) the HOST reads and writes; this component only\n * draws `chosen` and calls `onEditSidebar`. `SidebarPlacesChooser` is the \"Above More\" section of\n * the host's Edit sidebar dialog (`SidebarEditDialog` is the dialog's chrome).\n */\n\nimport type { ComponentType, KeyboardEvent, ReactNode } from \"react\";\nimport {\n ChevronRightIcon as ChevronRight,\n MoreHorizontalIcon as MoreHorizontal,\n PanelLeftIcon as PanelLeft,\n PlusIcon as Plus,\n SearchIcon as Search,\n} from \"../icons\";\nimport { Button } from \"../button\";\nimport { Checkbox } from \"../checkbox\";\nimport { cn } from \"../cn\";\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from \"../dialog\";\nimport { DropdownMenu, DropdownMenuTrigger } from \"../dropdown-menu\";\nimport {\n MenuLookContent,\n MenuLookItem,\n MenuLookLabel,\n MenuLookSeparator,\n MenuLookSub,\n MenuLookSubContent,\n MenuLookSubTrigger,\n} from \"../menu-look\";\nimport { InputWithPrefix } from \"../input\";\nimport { ItemRow } from \"./ItemRow\";\n\n/** One related place a product sidebar can offer (another product, a page, a list). */\nexport interface SidebarPlace {\n /** Stable id: what the layered \"above More\" knob stores. */\n id: string;\n label: string;\n icon: ComponentType<{ className?: string }>;\n /** Its address. Set it and the row is a real link (cmd/ctrl/middle-click opens a new tab). */\n href?: string | undefined;\n /** A sub-list: the row opens a flyout of these (the place itself first) instead of navigating. */\n children?: readonly SidebarPlace[] | undefined;\n}\n\n/** An extra group at the end of More (a product's own other pages, under its name). */\nexport interface SidebarMoreGroup {\n id: string;\n label?: string | undefined;\n places: readonly SidebarPlace[];\n}\n\nexport interface ProductSidebarTopSearch {\n value: string;\n onChange: (value: string) => void;\n /** Screen-reader name (\"Search conversations\"). */\n ariaLabel: string;\n placeholder?: string | undefined;\n}\n\nexport interface ProductSidebarTopProps {\n /** Above Search: one status line (a refusal, a notice). Render it only when it has something to say. */\n status?: ReactNode;\n search?: ProductSidebarTopSearch | undefined;\n /** \"New\" row; absent = none. */\n newItem?: { label?: string | undefined; href?: string | undefined; onOpen?: (() => void) | undefined } | undefined;\n /** Every related place, in order. */\n places: readonly SidebarPlace[];\n /** Ids shown above More, in this order (unknown ids are skipped). */\n chosen: readonly string[];\n /** A place was opened (plain click). Absent + `href` = the link navigates. */\n onOpenPlace?: ((place: SidebarPlace) => void) | undefined;\n /** Extra groups at the end of More, before \"Edit sidebar…\". */\n moreGroups?: readonly SidebarMoreGroup[] | undefined;\n /** \"Edit sidebar…\" in More; absent = not offered. */\n onEditSidebar?: (() => void) | undefined;\n /** Below the rows: the conversation sidebar's bucket toggles. */\n children?: ReactNode;\n /** The right-click menu's feature tag on every row. */\n sourceFeature: string;\n className?: string | undefined;\n}\n\n/** Places above More, in `chosen` order; the rest in `places` order. */\nexport function splitSidebarPlaces(\n places: readonly SidebarPlace[],\n chosen: readonly string[],\n): { above: SidebarPlace[]; more: SidebarPlace[] } {\n const byId = new Map(places.map((p) => [p.id, p]));\n const above = chosen.map((id) => byId.get(id)).filter((p): p is SidebarPlace => p != null);\n const aboveIds = new Set(above.map((p) => p.id));\n return { above, more: places.filter((p) => !aboveIds.has(p.id)) };\n}\n\nexport function ProductSidebarTop({\n status,\n search,\n newItem,\n places,\n chosen,\n onOpenPlace,\n moreGroups,\n onEditSidebar,\n children,\n sourceFeature,\n className,\n}: ProductSidebarTopProps) {\n const { above, more } = splitSidebarPlaces(places, chosen);\n const groups = (moreGroups ?? []).filter((g) => g.places.length > 0);\n const open = (place: SidebarPlace) => onOpenPlace?.(place);\n\n const onSearchKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (search && e.key === \"Escape\" && search.value) {\n e.preventDefault();\n search.onChange(\"\");\n }\n };\n\n return (\n <div data-product-sidebar-top=\"\" className={cn(\"flex shrink-0 flex-col gap-1 px-2 pb-1 pt-2\", className)}>\n {status}\n <div className=\"flex flex-col\">\n {newItem ? (\n <ItemRow\n size=\"sm\"\n label={newItem.label ?? \"New\"}\n leading={<Plus className=\"size-4\" />}\n href={newItem.href}\n openInPlace={newItem.href ? true : undefined}\n onOpen={newItem.onOpen}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n ) : null}\n {above.map((p) => (\n <PlaceRow key={p.id} place={p} onOpen={onOpenPlace ? open : undefined} sourceFeature={sourceFeature} chevron />\n ))}\n {more.length > 0 || groups.length > 0 || onEditSidebar ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <div data-sidebar-more-trigger=\"\">\n <ItemRow\n size=\"sm\"\n label=\"More\"\n leading={<MoreHorizontal className=\"size-4\" />}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n </div>\n </DropdownMenuTrigger>\n {/* THE ONE MENU LOOK (Arman, 2026-10-23: \"You don't even have the icons and text\n correctly displayed\"): More, its submenus and every flyout are menu-look parts —\n one 16px icon slot, one gap, one left edge, the chevron on the right. */}\n <MenuLookContent align=\"start\" data-sidebar-more-menu=\"\">\n {more.map((p) => (\n <PlaceMenuItem key={p.id} place={p} onOpen={open} />\n ))}\n {groups.map((g, i) => (\n <div key={g.id} role=\"group\" aria-label={g.label}>\n {more.length > 0 || i > 0 ? <MenuLookSeparator /> : null}\n {g.label ? <MenuLookLabel>{g.label}</MenuLookLabel> : null}\n {g.places.map((p) => (\n <PlaceMenuItem key={p.id} place={p} onOpen={open} />\n ))}\n </div>\n ))}\n {onEditSidebar ? (\n <>\n {more.length > 0 || groups.length > 0 ? <MenuLookSeparator /> : null}\n <MenuLookItem icon={<PanelLeft />} label=\"Edit sidebar…\" onSelect={onEditSidebar} />\n </>\n ) : null}\n </MenuLookContent>\n </DropdownMenu>\n ) : null}\n </div>\n\n {children}\n\n {search ? (\n <InputWithPrefix\n prefix={<Search className=\"size-4\" />}\n prefixInset=\"edge\"\n value={search.value}\n onChange={(e) => search.onChange(e.target.value)}\n onKeyDown={onSearchKeyDown}\n placeholder={search.placeholder ?? \"Search\"}\n aria-label={search.ariaLabel}\n className=\"h-8\"\n wrapperClassName=\"mt-1\"\n data-product-sidebar-search=\"\"\n />\n ) : null}\n </div>\n );\n}\n\n/** A place above More: a link row, or a flyout of its sub-list. */\nfunction PlaceRow({\n place,\n onOpen,\n sourceFeature,\n chevron,\n}: {\n place: SidebarPlace;\n onOpen: ((place: SidebarPlace) => void) | undefined;\n sourceFeature: string;\n chevron?: boolean;\n}) {\n const Icon = place.icon;\n const trailing = chevron ? <ChevronRight className=\"size-4 text-muted-foreground\" /> : undefined;\n if (place.children && place.children.length > 0) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <div data-sidebar-place={place.id} data-sidebar-place-flyout=\"\">\n <ItemRow\n size=\"sm\"\n label={place.label}\n leading={<Icon className=\"size-4\" />}\n trailing={trailing}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n </div>\n </DropdownMenuTrigger>\n <MenuLookContent side=\"right\" align=\"start\" data-sidebar-place-menu={place.id}>\n <FlyoutItems place={place} onOpen={(p) => (onOpen ? onOpen(p) : goTo(p))} />\n </MenuLookContent>\n </DropdownMenu>\n );\n }\n return (\n <div data-sidebar-place={place.id}>\n <ItemRow\n size=\"sm\"\n label={place.label}\n leading={<Icon className=\"size-4\" />}\n trailing={trailing}\n href={place.href}\n openInPlace={place.href && onOpen ? true : undefined}\n onOpen={onOpen ? () => onOpen(place) : undefined}\n sourceFeature={sourceFeature}\n disableContextMenu\n />\n </div>\n );\n}\n\n/** The place itself first, then its sub-list. */\nfunction FlyoutItems({ place, onOpen }: { place: SidebarPlace; onOpen: (place: SidebarPlace) => void }) {\n const Icon = place.icon;\n return (\n <>\n {place.href ? (\n <>\n <MenuLookItem icon={<Icon />} label={place.label} onSelect={() => onOpen({ ...place, children: undefined })} />\n <MenuLookSeparator />\n </>\n ) : null}\n {(place.children ?? []).map((c) => {\n const CIcon = c.icon;\n return <MenuLookItem key={c.id} icon={<CIcon />} label={c.label} onSelect={() => onOpen(c)} />;\n })}\n </>\n );\n}\n\nfunction PlaceMenuItem({ place, onOpen }: { place: SidebarPlace; onOpen: (place: SidebarPlace) => void }) {\n const Icon = place.icon;\n if (place.children && place.children.length > 0) {\n return (\n <MenuLookSub>\n <MenuLookSubTrigger icon={<Icon />} label={place.label} data-sidebar-more-place={place.id} />\n <MenuLookSubContent>\n <FlyoutItems place={place} onOpen={onOpen} />\n </MenuLookSubContent>\n </MenuLookSub>\n );\n }\n return <MenuLookItem icon={<Icon />} label={place.label} onSelect={() => onOpen(place)} data-sidebar-more-place={place.id} />;\n}\n\n/** No host handler: a place with an address is a plain navigation. */\nfunction goTo(place: SidebarPlace) {\n if (place.href && typeof window !== \"undefined\") window.location.assign(place.href);\n}\n\n/** \"Above More\": which places sit above More (the host saves it on its layered knob). */\nexport function SidebarPlacesChooser({\n places,\n chosen,\n onChange,\n title = \"Above More\",\n}: {\n places: readonly SidebarPlace[];\n chosen: readonly string[];\n /** The next chosen ids, in `places` order. */\n onChange: (next: string[]) => void;\n title?: string;\n}) {\n const flip = (id: string) =>\n onChange(places.filter((p) => (p.id === id ? !chosen.includes(id) : chosen.includes(p.id))).map((p) => p.id));\n return (\n <section className=\"flex flex-col gap-1\" data-sidebar-places-chooser=\"\">\n <span className=\"text-sm font-medium text-foreground\">{title}</span>\n {places.map((p) => {\n const Icon = p.icon;\n return (\n <label key={p.id} className=\"flex h-8 cursor-pointer items-center gap-2 rounded-md px-1 text-sm hover:bg-muted\">\n <Checkbox size=\"sm\" checked={chosen.includes(p.id)} onCheckedChange={() => flip(p.id)} />\n <Icon className=\"size-4 text-muted-foreground\" />\n <span className=\"text-foreground\">{p.label}</span>\n </label>\n );\n })}\n </section>\n );\n}\n\n/** The Edit sidebar dialog's chrome: title, the host's sections, a refusal line, Cancel / Save. */\nexport function SidebarEditDialog({\n open,\n onOpenChange,\n onSave,\n refusal,\n saveLabel = \"Save as my default\",\n children,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onSave: () => void;\n /** Why the last save was refused; shown in the dialog. */\n refusal?: string | null | undefined;\n saveLabel?: string;\n children: ReactNode;\n}) {\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent size=\"sm\" onOpenAutoFocus={(e) => e.preventDefault()}>\n <DialogHeader>\n <DialogTitle>Edit sidebar</DialogTitle>\n </DialogHeader>\n <div className=\"flex flex-col gap-4\">\n {children}\n <div className=\"h-5 truncate text-sm text-destructive\" role=\"status\">\n {refusal ?? \"\"}\n </div>\n </div>\n <DialogFooter>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={onSave}>{saveLabel}</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}