@k2b/ui 0.28.0 → 0.30.0

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 (278) hide show
  1. package/README.md +1 -1
  2. package/dist/base.css +2 -2
  3. package/dist/browser/actions/ContextMenu.js +5 -0
  4. package/dist/browser/actions/ContextMenu.js.map +1 -1
  5. package/dist/browser/actions/DragAndDrop.js +89 -0
  6. package/dist/browser/actions/DragAndDrop.js.map +1 -0
  7. package/dist/browser/actions/Dropdown.js +6 -3
  8. package/dist/browser/actions/Dropdown.js.map +1 -1
  9. package/dist/browser/actions/FilterChip.js +137 -7
  10. package/dist/browser/actions/FilterChip.js.map +1 -1
  11. package/dist/browser/actions/GestureMenu.js +26 -3
  12. package/dist/browser/actions/GestureMenu.js.map +1 -1
  13. package/dist/browser/actions/SegmentedControl.js +5 -9
  14. package/dist/browser/actions/SegmentedControl.js.map +1 -1
  15. package/dist/browser/actions/SpotlightSearch.js +6 -3
  16. package/dist/browser/actions/SpotlightSearch.js.map +1 -1
  17. package/dist/browser/actions/Tabs.js +5 -2
  18. package/dist/browser/actions/Tabs.js.map +1 -1
  19. package/dist/browser/actions/ViewTabs.js +294 -0
  20. package/dist/browser/actions/ViewTabs.js.map +1 -0
  21. package/dist/browser/actions/drag-and-drop-messages.js +75 -0
  22. package/dist/browser/actions/drag-and-drop-messages.js.map +1 -0
  23. package/dist/browser/actions/drag-and-drop.js +692 -0
  24. package/dist/browser/actions/drag-and-drop.js.map +1 -0
  25. package/dist/browser/actions/filter-messages.js +6 -2
  26. package/dist/browser/actions/filter-messages.js.map +1 -1
  27. package/dist/browser/actions/index.js +3 -1
  28. package/dist/browser/actions/index.js.map +1 -1
  29. package/dist/browser/chat/ChatComposer.js +1229 -605
  30. package/dist/browser/chat/ChatComposer.js.map +1 -1
  31. package/dist/browser/chat/ChatDecision.js +814 -0
  32. package/dist/browser/chat/ChatDecision.js.map +1 -0
  33. package/dist/browser/chat/ChatPrimitives.js +292 -153
  34. package/dist/browser/chat/ChatPrimitives.js.map +1 -1
  35. package/dist/browser/chat/ChatTimeline.js.map +1 -1
  36. package/dist/browser/chat/chat-messages.js +14 -0
  37. package/dist/browser/chat/chat-messages.js.map +1 -1
  38. package/dist/browser/chat/command-search.js +35 -17
  39. package/dist/browser/chat/command-search.js.map +1 -1
  40. package/dist/browser/chat/index.js +10 -3
  41. package/dist/browser/chat/index.js.map +1 -1
  42. package/dist/browser/chat/types.js.map +1 -1
  43. package/dist/browser/content/Calendar.js +146 -119
  44. package/dist/browser/content/Calendar.js.map +1 -1
  45. package/dist/browser/content/CalendarWeekView.js +291 -266
  46. package/dist/browser/content/CalendarWeekView.js.map +1 -1
  47. package/dist/browser/content/Chart.js +54 -71
  48. package/dist/browser/content/Chart.js.map +1 -1
  49. package/dist/browser/content/DataTable.js +224 -155
  50. package/dist/browser/content/DataTable.js.map +1 -1
  51. package/dist/browser/content/FileBrowser.js +2 -2
  52. package/dist/browser/content/FileBrowser.js.map +1 -1
  53. package/dist/browser/content/FileTree.js +42 -36
  54. package/dist/browser/content/FileTree.js.map +1 -1
  55. package/dist/browser/content/FileTypeIcon.js +72 -0
  56. package/dist/browser/content/FileTypeIcon.js.map +1 -0
  57. package/dist/browser/content/FileView.js +2 -2
  58. package/dist/browser/content/FileView.js.map +1 -1
  59. package/dist/browser/content/ReferenceChip.js +162 -0
  60. package/dist/browser/content/ReferenceChip.js.map +1 -0
  61. package/dist/browser/content/calendar-pointer.js +9 -0
  62. package/dist/browser/content/calendar-pointer.js.map +1 -1
  63. package/dist/browser/content/calendar-time-view.js +6 -3
  64. package/dist/browser/content/calendar-time-view.js.map +1 -1
  65. package/dist/browser/content/data-table-messages.js +4 -2
  66. package/dist/browser/content/data-table-messages.js.map +1 -1
  67. package/dist/browser/content/index.js +2 -0
  68. package/dist/browser/content/index.js.map +1 -1
  69. package/dist/browser/feedback/MovedHint.js +197 -0
  70. package/dist/browser/feedback/MovedHint.js.map +1 -0
  71. package/dist/browser/feedback/dialog-core.js +66 -9
  72. package/dist/browser/feedback/dialog-core.js.map +1 -1
  73. package/dist/browser/feedback/index.js +1 -0
  74. package/dist/browser/feedback/index.js.map +1 -1
  75. package/dist/browser/feedback/prompts.js +6 -1
  76. package/dist/browser/feedback/prompts.js.map +1 -1
  77. package/dist/browser/inputs/DatePicker.js +337 -212
  78. package/dist/browser/inputs/DatePicker.js.map +1 -1
  79. package/dist/browser/inputs/date-picker.js +59 -5
  80. package/dist/browser/inputs/date-picker.js.map +1 -1
  81. package/dist/browser/intl/messages.js +12 -0
  82. package/dist/browser/intl/messages.js.map +1 -1
  83. package/dist/browser/intl/weekend.js +39 -0
  84. package/dist/browser/intl/weekend.js.map +1 -0
  85. package/dist/browser/layout/AppOverview.js +1 -2
  86. package/dist/browser/layout/AppOverview.js.map +1 -1
  87. package/dist/browser/layout/AppWorkspace.js +947 -531
  88. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  89. package/dist/browser/layout/PageTitle.js +3 -2
  90. package/dist/browser/layout/PageTitle.js.map +1 -1
  91. package/dist/browser/layout/PanelDialog.js +88 -86
  92. package/dist/browser/layout/PanelDialog.js.map +1 -1
  93. package/dist/browser/layout/ResizeSeparator.js +81 -0
  94. package/dist/browser/layout/ResizeSeparator.js.map +1 -0
  95. package/dist/browser/layout/SettingsModal.js +2 -2
  96. package/dist/browser/layout/SettingsModal.js.map +1 -1
  97. package/dist/browser/layout/SidebarSwitcher.js +19 -11
  98. package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
  99. package/dist/browser/layout/TabBar.js +16 -13
  100. package/dist/browser/layout/TabBar.js.map +1 -1
  101. package/dist/browser/layout/app-host-width.js +44 -0
  102. package/dist/browser/layout/app-host-width.js.map +1 -0
  103. package/dist/browser/layout/app-workspace-controller.js +337 -44
  104. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  105. package/dist/browser/layout/index.js +4 -1
  106. package/dist/browser/layout/index.js.map +1 -1
  107. package/dist/browser/layout/resize-separator.js +90 -0
  108. package/dist/browser/layout/resize-separator.js.map +1 -0
  109. package/dist/browser/layout/workspace-messages.js +12 -2
  110. package/dist/browser/layout/workspace-messages.js.map +1 -1
  111. package/dist/browser/surfaces/LinkCard.js +1 -1
  112. package/dist/browser/surfaces/LinkCard.js.map +1 -1
  113. package/dist/browser/surfaces/Placeholder.js +45 -11
  114. package/dist/browser/surfaces/Placeholder.js.map +1 -1
  115. package/dist/browser/surfaces/StatCell.js +23 -0
  116. package/dist/browser/surfaces/StatCell.js.map +1 -1
  117. package/dist/browser/widgets/Widget.js +1 -1
  118. package/dist/browser/widgets/Widget.js.map +1 -1
  119. package/dist/ssr/actions/ContextMenu.js +5 -0
  120. package/dist/ssr/actions/ContextMenu.js.map +1 -1
  121. package/dist/ssr/actions/DragAndDrop.js +63 -0
  122. package/dist/ssr/actions/DragAndDrop.js.map +1 -0
  123. package/dist/ssr/actions/Dropdown.js +5 -2
  124. package/dist/ssr/actions/Dropdown.js.map +1 -1
  125. package/dist/ssr/actions/FilterChip.js +59 -7
  126. package/dist/ssr/actions/FilterChip.js.map +1 -1
  127. package/dist/ssr/actions/GestureMenu.js +26 -3
  128. package/dist/ssr/actions/GestureMenu.js.map +1 -1
  129. package/dist/ssr/actions/SegmentedControl.js +1 -2
  130. package/dist/ssr/actions/SegmentedControl.js.map +1 -1
  131. package/dist/ssr/actions/SpotlightSearch.js +2 -2
  132. package/dist/ssr/actions/SpotlightSearch.js.map +1 -1
  133. package/dist/ssr/actions/Tabs.js +2 -2
  134. package/dist/ssr/actions/Tabs.js.map +1 -1
  135. package/dist/ssr/actions/ViewTabs.js +211 -0
  136. package/dist/ssr/actions/ViewTabs.js.map +1 -0
  137. package/dist/ssr/actions/drag-and-drop-messages.js +75 -0
  138. package/dist/ssr/actions/drag-and-drop-messages.js.map +1 -0
  139. package/dist/ssr/actions/drag-and-drop.js +692 -0
  140. package/dist/ssr/actions/drag-and-drop.js.map +1 -0
  141. package/dist/ssr/actions/filter-messages.js +6 -2
  142. package/dist/ssr/actions/filter-messages.js.map +1 -1
  143. package/dist/ssr/actions/index.js +3 -1
  144. package/dist/ssr/actions/index.js.map +1 -1
  145. package/dist/ssr/chat/ChatComposer.js +668 -136
  146. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  147. package/dist/ssr/chat/ChatDecision.js +479 -0
  148. package/dist/ssr/chat/ChatDecision.js.map +1 -0
  149. package/dist/ssr/chat/ChatPrimitives.js +95 -24
  150. package/dist/ssr/chat/ChatPrimitives.js.map +1 -1
  151. package/dist/ssr/chat/ChatTimeline.js.map +1 -1
  152. package/dist/ssr/chat/chat-messages.js +14 -0
  153. package/dist/ssr/chat/chat-messages.js.map +1 -1
  154. package/dist/ssr/chat/command-search.js +35 -17
  155. package/dist/ssr/chat/command-search.js.map +1 -1
  156. package/dist/ssr/chat/index.js +10 -3
  157. package/dist/ssr/chat/index.js.map +1 -1
  158. package/dist/ssr/chat/types.js.map +1 -1
  159. package/dist/ssr/content/Calendar.js +112 -103
  160. package/dist/ssr/content/Calendar.js.map +1 -1
  161. package/dist/ssr/content/CalendarWeekView.js +42 -28
  162. package/dist/ssr/content/CalendarWeekView.js.map +1 -1
  163. package/dist/ssr/content/Chart.js +19 -23
  164. package/dist/ssr/content/Chart.js.map +1 -1
  165. package/dist/ssr/content/DataTable.js +78 -31
  166. package/dist/ssr/content/DataTable.js.map +1 -1
  167. package/dist/ssr/content/FileBrowser.js +2 -2
  168. package/dist/ssr/content/FileBrowser.js.map +1 -1
  169. package/dist/ssr/content/FileTree.js +21 -14
  170. package/dist/ssr/content/FileTree.js.map +1 -1
  171. package/dist/ssr/content/FileTypeIcon.js +50 -0
  172. package/dist/ssr/content/FileTypeIcon.js.map +1 -0
  173. package/dist/ssr/content/FileView.js +2 -2
  174. package/dist/ssr/content/FileView.js.map +1 -1
  175. package/dist/ssr/content/ReferenceChip.js +121 -0
  176. package/dist/ssr/content/ReferenceChip.js.map +1 -0
  177. package/dist/ssr/content/calendar-pointer.js +9 -0
  178. package/dist/ssr/content/calendar-pointer.js.map +1 -1
  179. package/dist/ssr/content/calendar-time-view.js +6 -3
  180. package/dist/ssr/content/calendar-time-view.js.map +1 -1
  181. package/dist/ssr/content/data-table-messages.js +4 -2
  182. package/dist/ssr/content/data-table-messages.js.map +1 -1
  183. package/dist/ssr/content/index.js +2 -0
  184. package/dist/ssr/content/index.js.map +1 -1
  185. package/dist/ssr/feedback/MovedHint.js +166 -0
  186. package/dist/ssr/feedback/MovedHint.js.map +1 -0
  187. package/dist/ssr/feedback/dialog-core.js +66 -9
  188. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  189. package/dist/ssr/feedback/index.js +1 -0
  190. package/dist/ssr/feedback/index.js.map +1 -1
  191. package/dist/ssr/feedback/prompts.js +6 -1
  192. package/dist/ssr/feedback/prompts.js.map +1 -1
  193. package/dist/ssr/inputs/DatePicker.js +138 -69
  194. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  195. package/dist/ssr/inputs/date-picker.js +59 -5
  196. package/dist/ssr/inputs/date-picker.js.map +1 -1
  197. package/dist/ssr/intl/messages.js +12 -0
  198. package/dist/ssr/intl/messages.js.map +1 -1
  199. package/dist/ssr/intl/weekend.js +39 -0
  200. package/dist/ssr/intl/weekend.js.map +1 -0
  201. package/dist/ssr/layout/AppOverview.js +1 -2
  202. package/dist/ssr/layout/AppOverview.js.map +1 -1
  203. package/dist/ssr/layout/AppWorkspace.js +457 -116
  204. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  205. package/dist/ssr/layout/PageTitle.js +3 -2
  206. package/dist/ssr/layout/PageTitle.js.map +1 -1
  207. package/dist/ssr/layout/PanelDialog.js +7 -6
  208. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  209. package/dist/ssr/layout/ResizeSeparator.js +45 -0
  210. package/dist/ssr/layout/ResizeSeparator.js.map +1 -0
  211. package/dist/ssr/layout/SettingsModal.js +2 -2
  212. package/dist/ssr/layout/SettingsModal.js.map +1 -1
  213. package/dist/ssr/layout/SidebarSwitcher.js +19 -11
  214. package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
  215. package/dist/ssr/layout/TabBar.js +2 -2
  216. package/dist/ssr/layout/TabBar.js.map +1 -1
  217. package/dist/ssr/layout/app-host-width.js +44 -0
  218. package/dist/ssr/layout/app-host-width.js.map +1 -0
  219. package/dist/ssr/layout/app-workspace-controller.js +337 -44
  220. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  221. package/dist/ssr/layout/index.js +4 -1
  222. package/dist/ssr/layout/index.js.map +1 -1
  223. package/dist/ssr/layout/resize-separator.js +90 -0
  224. package/dist/ssr/layout/resize-separator.js.map +1 -0
  225. package/dist/ssr/layout/workspace-messages.js +12 -2
  226. package/dist/ssr/layout/workspace-messages.js.map +1 -1
  227. package/dist/ssr/surfaces/LinkCard.js +1 -1
  228. package/dist/ssr/surfaces/LinkCard.js.map +1 -1
  229. package/dist/ssr/surfaces/Placeholder.js +25 -6
  230. package/dist/ssr/surfaces/Placeholder.js.map +1 -1
  231. package/dist/ssr/surfaces/StatCell.js +23 -0
  232. package/dist/ssr/surfaces/StatCell.js.map +1 -1
  233. package/dist/ssr/widgets/Widget.js +1 -1
  234. package/dist/ssr/widgets/Widget.js.map +1 -1
  235. package/dist/styles.css +1 -1
  236. package/dist/types/actions/ContextMenu.d.ts +1 -0
  237. package/dist/types/actions/DragAndDrop.d.ts +29 -0
  238. package/dist/types/actions/Dropdown.d.ts +4 -0
  239. package/dist/types/actions/FilterChip.d.ts +22 -0
  240. package/dist/types/actions/ViewTabs.d.ts +30 -0
  241. package/dist/types/actions/drag-and-drop-messages.d.ts +35 -0
  242. package/dist/types/actions/drag-and-drop.d.ts +36 -0
  243. package/dist/types/actions/filter-messages.d.ts +2 -0
  244. package/dist/types/actions/index.d.ts +6 -2
  245. package/dist/types/chat/ChatComposer.d.ts +71 -1
  246. package/dist/types/chat/ChatDecision.d.ts +149 -0
  247. package/dist/types/chat/ChatPrimitives.d.ts +14 -1
  248. package/dist/types/chat/ChatTimeline.d.ts +2 -1
  249. package/dist/types/chat/chat-messages.d.ts +7 -0
  250. package/dist/types/chat/command-search.d.ts +5 -0
  251. package/dist/types/chat/index.d.ts +28 -5
  252. package/dist/types/chat/types.d.ts +54 -1
  253. package/dist/types/content/Chart.d.ts +9 -3
  254. package/dist/types/content/DataTable.d.ts +3 -0
  255. package/dist/types/content/FileTypeIcon.d.ts +27 -0
  256. package/dist/types/content/ReferenceChip.d.ts +49 -0
  257. package/dist/types/content/calendar-pointer.d.ts +6 -0
  258. package/dist/types/content/data-table-messages.d.ts +1 -0
  259. package/dist/types/content/index.d.ts +3 -0
  260. package/dist/types/feedback/MovedHint.d.ts +25 -0
  261. package/dist/types/feedback/dialog-core.d.ts +5 -2
  262. package/dist/types/feedback/index.d.ts +2 -0
  263. package/dist/types/feedback/prompts.d.ts +2 -0
  264. package/dist/types/inputs/DatePicker.d.ts +7 -0
  265. package/dist/types/inputs/date-picker.d.ts +25 -1
  266. package/dist/types/intl/messages.d.ts +6 -0
  267. package/dist/types/intl/weekend.d.ts +12 -0
  268. package/dist/types/layout/AppWorkspace.d.ts +48 -10
  269. package/dist/types/layout/ResizeSeparator.d.ts +9 -0
  270. package/dist/types/layout/TabBar.d.ts +7 -0
  271. package/dist/types/layout/app-host-width.d.ts +6 -0
  272. package/dist/types/layout/app-workspace-controller.d.ts +2 -0
  273. package/dist/types/layout/index.d.ts +5 -2
  274. package/dist/types/layout/resize-separator.d.ts +18 -0
  275. package/dist/types/layout/workspace-messages.d.ts +5 -0
  276. package/dist/types/surfaces/Placeholder.d.ts +2 -1
  277. package/dist/types/surfaces/StatCell.d.ts +6 -0
  278. package/package.json +5 -5
@@ -1,4 +1,9 @@
1
1
  import { template as _$template } from "solid-js/web";
2
+ import { delegateEvents as _$delegateEvents } from "solid-js/web";
3
+ import { setProperty as _$setProperty } from "solid-js/web";
4
+ import { setAttribute as _$setAttribute } from "solid-js/web";
5
+ import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
6
+ import { setStyleProperty as _$setStyleProperty } from "solid-js/web";
2
7
  import { getNextMarker as _$getNextMarker } from "solid-js/web";
3
8
  import { insert as _$insert } from "solid-js/web";
4
9
  import { createComponent as _$createComponent } from "solid-js/web";
@@ -7,8 +12,13 @@ import { effect as _$effect } from "solid-js/web";
7
12
  import { getNextElement as _$getNextElement } from "solid-js/web";
8
13
  import { memo as _$memo } from "solid-js/web";
9
14
  var _tmpl$ = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
10
- _tmpl$2 = /*#__PURE__*/_$template(`<span><!$><!/><!$><!/>`),
11
- _tmpl$3 = /*#__PURE__*/_$template(`<i class="ti ti-chevron-down k2b-filter-chip__chevron"aria-hidden=true>`);
15
+ _tmpl$2 = /*#__PURE__*/_$template(`<span class=k2b-filter-chip__label><!$><!/><!$><!/>`),
16
+ _tmpl$3 = /*#__PURE__*/_$template(`<i class="ti ti-chevron-down k2b-filter-chip__chevron"aria-hidden=true>`),
17
+ _tmpl$4 = /*#__PURE__*/_$template(`<span class=k2b-filter-chip__value>: <!$><!/><!$><!/><!$><!/>`),
18
+ _tmpl$5 = /*#__PURE__*/_$template(`<span class=k2b-filter-chip__dot aria-hidden=true>`),
19
+ _tmpl$6 = /*#__PURE__*/_$template(`<span class=k2b-filter-chip__label>`),
20
+ _tmpl$7 = /*#__PURE__*/_$template(`<a>`),
21
+ _tmpl$8 = /*#__PURE__*/_$template(`<button type=button>`);
12
22
  import { createMemo, Show } from "solid-js";
13
23
  import { useUiMessages } from "../intl/messages";
14
24
  import Dropdown from "./Dropdown";
@@ -18,6 +28,7 @@ export function FilterChip(props) {
18
28
  const messages = useUiMessages();
19
29
  const filterMessages = useFilterMessages();
20
30
  const selectedValues = createMemo(() => new Set(props.value));
31
+ const selectedOptions = createMemo(() => props.options.flatMap(section => section.options).filter(option => selectedValues().has(option.value)));
21
32
  const defaultValues = createMemo(() => new Set(props.defaultValue ?? []));
22
33
  const sectionByValue = createMemo(() => {
23
34
  const sections = new Map();
@@ -29,6 +40,12 @@ export function FilterChip(props) {
29
40
  const hasDefault = () => (props.defaultValue?.length ?? 0) > 0;
30
41
  const selected = value => selectedValues().has(value);
31
42
  const active = () => props.isActive ?? props.value.length > 0;
43
+ const namedValue = () => props.showValue && !props.iconOnly && active() ? selectedOptions()[0] : undefined;
44
+ const triggerLabel = () => {
45
+ const first = namedValue();
46
+ if (!first) return props.label;
47
+ return `${props.label}: ${first.label}${props.value.length > 1 ? ` +${props.value.length - 1}` : ""}`;
48
+ };
32
49
  const atDefault = () => {
33
50
  if (!props.defaultValue) return false;
34
51
  const current = props.value;
@@ -122,7 +139,7 @@ export function FilterChip(props) {
122
139
  return props.iconOnly ? "true" : undefined;
123
140
  },
124
141
  get label() {
125
- return props.label;
142
+ return triggerLabel();
126
143
  },
127
144
  get children() {
128
145
  return [(() => {
@@ -143,11 +160,48 @@ export function FilterChip(props) {
143
160
  _$insert(_el$2, () => props.label, _el$4, _co$);
144
161
  _$insert(_el$2, _$createComponent(Show, {
145
162
  get when() {
146
- return _$memo(() => !!!hasDefault())() && props.value.length > 0;
163
+ return namedValue();
164
+ },
165
+ get fallback() {
166
+ return _$createComponent(Show, {
167
+ get when() {
168
+ return _$memo(() => !!!hasDefault())() && props.value.length > 0;
169
+ },
170
+ get children() {
171
+ return ` (${props.value.length})`;
172
+ }
173
+ });
147
174
  },
148
- get children() {
149
- return ` (${props.value.length})`;
150
- }
175
+ children: first => (() => {
176
+ var _el$8 = _$getNextElement(_tmpl$4),
177
+ _el$9 = _el$8.firstChild,
178
+ _el$1 = _el$9.nextSibling,
179
+ [_el$10, _co$3] = _$getNextMarker(_el$1.nextSibling),
180
+ _el$11 = _el$10.nextSibling,
181
+ [_el$12, _co$4] = _$getNextMarker(_el$11.nextSibling),
182
+ _el$13 = _el$12.nextSibling,
183
+ [_el$14, _co$5] = _$getNextMarker(_el$13.nextSibling);
184
+ _$insert(_el$8, _$createComponent(Show, {
185
+ get when() {
186
+ return first().color;
187
+ },
188
+ children: color => (() => {
189
+ var _el$15 = _$getNextElement(_tmpl$5);
190
+ _$effect(_$p => _$setStyleProperty(_el$15, "--k2b-filter-color", color()));
191
+ return _el$15;
192
+ })()
193
+ }), _el$10, _co$3);
194
+ _$insert(_el$8, () => first().label, _el$12, _co$4);
195
+ _$insert(_el$8, _$createComponent(Show, {
196
+ get when() {
197
+ return props.value.length > 1;
198
+ },
199
+ get children() {
200
+ return ` +${props.value.length - 1}`;
201
+ }
202
+ }), _el$14, _co$5);
203
+ return _el$8;
204
+ })()
151
205
  }), _el$6, _co$2);
152
206
  return _el$2;
153
207
  })(), _$getNextElement(_tmpl$3)];
@@ -159,4 +213,80 @@ export function FilterChip(props) {
159
213
  });
160
214
  }
161
215
  export default FilterChip;
216
+ /**
217
+ * One on/off filter in the chip look: a link marked `aria-current="true"` while active, or a button with
218
+ * `aria-pressed`. Selection changes only colour and background, so neighbouring chips never move.
219
+ */
220
+ export function FilterToggle(props) {
221
+ const content = () => [(() => {
222
+ var _el$16 = _$getNextElement(_tmpl$);
223
+ _$effect(() => _$className(_el$16, props.icon));
224
+ return _el$16;
225
+ })(), (() => {
226
+ var _el$17 = _$getNextElement(_tmpl$6);
227
+ _$insert(_el$17, () => props.label);
228
+ return _el$17;
229
+ })()];
230
+ const className = () => `k2b-filter-chip ${props.class ?? ""}`;
231
+ return _$createComponent(Show, {
232
+ get when() {
233
+ return _$memo(() => props.href !== undefined)() && !props.disabled;
234
+ },
235
+ get fallback() {
236
+ return (() => {
237
+ var _el$19 = _$getNextElement(_tmpl$8);
238
+ _el$19.$$click = event => props.onClick?.(event);
239
+ _$insert(_el$19, content);
240
+ _$effect(_p$ => {
241
+ var _v$6 = className(),
242
+ _v$7 = props.active ? "true" : undefined,
243
+ _v$8 = props.active,
244
+ _v$9 = props.title,
245
+ _v$0 = props.disabled;
246
+ _v$6 !== _p$.e && _$className(_el$19, _p$.e = _v$6);
247
+ _v$7 !== _p$.t && _$setAttribute(_el$19, "data-active", _p$.t = _v$7);
248
+ _v$8 !== _p$.a && _$setAttribute(_el$19, "aria-pressed", _p$.a = _v$8);
249
+ _v$9 !== _p$.o && _$setAttribute(_el$19, "title", _p$.o = _v$9);
250
+ _v$0 !== _p$.i && _$setProperty(_el$19, "disabled", _p$.i = _v$0);
251
+ return _p$;
252
+ }, {
253
+ e: undefined,
254
+ t: undefined,
255
+ a: undefined,
256
+ o: undefined,
257
+ i: undefined
258
+ });
259
+ _$runHydrationEvents();
260
+ return _el$19;
261
+ })();
262
+ },
263
+ get children() {
264
+ var _el$18 = _$getNextElement(_tmpl$7);
265
+ _el$18.$$click = event => props.onClick?.(event);
266
+ _$insert(_el$18, content);
267
+ _$effect(_p$ => {
268
+ var _v$ = className(),
269
+ _v$2 = props.href,
270
+ _v$3 = props.active ? "true" : undefined,
271
+ _v$4 = props.active ? "true" : undefined,
272
+ _v$5 = props.title;
273
+ _v$ !== _p$.e && _$className(_el$18, _p$.e = _v$);
274
+ _v$2 !== _p$.t && _$setAttribute(_el$18, "href", _p$.t = _v$2);
275
+ _v$3 !== _p$.a && _$setAttribute(_el$18, "data-active", _p$.a = _v$3);
276
+ _v$4 !== _p$.o && _$setAttribute(_el$18, "aria-current", _p$.o = _v$4);
277
+ _v$5 !== _p$.i && _$setAttribute(_el$18, "title", _p$.i = _v$5);
278
+ return _p$;
279
+ }, {
280
+ e: undefined,
281
+ t: undefined,
282
+ a: undefined,
283
+ o: undefined,
284
+ i: undefined
285
+ });
286
+ _$runHydrationEvents();
287
+ return _el$18;
288
+ }
289
+ });
290
+ }
291
+ _$delegateEvents(["click"]);
162
292
  //# sourceMappingURL=FilterChip.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/FilterChip.tsx"],"sourcesContent":["import { createMemo, type JSX, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { ButtonVariant } from \"./Button\";\nimport Dropdown, { type DropdownItem } from \"./Dropdown\";\nimport { useFilterMessages } from \"./filter-messages\";\n\nexport type FilterChipOption = {\n value: string;\n label: string;\n icon?: string;\n color?: string;\n};\n\nexport type FilterChipSection = {\n label?: string;\n options: readonly FilterChipOption[];\n multiple?: boolean;\n /**\n * `row` sets a few short single-select options side by side as one segmented row under its `label`. Selecting the\n * chosen option again keeps it; give the row a value in `defaultValue` so Reset keeps a choice too.\n */\n layout?: \"row\";\n};\n\nexport type FilterChipProps = {\n label: string;\n icon: string;\n options: readonly FilterChipSection[];\n value: readonly string[];\n onValueChange: (value: string[]) => void;\n isActive?: boolean;\n position?: \"bottom-left\" | \"bottom-right\";\n defaultValue?: readonly string[];\n iconOnly?: boolean;\n /** Use a standard button appearance instead of the default filter field. */\n variant?: ButtonVariant;\n disabled?: boolean;\n class?: string;\n};\n\n/** Section-aware controlled filter with immediate single- and multi-select commits. */\nexport function FilterChip(props: FilterChipProps): JSX.Element {\n const messages = useUiMessages();\n const filterMessages = useFilterMessages();\n const selectedValues = createMemo(() => new Set(props.value));\n const defaultValues = createMemo(() => new Set(props.defaultValue ?? []));\n const sectionByValue = createMemo(() => {\n const sections = new Map<string, FilterChipSection>();\n for (const section of props.options) {\n for (const option of section.options) sections.set(option.value, section);\n }\n return sections;\n });\n const hasDefault = () => (props.defaultValue?.length ?? 0) > 0;\n const selected = (value: string) => selectedValues().has(value);\n const active = () => props.isActive ?? props.value.length > 0;\n const atDefault = () => {\n if (!props.defaultValue) return false;\n const current = props.value;\n return current.length === props.defaultValue.length && current.every((value) => defaultValues().has(value));\n };\n const emit = (value: string[]) => props.onValueChange(value);\n const toggle = (value: string) => {\n const section = sectionByValue().get(value);\n if (!section) return;\n const current = props.value;\n if (section.multiple) {\n emit(selected(value) ? current.filter((entry) => entry !== value) : [...current, value]);\n return;\n }\n // A segmented row always keeps one choice, like a SegmentedControl.\n if (section.layout === \"row\" && selected(value)) return;\n const sectionValues = new Set(section.options.map((option) => option.value));\n const otherValues = current.filter((entry) => !sectionValues.has(entry));\n emit(selected(value) ? otherValues : [...otherValues, value]);\n };\n const reset = () => emit(props.defaultValue ? [...props.defaultValue] : []);\n const showReset = () => (hasDefault() && !atDefault()) || (!hasDefault() && props.value.length > 0);\n const optionItems = createMemo<DropdownItem[]>(() => {\n const result: DropdownItem[] = [];\n for (const section of props.options) {\n const items = section.options.map((option) => ({\n action: () => toggle(option.value),\n checked: () => props.value.includes(option.value),\n choice: section.multiple ? (\"checkbox\" as const) : (\"radio\" as const),\n class: \"k2b-filter-chip__option\",\n closeOnSelect: false,\n color: option.color,\n icon: !section.multiple ? option.icon : undefined,\n label: option.label,\n }));\n if (section.label || section.layout) result.push({ sectionLabel: section.label, layout: section.layout, items });\n else result.push(...items);\n }\n return result;\n });\n const items = createMemo<DropdownItem[]>(() => {\n if (!showReset()) return optionItems();\n return [\n ...optionItems(),\n {\n sectionLabel: filterMessages().filterActions,\n items: [\n {\n action: reset,\n icon: hasDefault() ? \"ti ti-refresh\" : \"ti ti-x\",\n label: hasDefault() ? messages().reset : messages().clear,\n variant: \"danger\",\n },\n ],\n },\n ];\n });\n\n return (\n <Dropdown.Root\n disabled={props.disabled}\n items={items()}\n position={props.position ?? \"bottom-left\"}\n menuClass=\"k2b-filter-chip__menu\"\n label={props.label}\n >\n <Dropdown.Trigger\n appearance={props.variant ? \"button\" : \"plain\"}\n variant={props.variant}\n iconOnly={props.iconOnly}\n class={props.variant ? props.class : `k2b-filter-chip ${props.class ?? \"\"}`}\n data-state={active() ? \"active\" : \"idle\"}\n data-active={active() ? \"true\" : undefined}\n data-icon-only={props.iconOnly ? \"true\" : undefined}\n label={props.label}\n >\n <i class={props.icon} aria-hidden=\"true\" />\n <Show when={!props.iconOnly}>\n <span>\n {props.label}\n <Show when={!hasDefault() && props.value.length > 0}>{` (${props.value.length})`}</Show>\n </span>\n <i class=\"ti ti-chevron-down k2b-filter-chip__chevron\" aria-hidden=\"true\" />\n </Show>\n </Dropdown.Trigger>\n </Dropdown.Root>\n );\n}\n\nexport default FilterChip;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/FilterChip.tsx"],"sourcesContent":["import { createMemo, type JSX, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { ButtonVariant } from \"./Button\";\nimport Dropdown, { type DropdownItem } from \"./Dropdown\";\nimport { useFilterMessages } from \"./filter-messages\";\n\nexport type FilterChipOption = {\n value: string;\n label: string;\n icon?: string;\n color?: string;\n};\n\nexport type FilterChipSection = {\n label?: string;\n options: readonly FilterChipOption[];\n multiple?: boolean;\n /**\n * `row` sets a few short single-select options side by side as one segmented row under its `label`. Selecting the\n * chosen option again keeps it; give the row a value in `defaultValue` so Reset keeps a choice too.\n */\n layout?: \"row\";\n};\n\nexport type FilterChipProps = {\n label: string;\n icon: string;\n options: readonly FilterChipSection[];\n value: readonly string[];\n onValueChange: (value: string[]) => void;\n isActive?: boolean;\n position?: \"bottom-left\" | \"bottom-right\";\n defaultValue?: readonly string[];\n iconOnly?: boolean;\n /** Use a standard button appearance instead of the default filter field. */\n variant?: ButtonVariant;\n /**\n * An active chip names its first value instead of a count: \"Tags: Customer\", \"Tags: Customer +2\". Use it for the\n * chips of `AppWorkspace.Head`; pass only the filter's name as `label`. The chip then grows with its value.\n */\n showValue?: boolean;\n disabled?: boolean;\n class?: string;\n};\n\n/** Section-aware controlled filter with immediate single- and multi-select commits. */\nexport function FilterChip(props: FilterChipProps): JSX.Element {\n const messages = useUiMessages();\n const filterMessages = useFilterMessages();\n const selectedValues = createMemo(() => new Set(props.value));\n const selectedOptions = createMemo(() =>\n props.options.flatMap((section) => section.options).filter((option) => selectedValues().has(option.value)),\n );\n const defaultValues = createMemo(() => new Set(props.defaultValue ?? []));\n const sectionByValue = createMemo(() => {\n const sections = new Map<string, FilterChipSection>();\n for (const section of props.options) {\n for (const option of section.options) sections.set(option.value, section);\n }\n return sections;\n });\n const hasDefault = () => (props.defaultValue?.length ?? 0) > 0;\n const selected = (value: string) => selectedValues().has(value);\n const active = () => props.isActive ?? props.value.length > 0;\n const namedValue = () => (props.showValue && !props.iconOnly && active() ? selectedOptions()[0] : undefined);\n const triggerLabel = () => {\n const first = namedValue();\n if (!first) return props.label;\n return `${props.label}: ${first.label}${props.value.length > 1 ? ` +${props.value.length - 1}` : \"\"}`;\n };\n const atDefault = () => {\n if (!props.defaultValue) return false;\n const current = props.value;\n return current.length === props.defaultValue.length && current.every((value) => defaultValues().has(value));\n };\n const emit = (value: string[]) => props.onValueChange(value);\n const toggle = (value: string) => {\n const section = sectionByValue().get(value);\n if (!section) return;\n const current = props.value;\n if (section.multiple) {\n emit(selected(value) ? current.filter((entry) => entry !== value) : [...current, value]);\n return;\n }\n // A segmented row always keeps one choice, like a SegmentedControl.\n if (section.layout === \"row\" && selected(value)) return;\n const sectionValues = new Set(section.options.map((option) => option.value));\n const otherValues = current.filter((entry) => !sectionValues.has(entry));\n emit(selected(value) ? otherValues : [...otherValues, value]);\n };\n const reset = () => emit(props.defaultValue ? [...props.defaultValue] : []);\n const showReset = () => (hasDefault() && !atDefault()) || (!hasDefault() && props.value.length > 0);\n const optionItems = createMemo<DropdownItem[]>(() => {\n const result: DropdownItem[] = [];\n for (const section of props.options) {\n const items = section.options.map((option) => ({\n action: () => toggle(option.value),\n checked: () => props.value.includes(option.value),\n choice: section.multiple ? (\"checkbox\" as const) : (\"radio\" as const),\n class: \"k2b-filter-chip__option\",\n closeOnSelect: false,\n color: option.color,\n icon: !section.multiple ? option.icon : undefined,\n label: option.label,\n }));\n if (section.label || section.layout) result.push({ sectionLabel: section.label, layout: section.layout, items });\n else result.push(...items);\n }\n return result;\n });\n const items = createMemo<DropdownItem[]>(() => {\n if (!showReset()) return optionItems();\n return [\n ...optionItems(),\n {\n sectionLabel: filterMessages().filterActions,\n items: [\n {\n action: reset,\n icon: hasDefault() ? \"ti ti-refresh\" : \"ti ti-x\",\n label: hasDefault() ? messages().reset : messages().clear,\n variant: \"danger\",\n },\n ],\n },\n ];\n });\n\n return (\n <Dropdown.Root\n disabled={props.disabled}\n items={items()}\n position={props.position ?? \"bottom-left\"}\n menuClass=\"k2b-filter-chip__menu\"\n label={props.label}\n >\n <Dropdown.Trigger\n appearance={props.variant ? \"button\" : \"plain\"}\n variant={props.variant}\n iconOnly={props.iconOnly}\n class={props.variant ? props.class : `k2b-filter-chip ${props.class ?? \"\"}`}\n data-state={active() ? \"active\" : \"idle\"}\n data-active={active() ? \"true\" : undefined}\n data-icon-only={props.iconOnly ? \"true\" : undefined}\n label={triggerLabel()}\n >\n <i class={props.icon} aria-hidden=\"true\" />\n <Show when={!props.iconOnly}>\n <span class=\"k2b-filter-chip__label\">\n {props.label}\n <Show when={namedValue()} fallback={<Show when={!hasDefault() && props.value.length > 0}>{` (${props.value.length})`}</Show>}>\n {(first) => (\n <span class=\"k2b-filter-chip__value\">\n :{\" \"}\n <Show when={first().color}>\n {(color) => <span class=\"k2b-filter-chip__dot\" style={{ \"--k2b-filter-color\": color() }} aria-hidden=\"true\" />}\n </Show>\n {first().label}\n <Show when={props.value.length > 1}>{` +${props.value.length - 1}`}</Show>\n </span>\n )}\n </Show>\n </span>\n <i class=\"ti ti-chevron-down k2b-filter-chip__chevron\" aria-hidden=\"true\" />\n </Show>\n </Dropdown.Trigger>\n </Dropdown.Root>\n );\n}\n\nexport default FilterChip;\n\nexport type FilterToggleProps = {\n label: JSX.Element;\n icon: string;\n /** Whether the filter is on. An active toggle carries the same tint as an active `FilterChip`. */\n active: boolean;\n /** Link to the URL with the filter switched. The link keeps working without JavaScript. */\n href?: string;\n onClick?: (event: MouseEvent) => void;\n title?: string;\n disabled?: boolean;\n class?: string;\n};\n\n/**\n * One on/off filter in the chip look: a link marked `aria-current=\"true\"` while active, or a button with\n * `aria-pressed`. Selection changes only colour and background, so neighbouring chips never move.\n */\nexport function FilterToggle(props: FilterToggleProps): JSX.Element {\n const content = () => (\n <>\n <i class={props.icon} aria-hidden=\"true\" />\n <span class=\"k2b-filter-chip__label\">{props.label}</span>\n </>\n );\n const className = () => `k2b-filter-chip ${props.class ?? \"\"}`;\n return (\n <Show\n when={props.href !== undefined && !props.disabled}\n fallback={\n <button\n type=\"button\"\n class={className()}\n data-active={props.active ? \"true\" : undefined}\n aria-pressed={props.active}\n title={props.title}\n disabled={props.disabled}\n onClick={(event) => props.onClick?.(event)}\n >\n {content()}\n </button>\n }\n >\n <a\n class={className()}\n href={props.href}\n data-active={props.active ? \"true\" : undefined}\n aria-current={props.active ? \"true\" : undefined}\n title={props.title}\n onClick={(event) => props.onClick?.(event)}\n >\n {content()}\n </a>\n </Show>\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -15,6 +15,7 @@ import { useLocale } from "../intl/locale";
15
15
  import { prefersReducedMotion } from "../motion";
16
16
  import { ContextMenuBase } from "./ContextMenu";
17
17
  import { DropdownItems } from "./Dropdown";
18
+ import { onPointerDragStart } from "./drag-and-drop";
18
19
  import { openMenuSheet } from "./menu-sheet";
19
20
 
20
21
  /** A finger held this long without moving opens the menu, as the platforms' own long press does. */
@@ -62,6 +63,8 @@ export function GestureMenu(props) {
62
63
  const [swipe, setSwipe] = createSignal();
63
64
  let surface;
64
65
  let openMenuAt;
66
+ let closeMenu;
67
+ let sheetController;
65
68
  let press;
66
69
  let lastTap;
67
70
  let lastPointer = "mouse";
@@ -101,6 +104,12 @@ export function GestureMenu(props) {
101
104
  const openSheet = () => {
102
105
  if (sheetOpen || !active()) return;
103
106
  sheetOpen = true;
107
+ const controller = new AbortController();
108
+ sheetController = controller;
109
+ const abortSheet = () => controller.abort();
110
+ disposed.signal.addEventListener("abort", abortSheet, {
111
+ once: true
112
+ });
104
113
  props.onOpen?.();
105
114
  void openMenuSheet({
106
115
  Items: DropdownItems,
@@ -108,9 +117,13 @@ export function GestureMenu(props) {
108
117
  label: props.label,
109
118
  locale: locale(),
110
119
  top: props.sheetTop,
111
- signal: disposed.signal
120
+ signal: controller.signal
112
121
  }).finally(() => {
113
- sheetOpen = false;
122
+ disposed.signal.removeEventListener("abort", abortSheet);
123
+ if (sheetController === controller) {
124
+ sheetController = undefined;
125
+ sheetOpen = false;
126
+ }
114
127
  });
115
128
  };
116
129
 
@@ -191,7 +204,7 @@ export function GestureMenu(props) {
191
204
  const onPointerMove = event => {
192
205
  const current = press;
193
206
  if (!current || event.pointerId !== current.id) return;
194
- // A later "hold, then drag" gesture takes over the pointer here.
207
+ // Hold-then-drag hands this press to DragSource through onPointerDragStart.
195
208
  if (current.long) return;
196
209
  const dx = event.clientX - current.x;
197
210
  const dy = event.clientY - current.y;
@@ -299,6 +312,14 @@ export function GestureMenu(props) {
299
312
  doubleTap.action();
300
313
  };
301
314
  onMount(() => {
315
+ const unsubscribeDrag = onPointerDragStart(pointerId => {
316
+ if (press?.id !== pointerId) return;
317
+ consumed = true;
318
+ lastTap = undefined;
319
+ closeMenu?.();
320
+ sheetController?.abort();
321
+ endPress();
322
+ });
302
323
  surface.addEventListener("pointerdown", onPointerDown);
303
324
  surface.addEventListener("pointermove", onPointerMove);
304
325
  surface.addEventListener("pointerup", onPointerUp);
@@ -314,6 +335,7 @@ export function GestureMenu(props) {
314
335
  surface.addEventListener("mousedown", onMouseDown);
315
336
  surface.addEventListener("dblclick", onDoubleClick);
316
337
  onCleanup(() => {
338
+ unsubscribeDrag();
317
339
  disposed.abort();
318
340
  endPress();
319
341
  clearTimeout(settleTimer);
@@ -331,6 +353,7 @@ export function GestureMenu(props) {
331
353
  });
332
354
  return _$createComponent(ContextMenuBase, {
333
355
  openAt: open => openMenuAt = open,
356
+ closeWith: close => closeMenu = close,
334
357
  get title() {
335
358
  return props.label;
336
359
  },
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/GestureMenu.tsx"],"sourcesContent":["import { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { useLocale } from \"../intl/locale\";\nimport { prefersReducedMotion } from \"../motion\";\nimport { ContextMenuBase } from \"./ContextMenu\";\nimport { type DropdownAction, type DropdownActionBase, type DropdownChoice, DropdownItems, type DropdownSection } from \"./Dropdown\";\nimport { openMenuSheet } from \"./menu-sheet\";\n\n/** A finger held this long without moving opens the menu, as the platforms' own long press does. */\nconst LONG_PRESS_MS = 500;\n/** A second tap that starts this soon after the first ended makes a double tap. */\nconst DOUBLE_TAP_MS = 300;\n/** The second tap lands at most this far from the first. */\nconst DOUBLE_TAP_DISTANCE = 32;\n/** Movement up to this is still a tap or a long press. */\nconst SLOP = 10;\n/** A swipe must be this many times wider than tall; anything steeper belongs to the page's scrolling. */\nconst SWIPE_RATIO = 1.5;\n/** Travel at which a released swipe runs its action. */\nconst SWIPE_THRESHOLD = 64;\n/** The content follows the finger up to the threshold, then at a quarter of its travel, up to this. */\nconst SWIPE_MAX = 96;\nconst SWIPE_RESISTANCE = 0.25;\n/** Swipes do not start this close to the screen's side edges, where the system's back and forward gestures are. */\nconst EDGE = 20;\n/** Duration of the snap back in `.k2b-gesture-menu[data-settling]`. */\nconst SETTLE_MS = 160;\n\n/**\n * Gestures never start on these elements: links, controls, fields, code blocks, and anything marked\n * `data-gesture-ignore` keep their own touch and mouse behavior.\n */\nconst IGNORE = [\n \"a[href]\",\n \"button\",\n \"input\",\n \"textarea\",\n \"select\",\n \"summary\",\n \"label\",\n \"audio\",\n \"video\",\n \"pre\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[role='button']\",\n \"[role='link']\",\n \"[role='checkbox']\",\n \"[role='switch']\",\n \"[role='slider']\",\n \"[role='tab']\",\n \"[role^='menuitem']\",\n \"[data-gesture-ignore]\",\n].join(\", \");\n\nexport type GestureKind = \"swipe-right\" | \"swipe-left\" | \"double-tap\";\n\n/** A menu action that a gesture runs as well. */\nexport type GestureMenuAction = DropdownActionBase & {\n action: () => void;\n /** The gesture that runs this action. Give each gesture to at most one item; a disabled item disables its gesture. */\n gesture?: GestureKind;\n};\n\nexport type GestureMenuSection = Omit<DropdownSection, \"items\"> & {\n items: readonly (GestureMenuAction | DropdownAction | DropdownChoice)[];\n};\n\nexport type GestureMenuItem = GestureMenuAction | DropdownAction | DropdownChoice | GestureMenuSection;\n\nexport type GestureMenuProps = {\n /**\n * The menu. A long press opens a BottomSheet below 48rem and the same menu at the finger from 48rem.\n * Right-click opens it at the pointer; the Context Menu key and Shift+F10 open it beside the focused element.\n * An item with `gesture` is also run by that gesture, so every gesture has its entry here.\n */\n items: readonly GestureMenuItem[];\n /** Names the element and its menu, for example \"Message from Nora, 10:42\". */\n label: string;\n children: JSX.Element;\n /** Shown only above the menu in the phone sheet, for example a row of quick reactions. `close` closes the sheet. */\n sheetTop?: (close: () => void) => JSX.Element;\n /** Tab order of the element. A list that moves focus between its rows itself passes -1. */\n tabIndex?: number;\n /** Runs before the menu or the sheet shows its items, for example to select what was pressed. */\n onOpen?: () => void;\n class?: string;\n};\n\ntype SwipeDirection = \"right\" | \"left\";\n\ntype Swipe = {\n direction: SwipeDirection;\n icon?: string;\n /** How far the content is moved, in pixels; always 0 with reduced motion. */\n offset: number;\n /** Travel relative to the threshold, from 0 to 1. */\n progress: number;\n armed: boolean;\n settling: boolean;\n};\n\ntype Press = {\n id: number;\n x: number;\n y: number;\n timer?: ReturnType<typeof setTimeout>;\n /** The finger left the slop: no tap or long press any more. */\n moved: boolean;\n /** The long press opened the menu or the sheet. */\n long: boolean;\n /** The press started soon after a tap nearby. */\n second: boolean;\n /** The press started at a side edge of the screen. */\n edge: boolean;\n direction?: SwipeDirection;\n};\n\nconst gestureAction = (items: readonly GestureMenuItem[], kind: GestureKind): GestureMenuAction | undefined => {\n for (const item of items)\n for (const entry of \"items\" in item ? item.items : [item])\n if (\"gesture\" in entry && entry.gesture === kind) return entry.disabled ? undefined : entry;\n return undefined;\n};\n\nconst swipeKind = (direction: SwipeDirection): GestureKind => (direction === \"right\" ? \"swipe-right\" : \"swipe-left\");\n\n/**\n * Touch gestures for an element, each the shortcut of an entry in its menu: a horizontal swipe, a double tap, and a\n * long press that opens a `BottomSheet` below 48rem and the same menu at the finger from 48rem. A mouse double-click\n * runs the double-tap action; right-click opens the menu at the pointer, the keyboard beside the focused element.\n * Vertical scrolling never turns into a swipe.\n */\nexport function GestureMenu(props: GestureMenuProps): JSX.Element {\n const locale = useLocale();\n const [swipe, setSwipe] = createSignal<Swipe>();\n let surface!: HTMLDivElement;\n let openMenuAt: ((x: number, y: number) => void) | undefined;\n let press: Press | undefined;\n let lastTap: { x: number; y: number; at: number } | undefined;\n let lastPointer = \"mouse\";\n /**\n * The touch or pen press that just ended did something: its `touchend` is cancelled, so no click or mouse events\n * follow, and a pen's click, which comes without touch events, is cancelled itself.\n */\n let consumed = false;\n let sheetOpen = false;\n /** Closes an open sheet when the element goes, for example when its message is deleted. */\n const disposed = new AbortController();\n let reduced = false;\n let settleTimer: ReturnType<typeof setTimeout> | undefined;\n\n const active = () => props.items.length > 0;\n const wide = () => window.matchMedia?.(\"(min-width: 48rem)\").matches ?? false;\n /**\n * A modal dialog makes everything outside it inert, also ContextMenu's menu on the body, so inside one the hold\n * keeps the sheet, which opens on the same dialog stack. An engine without `:modal` gets the sheet too.\n */\n const inModal = () => {\n const dialog = surface.closest(\"dialog[open]\");\n if (!dialog) return false;\n try {\n return dialog.matches(\":modal\");\n } catch {\n return true;\n }\n };\n const action = (kind: GestureKind) => gestureAction(props.items, kind);\n const touchAction = () => (action(\"swipe-right\") || action(\"swipe-left\") ? \"swipe\" : action(\"double-tap\") ? \"tap\" : undefined);\n\n /** Whether the event started on something with a meaning of its own, inside this element. */\n const ignored = (target: EventTarget | null) => {\n const found = target instanceof Element ? target.closest(IGNORE) : null;\n return found !== null && found !== surface && surface.contains(found);\n };\n\n const openSheet = () => {\n if (sheetOpen || !active()) return;\n sheetOpen = true;\n props.onOpen?.();\n void openMenuSheet({\n Items: DropdownItems,\n items: props.items,\n label: props.label,\n locale: locale(),\n top: props.sheetTop,\n signal: disposed.signal,\n }).finally(() => {\n sheetOpen = false;\n });\n };\n\n /** Another pointer that goes down anywhere while a finger presses, as in a pinch, ends the gesture. */\n const onOtherPointer = (event: PointerEvent) => {\n if (!press || event.pointerId === press.id) return;\n if (press.direction) settle();\n endPress();\n };\n\n const endPress = () => {\n clearTimeout(press?.timer);\n press = undefined;\n document.removeEventListener(\"pointerdown\", onOtherPointer, true);\n delete surface.dataset.pressing;\n };\n\n const settle = () => {\n const current = swipe();\n if (!current) return;\n clearTimeout(settleTimer);\n if (reduced || current.offset === 0) {\n setSwipe(undefined);\n return;\n }\n setSwipe({ ...current, offset: 0, progress: 0, armed: false, settling: true });\n settleTimer = setTimeout(() => setSwipe(undefined), SETTLE_MS);\n };\n\n const moveSwipe = (current: Press, direction: SwipeDirection, dx: number) => {\n const travel = Math.max(0, direction === \"right\" ? dx : -dx);\n const moved = travel <= SWIPE_THRESHOLD ? travel : SWIPE_THRESHOLD + (travel - SWIPE_THRESHOLD) * SWIPE_RESISTANCE;\n const offset = reduced ? 0 : Math.min(SWIPE_MAX, moved) * (direction === \"right\" ? 1 : -1);\n current.direction = direction;\n setSwipe({\n direction,\n icon: action(swipeKind(direction))?.icon,\n offset,\n progress: Math.min(1, travel / SWIPE_THRESHOLD),\n armed: travel >= SWIPE_THRESHOLD,\n settling: false,\n });\n };\n\n const longPress = () => {\n if (!press) return;\n press.long = true;\n lastTap = undefined;\n if (wide() && !inModal()) openMenuAt?.(press.x, press.y);\n else openSheet();\n };\n\n const onPointerDown = (event: PointerEvent) => {\n lastPointer = event.pointerType;\n consumed = false;\n // Any press in between, on a link, with a mouse, or with another finger, ends a pending double tap.\n const previous = lastTap;\n lastTap = undefined;\n // Another finger ends the gesture through `onOtherPointer` and starts none.\n if (event.pointerType === \"mouse\" || !event.isPrimary) return;\n endPress();\n if (!active() || ignored(event.target)) return;\n const second =\n previous !== undefined &&\n performance.now() - previous.at <= DOUBLE_TAP_MS &&\n Math.hypot(event.clientX - previous.x, event.clientY - previous.y) <= DOUBLE_TAP_DISTANCE;\n press = {\n id: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n moved: false,\n long: false,\n second,\n edge: event.clientX < EDGE || event.clientX > window.innerWidth - EDGE,\n timer: setTimeout(longPress, LONG_PRESS_MS),\n };\n document.addEventListener(\"pointerdown\", onOtherPointer, true);\n // Hybrid devices keep text selection for the mouse; a finger on the element selects nothing.\n surface.dataset.pressing = \"\";\n };\n\n const onPointerMove = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n // A later \"hold, then drag\" gesture takes over the pointer here.\n if (current.long) return;\n const dx = event.clientX - current.x;\n const dy = event.clientY - current.y;\n if (current.direction) {\n moveSwipe(current, current.direction, dx);\n return;\n }\n if (current.moved || Math.hypot(dx, dy) < SLOP) return;\n current.moved = true;\n clearTimeout(current.timer);\n if (current.edge || Math.abs(dx) < Math.abs(dy) * SWIPE_RATIO) return;\n const direction: SwipeDirection = dx > 0 ? \"right\" : \"left\";\n if (!action(swipeKind(direction))) return;\n clearTimeout(settleTimer);\n reduced = prefersReducedMotion();\n moveSwipe(current, direction, dx);\n };\n\n const onPointerUp = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n endPress();\n if (current.long) {\n consumed = true;\n return;\n }\n if (current.direction) {\n // Where the finger lifts decides, and the item as it is now.\n moveSwipe(current, current.direction, event.clientX - current.x);\n const swipeAction = swipe()?.armed ? action(swipeKind(current.direction)) : undefined;\n settle();\n if (swipeAction) {\n consumed = true;\n swipeAction.action();\n }\n return;\n }\n if (current.moved) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n if (current.second) {\n consumed = true;\n doubleTap.action();\n return;\n }\n lastTap = { x: event.clientX, y: event.clientY, at: performance.now() };\n };\n\n // The browser took the touch, for example to scroll the page.\n const onPointerCancel = (event: PointerEvent) => {\n if (!press || event.pointerId !== press.id) return;\n if (press.direction) settle();\n endPress();\n lastTap = undefined;\n };\n\n // Once the hold opens the menu or sheet, further movement must not scroll the page underneath it.\n const onTouchMove = (event: TouchEvent) => {\n if (press?.long && event.cancelable) event.preventDefault();\n };\n\n const onTouchEnd = (event: TouchEvent) => {\n if (!consumed) return;\n consumed = false;\n if (event.cancelable) event.preventDefault();\n };\n\n // A pen sends no touch events; the click after its gesture is cancelled here. A keyboard's click has no detail.\n const onClick = (event: MouseEvent) => {\n if (!consumed || event.detail === 0) return;\n consumed = false;\n event.preventDefault();\n event.stopPropagation();\n };\n\n const onContextMenu = (event: MouseEvent) => {\n // Without items the element has no menu, and the browser keeps its own.\n if (!active()) return;\n // Links, fields, and code keep the browser's own menu.\n if (ignored(event.target)) {\n event.stopPropagation();\n return;\n }\n // A mouse or the keyboard opens the menu beside the element through ContextMenu.\n if (!press && !(\"pointerType\" in event && (event.pointerType === \"touch\" || event.pointerType === \"pen\"))) return;\n // Android and touch screens report a long press as a context-menu event, sometimes before the timer.\n event.preventDefault();\n event.stopPropagation();\n if (press && !press.long && !press.moved) {\n clearTimeout(press.timer);\n longPress();\n }\n };\n\n // The second press of a mouse double-click would select a word; in this element it runs the double-tap action.\n const onMouseDown = (event: MouseEvent) => {\n if (event.button === 0 && event.detail >= 2 && lastPointer === \"mouse\" && action(\"double-tap\") && !ignored(event.target))\n event.preventDefault();\n };\n\n const onDoubleClick = (event: MouseEvent) => {\n if (lastPointer !== \"mouse\" || ignored(event.target)) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n event.preventDefault();\n doubleTap.action();\n };\n\n onMount(() => {\n surface.addEventListener(\"pointerdown\", onPointerDown);\n surface.addEventListener(\"pointermove\", onPointerMove);\n surface.addEventListener(\"pointerup\", onPointerUp);\n surface.addEventListener(\"pointercancel\", onPointerCancel);\n surface.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n surface.addEventListener(\"touchend\", onTouchEnd, { passive: false });\n surface.addEventListener(\"click\", onClick, true);\n surface.addEventListener(\"contextmenu\", onContextMenu);\n surface.addEventListener(\"mousedown\", onMouseDown);\n surface.addEventListener(\"dblclick\", onDoubleClick);\n onCleanup(() => {\n disposed.abort();\n endPress();\n clearTimeout(settleTimer);\n surface.removeEventListener(\"pointerdown\", onPointerDown);\n surface.removeEventListener(\"pointermove\", onPointerMove);\n surface.removeEventListener(\"pointerup\", onPointerUp);\n surface.removeEventListener(\"pointercancel\", onPointerCancel);\n surface.removeEventListener(\"touchmove\", onTouchMove);\n surface.removeEventListener(\"touchend\", onTouchEnd);\n surface.removeEventListener(\"click\", onClick, true);\n surface.removeEventListener(\"contextmenu\", onContextMenu);\n surface.removeEventListener(\"mousedown\", onMouseDown);\n surface.removeEventListener(\"dblclick\", onDoubleClick);\n });\n });\n\n return (\n <ContextMenuBase\n openAt={(open) => (openMenuAt = open)}\n title={props.label}\n items={props.items}\n label={props.label}\n tabIndex={props.tabIndex}\n disabled={!active()}\n onOpen={props.onOpen}\n class={props.class}\n >\n <div\n ref={surface}\n class=\"k2b-gesture-menu\"\n data-active={active() ? \"\" : undefined}\n data-touch={touchAction()}\n data-swipe={swipe()?.direction}\n data-armed={swipe()?.armed ? \"\" : undefined}\n data-settling={swipe()?.settling ? \"\" : undefined}\n style={{\n \"--k2b-gesture-menu-offset\": `${swipe()?.offset ?? 0}px`,\n \"--k2b-gesture-menu-progress\": String(swipe()?.progress ?? 0),\n }}\n >\n <Show when={swipe()}>\n {(current) => (\n <span class=\"k2b-gesture-menu__swipe\" aria-hidden=\"true\">\n <i class={current().icon ?? (current().direction === \"right\" ? \"ti ti-arrow-right\" : \"ti ti-arrow-left\")} />\n </span>\n )}\n </Show>\n <div class=\"k2b-gesture-menu__content\">{props.children}</div>\n </div>\n </ContextMenuBase>\n );\n}\n\nexport default GestureMenu;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/GestureMenu.tsx"],"sourcesContent":["import { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { useLocale } from \"../intl/locale\";\nimport { prefersReducedMotion } from \"../motion\";\nimport { ContextMenuBase } from \"./ContextMenu\";\nimport { type DropdownAction, type DropdownActionBase, type DropdownChoice, DropdownItems, type DropdownSection } from \"./Dropdown\";\nimport { onPointerDragStart } from \"./drag-and-drop\";\nimport { openMenuSheet } from \"./menu-sheet\";\n\n/** A finger held this long without moving opens the menu, as the platforms' own long press does. */\nconst LONG_PRESS_MS = 500;\n/** A second tap that starts this soon after the first ended makes a double tap. */\nconst DOUBLE_TAP_MS = 300;\n/** The second tap lands at most this far from the first. */\nconst DOUBLE_TAP_DISTANCE = 32;\n/** Movement up to this is still a tap or a long press. */\nconst SLOP = 10;\n/** A swipe must be this many times wider than tall; anything steeper belongs to the page's scrolling. */\nconst SWIPE_RATIO = 1.5;\n/** Travel at which a released swipe runs its action. */\nconst SWIPE_THRESHOLD = 64;\n/** The content follows the finger up to the threshold, then at a quarter of its travel, up to this. */\nconst SWIPE_MAX = 96;\nconst SWIPE_RESISTANCE = 0.25;\n/** Swipes do not start this close to the screen's side edges, where the system's back and forward gestures are. */\nconst EDGE = 20;\n/** Duration of the snap back in `.k2b-gesture-menu[data-settling]`. */\nconst SETTLE_MS = 160;\n\n/**\n * Gestures never start on these elements: links, controls, fields, code blocks, and anything marked\n * `data-gesture-ignore` keep their own touch and mouse behavior.\n */\nconst IGNORE = [\n \"a[href]\",\n \"button\",\n \"input\",\n \"textarea\",\n \"select\",\n \"summary\",\n \"label\",\n \"audio\",\n \"video\",\n \"pre\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[role='button']\",\n \"[role='link']\",\n \"[role='checkbox']\",\n \"[role='switch']\",\n \"[role='slider']\",\n \"[role='tab']\",\n \"[role^='menuitem']\",\n \"[data-gesture-ignore]\",\n].join(\", \");\n\nexport type GestureKind = \"swipe-right\" | \"swipe-left\" | \"double-tap\";\n\n/** A menu action that a gesture runs as well. */\nexport type GestureMenuAction = DropdownActionBase & {\n action: () => void;\n /** The gesture that runs this action. Give each gesture to at most one item; a disabled item disables its gesture. */\n gesture?: GestureKind;\n};\n\nexport type GestureMenuSection = Omit<DropdownSection, \"items\"> & {\n items: readonly (GestureMenuAction | DropdownAction | DropdownChoice)[];\n};\n\nexport type GestureMenuItem = GestureMenuAction | DropdownAction | DropdownChoice | GestureMenuSection;\n\nexport type GestureMenuProps = {\n /**\n * The menu. A long press opens a BottomSheet below 48rem and the same menu at the finger from 48rem.\n * Right-click opens it at the pointer; the Context Menu key and Shift+F10 open it beside the focused element.\n * An item with `gesture` is also run by that gesture, so every gesture has its entry here.\n */\n items: readonly GestureMenuItem[];\n /** Names the element and its menu, for example \"Message from Nora, 10:42\". */\n label: string;\n children: JSX.Element;\n /** Shown only above the menu in the phone sheet, for example a row of quick reactions. `close` closes the sheet. */\n sheetTop?: (close: () => void) => JSX.Element;\n /** Tab order of the element. A list that moves focus between its rows itself passes -1. */\n tabIndex?: number;\n /** Runs before the menu or the sheet shows its items, for example to select what was pressed. */\n onOpen?: () => void;\n class?: string;\n};\n\ntype SwipeDirection = \"right\" | \"left\";\n\ntype Swipe = {\n direction: SwipeDirection;\n icon?: string;\n /** How far the content is moved, in pixels; always 0 with reduced motion. */\n offset: number;\n /** Travel relative to the threshold, from 0 to 1. */\n progress: number;\n armed: boolean;\n settling: boolean;\n};\n\ntype Press = {\n id: number;\n x: number;\n y: number;\n timer?: ReturnType<typeof setTimeout>;\n /** The finger left the slop: no tap or long press any more. */\n moved: boolean;\n /** The long press opened the menu or the sheet. */\n long: boolean;\n /** The press started soon after a tap nearby. */\n second: boolean;\n /** The press started at a side edge of the screen. */\n edge: boolean;\n direction?: SwipeDirection;\n};\n\nconst gestureAction = (items: readonly GestureMenuItem[], kind: GestureKind): GestureMenuAction | undefined => {\n for (const item of items)\n for (const entry of \"items\" in item ? item.items : [item])\n if (\"gesture\" in entry && entry.gesture === kind) return entry.disabled ? undefined : entry;\n return undefined;\n};\n\nconst swipeKind = (direction: SwipeDirection): GestureKind => (direction === \"right\" ? \"swipe-right\" : \"swipe-left\");\n\n/**\n * Touch gestures for an element, each the shortcut of an entry in its menu: a horizontal swipe, a double tap, and a\n * long press that opens a `BottomSheet` below 48rem and the same menu at the finger from 48rem. A mouse double-click\n * runs the double-tap action; right-click opens the menu at the pointer, the keyboard beside the focused element.\n * Vertical scrolling never turns into a swipe.\n */\nexport function GestureMenu(props: GestureMenuProps): JSX.Element {\n const locale = useLocale();\n const [swipe, setSwipe] = createSignal<Swipe>();\n let surface!: HTMLDivElement;\n let openMenuAt: ((x: number, y: number) => void) | undefined;\n let closeMenu: (() => void) | undefined;\n let sheetController: AbortController | undefined;\n let press: Press | undefined;\n let lastTap: { x: number; y: number; at: number } | undefined;\n let lastPointer = \"mouse\";\n /**\n * The touch or pen press that just ended did something: its `touchend` is cancelled, so no click or mouse events\n * follow, and a pen's click, which comes without touch events, is cancelled itself.\n */\n let consumed = false;\n let sheetOpen = false;\n /** Closes an open sheet when the element goes, for example when its message is deleted. */\n const disposed = new AbortController();\n let reduced = false;\n let settleTimer: ReturnType<typeof setTimeout> | undefined;\n\n const active = () => props.items.length > 0;\n const wide = () => window.matchMedia?.(\"(min-width: 48rem)\").matches ?? false;\n /**\n * A modal dialog makes everything outside it inert, also ContextMenu's menu on the body, so inside one the hold\n * keeps the sheet, which opens on the same dialog stack. An engine without `:modal` gets the sheet too.\n */\n const inModal = () => {\n const dialog = surface.closest(\"dialog[open]\");\n if (!dialog) return false;\n try {\n return dialog.matches(\":modal\");\n } catch {\n return true;\n }\n };\n const action = (kind: GestureKind) => gestureAction(props.items, kind);\n const touchAction = () => (action(\"swipe-right\") || action(\"swipe-left\") ? \"swipe\" : action(\"double-tap\") ? \"tap\" : undefined);\n\n /** Whether the event started on something with a meaning of its own, inside this element. */\n const ignored = (target: EventTarget | null) => {\n const found = target instanceof Element ? target.closest(IGNORE) : null;\n return found !== null && found !== surface && surface.contains(found);\n };\n\n const openSheet = () => {\n if (sheetOpen || !active()) return;\n sheetOpen = true;\n const controller = new AbortController();\n sheetController = controller;\n const abortSheet = () => controller.abort();\n disposed.signal.addEventListener(\"abort\", abortSheet, { once: true });\n props.onOpen?.();\n void openMenuSheet({\n Items: DropdownItems,\n items: props.items,\n label: props.label,\n locale: locale(),\n top: props.sheetTop,\n signal: controller.signal,\n }).finally(() => {\n disposed.signal.removeEventListener(\"abort\", abortSheet);\n if (sheetController === controller) {\n sheetController = undefined;\n sheetOpen = false;\n }\n });\n };\n\n /** Another pointer that goes down anywhere while a finger presses, as in a pinch, ends the gesture. */\n const onOtherPointer = (event: PointerEvent) => {\n if (!press || event.pointerId === press.id) return;\n if (press.direction) settle();\n endPress();\n };\n\n const endPress = () => {\n clearTimeout(press?.timer);\n press = undefined;\n document.removeEventListener(\"pointerdown\", onOtherPointer, true);\n delete surface.dataset.pressing;\n };\n\n const settle = () => {\n const current = swipe();\n if (!current) return;\n clearTimeout(settleTimer);\n if (reduced || current.offset === 0) {\n setSwipe(undefined);\n return;\n }\n setSwipe({ ...current, offset: 0, progress: 0, armed: false, settling: true });\n settleTimer = setTimeout(() => setSwipe(undefined), SETTLE_MS);\n };\n\n const moveSwipe = (current: Press, direction: SwipeDirection, dx: number) => {\n const travel = Math.max(0, direction === \"right\" ? dx : -dx);\n const moved = travel <= SWIPE_THRESHOLD ? travel : SWIPE_THRESHOLD + (travel - SWIPE_THRESHOLD) * SWIPE_RESISTANCE;\n const offset = reduced ? 0 : Math.min(SWIPE_MAX, moved) * (direction === \"right\" ? 1 : -1);\n current.direction = direction;\n setSwipe({\n direction,\n icon: action(swipeKind(direction))?.icon,\n offset,\n progress: Math.min(1, travel / SWIPE_THRESHOLD),\n armed: travel >= SWIPE_THRESHOLD,\n settling: false,\n });\n };\n\n const longPress = () => {\n if (!press) return;\n press.long = true;\n lastTap = undefined;\n if (wide() && !inModal()) openMenuAt?.(press.x, press.y);\n else openSheet();\n };\n\n const onPointerDown = (event: PointerEvent) => {\n lastPointer = event.pointerType;\n consumed = false;\n // Any press in between, on a link, with a mouse, or with another finger, ends a pending double tap.\n const previous = lastTap;\n lastTap = undefined;\n // Another finger ends the gesture through `onOtherPointer` and starts none.\n if (event.pointerType === \"mouse\" || !event.isPrimary) return;\n endPress();\n if (!active() || ignored(event.target)) return;\n const second =\n previous !== undefined &&\n performance.now() - previous.at <= DOUBLE_TAP_MS &&\n Math.hypot(event.clientX - previous.x, event.clientY - previous.y) <= DOUBLE_TAP_DISTANCE;\n press = {\n id: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n moved: false,\n long: false,\n second,\n edge: event.clientX < EDGE || event.clientX > window.innerWidth - EDGE,\n timer: setTimeout(longPress, LONG_PRESS_MS),\n };\n document.addEventListener(\"pointerdown\", onOtherPointer, true);\n // Hybrid devices keep text selection for the mouse; a finger on the element selects nothing.\n surface.dataset.pressing = \"\";\n };\n\n const onPointerMove = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n // Hold-then-drag hands this press to DragSource through onPointerDragStart.\n if (current.long) return;\n const dx = event.clientX - current.x;\n const dy = event.clientY - current.y;\n if (current.direction) {\n moveSwipe(current, current.direction, dx);\n return;\n }\n if (current.moved || Math.hypot(dx, dy) < SLOP) return;\n current.moved = true;\n clearTimeout(current.timer);\n if (current.edge || Math.abs(dx) < Math.abs(dy) * SWIPE_RATIO) return;\n const direction: SwipeDirection = dx > 0 ? \"right\" : \"left\";\n if (!action(swipeKind(direction))) return;\n clearTimeout(settleTimer);\n reduced = prefersReducedMotion();\n moveSwipe(current, direction, dx);\n };\n\n const onPointerUp = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n endPress();\n if (current.long) {\n consumed = true;\n return;\n }\n if (current.direction) {\n // Where the finger lifts decides, and the item as it is now.\n moveSwipe(current, current.direction, event.clientX - current.x);\n const swipeAction = swipe()?.armed ? action(swipeKind(current.direction)) : undefined;\n settle();\n if (swipeAction) {\n consumed = true;\n swipeAction.action();\n }\n return;\n }\n if (current.moved) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n if (current.second) {\n consumed = true;\n doubleTap.action();\n return;\n }\n lastTap = { x: event.clientX, y: event.clientY, at: performance.now() };\n };\n\n // The browser took the touch, for example to scroll the page.\n const onPointerCancel = (event: PointerEvent) => {\n if (!press || event.pointerId !== press.id) return;\n if (press.direction) settle();\n endPress();\n lastTap = undefined;\n };\n\n // Once the hold opens the menu or sheet, further movement must not scroll the page underneath it.\n const onTouchMove = (event: TouchEvent) => {\n if (press?.long && event.cancelable) event.preventDefault();\n };\n\n const onTouchEnd = (event: TouchEvent) => {\n if (!consumed) return;\n consumed = false;\n if (event.cancelable) event.preventDefault();\n };\n\n // A pen sends no touch events; the click after its gesture is cancelled here. A keyboard's click has no detail.\n const onClick = (event: MouseEvent) => {\n if (!consumed || event.detail === 0) return;\n consumed = false;\n event.preventDefault();\n event.stopPropagation();\n };\n\n const onContextMenu = (event: MouseEvent) => {\n // Without items the element has no menu, and the browser keeps its own.\n if (!active()) return;\n // Links, fields, and code keep the browser's own menu.\n if (ignored(event.target)) {\n event.stopPropagation();\n return;\n }\n // A mouse or the keyboard opens the menu beside the element through ContextMenu.\n if (!press && !(\"pointerType\" in event && (event.pointerType === \"touch\" || event.pointerType === \"pen\"))) return;\n // Android and touch screens report a long press as a context-menu event, sometimes before the timer.\n event.preventDefault();\n event.stopPropagation();\n if (press && !press.long && !press.moved) {\n clearTimeout(press.timer);\n longPress();\n }\n };\n\n // The second press of a mouse double-click would select a word; in this element it runs the double-tap action.\n const onMouseDown = (event: MouseEvent) => {\n if (event.button === 0 && event.detail >= 2 && lastPointer === \"mouse\" && action(\"double-tap\") && !ignored(event.target))\n event.preventDefault();\n };\n\n const onDoubleClick = (event: MouseEvent) => {\n if (lastPointer !== \"mouse\" || ignored(event.target)) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n event.preventDefault();\n doubleTap.action();\n };\n\n onMount(() => {\n const unsubscribeDrag = onPointerDragStart((pointerId) => {\n if (press?.id !== pointerId) return;\n consumed = true;\n lastTap = undefined;\n closeMenu?.();\n sheetController?.abort();\n endPress();\n });\n surface.addEventListener(\"pointerdown\", onPointerDown);\n surface.addEventListener(\"pointermove\", onPointerMove);\n surface.addEventListener(\"pointerup\", onPointerUp);\n surface.addEventListener(\"pointercancel\", onPointerCancel);\n surface.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n surface.addEventListener(\"touchend\", onTouchEnd, { passive: false });\n surface.addEventListener(\"click\", onClick, true);\n surface.addEventListener(\"contextmenu\", onContextMenu);\n surface.addEventListener(\"mousedown\", onMouseDown);\n surface.addEventListener(\"dblclick\", onDoubleClick);\n onCleanup(() => {\n unsubscribeDrag();\n disposed.abort();\n endPress();\n clearTimeout(settleTimer);\n surface.removeEventListener(\"pointerdown\", onPointerDown);\n surface.removeEventListener(\"pointermove\", onPointerMove);\n surface.removeEventListener(\"pointerup\", onPointerUp);\n surface.removeEventListener(\"pointercancel\", onPointerCancel);\n surface.removeEventListener(\"touchmove\", onTouchMove);\n surface.removeEventListener(\"touchend\", onTouchEnd);\n surface.removeEventListener(\"click\", onClick, true);\n surface.removeEventListener(\"contextmenu\", onContextMenu);\n surface.removeEventListener(\"mousedown\", onMouseDown);\n surface.removeEventListener(\"dblclick\", onDoubleClick);\n });\n });\n\n return (\n <ContextMenuBase\n openAt={(open) => (openMenuAt = open)}\n closeWith={(close) => (closeMenu = close)}\n title={props.label}\n items={props.items}\n label={props.label}\n tabIndex={props.tabIndex}\n disabled={!active()}\n onOpen={props.onOpen}\n class={props.class}\n >\n <div\n ref={surface}\n class=\"k2b-gesture-menu\"\n data-active={active() ? \"\" : undefined}\n data-touch={touchAction()}\n data-swipe={swipe()?.direction}\n data-armed={swipe()?.armed ? \"\" : undefined}\n data-settling={swipe()?.settling ? \"\" : undefined}\n style={{\n \"--k2b-gesture-menu-offset\": `${swipe()?.offset ?? 0}px`,\n \"--k2b-gesture-menu-progress\": String(swipe()?.progress ?? 0),\n }}\n >\n <Show when={swipe()}>\n {(current) => (\n <span class=\"k2b-gesture-menu__swipe\" aria-hidden=\"true\">\n <i class={current().icon ?? (current().direction === \"right\" ? \"ti ti-arrow-right\" : \"ti ti-arrow-left\")} />\n </span>\n )}\n </Show>\n <div class=\"k2b-gesture-menu__content\">{props.children}</div>\n </div>\n </ContextMenuBase>\n );\n}\n\nexport default GestureMenu;\n"],"mappings":"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","ignoreList":[]}
@@ -54,7 +54,6 @@ export function SegmentedControl(props) {
54
54
  if (currentValue() === value) return 0;
55
55
  return !selectedEnabled() && enabled()[0]?.index === index ? 0 : -1;
56
56
  };
57
- const divider = (index, value) => index < props.options.length - 1 && currentValue() !== value && currentValue() !== props.options[index + 1]?.value;
58
57
  return (() => {
59
58
  var _el$ = _$getNextElement(_tmpl$);
60
59
  _$insert(_el$, _$createComponent(For, {
@@ -94,21 +93,18 @@ export function SegmentedControl(props) {
94
93
  _$effect(_p$ => {
95
94
  var _v$5 = currentValue() === option.value,
96
95
  _v$6 = currentValue() === option.value ? "true" : undefined,
97
- _v$7 = divider(index(), option.value) ? "true" : undefined,
98
- _v$8 = props.disabled || option.disabled,
99
- _v$9 = tabIndex(index(), option.value);
96
+ _v$7 = props.disabled || option.disabled,
97
+ _v$8 = tabIndex(index(), option.value);
100
98
  _v$5 !== _p$.e && _$setAttribute(_el$2, "aria-checked", _p$.e = _v$5);
101
99
  _v$6 !== _p$.t && _$setAttribute(_el$2, "data-selected", _p$.t = _v$6);
102
- _v$7 !== _p$.a && _$setAttribute(_el$2, "data-divider", _p$.a = _v$7);
103
- _v$8 !== _p$.o && _$setProperty(_el$2, "disabled", _p$.o = _v$8);
104
- _v$9 !== _p$.i && _$setAttribute(_el$2, "tabindex", _p$.i = _v$9);
100
+ _v$7 !== _p$.a && _$setProperty(_el$2, "disabled", _p$.a = _v$7);
101
+ _v$8 !== _p$.o && _$setAttribute(_el$2, "tabindex", _p$.o = _v$8);
105
102
  return _p$;
106
103
  }, {
107
104
  e: undefined,
108
105
  t: undefined,
109
106
  a: undefined,
110
- o: undefined,
111
- i: undefined
107
+ o: undefined
112
108
  });
113
109
  _$runHydrationEvents();
114
110
  return _el$2;
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/SegmentedControl.tsx"],"sourcesContent":["import { createMemo, For, type JSX } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type SegmentOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n};\n\nexport type SegmentedControlProps<T extends string = string> = {\n options: readonly SegmentOption<T>[];\n value: T | (() => T);\n onValueChange: (value: T) => void;\n disabled?: boolean;\n ariaLabel?: string;\n label?: string;\n size?: \"sm\" | \"md\";\n class?: string;\n};\n\n/** Controlled radio group with automatic selection during arrow-key navigation. */\nexport function SegmentedControl<T extends string = string>(props: SegmentedControlProps<T>): JSX.Element {\n const messages = useUiMessages();\n const buttons: HTMLButtonElement[] = [];\n const currentValue = createMemo<T>(() => (typeof props.value === \"function\" ? props.value() : props.value));\n const enabled = createMemo(() =>\n props.options.map((option, index) => ({ option, index })).filter(({ option }) => !props.disabled && !option.disabled),\n );\n const selectedEnabled = createMemo(() =>\n props.options.some((option) => option.value === currentValue() && !props.disabled && !option.disabled),\n );\n const emit = (value: T) => props.onValueChange(value);\n const select = (index: number) => {\n const option = props.options[index];\n if (!option || props.disabled || option.disabled) return;\n emit(option.value);\n queueMicrotask(() => buttons[index]?.focus());\n };\n const selectRelative = (currentIndex: number, direction: 1 | -1) => {\n const available = enabled();\n if (available.length === 0) return;\n const current = available.findIndex(({ index }) => index === currentIndex);\n const next = available[(current + direction + available.length) % available.length] ?? available[0];\n if (next) select(next.index);\n };\n const edge = (last: boolean) => {\n const available = enabled();\n const next = last ? available.at(-1) : available[0];\n if (next) select(next.index);\n };\n const tabIndex = (index: number, value: T) => {\n if (props.disabled || props.options[index]?.disabled) return -1;\n if (currentValue() === value) return 0;\n return !selectedEnabled() && enabled()[0]?.index === index ? 0 : -1;\n };\n const divider = (index: number, value: T) =>\n index < props.options.length - 1 && currentValue() !== value && currentValue() !== props.options[index + 1]?.value;\n\n return (\n <div\n class={`k2b-segmented-control ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n role=\"radiogroup\"\n aria-label={props.ariaLabel ?? props.label ?? messages().options}\n aria-orientation=\"horizontal\"\n aria-disabled={props.disabled ? \"true\" : undefined}\n >\n <For each={props.options}>\n {(option, index) => (\n <button\n ref={(element) => {\n buttons[index()] = element;\n }}\n type=\"button\"\n role=\"radio\"\n class=\"k2b-segmented-control__option\"\n aria-checked={currentValue() === option.value}\n data-selected={currentValue() === option.value ? \"true\" : undefined}\n data-divider={divider(index(), option.value) ? \"true\" : undefined}\n disabled={props.disabled || option.disabled}\n tabIndex={tabIndex(index(), option.value)}\n onClick={() => emit(option.value)}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n selectRelative(index(), 1);\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n selectRelative(index(), -1);\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n edge(event.key === \"End\");\n }\n }}\n >\n {option.icon && <i class={option.icon} aria-hidden=\"true\" />}\n <span>{option.label}</span>\n </button>\n )}\n </For>\n </div>\n );\n}\n\nexport default SegmentedControl;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/SegmentedControl.tsx"],"sourcesContent":["import { createMemo, For, type JSX } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type SegmentOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n};\n\nexport type SegmentedControlProps<T extends string = string> = {\n options: readonly SegmentOption<T>[];\n value: T | (() => T);\n onValueChange: (value: T) => void;\n disabled?: boolean;\n ariaLabel?: string;\n label?: string;\n size?: \"sm\" | \"md\";\n class?: string;\n};\n\n/** Controlled radio group with automatic selection during arrow-key navigation. */\nexport function SegmentedControl<T extends string = string>(props: SegmentedControlProps<T>): JSX.Element {\n const messages = useUiMessages();\n const buttons: HTMLButtonElement[] = [];\n const currentValue = createMemo<T>(() => (typeof props.value === \"function\" ? props.value() : props.value));\n const enabled = createMemo(() =>\n props.options.map((option, index) => ({ option, index })).filter(({ option }) => !props.disabled && !option.disabled),\n );\n const selectedEnabled = createMemo(() =>\n props.options.some((option) => option.value === currentValue() && !props.disabled && !option.disabled),\n );\n const emit = (value: T) => props.onValueChange(value);\n const select = (index: number) => {\n const option = props.options[index];\n if (!option || props.disabled || option.disabled) return;\n emit(option.value);\n queueMicrotask(() => buttons[index]?.focus());\n };\n const selectRelative = (currentIndex: number, direction: 1 | -1) => {\n const available = enabled();\n if (available.length === 0) return;\n const current = available.findIndex(({ index }) => index === currentIndex);\n const next = available[(current + direction + available.length) % available.length] ?? available[0];\n if (next) select(next.index);\n };\n const edge = (last: boolean) => {\n const available = enabled();\n const next = last ? available.at(-1) : available[0];\n if (next) select(next.index);\n };\n const tabIndex = (index: number, value: T) => {\n if (props.disabled || props.options[index]?.disabled) return -1;\n if (currentValue() === value) return 0;\n return !selectedEnabled() && enabled()[0]?.index === index ? 0 : -1;\n };\n\n return (\n <div\n class={`k2b-segmented-control ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n role=\"radiogroup\"\n aria-label={props.ariaLabel ?? props.label ?? messages().options}\n aria-orientation=\"horizontal\"\n aria-disabled={props.disabled ? \"true\" : undefined}\n >\n <For each={props.options}>\n {(option, index) => (\n <button\n ref={(element) => {\n buttons[index()] = element;\n }}\n type=\"button\"\n role=\"radio\"\n class=\"k2b-segmented-control__option\"\n aria-checked={currentValue() === option.value}\n data-selected={currentValue() === option.value ? \"true\" : undefined}\n disabled={props.disabled || option.disabled}\n tabIndex={tabIndex(index(), option.value)}\n onClick={() => emit(option.value)}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n selectRelative(index(), 1);\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n selectRelative(index(), -1);\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n edge(event.key === \"End\");\n }\n }}\n >\n {option.icon && <i class={option.icon} aria-hidden=\"true\" />}\n <span>{option.label}</span>\n </button>\n )}\n </For>\n </div>\n );\n}\n\nexport default SegmentedControl;\n"],"mappings":"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","ignoreList":[]}
@@ -10,7 +10,7 @@ import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
10
10
  import { getNextMarker as _$getNextMarker } from "solid-js/web";
11
11
  import { memo as _$memo } from "solid-js/web";
12
12
  import { insert as _$insert } from "solid-js/web";
13
- var _tmpl$ = /*#__PURE__*/_$template(`<button type=button><i aria-hidden=true></i><span class=k2b-spotlight-button__label></span><!$><!/>`),
13
+ var _tmpl$ = /*#__PURE__*/_$template(`<button type=button><i aria-hidden=true></i><span></span><!$><!/>`),
14
14
  _tmpl$2 = /*#__PURE__*/_$template(`<kbd class=k2b-kbd><kbd class=k2b-kbd__key>`);
15
15
  import { Kbd } from "../content/Kbd";
16
16
  import { prompts } from "../feedback/prompts";
@@ -67,13 +67,15 @@ export function SpotlightButton(props) {
67
67
  _v$3 = props.disabled,
68
68
  _v$4 = props.ariaLabel ?? (["compact", "icon"].includes(variant()) ? label() : undefined),
69
69
  _v$5 = title(),
70
- _v$6 = icon();
70
+ _v$6 = icon(),
71
+ _v$7 = variant() === "sidebar" ? "k2b-spotlight-button__label k2b-truncate-fade" : "k2b-spotlight-button__label";
71
72
  _v$ !== _p$.e && _$className(_el$, _p$.e = _v$);
72
73
  _v$2 !== _p$.t && _$setAttribute(_el$, "data-variant", _p$.t = _v$2);
73
74
  _v$3 !== _p$.a && _$setProperty(_el$, "disabled", _p$.a = _v$3);
74
75
  _v$4 !== _p$.o && _$setAttribute(_el$, "aria-label", _p$.o = _v$4);
75
76
  _v$5 !== _p$.i && _$setAttribute(_el$, "title", _p$.i = _v$5);
76
77
  _v$6 !== _p$.n && _$className(_el$2, _p$.n = _v$6);
78
+ _v$7 !== _p$.s && _$className(_el$3, _p$.s = _v$7);
77
79
  return _p$;
78
80
  }, {
79
81
  e: undefined,
@@ -81,7 +83,8 @@ export function SpotlightButton(props) {
81
83
  a: undefined,
82
84
  o: undefined,
83
85
  i: undefined,
84
- n: undefined
86
+ n: undefined,
87
+ s: undefined
85
88
  });
86
89
  _$runHydrationEvents();
87
90
  return _el$;
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/SpotlightSearch.tsx"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { Kbd } from \"../content/Kbd\";\nimport type { PromptSearchInput, PromptSearchItem, PromptSearchOptions } from \"../feedback/prompts\";\nimport { prompts } from \"../feedback/prompts\";\nimport { resolveUiMessages, useUiMessages } from \"../intl/messages\";\nimport { resolveSpotlightMessages } from \"./spotlight-messages\";\n\nexport type SpotlightSearchResolver<T = unknown> = (input: PromptSearchInput) => Promise<PromptSearchItem<T>[]> | PromptSearchItem<T>[];\n\nexport type SpotlightSearchOptions<T = unknown> = PromptSearchOptions & {\n resolve: SpotlightSearchResolver<T>;\n};\n\nexport type SpotlightButtonVariant = \"default\" | \"compact\" | \"chip\" | \"sidebar\" | \"sidebar-mobile\" | \"icon\";\n\nexport type SpotlightButtonProps = {\n variant?: SpotlightButtonVariant;\n label?: string;\n title?: string;\n icon?: string;\n /** Shortcut such as \"mod+k\"; takes precedence over shortcutLabel. */\n shortcut?: string;\n shortcutLabel?: string | false;\n ariaLabel?: string;\n disabled?: boolean;\n class?: string;\n onClick: () => void | Promise<void>;\n};\n\nexport const openSpotlightSearch = <T extends unknown = unknown>(\n options: SpotlightSearchOptions<T>,\n): Promise<PromptSearchItem<T> | undefined> => {\n const { resolve, ...promptOptions } = options;\n const messages = resolveUiMessages();\n const spotlightMessages = resolveSpotlightMessages();\n return prompts.search(resolve, {\n icon: \"ti ti-search\",\n placeholder: messages.search,\n minQueryLength: 0,\n noResultsText: spotlightMessages.spotlightNoResults,\n size: \"small\",\n ...promptOptions,\n });\n};\n\nexport function SpotlightButton(props: SpotlightButtonProps): JSX.Element {\n const messages = useUiMessages();\n const variant = () => props.variant ?? \"default\";\n const label = () => props.label ?? messages().searchLabel;\n const icon = () => props.icon ?? \"ti ti-search\";\n const shortcut = () => props.shortcut ?? props.shortcutLabel;\n const title = () => props.title ?? label();\n const showsShortcut = () => Boolean(shortcut()) && [\"chip\", \"sidebar\"].includes(variant());\n\n return (\n <button\n type=\"button\"\n class={`k2b-spotlight-button ${props.class ?? \"\"}`}\n data-variant={variant()}\n disabled={props.disabled}\n aria-label={props.ariaLabel ?? ([\"compact\", \"icon\"].includes(variant()) ? label() : undefined)}\n title={title()}\n onClick={() => void props.onClick()}\n >\n <i class={icon()} aria-hidden=\"true\" />\n <span class=\"k2b-spotlight-button__label\">{label()}</span>\n {showsShortcut() &&\n (props.shortcut !== undefined ? (\n <Kbd keys={props.shortcut} />\n ) : (\n <kbd class=\"k2b-kbd\">\n <kbd class=\"k2b-kbd__key\">{props.shortcutLabel}</kbd>\n </kbd>\n ))}\n </button>\n );\n}\n\nexport default SpotlightButton;\n"],"mappings":";;;;;;;;;;;;;;AACA,SAAS,GAAG,QAAQ,gBAAgB;AAEpC,SAAS,OAAO,QAAQ,qBAAqB;AAC7C,SAAS,iBAAiB,EAAE,aAAa,QAAQ,kBAAkB;AACnE,SAAS,wBAAwB,QAAQ,sBAAsB;AAwB/D,OAAO,MAAM,mBAAmB,GAC9B,OAAkC,IACW;EAC7C,MAAM;IAAE,OAAO;IAAE,GAAG;EAAc,CAAC,GAAG,OAAO;EAC7C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,CAAC;EACpC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,CAAC;EACpD,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE;IAC7B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,QAAQ,CAAC,MAAM;IAC5B,cAAc,EAAE,CAAC;IACjB,aAAa,EAAE,iBAAiB,CAAC,kBAAkB;IACnD,IAAI,EAAE,OAAO;IACb,GAAG;EACL,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,SAAS,eAAe,CAAC,KAA2B,EAAe;EACxE,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,IAAI,SAAS;EAChD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,WAAW;EACzD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,cAAc;EAC/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,aAAa;EAC5D,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC;EAC1C,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;EAE1F;IAAA;MAAA;MAAA;MAAA;MAAA;IAAA,eAQa,MAAM,KAAK,KAAK,CAAC,OAAO,CAAC,CAAC;IAAA,gBAGQ,KAAK;IAAA;MAAA,yBAC/C,aAAa,CAAC,CAAC;MAAA,aAAf,UACE,KAAK,CAAC,QAAQ,KAAK,SAAS,qBAC1B,GAAG;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,QAAQ;QAAA;MAAA;QAAA;UAAA;QAAA,sBAGI,KAAK,CAAC,aAAa;QAAA;MAAA,IAEjD,CAAC;IAAA;IAAA;MAAA,UAhBG,wBAAwB,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE;QAAA,OACpC,OAAO,CAAC,CAAC;QAAA,OACb,KAAK,CAAC,QAAQ;QAAA,OACZ,KAAK,CAAC,SAAS,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;QAAA,OACvF,KAAK,CAAC,CAAC;QAAA,OAGJ,IAAI,CAAC,CAAC;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;IAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;IAAA;IAAA;IAAA;EAAA;AAYtB;AAEA,eAAe,eAAe;AAAC","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/SpotlightSearch.tsx"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { Kbd } from \"../content/Kbd\";\nimport type { PromptSearchInput, PromptSearchItem, PromptSearchOptions } from \"../feedback/prompts\";\nimport { prompts } from \"../feedback/prompts\";\nimport { resolveUiMessages, useUiMessages } from \"../intl/messages\";\nimport { resolveSpotlightMessages } from \"./spotlight-messages\";\n\nexport type SpotlightSearchResolver<T = unknown> = (input: PromptSearchInput) => Promise<PromptSearchItem<T>[]> | PromptSearchItem<T>[];\n\nexport type SpotlightSearchOptions<T = unknown> = PromptSearchOptions & {\n resolve: SpotlightSearchResolver<T>;\n};\n\nexport type SpotlightButtonVariant = \"default\" | \"compact\" | \"chip\" | \"sidebar\" | \"sidebar-mobile\" | \"icon\";\n\nexport type SpotlightButtonProps = {\n variant?: SpotlightButtonVariant;\n label?: string;\n title?: string;\n icon?: string;\n /** Shortcut such as \"mod+k\"; takes precedence over shortcutLabel. */\n shortcut?: string;\n shortcutLabel?: string | false;\n ariaLabel?: string;\n disabled?: boolean;\n class?: string;\n onClick: () => void | Promise<void>;\n};\n\nexport const openSpotlightSearch = <T extends unknown = unknown>(\n options: SpotlightSearchOptions<T>,\n): Promise<PromptSearchItem<T> | undefined> => {\n const { resolve, ...promptOptions } = options;\n const messages = resolveUiMessages();\n const spotlightMessages = resolveSpotlightMessages();\n return prompts.search(resolve, {\n icon: \"ti ti-search\",\n placeholder: messages.search,\n minQueryLength: 0,\n noResultsText: spotlightMessages.spotlightNoResults,\n size: \"small\",\n ...promptOptions,\n });\n};\n\nexport function SpotlightButton(props: SpotlightButtonProps): JSX.Element {\n const messages = useUiMessages();\n const variant = () => props.variant ?? \"default\";\n const label = () => props.label ?? messages().searchLabel;\n const icon = () => props.icon ?? \"ti ti-search\";\n const shortcut = () => props.shortcut ?? props.shortcutLabel;\n const title = () => props.title ?? label();\n const showsShortcut = () => Boolean(shortcut()) && [\"chip\", \"sidebar\"].includes(variant());\n\n return (\n <button\n type=\"button\"\n class={`k2b-spotlight-button ${props.class ?? \"\"}`}\n data-variant={variant()}\n disabled={props.disabled}\n aria-label={props.ariaLabel ?? ([\"compact\", \"icon\"].includes(variant()) ? label() : undefined)}\n title={title()}\n onClick={() => void props.onClick()}\n >\n <i class={icon()} aria-hidden=\"true\" />\n <span class={variant() === \"sidebar\" ? \"k2b-spotlight-button__label k2b-truncate-fade\" : \"k2b-spotlight-button__label\"}>\n {label()}\n </span>\n {showsShortcut() &&\n (props.shortcut !== undefined ? (\n <Kbd keys={props.shortcut} />\n ) : (\n <kbd class=\"k2b-kbd\">\n <kbd class=\"k2b-kbd__key\">{props.shortcutLabel}</kbd>\n </kbd>\n ))}\n </button>\n );\n}\n\nexport default SpotlightButton;\n"],"mappings":";;;;;;;;;;;;;;AACA,SAAS,GAAG,QAAQ,gBAAgB;AAEpC,SAAS,OAAO,QAAQ,qBAAqB;AAC7C,SAAS,iBAAiB,EAAE,aAAa,QAAQ,kBAAkB;AACnE,SAAS,wBAAwB,QAAQ,sBAAsB;AAwB/D,OAAO,MAAM,mBAAmB,GAC9B,OAAkC,IACW;EAC7C,MAAM;IAAE,OAAO;IAAE,GAAG;EAAc,CAAC,GAAG,OAAO;EAC7C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,CAAC;EACpC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,CAAC;EACpD,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE;IAC7B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,QAAQ,CAAC,MAAM;IAC5B,cAAc,EAAE,CAAC;IACjB,aAAa,EAAE,iBAAiB,CAAC,kBAAkB;IACnD,IAAI,EAAE,OAAO;IACb,GAAG;EACL,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,SAAS,eAAe,CAAC,KAA2B,EAAe;EACxE,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,IAAI,SAAS;EAChD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,WAAW;EACzD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,cAAc;EAC/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,aAAa;EAC5D,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC;EAC1C,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;EAE1F;IAAA;MAAA;MAAA;MAAA;MAAA;IAAA,eAQa,MAAM,KAAK,KAAK,CAAC,OAAO,CAAC,CAAC;IAAA,gBAIhC,KAAK;IAAA;MAAA,yBAEP,aAAa,CAAC,CAAC;MAAA,aAAf,UACE,KAAK,CAAC,QAAQ,KAAK,SAAS,qBAC1B,GAAG;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,QAAQ;QAAA;MAAA;QAAA;UAAA;QAAA,sBAGI,KAAK,CAAC,aAAa;QAAA;MAAA,IAEjD,CAAC;IAAA;IAAA;MAAA,UAlBG,wBAAwB,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE;QAAA,OACpC,OAAO,CAAC,CAAC;QAAA,OACb,KAAK,CAAC,QAAQ;QAAA,OACZ,KAAK,CAAC,SAAS,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;QAAA,OACvF,KAAK,CAAC,CAAC;QAAA,OAGJ,IAAI,CAAC,CAAC;QAAA,OACH,OAAO,CAAC,CAAC,KAAK,SAAS,GAAG,+CAA+C,GAAG,6BAA6B;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;IAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;IAAA;IAAA;IAAA;EAAA;AAa5H;AAEA,eAAe,eAAe;AAAC","ignoreList":[]}