@adea-ai/ui 0.85.0 → 0.88.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 (239) hide show
  1. package/README.md +17 -1
  2. package/dist/NOTICE +34 -0
  3. package/dist/components/composites/action-button/action-button.d.ts.map +1 -1
  4. package/dist/components/composites/action-button/action-button.js +2 -2
  5. package/dist/components/composites/action-button/action-button.js.map +1 -1
  6. package/dist/components/composites/list-row/list-row.d.ts +6 -3
  7. package/dist/components/composites/list-row/list-row.d.ts.map +1 -1
  8. package/dist/components/composites/list-row/list-row.js +69 -7
  9. package/dist/components/composites/list-row/list-row.js.map +1 -1
  10. package/dist/components/composites/settings/settings.d.ts +9 -11
  11. package/dist/components/composites/settings/settings.d.ts.map +1 -1
  12. package/dist/components/composites/settings/settings.js +48 -33
  13. package/dist/components/composites/settings/settings.js.map +1 -1
  14. package/dist/components/conversation/message-composer.js +1 -1
  15. package/dist/components/conversation/scroll-follow.d.ts.map +1 -1
  16. package/dist/components/conversation/scroll-follow.js +95 -15
  17. package/dist/components/conversation/scroll-follow.js.map +1 -1
  18. package/dist/components/layout/app-shell/index.d.ts +1 -0
  19. package/dist/components/layout/app-shell/index.d.ts.map +1 -1
  20. package/dist/components/layout/app-shell/index.js +2 -1
  21. package/dist/components/layout/app-shell/skip-link.d.ts +11 -0
  22. package/dist/components/layout/app-shell/skip-link.d.ts.map +1 -0
  23. package/dist/components/layout/app-shell/skip-link.js +44 -0
  24. package/dist/components/layout/app-shell/skip-link.js.map +1 -0
  25. package/dist/components/layout/floating-preview/floating-preview.d.ts +12 -0
  26. package/dist/components/layout/floating-preview/floating-preview.d.ts.map +1 -0
  27. package/dist/components/layout/floating-preview/floating-preview.js +283 -0
  28. package/dist/components/layout/floating-preview/floating-preview.js.map +1 -0
  29. package/dist/components/layout/floating-preview/index.d.ts +3 -0
  30. package/dist/components/layout/floating-preview/index.d.ts.map +1 -0
  31. package/dist/components/layout/floating-preview/index.js +3 -0
  32. package/dist/components/layout/floating-preview/model.d.ts +74 -0
  33. package/dist/components/layout/floating-preview/model.d.ts.map +1 -0
  34. package/dist/components/layout/floating-preview/model.js +146 -0
  35. package/dist/components/layout/floating-preview/model.js.map +1 -0
  36. package/dist/components/layout/sidebar-nav/index.d.ts +1 -1
  37. package/dist/components/layout/sidebar-nav/index.d.ts.map +1 -1
  38. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts +18 -2
  39. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts.map +1 -1
  40. package/dist/components/layout/sidebar-nav/sidebar-nav.js +42 -11
  41. package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
  42. package/dist/components/theme/index.d.ts +1 -0
  43. package/dist/components/theme/index.d.ts.map +1 -1
  44. package/dist/components/theme/index.js +2 -1
  45. package/dist/components/theme/theme-mode-toggle.d.ts +10 -0
  46. package/dist/components/theme/theme-mode-toggle.d.ts.map +1 -0
  47. package/dist/components/theme/theme-mode-toggle.js +82 -0
  48. package/dist/components/theme/theme-mode-toggle.js.map +1 -0
  49. package/dist/components/ui/checkbox/checkbox.d.ts +2 -0
  50. package/dist/components/ui/checkbox/checkbox.d.ts.map +1 -1
  51. package/dist/components/ui/checkbox/checkbox.js +24 -3
  52. package/dist/components/ui/checkbox/checkbox.js.map +1 -1
  53. package/dist/components/ui/combobox/combobox.d.ts.map +1 -1
  54. package/dist/components/ui/combobox/combobox.js +41 -4
  55. package/dist/components/ui/combobox/combobox.js.map +1 -1
  56. package/dist/components/ui/combobox/index.d.ts +1 -0
  57. package/dist/components/ui/combobox/index.d.ts.map +1 -1
  58. package/dist/components/ui/combobox/index.js +2 -1
  59. package/dist/components/ui/combobox/value-combobox.d.ts +19 -0
  60. package/dist/components/ui/combobox/value-combobox.d.ts.map +1 -0
  61. package/dist/components/ui/combobox/value-combobox.js +42 -0
  62. package/dist/components/ui/combobox/value-combobox.js.map +1 -0
  63. package/dist/components/ui/empty/empty-state.d.ts +15 -0
  64. package/dist/components/ui/empty/empty-state.d.ts.map +1 -0
  65. package/dist/components/ui/empty/empty-state.js +96 -0
  66. package/dist/components/ui/empty/empty-state.js.map +1 -0
  67. package/dist/components/ui/empty/index.d.ts +1 -0
  68. package/dist/components/ui/empty/index.d.ts.map +1 -1
  69. package/dist/components/ui/empty/index.js +2 -1
  70. package/dist/components/ui/entity-icon/entity-icon.d.ts +4 -1
  71. package/dist/components/ui/entity-icon/entity-icon.d.ts.map +1 -1
  72. package/dist/components/ui/entity-icon/entity-icon.js +37 -13
  73. package/dist/components/ui/entity-icon/entity-icon.js.map +1 -1
  74. package/dist/components/ui/field/field.d.ts +36 -13
  75. package/dist/components/ui/field/field.d.ts.map +1 -1
  76. package/dist/components/ui/field/field.js +146 -24
  77. package/dist/components/ui/field/field.js.map +1 -1
  78. package/dist/components/ui/field/index.d.ts +3 -1
  79. package/dist/components/ui/field/index.d.ts.map +1 -1
  80. package/dist/components/ui/field/index.js +3 -2
  81. package/dist/components/ui/field/number-field.d.ts +19 -0
  82. package/dist/components/ui/field/number-field.d.ts.map +1 -0
  83. package/dist/components/ui/field/number-field.js +76 -0
  84. package/dist/components/ui/field/number-field.js.map +1 -0
  85. package/dist/components/ui/input/index.d.ts +1 -0
  86. package/dist/components/ui/input/index.d.ts.map +1 -1
  87. package/dist/components/ui/input/index.js +2 -1
  88. package/dist/components/ui/input/input-control.d.ts +11 -0
  89. package/dist/components/ui/input/input-control.d.ts.map +1 -0
  90. package/dist/components/ui/input/input-control.js +24 -0
  91. package/dist/components/ui/input/input-control.js.map +1 -0
  92. package/dist/components/ui/input/input.d.ts.map +1 -1
  93. package/dist/components/ui/input/input.js +56 -28
  94. package/dist/components/ui/input/input.js.map +1 -1
  95. package/dist/components/ui/input-group/index.d.ts +1 -0
  96. package/dist/components/ui/input-group/index.d.ts.map +1 -1
  97. package/dist/components/ui/input-group/index.js +2 -1
  98. package/dist/components/ui/input-group/input-group.d.ts.map +1 -1
  99. package/dist/components/ui/input-group/input-group.js +42 -5
  100. package/dist/components/ui/input-group/input-group.js.map +1 -1
  101. package/dist/components/ui/input-group/secret-input-group.d.ts +11 -0
  102. package/dist/components/ui/input-group/secret-input-group.d.ts.map +1 -0
  103. package/dist/components/ui/input-group/secret-input-group.js +67 -0
  104. package/dist/components/ui/input-group/secret-input-group.js.map +1 -0
  105. package/dist/components/ui/native-select/native-select.d.ts.map +1 -1
  106. package/dist/components/ui/native-select/native-select.js +39 -4
  107. package/dist/components/ui/native-select/native-select.js.map +1 -1
  108. package/dist/components/ui/progress/progress.d.ts.map +1 -1
  109. package/dist/components/ui/progress/progress.js +30 -18
  110. package/dist/components/ui/progress/progress.js.map +1 -1
  111. package/dist/components/ui/radio-group/radio-group.d.ts.map +1 -1
  112. package/dist/components/ui/radio-group/radio-group.js +41 -4
  113. package/dist/components/ui/radio-group/radio-group.js.map +1 -1
  114. package/dist/components/ui/switch/switch.d.ts +2 -0
  115. package/dist/components/ui/switch/switch.d.ts.map +1 -1
  116. package/dist/components/ui/switch/switch.js +24 -3
  117. package/dist/components/ui/switch/switch.js.map +1 -1
  118. package/dist/components/ui/tabs/tabs.js +1 -1
  119. package/dist/components/ui/tabs/tabs.js.map +1 -1
  120. package/dist/components/ui/text-link/index.d.ts +2 -0
  121. package/dist/components/ui/text-link/index.d.ts.map +1 -0
  122. package/dist/components/ui/text-link/index.js +2 -0
  123. package/dist/components/ui/text-link/text-link.d.ts +9 -0
  124. package/dist/components/ui/text-link/text-link.d.ts.map +1 -0
  125. package/dist/components/ui/text-link/text-link.js +30 -0
  126. package/dist/components/ui/text-link/text-link.js.map +1 -0
  127. package/dist/components/ui/textarea/textarea.d.ts.map +1 -1
  128. package/dist/components/ui/textarea/textarea.js +41 -4
  129. package/dist/components/ui/textarea/textarea.js.map +1 -1
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +18 -7
  133. package/dist/lib/clipboard.d.ts +3 -0
  134. package/dist/lib/clipboard.d.ts.map +1 -0
  135. package/dist/lib/clipboard.js +35 -0
  136. package/dist/lib/clipboard.js.map +1 -0
  137. package/dist/lib/download.d.ts +3 -0
  138. package/dist/lib/download.d.ts.map +1 -0
  139. package/dist/lib/download.js +31 -0
  140. package/dist/lib/download.js.map +1 -0
  141. package/dist/lib/form-field.d.ts +37 -0
  142. package/dist/lib/form-field.d.ts.map +1 -0
  143. package/dist/lib/form-field.js +47 -0
  144. package/dist/lib/form-field.js.map +1 -0
  145. package/dist/r/app-shell.json +5 -0
  146. package/dist/r/combobox.json +5 -0
  147. package/dist/r/empty.json +10 -1
  148. package/dist/r/field.json +7 -0
  149. package/dist/r/floating-preview.json +30 -0
  150. package/dist/r/input-group.json +6 -0
  151. package/dist/r/input.json +5 -0
  152. package/dist/r/lib.json +15 -0
  153. package/dist/r/list-row.json +1 -0
  154. package/dist/r/registry.json +112 -1
  155. package/dist/r/src/components/composites/action-button/action-button.tsx +5 -1
  156. package/dist/r/src/components/composites/list-row/list-row.tsx +81 -8
  157. package/dist/r/src/components/composites/settings/settings.tsx +67 -37
  158. package/dist/r/src/components/conversation/scroll-follow.ts +109 -15
  159. package/dist/r/src/components/layout/app-shell/index.ts +1 -0
  160. package/dist/r/src/components/layout/app-shell/skip-link.tsx +35 -0
  161. package/dist/r/src/components/layout/floating-preview/floating-preview.tsx +260 -0
  162. package/dist/r/src/components/layout/floating-preview/index.ts +2 -0
  163. package/dist/r/src/components/layout/floating-preview/model.ts +285 -0
  164. package/dist/r/src/components/layout/sidebar-nav/index.ts +2 -0
  165. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +71 -16
  166. package/dist/r/src/components/theme/index.ts +1 -0
  167. package/dist/r/src/components/theme/theme-mode-toggle.tsx +56 -0
  168. package/dist/r/src/components/ui/checkbox/checkbox.tsx +20 -3
  169. package/dist/r/src/components/ui/combobox/combobox.tsx +24 -1
  170. package/dist/r/src/components/ui/combobox/index.ts +1 -0
  171. package/dist/r/src/components/ui/combobox/value-combobox.tsx +38 -0
  172. package/dist/r/src/components/ui/empty/empty-state.tsx +71 -0
  173. package/dist/r/src/components/ui/empty/index.ts +1 -0
  174. package/dist/r/src/components/ui/entity-icon/entity-icon.tsx +33 -2
  175. package/dist/r/src/components/ui/field/field.tsx +102 -5
  176. package/dist/r/src/components/ui/field/index.ts +5 -0
  177. package/dist/r/src/components/ui/field/number-field.tsx +71 -0
  178. package/dist/r/src/components/ui/input/index.ts +1 -0
  179. package/dist/r/src/components/ui/input/input-control.tsx +38 -0
  180. package/dist/r/src/components/ui/input/input.tsx +32 -20
  181. package/dist/r/src/components/ui/input-group/index.ts +1 -0
  182. package/dist/r/src/components/ui/input-group/input-group.tsx +25 -2
  183. package/dist/r/src/components/ui/input-group/secret-input-group.tsx +58 -0
  184. package/dist/r/src/components/ui/native-select/native-select.tsx +27 -1
  185. package/dist/r/src/components/ui/progress/progress.tsx +12 -8
  186. package/dist/r/src/components/ui/radio-group/radio-group.tsx +30 -2
  187. package/dist/r/src/components/ui/switch/switch.tsx +20 -3
  188. package/dist/r/src/components/ui/tabs/tabs.tsx +1 -1
  189. package/dist/r/src/components/ui/text-link/index.ts +2 -0
  190. package/dist/r/src/components/ui/text-link/text-link.tsx +28 -0
  191. package/dist/r/src/components/ui/textarea/textarea.tsx +24 -1
  192. package/dist/r/src/lib/clipboard.ts +41 -0
  193. package/dist/r/src/lib/download.ts +29 -0
  194. package/dist/r/src/lib/form-field.ts +93 -0
  195. package/dist/r/text-link.json +22 -0
  196. package/dist/r/theming.json +6 -0
  197. package/package.json +1 -1
  198. package/registry.json +112 -1
  199. package/src/components/composites/action-button/action-button.tsx +5 -1
  200. package/src/components/composites/list-row/list-row.tsx +81 -8
  201. package/src/components/composites/settings/settings.tsx +67 -37
  202. package/src/components/conversation/scroll-follow.ts +109 -15
  203. package/src/components/layout/app-shell/index.ts +1 -0
  204. package/src/components/layout/app-shell/skip-link.tsx +35 -0
  205. package/src/components/layout/floating-preview/floating-preview.tsx +260 -0
  206. package/src/components/layout/floating-preview/index.ts +2 -0
  207. package/src/components/layout/floating-preview/model.ts +285 -0
  208. package/src/components/layout/sidebar-nav/index.ts +2 -0
  209. package/src/components/layout/sidebar-nav/sidebar-nav.tsx +71 -16
  210. package/src/components/theme/index.ts +1 -0
  211. package/src/components/theme/theme-mode-toggle.tsx +56 -0
  212. package/src/components/ui/checkbox/checkbox.tsx +20 -3
  213. package/src/components/ui/combobox/combobox.tsx +24 -1
  214. package/src/components/ui/combobox/index.ts +1 -0
  215. package/src/components/ui/combobox/value-combobox.tsx +38 -0
  216. package/src/components/ui/empty/empty-state.tsx +71 -0
  217. package/src/components/ui/empty/index.ts +1 -0
  218. package/src/components/ui/entity-icon/entity-icon.tsx +33 -2
  219. package/src/components/ui/field/field.tsx +102 -5
  220. package/src/components/ui/field/index.ts +5 -0
  221. package/src/components/ui/field/number-field.tsx +71 -0
  222. package/src/components/ui/input/index.ts +1 -0
  223. package/src/components/ui/input/input-control.tsx +38 -0
  224. package/src/components/ui/input/input.tsx +32 -20
  225. package/src/components/ui/input-group/index.ts +1 -0
  226. package/src/components/ui/input-group/input-group.tsx +25 -2
  227. package/src/components/ui/input-group/secret-input-group.tsx +58 -0
  228. package/src/components/ui/native-select/native-select.tsx +27 -1
  229. package/src/components/ui/progress/progress.tsx +12 -8
  230. package/src/components/ui/radio-group/radio-group.tsx +30 -2
  231. package/src/components/ui/switch/switch.tsx +20 -3
  232. package/src/components/ui/tabs/tabs.tsx +1 -1
  233. package/src/components/ui/text-link/index.ts +2 -0
  234. package/src/components/ui/text-link/text-link.tsx +28 -0
  235. package/src/components/ui/textarea/textarea.tsx +24 -1
  236. package/src/index.ts +3 -0
  237. package/src/lib/clipboard.ts +41 -0
  238. package/src/lib/download.ts +29 -0
  239. package/src/lib/form-field.ts +93 -0
@@ -1,7 +1,7 @@
1
1
  import { cn } from "../../lib/utils.js";
2
2
  import { Button } from "../ui/button/button.js";
3
- import { Kbd } from "../ui/kbd/kbd.js";
4
3
  import { Spinner } from "../ui/spinner/spinner.js";
4
+ import { Kbd } from "../ui/kbd/kbd.js";
5
5
  import { Textarea } from "../ui/textarea/textarea.js";
6
6
  import { createComposerImeGuard } from "./ime-guard.js";
7
7
  import { className, createComponent, effect, insert, memo, mergeProps, spread, template } from "solid-js/web";
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-follow.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/scroll-follow.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAA;AAezE,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,OAAO,EAAE,MAAM,OAAO,CAAA;IACtB,QAAQ,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAClC,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,eAAe,CAAC,EAAE,MAAM,2BAA2B,GAAG,SAAS,CAAA;IAC/D,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,IAAI,CAAA;CACnE;;;;4BAsH2B,cAAc;2BAGf,cAAc;EAIxC"}
1
+ {"version":3,"file":"scroll-follow.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/scroll-follow.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAA;AAgBzE,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,OAAO,EAAE,MAAM,OAAO,CAAA;IACtB,QAAQ,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAClC,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,eAAe,CAAC,EAAE,MAAM,2BAA2B,GAAG,SAAS,CAAA;IAC/D,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,IAAI,CAAA;CACnE;;;;4BAmN2B,cAAc;2BAGf,cAAc;EAIxC"}
@@ -6,6 +6,7 @@ var geometry = (element) => ({
6
6
  scrollHeight: element.scrollHeight,
7
7
  clientHeight: element.clientHeight
8
8
  });
9
+ var noop = () => {};
9
10
  /** Internal plain-scroller binding; host-owned restoration can disable follow. */
10
11
  function createScrollFollow(options) {
11
12
  const [atBottom, setAtBottom] = createSignal(true);
@@ -16,6 +17,9 @@ function createScrollFollow(options) {
16
17
  let lastWriteClientHeight = -1;
17
18
  let previousTop = -1;
18
19
  let lastScrollClientHeight = 0;
20
+ let pendingRestore;
21
+ let pendingRestoreUserIntent = false;
22
+ let removeRestoreIntentListeners = noop;
19
23
  const reportPosition = () => {
20
24
  if (scroller) untrack(() => options.onPositionChange?.({
21
25
  top: scroller.scrollTop,
@@ -25,12 +29,12 @@ function createScrollFollow(options) {
25
29
  onCleanup(reportPosition);
26
30
  const writePin = (element, target) => {
27
31
  element.scrollTop = target;
28
- lastWriteTop = target;
32
+ lastWriteTop = element.scrollTop;
29
33
  lastWriteClientHeight = element.clientHeight;
30
- previousTop = target;
34
+ previousTop = element.scrollTop;
31
35
  };
32
36
  const pinAuto = () => {
33
- if (!scroller || !options.enabled()) return;
37
+ if (!scroller || !options.enabled() || pendingRestore) return;
34
38
  const geom = geometry(scroller);
35
39
  const result = evaluateAutoPin({
36
40
  stick,
@@ -49,6 +53,17 @@ function createScrollFollow(options) {
49
53
  };
50
54
  const onScroll = () => {
51
55
  if (!scroller) return;
56
+ if (pendingRestore) {
57
+ const maxTop = Math.max(0, scroller.scrollHeight - scroller.clientHeight);
58
+ const clampedFromTop = Math.min(pendingRestore.fromTop, maxTop);
59
+ if (pendingRestore.fromTop - clampedFromTop > 1 && Math.abs(scroller.scrollTop - clampedFromTop) <= 1) return;
60
+ if (!pendingRestoreUserIntent) return;
61
+ cancelAnimationFrame(pendingRestore.frame);
62
+ pendingRestore = void 0;
63
+ pendingRestoreUserIntent = false;
64
+ removeRestoreIntentListeners();
65
+ removeRestoreIntentListeners = noop;
66
+ }
52
67
  if (!options.enabled()) {
53
68
  reportPosition();
54
69
  return;
@@ -84,7 +99,20 @@ function createScrollFollow(options) {
84
99
  createEffect(() => {
85
100
  options.resetKey();
86
101
  const enabled = options.enabled();
87
- const initial = untrack(() => options.initialPosition?.());
102
+ const candidate = untrack(() => options.initialPosition?.());
103
+ const initial = candidate && Number.isFinite(candidate.top) && candidate.top >= 0 ? candidate : void 0;
104
+ let scheduledRestore;
105
+ let observer;
106
+ onCleanup(() => {
107
+ if (scheduledRestore) {
108
+ cancelAnimationFrame(scheduledRestore.frame);
109
+ if (pendingRestore === scheduledRestore) pendingRestore = void 0;
110
+ }
111
+ pendingRestoreUserIntent = false;
112
+ removeRestoreIntentListeners();
113
+ removeRestoreIntentListeners = noop;
114
+ observer?.disconnect();
115
+ });
88
116
  stick = true;
89
117
  lastWriteTop = -1;
90
118
  lastWriteClientHeight = -1;
@@ -92,19 +120,71 @@ function createScrollFollow(options) {
92
120
  lastScrollClientHeight = 0;
93
121
  setAtBottom(true);
94
122
  if (!enabled || !scroller) return;
95
- if (initial && Number.isFinite(initial.top) && initial.top >= 0) {
96
- stick = initial.following;
97
- writePin(scroller, stick ? bottomTarget(geometry(scroller)) : initial.top);
98
- previousTop = scroller.scrollTop;
99
- lastScrollClientHeight = scroller.clientHeight;
100
- } else writePin(scroller, bottomTarget(geometry(scroller)));
123
+ if (initial) stick = enabled && initial.following;
124
+ const observe = () => {
125
+ if (!enabled || typeof ResizeObserver === "undefined") return;
126
+ observer = new ResizeObserver(pinAuto);
127
+ observer.observe(scroller);
128
+ if (content) observer.observe(content);
129
+ };
130
+ const watchRestoreIntent = () => {
131
+ const element = scroller;
132
+ if (!element) return;
133
+ const markIntent = (event) => {
134
+ if (!pendingRestore) return;
135
+ if (event.type === "pointerdown" && event.target !== element) return;
136
+ if (event.type === "keydown") {
137
+ if (event.target !== element) return;
138
+ const key = event.key;
139
+ if (![
140
+ "ArrowDown",
141
+ "ArrowUp",
142
+ "PageDown",
143
+ "PageUp",
144
+ "Home",
145
+ "End",
146
+ " "
147
+ ].includes(key)) return;
148
+ }
149
+ pendingRestoreUserIntent = true;
150
+ };
151
+ element.addEventListener("wheel", markIntent, { passive: true });
152
+ element.addEventListener("pointerdown", markIntent);
153
+ element.addEventListener("keydown", markIntent);
154
+ removeRestoreIntentListeners = () => {
155
+ element.removeEventListener("wheel", markIntent);
156
+ element.removeEventListener("pointerdown", markIntent);
157
+ element.removeEventListener("keydown", markIntent);
158
+ };
159
+ };
160
+ if (initial && !stick) {
161
+ const restore = {
162
+ frame: 0,
163
+ fromTop: scroller.scrollTop,
164
+ target: initial.top
165
+ };
166
+ scheduledRestore = restore;
167
+ pendingRestore = restore;
168
+ pendingRestoreUserIntent = false;
169
+ watchRestoreIntent();
170
+ observe();
171
+ restore.frame = requestAnimationFrame(() => {
172
+ if (pendingRestore !== restore || !scroller) return;
173
+ pendingRestore = void 0;
174
+ pendingRestoreUserIntent = false;
175
+ removeRestoreIntentListeners();
176
+ removeRestoreIntentListeners = noop;
177
+ writePin(scroller, restore.target);
178
+ setAtBottom(computeAtBottom(geometry(scroller), options.threshold()));
179
+ reportPosition();
180
+ });
181
+ return;
182
+ }
183
+ if (!initial && enabled) writePin(scroller, bottomTarget(geometry(scroller)));
184
+ else if (initial && stick) writePin(scroller, bottomTarget(geometry(scroller)));
101
185
  setAtBottom(computeAtBottom(geometry(scroller), options.threshold()));
102
186
  reportPosition();
103
- if (typeof ResizeObserver === "undefined") return;
104
- const observer = new ResizeObserver(pinAuto);
105
- observer.observe(scroller);
106
- if (content) observer.observe(content);
107
- onCleanup(() => observer.disconnect());
187
+ observe();
108
188
  });
109
189
  return {
110
190
  atBottom,
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-follow.js","names":[],"sources":["../../../src/components/conversation/scroll-follow.ts"],"sourcesContent":["/*\n * Substantially translated from KiroCrew website/src/app-sdk/useChatScrollFollow.ts,\n * pinned at 283e136c0f902e965a535a7c9548c57c7504fed0.\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * This product includes software developed at Amazon.com, Inc. (https://www.amazon.com/).\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy at http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software distributed\n * under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n * CONDITIONS OF ANY KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations under the License.\n * Solid owner effects replace React refs/effects; native geometry and the\n * content/viewport observer contract are retained. No session store is copied.\n */\nimport { createEffect, createSignal, onCleanup, untrack } from 'solid-js'\nimport type { ConversationReadingPosition } from './conversation-surface'\nimport {\n bottomTarget,\n computeAtBottom,\n evaluateAutoPin,\n isSelfScroll,\n resolveUserScrollStick,\n} from './scroll-follow-core'\n\nconst geometry = (element: HTMLDivElement) => ({\n scrollTop: element.scrollTop,\n scrollHeight: element.scrollHeight,\n clientHeight: element.clientHeight,\n})\n\n/** Internal plain-scroller binding; host-owned restoration can disable follow. */\nexport function createScrollFollow(options: {\n enabled: () => boolean\n resetKey: () => string | undefined\n threshold: () => number\n initialPosition?: () => ConversationReadingPosition | undefined\n onPositionChange?: (position: ConversationReadingPosition) => void\n}) {\n const [atBottom, setAtBottom] = createSignal(true)\n let scroller: HTMLDivElement | undefined\n let content: HTMLDivElement | undefined\n let stick = true\n let lastWriteTop = -1\n let lastWriteClientHeight = -1\n let previousTop = -1\n let lastScrollClientHeight = 0\n const reportPosition = () => {\n if (scroller)\n untrack(() =>\n options.onPositionChange?.({\n top: scroller!.scrollTop,\n following: options.enabled() && stick,\n })\n )\n }\n onCleanup(reportPosition)\n\n const writePin = (element: HTMLDivElement, target: number) => {\n // Instant writes keep the self-scroll reference synchronized. A smooth\n // animation would produce intermediate positions that resemble user input.\n element.scrollTop = target\n lastWriteTop = target\n lastWriteClientHeight = element.clientHeight\n previousTop = target\n }\n const pinAuto = () => {\n if (!scroller || !options.enabled()) return\n const geom = geometry(scroller)\n const result = evaluateAutoPin({\n stick,\n geom,\n lastWriteTop,\n viewportShrink: lastWriteClientHeight >= 0 ? lastWriteClientHeight - geom.clientHeight : 0,\n })\n stick = result.stick\n if (result.pin) writePin(scroller, result.target)\n else if (result.stick) {\n lastWriteTop = result.target\n lastWriteClientHeight = geom.clientHeight\n }\n setAtBottom(computeAtBottom(geometry(scroller), options.threshold()))\n reportPosition()\n }\n const onScroll = () => {\n if (!scroller) return\n if (!options.enabled()) {\n reportPosition()\n return\n }\n const geom = geometry(scroller)\n setAtBottom(computeAtBottom(geom, options.threshold()))\n if (!isSelfScroll(geom.scrollTop, lastWriteTop)) {\n stick = resolveUserScrollStick({\n stick,\n followOutput: true,\n scrollTop: geom.scrollTop,\n prevScrollTop: previousTop,\n geom,\n viewportGrowth: lastScrollClientHeight > 0 ? geom.clientHeight - lastScrollClientHeight : 0,\n })\n if (!stick) {\n lastWriteTop = -1\n lastWriteClientHeight = -1\n }\n }\n previousTop = geom.scrollTop\n // This baseline belongs only to scroll events, not observer callbacks.\n // Advancing it during resize would erase the viewport-clamp evidence.\n lastScrollClientHeight = geom.clientHeight\n reportPosition()\n }\n const jump = () => {\n if (!scroller || !options.enabled()) return\n stick = true\n writePin(scroller, bottomTarget(geometry(scroller)))\n setAtBottom(true)\n reportPosition()\n // The jump control disappears at the bottom. Return its keyboard focus to\n // the transcript instead of leaving the reader on a detached button.\n scroller.focus({ preventScroll: true })\n }\n\n createEffect(() => {\n options.resetKey()\n const enabled = options.enabled()\n // Capture before any reporting callback can replace the host snapshot.\n const initial = untrack(() => options.initialPosition?.())\n stick = true\n lastWriteTop = -1\n lastWriteClientHeight = -1\n previousTop = -1\n lastScrollClientHeight = 0\n setAtBottom(true)\n if (!enabled || !scroller) return\n // Snapshot updates must not become another positioning owner. Consume the\n // host's snapshot only at entry/reset, then native reader intent owns follow.\n if (initial && Number.isFinite(initial.top) && initial.top >= 0) {\n stick = initial.following\n writePin(scroller, stick ? bottomTarget(geometry(scroller)) : initial.top)\n previousTop = scroller.scrollTop\n lastScrollClientHeight = scroller.clientHeight\n } else writePin(scroller, bottomTarget(geometry(scroller)))\n setAtBottom(computeAtBottom(geometry(scroller), options.threshold()))\n reportPosition()\n if (typeof ResizeObserver === 'undefined') return\n const observer = new ResizeObserver(pinAuto)\n observer.observe(scroller)\n if (content) observer.observe(content)\n onCleanup(() => observer.disconnect())\n })\n\n return {\n atBottom,\n onScroll,\n jump,\n bindScroller: (element: HTMLDivElement) => {\n scroller = element\n },\n bindContent: (element: HTMLDivElement) => {\n content = element\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scroll-follow.js","names":[],"sources":["../../../src/components/conversation/scroll-follow.ts"],"sourcesContent":["/*\n * Substantially translated from KiroCrew website/src/app-sdk/useChatScrollFollow.ts,\n * pinned at 283e136c0f902e965a535a7c9548c57c7504fed0.\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * This product includes software developed at Amazon.com, Inc. (https://www.amazon.com/).\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy at http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software distributed\n * under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n * CONDITIONS OF ANY KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations under the License.\n * Solid owner effects replace React refs/effects; native geometry and the\n * content/viewport observer contract are retained. No session store is copied.\n */\nimport { createEffect, createSignal, onCleanup, untrack } from 'solid-js'\nimport type { ConversationReadingPosition } from './conversation-surface'\nimport {\n bottomTarget,\n computeAtBottom,\n evaluateAutoPin,\n isSelfScroll,\n resolveUserScrollStick,\n} from './scroll-follow-core'\n\nconst geometry = (element: HTMLDivElement) => ({\n scrollTop: element.scrollTop,\n scrollHeight: element.scrollHeight,\n clientHeight: element.clientHeight,\n})\nconst noop = () => {}\n\n/** Internal plain-scroller binding; host-owned restoration can disable follow. */\nexport function createScrollFollow(options: {\n enabled: () => boolean\n resetKey: () => string | undefined\n threshold: () => number\n initialPosition?: () => ConversationReadingPosition | undefined\n onPositionChange?: (position: ConversationReadingPosition) => void\n}) {\n const [atBottom, setAtBottom] = createSignal(true)\n let scroller: HTMLDivElement | undefined\n let content: HTMLDivElement | undefined\n let stick = true\n let lastWriteTop = -1\n let lastWriteClientHeight = -1\n let previousTop = -1\n let lastScrollClientHeight = 0\n let pendingRestore: { frame: number; fromTop: number; target: number } | undefined\n let pendingRestoreUserIntent = false\n let removeRestoreIntentListeners = noop\n const reportPosition = () => {\n if (scroller)\n untrack(() =>\n options.onPositionChange?.({\n top: scroller!.scrollTop,\n following: options.enabled() && stick,\n })\n )\n }\n onCleanup(reportPosition)\n\n const writePin = (element: HTMLDivElement, target: number) => {\n // Instant writes keep the self-scroll reference synchronized. A smooth\n // animation would produce intermediate positions that resemble user input.\n element.scrollTop = target\n lastWriteTop = element.scrollTop\n lastWriteClientHeight = element.clientHeight\n previousTop = element.scrollTop\n }\n const pinAuto = () => {\n if (!scroller || !options.enabled() || pendingRestore) return\n const geom = geometry(scroller)\n const result = evaluateAutoPin({\n stick,\n geom,\n lastWriteTop,\n viewportShrink: lastWriteClientHeight >= 0 ? lastWriteClientHeight - geom.clientHeight : 0,\n })\n stick = result.stick\n if (result.pin) writePin(scroller, result.target)\n else if (result.stick) {\n lastWriteTop = result.target\n lastWriteClientHeight = geom.clientHeight\n }\n setAtBottom(computeAtBottom(geometry(scroller), options.threshold()))\n reportPosition()\n }\n const onScroll = () => {\n if (!scroller) return\n if (pendingRestore) {\n // A reset can clamp the outgoing offset while the incoming rows are\n // shorter. That notification is layout, not reader intent, and must not\n // cancel the snapshot waiting for the new rows to commit.\n const maxTop = Math.max(0, scroller.scrollHeight - scroller.clientHeight)\n const clampedFromTop = Math.min(pendingRestore.fromTop, maxTop)\n if (\n pendingRestore.fromTop - clampedFromTop > 1 &&\n Math.abs(scroller.scrollTop - clampedFromTop) <= 1\n )\n return\n // An unexplained offset change can also be a browser clamp. Only actual\n // user scroll intent followed by a non-clamp movement cancels restoration.\n if (!pendingRestoreUserIntent) return\n cancelAnimationFrame(pendingRestore.frame)\n pendingRestore = undefined\n pendingRestoreUserIntent = false\n removeRestoreIntentListeners()\n removeRestoreIntentListeners = noop\n }\n if (!options.enabled()) {\n reportPosition()\n return\n }\n const geom = geometry(scroller)\n setAtBottom(computeAtBottom(geom, options.threshold()))\n if (!isSelfScroll(geom.scrollTop, lastWriteTop)) {\n stick = resolveUserScrollStick({\n stick,\n followOutput: true,\n scrollTop: geom.scrollTop,\n prevScrollTop: previousTop,\n geom,\n viewportGrowth: lastScrollClientHeight > 0 ? geom.clientHeight - lastScrollClientHeight : 0,\n })\n if (!stick) {\n lastWriteTop = -1\n lastWriteClientHeight = -1\n }\n }\n previousTop = geom.scrollTop\n // This baseline belongs only to scroll events, not observer callbacks.\n // Advancing it during resize would erase the viewport-clamp evidence.\n lastScrollClientHeight = geom.clientHeight\n reportPosition()\n }\n const jump = () => {\n if (!scroller || !options.enabled()) return\n stick = true\n writePin(scroller, bottomTarget(geometry(scroller)))\n setAtBottom(true)\n reportPosition()\n // The jump control disappears at the bottom. Return its keyboard focus to\n // the transcript instead of leaving the reader on a detached button.\n scroller.focus({ preventScroll: true })\n }\n\n createEffect(() => {\n options.resetKey()\n const enabled = options.enabled()\n // Capture before any reporting callback can replace the host snapshot.\n const candidate = untrack(() => options.initialPosition?.())\n const initial =\n candidate && Number.isFinite(candidate.top) && candidate.top >= 0 ? candidate : undefined\n let scheduledRestore: typeof pendingRestore\n let observer: ResizeObserver | undefined\n onCleanup(() => {\n if (scheduledRestore) {\n cancelAnimationFrame(scheduledRestore.frame)\n if (pendingRestore === scheduledRestore) pendingRestore = undefined\n }\n pendingRestoreUserIntent = false\n removeRestoreIntentListeners()\n removeRestoreIntentListeners = noop\n observer?.disconnect()\n })\n stick = true\n lastWriteTop = -1\n lastWriteClientHeight = -1\n previousTop = -1\n lastScrollClientHeight = 0\n setAtBottom(true)\n if (!enabled || !scroller) return\n // Snapshot updates must not become another positioning owner. Consume the\n // host's snapshot only at entry/reset, then native reader intent owns follow.\n if (initial) {\n stick = enabled && initial.following\n }\n\n const observe = () => {\n if (!enabled || typeof ResizeObserver === 'undefined') return\n observer = new ResizeObserver(pinAuto)\n observer.observe(scroller!)\n if (content) observer.observe(content)\n }\n\n const watchRestoreIntent = () => {\n const element = scroller\n if (!element) return\n const markIntent = (event: Event) => {\n if (!pendingRestore) return\n if (event.type === 'pointerdown' && event.target !== element) return\n if (event.type === 'keydown') {\n if (event.target !== element) return\n const key = (event as KeyboardEvent).key\n if (!['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp', 'Home', 'End', ' '].includes(key))\n return\n }\n pendingRestoreUserIntent = true\n }\n element.addEventListener('wheel', markIntent, { passive: true })\n element.addEventListener('pointerdown', markIntent)\n element.addEventListener('keydown', markIntent)\n removeRestoreIntentListeners = () => {\n element.removeEventListener('wheel', markIntent)\n element.removeEventListener('pointerdown', markIntent)\n element.removeEventListener('keydown', markIntent)\n }\n }\n\n if (initial && !stick) {\n // The identity effect can run before Solid has inserted the new rows. A\n // synchronous write is clamped by the outgoing short transcript, so defer\n // restoration until the browser has committed the new content and layout.\n const restore = {\n frame: 0,\n fromTop: scroller.scrollTop,\n target: initial.top,\n }\n scheduledRestore = restore\n pendingRestore = restore\n pendingRestoreUserIntent = false\n watchRestoreIntent()\n // Keep resize observation alive during the pending frame. Its callback is\n // guarded above, and remains active if user input cancels restoration.\n observe()\n restore.frame = requestAnimationFrame(() => {\n if (pendingRestore !== restore || !scroller) return\n pendingRestore = undefined\n pendingRestoreUserIntent = false\n removeRestoreIntentListeners()\n removeRestoreIntentListeners = noop\n writePin(scroller, restore.target)\n setAtBottom(computeAtBottom(geometry(scroller), options.threshold()))\n reportPosition()\n })\n return\n }\n\n if (!initial && enabled) writePin(scroller, bottomTarget(geometry(scroller)))\n else if (initial && stick) writePin(scroller, bottomTarget(geometry(scroller)))\n setAtBottom(computeAtBottom(geometry(scroller), options.threshold()))\n reportPosition()\n observe()\n })\n\n return {\n atBottom,\n onScroll,\n jump,\n bindScroller: (element: HTMLDivElement) => {\n scroller = element\n },\n bindContent: (element: HTMLDivElement) => {\n content = element\n },\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,3 @@
1
1
  export { AppShell, AppShellBody, AppShellContent, AppShellMain } from './app-shell';
2
+ export { SkipLink } from './skip-link';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/app-shell/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/app-shell/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACnF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA"}
@@ -1,2 +1,3 @@
1
1
  import { AppShell, AppShellBody, AppShellContent, AppShellMain } from "./app-shell.js";
2
- export { AppShell, AppShellBody, AppShellContent, AppShellMain };
2
+ import { SkipLink } from "./skip-link.js";
3
+ export { AppShell, AppShellBody, AppShellContent, AppShellMain, SkipLink };
@@ -0,0 +1,11 @@
1
+ import type { ComponentProps } from 'solid-js';
2
+ /**
3
+ * A keyboard-first link to the main content region.
4
+ *
5
+ * Place it before the shell's navigation and set the destination element's
6
+ * `id` to match `href`. The link stays translated above the viewport until it
7
+ * receives focus, then moves into view. Its text remains available to assistive
8
+ * technology while it is visually hidden.
9
+ */
10
+ export declare function SkipLink(props: ComponentProps<'a'>): import("solid-js").JSX.Element;
11
+ //# sourceMappingURL=skip-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skip-link.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/app-shell/skip-link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAI9C;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,kCAsBlD"}
@@ -0,0 +1,44 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { insert, memo, mergeProps, spread, template } from "solid-js/web";
3
+ import { splitProps } from "solid-js";
4
+ //#region src/components/layout/app-shell/skip-link.tsx
5
+ var _tmpl$ = /*#__PURE__*/ template(`<a data-slot=skip-link>`);
6
+ /**
7
+ * A keyboard-first link to the main content region.
8
+ *
9
+ * Place it before the shell's navigation and set the destination element's
10
+ * `id` to match `href`. The link stays translated above the viewport until it
11
+ * receives focus, then moves into view. Its text remains available to assistive
12
+ * technology while it is visually hidden.
13
+ */
14
+ function SkipLink(props) {
15
+ const [local, rest] = splitProps(props, [
16
+ "class",
17
+ "children",
18
+ "href",
19
+ "tabIndex"
20
+ ]);
21
+ return (() => {
22
+ var _el$ = _tmpl$();
23
+ spread(_el$, mergeProps({
24
+ get ["class"]() {
25
+ return cn("fixed top-0 start-2 z-(--z-toast) -translate-y-full", "inline-flex items-center rounded-md border border-border bg-background", "px-control-md py-2 text-sm font-medium text-foreground shadow-lg", "underline decoration-2 underline-offset-2 outline-none transition-transform duration-150", "focus:translate-y-0 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle", "motion-reduce:transition-none", local.class);
26
+ },
27
+ get href() {
28
+ return local.href ?? "#main-content";
29
+ },
30
+ get tabIndex() {
31
+ return local.tabIndex ?? 0;
32
+ }
33
+ }, rest), false, true);
34
+ insert(_el$, (() => {
35
+ var _c$ = memo(() => local.children === void 0);
36
+ return () => _c$() ? "Skip to main content" : local.children;
37
+ })());
38
+ return _el$;
39
+ })();
40
+ }
41
+ //#endregion
42
+ export { SkipLink };
43
+
44
+ //# sourceMappingURL=skip-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skip-link.js","names":["ComponentProps","splitProps","cn","SkipLink","props","local","rest","_el$","_tmpl$","_$spread","_$mergeProps","class","href","tabIndex","_$insert","_c$","_$memo","children","undefined","_$mergeProps","_$memo"],"sources":["../../../../src/components/layout/app-shell/skip-link.tsx"],"sourcesContent":["import type { ComponentProps } from 'solid-js'\nimport { splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * A keyboard-first link to the main content region.\n *\n * Place it before the shell's navigation and set the destination element's\n * `id` to match `href`. The link stays translated above the viewport until it\n * receives focus, then moves into view. Its text remains available to assistive\n * technology while it is visually hidden.\n */\nexport function SkipLink(props: ComponentProps<'a'>) {\n const [local, rest] = splitProps(props, ['class', 'children', 'href', 'tabIndex'])\n\n return (\n <a\n data-slot=\"skip-link\"\n class={cn(\n 'fixed top-0 start-2 z-(--z-toast) -translate-y-full',\n 'inline-flex items-center rounded-md border border-border bg-background',\n 'px-control-md py-2 text-sm font-medium text-foreground shadow-lg',\n 'underline decoration-2 underline-offset-2 outline-none transition-transform duration-150',\n 'focus:translate-y-0 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'motion-reduce:transition-none',\n local.class\n )}\n href={local.href ?? '#main-content'}\n tabIndex={local.tabIndex ?? 0}\n {...rest}\n >\n {local.children === undefined ? 'Skip to main content' : local.children}\n </a>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgBG,SAASC,OAA4B;CACnD,MAAM,CAACC,OAAOC,QAAQL,WAAWG,OAAO;EAAC;EAAS;EAAY;EAAQ;CAAU,CAAC;CAEjF,cAAA;EAAA,IAAAG,OAAAC,OAAA;EAAAC,OAAAF,MAAAG,WAAA;GAAA,KAAA,WAAA;IAAA,OAGWR,GACL,uDACA,0EACA,oEACA,4FACA,wGACA,iCACAG,MAAMM,KACR;GAAC;GAAA,IACDC,OAAI;IAAA,OAAEP,MAAMO,QAAQ;GAAe;GAAA,IACnCC,WAAQ;IAAA,OAAER,MAAMQ,YAAY;GAAC;EAAA,GACzBP,IAAI,GAAA,OAAA,IAAA;EAAAQ,OAAAP,aAAA;GAAA,IAAAQ,MAAAC,WAEPX,MAAMY,aAAaC,KAAAA,CAAS;GAAA,aAA5BH,IAAA,IAA+B,yBAAyBV,MAAMY;EAAQ,EAAA,CAAA,CAAA;EAAA,OAAAV;CAAA,EAAA,CAAA;AAG7E"}
@@ -0,0 +1,12 @@
1
+ import { type JSX } from 'solid-js';
2
+ import { type FloatingPreviewSize } from './model';
3
+ export type FloatingPreviewProps = {
4
+ label: string;
5
+ source: FloatingPreviewSize;
6
+ onClose?: () => void;
7
+ actions?: JSX.Element;
8
+ children: JSX.Element;
9
+ };
10
+ /** A host-bounded movable preview frame. Content and actions remain caller-owned. */
11
+ export declare function FloatingPreview(props: FloatingPreviewProps): JSX.Element;
12
+ //# sourceMappingURL=floating-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating-preview.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/floating-preview/floating-preview.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAIvF,OAAO,EAGL,KAAK,mBAAmB,EAGzB,MAAM,SAAS,CAAA;AAiDhB,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,mBAAmB,CAAA;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB,CAAA;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,eA+L1D"}
@@ -0,0 +1,283 @@
1
+ import { ActionButton } from "../../composites/action-button/action-button.js";
2
+ import { ScrollArea } from "../../ui/scroll-area/scroll-area.js";
3
+ import { resizeFloatingPreview, resolveFloatingPreviewFrame } from "./model.js";
4
+ import { createComponent, effect, insert, memo, setAttribute, setStyleProperty, template, use } from "solid-js/web";
5
+ import { Move, X } from "lucide-solid";
6
+ import { createEffect, createSignal, on, onCleanup, onMount } from "solid-js";
7
+ //#region src/components/layout/floating-preview/floating-preview.tsx
8
+ var _tmpl$ = /*#__PURE__*/ template(`<div class="pointer-events-none absolute inset-0 z-(--z-sticky) overflow-hidden"><section class="pointer-events-auto absolute flex flex-col overflow-visible rounded-lg border border-border bg-card text-card-foreground shadow-lg"><header class="flex h-control-sm items-center gap-1 border-b border-border p-1"><div class="flex items-center gap-1">`);
9
+ var _tmpl$2 = /*#__PURE__*/ template(`<span aria-hidden=true>`);
10
+ var directions = [
11
+ {
12
+ direction: "north",
13
+ class: "absolute -top-3 right-6 left-6 h-control-xs w-auto cursor-ns-resize touch-none",
14
+ glyph: "↕"
15
+ },
16
+ {
17
+ direction: "south",
18
+ class: "absolute -bottom-3 right-6 left-6 h-control-xs w-auto cursor-ns-resize touch-none",
19
+ glyph: "↕"
20
+ },
21
+ {
22
+ direction: "east",
23
+ class: "absolute -right-3 top-6 bottom-6 w-6 h-auto cursor-ew-resize touch-none",
24
+ glyph: "↔"
25
+ },
26
+ {
27
+ direction: "west",
28
+ class: "absolute -left-3 top-6 bottom-6 w-6 h-auto cursor-ew-resize touch-none",
29
+ glyph: "↔"
30
+ },
31
+ {
32
+ direction: "northwest",
33
+ class: "absolute -top-3 -left-3 size-control-xs cursor-nwse-resize touch-none",
34
+ glyph: "↖"
35
+ },
36
+ {
37
+ direction: "northeast",
38
+ class: "absolute -top-3 -right-3 size-control-xs cursor-nesw-resize touch-none",
39
+ glyph: "↗"
40
+ },
41
+ {
42
+ direction: "southwest",
43
+ class: "absolute -bottom-3 -left-3 size-control-xs cursor-nesw-resize touch-none",
44
+ glyph: "↙"
45
+ },
46
+ {
47
+ direction: "southeast",
48
+ class: "absolute -bottom-3 -right-3 size-control-xs cursor-nwse-resize touch-none",
49
+ glyph: "↘"
50
+ }
51
+ ];
52
+ /** A host-bounded movable preview frame. Content and actions remain caller-owned. */
53
+ function FloatingPreview(props) {
54
+ const [frame, setFrame] = createSignal({
55
+ x: 0,
56
+ y: 0,
57
+ width: 1,
58
+ height: 1
59
+ });
60
+ let bounds;
61
+ let observer;
62
+ let gesture;
63
+ const measure = () => {
64
+ const rect = bounds?.getBoundingClientRect();
65
+ if (!rect) return;
66
+ setFrame((current) => resolveFloatingPreviewFrame({
67
+ width: current.width > 1 ? current.width : null,
68
+ position: current.width > 1 ? {
69
+ x: current.x,
70
+ y: current.y
71
+ } : null,
72
+ source: props.source,
73
+ container: {
74
+ width: rect.width,
75
+ height: rect.height
76
+ }
77
+ }));
78
+ };
79
+ createEffect(on(() => [props.source.width, props.source.height], () => measure(), { defer: true }));
80
+ onMount(() => {
81
+ if (bounds) {
82
+ observer = new ResizeObserver(measure);
83
+ observer.observe(bounds);
84
+ measure();
85
+ }
86
+ });
87
+ onCleanup(() => observer?.disconnect());
88
+ function start(event, direction) {
89
+ if (event.button !== 0 || gesture) return;
90
+ event.preventDefault();
91
+ event.stopPropagation();
92
+ gesture = {
93
+ id: event.pointerId,
94
+ x: event.clientX,
95
+ y: event.clientY,
96
+ start: frame(),
97
+ direction
98
+ };
99
+ event.currentTarget.setPointerCapture(event.pointerId);
100
+ }
101
+ function move(event) {
102
+ if (!gesture || gesture.id !== event.pointerId) return;
103
+ const rect = bounds?.getBoundingClientRect();
104
+ if (!rect) return;
105
+ const container = {
106
+ width: rect.width,
107
+ height: rect.height
108
+ };
109
+ const delta = {
110
+ x: event.clientX - gesture.x,
111
+ y: event.clientY - gesture.y
112
+ };
113
+ setFrame(gesture.direction ? resizeFloatingPreview({
114
+ start: gesture.start,
115
+ direction: gesture.direction,
116
+ delta,
117
+ source: props.source,
118
+ container
119
+ }) : resolveFloatingPreviewFrame({
120
+ width: gesture.start.width,
121
+ position: {
122
+ x: gesture.start.x + delta.x,
123
+ y: gesture.start.y + delta.y
124
+ },
125
+ source: props.source,
126
+ container
127
+ }));
128
+ }
129
+ function end(event) {
130
+ if (gesture?.id === event.pointerId) gesture = void 0;
131
+ }
132
+ function keyboardMove(event) {
133
+ const delta = {
134
+ x: 0,
135
+ y: 0
136
+ };
137
+ if (event.key === "ArrowLeft") delta.x = -10;
138
+ else if (event.key === "ArrowRight") delta.x = 10;
139
+ else if (event.key === "ArrowUp") delta.y = -10;
140
+ else if (event.key === "ArrowDown") delta.y = 10;
141
+ else return;
142
+ event.preventDefault();
143
+ const rect = bounds?.getBoundingClientRect();
144
+ if (!rect) return;
145
+ const current = frame();
146
+ setFrame(resolveFloatingPreviewFrame({
147
+ width: current.width,
148
+ position: {
149
+ x: current.x + delta.x,
150
+ y: current.y + delta.y
151
+ },
152
+ source: props.source,
153
+ container: {
154
+ width: rect.width,
155
+ height: rect.height
156
+ }
157
+ }));
158
+ }
159
+ function keyboardResize(event, direction) {
160
+ if (!event.key.startsWith("Arrow")) return;
161
+ event.preventDefault();
162
+ const rect = bounds?.getBoundingClientRect();
163
+ if (!rect) return;
164
+ const delta = {
165
+ x: event.key === "ArrowRight" ? 10 : event.key === "ArrowLeft" ? -10 : 0,
166
+ y: event.key === "ArrowDown" ? 10 : event.key === "ArrowUp" ? -10 : 0
167
+ };
168
+ setFrame(resizeFloatingPreview({
169
+ start: frame(),
170
+ direction,
171
+ delta,
172
+ source: props.source,
173
+ container: {
174
+ width: rect.width,
175
+ height: rect.height
176
+ }
177
+ }));
178
+ }
179
+ return (() => {
180
+ var _el$ = _tmpl$(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild;
181
+ var _ref$ = bounds;
182
+ typeof _ref$ === "function" ? use(_ref$, _el$) : bounds = _el$;
183
+ insert(_el$3, createComponent(ActionButton, {
184
+ type: "button",
185
+ variant: "ghost",
186
+ size: "sm",
187
+ "class": "flex-1 cursor-move touch-none",
188
+ get ["aria-label"]() {
189
+ return `Move ${props.label}`;
190
+ },
191
+ get tooltip() {
192
+ return `Move ${props.label}. Use arrow keys to adjust its position.`;
193
+ },
194
+ onPointerDown: (event) => start(event, null),
195
+ onPointerMove: move,
196
+ onPointerUp: end,
197
+ onPointerCancel: end,
198
+ onLostPointerCapture: end,
199
+ onKeyDown: keyboardMove,
200
+ get children() {
201
+ return [createComponent(Move, { "aria-hidden": "true" }), "Move"];
202
+ }
203
+ }), _el$4);
204
+ insert(_el$4, () => props.actions);
205
+ insert(_el$3, (() => {
206
+ var _c$ = memo(() => !!props.onClose);
207
+ return () => _c$() && createComponent(ActionButton, {
208
+ type: "button",
209
+ variant: "ghost",
210
+ size: "icon-sm",
211
+ get ["aria-label"]() {
212
+ return `Close ${props.label}`;
213
+ },
214
+ get tooltip() {
215
+ return `Close ${props.label}.`;
216
+ },
217
+ get onClick() {
218
+ return props.onClose;
219
+ },
220
+ get children() {
221
+ return createComponent(X, { "aria-hidden": "true" });
222
+ }
223
+ });
224
+ })(), null);
225
+ insert(_el$2, createComponent(ScrollArea, {
226
+ role: "region",
227
+ get ["aria-label"]() {
228
+ return `${props.label} content`;
229
+ },
230
+ "class": "flex-1",
231
+ tabIndex: 0,
232
+ get children() {
233
+ return props.children;
234
+ }
235
+ }), null);
236
+ insert(_el$2, () => directions.map(({ direction, class: className, glyph }) => createComponent(ActionButton, {
237
+ type: "button",
238
+ variant: "ghost",
239
+ size: "icon-sm",
240
+ "class": className,
241
+ "data-direction": direction,
242
+ get ["aria-label"]() {
243
+ return `Resize ${props.label} ${direction}`;
244
+ },
245
+ get tooltip() {
246
+ return `Resize ${props.label} from the ${direction} edge. Use arrow keys to resize.`;
247
+ },
248
+ onPointerDown: (event) => start(event, direction),
249
+ onPointerMove: move,
250
+ onPointerUp: end,
251
+ onPointerCancel: end,
252
+ onLostPointerCapture: end,
253
+ onKeyDown: (event) => keyboardResize(event, direction),
254
+ get children() {
255
+ var _el$5 = _tmpl$2();
256
+ insert(_el$5, glyph);
257
+ return _el$5;
258
+ }
259
+ })), null);
260
+ effect((_p$) => {
261
+ var _v$ = props.label, _v$2 = props.label, _v$3 = `${frame().x}px`, _v$4 = `${frame().y}px`, _v$5 = `${frame().width}px`, _v$6 = `${frame().height}px`;
262
+ _v$ !== _p$.e && setAttribute(_el$, "aria-label", _p$.e = _v$);
263
+ _v$2 !== _p$.t && setAttribute(_el$2, "aria-label", _p$.t = _v$2);
264
+ _v$3 !== _p$.a && setStyleProperty(_el$2, "left", _p$.a = _v$3);
265
+ _v$4 !== _p$.o && setStyleProperty(_el$2, "top", _p$.o = _v$4);
266
+ _v$5 !== _p$.i && setStyleProperty(_el$2, "width", _p$.i = _v$5);
267
+ _v$6 !== _p$.n && setStyleProperty(_el$2, "height", _p$.n = _v$6);
268
+ return _p$;
269
+ }, {
270
+ e: void 0,
271
+ t: void 0,
272
+ a: void 0,
273
+ o: void 0,
274
+ i: void 0,
275
+ n: void 0
276
+ });
277
+ return _el$;
278
+ })();
279
+ }
280
+ //#endregion
281
+ export { FloatingPreview };
282
+
283
+ //# sourceMappingURL=floating-preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating-preview.js","names":["createEffect","createSignal","onCleanup","onMount","on","JSX","Move","X","ActionButton","ScrollArea","FloatingPreviewFrame","FloatingPreviewResizeDirection","FloatingPreviewSize","resolveFloatingPreviewFrame","resizeFloatingPreview","directions","direction","class","glyph","FloatingPreviewProps","label","source","onClose","actions","Element","children","FloatingPreview","props","frame","setFrame","x","y","width","height","bounds","HTMLDivElement","observer","ResizeObserver","gesture","id","start","measure","rect","getBoundingClientRect","current","position","container","const","defer","observe","disconnect","event","PointerEvent","button","preventDefault","stopPropagation","pointerId","clientX","clientY","currentTarget","HTMLElement","setPointerCapture","move","delta","end","undefined","keyboardMove","KeyboardEvent","key","keyboardResize","startsWith","_el$","_tmpl$","_el$2","firstChild","_el$3","_el$4","_ref$","_$use","_$insert","_$createComponent","type","variant","size","aria-label","tooltip","onPointerDown","onPointerMove","onPointerUp","onPointerCancel","onLostPointerCapture","onKeyDown","_c$","_$memo","onClick","role","tabIndex","map","className","_el$5","_tmpl$2","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","_v$6","e","_$setAttribute","t","a","_$setStyleProperty","o","i","n","_$use","_$createComponent","_$memo","_$setAttribute","_$setStyleProperty"],"sources":["../../../../src/components/layout/floating-preview/floating-preview.tsx"],"sourcesContent":["import { createEffect, createSignal, onCleanup, onMount, on, type JSX } from 'solid-js'\nimport { Move, X } from 'lucide-solid'\nimport { ActionButton } from '../../composites/action-button'\nimport { ScrollArea } from '../../ui/scroll-area'\nimport {\n type FloatingPreviewFrame,\n type FloatingPreviewResizeDirection,\n type FloatingPreviewSize,\n resolveFloatingPreviewFrame,\n resizeFloatingPreview,\n} from './model'\n\nconst directions: readonly {\n direction: FloatingPreviewResizeDirection\n class: string\n glyph: string\n}[] = [\n {\n direction: 'north',\n class: 'absolute -top-3 right-6 left-6 h-control-xs w-auto cursor-ns-resize touch-none',\n glyph: '↕',\n },\n {\n direction: 'south',\n class: 'absolute -bottom-3 right-6 left-6 h-control-xs w-auto cursor-ns-resize touch-none',\n glyph: '↕',\n },\n {\n direction: 'east',\n class: 'absolute -right-3 top-6 bottom-6 w-6 h-auto cursor-ew-resize touch-none',\n glyph: '↔',\n },\n {\n direction: 'west',\n class: 'absolute -left-3 top-6 bottom-6 w-6 h-auto cursor-ew-resize touch-none',\n glyph: '↔',\n },\n {\n direction: 'northwest',\n class: 'absolute -top-3 -left-3 size-control-xs cursor-nwse-resize touch-none',\n glyph: '↖',\n },\n {\n direction: 'northeast',\n class: 'absolute -top-3 -right-3 size-control-xs cursor-nesw-resize touch-none',\n glyph: '↗',\n },\n {\n direction: 'southwest',\n class: 'absolute -bottom-3 -left-3 size-control-xs cursor-nesw-resize touch-none',\n glyph: '↙',\n },\n {\n direction: 'southeast',\n class: 'absolute -bottom-3 -right-3 size-control-xs cursor-nwse-resize touch-none',\n glyph: '↘',\n },\n]\n\nexport type FloatingPreviewProps = {\n label: string\n source: FloatingPreviewSize\n onClose?: () => void\n actions?: JSX.Element\n children: JSX.Element\n}\n\n/** A host-bounded movable preview frame. Content and actions remain caller-owned. */\nexport function FloatingPreview(props: FloatingPreviewProps) {\n const [frame, setFrame] = createSignal<FloatingPreviewFrame>({ x: 0, y: 0, width: 1, height: 1 })\n // oxlint-disable-next-line no-unassigned-vars -- assigned through Solid's ref callback.\n let bounds: HTMLDivElement | undefined\n let observer: ResizeObserver | undefined\n let gesture:\n | {\n id: number\n x: number\n y: number\n start: FloatingPreviewFrame\n direction: FloatingPreviewResizeDirection | null\n }\n | undefined\n\n const measure = () => {\n const rect = bounds?.getBoundingClientRect()\n if (!rect) return\n setFrame((current) =>\n resolveFloatingPreviewFrame({\n width: current.width > 1 ? current.width : null,\n position: current.width > 1 ? { x: current.x, y: current.y } : null,\n source: props.source,\n container: { width: rect.width, height: rect.height },\n })\n )\n }\n createEffect(\n on(\n () => [props.source.width, props.source.height] as const,\n () => measure(),\n { defer: true }\n )\n )\n onMount(() => {\n if (bounds) {\n observer = new ResizeObserver(measure)\n observer.observe(bounds)\n measure()\n }\n })\n onCleanup(() => observer?.disconnect())\n\n function start(event: PointerEvent, direction: FloatingPreviewResizeDirection | null) {\n if (event.button !== 0 || gesture) return\n event.preventDefault()\n event.stopPropagation()\n gesture = { id: event.pointerId, x: event.clientX, y: event.clientY, start: frame(), direction }\n ;(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId)\n }\n function move(event: PointerEvent) {\n if (!gesture || gesture.id !== event.pointerId) return\n const rect = bounds?.getBoundingClientRect()\n if (!rect) return\n const container = { width: rect.width, height: rect.height }\n const delta = { x: event.clientX - gesture.x, y: event.clientY - gesture.y }\n setFrame(\n gesture.direction\n ? resizeFloatingPreview({\n start: gesture.start,\n direction: gesture.direction,\n delta,\n source: props.source,\n container,\n })\n : resolveFloatingPreviewFrame({\n width: gesture.start.width,\n position: { x: gesture.start.x + delta.x, y: gesture.start.y + delta.y },\n source: props.source,\n container,\n })\n )\n }\n function end(event: PointerEvent) {\n if (gesture?.id === event.pointerId) gesture = undefined\n }\n function keyboardMove(event: KeyboardEvent) {\n const delta = { x: 0, y: 0 }\n if (event.key === 'ArrowLeft') delta.x = -10\n else if (event.key === 'ArrowRight') delta.x = 10\n else if (event.key === 'ArrowUp') delta.y = -10\n else if (event.key === 'ArrowDown') delta.y = 10\n else return\n event.preventDefault()\n const rect = bounds?.getBoundingClientRect()\n if (!rect) return\n const current = frame()\n setFrame(\n resolveFloatingPreviewFrame({\n width: current.width,\n position: { x: current.x + delta.x, y: current.y + delta.y },\n source: props.source,\n container: { width: rect.width, height: rect.height },\n })\n )\n }\n function keyboardResize(event: KeyboardEvent, direction: FloatingPreviewResizeDirection) {\n if (!event.key.startsWith('Arrow')) return\n event.preventDefault()\n const rect = bounds?.getBoundingClientRect()\n if (!rect) return\n const delta = {\n x: event.key === 'ArrowRight' ? 10 : event.key === 'ArrowLeft' ? -10 : 0,\n y: event.key === 'ArrowDown' ? 10 : event.key === 'ArrowUp' ? -10 : 0,\n }\n setFrame(\n resizeFloatingPreview({\n start: frame(),\n direction,\n delta,\n source: props.source,\n container: { width: rect.width, height: rect.height },\n })\n )\n }\n\n return (\n <div\n ref={bounds}\n class=\"pointer-events-none absolute inset-0 z-(--z-sticky) overflow-hidden\"\n aria-label={props.label}\n >\n <section\n class=\"pointer-events-auto absolute flex flex-col overflow-visible rounded-lg border border-border bg-card text-card-foreground shadow-lg\"\n aria-label={props.label}\n style={{\n left: `${frame().x}px`,\n top: `${frame().y}px`,\n width: `${frame().width}px`,\n height: `${frame().height}px`,\n }}\n >\n <header class=\"flex h-control-sm items-center gap-1 border-b border-border p-1\">\n <ActionButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"flex-1 cursor-move touch-none\"\n aria-label={`Move ${props.label}`}\n tooltip={`Move ${props.label}. Use arrow keys to adjust its position.`}\n onPointerDown={(event) => start(event, null)}\n onPointerMove={move}\n onPointerUp={end}\n onPointerCancel={end}\n onLostPointerCapture={end}\n onKeyDown={keyboardMove}\n >\n <>\n <Move aria-hidden=\"true\" />\n Move\n </>\n </ActionButton>\n <div class=\"flex items-center gap-1\">{props.actions}</div>\n {props.onClose && (\n <ActionButton\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={`Close ${props.label}`}\n tooltip={`Close ${props.label}.`}\n onClick={props.onClose}\n >\n <X aria-hidden=\"true\" />\n </ActionButton>\n )}\n </header>\n <ScrollArea role=\"region\" aria-label={`${props.label} content`} class=\"flex-1\" tabIndex={0}>\n {props.children}\n </ScrollArea>\n {directions.map(({ direction, class: className, glyph }) => (\n <ActionButton\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n class={className}\n data-direction={direction}\n aria-label={`Resize ${props.label} ${direction}`}\n tooltip={`Resize ${props.label} from the ${direction} edge. Use arrow keys to resize.`}\n onPointerDown={(event) => start(event, direction)}\n onPointerMove={move}\n onPointerUp={end}\n onPointerCancel={end}\n onLostPointerCapture={end}\n onKeyDown={(event) => keyboardResize(event, direction)}\n >\n <span aria-hidden=\"true\">{glyph}</span>\n </ActionButton>\n ))}\n </section>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './model';
2
+ export * from './floating-preview';
3
+ //# sourceMappingURL=index.d.ts.map