@fusion.dev/helix-core 0.148.0 → 0.149.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/custom-elements.json +8518 -6050
  2. package/dist/controllers/aria-forward-controller/aria-forward-controller.js +1 -1
  3. package/dist/controllers/chart-pointer-controller/chart-pointer-controller.d.ts +2 -2
  4. package/dist/controllers/chart-pointer-controller/chart-pointer-controller.js +5 -4
  5. package/dist/controllers/machine-controller/machine-controller.d.ts +69 -0
  6. package/dist/controllers/machine-controller/machine-controller.js +78 -0
  7. package/dist/controllers/machine-controller/machine.d.ts +93 -0
  8. package/dist/controllers/machine-controller/machine.js +20 -0
  9. package/dist/controllers/reorder-controller/reorder-controller.d.ts +285 -0
  10. package/dist/controllers/reorder-controller/reorder-controller.js +497 -0
  11. package/dist/controllers/source-controller/source-controller.js +1 -1
  12. package/dist/controllers/virtualize-controller/heights.js +1 -1
  13. package/dist/controllers/virtualize-controller/virtualize-controller.d.ts +117 -3
  14. package/dist/controllers/virtualize-controller/virtualize-controller.js +134 -32
  15. package/dist/events/before-reorder.d.ts +14 -0
  16. package/dist/events/before-reorder.js +11 -0
  17. package/dist/events/details.d.ts +28 -0
  18. package/dist/events/events.d.ts +4 -2
  19. package/dist/events/events.js +3 -1
  20. package/dist/events/names.js +1 -1
  21. package/dist/events/reorder.d.ts +18 -12
  22. package/dist/events/reordered.d.ts +4 -4
  23. package/dist/helix-element/helix-element.js +2 -1
  24. package/dist/helix-element/react-audit-off.d.ts +11 -0
  25. package/dist/helix-element/react-audit-off.js +1 -0
  26. package/dist/helix-element/react-audit.d.ts +20 -0
  27. package/dist/helix-element/react-audit.js +56 -0
  28. package/dist/helix-element/react-bridge.d.ts +2 -22
  29. package/dist/helix-element/react-bridge.js +1 -56
  30. package/dist/index.d.ts +10 -4
  31. package/dist/index.js +10 -4
  32. package/dist/mixins/mixin-chart-source/mixin-chart-source.d.ts +2 -2
  33. package/dist/mixins/mixin-chart-source/mixin-chart-source.js +3 -0
  34. package/dist/mixins/mixin-collection/mixin-collection.js +4 -0
  35. package/dist/mixins/mixin-dismissible/mixin-dismissible.js +3 -0
  36. package/dist/mixins/mixin-field/mixin-field.js +1 -1
  37. package/dist/mixins/mixin-segmented-field/mixin-segmented-field.d.ts +12 -0
  38. package/dist/mixins/mixin-segmented-field/mixin-segmented-field.js +15 -2
  39. package/dist/mixins/mixin-tokens/mixin-tokens.d.ts +5 -0
  40. package/dist/mixins/mixin-tokens/mixin-tokens.js +13 -2
  41. package/dist/mixins/mixin-viewport/mixin-viewport.d.ts +17 -15
  42. package/dist/mixins/mixin-viewport/mixin-viewport.js +15 -34
  43. package/dist/utils/calendar/calendar.d.ts +27 -0
  44. package/dist/utils/calendar/calendar.js +17 -0
  45. package/dist/utils/count-label/count-label.d.ts +7 -4
  46. package/dist/utils/count-label/count-label.js +2 -5
  47. package/dist/utils/date-segments/date-segments.d.ts +2 -1
  48. package/dist/utils/date-segments/date-segments.js +10 -0
  49. package/dist/utils/locale-of/locale-of.d.ts +5 -0
  50. package/dist/utils/locale-of/locale-of.js +8 -2
  51. package/dist/utils/reorder/drag-preview.d.ts +46 -0
  52. package/dist/utils/reorder/drag-preview.js +58 -0
  53. package/dist/utils/reorder/reorder.d.ts +178 -0
  54. package/dist/utils/reorder/reorder.js +112 -0
  55. package/dist/utils/report-runtime/report-runtime.d.ts +7 -4
  56. package/dist/utils/slotted-words/slotted-words.d.ts +3 -2
  57. package/dist/utils/slotted-words/slotted-words.js +3 -1
  58. package/dist/version.d.ts +1 -1
  59. package/dist/version.js +1 -1
  60. package/dist/words/index.d.ts +3 -0
  61. package/dist/words/index.js +3 -0
  62. package/dist/words/message.d.ts +47 -0
  63. package/dist/words/message.js +152 -0
  64. package/dist/words/registry.d.ts +89 -0
  65. package/dist/words/registry.js +101 -0
  66. package/dist/words/words-locale.d.ts +34 -0
  67. package/dist/words/words-locale.js +30 -0
  68. package/dist/words/words.d.ts +52 -0
  69. package/dist/words/words.js +100 -0
  70. package/package.json +40 -25
@@ -2,6 +2,7 @@ import { endInSight } from '../../utils/load-more/load-more.js';
2
2
  import { reportRuntime } from '../../utils/report-runtime/report-runtime.js';
3
3
  import { Heights } from './heights.js';
4
4
  const UNSTABLE = 10;
5
+ const REST = 150;
5
6
  export class VirtualizeController {
6
7
  constructor(host, options) {
7
8
  this.watching = false;
@@ -10,13 +11,45 @@ export class VirtualizeController {
10
11
  this.window = { after: 0, before: 0, first: 0, last: 0 };
11
12
  this.owed = 0;
12
13
  this.askedAt = -1;
14
+ this.drift = 0;
15
+ this.lastTop = 0;
16
+ this.heading = 0;
17
+ this.touching = false;
18
+ this.uneven = false;
13
19
  this.handleScroll = () => {
20
+ const top = this.options.container()?.scrollTop ?? 0;
21
+ if (top !== this.lastTop) {
22
+ this.heading = top > this.lastTop ? 1 : -1;
23
+ this.lastTop = top;
24
+ this.target = undefined;
25
+ clearTimeout(this.resting);
26
+ this.resting = setTimeout(this.rest, REST);
27
+ }
28
+ this.settling = 0;
29
+ this.measure();
30
+ };
31
+ this.handleTouchStart = () => {
32
+ this.touching = true;
33
+ };
34
+ this.handleTouchEnd = () => {
35
+ this.touching = false;
36
+ if (this.resting === undefined) {
37
+ this.rest();
38
+ }
39
+ };
40
+ this.rest = () => {
41
+ this.resting = undefined;
42
+ if (this.touching || this.drift === 0) {
43
+ return;
44
+ }
45
+ this.square();
14
46
  this.settling = 0;
15
47
  this.measure();
48
+ this.host.requestUpdate();
16
49
  };
17
50
  this.host = host;
18
51
  this.options = options;
19
- this.heights = new Heights(() => this.options.estimate());
52
+ this.heights = new Heights(() => this.line());
20
53
  host.addController(this);
21
54
  host.constructor.disableWarning?.('change-in-update');
22
55
  }
@@ -29,7 +62,15 @@ export class VirtualizeController {
29
62
  this.observer?.disconnect();
30
63
  this.observer = undefined;
31
64
  this.watching = false;
32
- this.options.container()?.removeEventListener('scroll', this.handleScroll);
65
+ const box = this.options.container();
66
+ box?.removeEventListener('scroll', this.handleScroll, { capture: true });
67
+ box?.removeEventListener('touchstart', this.handleTouchStart);
68
+ box?.removeEventListener('touchend', this.handleTouchEnd);
69
+ box?.removeEventListener('touchcancel', this.handleTouchEnd);
70
+ box?.removeEventListener('scrollend', this.handleTouchEnd);
71
+ clearTimeout(this.resting);
72
+ this.resting = undefined;
73
+ this.touching = false;
33
74
  }
34
75
  watch() {
35
76
  if (this.watching) {
@@ -40,10 +81,38 @@ export class VirtualizeController {
40
81
  return;
41
82
  }
42
83
  this.observer.observe(box);
43
- box.addEventListener('scroll', this.handleScroll, { passive: true });
84
+ box.addEventListener('scroll', this.handleScroll, { capture: true, passive: true });
85
+ box.addEventListener('touchstart', this.handleTouchStart, { passive: true });
86
+ box.addEventListener('touchend', this.handleTouchEnd, { passive: true });
87
+ box.addEventListener('touchcancel', this.handleTouchEnd, { passive: true });
88
+ box.addEventListener('scrollend', this.handleTouchEnd, { passive: true });
89
+ this.lastTop = box.scrollTop;
44
90
  box.setAttribute('data-virtual', '');
45
91
  this.watching = true;
46
92
  }
93
+ scrolling() {
94
+ return (this.touching ||
95
+ this.resting !== undefined ||
96
+ (this.options.container()?.scrollTop ?? this.lastTop) !== this.lastTop);
97
+ }
98
+ square() {
99
+ const box = this.options.container();
100
+ if (this.drift > 0 && box) {
101
+ box.scrollTop -= this.drift;
102
+ this.lastTop = box.scrollTop;
103
+ }
104
+ else if (this.drift !== 0) {
105
+ this.owed -= this.drift;
106
+ this.host.requestUpdate();
107
+ }
108
+ this.drift = 0;
109
+ }
110
+ offset(box) {
111
+ return box.scrollTop + this.owed - this.drift;
112
+ }
113
+ lead(box) {
114
+ return this.heading === 0 ? 0 : box.clientHeight;
115
+ }
47
116
  measure() {
48
117
  this.watch();
49
118
  const box = this.options.container();
@@ -53,9 +122,15 @@ export class VirtualizeController {
53
122
  return;
54
123
  }
55
124
  const overscan = this.options.overscan ?? 4;
56
- const next = this.measuring()
125
+ let next = this.measuring()
57
126
  ? this.placed(box, total, overscan)
58
127
  : this.uniform(box, total, size, overscan);
128
+ if (this.drift !== 0 && (next.before < 0 || next.first === 0)) {
129
+ this.square();
130
+ next = this.measuring()
131
+ ? this.placed(box, total, overscan)
132
+ : this.uniform(box, total, size, overscan);
133
+ }
59
134
  if (this.last?.count !== total || this.last.estimate !== size) {
60
135
  this.last = { count: total, estimate: size };
61
136
  this.settling = 0;
@@ -77,8 +152,10 @@ export class VirtualizeController {
77
152
  this.host.requestUpdate();
78
153
  }
79
154
  uniform(box, total, size, overscan) {
80
- const first = Math.max(0, Math.min(Math.floor(box.scrollTop / size), total) - overscan);
81
- const fits = Math.ceil(box.clientHeight / size) + overscan * 2;
155
+ const extra = Math.ceil(this.lead(box) / size);
156
+ const at = Math.min(Math.floor(this.offset(box) / size), total);
157
+ const first = Math.max(0, at - overscan - (this.heading < 0 ? extra : 0));
158
+ const fits = Math.ceil(box.clientHeight / size) + overscan * 2 + (this.heading === 0 ? 0 : extra);
82
159
  const last = Math.min(total, first + fits);
83
160
  return { after: Math.max(0, (total - last) * size), before: first * size, first, last };
84
161
  }
@@ -88,9 +165,6 @@ export class VirtualizeController {
88
165
  }
89
166
  sampleRows() {
90
167
  const estimate = Math.max(1, this.options.estimate());
91
- if (this.sample?.estimate === estimate) {
92
- return;
93
- }
94
168
  const heights = new Map();
95
169
  for (const { element, index } of this.options.rows?.() ?? []) {
96
170
  heights.set(index, (heights.get(index) ?? 0) + element.getBoundingClientRect().height);
@@ -99,33 +173,45 @@ export class VirtualizeController {
99
173
  if (seen.length === 0) {
100
174
  return;
101
175
  }
102
- const was = this.line();
103
- const size = Math.max(1, seen.reduce((sum, height) => sum + height, 0) / seen.length);
104
- this.sample = { estimate, size };
105
- if (Math.abs(size - was) < 0.5) {
106
- return;
176
+ const uneven = Math.max(...seen) - Math.min(...seen) > 1;
177
+ if (this.sample?.estimate !== estimate) {
178
+ const was = this.line();
179
+ const size = Math.max(1, seen.reduce((sum, height) => sum + height, 0) / seen.length);
180
+ this.sample = { estimate, size };
181
+ if (Math.abs(size - was) >= 0.5) {
182
+ const box = this.options.container();
183
+ if (box && box.scrollTop > 0) {
184
+ box.scrollTop = (box.scrollTop / was) * size;
185
+ this.lastTop = box.scrollTop;
186
+ }
187
+ this.settling = 0;
188
+ if (!uneven) {
189
+ this.measure();
190
+ }
191
+ }
107
192
  }
108
- const box = this.options.container();
109
- if (box && box.scrollTop > 0) {
110
- box.scrollTop = (box.scrollTop / was) * size;
193
+ if (uneven) {
194
+ this.uneven = true;
195
+ this.settle();
111
196
  }
112
- this.settling = 0;
113
- this.measure();
114
197
  }
115
198
  measuring() {
116
- return this.options.rows !== undefined && (this.options.measured?.() ?? true);
199
+ return this.options.rows !== undefined && (this.uneven || (this.options.measured?.() ?? true));
117
200
  }
118
201
  placed(box, total, overscan) {
119
- const first = Math.max(0, this.heights.indexAt(box.scrollTop, total) - overscan);
120
- const bottom = box.scrollTop + box.clientHeight;
121
- let last = this.heights.indexAt(box.scrollTop, total);
202
+ const top = this.offset(box);
203
+ const lead = this.lead(box);
204
+ const from = this.heading < 0 ? top - lead : top;
205
+ const first = Math.max(0, this.heights.indexAt(from, total) - overscan);
206
+ const bottom = top + box.clientHeight + (this.heading > 0 ? lead : 0);
207
+ let last = this.heights.indexAt(top, total);
122
208
  while (last < total && this.heights.before(last, total) < bottom) {
123
209
  last += 1;
124
210
  }
125
211
  last = Math.min(total, last + overscan);
126
212
  return {
127
213
  after: Math.max(0, this.heights.total(total) - this.heights.before(last, total)),
128
- before: this.heights.before(first, total),
214
+ before: this.heights.before(first, total) + this.drift,
129
215
  first,
130
216
  last,
131
217
  };
@@ -136,7 +222,7 @@ export class VirtualizeController {
136
222
  if (!box || total === 0) {
137
223
  return { first: 0, last: 0 };
138
224
  }
139
- const top = Math.max(0, box.scrollTop);
225
+ const top = Math.max(0, this.offset(box));
140
226
  const bottom = top + box.clientHeight;
141
227
  if (!this.measuring()) {
142
228
  const size = this.line();
@@ -157,7 +243,7 @@ export class VirtualizeController {
157
243
  return 0;
158
244
  }
159
245
  const length = this.measuring() ? this.heights.total(total) : total * this.line();
160
- return Math.max(0, length - Math.max(0, box.scrollTop) - box.clientHeight);
246
+ return Math.max(0, length - Math.max(0, this.offset(box)) - box.clientHeight);
161
247
  }
162
248
  endInSight(length = Math.max(0, this.options.count())) {
163
249
  if (this.options.count() <= 0 ||
@@ -188,9 +274,13 @@ export class VirtualizeController {
188
274
  const box = this.options.container();
189
275
  if (box) {
190
276
  box.scrollTop += this.owed;
277
+ this.lastTop = box.scrollTop;
191
278
  }
192
279
  this.owed = 0;
193
280
  }
281
+ this.settle();
282
+ }
283
+ settle() {
194
284
  if (!this.measuring()) {
195
285
  this.sampleRows();
196
286
  return;
@@ -200,7 +290,10 @@ export class VirtualizeController {
200
290
  return;
201
291
  }
202
292
  const total = Math.max(0, this.options.count());
203
- const was = this.heights.before(this.window.first, total);
293
+ const box = this.options.container();
294
+ const top = box ? this.offset(box) : 0;
295
+ const anchor = this.target ?? this.heights.indexAt(top, total);
296
+ const was = this.heights.before(anchor, total);
204
297
  let news = false;
205
298
  for (const { element, index } of rows) {
206
299
  if (this.heights.record(index, element.getBoundingClientRect().height)) {
@@ -211,10 +304,15 @@ export class VirtualizeController {
211
304
  return;
212
305
  }
213
306
  this.settling = 0;
214
- const box = this.options.container();
215
- const now = this.heights.before(this.window.first, total);
216
- if (box && box.scrollTop > 0 && now !== was) {
217
- box.scrollTop += now - was;
307
+ const moved = this.heights.before(anchor, total) - was;
308
+ if (box && top > 0 && moved !== 0 && (this.options.anchor?.() ?? true)) {
309
+ if (this.scrolling()) {
310
+ this.drift -= moved;
311
+ }
312
+ else {
313
+ box.scrollTop += moved;
314
+ this.lastTop = box.scrollTop;
315
+ }
218
316
  }
219
317
  this.measure();
220
318
  }
@@ -269,17 +367,21 @@ export class VirtualizeController {
269
367
  }
270
368
  else {
271
369
  box.scrollTop = next;
370
+ this.lastTop = box.scrollTop;
371
+ this.target = index;
272
372
  }
273
373
  }
274
374
  offsetOf(index) {
275
375
  const total = Math.max(0, this.options.count());
276
376
  return this.measuring()
277
- ? this.heights.before(index, total)
377
+ ? this.heights.before(index, total) + this.drift
278
378
  : Math.max(0, Math.min(index, total)) * this.line();
279
379
  }
280
380
  forget() {
281
381
  this.heights.forget();
282
382
  this.sample = undefined;
383
+ this.uneven = false;
384
+ this.square();
283
385
  }
284
386
  report() {
285
387
  if (this.warned) {
@@ -0,0 +1,14 @@
1
+ import type { ReorderDetail } from './details.js';
2
+ /**
3
+ * A row or an item is about to move to a new place, and the move can be
4
+ * refused.
5
+ *
6
+ * Sent once, when a drag lets go or a key drops the item, with the whole order
7
+ * the move would leave. Call `preventDefault()` to keep the item where it is: a
8
+ * pinned row, or a place the item may not go. Nothing has moved yet, and
9
+ * `helix-reorder` follows where nobody refused.
10
+ */
11
+ export declare class HelixBeforeReorderEvent extends CustomEvent<ReorderDetail> {
12
+ static readonly eventName = "helix-before-reorder";
13
+ constructor(detail: ReorderDetail);
14
+ }
@@ -0,0 +1,11 @@
1
+ export class HelixBeforeReorderEvent extends CustomEvent {
2
+ static { this.eventName = 'helix-before-reorder'; }
3
+ constructor(detail) {
4
+ super(HelixBeforeReorderEvent.eventName, {
5
+ bubbles: true,
6
+ cancelable: true,
7
+ composed: true,
8
+ detail,
9
+ });
10
+ }
11
+ }
@@ -261,6 +261,34 @@ export interface ChangeDetail {
261
261
  /** The value after the change. */
262
262
  value: string;
263
263
  }
264
+ /**
265
+ * Detail carried by `helix-before-reorder`, `helix-reorder`, and
266
+ * `helix-reordered`: one row, item, or column moved to a new place.
267
+ *
268
+ * `from` and `to` count from 0 in the old order and in `keys`. Where your
269
+ * array holds every key in the same order, `rows.splice(to, 0,
270
+ * ...rows.splice(from, 1))` makes the same move.
271
+ *
272
+ * **`kind` is a field because one element sends both.** A data table moves its
273
+ * rows and its columns, and both are `helix-reorder` from the same host.
274
+ */
275
+ export interface ReorderDetail extends ChangeDetail {
276
+ /** Where the key was before the move, counting from 0 in the old order. */
277
+ from: number;
278
+ /** The key of what moved: a row's key, an item's value, or a column's field. */
279
+ key: string;
280
+ /** Every key in the new order. */
281
+ keys: string[];
282
+ /** What moved: a column of a data table, an item of a list, or a row of a data table. */
283
+ kind: 'column' | 'item' | 'row';
284
+ /** Where the key is after the move, counting from 0 in `keys`. */
285
+ to: number;
286
+ /**
287
+ * The new order as one string: fields separated by spaces for columns, which
288
+ * is what `order` takes, and keys separated by commas for rows and items.
289
+ */
290
+ value: string;
291
+ }
264
292
  /** Detail carried by `helix-activate`: the value after the move, and the one before it. */
265
293
  export interface ActivateDetail extends ChangeDetail {
266
294
  /** The value that was current before the move, where the set knows it. */
@@ -43,6 +43,7 @@ import { HelixBeforePanelResizeEvent } from './before-panel-resize.js';
43
43
  import { HelixBeforePinEvent } from './before-pin.js';
44
44
  import { HelixBeforeReconnectEvent } from './before-reconnect.js';
45
45
  import { HelixBeforeRelabelEvent } from './before-relabel.js';
46
+ import { HelixBeforeReorderEvent } from './before-reorder.js';
46
47
  import { HelixBeforeResizeEvent } from './before-resize.js';
47
48
  import { HelixBeforeSplitEvent } from './before-split.js';
48
49
  import { HelixBeforeToggleEvent } from './before-toggle.js';
@@ -115,9 +116,9 @@ import { HelixToggleEvent } from './toggle.js';
115
116
  import { HelixTourAskEvent } from './tour-ask.js';
116
117
  import { HelixTourStatusEvent } from './tour-status.js';
117
118
  import { HelixTypingEvent } from './typing.js';
118
- export type { ActivateDetail, AuraFallbackDetail, BandDetail, CanvasView, CaretDetail, ChangeDetail, CompleteDetail, ConnectDetail, ConsoleDetail, CopyDetail, CreateDetail, DismissDetail, FacetDetail, FilterDetail, GraphFilterDetail, GraphLayoutDetail, GraphPartChangeDetail, GraphSignalDetail, MapClusterDetail, MapPanDetail, MapPartChangeDetail, MapRotateDetail, MapTiltDetail, MapZoomDetail, MoveDetail, NavigateDetail, OpenDetail, PressDetail, PressPointerType, RangeDetail, ReadDetail, ReconnectDetail, Refusal, RefusedFile, RejectDetail, RelabelDetail, RemoveDetail, ResizeDetail, ScrolledDetail, SelectDetail, SendDetail, ShortcutDetail, SkipDetail, SortDetail, ToggleDetail, TourAskDetail, TourStatusDetail, TypingDetail, ViewportPanDetail, ViewportZoomDetail, } from './details.js';
119
+ export type { ActivateDetail, AuraFallbackDetail, BandDetail, CanvasView, CaretDetail, ChangeDetail, CompleteDetail, ConnectDetail, ConsoleDetail, CopyDetail, CreateDetail, DismissDetail, FacetDetail, FilterDetail, GraphFilterDetail, GraphLayoutDetail, GraphPartChangeDetail, GraphSignalDetail, MapClusterDetail, MapPanDetail, MapPartChangeDetail, MapRotateDetail, MapTiltDetail, MapZoomDetail, MoveDetail, NavigateDetail, OpenDetail, PressDetail, PressPointerType, RangeDetail, ReadDetail, ReconnectDetail, Refusal, RefusedFile, RejectDetail, RelabelDetail, RemoveDetail, ReorderDetail, ResizeDetail, ScrolledDetail, SelectDetail, SendDetail, ShortcutDetail, SkipDetail, SortDetail, ToggleDetail, TourAskDetail, TourStatusDetail, TypingDetail, ViewportPanDetail, ViewportZoomDetail, } from './details.js';
119
120
  export { helixEventNames } from './names.js';
120
- export { HelixActionEvent, HelixActivateEvent, HelixAuraFallbackEvent, HelixBandEvent, HelixBeforeActivateEvent, HelixBeforeChangeEvent, HelixBeforeCloseEvent, HelixBeforeCollapseEvent, HelixBeforeEditEvent, HelixBeforeMoveEvent, HelixBeforeOpenEvent, HelixBeforePanelResizeEvent, HelixBeforePinEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixBeforeResizeEvent, HelixBeforeSplitEvent, HelixBeforeToggleEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixCaretEvent, HelixClearEvent, HelixCollapseEvent, HelixCompleteEvent, HelixConnectEvent, HelixConsoleEvent, HelixCopyErrorEvent, HelixCopyEvent, HelixCreateEvent, HelixDismissEvent, HelixEditEvent, HelixEndEvent, HelixExpandEvent, HelixFacetEvent, HelixFilterEvent, HelixFilteredEvent, HelixGraphFilterEvent, HelixGraphLayoutEvent, HelixGraphPanEvent, HelixGraphPartChangeEvent, HelixGraphReadyEvent, HelixGraphSignalEvent, HelixGraphZoomEvent, HelixHistoryEvent, HelixLoadEvent, HelixLoadMoreEvent, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, HelixMoveEvent, HelixNavigateEvent, HelixNextEvent, HelixPanelResizeEvent, HelixPinEvent, HelixPressEvent, HelixPreviewEvent, HelixPreviousEvent, HelixRangeChangeEvent, HelixReadEvent, HelixReconnectEvent, HelixRejectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixReorderEvent, HelixReorderedEvent, HelixResizedEvent, HelixResizeEvent, HelixSampleEndEvent, HelixSampleStartEvent, HelixScrolledEvent, HelixSelectEvent, HelixSelectedEvent, HelixSendEvent, HelixShortcutEvent, HelixSortEvent, HelixSortedEvent, HelixSplitEvent, HelixToggleEvent, HelixTourAskEvent, HelixTourStatusEvent, HelixTypingEvent, };
121
+ export { HelixActionEvent, HelixActivateEvent, HelixAuraFallbackEvent, HelixBandEvent, HelixBeforeActivateEvent, HelixBeforeChangeEvent, HelixBeforeCloseEvent, HelixBeforeCollapseEvent, HelixBeforeEditEvent, HelixBeforeMoveEvent, HelixBeforeOpenEvent, HelixBeforePanelResizeEvent, HelixBeforePinEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixBeforeReorderEvent, HelixBeforeResizeEvent, HelixBeforeSplitEvent, HelixBeforeToggleEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixCaretEvent, HelixClearEvent, HelixCollapseEvent, HelixCompleteEvent, HelixConnectEvent, HelixConsoleEvent, HelixCopyErrorEvent, HelixCopyEvent, HelixCreateEvent, HelixDismissEvent, HelixEditEvent, HelixEndEvent, HelixExpandEvent, HelixFacetEvent, HelixFilterEvent, HelixFilteredEvent, HelixGraphFilterEvent, HelixGraphLayoutEvent, HelixGraphPanEvent, HelixGraphPartChangeEvent, HelixGraphReadyEvent, HelixGraphSignalEvent, HelixGraphZoomEvent, HelixHistoryEvent, HelixLoadEvent, HelixLoadMoreEvent, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, HelixMoveEvent, HelixNavigateEvent, HelixNextEvent, HelixPanelResizeEvent, HelixPinEvent, HelixPressEvent, HelixPreviewEvent, HelixPreviousEvent, HelixRangeChangeEvent, HelixReadEvent, HelixReconnectEvent, HelixRejectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixReorderEvent, HelixReorderedEvent, HelixResizedEvent, HelixResizeEvent, HelixSampleEndEvent, HelixSampleStartEvent, HelixScrolledEvent, HelixSelectEvent, HelixSelectedEvent, HelixSendEvent, HelixShortcutEvent, HelixSortEvent, HelixSortedEvent, HelixSplitEvent, HelixToggleEvent, HelixTourAskEvent, HelixTourStatusEvent, HelixTypingEvent, };
121
122
  /**
122
123
  * Every event class, and the one place a new one is registered: a class in a
123
124
  * module of its own, imported above, and named here and in `names.ts`.
@@ -146,6 +147,7 @@ declare const registry: {
146
147
  readonly HelixBeforePinEvent: typeof HelixBeforePinEvent;
147
148
  readonly HelixBeforeReconnectEvent: typeof HelixBeforeReconnectEvent;
148
149
  readonly HelixBeforeRelabelEvent: typeof HelixBeforeRelabelEvent;
150
+ readonly HelixBeforeReorderEvent: typeof HelixBeforeReorderEvent;
149
151
  readonly HelixBeforeResizeEvent: typeof HelixBeforeResizeEvent;
150
152
  readonly HelixBeforeSplitEvent: typeof HelixBeforeSplitEvent;
151
153
  readonly HelixBeforeToggleEvent: typeof HelixBeforeToggleEvent;
@@ -13,6 +13,7 @@ import { HelixBeforePanelResizeEvent } from './before-panel-resize.js';
13
13
  import { HelixBeforePinEvent } from './before-pin.js';
14
14
  import { HelixBeforeReconnectEvent } from './before-reconnect.js';
15
15
  import { HelixBeforeRelabelEvent } from './before-relabel.js';
16
+ import { HelixBeforeReorderEvent } from './before-reorder.js';
16
17
  import { HelixBeforeResizeEvent } from './before-resize.js';
17
18
  import { HelixBeforeSplitEvent } from './before-split.js';
18
19
  import { HelixBeforeToggleEvent } from './before-toggle.js';
@@ -86,7 +87,7 @@ import { HelixTourAskEvent } from './tour-ask.js';
86
87
  import { HelixTourStatusEvent } from './tour-status.js';
87
88
  import { HelixTypingEvent } from './typing.js';
88
89
  export { helixEventNames } from './names.js';
89
- export { HelixActionEvent, HelixActivateEvent, HelixAuraFallbackEvent, HelixBandEvent, HelixBeforeActivateEvent, HelixBeforeChangeEvent, HelixBeforeCloseEvent, HelixBeforeCollapseEvent, HelixBeforeEditEvent, HelixBeforeMoveEvent, HelixBeforeOpenEvent, HelixBeforePanelResizeEvent, HelixBeforePinEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixBeforeResizeEvent, HelixBeforeSplitEvent, HelixBeforeToggleEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixCaretEvent, HelixClearEvent, HelixCollapseEvent, HelixCompleteEvent, HelixConnectEvent, HelixConsoleEvent, HelixCopyErrorEvent, HelixCopyEvent, HelixCreateEvent, HelixDismissEvent, HelixEditEvent, HelixEndEvent, HelixExpandEvent, HelixFacetEvent, HelixFilterEvent, HelixFilteredEvent, HelixGraphFilterEvent, HelixGraphLayoutEvent, HelixGraphPanEvent, HelixGraphPartChangeEvent, HelixGraphReadyEvent, HelixGraphSignalEvent, HelixGraphZoomEvent, HelixHistoryEvent, HelixLoadEvent, HelixLoadMoreEvent, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, HelixMoveEvent, HelixNavigateEvent, HelixNextEvent, HelixPanelResizeEvent, HelixPinEvent, HelixPressEvent, HelixPreviewEvent, HelixPreviousEvent, HelixRangeChangeEvent, HelixReadEvent, HelixReconnectEvent, HelixRejectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixReorderEvent, HelixReorderedEvent, HelixResizedEvent, HelixResizeEvent, HelixSampleEndEvent, HelixSampleStartEvent, HelixScrolledEvent, HelixSelectEvent, HelixSelectedEvent, HelixSendEvent, HelixShortcutEvent, HelixSortEvent, HelixSortedEvent, HelixSplitEvent, HelixToggleEvent, HelixTourAskEvent, HelixTourStatusEvent, HelixTypingEvent, };
90
+ export { HelixActionEvent, HelixActivateEvent, HelixAuraFallbackEvent, HelixBandEvent, HelixBeforeActivateEvent, HelixBeforeChangeEvent, HelixBeforeCloseEvent, HelixBeforeCollapseEvent, HelixBeforeEditEvent, HelixBeforeMoveEvent, HelixBeforeOpenEvent, HelixBeforePanelResizeEvent, HelixBeforePinEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixBeforeReorderEvent, HelixBeforeResizeEvent, HelixBeforeSplitEvent, HelixBeforeToggleEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixCaretEvent, HelixClearEvent, HelixCollapseEvent, HelixCompleteEvent, HelixConnectEvent, HelixConsoleEvent, HelixCopyErrorEvent, HelixCopyEvent, HelixCreateEvent, HelixDismissEvent, HelixEditEvent, HelixEndEvent, HelixExpandEvent, HelixFacetEvent, HelixFilterEvent, HelixFilteredEvent, HelixGraphFilterEvent, HelixGraphLayoutEvent, HelixGraphPanEvent, HelixGraphPartChangeEvent, HelixGraphReadyEvent, HelixGraphSignalEvent, HelixGraphZoomEvent, HelixHistoryEvent, HelixLoadEvent, HelixLoadMoreEvent, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, HelixMoveEvent, HelixNavigateEvent, HelixNextEvent, HelixPanelResizeEvent, HelixPinEvent, HelixPressEvent, HelixPreviewEvent, HelixPreviousEvent, HelixRangeChangeEvent, HelixReadEvent, HelixReconnectEvent, HelixRejectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixReorderEvent, HelixReorderedEvent, HelixResizedEvent, HelixResizeEvent, HelixSampleEndEvent, HelixSampleStartEvent, HelixScrolledEvent, HelixSelectEvent, HelixSelectedEvent, HelixSendEvent, HelixShortcutEvent, HelixSortEvent, HelixSortedEvent, HelixSplitEvent, HelixToggleEvent, HelixTourAskEvent, HelixTourStatusEvent, HelixTypingEvent, };
90
91
  const registry = {
91
92
  HelixActionEvent,
92
93
  HelixActivateEvent,
@@ -103,6 +104,7 @@ const registry = {
103
104
  HelixBeforePinEvent,
104
105
  HelixBeforeReconnectEvent,
105
106
  HelixBeforeRelabelEvent,
107
+ HelixBeforeReorderEvent,
106
108
  HelixBeforeResizeEvent,
107
109
  HelixBeforeSplitEvent,
108
110
  HelixBeforeToggleEvent,
@@ -1,6 +1,6 @@
1
1
  export const helixEventNames = new Set(('action activate aura-fallback band before-activate before-change before-close ' +
2
2
  'before-collapse before-edit before-move before-open before-panel-resize before-pin ' +
3
- 'before-reconnect before-relabel before-resize before-split before-toggle ' +
3
+ 'before-reconnect before-relabel before-reorder before-resize before-split before-toggle ' +
4
4
  'canvas-edit canvas-pan canvas-view canvas-zoom caret clear collapse complete ' +
5
5
  'connect console copy copy-error create dismiss edit end expand facet filter ' +
6
6
  'filtered graph-filter graph-layout graph-pan graph-part-change graph-ready ' +
@@ -1,18 +1,24 @@
1
- import type { ChangeDetail } from './details.js';
1
+ import type { ReorderDetail } from './details.js';
2
2
  /**
3
- * Fired when the reader asks for the columns in a different order.
3
+ * Fired when you ask for a row, an item, or a column to move to a new place.
4
4
  *
5
- * Cancelable, and refusing it leaves the columns where they were, so a consumer
6
- * who stores the order, in a URL or a preference, can take the decision the way
7
- * a server-side sort takes `helix-sort`. The detail is the whole order as
8
- * space-separated fields rather than one move, because the order is the fact a
9
- * consumer stores, and a move is only meaningful against an order they would
10
- * then have to keep in step.
5
+ * **For rows and items, you move them.** Helix moves no element it does not
6
+ * own, so a list or a data table sends this after `helix-before-reorder`, and
7
+ * you move your data to the order in `keys`. Calling `preventDefault()` says
8
+ * the move did not happen, and the element tells a screen reader it was
9
+ * canceled.
11
10
  *
12
- * Not `helix-sort`: that reorders the rows, this reorders the columns, and a
13
- * consumer listening for one should not hear the other.
11
+ * **For Data Table's columns, the table moves them.** Calling
12
+ * `preventDefault()` leaves the columns where they were, so you can store the
13
+ * order in a URL or a preference and decide it yourself, the way a server-side
14
+ * sort takes `helix-sort`. `value` is the whole order as fields separated by
15
+ * spaces, which is what `order` takes.
16
+ *
17
+ * `kind` says which of the three moved, since a data table sends this for its
18
+ * rows and for its columns. `helix-sort` orders rows by a column, and this
19
+ * moves one row or column by hand.
14
20
  */
15
- export declare class HelixReorderEvent extends CustomEvent<ChangeDetail> {
21
+ export declare class HelixReorderEvent extends CustomEvent<ReorderDetail> {
16
22
  static readonly eventName = "helix-reorder";
17
- constructor(detail: ChangeDetail);
23
+ constructor(detail: ReorderDetail);
18
24
  }
@@ -1,12 +1,12 @@
1
- import type { ChangeDetail } from './details.js';
1
+ import type { ReorderDetail } from './details.js';
2
2
  /**
3
- * The columns are in a different order.
3
+ * Data Table's columns are in a different order.
4
4
  *
5
5
  * The notification after `helix-reorder`, sent once the order has moved, with
6
6
  * every field in the new one. Not cancelable, and past tense for the reason
7
7
  * `helix-sorted` is.
8
8
  */
9
- export declare class HelixReorderedEvent extends CustomEvent<ChangeDetail> {
9
+ export declare class HelixReorderedEvent extends CustomEvent<ReorderDetail> {
10
10
  static readonly eventName = "helix-reordered";
11
- constructor(detail: ChangeDetail);
11
+ constructor(detail: ReorderDetail);
12
12
  }
@@ -1,7 +1,8 @@
1
1
  import { LitElement, unsafeCSS } from 'lit';
2
+ import { auditReactProps } from '@fusion.dev/helix-core/audits/react';
2
3
  import { measuring, reportRender } from '../utils/report-render/report-render.js';
3
4
  import { noteVersion, reportUsage } from '../utils/report-usage/report-usage.js';
4
- import { applyReactProperties, auditReactProps, bindReactHandler, reactPropsOf, } from './react-bridge.js';
5
+ import { applyReactProperties, bindReactHandler, reactPropsOf } from './react-bridge.js';
5
6
  const BOX_SIZING = '*,::before,::after{box-sizing:border-box}';
6
7
  const HIDDEN = ":host([hidden]:not([hidden='until-found'])){display:none}";
7
8
  const SCROLLER = '[data-scroller]{overflow:auto}';
@@ -0,0 +1,11 @@
1
+ import type { auditReactProps as audit } from './react-audit.js';
2
+ /**
3
+ * The React prop audit in a production build: nothing.
4
+ *
5
+ * `#react-audit` resolves here unless the bundler or runtime asks for the
6
+ * `development` condition, so a production build carries none of the audit's
7
+ * code, its sentences or the list of every event name it checks against. The
8
+ * signature is the audit's, so a call site reads the same in both builds. See
9
+ * `react-audit.ts`.
10
+ */
11
+ export declare const auditReactProps: typeof audit;
@@ -0,0 +1 @@
1
+ export const auditReactProps = () => { };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Says so when a handler prop is attached to nothing.
3
+ *
4
+ * **TypeScript will not catch any of this, and that is not our tooling's
5
+ * fault.** A JSX attribute whose name is not a valid identifier is exempt from
6
+ * checking on an intrinsic element, and every one of ours carries a hyphen. So
7
+ * `onhelix-opne` type-checks, `on:helix-open` type-checks, and a made-up
8
+ * `totally-invented` prop type-checks, all against fully generated types that
9
+ * do reject a wrong *value* on a normal attribute. Measured with `tsc`.
10
+ *
11
+ * That leaves runtime as the only place a typo can be caught, and React's props
12
+ * bag as the only place to look, which the bridge already reads. Once per
13
+ * element, because a warning that repeats on every keystroke is one a consumer
14
+ * silences.
15
+ *
16
+ * `on:helix-open` gets its own message because it is not a mistake so much as
17
+ * the wrong dialect. It is what the Solid types offer, correctly, and React
18
+ * binds it as an event named `:helix-open`.
19
+ */
20
+ export declare const auditReactProps: (host: EventTarget, props: Record<string, unknown>) => void;
@@ -0,0 +1,56 @@
1
+ import { eventsForTag } from '../events/element-events.js';
2
+ import { helixEventNames } from '../events/names.js';
3
+ import { reportRuntime } from '../utils/report-runtime/report-runtime.js';
4
+ const audited = new WeakSet();
5
+ const REMOVED = new Set(['onActiveChange', 'onCheckedChange', 'onOpenChange', 'onValueChange']);
6
+ export const auditReactProps = (host, props) => {
7
+ if (audited.has(host)) {
8
+ return;
9
+ }
10
+ audited.add(host);
11
+ const tag = host instanceof Element ? `<${host.localName}>` : 'A Helix element';
12
+ const element = host instanceof Element ? host.localName : undefined;
13
+ for (const key of Object.keys(props)) {
14
+ if (key.startsWith('on:')) {
15
+ reportRuntime({
16
+ kind: 'solid-handler-syntax',
17
+ message: `${tag} was given \`${key}\`, which is Solid's syntax. React binds the name after \`on\` ` +
18
+ `verbatim, so this listens for an event called \`${key.slice(2)}\`. Write \`on${key.slice(3)}\`.`,
19
+ tag: element,
20
+ });
21
+ continue;
22
+ }
23
+ if (REMOVED.has(key)) {
24
+ reportRuntime({
25
+ kind: 'removed-callback',
26
+ message: `${tag} was given \`${key}\`, which was removed. It never worked from JSX, because React ` +
27
+ `binds any \`on\` prop as an event of that name. Listen for the element's change event instead.`,
28
+ tag: element,
29
+ });
30
+ continue;
31
+ }
32
+ if (!key.startsWith('on') || !key.includes('-')) {
33
+ continue;
34
+ }
35
+ const name = key.slice(2);
36
+ if (!helixEventNames.has(name)) {
37
+ reportRuntime({
38
+ kind: 'unknown-event',
39
+ message: `${tag} was given \`${key}\`, and nothing dispatches \`${name}\`. TypeScript cannot ` +
40
+ `check a hyphenated JSX prop, so this is the only place it shows up.`,
41
+ tag: element,
42
+ });
43
+ continue;
44
+ }
45
+ const mine = host instanceof Element ? eventsForTag(host.localName) : undefined;
46
+ if (mine && !mine.has(name)) {
47
+ reportRuntime({
48
+ kind: 'misplaced-handler',
49
+ message: `${tag} was given \`${key}\`, but it dispatches ${[...mine].map((one) => `\`${one}\``).join(', ')}. ` +
50
+ `\`${name}\` is sent by a different element, and React only wires an \`on\` prop on the ` +
51
+ 'element that dispatches, so this handler will never run. Put it on that element.',
52
+ tag: element,
53
+ });
54
+ }
55
+ }
56
+ };
@@ -1,26 +1,6 @@
1
1
  import type { LitElement } from 'lit';
2
2
  /** The props React is holding for a node, if React is holding any. */
3
3
  export declare const reactPropsOf: (node: EventTarget) => Record<string, unknown> | undefined;
4
- /**
5
- * Says so when a handler prop is attached to nothing.
6
- *
7
- * **TypeScript will not catch any of this, and that is not our tooling's
8
- * fault.** A JSX attribute whose name is not a valid identifier is exempt from
9
- * checking on an intrinsic element, and every one of ours carries a hyphen. So
10
- * `onhelix-opne` type-checks, `on:helix-open` type-checks, and a made-up
11
- * `totally-invented` prop type-checks, all against fully generated types that
12
- * do reject a wrong *value* on a normal attribute. Measured with `tsc`.
13
- *
14
- * That leaves runtime as the only place a typo can be caught, and React's props
15
- * bag as the only place to look, which the binding above already reads. Once per
16
- * element, because a warning that repeats on every keystroke is one a consumer
17
- * silences.
18
- *
19
- * `on:helix-open` gets its own message because it is not a mistake so much as
20
- * the wrong dialect. It is what the Solid types offer, correctly, and React
21
- * binds it as an event named `:helix-open`.
22
- */
23
- export declare const auditReactProps: (host: EventTarget, props: Record<string, unknown>) => void;
24
4
  /**
25
5
  * The prop React would be holding for this event, if it is holding one.
26
6
  *
@@ -83,8 +63,8 @@ export declare const reactNativeProp: (type: string) => string;
83
63
  *
84
64
  * Called by the host as it dispatches, which is the first moment it knows the
85
65
  * event's name. A host React does not render holds no props, and nothing is
86
- * bound. The props are audited on the way, so a handler attached to nothing
87
- * warns.
66
+ * bound. In a development build the props are audited on the way, so a
67
+ * handler attached to nothing warns; see `react-audit.ts`.
88
68
  */
89
69
  export declare const bindReactHandler: (host: EventTarget, event: Event) => void;
90
70
  /**