@adea-ai/ui 0.81.1 → 0.82.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.
Files changed (70) hide show
  1. package/README.md +41 -8
  2. package/dist/components/composites/account-menu/account-menu.d.ts +5 -0
  3. package/dist/components/composites/account-menu/account-menu.d.ts.map +1 -1
  4. package/dist/components/composites/account-menu/account-menu.js +122 -70
  5. package/dist/components/composites/account-menu/account-menu.js.map +1 -1
  6. package/dist/components/composites/action-button/action-button.d.ts +27 -0
  7. package/dist/components/composites/action-button/action-button.d.ts.map +1 -0
  8. package/dist/components/composites/action-button/action-button.js +121 -0
  9. package/dist/components/composites/action-button/action-button.js.map +1 -0
  10. package/dist/components/composites/action-button/index.d.ts +3 -0
  11. package/dist/components/composites/action-button/index.d.ts.map +1 -0
  12. package/dist/components/composites/action-button/index.js +2 -0
  13. package/dist/components/conversation/thread-panel.d.ts +2 -0
  14. package/dist/components/conversation/thread-panel.d.ts.map +1 -1
  15. package/dist/components/conversation/thread-panel.js +36 -31
  16. package/dist/components/conversation/thread-panel.js.map +1 -1
  17. package/dist/components/layout/sidebar-nav/index.d.ts +1 -1
  18. package/dist/components/layout/sidebar-nav/index.d.ts.map +1 -1
  19. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts +6 -1
  20. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts.map +1 -1
  21. package/dist/components/layout/sidebar-nav/sidebar-nav.js +66 -62
  22. package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
  23. package/dist/components/ui/board/board.d.ts.map +1 -1
  24. package/dist/components/ui/board/board.js +54 -7
  25. package/dist/components/ui/board/board.js.map +1 -1
  26. package/dist/components/ui/command/command.d.ts +5 -1
  27. package/dist/components/ui/command/command.d.ts.map +1 -1
  28. package/dist/components/ui/command/command.js +8 -3
  29. package/dist/components/ui/command/command.js.map +1 -1
  30. package/dist/components/ui/input/index.d.ts +1 -1
  31. package/dist/components/ui/input/index.d.ts.map +1 -1
  32. package/dist/components/ui/input/input.d.ts +5 -1
  33. package/dist/components/ui/input/input.d.ts.map +1 -1
  34. package/dist/components/ui/input/input.js +36 -17
  35. package/dist/components/ui/input/input.js.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -1
  39. package/dist/lint/index.d.ts +2 -0
  40. package/dist/lint/index.d.ts.map +1 -1
  41. package/dist/lint.js +82 -0
  42. package/dist/lint.js.map +1 -1
  43. package/dist/r/account-menu.json +1 -0
  44. package/dist/r/action-button.json +24 -0
  45. package/dist/r/conversation.json +1 -0
  46. package/dist/r/registry.json +26 -0
  47. package/dist/r/src/components/composites/account-menu/account-menu.tsx +100 -44
  48. package/dist/r/src/components/composites/action-button/action-button.tsx +139 -0
  49. package/dist/r/src/components/composites/action-button/index.ts +2 -0
  50. package/dist/r/src/components/conversation/thread-panel.tsx +22 -12
  51. package/dist/r/src/components/layout/sidebar-nav/index.ts +1 -0
  52. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +29 -21
  53. package/dist/r/src/components/ui/board/board.tsx +74 -6
  54. package/dist/r/src/components/ui/command/command.tsx +15 -4
  55. package/dist/r/src/components/ui/input/index.ts +1 -1
  56. package/dist/r/src/components/ui/input/input.tsx +38 -21
  57. package/package.json +1 -1
  58. package/registry.json +26 -0
  59. package/src/components/composites/account-menu/account-menu.tsx +100 -44
  60. package/src/components/composites/action-button/action-button.tsx +139 -0
  61. package/src/components/composites/action-button/index.ts +2 -0
  62. package/src/components/conversation/thread-panel.tsx +22 -12
  63. package/src/components/layout/sidebar-nav/index.ts +1 -0
  64. package/src/components/layout/sidebar-nav/sidebar-nav.tsx +29 -21
  65. package/src/components/ui/board/board.tsx +74 -6
  66. package/src/components/ui/command/command.tsx +15 -4
  67. package/src/components/ui/input/index.ts +1 -1
  68. package/src/components/ui/input/input.tsx +38 -21
  69. package/src/index.ts +1 -0
  70. package/src/lint/index.ts +95 -0
package/README.md CHANGED
@@ -47,12 +47,19 @@ keyboard, form submission, option, and label behavior:
47
47
 
48
48
  ```tsx
49
49
  import { NativeSelect } from '@adea-ai/ui/components/ui/native-select'
50
-
51
- <label for="relationship-kind">Relationship kind</label>
52
- <NativeSelect id="relationship-kind" name="relationshipKind" value={kind()} onChange={handleChange}>
53
- <option value="all">All relationships</option>
54
- <option value="derived">Derived</option>
55
- </NativeSelect>
50
+ import { Label } from '@adea-ai/ui/components/ui/label'
51
+
52
+ <Label for="relationship-kind">Relationship kind</Label>
53
+ <NativeSelect
54
+ id="relationship-kind"
55
+ name="relationshipKind"
56
+ value={kind()}
57
+ onChange={handleChange}
58
+ options={[
59
+ { value: 'all', label: 'All relationships' },
60
+ { value: 'derived', label: 'Derived' },
61
+ ]}
62
+ />
56
63
  ```
57
64
 
58
65
  `NativeSelect` renders a real `<select>` and passes native props and children
@@ -60,6 +67,32 @@ through. Use `value` with `onChange` for a controlled selection, or `defaultValu
60
67
  to initialize an uncontrolled one. Use `Select` for searchable, runtime, or
61
68
  longer lists that need a custom popover.
62
69
 
70
+ For free-form text with native suggestions, pass `suggestions` to `Input`.
71
+ The library owns the datalist and unique association; a suggestion does not
72
+ restrict the submitted value. Native `required`, `pattern`, form, event, and
73
+ ref props still apply to the input.
74
+
75
+ `ThreadPanel.headerActions` accepts shared controls for host actions such as
76
+ marking a thread unread. Closing the thread remains a separate labelled,
77
+ tooltip-backed control. Hosts retain read-marker and message authority.
78
+
79
+ `AccountMenu` owns the trigger tooltip, menu keyboard behavior, and session row.
80
+ Pass `size` to match its host control size. Use an item's `onSelect` for an
81
+ immediate action, or `onSelectAfterClose` to open a dialog after the menu has
82
+ finished closing. The latter receives the connected trigger button for dialog
83
+ focus restoration and is cancelled if the menu unmounts. Authentication,
84
+ updates, navigation, and other effects remain host callbacks.
85
+
86
+ `SidebarNavTitle` accepts polymorphic `as` for a host's title heading.
87
+ Use `SidebarNavSection.headingAs` (h1 through h6) for section headings.
88
+ Disclosure buttons stay inside their heading and trailing actions stay outside
89
+ it, preserving hierarchy and independent keyboard actions.
90
+
91
+ `Board` checks the caller's legal-move predicate before settling a pointer drop.
92
+ Ctrl/Cmd + arrow moves skip disabled columns without wrapping at the edges.
93
+ After a controlled move settles, focus follows the moved card only when the
94
+ source card owned focus; another focus or pointer action cancels restoration.
95
+
63
96
  Tailwind ignores dependency directories by default. Register the component
64
97
  directories your application uses in its stylesheet, relative to that stylesheet:
65
98
 
@@ -95,7 +128,7 @@ notes through the breaking Conventional Commit, rather than a silent patch.
95
128
 
96
129
  ## Theming
97
130
 
98
- The catalogue is 27 themes across two appearances, grouped into families. The
131
+ The catalogue is 34 themes across two appearances, grouped into families. The
99
132
  provider takes an initial selection and every axis is a plain value:
100
133
 
101
134
  ```tsx
@@ -113,7 +146,7 @@ provider takes an initial selection and every axis is a plain value:
113
146
  | Axis | Values | How it is applied |
114
147
  | ---------- | -------------------------------------------------- | -------------------------------------------------------------- |
115
148
  | Appearance | `light`, `dark`, `system` | a `dark` class plus `color-scheme` on `<html>` |
116
- | Theme | any of the 27 catalogue ids | the variant's tokens, written as custom properties on `<html>` |
149
+ | Theme | any of the 34 catalogue ids | the variant's tokens, written as custom properties on `<html>` |
117
150
  | Accent | `theme` (follow the variant) or one of six presets | a `data-accent` attribute on `<html>` |
118
151
  | Typeface | five options | a `data-font` attribute on `<html>` |
119
152
 
@@ -1,4 +1,5 @@
1
1
  import type { JSX } from 'solid-js';
2
+ import { type ButtonProps } from '../../ui/button/button';
2
3
  /**
3
4
  * AccountMenu.
4
5
  *
@@ -26,9 +27,13 @@ export type AccountMenuItem = {
26
27
  /** Render only on this platform. Omit to always render. */
27
28
  platform?: 'desktop' | 'web';
28
29
  onSelect?: () => void;
30
+ /** Run after the menu's close-focus cycle, with its trigger as a stable opener. */
31
+ onSelectAfterClose?: (trigger: HTMLButtonElement | undefined) => void;
29
32
  };
30
33
  export type AccountMenuProps = {
31
34
  class?: string;
35
+ /** The trigger size. Icon-only menus default to the standard icon size. */
36
+ size?: ButtonProps['size'];
32
37
  /** The entries above the separator. */
33
38
  items: readonly AccountMenuItem[];
34
39
  /** Which platform this is rendered on, for items that declare one. */
@@ -1 +1 @@
1
- {"version":3,"file":"account-menu.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/account-menu/account-menu.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAanC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAClB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC5B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uCAAuC;IACvC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAA;IACjC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC5B,kEAAkE;IAClE,aAAa,EAAE,OAAO,CAAA;IACtB,wEAAwE;IACxE,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA;AAWD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eA4DlD"}
1
+ {"version":3,"file":"account-menu.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/account-menu/account-menu.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAkB,GAAG,EAAE,MAAM,UAAU,CAAA;AAGnD,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAWjE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAClB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC5B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,KAAK,IAAI,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC1B,uCAAuC;IACvC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAA;IACjC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,CAAA;IAC5B,kEAAkE;IAClE,aAAa,EAAE,OAAO,CAAA;IACtB,wEAAwE;IACxE,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA;AAWD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eA2GlD"}
@@ -1,9 +1,10 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { Button } from "../../ui/button/button.js";
3
3
  import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "../../ui/dropdown-menu/dropdown-menu.js";
4
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../../ui/tooltip/tooltip.js";
4
5
  import { createComponent, insert, memo, mergeProps, template } from "solid-js/web";
5
6
  import { CircleHelp, Info, LogIn, LogOut, Megaphone, RefreshCw, Settings2, Smartphone, UserRound } from "lucide-solid";
6
- import { For, Show, splitProps } from "solid-js";
7
+ import { For, Show, createSignal, onCleanup, splitProps } from "solid-js";
7
8
  //#region src/components/composites/account-menu/account-menu.tsx
8
9
  var _tmpl$ = /*#__PURE__*/ template(`<span>`);
9
10
  var FALLBACK_ICONS = {
@@ -17,6 +18,7 @@ var FALLBACK_ICONS = {
17
18
  function AccountMenu(props) {
18
19
  const [local, rest] = splitProps(props, [
19
20
  "class",
21
+ "size",
20
22
  "items",
21
23
  "platform",
22
24
  "authenticated",
@@ -26,85 +28,135 @@ function AccountMenu(props) {
26
28
  "onSignOut",
27
29
  "onIntent"
28
30
  ]);
31
+ let trigger;
32
+ let pendingAfterClose;
33
+ let scheduledAfterClose;
34
+ const [menuOpen, setMenuOpen] = createSignal(false);
35
+ const [tooltipOpen, setTooltipOpen] = createSignal(false);
36
+ onCleanup(() => {
37
+ pendingAfterClose = void 0;
38
+ scheduledAfterClose = void 0;
39
+ });
29
40
  const visible = () => local.items.filter((item) => !item.platform || item.platform === (local.platform ?? "desktop"));
30
- return createComponent(DropdownMenu, {
31
- modal: false,
41
+ return createComponent(Tooltip, {
42
+ get open() {
43
+ return tooltipOpen();
44
+ },
45
+ onOpenChange: (open) => setTooltipOpen(open && !menuOpen()),
32
46
  get children() {
33
- return [createComponent(DropdownMenuTrigger, mergeProps({
34
- as: Button,
35
- variant: "ghost",
36
- size: "icon-md",
37
- get ["class"]() {
38
- return cn("text-muted-foreground", local.class);
39
- },
40
- get ["aria-label"]() {
41
- return local.label ?? "Account and settings";
47
+ return createComponent(DropdownMenu, {
48
+ modal: false,
49
+ onOpenChange: (open) => {
50
+ setMenuOpen(open);
51
+ if (open) setTooltipOpen(false);
42
52
  },
43
- onFocus: () => local.onIntent?.(),
44
- onPointerEnter: () => local.onIntent?.()
45
- }, rest, { get children() {
46
- return createComponent(UserRound, { "aria-hidden": "true" });
47
- } })), createComponent(DropdownMenuContent, {
48
- side: "top",
49
- align: "start",
50
- "class": "min-w-56",
51
53
  get children() {
52
54
  return [
53
- createComponent(DropdownMenuGroup, { get children() {
54
- return createComponent(For, {
55
- get each() {
56
- return visible();
57
- },
58
- children: (item) => createComponent(DropdownMenuItem, {
59
- get disabled() {
60
- return item.disabled;
61
- },
62
- onSelect: () => item.onSelect?.(),
63
- get shortcut() {
64
- return item.shortcut;
65
- },
66
- get children() {
67
- return [memo(() => item.icon ?? renderFallbackIcon(item.id)), (() => {
68
- var _el$2 = _tmpl$();
69
- insert(_el$2, () => item.label);
70
- return _el$2;
71
- })()];
72
- }
73
- })
74
- });
75
- } }),
76
- createComponent(DropdownMenuSeparator, {}),
77
- createComponent(DropdownMenuGroup, { get children() {
78
- return createComponent(DropdownMenuItem, {
79
- get disabled() {
80
- return local.busy;
81
- },
82
- onSelect: () => local.authenticated ? local.onSignOut?.() : local.onSignIn?.(),
83
- get children() {
84
- return [createComponent(Show, {
85
- get when() {
86
- return local.authenticated;
87
- },
88
- get fallback() {
89
- return createComponent(LogIn, { "aria-hidden": "true" });
90
- },
91
- get children() {
92
- return createComponent(LogOut, { "aria-hidden": "true" });
93
- }
94
- }), (() => {
95
- var _el$ = _tmpl$();
96
- insert(_el$, () => local.authenticated ? "Sign out" : "Sign in");
97
- return _el$;
98
- })()];
99
- }
100
- });
101
- } })
55
+ createComponent(TooltipTrigger, mergeProps({
56
+ as: AccountMenuButton,
57
+ ref: (element) => trigger = element,
58
+ variant: "ghost",
59
+ get size() {
60
+ return local.size ?? "icon-md";
61
+ },
62
+ get ["class"]() {
63
+ return cn("text-muted-foreground", local.class);
64
+ },
65
+ get ["aria-label"]() {
66
+ return local.label ?? "Account and settings";
67
+ },
68
+ onFocus: () => local.onIntent?.(),
69
+ onPointerEnter: () => local.onIntent?.()
70
+ }, rest, { get children() {
71
+ return createComponent(UserRound, { "aria-hidden": "true" });
72
+ } })),
73
+ createComponent(TooltipContent, {
74
+ placement: "top",
75
+ get children() {
76
+ return local.label ?? "Account and settings";
77
+ }
78
+ }),
79
+ createComponent(DropdownMenuContent, {
80
+ placement: "top-start",
81
+ "class": "min-w-56 max-h-(--kb-popper-available-height) overflow-x-hidden overflow-y-auto",
82
+ onCloseAutoFocus: (event) => {
83
+ const selection = pendingAfterClose;
84
+ pendingAfterClose = void 0;
85
+ if (!selection) return;
86
+ event.preventDefault();
87
+ scheduledAfterClose = selection;
88
+ queueMicrotask(() => {
89
+ if (scheduledAfterClose !== selection) return;
90
+ scheduledAfterClose = void 0;
91
+ selection.callback(trigger);
92
+ });
93
+ },
94
+ get children() {
95
+ return [
96
+ createComponent(DropdownMenuGroup, { get children() {
97
+ return createComponent(For, {
98
+ get each() {
99
+ return visible();
100
+ },
101
+ children: (item) => createComponent(DropdownMenuItem, {
102
+ get disabled() {
103
+ return item.disabled;
104
+ },
105
+ onSelect: () => {
106
+ pendingAfterClose = item.onSelectAfterClose ? { callback: item.onSelectAfterClose } : void 0;
107
+ item.onSelect?.();
108
+ },
109
+ get shortcut() {
110
+ return item.shortcut;
111
+ },
112
+ get children() {
113
+ return [memo(() => item.icon ?? renderFallbackIcon(item.id)), (() => {
114
+ var _el$2 = _tmpl$();
115
+ insert(_el$2, () => item.label);
116
+ return _el$2;
117
+ })()];
118
+ }
119
+ })
120
+ });
121
+ } }),
122
+ createComponent(DropdownMenuSeparator, {}),
123
+ createComponent(DropdownMenuGroup, { get children() {
124
+ return createComponent(DropdownMenuItem, {
125
+ get disabled() {
126
+ return local.busy;
127
+ },
128
+ onSelect: () => local.authenticated ? local.onSignOut?.() : local.onSignIn?.(),
129
+ get children() {
130
+ return [createComponent(Show, {
131
+ get when() {
132
+ return local.authenticated;
133
+ },
134
+ get fallback() {
135
+ return createComponent(LogIn, { "aria-hidden": "true" });
136
+ },
137
+ get children() {
138
+ return createComponent(LogOut, { "aria-hidden": "true" });
139
+ }
140
+ }), (() => {
141
+ var _el$ = _tmpl$();
142
+ insert(_el$, () => local.authenticated ? "Sign out" : "Sign in");
143
+ return _el$;
144
+ })()];
145
+ }
146
+ });
147
+ } })
148
+ ];
149
+ }
150
+ })
102
151
  ];
103
152
  }
104
- })];
153
+ });
105
154
  }
106
155
  });
107
156
  }
157
+ function AccountMenuButton(props) {
158
+ return createComponent(DropdownMenuTrigger, mergeProps({ as: Button }, props));
159
+ }
108
160
  /**
109
161
  * A known item id gets its conventional glyph, so a caller that only wants the
110
162
  * standard menu does not have to import six icons to get it.
@@ -1 +1 @@
1
- {"version":3,"file":"account-menu.js","names":["CircleHelp","Info","LogIn","LogOut","Megaphone","RefreshCw","Settings2","Smartphone","UserRound","JSX","For","Show","splitProps","cn","Button","DropdownMenu","DropdownMenuContent","DropdownMenuGroup","DropdownMenuItem","DropdownMenuSeparator","DropdownMenuTrigger","AccountMenuItem","id","label","icon","Element","shortcut","disabled","platform","onSelect","AccountMenuProps","class","items","authenticated","busy","onSignIn","onSignOut","onIntent","FALLBACK_ICONS","Record","mobile","settings","about","help","feedback","updates","AccountMenu","props","local","rest","visible","filter","item","_$createComponent","modal","children","_$mergeProps","as","variant","size","aria-label","onFocus","onPointerEnter","side","align","each","_$memo","renderFallbackIcon","_el$2","_tmpl$","_$insert","when","fallback","_el$","Icon","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/composites/account-menu/account-menu.tsx"],"sourcesContent":["import {\n CircleHelp,\n Info,\n LogIn,\n LogOut,\n Megaphone,\n RefreshCw,\n Settings2,\n Smartphone,\n UserRound,\n} from 'lucide-solid'\nimport type { JSX } from 'solid-js'\nimport { For, Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Button } from '../../ui/button/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../../ui/dropdown-menu/dropdown-menu'\n\n/**\n * AccountMenu.\n *\n * The trailing control in a rail or a top bar: the account, the way into settings,\n * and the way out. Every desktop application has one and they are all the same menu,\n * which is why it belongs here rather than being redrawn per app.\n *\n * ## The items are the caller's\n *\n * The menu takes a list rather than hard-coding one. An application adds and removes\n * entries — a mobile hand-off that only makes sense on desktop, a feedback link that\n * only exists once there is somewhere to send it — and a component that decided the\n * list could not be used by two products.\n *\n * `disabled` on an item is deliberately visible rather than hidden: a greyed \"Help\n * Center\" says the destination is coming, while an absent one says it does not exist.\n */\nexport type AccountMenuItem = {\n id: string\n label: string\n icon?: JSX.Element\n /** A chord drawn at the trailing edge, e.g. `⌘,`. */\n shortcut?: string\n disabled?: boolean\n /** Render only on this platform. Omit to always render. */\n platform?: 'desktop' | 'web'\n onSelect?: () => void\n}\n\nexport type AccountMenuProps = {\n class?: string\n /** The entries above the separator. */\n items: readonly AccountMenuItem[]\n /** Which platform this is rendered on, for items that declare one. */\n platform?: 'desktop' | 'web'\n /** Whether a session exists. Decides the sign-in/sign-out row. */\n authenticated: boolean\n /** Disable the session row while a sign-in or sign-out is in flight. */\n busy?: boolean\n /** The name shown on the trigger's accessible label. */\n label?: string\n onSignIn?: () => void\n onSignOut?: () => void\n /** Fires on hover or focus of the trigger — a chance to prefetch. */\n onIntent?: () => void\n}\n\nconst FALLBACK_ICONS: Record<string, typeof Settings2> = {\n mobile: Smartphone,\n settings: Settings2,\n about: Info,\n help: CircleHelp,\n feedback: Megaphone,\n updates: RefreshCw,\n}\n\nexport function AccountMenu(props: AccountMenuProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'items',\n 'platform',\n 'authenticated',\n 'busy',\n 'label',\n 'onSignIn',\n 'onSignOut',\n 'onIntent',\n ])\n\n const visible = () =>\n local.items.filter((item) => !item.platform || item.platform === (local.platform ?? 'desktop'))\n\n return (\n <DropdownMenu modal={false}>\n <DropdownMenuTrigger\n as={Button}\n variant=\"ghost\"\n size=\"icon-md\"\n class={cn('text-muted-foreground', local.class)}\n aria-label={local.label ?? 'Account and settings'}\n onFocus={() => local.onIntent?.()}\n onPointerEnter={() => local.onIntent?.()}\n {...rest}\n >\n <UserRound aria-hidden=\"true\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"top\" align=\"start\" class=\"min-w-56\">\n <DropdownMenuGroup>\n <For each={visible()}>\n {(item) => (\n <DropdownMenuItem\n disabled={item.disabled}\n onSelect={() => item.onSelect?.()}\n shortcut={item.shortcut}\n >\n {item.icon ?? renderFallbackIcon(item.id)}\n <span>{item.label}</span>\n </DropdownMenuItem>\n )}\n </For>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem\n disabled={local.busy}\n onSelect={() => (local.authenticated ? local.onSignOut?.() : local.onSignIn?.())}\n >\n <Show when={local.authenticated} fallback={<LogIn aria-hidden=\"true\" />}>\n <LogOut aria-hidden=\"true\" />\n </Show>\n <span>{local.authenticated ? 'Sign out' : 'Sign in'}</span>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\n/**\n * A known item id gets its conventional glyph, so a caller that only wants the\n * standard menu does not have to import six icons to get it.\n */\nfunction renderFallbackIcon(id: string): JSX.Element {\n const Icon = FALLBACK_ICONS[id]\n return Icon ? <Icon aria-hidden=\"true\" /> : null\n}\n"],"mappings":";;;;;;;;AAuEA,IAAMsC,iBAAmD;CACvDE,QAAQjC;CACRkC,UAAUnC;CACVoC,OAAOzC;CACP0C,MAAM3C;CACN4C,UAAUxC;CACVyC,SAASxC;AACX;AAEA,SAAgByC,YAAYC,OAAyB;CACnD,MAAM,CAACC,OAAOC,QAAQrC,WAAWmC,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAU,CACX;CAED,MAAMG,gBACJF,MAAMhB,MAAMmB,QAAQC,SAAS,CAACA,KAAKxB,YAAYwB,KAAKxB,cAAcoB,MAAMpB,YAAY,UAAU;CAEhG,OAAAyB,gBACGtC,cAAY;EAACuC,OAAO;EAAK,IAAAC,WAAA;GAAA,OAAA,CAAAF,gBACvBjC,qBAAmBoC,WAAA;IAClBC,IAAI3C;IACJ4C,SAAO;IACPC,MAAI;IAAA,KAAA,WAAA;KAAA,OACG9C,GAAG,yBAAyBmC,MAAMjB,KAAK;IAAC;IAAA,KAAA,gBAAA;KAAA,OACnCiB,MAAMzB,SAAS;IAAsB;IACjDsC,eAAeb,MAAMX,WAAW;IAChCyB,sBAAsBd,MAAMX,WAAW;GAAC,GACpCY,MAAI,EAAA,IAAAM,WAAA;IAAA,OAAAF,gBAEP7C,WAAS,EAAA,eAAA,OAAA,CAAA;GAAA,EAAA,CAAA,CAAA,GAAA6C,gBAEXrC,qBAAmB;IAAC+C,MAAI;IAAOC,OAAK;IAAA,SAAA;IAAA,IAAAT,WAAA;KAAA,OAAA;MAAAF,gBAClCpC,mBAAiB,EAAA,IAAAsC,WAAA;OAAA,OAAAF,gBACf3C,KAAG;QAAA,IAACuD,OAAI;SAAA,OAAEf,QAAQ;QAAC;QAAAK,WAChBH,SAAIC,gBACHnC,kBAAgB;SAAA,IACfS,WAAQ;UAAA,OAAEyB,KAAKzB;SAAQ;SACvBE,gBAAgBuB,KAAKvB,WAAW;SAAC,IACjCH,WAAQ;UAAA,OAAE0B,KAAK1B;SAAQ;SAAA,IAAA6B,WAAA;UAAA,OAAA,CAAAW,WAEtBd,KAAK5B,QAAQ2C,mBAAmBf,KAAK9B,EAAE,CAAC,UAAA;WAAA,IAAA8C,QAAAC,OAAA;WAAAC,OAAAF,aAClChB,KAAK7B,KAAK;WAAA,OAAA6C;UAAA,EAAA,CAAA,CAAA;SAAA;QAAA,CAAA;OAEpB,CAAA;MAAA,EAAA,CAAA;MAAAf,gBAGJlC,uBAAqB,CAAA,CAAA;MAAAkC,gBACrBpC,mBAAiB,EAAA,IAAAsC,WAAA;OAAA,OAAAF,gBACfnC,kBAAgB;QAAA,IACfS,WAAQ;SAAA,OAAEqB,MAAMd;QAAI;QACpBL,gBAAiBmB,MAAMf,gBAAgBe,MAAMZ,YAAY,IAAIY,MAAMb,WAAW;QAAE,IAAAoB,WAAA;SAAA,OAAA,CAAAF,gBAE/E1C,MAAI;UAAA,IAAC4D,OAAI;WAAA,OAAEvB,MAAMf;UAAa;UAAA,IAAEuC,WAAQ;WAAA,OAAAnB,gBAAGnD,OAAK,EAAA,eAAA,OAAA,CAAA;UAAA;UAAA,IAAAqD,WAAA;WAAA,OAAAF,gBAC9ClD,QAAM,EAAA,eAAA,OAAA,CAAA;UAAA;SAAA,CAAA,UAAA;UAAA,IAAAsE,OAAAJ,OAAA;UAAAC,OAAAG,YAEFzB,MAAMf,gBAAgB,aAAa,SAAS;UAAA,OAAAwC;SAAA,EAAA,CAAA,CAAA;QAAA;OAAA,CAAA;MAAA,EAAA,CAAA;KAAA;IAAA;GAAA,CAAA,CAAA;EAAA;CAAA,CAAA;AAM/D;;;;;AAMA,SAASN,mBAAmB7C,IAAyB;CACnD,MAAMoD,OAAOpC,eAAehB;CAC5B,OAAOoD,OAAIrB,gBAAIqB,MAAI,EAAA,eAAA,OAAA,CAAA,IAAyB;AAC9C"}
1
+ {"version":3,"file":"account-menu.js","names":["CircleHelp","Info","LogIn","LogOut","Megaphone","RefreshCw","Settings2","Smartphone","UserRound","ComponentProps","JSX","For","Show","createSignal","onCleanup","splitProps","cn","Button","ButtonProps","DropdownMenu","DropdownMenuContent","DropdownMenuGroup","DropdownMenuItem","DropdownMenuSeparator","DropdownMenuTrigger","Tooltip","TooltipContent","TooltipTrigger","AccountMenuItem","id","label","icon","Element","shortcut","disabled","platform","onSelect","onSelectAfterClose","trigger","HTMLButtonElement","AccountMenuProps","class","size","items","authenticated","busy","onSignIn","onSignOut","onIntent","FALLBACK_ICONS","Record","mobile","settings","about","help","feedback","updates","AccountMenu","props","local","rest","pendingAfterClose","callback","NonNullable","scheduledAfterClose","menuOpen","setMenuOpen","tooltipOpen","setTooltipOpen","undefined","visible","filter","item","_$createComponent","open","onOpenChange","children","modal","_$mergeProps","as","AccountMenuButton","ref","element","variant","aria-label","onFocus","onPointerEnter","placement","onCloseAutoFocus","event","selection","preventDefault","queueMicrotask","each","_$memo","renderFallbackIcon","_el$2","_tmpl$","_$insert","when","fallback","_el$","Icon","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/composites/account-menu/account-menu.tsx"],"sourcesContent":["import {\n CircleHelp,\n Info,\n LogIn,\n LogOut,\n Megaphone,\n RefreshCw,\n Settings2,\n Smartphone,\n UserRound,\n} from 'lucide-solid'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { For, Show, createSignal, onCleanup, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Button, type ButtonProps } from '../../ui/button/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../../ui/dropdown-menu/dropdown-menu'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip/tooltip'\n\n/**\n * AccountMenu.\n *\n * The trailing control in a rail or a top bar: the account, the way into settings,\n * and the way out. Every desktop application has one and they are all the same menu,\n * which is why it belongs here rather than being redrawn per app.\n *\n * ## The items are the caller's\n *\n * The menu takes a list rather than hard-coding one. An application adds and removes\n * entries — a mobile hand-off that only makes sense on desktop, a feedback link that\n * only exists once there is somewhere to send it — and a component that decided the\n * list could not be used by two products.\n *\n * `disabled` on an item is deliberately visible rather than hidden: a greyed \"Help\n * Center\" says the destination is coming, while an absent one says it does not exist.\n */\nexport type AccountMenuItem = {\n id: string\n label: string\n icon?: JSX.Element\n /** A chord drawn at the trailing edge, e.g. `⌘,`. */\n shortcut?: string\n disabled?: boolean\n /** Render only on this platform. Omit to always render. */\n platform?: 'desktop' | 'web'\n onSelect?: () => void\n /** Run after the menu's close-focus cycle, with its trigger as a stable opener. */\n onSelectAfterClose?: (trigger: HTMLButtonElement | undefined) => void\n}\n\nexport type AccountMenuProps = {\n class?: string\n /** The trigger size. Icon-only menus default to the standard icon size. */\n size?: ButtonProps['size']\n /** The entries above the separator. */\n items: readonly AccountMenuItem[]\n /** Which platform this is rendered on, for items that declare one. */\n platform?: 'desktop' | 'web'\n /** Whether a session exists. Decides the sign-in/sign-out row. */\n authenticated: boolean\n /** Disable the session row while a sign-in or sign-out is in flight. */\n busy?: boolean\n /** The name shown on the trigger's accessible label. */\n label?: string\n onSignIn?: () => void\n onSignOut?: () => void\n /** Fires on hover or focus of the trigger — a chance to prefetch. */\n onIntent?: () => void\n}\n\nconst FALLBACK_ICONS: Record<string, typeof Settings2> = {\n mobile: Smartphone,\n settings: Settings2,\n about: Info,\n help: CircleHelp,\n feedback: Megaphone,\n updates: RefreshCw,\n}\n\nexport function AccountMenu(props: AccountMenuProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'size',\n 'items',\n 'platform',\n 'authenticated',\n 'busy',\n 'label',\n 'onSignIn',\n 'onSignOut',\n 'onIntent',\n ])\n\n let trigger: HTMLButtonElement | undefined\n let pendingAfterClose:\n | { callback: NonNullable<AccountMenuItem['onSelectAfterClose']> }\n | undefined\n let scheduledAfterClose:\n | { callback: NonNullable<AccountMenuItem['onSelectAfterClose']> }\n | undefined\n const [menuOpen, setMenuOpen] = createSignal(false)\n const [tooltipOpen, setTooltipOpen] = createSignal(false)\n\n onCleanup(() => {\n pendingAfterClose = undefined\n scheduledAfterClose = undefined\n })\n\n const visible = () =>\n local.items.filter((item) => !item.platform || item.platform === (local.platform ?? 'desktop'))\n\n return (\n <Tooltip open={tooltipOpen()} onOpenChange={(open) => setTooltipOpen(open && !menuOpen())}>\n <DropdownMenu\n modal={false}\n onOpenChange={(open) => {\n setMenuOpen(open)\n if (open) setTooltipOpen(false)\n }}\n >\n <TooltipTrigger\n as={AccountMenuButton}\n ref={(element: HTMLButtonElement) => (trigger = element)}\n variant=\"ghost\"\n size={local.size ?? 'icon-md'}\n class={cn('text-muted-foreground', local.class)}\n aria-label={local.label ?? 'Account and settings'}\n onFocus={() => local.onIntent?.()}\n onPointerEnter={() => local.onIntent?.()}\n {...rest}\n >\n <UserRound aria-hidden=\"true\" />\n </TooltipTrigger>\n <TooltipContent placement=\"top\">{local.label ?? 'Account and settings'}</TooltipContent>\n <DropdownMenuContent\n placement=\"top-start\"\n class=\"min-w-56 max-h-(--kb-popper-available-height) overflow-x-hidden overflow-y-auto\"\n onCloseAutoFocus={(event) => {\n const selection = pendingAfterClose\n pendingAfterClose = undefined\n if (!selection) return\n\n event.preventDefault()\n scheduledAfterClose = selection\n queueMicrotask(() => {\n if (scheduledAfterClose !== selection) return\n scheduledAfterClose = undefined\n selection.callback(trigger)\n })\n }}\n >\n <DropdownMenuGroup>\n <For each={visible()}>\n {(item) => (\n <DropdownMenuItem\n disabled={item.disabled}\n onSelect={() => {\n pendingAfterClose = item.onSelectAfterClose\n ? { callback: item.onSelectAfterClose }\n : undefined\n item.onSelect?.()\n }}\n shortcut={item.shortcut}\n >\n {item.icon ?? renderFallbackIcon(item.id)}\n <span>{item.label}</span>\n </DropdownMenuItem>\n )}\n </For>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem\n disabled={local.busy}\n onSelect={() => (local.authenticated ? local.onSignOut?.() : local.onSignIn?.())}\n >\n <Show when={local.authenticated} fallback={<LogIn aria-hidden=\"true\" />}>\n <LogOut aria-hidden=\"true\" />\n </Show>\n <span>{local.authenticated ? 'Sign out' : 'Sign in'}</span>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </Tooltip>\n )\n}\n\nfunction AccountMenuButton(props: ComponentProps<typeof Button>) {\n return <DropdownMenuTrigger as={Button} {...props} />\n}\n\n/**\n * A known item id gets its conventional glyph, so a caller that only wants the\n * standard menu does not have to import six icons to get it.\n */\nfunction renderFallbackIcon(id: string): JSX.Element {\n const Icon = FALLBACK_ICONS[id]\n return Icon ? <Icon aria-hidden=\"true\" /> : null\n}\n"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type JSX, type ValidComponent } from 'solid-js';
2
+ import { type ButtonProps } from '../../ui/button';
3
+ /**
4
+ * ActionButton.
5
+ *
6
+ * A Button with optional explanatory tooltip and busy feedback. Use it for a
7
+ * simple action that needs these states; actions with product-specific rules
8
+ * should compose Button directly.
9
+ *
10
+ * The tooltip trigger renders the polymorphic Button itself. A disabled native
11
+ * control cannot receive pointer or keyboard events. When a tooltip is set,
12
+ * disabled actions therefore use focusable `aria-disabled` semantics and guard
13
+ * activation; without a tooltip, native buttons retain native disabling.
14
+ * Custom polymorphic components must forward aria, event, and href props for
15
+ * these guarantees to apply.
16
+ */
17
+ export type ActionButtonProps<T extends ValidComponent = 'button'> = ButtonProps<T> & {
18
+ /** A short explanation, also shown on keyboard focus. The Button still needs its own name. */
19
+ tooltip?: string;
20
+ tooltipSide?: 'top' | 'right' | 'bottom' | 'left';
21
+ /** Disables the action and announces the busy label through a polite status region. */
22
+ busy?: boolean;
23
+ /** The activity announced while busy. The Button's accessible name stays unchanged. */
24
+ busyLabel?: string;
25
+ };
26
+ export declare function ActionButton<T extends ValidComponent = 'button'>(props: ActionButtonProps<T>): JSX.Element;
27
+ //# sourceMappingURL=action-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-button.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/action-button/action-button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,GAAG,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AAC/F,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAI1D;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG;IACpF,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IACjD,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AA+BD,wBAAgB,YAAY,CAAC,CAAC,SAAS,cAAc,GAAG,QAAQ,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,eAgF5F"}
@@ -0,0 +1,121 @@
1
+ import { Button } from "../../ui/button/button.js";
2
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../../ui/tooltip/tooltip.js";
3
+ import { Spinner } from "../../ui/spinner/spinner.js";
4
+ import { createComponent, insert, memo, mergeProps, template } from "solid-js/web";
5
+ import { Show, splitProps } from "solid-js";
6
+ //#region src/components/composites/action-button/action-button.tsx
7
+ var _tmpl$ = /*#__PURE__*/ template(`<span role=status aria-live=polite class=visually-hidden>`);
8
+ function guardedClick(handler, disabled) {
9
+ return (event) => {
10
+ if (disabled()) {
11
+ event.preventDefault();
12
+ event.stopImmediatePropagation();
13
+ return;
14
+ }
15
+ if (Array.isArray(handler)) {
16
+ const [callback, data] = handler;
17
+ callback(data, event);
18
+ } else if (typeof handler === "function") handler(event);
19
+ };
20
+ }
21
+ /** Adapter keeps TooltipTrigger's `as` separate from Button's polymorphic `as`. */
22
+ function ButtonTarget(props) {
23
+ const [local, rest] = splitProps(props, ["actionAs"]);
24
+ return createComponent(Button, mergeProps({ get as() {
25
+ return local.actionAs ?? "button";
26
+ } }, rest));
27
+ }
28
+ function ActionButton(props) {
29
+ const [local, rest] = splitProps(props, [
30
+ "as",
31
+ "variant",
32
+ "size",
33
+ "class",
34
+ "children",
35
+ "disabled",
36
+ "aria-busy",
37
+ "tooltip",
38
+ "tooltipSide",
39
+ "busy",
40
+ "busyLabel"
41
+ ]);
42
+ const busy = () => local.busy ?? false;
43
+ const disabled = () => busy() || !!local.disabled;
44
+ const busyStatus = () => local.busyLabel ?? "Working";
45
+ const onClickCapture = rest.onClickCapture;
46
+ const PolymorphicButton = Button;
47
+ const PolymorphicButtonTarget = ButtonTarget;
48
+ const buttonProps = () => ({
49
+ ...rest,
50
+ variant: local.variant,
51
+ size: local.size,
52
+ class: [local.class, local.tooltip && disabled() && "aria-disabled:pointer-events-auto"].filter(Boolean).join(" "),
53
+ disabled: disabled() && !local.tooltip,
54
+ "aria-disabled": disabled() ? true : rest["aria-disabled"],
55
+ tabIndex: local.as === "a" && disabled() ? local.tooltip ? 0 : -1 : rest.tabIndex,
56
+ role: local.as === "a" && disabled() ? "link" : rest.role,
57
+ href: local.as === "a" && disabled() ? void 0 : rest.href,
58
+ "aria-busy": busy() || local["aria-busy"],
59
+ onClick: guardedClick(rest.onClick, disabled),
60
+ onClickCapture: onClickCapture ? guardedClick(onClickCapture, disabled) : void 0,
61
+ "on:click": guardedClick(rest["on:click"], disabled),
62
+ "oncapture:click": guardedClick(rest["oncapture:click"], disabled)
63
+ });
64
+ const contents = () => [createComponent(Show, {
65
+ get when() {
66
+ return busy();
67
+ },
68
+ get children() {
69
+ return createComponent(Spinner, {
70
+ size: "sm",
71
+ label: false,
72
+ "aria-hidden": "true",
73
+ "data-icon": "inline-start"
74
+ });
75
+ }
76
+ }), memo(() => local.children)];
77
+ return [createComponent(Show, {
78
+ get when() {
79
+ return local.tooltip;
80
+ },
81
+ get fallback() {
82
+ return createComponent(PolymorphicButton, mergeProps({ get as() {
83
+ return local.as ?? "button";
84
+ } }, () => buttonProps(), { get children() {
85
+ return contents();
86
+ } }));
87
+ },
88
+ get children() {
89
+ return createComponent(Tooltip, { get children() {
90
+ return [createComponent(TooltipTrigger, mergeProps({ as: PolymorphicButtonTarget }, () => buttonProps(), {
91
+ get actionAs() {
92
+ return local.as ?? "button";
93
+ },
94
+ get children() {
95
+ return contents();
96
+ }
97
+ })), createComponent(TooltipContent, {
98
+ get side() {
99
+ return local.tooltipSide;
100
+ },
101
+ get children() {
102
+ return local.tooltip;
103
+ }
104
+ })];
105
+ } });
106
+ }
107
+ }), createComponent(Show, {
108
+ get when() {
109
+ return busy();
110
+ },
111
+ get children() {
112
+ var _el$ = _tmpl$();
113
+ insert(_el$, busyStatus);
114
+ return _el$;
115
+ }
116
+ })];
117
+ }
118
+ //#endregion
119
+ export { ActionButton };
120
+
121
+ //# sourceMappingURL=action-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-button.js","names":["Show","splitProps","ComponentProps","JSX","ValidComponent","Button","ButtonProps","Spinner","Tooltip","TooltipContent","TooltipTrigger","ActionButtonProps","T","tooltip","tooltipSide","busy","busyLabel","guardedClick","handler","disabled","event","MouseEvent","preventDefault","stopImmediatePropagation","Array","isArray","callback","data","ButtonTargetProps","Omit","actionAs","ButtonTarget","props","local","rest","PolymorphicButton","targetProps","Element","_$createComponent","_$mergeProps","as","ActionButton","busyStatus","onClickCapture","buttonProps","PolymorphicButtonTarget","variant","size","class","filter","Boolean","join","tabIndex","role","href","undefined","onClick","Record","contents","when","children","label","_$memo","fallback","side","_el$","_tmpl$","_$insert","_$createComponent","PolymorphicButton","_$mergeProps","_$memo"],"sources":["../../../../src/components/composites/action-button/action-button.tsx"],"sourcesContent":["import { Show, splitProps, type ComponentProps, type JSX, type ValidComponent } from 'solid-js'\nimport { Button, type ButtonProps } from '../../ui/button'\nimport { Spinner } from '../../ui/spinner'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip'\n\n/**\n * ActionButton.\n *\n * A Button with optional explanatory tooltip and busy feedback. Use it for a\n * simple action that needs these states; actions with product-specific rules\n * should compose Button directly.\n *\n * The tooltip trigger renders the polymorphic Button itself. A disabled native\n * control cannot receive pointer or keyboard events. When a tooltip is set,\n * disabled actions therefore use focusable `aria-disabled` semantics and guard\n * activation; without a tooltip, native buttons retain native disabling.\n * Custom polymorphic components must forward aria, event, and href props for\n * these guarantees to apply.\n */\nexport type ActionButtonProps<T extends ValidComponent = 'button'> = ButtonProps<T> & {\n /** A short explanation, also shown on keyboard focus. The Button still needs its own name. */\n tooltip?: string\n tooltipSide?: 'top' | 'right' | 'bottom' | 'left'\n /** Disables the action and announces the busy label through a polite status region. */\n busy?: boolean\n /** The activity announced while busy. The Button's accessible name stays unchanged. */\n busyLabel?: string\n}\n\nfunction guardedClick(handler: unknown, disabled: () => boolean) {\n return (event: MouseEvent) => {\n if (disabled()) {\n event.preventDefault()\n event.stopImmediatePropagation()\n return\n }\n\n if (Array.isArray(handler)) {\n const [callback, data] = handler as [(data: unknown, event: MouseEvent) => void, unknown]\n callback(data, event)\n } else if (typeof handler === 'function') {\n const callback = handler as (event: MouseEvent) => void\n callback(event)\n }\n }\n}\n\ntype ButtonTargetProps<T extends ValidComponent = 'button'> = Omit<ButtonProps<T>, 'as'> & {\n actionAs?: T\n}\n\n/** Adapter keeps TooltipTrigger's `as` separate from Button's polymorphic `as`. */\nfunction ButtonTarget<T extends ValidComponent = 'button'>(props: ButtonTargetProps<T>) {\n const [local, rest] = splitProps(props as ButtonTargetProps, ['actionAs'])\n const PolymorphicButton = Button as (targetProps: ButtonProps<T>) => JSX.Element\n return <PolymorphicButton as={(local.actionAs ?? 'button') as T} {...(rest as ButtonProps<T>)} />\n}\n\nexport function ActionButton<T extends ValidComponent = 'button'>(props: ActionButtonProps<T>) {\n const [local, rest] = splitProps(props as ActionButtonProps, [\n 'as',\n 'variant',\n 'size',\n 'class',\n 'children',\n 'disabled',\n 'aria-busy',\n 'tooltip',\n 'tooltipSide',\n 'busy',\n 'busyLabel',\n ])\n const busy = () => local.busy ?? false\n const disabled = () => busy() || !!local.disabled\n const busyStatus = () => local.busyLabel ?? 'Working'\n const onClickCapture = (rest as { onClickCapture?: unknown }).onClickCapture\n const PolymorphicButton = Button as (buttonProps: ButtonProps<T>) => JSX.Element\n const PolymorphicButtonTarget = ButtonTarget as (targetProps: ButtonTargetProps<T>) => JSX.Element\n\n const buttonProps = () => ({\n ...rest,\n variant: local.variant,\n size: local.size,\n class: [local.class, local.tooltip && disabled() && 'aria-disabled:pointer-events-auto']\n .filter(Boolean)\n .join(' '),\n disabled: disabled() && !local.tooltip,\n 'aria-disabled': disabled() ? true : rest['aria-disabled'],\n tabIndex: local.as === 'a' && disabled() ? (local.tooltip ? 0 : -1) : rest.tabIndex,\n role: local.as === 'a' && disabled() ? 'link' : rest.role,\n href: local.as === 'a' && disabled() ? undefined : (rest as { href?: string }).href,\n 'aria-busy': busy() || local['aria-busy'],\n onClick: guardedClick(rest.onClick, disabled),\n onClickCapture: onClickCapture ? guardedClick(onClickCapture, disabled) : undefined,\n 'on:click': guardedClick((rest as Record<string, unknown>)['on:click'], disabled),\n 'oncapture:click': guardedClick((rest as Record<string, unknown>)['oncapture:click'], disabled),\n })\n\n const contents = () => (\n <>\n <Show when={busy()}>\n <Spinner size=\"sm\" label={false} aria-hidden=\"true\" data-icon=\"inline-start\" />\n </Show>\n {local.children}\n </>\n )\n\n return (\n <>\n <Show\n when={local.tooltip}\n fallback={\n <PolymorphicButton\n as={(local.as ?? 'button') as T}\n {...(buttonProps() as unknown as ButtonProps<T>)}\n >\n {contents()}\n </PolymorphicButton>\n }\n >\n <Tooltip>\n <TooltipTrigger\n as={PolymorphicButtonTarget}\n {...(buttonProps() as unknown as ComponentProps<typeof PolymorphicButtonTarget>)}\n actionAs={(local.as ?? 'button') as T}\n >\n {contents()}\n </TooltipTrigger>\n <TooltipContent side={local.tooltipSide}>{local.tooltip}</TooltipContent>\n </Tooltip>\n </Show>\n <Show when={busy()}>\n <span role=\"status\" aria-live=\"polite\" class=\"visually-hidden\">\n {busyStatus()}\n </span>\n </Show>\n </>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** A shared Button with optional tooltip and busy-state feedback. */
2
+ export { ActionButton, type ActionButtonProps } from './action-button';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/action-button/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,2 @@
1
+ import { ActionButton } from "./action-button.js";
2
+ export { ActionButton };
@@ -21,6 +21,8 @@ export type ThreadPanelProps = ComponentProps<'aside'> & {
21
21
  root?: JSX.Element;
22
22
  /** The composer for a reply. */
23
23
  composer?: JSX.Element;
24
+ /** Host actions, such as marking the thread unread, before the close control. */
25
+ headerActions?: JSX.Element;
24
26
  onClose?: () => void;
25
27
  };
26
28
  export declare function ThreadPanel(props: ThreadPanelProps): JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"thread-panel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/thread-panel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAKnD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG;IACvD,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAClB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eA6DlD;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mEAAmE;IACnE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACnB,CAAA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,eA4BxD"}
1
+ {"version":3,"file":"thread-panel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/thread-panel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAMnD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG;IACvD,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAClB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,iFAAiF;IACjF,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eAoElD;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mEAAmE;IACnE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACnB,CAAA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,eA4BxD"}