@k2b/ui 0.27.0 → 0.28.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 (191) hide show
  1. package/README.md +1 -1
  2. package/dist/base.css +147 -2
  3. package/dist/browser/actions/ContextMenu.js +30 -4
  4. package/dist/browser/actions/ContextMenu.js.map +1 -1
  5. package/dist/browser/actions/Dropdown.js +184 -158
  6. package/dist/browser/actions/Dropdown.js.map +1 -1
  7. package/dist/browser/actions/GestureMenu.js +71 -138
  8. package/dist/browser/actions/GestureMenu.js.map +1 -1
  9. package/dist/browser/actions/Toolbar.js +379 -48
  10. package/dist/browser/actions/Toolbar.js.map +1 -1
  11. package/dist/browser/actions/index.js.map +1 -1
  12. package/dist/browser/actions/menu-rows.js +15 -0
  13. package/dist/browser/actions/menu-rows.js.map +1 -0
  14. package/dist/browser/actions/menu-sheet.js +154 -0
  15. package/dist/browser/actions/menu-sheet.js.map +1 -0
  16. package/dist/browser/actions/toolbar-messages.js +20 -0
  17. package/dist/browser/actions/toolbar-messages.js.map +1 -0
  18. package/dist/browser/chart-inspection.js +3 -0
  19. package/dist/browser/chart-inspection.js.map +1 -0
  20. package/dist/browser/chat/ChatComposer.js +581 -397
  21. package/dist/browser/chat/ChatComposer.js.map +1 -1
  22. package/dist/browser/chat/chat-messages.js +19 -1
  23. package/dist/browser/chat/chat-messages.js.map +1 -1
  24. package/dist/browser/chat/command-search.js +3 -0
  25. package/dist/browser/chat/command-search.js.map +1 -1
  26. package/dist/browser/chat/index.js +2 -0
  27. package/dist/browser/chat/index.js.map +1 -1
  28. package/dist/browser/chat/reaction-people.js +15 -0
  29. package/dist/browser/chat/reaction-people.js.map +1 -0
  30. package/dist/browser/content/Chart.js +6 -15
  31. package/dist/browser/content/Chart.js.map +1 -1
  32. package/dist/browser/content/ChartSnapshotView.js +7 -10
  33. package/dist/browser/content/ChartSnapshotView.js.map +1 -1
  34. package/dist/browser/content/MessageRow.js +330 -448
  35. package/dist/browser/content/MessageRow.js.map +1 -1
  36. package/dist/browser/content/ReactionBar.js +419 -0
  37. package/dist/browser/content/ReactionBar.js.map +1 -0
  38. package/dist/browser/content/chart-inspection-core.js +557 -0
  39. package/dist/browser/content/chart-inspection-core.js.map +1 -0
  40. package/dist/browser/content/chart-inspection.js +10 -445
  41. package/dist/browser/content/chart-inspection.js.map +1 -1
  42. package/dist/browser/content/chart-line-gaps.js +1 -1
  43. package/dist/browser/content/chart-line-gaps.js.map +1 -1
  44. package/dist/browser/content/chart-snapshot.js +1 -1
  45. package/dist/browser/content/chart-snapshot.js.map +1 -1
  46. package/dist/browser/content/index.js +1 -0
  47. package/dist/browser/content/index.js.map +1 -1
  48. package/dist/browser/feedback/dialog-core.js +135 -23
  49. package/dist/browser/feedback/dialog-core.js.map +1 -1
  50. package/dist/browser/index.js +1 -0
  51. package/dist/browser/index.js.map +1 -1
  52. package/dist/browser/input-mode.js +40 -0
  53. package/dist/browser/input-mode.js.map +1 -0
  54. package/dist/browser/inputs/FileDropTarget.js +24 -9
  55. package/dist/browser/inputs/FileDropTarget.js.map +1 -1
  56. package/dist/browser/inputs/FileInputs.js +2 -2
  57. package/dist/browser/inputs/FileInputs.js.map +1 -1
  58. package/dist/browser/inputs/SelectChip.js +9 -0
  59. package/dist/browser/inputs/SelectChip.js.map +1 -1
  60. package/dist/browser/inputs/emoji/EmojiPicker.js +13 -0
  61. package/dist/browser/inputs/emoji/EmojiPicker.js.map +1 -1
  62. package/dist/browser/inputs/file-drop.js.map +1 -1
  63. package/dist/browser/layout/DetailPanel.js +283 -197
  64. package/dist/browser/layout/DetailPanel.js.map +1 -1
  65. package/dist/browser/layout/Discussion.js +233 -185
  66. package/dist/browser/layout/Discussion.js.map +1 -1
  67. package/dist/browser/layout/TableOfContents.js +10 -2
  68. package/dist/browser/layout/TableOfContents.js.map +1 -1
  69. package/dist/browser/layout/detail-panel-messages.js +35 -0
  70. package/dist/browser/layout/detail-panel-messages.js.map +1 -0
  71. package/dist/browser/surfaces/Avatar.js +50 -20
  72. package/dist/browser/surfaces/Avatar.js.map +1 -1
  73. package/dist/browser/surfaces/AvatarStack.js +406 -0
  74. package/dist/browser/surfaces/AvatarStack.js.map +1 -0
  75. package/dist/browser/surfaces/avatar-messages.js +8 -2
  76. package/dist/browser/surfaces/avatar-messages.js.map +1 -1
  77. package/dist/browser/surfaces/index.js +1 -0
  78. package/dist/browser/surfaces/index.js.map +1 -1
  79. package/dist/ssr/actions/ContextMenu.js +21 -3
  80. package/dist/ssr/actions/ContextMenu.js.map +1 -1
  81. package/dist/ssr/actions/Dropdown.js +140 -72
  82. package/dist/ssr/actions/Dropdown.js.map +1 -1
  83. package/dist/ssr/actions/GestureMenu.js +52 -106
  84. package/dist/ssr/actions/GestureMenu.js.map +1 -1
  85. package/dist/ssr/actions/Toolbar.js +294 -14
  86. package/dist/ssr/actions/Toolbar.js.map +1 -1
  87. package/dist/ssr/actions/index.js.map +1 -1
  88. package/dist/ssr/actions/menu-rows.js +15 -0
  89. package/dist/ssr/actions/menu-rows.js.map +1 -0
  90. package/dist/ssr/actions/menu-sheet.js +138 -0
  91. package/dist/ssr/actions/menu-sheet.js.map +1 -0
  92. package/dist/ssr/actions/toolbar-messages.js +20 -0
  93. package/dist/ssr/actions/toolbar-messages.js.map +1 -0
  94. package/dist/ssr/chart-inspection.js +3 -0
  95. package/dist/ssr/chart-inspection.js.map +1 -0
  96. package/dist/ssr/chat/ChatComposer.js +263 -89
  97. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  98. package/dist/ssr/chat/chat-messages.js +19 -1
  99. package/dist/ssr/chat/chat-messages.js.map +1 -1
  100. package/dist/ssr/chat/command-search.js +3 -0
  101. package/dist/ssr/chat/command-search.js.map +1 -1
  102. package/dist/ssr/chat/index.js +2 -0
  103. package/dist/ssr/chat/index.js.map +1 -1
  104. package/dist/ssr/chat/reaction-people.js +15 -0
  105. package/dist/ssr/chat/reaction-people.js.map +1 -0
  106. package/dist/ssr/content/Chart.js +6 -15
  107. package/dist/ssr/content/Chart.js.map +1 -1
  108. package/dist/ssr/content/ChartSnapshotView.js +7 -10
  109. package/dist/ssr/content/ChartSnapshotView.js.map +1 -1
  110. package/dist/ssr/content/MessageRow.js +98 -152
  111. package/dist/ssr/content/MessageRow.js.map +1 -1
  112. package/dist/ssr/content/ReactionBar.js +304 -0
  113. package/dist/ssr/content/ReactionBar.js.map +1 -0
  114. package/dist/ssr/content/chart-inspection-core.js +557 -0
  115. package/dist/ssr/content/chart-inspection-core.js.map +1 -0
  116. package/dist/ssr/content/chart-inspection.js +10 -445
  117. package/dist/ssr/content/chart-inspection.js.map +1 -1
  118. package/dist/ssr/content/chart-line-gaps.js +1 -1
  119. package/dist/ssr/content/chart-line-gaps.js.map +1 -1
  120. package/dist/ssr/content/chart-snapshot.js +1 -1
  121. package/dist/ssr/content/chart-snapshot.js.map +1 -1
  122. package/dist/ssr/content/index.js +1 -0
  123. package/dist/ssr/content/index.js.map +1 -1
  124. package/dist/ssr/feedback/dialog-core.js +135 -23
  125. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  126. package/dist/ssr/index.js +1 -0
  127. package/dist/ssr/index.js.map +1 -1
  128. package/dist/ssr/input-mode.js +40 -0
  129. package/dist/ssr/input-mode.js.map +1 -0
  130. package/dist/ssr/inputs/FileDropTarget.js +17 -5
  131. package/dist/ssr/inputs/FileDropTarget.js.map +1 -1
  132. package/dist/ssr/inputs/FileInputs.js +2 -2
  133. package/dist/ssr/inputs/FileInputs.js.map +1 -1
  134. package/dist/ssr/inputs/SelectChip.js +9 -0
  135. package/dist/ssr/inputs/SelectChip.js.map +1 -1
  136. package/dist/ssr/inputs/emoji/EmojiPicker.js +12 -0
  137. package/dist/ssr/inputs/emoji/EmojiPicker.js.map +1 -1
  138. package/dist/ssr/inputs/file-drop.js.map +1 -1
  139. package/dist/ssr/layout/DetailPanel.js +112 -58
  140. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  141. package/dist/ssr/layout/Discussion.js +63 -36
  142. package/dist/ssr/layout/Discussion.js.map +1 -1
  143. package/dist/ssr/layout/TableOfContents.js +10 -2
  144. package/dist/ssr/layout/TableOfContents.js.map +1 -1
  145. package/dist/ssr/layout/detail-panel-messages.js +35 -0
  146. package/dist/ssr/layout/detail-panel-messages.js.map +1 -0
  147. package/dist/ssr/surfaces/Avatar.js +20 -2
  148. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  149. package/dist/ssr/surfaces/AvatarStack.js +286 -0
  150. package/dist/ssr/surfaces/AvatarStack.js.map +1 -0
  151. package/dist/ssr/surfaces/avatar-messages.js +8 -2
  152. package/dist/ssr/surfaces/avatar-messages.js.map +1 -1
  153. package/dist/ssr/surfaces/index.js +1 -0
  154. package/dist/ssr/surfaces/index.js.map +1 -1
  155. package/dist/styles.css +1 -1
  156. package/dist/types/actions/ContextMenu.d.ts +8 -0
  157. package/dist/types/actions/Dropdown.d.ts +12 -5
  158. package/dist/types/actions/GestureMenu.d.ts +6 -4
  159. package/dist/types/actions/Toolbar.d.ts +20 -0
  160. package/dist/types/actions/index.d.ts +1 -1
  161. package/dist/types/actions/menu-rows.d.ts +5 -0
  162. package/dist/types/actions/menu-sheet.d.ts +22 -0
  163. package/dist/types/actions/toolbar-messages.d.ts +8 -0
  164. package/dist/types/chart-inspection.d.ts +2 -0
  165. package/dist/types/chat/ChatComposer.d.ts +7 -0
  166. package/dist/types/chat/chat-messages.d.ts +10 -2
  167. package/dist/types/chat/command-search.d.ts +2 -0
  168. package/dist/types/chat/index.d.ts +2 -0
  169. package/dist/types/chat/reaction-people.d.ts +9 -0
  170. package/dist/types/content/Chart.d.ts +2 -2
  171. package/dist/types/content/MessageRow.d.ts +3 -10
  172. package/dist/types/content/ReactionBar.d.ts +32 -0
  173. package/dist/types/content/chart-inspection-core.d.ts +61 -0
  174. package/dist/types/content/chart-inspection.d.ts +4 -20
  175. package/dist/types/content/chart-snapshot.d.ts +1 -1
  176. package/dist/types/content/index.d.ts +2 -1
  177. package/dist/types/feedback/dialog-core.d.ts +16 -1
  178. package/dist/types/index.d.ts +1 -0
  179. package/dist/types/input-mode.d.ts +7 -0
  180. package/dist/types/inputs/FileDropTarget.d.ts +6 -3
  181. package/dist/types/inputs/SelectChip.d.ts +2 -0
  182. package/dist/types/inputs/file-drop.d.ts +2 -0
  183. package/dist/types/layout/DetailPanel.d.ts +11 -0
  184. package/dist/types/layout/Discussion.d.ts +8 -0
  185. package/dist/types/layout/TableOfContents.d.ts +2 -0
  186. package/dist/types/layout/detail-panel-messages.d.ts +15 -0
  187. package/dist/types/surfaces/Avatar.d.ts +12 -0
  188. package/dist/types/surfaces/AvatarStack.d.ts +41 -0
  189. package/dist/types/surfaces/avatar-messages.d.ts +3 -0
  190. package/dist/types/surfaces/index.d.ts +3 -1
  191. package/package.json +6 -1
@@ -1,18 +1,16 @@
1
- import { ssrStyleProperty as _$ssrStyleProperty } from "solid-js/web";
2
1
  import { ssr as _$ssr } from "solid-js/web";
3
2
  import { createComponent as _$createComponent } from "solid-js/web";
3
+ import { ssrStyleProperty as _$ssrStyleProperty } from "solid-js/web";
4
4
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
5
5
  import { escape as _$escape } from "solid-js/web";
6
- var _tmpl$ = ["<div class=\"k2b-gesture-menu__sheet-menu\" role=\"menu\"", ">", "</div>"],
7
- _tmpl$2 = ["<div class=\"k2b-gesture-menu\"", " style=\"", "\">", "<div class=\"k2b-gesture-menu__content\">", "</div></div>"],
8
- _tmpl$3 = ["<span class=\"k2b-gesture-menu__swipe\" aria-hidden=\"true\"><i", "></i></span>"];
6
+ var _tmpl$ = ["<div class=\"k2b-gesture-menu\"", " style=\"", "\">", "<div class=\"k2b-gesture-menu__content\">", "</div></div>"],
7
+ _tmpl$2 = ["<span class=\"k2b-gesture-menu__swipe\" aria-hidden=\"true\"><i", "></i></span>"];
9
8
  import { createSignal, onCleanup, onMount, Show } from "solid-js";
10
- import { dialogCore } from "../feedback/dialog-core";
11
- import { LocaleProvider, useLocale } from "../intl/locale";
12
- import BottomSheet, { bottomSheetOptions } from "../layout/BottomSheet";
9
+ import { useLocale } from "../intl/locale";
13
10
  import { prefersReducedMotion } from "../motion";
14
- import { ContextMenu } from "./ContextMenu";
15
- import { DropdownItems, focusRowSegment } from "./Dropdown";
11
+ import { ContextMenuBase } from "./ContextMenu";
12
+ import { DropdownItems } from "./Dropdown";
13
+ import { openMenuSheet } from "./menu-sheet";
16
14
 
17
15
  /** A finger held this long without moving opens the menu, as the platforms' own long press does. */
18
16
  const LONG_PRESS_MS = 500;
@@ -48,68 +46,17 @@ const gestureAction = (items, kind) => {
48
46
  };
49
47
  const swipeKind = direction => direction === "right" ? "swipe-right" : "swipe-left";
50
48
 
51
- /**
52
- * The sheet's items hand their action to `run` instead of running it while the sheet closes: `dialogCore` settles the
53
- * sheet after it left the history, and only then may an action navigate or open the next dialog.
54
- * A choice or action that keeps the menu open runs at once.
55
- */
56
- const afterClose = (items, run) => {
57
- const entry = item => {
58
- const action = item.action;
59
- if (!action || "closeOnSelect" in item && item.closeOnSelect === false) return item;
60
- return {
61
- ...item,
62
- action: () => run(action)
63
- };
64
- };
65
- return items.map(item => "items" in item ? {
66
- ...item,
67
- items: item.items.map(entry)
68
- } : entry(item));
69
- };
70
- const menuItems = menu => Array.from(menu.querySelectorAll("[role^='menuitem']:not([aria-disabled='true'])"));
71
-
72
- /**
73
- * The menu inside the long-press sheet: the same items, at touch size, with arrow keys for a connected keyboard. Focus
74
- * starts on the sheet itself, which shows no ring on a phone; the first arrow key moves it into the menu.
75
- */
76
- function SheetMenu(props) {
77
- let menu;
78
- const focus = index => {
79
- const items = menuItems(menu);
80
- items[(index + items.length) % items.length]?.focus();
81
- };
82
- const onKeyDown = event => {
83
- const items = menuItems(menu);
84
- const current = items.indexOf(document.activeElement);
85
- if (event.key === "ArrowDown") focus(current + 1);else if (event.key === "ArrowUp") focus(current < 0 ? -1 : current - 1);else if (event.key === "Home" || event.key === "End") focus(event.key === "Home" ? 0 : -1);else if (!focusRowSegment(items, event.key)) return;
86
- event.preventDefault();
87
- };
88
- // Keys pressed on the sheet itself, while it is the top level of the shared dialog.
89
- const onSheetKeyDown = event => {
90
- if (event.target === props.dialog && props.dialog.lastElementChild?.contains(menu)) onKeyDown(event);
91
- };
92
- onMount(() => {
93
- props.dialog.addEventListener("keydown", onSheetKeyDown);
94
- onCleanup(() => props.dialog.removeEventListener("keydown", onSheetKeyDown));
95
- });
96
- return _$ssr(_tmpl$, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$escape(_$createComponent(DropdownItems, {
97
- get items() {
98
- return props.items;
99
- },
100
- close: () => props.close()
101
- })));
102
- }
103
-
104
49
  /**
105
50
  * Touch gestures for an element, each the shortcut of an entry in its menu: a horizontal swipe, a double tap, and a
106
- * long press that opens the whole menu as a `BottomSheet`. A mouse double-click runs the double-tap action; a
107
- * right-click and the keyboard open the menu beside the element. Vertical scrolling never turns into a swipe.
51
+ * long press that opens a `BottomSheet` below 48rem and the same menu at the finger from 48rem. A mouse double-click
52
+ * runs the double-tap action; right-click opens the menu at the pointer, the keyboard beside the focused element.
53
+ * Vertical scrolling never turns into a swipe.
108
54
  */
109
55
  export function GestureMenu(props) {
110
56
  const locale = useLocale();
111
57
  const [swipe, setSwipe] = createSignal();
112
58
  let surface;
59
+ let openMenuAt;
113
60
  let press;
114
61
  let lastTap;
115
62
  let lastPointer = "mouse";
@@ -124,6 +71,20 @@ export function GestureMenu(props) {
124
71
  let reduced = false;
125
72
  let settleTimer;
126
73
  const active = () => props.items.length > 0;
74
+ const wide = () => window.matchMedia?.("(min-width: 48rem)").matches ?? false;
75
+ /**
76
+ * A modal dialog makes everything outside it inert, also ContextMenu's menu on the body, so inside one the hold
77
+ * keeps the sheet, which opens on the same dialog stack. An engine without `:modal` gets the sheet too.
78
+ */
79
+ const inModal = () => {
80
+ const dialog = surface.closest("dialog[open]");
81
+ if (!dialog) return false;
82
+ try {
83
+ return dialog.matches(":modal");
84
+ } catch {
85
+ return true;
86
+ }
87
+ };
127
88
  const action = kind => gestureAction(props.items, kind);
128
89
  const touchAction = () => action("swipe-right") || action("swipe-left") ? "swipe" : action("double-tap") ? "tap" : undefined;
129
90
 
@@ -136,44 +97,14 @@ export function GestureMenu(props) {
136
97
  if (sheetOpen || !active()) return;
137
98
  sheetOpen = true;
138
99
  props.onOpen?.();
139
- const current = locale();
140
- let chosen;
141
- const choose = action => {
142
- chosen = action;
143
- };
144
- void dialogCore.open((close, context) => _$createComponent(LocaleProvider, {
145
- locale: current,
146
- get children() {
147
- return _$createComponent(BottomSheet, {
148
- get onDismiss() {
149
- return context.requestDismiss;
150
- },
151
- get children() {
152
- return _$createComponent(BottomSheet.Body, {
153
- get children() {
154
- return [props.sheetTop?.(() => close()), _$createComponent(SheetMenu, {
155
- get items() {
156
- return afterClose(props.items, choose);
157
- },
158
- get label() {
159
- return props.label;
160
- },
161
- close: () => close(),
162
- get dialog() {
163
- return context.dialog;
164
- }
165
- })];
166
- }
167
- });
168
- }
169
- });
170
- }
171
- }), {
172
- ...bottomSheetOptions,
173
- ariaLabel: props.label,
174
- history: true,
100
+ void openMenuSheet({
101
+ Items: DropdownItems,
102
+ items: props.items,
103
+ label: props.label,
104
+ locale: locale(),
105
+ top: props.sheetTop,
175
106
  signal: disposed.signal
176
- }).then(() => chosen?.()).finally(() => {
107
+ }).finally(() => {
177
108
  sheetOpen = false;
178
109
  });
179
110
  };
@@ -225,7 +156,7 @@ export function GestureMenu(props) {
225
156
  if (!press) return;
226
157
  press.long = true;
227
158
  lastTap = undefined;
228
- openSheet();
159
+ if (wide() && !inModal()) openMenuAt?.(press.x, press.y);else openSheet();
229
160
  };
230
161
  const onPointerDown = event => {
231
162
  lastPointer = event.pointerType;
@@ -254,7 +185,9 @@ export function GestureMenu(props) {
254
185
  };
255
186
  const onPointerMove = event => {
256
187
  const current = press;
257
- if (!current || event.pointerId !== current.id || current.long) return;
188
+ if (!current || event.pointerId !== current.id) return;
189
+ // A later "hold, then drag" gesture takes over the pointer here.
190
+ if (current.long) return;
258
191
  const dx = event.clientX - current.x;
259
192
  const dy = event.clientY - current.y;
260
193
  if (current.direction) {
@@ -312,6 +245,11 @@ export function GestureMenu(props) {
312
245
  endPress();
313
246
  lastTap = undefined;
314
247
  };
248
+
249
+ // Once the hold opens the menu or sheet, further movement must not scroll the page underneath it.
250
+ const onTouchMove = event => {
251
+ if (press?.long && event.cancelable) event.preventDefault();
252
+ };
315
253
  const onTouchEnd = event => {
316
254
  if (!consumed) return;
317
255
  consumed = false;
@@ -360,6 +298,9 @@ export function GestureMenu(props) {
360
298
  surface.addEventListener("pointermove", onPointerMove);
361
299
  surface.addEventListener("pointerup", onPointerUp);
362
300
  surface.addEventListener("pointercancel", onPointerCancel);
301
+ surface.addEventListener("touchmove", onTouchMove, {
302
+ passive: false
303
+ });
363
304
  surface.addEventListener("touchend", onTouchEnd, {
364
305
  passive: false
365
306
  });
@@ -375,6 +316,7 @@ export function GestureMenu(props) {
375
316
  surface.removeEventListener("pointermove", onPointerMove);
376
317
  surface.removeEventListener("pointerup", onPointerUp);
377
318
  surface.removeEventListener("pointercancel", onPointerCancel);
319
+ surface.removeEventListener("touchmove", onTouchMove);
378
320
  surface.removeEventListener("touchend", onTouchEnd);
379
321
  surface.removeEventListener("click", onClick, true);
380
322
  surface.removeEventListener("contextmenu", onContextMenu);
@@ -382,7 +324,11 @@ export function GestureMenu(props) {
382
324
  surface.removeEventListener("dblclick", onDoubleClick);
383
325
  });
384
326
  });
385
- return _$createComponent(ContextMenu, {
327
+ return _$createComponent(ContextMenuBase, {
328
+ openAt: open => openMenuAt = open,
329
+ get title() {
330
+ return props.label;
331
+ },
386
332
  get items() {
387
333
  return props.items;
388
334
  },
@@ -402,11 +348,11 @@ export function GestureMenu(props) {
402
348
  return props.class;
403
349
  },
404
350
  get children() {
405
- return _$ssr(_tmpl$2, _$ssrAttribute("data-active", active() ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-touch", _$escape(touchAction(), true), false) + _$ssrAttribute("data-swipe", _$escape(swipe()?.direction, true), false) + _$ssrAttribute("data-armed", swipe()?.armed ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-settling", swipe()?.settling ? "" : _$escape(undefined, true), false), _$ssrStyleProperty("--k2b-gesture-menu-offset:", `${_$escape(swipe()?.offset ?? 0, true)}px`) + _$ssrStyleProperty(";--k2b-gesture-menu-progress:", _$escape(String(swipe()?.progress ?? 0), true)), _$escape(_$createComponent(Show, {
351
+ return _$ssr(_tmpl$, _$ssrAttribute("data-active", active() ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-touch", _$escape(touchAction(), true), false) + _$ssrAttribute("data-swipe", _$escape(swipe()?.direction, true), false) + _$ssrAttribute("data-armed", swipe()?.armed ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-settling", swipe()?.settling ? "" : _$escape(undefined, true), false), _$ssrStyleProperty("--k2b-gesture-menu-offset:", `${_$escape(swipe()?.offset ?? 0, true)}px`) + _$ssrStyleProperty(";--k2b-gesture-menu-progress:", _$escape(String(swipe()?.progress ?? 0), true)), _$escape(_$createComponent(Show, {
406
352
  get when() {
407
353
  return swipe();
408
354
  },
409
- children: current => _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(current().icon ?? (current().direction === "right" ? "ti ti-arrow-right" : "ti ti-arrow-left"), true), false))
355
+ children: current => _$ssr(_tmpl$2, _$ssrAttribute("class", _$escape(current().icon ?? (current().direction === "right" ? "ti ti-arrow-right" : "ti ti-arrow-left"), true), false))
410
356
  })), _$escape(props.children));
411
357
  }
412
358
  });
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/GestureMenu.tsx"],"sourcesContent":["import { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { dialogCore } from \"../feedback/dialog-core\";\nimport { LocaleProvider, useLocale } from \"../intl/locale\";\nimport BottomSheet, { bottomSheetOptions } from \"../layout/BottomSheet\";\nimport { prefersReducedMotion } from \"../motion\";\nimport { ContextMenu } from \"./ContextMenu\";\nimport {\n type DropdownAction,\n type DropdownActionBase,\n type DropdownChoice,\n DropdownItems,\n type DropdownSection,\n focusRowSegment,\n} from \"./Dropdown\";\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 it as a bottom sheet, a right-click, the Context Menu key, or Shift+F10 as a menu.\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 above the menu in the long-press 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 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\ntype Entry = GestureMenuAction | DropdownAction | DropdownChoice;\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 * The sheet's items hand their action to `run` instead of running it while the sheet closes: `dialogCore` settles the\n * sheet after it left the history, and only then may an action navigate or open the next dialog.\n * A choice or action that keeps the menu open runs at once.\n */\nconst afterClose = (items: readonly GestureMenuItem[], run: (action: () => void) => void): GestureMenuItem[] => {\n const entry = (item: Entry): Entry => {\n const action = item.action;\n if (!action || (\"closeOnSelect\" in item && item.closeOnSelect === false)) return item;\n return { ...item, action: () => run(action) };\n };\n return items.map((item) => (\"items\" in item ? { ...item, items: item.items.map(entry) } : entry(item)));\n};\n\nconst menuItems = (menu: HTMLElement): HTMLElement[] =>\n Array.from(menu.querySelectorAll<HTMLElement>(\"[role^='menuitem']:not([aria-disabled='true'])\"));\n\n/**\n * The menu inside the long-press sheet: the same items, at touch size, with arrow keys for a connected keyboard. Focus\n * starts on the sheet itself, which shows no ring on a phone; the first arrow key moves it into the menu.\n */\nfunction SheetMenu(props: { items: readonly GestureMenuItem[]; label: string; close: () => void; dialog: HTMLDialogElement }): JSX.Element {\n let menu!: HTMLDivElement;\n const focus = (index: number) => {\n const items = menuItems(menu);\n items[(index + items.length) % items.length]?.focus();\n };\n const onKeyDown = (event: KeyboardEvent) => {\n const items = menuItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\") focus(current + 1);\n else if (event.key === \"ArrowUp\") focus(current < 0 ? -1 : current - 1);\n else if (event.key === \"Home\" || event.key === \"End\") focus(event.key === \"Home\" ? 0 : -1);\n else if (!focusRowSegment(items, event.key)) return;\n event.preventDefault();\n };\n // Keys pressed on the sheet itself, while it is the top level of the shared dialog.\n const onSheetKeyDown = (event: KeyboardEvent) => {\n if (event.target === props.dialog && props.dialog.lastElementChild?.contains(menu)) onKeyDown(event);\n };\n onMount(() => {\n props.dialog.addEventListener(\"keydown\", onSheetKeyDown);\n onCleanup(() => props.dialog.removeEventListener(\"keydown\", onSheetKeyDown));\n });\n return (\n <div ref={menu} class=\"k2b-gesture-menu__sheet-menu\" role=\"menu\" aria-label={props.label} onKeyDown={onKeyDown}>\n <DropdownItems items={props.items} close={() => props.close()} />\n </div>\n );\n}\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 the whole menu as a `BottomSheet`. A mouse double-click runs the double-tap action; a\n * right-click and the keyboard open the menu beside the element. 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 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 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 const current = locale();\n let chosen: (() => void) | undefined;\n const choose = (action: () => void) => {\n chosen = action;\n };\n void dialogCore\n .open<void>(\n (close, context) => (\n <LocaleProvider locale={current}>\n <BottomSheet onDismiss={context.requestDismiss}>\n <BottomSheet.Body>\n {props.sheetTop?.(() => close())}\n <SheetMenu items={afterClose(props.items, choose)} label={props.label} close={() => close()} dialog={context.dialog} />\n </BottomSheet.Body>\n </BottomSheet>\n </LocaleProvider>\n ),\n { ...bottomSheetOptions, ariaLabel: props.label, history: true, signal: disposed.signal },\n )\n .then(() => chosen?.())\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 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 || 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 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(\"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(\"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 <ContextMenu\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 </ContextMenu>\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 { 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":";;;;;;;AAAA,SAAS,YAAY,EAAY,SAAS,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU;AAC3E,SAAS,SAAS,QAAQ,gBAAgB;AAC1C,SAAS,oBAAoB,QAAQ,WAAW;AAChD,SAAS,eAAe,QAAQ,eAAe;AAC/C,SAA4E,aAAa,QAA8B,YAAY;AACnI,SAAS,aAAa,QAAQ,cAAc;;AAE5C;AACA,MAAM,aAAa,GAAG,GAAG;AACzB;AACA,MAAM,aAAa,GAAG,GAAG;AACzB;AACA,MAAM,mBAAmB,GAAG,EAAE;AAC9B;AACA,MAAM,IAAI,GAAG,EAAE;AACf;AACA,MAAM,WAAW,GAAG,GAAG;AACvB;AACA,MAAM,eAAe,GAAG,EAAE;AAC1B;AACA,MAAM,SAAS,GAAG,EAAE;AACpB,MAAM,gBAAgB,GAAG,IAAI;AAC7B;AACA,MAAM,IAAI,GAAG,EAAE;AACf;AACA,MAAM,SAAS,GAAG,GAAG;;AAErB;AACA;AACA;AACA;AACA,MAAM,MAAM,GAAG,CACb,SAAS,EACT,QAAQ,EACR,OAAO,EACP,UAAU,EACV,QAAQ,EACR,SAAS,EACT,OAAO,EACP,OAAO,EACP,OAAO,EACP,KAAK,EACL,kDAAkD,EAClD,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,CACxB,CAAC,IAAI,CAAC,IAAI,CAAC;;AAIZ;;AA6DA,MAAM,aAAa,GAAG,CAAC,KAAiC,EAAE,IAAiB,KAAoC;EAC7G,KAAK,MAAM,IAAI,IAAI,KAAK,EACtB,KAAK,MAAM,KAAK,IAAI,OAAO,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,EACvD,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,OAAO,KAAK,CAAC,QAAQ,GAAG,SAAS,GAAG,KAAK;EAC/F,OAAO,SAAS;AAClB,CAAC;AAED,MAAM,SAAS,GAAI,SAAyB,IAAmB,SAAS,KAAK,OAAO,GAAG,aAAa,GAAG,YAAa;;AAEpH;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,WAAW,CAAC,KAAuB,EAAe;EAChE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAQ,CAAC;EAC/C,IAAI,OAAwB;EAC5B,IAAI,UAAwD;EAC5D,IAAI,KAAwB;EAC5B,IAAI,OAAyD;EAC7D,IAAI,WAAW,GAAG,OAAO;EACzB;AACF;AACA;AACA;EACE,IAAI,QAAQ,GAAG,KAAK;EACpB,IAAI,SAAS,GAAG,KAAK;EACrB;EACA,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,CAAC;EACtC,IAAI,OAAO,GAAG,KAAK;EACnB,IAAI,WAAsD;EAE1D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;EAC3C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,GAAG,oBAAoB,CAAC,CAAC,OAAO,IAAI,KAAK;EAC7E;AACF;AACA;AACA;EACE,MAAM,OAAO,GAAG,MAAM;IACpB,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;IAC9C,IAAI,CAAC,MAAM,EAAE,OAAO,KAAK;IACzB,IAAI;MACF,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjC,CAAC,CAAC,MAAM;MACN,OAAO,IAAI;IACb;EACF,CAAC;EACD,MAAM,MAAM,GAAI,IAAiB,IAAK,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC;EACtE,MAAM,WAAW,GAAG,MAAO,MAAM,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,GAAG,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,GAAG,SAAU;;EAE9H;EACA,MAAM,OAAO,GAAI,MAA0B,IAAK;IAC9C,MAAM,KAAK,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI;IACvE,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;EACvE,CAAC;EAED,MAAM,SAAS,GAAG,MAAM;IACtB,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;IAC5B,SAAS,GAAG,IAAI;IAChB,KAAK,CAAC,MAAM,GAAG,CAAC;IAChB,KAAK,aAAa,CAAC;MACjB,KAAK,EAAE,aAAa;MACpB,KAAK,EAAE,KAAK,CAAC,KAAK;MAClB,KAAK,EAAE,KAAK,CAAC,KAAK;MAClB,MAAM,EAAE,MAAM,CAAC,CAAC;MAChB,GAAG,EAAE,KAAK,CAAC,QAAQ;MACnB,MAAM,EAAE,QAAQ,CAAC;IACnB,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;MACf,SAAS,GAAG,KAAK;IACnB,CAAC,CAAC;EACJ,CAAC;;EAED;EACA,MAAM,cAAc,GAAI,KAAmB,IAAK;IAC9C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,EAAE;IAC5C,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,CAAC;EACZ,CAAC;EAED,MAAM,QAAQ,GAAG,MAAM;IACrB,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC;IAC1B,KAAK,GAAG,SAAS;IACjB,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,cAAc,EAAE,IAAI,CAAC;IACjE,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ;EACjC,CAAC;EAED,MAAM,MAAM,GAAG,MAAM;IACnB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC;IACvB,IAAI,CAAC,OAAO,EAAE;IACd,YAAY,CAAC,WAAW,CAAC;IACzB,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;MACnC,QAAQ,CAAC,SAAS,CAAC;MACnB;IACF;IACA,QAAQ,CAAC;MAAE,GAAG,OAAO;MAAE,MAAM,EAAE,CAAC;MAAE,QAAQ,EAAE,CAAC;MAAE,KAAK,EAAE,KAAK;MAAE,QAAQ,EAAE;IAAK,CAAC,CAAC;IAC9E,WAAW,GAAG,UAAU,CAAC,MAAM,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;EAChE,CAAC;EAED,MAAM,SAAS,GAAG,CAAC,OAAc,EAAE,SAAyB,EAAE,EAAU,KAAK;IAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,KAAK,OAAO,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,IAAI,eAAe,GAAG,MAAM,GAAG,eAAe,GAAG,CAAC,MAAM,GAAG,eAAe,IAAI,gBAAgB;IAClH,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,SAAS,KAAK,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,SAAS,GAAG,SAAS;IAC7B,QAAQ,CAAC;MACP,SAAS;MACT,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI;MACxC,MAAM;MACN,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;MAC/C,KAAK,EAAE,MAAM,IAAI,eAAe;MAChC,QAAQ,EAAE;IACZ,CAAC,CAAC;EACJ,CAAC;EAED,MAAM,SAAS,GAAG,MAAM;IACtB,IAAI,CAAC,KAAK,EAAE;IACZ,KAAK,CAAC,IAAI,GAAG,IAAI;IACjB,OAAO,GAAG,SAAS;IACnB,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KACpD,SAAS,CAAC,CAAC;EAClB,CAAC;EAED,MAAM,aAAa,GAAI,KAAmB,IAAK;IAC7C,WAAW,GAAG,KAAK,CAAC,WAAW;IAC/B,QAAQ,GAAG,KAAK;IAChB;IACA,MAAM,QAAQ,GAAG,OAAO;IACxB,OAAO,GAAG,SAAS;IACnB;IACA,IAAI,KAAK,CAAC,WAAW,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;IACvD,QAAQ,CAAC,CAAC;IACV,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;IACxC,MAAM,MAAM,GACV,QAAQ,KAAK,SAAS,IACtB,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,IAAI,aAAa,IAChD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,mBAAmB;IAC3F,KAAK,GAAG;MACN,EAAE,EAAE,KAAK,CAAC,SAAS;MACnB,CAAC,EAAE,KAAK,CAAC,OAAO;MAChB,CAAC,EAAE,KAAK,CAAC,OAAO;MAChB,KAAK,EAAE,KAAK;MACZ,IAAI,EAAE,KAAK;MACX,MAAM;MACN,IAAI,EAAE,KAAK,CAAC,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI;MACtE,KAAK,EAAE,UAAU,CAAC,SAAS,EAAE,aAAa;IAC5C,CAAC;IACD,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,cAAc,EAAE,IAAI,CAAC;IAC9D;IACA,OAAO,CAAC,OAAO,CAAC,QAAQ,GAAG,EAAE;EAC/B,CAAC;EAED,MAAM,aAAa,GAAI,KAAmB,IAAK;IAC7C,MAAM,OAAO,GAAG,KAAK;IACrB,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,EAAE;IAChD;IACA,IAAI,OAAO,CAAC,IAAI,EAAE;IAClB,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC;IACpC,IAAI,OAAO,CAAC,SAAS,EAAE;MACrB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;MACzC;IACF;IACA,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE;IAChD,OAAO,CAAC,KAAK,GAAG,IAAI;IACpB,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;IAC3B,IAAI,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE;IAC/D,MAAM,SAAyB,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,GAAG,MAAM;IAC3D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE;IACnC,YAAY,CAAC,WAAW,CAAC;IACzB,OAAO,GAAG,oBAAoB,CAAC,CAAC;IAChC,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC;EACnC,CAAC;EAED,MAAM,WAAW,GAAI,KAAmB,IAAK;IAC3C,MAAM,OAAO,GAAG,KAAK;IACrB,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,EAAE;IAChD,QAAQ,CAAC,CAAC;IACV,IAAI,OAAO,CAAC,IAAI,EAAE;MAChB,QAAQ,GAAG,IAAI;MACf;IACF;IACA,IAAI,OAAO,CAAC,SAAS,EAAE;MACrB;MACA,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;MAChE,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,SAAS;MACrF,MAAM,CAAC,CAAC;MACR,IAAI,WAAW,EAAE;QACf,QAAQ,GAAG,IAAI;QACf,WAAW,CAAC,MAAM,CAAC,CAAC;MACtB;MACA;IACF;IACA,IAAI,OAAO,CAAC,KAAK,EAAE;IACnB,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;IACtC,IAAI,CAAC,SAAS,EAAE;IAChB,IAAI,OAAO,CAAC,MAAM,EAAE;MAClB,QAAQ,GAAG,IAAI;MACf,SAAS,CAAC,MAAM,CAAC,CAAC;MAClB;IACF;IACA,OAAO,GAAG;MAAE,CAAC,EAAE,KAAK,CAAC,OAAO;MAAE,CAAC,EAAE,KAAK,CAAC,OAAO;MAAE,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC;IAAE,CAAC;EACzE,CAAC;;EAED;EACA,MAAM,eAAe,GAAI,KAAmB,IAAK;IAC/C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,EAAE;IAC5C,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,CAAC;IACV,OAAO,GAAG,SAAS;EACrB,CAAC;;EAED;EACA,MAAM,WAAW,GAAI,KAAiB,IAAK;IACzC,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;EAC7D,CAAC;EAED,MAAM,UAAU,GAAI,KAAiB,IAAK;IACxC,IAAI,CAAC,QAAQ,EAAE;IACf,QAAQ,GAAG,KAAK;IAChB,IAAI,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;EAC9C,CAAC;;EAED;EACA,MAAM,OAAO,GAAI,KAAiB,IAAK;IACrC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;IACrC,QAAQ,GAAG,KAAK;IAChB,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,KAAK,CAAC,eAAe,CAAC,CAAC;EACzB,CAAC;EAED,MAAM,aAAa,GAAI,KAAiB,IAAK;IAC3C;IACA,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;IACf;IACA,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;MACzB,KAAK,CAAC,eAAe,CAAC,CAAC;MACvB;IACF;IACA;IACA,IAAI,CAAC,KAAK,IAAI,EAAE,aAAa,IAAI,KAAK,KAAK,KAAK,CAAC,WAAW,KAAK,OAAO,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,EAAE;IAC3G;IACA,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,KAAK,CAAC,eAAe,CAAC,CAAC;IACvB,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;MACxC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC;MACzB,SAAS,CAAC,CAAC;IACb;EACF,CAAC;;EAED;EACA,MAAM,WAAW,GAAI,KAAiB,IAAK;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,WAAW,KAAK,OAAO,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EACtH,KAAK,CAAC,cAAc,CAAC,CAAC;EAC1B,CAAC;EAED,MAAM,aAAa,GAAI,KAAiB,IAAK;IAC3C,IAAI,WAAW,KAAK,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;IACtD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;IACtC,IAAI,CAAC,SAAS,EAAE;IAChB,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,SAAS,CAAC,MAAM,CAAC,CAAC;EACpB,CAAC;EAED,OAAO,CAAC,MAAM;IACZ,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;IACtD,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;IACtD,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC;IAClD,OAAO,CAAC,gBAAgB,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1D,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE;MAAE,OAAO,EAAE;IAAM,CAAC,CAAC;IACtE,OAAO,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE;MAAE,OAAO,EAAE;IAAM,CAAC,CAAC;IACpE,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;IAChD,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;IACtD,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC;IAClD,OAAO,CAAC,gBAAgB,CAAC,UAAU,EAAE,aAAa,CAAC;IACnD,SAAS,CAAC,MAAM;MACd,QAAQ,CAAC,KAAK,CAAC,CAAC;MAChB,QAAQ,CAAC,CAAC;MACV,YAAY,CAAC,WAAW,CAAC;MACzB,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;MACzD,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;MACzD,OAAO,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;MACrD,OAAO,CAAC,mBAAmB,CAAC,eAAe,EAAE,eAAe,CAAC;MAC7D,OAAO,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;MACrD,OAAO,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC;MACnD,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;MACnD,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;MACzD,OAAO,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;MACrD,OAAO,CAAC,mBAAmB,CAAC,UAAU,EAAE,aAAa,CAAC;IACxD,CAAC,CAAC;EACJ,CAAC,CAAC;EAEF,yBACG,eAAe;IACd,MAAM,EAAG,IAAI,IAAM,UAAU,GAAG,IAAK;IAAA,IACrC,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,QAAQ;MAAA,OAAE,CAAC,MAAM,CAAC,CAAC;IAAA;IAAA,IACnB,MAAM;MAAA,OAAE,KAAK,CAAC,MAAM;IAAA;IAAA;MAAA,OACb,KAAK,CAAC,KAAK;IAAA;IAAA;MAAA,mDAKH,MAAM,CAAC,CAAC,GAAG,EAAE,YAAG,SAAS,wDAC1B,WAAW,CAAC,CAAC,wDACb,KAAK,CAAC,CAAC,EAAE,SAAS,+CAClB,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,YAAG,SAAS,kDAC5B,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,EAAE,YAAG,SAAS,kEAElB,YAAG,KAAK,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,WAAI,iEACzB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,IAAI,CAAC,CAAC,qCAG9D,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,CAAC;QAAA;QAAA,UACf,OAAO,oDAEK,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,OAAO,GAAG,mBAAmB,GAAG,kBAAkB,CAAC;MAE3G,cAEqC,KAAK,CAAC,QAAQ;IAAA;EAAA;AAI9D;AAEA,eAAe,WAAW","ignoreList":[]}