@ixfx/components 0.8.1 → 0.8.3
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.
- package/bundle/index.d.ts +326 -103
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +2840 -1285
- package/bundle/index.js.map +1 -1
- package/dist/ac-text.js +3 -3
- package/dist/ac-token.js +3 -3
- package/dist/checkbox.js +1 -1
- package/dist/{colour-picker-Ddsk-7E_.js → colour-picker-CSxwUmtE.js} +2 -2
- package/dist/{colour-picker-Ddsk-7E_.js.map → colour-picker-CSxwUmtE.js.map} +1 -1
- package/dist/colour-picker.js +1 -1
- package/dist/crumbs.js +4 -4
- package/dist/data-display.js +1 -1
- package/dist/data-grid-D-z7bx5-.d.ts.map +1 -1
- package/dist/data-grid.js +9 -6
- package/dist/data-grid.js.map +1 -1
- package/dist/detail-list-_ZJHYEBr.d.ts.map +1 -1
- package/dist/detail-list.js +68 -5
- package/dist/detail-list.js.map +1 -1
- package/dist/editable-label.js +1 -1
- package/dist/{fallbacks-DNI9xt0F.js → fallbacks-BcKGq-2F.js} +17 -1
- package/dist/{fallbacks-DNI9xt0F.js.map → fallbacks-BcKGq-2F.js.map} +1 -1
- package/dist/{grid-list-nRUQOcEL.js → grid-list-BXfY3XXX.js} +531 -29
- package/dist/grid-list-BXfY3XXX.js.map +1 -0
- package/dist/{grid-list-u33vmKzb.d.ts → grid-list-x550wJ0X.d.ts} +115 -3
- package/dist/grid-list-x550wJ0X.d.ts.map +1 -0
- package/dist/grid-list.d.ts +2 -2
- package/dist/grid-list.js +1 -1
- package/dist/handle-BPOxBOKf.js +219 -0
- package/dist/handle-BPOxBOKf.js.map +1 -0
- package/dist/{icon-DcEEGQa_.js → icon-Dy33gu4Z.js} +2 -2
- package/dist/{icon-DcEEGQa_.js.map → icon-Dy33gu4Z.js.map} +1 -1
- package/dist/icons.js +1 -1
- package/dist/{index-BeuCXtiO.d.ts → index-DV3iaUBW.d.ts} +2 -2
- package/dist/{index-BeuCXtiO.d.ts.map → index-DV3iaUBW.d.ts.map} +1 -1
- package/dist/index.d.ts +132 -50
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +554 -206
- package/dist/index.js.map +1 -1
- package/dist/{interaction-Cr13azbM.js → interaction-B9AAlsFO.js} +1 -1
- package/dist/labelled-radial-input.js +2 -2
- package/dist/{labelled-slider-input-BInB5GKL.js → labelled-slider-input-BCH9968c.js} +3 -3
- package/dist/{labelled-slider-input-BInB5GKL.js.map → labelled-slider-input-BCH9968c.js.map} +1 -1
- package/dist/labelled-slider-input.js +1 -1
- package/dist/list-selection-controller-SA4piSBi.js +589 -0
- package/dist/list-selection-controller-SA4piSBi.js.map +1 -0
- package/dist/{menu-Bg90Qr0B.js → menu-HMoxCPY2.js} +5 -5
- package/dist/{menu-Bg90Qr0B.js.map → menu-HMoxCPY2.js.map} +1 -1
- package/dist/{menu-item-Bx-Fs7jq.js → menu-item-BQDYxk5A.js} +5 -5
- package/dist/{menu-item-Bx-Fs7jq.js.map → menu-item-BQDYxk5A.js.map} +1 -1
- package/dist/menu.js +2 -2
- package/dist/miller.d.ts +1 -1
- package/dist/miller.js +3 -3
- package/dist/narrowed-text.js +3 -3
- package/dist/notifier.js +1 -1
- package/dist/panel.d.ts +1 -1
- package/dist/panel.js +1 -1
- package/dist/plots.d.ts +2 -2
- package/dist/plots.js +1 -1
- package/dist/polar-pad.js +1 -1
- package/dist/{radial-input-BfA3GO0H.js → radial-input-DyxfbNzD.js} +2 -2
- package/dist/{radial-input-BfA3GO0H.js.map → radial-input-DyxfbNzD.js.map} +1 -1
- package/dist/radial-input.js +1 -1
- package/dist/range-input.js +1 -1
- package/dist/range.js +1 -1
- package/dist/select-horiz.js +3 -3
- package/dist/{slider-input-Bl1hFE89.js → slider-input-WR8_RwHg.js} +2 -2
- package/dist/{slider-input-Bl1hFE89.js.map → slider-input-WR8_RwHg.js.map} +1 -1
- package/dist/slider-input.js +1 -1
- package/dist/snackbar.js +1 -1
- package/dist/{split-layout-BFSbUZQv.js → split-layout-CA5jbNbG.js} +22 -33
- package/dist/split-layout-CA5jbNbG.js.map +1 -0
- package/dist/split-layout-JK3xWVX2.d.ts.map +1 -1
- package/dist/split-layout.js +1 -1
- package/dist/swipe.js +1 -1
- package/dist/tabs.js +1 -1
- package/dist/{tickled-controller-Bn3YdQsM.d.ts → tickled-controller-C1ZsHpyg.d.ts} +10 -1
- package/dist/tickled-controller-C1ZsHpyg.d.ts.map +1 -0
- package/dist/{tickled-controller-C66DgJHl.js → tickled-controller-Dh1Uh_vG.js} +4 -1
- package/dist/tickled-controller-Dh1Uh_vG.js.map +1 -0
- package/dist/{timeline-B2fgDL4U.js → timeline-THyvH8xy.js} +14 -8
- package/dist/timeline-THyvH8xy.js.map +1 -0
- package/dist/timeline.d.ts +1 -1
- package/dist/timeline.js +1 -1
- package/dist/{titlebar-YQ-jVQoS.d.ts → titlebar-Tqu-VvMU.d.ts} +5 -1
- package/dist/titlebar-Tqu-VvMU.d.ts.map +1 -0
- package/dist/titlebar.d.ts +1 -1
- package/dist/titlebar.js +5 -3
- package/dist/titlebar.js.map +1 -1
- package/dist/{tree-Chptss7I.js → tree-DTQon838.js} +4 -4
- package/dist/{tree-Chptss7I.js.map → tree-DTQon838.js.map} +1 -1
- package/dist/tree.d.ts +1 -1
- package/dist/tree.js +1 -1
- package/dist/vertical-list-CFuFDygi.d.ts.map +1 -1
- package/dist/vertical-list.js +68 -4
- package/dist/vertical-list.js.map +1 -1
- package/dist/{xy-axis-DzM1brBZ.js → xy-axis-CrrVdDFe.js} +28 -3
- package/dist/xy-axis-CrrVdDFe.js.map +1 -0
- package/dist/{xy-axis-BfP9hKLj.d.ts → xy-axis-DQqd2yXJ.d.ts} +28 -12
- package/dist/{xy-axis-BfP9hKLj.d.ts.map → xy-axis-DQqd2yXJ.d.ts.map} +1 -1
- package/dist/xy-pad.js +1 -1
- package/docs-user/data-grid.md +1 -1
- package/docs-user/detail-list.md +4 -0
- package/docs-user/dock.md +6 -3
- package/docs-user/grid-list.md +49 -0
- package/docs-user/index.json +2 -2
- package/docs-user/infra-tickled.md +2 -0
- package/docs-user/split-layout.md +2 -4
- package/docs-user/twosplit-layout.md +14 -16
- package/docs-user/vertical-list.md +4 -0
- package/package.json +1 -1
- package/dist/grid-list-nRUQOcEL.js.map +0 -1
- package/dist/grid-list-u33vmKzb.d.ts.map +0 -1
- package/dist/list-selection-controller-DTFI40li.js +0 -264
- package/dist/list-selection-controller-DTFI40li.js.map +0 -1
- package/dist/split-layout-BFSbUZQv.js.map +0 -1
- package/dist/tickled-controller-Bn3YdQsM.d.ts.map +0 -1
- package/dist/tickled-controller-C66DgJHl.js.map +0 -1
- package/dist/timeline-B2fgDL4U.js.map +0 -1
- package/dist/titlebar-YQ-jVQoS.d.ts.map +0 -1
- package/dist/xy-axis-DzM1brBZ.js.map +0 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { t as TickledController } from "./tickled-controller-
|
|
1
|
+
import { t as TickledController } from "./tickled-controller-Dh1Uh_vG.js";
|
|
2
2
|
import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
|
|
3
|
-
import { t as themeFallbacks } from "./fallbacks-
|
|
3
|
+
import { t as themeFallbacks } from "./fallbacks-BcKGq-2F.js";
|
|
4
4
|
import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
|
|
5
5
|
import { c as createElementListSearchAdapter, d as createDataListSearchAdapter, i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, u as keyForElement } from "./incr-search-C05WjbZh.js";
|
|
6
|
+
import { r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-SA4piSBi.js";
|
|
6
7
|
import { i as listItemFadeKeyframes } from "./list-item-animation-DuiwgN3l.js";
|
|
7
|
-
import
|
|
8
|
-
import "./interaction-Cr13azbM.js";
|
|
8
|
+
import "./interaction-B9AAlsFO.js";
|
|
9
9
|
import { t as scrollFadeStyles } from "./scroll-fade-CAs1EabA.js";
|
|
10
10
|
import { LitElement, css, html } from "lit";
|
|
11
|
-
import { property, state } from "lit/decorators.js";
|
|
11
|
+
import { property, query, state } from "lit/decorators.js";
|
|
12
12
|
import { createCommandRegistry } from "@clinth/ui-commands";
|
|
13
13
|
import { repeat } from "lit/directives/repeat.js";
|
|
14
14
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
15
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
15
16
|
//#region src/grid-list/grid-list-source.ts
|
|
16
17
|
const ITEM_SELECTOR$1 = `:scope > *`;
|
|
17
18
|
const SYNTHETIC_PREFIX = `gl-auto-`;
|
|
@@ -232,6 +233,233 @@ var DataGridListSource = class {
|
|
|
232
233
|
}
|
|
233
234
|
};
|
|
234
235
|
//#endregion
|
|
236
|
+
//#region src/pan-text/pan-text.ts
|
|
237
|
+
const SPEED = 45;
|
|
238
|
+
const END_PADDING = 4;
|
|
239
|
+
const START_DELAY = 300;
|
|
240
|
+
const END_DWELL = 2e3;
|
|
241
|
+
const RESET_DURATION = 400;
|
|
242
|
+
const PAN_EASING = `cubic-bezier(0.25, 0.46, 0.45, 0.94)`;
|
|
243
|
+
let PanTextElement = class PanTextElement extends LitElement {
|
|
244
|
+
constructor(..._args) {
|
|
245
|
+
super(..._args);
|
|
246
|
+
this.direction = `end`;
|
|
247
|
+
this.disabled = false;
|
|
248
|
+
this.mode = `hover`;
|
|
249
|
+
this._isOverflowing = false;
|
|
250
|
+
this._isHovering = false;
|
|
251
|
+
this._loopActive = false;
|
|
252
|
+
this._loopAtEnd = false;
|
|
253
|
+
this._overflow = 0;
|
|
254
|
+
this._resizeObserver = null;
|
|
255
|
+
this._loopTimer = 0;
|
|
256
|
+
this._onMouseEnter = () => {
|
|
257
|
+
this._isHovering = true;
|
|
258
|
+
};
|
|
259
|
+
this._onMouseLeave = () => {
|
|
260
|
+
this._isHovering = false;
|
|
261
|
+
};
|
|
262
|
+
this._measure = () => {
|
|
263
|
+
if (this._isHovering || this._loopAtEnd) return;
|
|
264
|
+
const el = this._textEl;
|
|
265
|
+
if (!el) return;
|
|
266
|
+
this._overflow = Math.max(0, el.scrollWidth - el.clientWidth);
|
|
267
|
+
const overflowing = this._overflow > 0;
|
|
268
|
+
this.classList.toggle(`is-overflowing`, overflowing);
|
|
269
|
+
if (overflowing !== this._isOverflowing) this._isOverflowing = overflowing;
|
|
270
|
+
if (this._loopActive && this.mode === `loop` && !this.disabled && overflowing && this._loopTimer === 0) this._scheduleLoopPan(START_DELAY);
|
|
271
|
+
if (!overflowing && this._loopAtEnd) {
|
|
272
|
+
this._loopAtEnd = false;
|
|
273
|
+
this.requestUpdate();
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
connectedCallback() {
|
|
278
|
+
super.connectedCallback();
|
|
279
|
+
this._resizeObserver = new ResizeObserver(() => this._measure());
|
|
280
|
+
this.addEventListener(`mouseenter`, this._onMouseEnter);
|
|
281
|
+
this.addEventListener(`mouseleave`, this._onMouseLeave);
|
|
282
|
+
}
|
|
283
|
+
disconnectedCallback() {
|
|
284
|
+
super.disconnectedCallback();
|
|
285
|
+
this._clearLoopTimer();
|
|
286
|
+
this._loopActive = false;
|
|
287
|
+
this._loopAtEnd = false;
|
|
288
|
+
this._resizeObserver?.disconnect();
|
|
289
|
+
this._resizeObserver = null;
|
|
290
|
+
this.removeEventListener(`mouseenter`, this._onMouseEnter);
|
|
291
|
+
this.removeEventListener(`mouseleave`, this._onMouseLeave);
|
|
292
|
+
}
|
|
293
|
+
firstUpdated() {
|
|
294
|
+
this._measure();
|
|
295
|
+
this._resizeObserver?.observe(this);
|
|
296
|
+
document.fonts?.ready.then(() => this._measure());
|
|
297
|
+
if (this.mode === `loop`) this.startLoop();
|
|
298
|
+
}
|
|
299
|
+
updated(changed) {
|
|
300
|
+
if (changed.has(`mode`)) {
|
|
301
|
+
if (this.mode === `loop`) this.startLoop();
|
|
302
|
+
else this.stopLoop();
|
|
303
|
+
}
|
|
304
|
+
if (changed.has(`disabled`) && this.disabled) this.stopLoop();
|
|
305
|
+
this._measure();
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Whether a loop pan is currently active (between `startLoop()` and `stopLoop()`).
|
|
309
|
+
*/
|
|
310
|
+
get looping() {
|
|
311
|
+
return this._loopActive;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Begin looping: pan to the end, dwell there for 2 seconds, reset to the
|
|
315
|
+
* start and pan again, repeating until `stopLoop()` is called. A no-op when
|
|
316
|
+
* `disabled`, when there is nothing to reveal, or under reduced-motion.
|
|
317
|
+
*/
|
|
318
|
+
startLoop() {
|
|
319
|
+
if (this.disabled || this._prefersReducedMotion()) return;
|
|
320
|
+
this._loopActive = true;
|
|
321
|
+
this._loopAtEnd = false;
|
|
322
|
+
this.requestUpdate();
|
|
323
|
+
if (this._isOverflowing && this._loopTimer === 0) this._scheduleLoopPan(START_DELAY);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Stop a loop started with `startLoop()` and snap back to the rest position.
|
|
327
|
+
*/
|
|
328
|
+
stopLoop() {
|
|
329
|
+
if (!this._loopActive && !this._loopAtEnd && this._loopTimer === 0) return;
|
|
330
|
+
this._clearLoopTimer();
|
|
331
|
+
this._loopActive = false;
|
|
332
|
+
this._loopAtEnd = false;
|
|
333
|
+
this.requestUpdate();
|
|
334
|
+
}
|
|
335
|
+
_prefersReducedMotion() {
|
|
336
|
+
return globalThis.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches ?? false;
|
|
337
|
+
}
|
|
338
|
+
_panDuration() {
|
|
339
|
+
return Math.max(1.5, (this._overflow + END_PADDING) / SPEED);
|
|
340
|
+
}
|
|
341
|
+
_clearLoopTimer() {
|
|
342
|
+
if (this._loopTimer !== 0) {
|
|
343
|
+
clearTimeout(this._loopTimer);
|
|
344
|
+
this._loopTimer = 0;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
_scheduleLoopPan(delay) {
|
|
348
|
+
this._clearLoopTimer();
|
|
349
|
+
this._loopTimer = window.setTimeout(() => {
|
|
350
|
+
this._loopTimer = 0;
|
|
351
|
+
if (!this._loopActive || this.disabled || !this._isOverflowing) return;
|
|
352
|
+
this._loopAtEnd = true;
|
|
353
|
+
this.requestUpdate();
|
|
354
|
+
const dwell = this._panDuration() * 1e3 + END_DWELL;
|
|
355
|
+
this._loopTimer = window.setTimeout(() => {
|
|
356
|
+
this._loopTimer = 0;
|
|
357
|
+
if (!this._loopActive) return;
|
|
358
|
+
this._loopAtEnd = false;
|
|
359
|
+
this.requestUpdate();
|
|
360
|
+
this._scheduleLoopPan(700);
|
|
361
|
+
}, dwell);
|
|
362
|
+
}, delay);
|
|
363
|
+
}
|
|
364
|
+
_textStyle() {
|
|
365
|
+
if (!this._isOverflowing) return ``;
|
|
366
|
+
const distance = this._overflow + END_PADDING;
|
|
367
|
+
const duration = Math.max(1.5, distance / SPEED);
|
|
368
|
+
const revealEnd = this.direction === `end`;
|
|
369
|
+
const restX = revealEnd ? 0 : -distance;
|
|
370
|
+
const hoverX = revealEnd ? -distance : 0;
|
|
371
|
+
if (this._loopActive && this.mode === `loop`) {
|
|
372
|
+
if (this._loopAtEnd) return [
|
|
373
|
+
`transform: translateX(${hoverX}px)`,
|
|
374
|
+
`transition: transform ${duration}s ${PAN_EASING}`,
|
|
375
|
+
`overflow: visible`,
|
|
376
|
+
`text-overflow: clip`
|
|
377
|
+
].join(`; `);
|
|
378
|
+
return [
|
|
379
|
+
`transform: translateX(${restX}px)`,
|
|
380
|
+
`transition: transform ${RESET_DURATION}ms ${PAN_EASING}`,
|
|
381
|
+
revealEnd ? `` : `overflow: visible; text-overflow: clip`
|
|
382
|
+
].filter(Boolean).join(`; `);
|
|
383
|
+
}
|
|
384
|
+
if (this._isHovering) return [
|
|
385
|
+
`transform: translateX(${hoverX}px)`,
|
|
386
|
+
`transition: transform ${duration}s ${PAN_EASING} ${START_DELAY}ms`,
|
|
387
|
+
`overflow: visible`,
|
|
388
|
+
`text-overflow: clip`
|
|
389
|
+
].join(`; `);
|
|
390
|
+
return [
|
|
391
|
+
`transform: translateX(${restX}px)`,
|
|
392
|
+
`transition: transform 400ms ${PAN_EASING}`,
|
|
393
|
+
revealEnd ? `` : `overflow: visible; text-overflow: clip`
|
|
394
|
+
].filter(Boolean).join(`; `);
|
|
395
|
+
}
|
|
396
|
+
render() {
|
|
397
|
+
const textClasses = {
|
|
398
|
+
"is-overflowing": this._isOverflowing,
|
|
399
|
+
"is-hovering": this._isHovering
|
|
400
|
+
};
|
|
401
|
+
return html`
|
|
402
|
+
<span class="text ${classMap(textClasses)}" part="text" style=${this._textStyle()}>
|
|
403
|
+
<slot @slotchange=${this._measure}></slot>
|
|
404
|
+
</span>
|
|
405
|
+
`;
|
|
406
|
+
}
|
|
407
|
+
static {
|
|
408
|
+
this.styles = [themeFallbacks, css`
|
|
409
|
+
/* Renders like plain inline text: no colours, border, padding or margin
|
|
410
|
+
of its own — it only adds the clipping needed to pan on hover. */
|
|
411
|
+
:host {
|
|
412
|
+
display: inline-block;
|
|
413
|
+
overflow: hidden;
|
|
414
|
+
white-space: nowrap;
|
|
415
|
+
max-width: 100%;
|
|
416
|
+
box-sizing: border-box;
|
|
417
|
+
font: inherit;
|
|
418
|
+
color: inherit;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
:host([disabled]) {
|
|
422
|
+
opacity: var(--disabled-opacity, 0.5);
|
|
423
|
+
pointer-events: none;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.text {
|
|
427
|
+
display: block;
|
|
428
|
+
overflow: hidden;
|
|
429
|
+
text-overflow: ellipsis;
|
|
430
|
+
white-space: nowrap;
|
|
431
|
+
will-change: transform;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
@media (prefers-reduced-motion: reduce) {
|
|
435
|
+
.text {
|
|
436
|
+
transition: none !important;
|
|
437
|
+
transform: none !important;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
`];
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
__decorate([property({
|
|
444
|
+
type: String,
|
|
445
|
+
attribute: `direction`
|
|
446
|
+
})], PanTextElement.prototype, "direction", void 0);
|
|
447
|
+
__decorate([property({
|
|
448
|
+
type: Boolean,
|
|
449
|
+
attribute: `disabled`
|
|
450
|
+
})], PanTextElement.prototype, "disabled", void 0);
|
|
451
|
+
__decorate([property({
|
|
452
|
+
type: String,
|
|
453
|
+
attribute: `mode`,
|
|
454
|
+
reflect: true
|
|
455
|
+
})], PanTextElement.prototype, "mode", void 0);
|
|
456
|
+
__decorate([state()], PanTextElement.prototype, "_isOverflowing", void 0);
|
|
457
|
+
__decorate([state()], PanTextElement.prototype, "_isHovering", void 0);
|
|
458
|
+
__decorate([state()], PanTextElement.prototype, "_loopActive", void 0);
|
|
459
|
+
__decorate([state()], PanTextElement.prototype, "_loopAtEnd", void 0);
|
|
460
|
+
__decorate([query(`.text`)], PanTextElement.prototype, "_textEl", void 0);
|
|
461
|
+
PanTextElement = __decorate([safeCustomElement(`ixfx-pan-text`)], PanTextElement);
|
|
462
|
+
//#endregion
|
|
235
463
|
//#region src/grid-list/grid-list.ts
|
|
236
464
|
const ITEM_SELECTOR = `:scope > *`;
|
|
237
465
|
const MIN_ITEM_SIZE = 16;
|
|
@@ -317,6 +545,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
317
545
|
super(..._args);
|
|
318
546
|
this.selectionMode = `single`;
|
|
319
547
|
this.interactionMode = `standard`;
|
|
548
|
+
this.disableHoverTickle = false;
|
|
320
549
|
this.itemSize = 160;
|
|
321
550
|
this.gap = 8;
|
|
322
551
|
this.orientation = `grid`;
|
|
@@ -326,6 +555,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
326
555
|
this.captionBackdrop = `scrim`;
|
|
327
556
|
this.captionHeight = 24;
|
|
328
557
|
this.itemWrap = `stop`;
|
|
558
|
+
this.itemsDraggable = false;
|
|
329
559
|
this.items = [];
|
|
330
560
|
this._scrollTop = 0;
|
|
331
561
|
this._scrollLeft = 0;
|
|
@@ -362,10 +592,56 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
362
592
|
enabled: this.#source.isSelectable(i)
|
|
363
593
|
})),
|
|
364
594
|
onTickle: (k) => {
|
|
595
|
+
this.#stopActiveCaptionPan();
|
|
365
596
|
if (k !== void 0) this.#emitItemEvent(`list-tickle`, k);
|
|
366
597
|
},
|
|
367
598
|
onStateChange: () => this._syncItemStates(),
|
|
368
|
-
itemWrap: this.#itemWrap
|
|
599
|
+
itemWrap: this.#itemWrap,
|
|
600
|
+
hoverDisabled: () => this.disableHoverTickle || this.#dragSelect.isDragging
|
|
601
|
+
});
|
|
602
|
+
this.#marqueePreview = /* @__PURE__ */ new Set();
|
|
603
|
+
this.#nativeDragging = false;
|
|
604
|
+
this.#dragOriginKey = void 0;
|
|
605
|
+
this.#postDragSuppressTimer = 0;
|
|
606
|
+
this.#activeCaptionPan = null;
|
|
607
|
+
this.#dragSelect = new ListDragSelectController(this, {
|
|
608
|
+
getSurface: () => this.#viewportRef.value,
|
|
609
|
+
isEnabled: () => this.selection.canDragSelect() && this.#source.count > 0 && !this.hasAttribute(`disable-drag-select`),
|
|
610
|
+
hitTest: (rect) => this.#marqueeHitTest(rect),
|
|
611
|
+
getBaseSelection: () => this.selection.selected,
|
|
612
|
+
onPreview: (preview, rect) => {
|
|
613
|
+
this.#marqueePreview = preview;
|
|
614
|
+
this.#marqueeRect = rect;
|
|
615
|
+
this.requestUpdate();
|
|
616
|
+
},
|
|
617
|
+
onCommit: (finalSet) => {
|
|
618
|
+
this.selection.applyDragSelection(finalSet);
|
|
619
|
+
this.#marqueePreview = /* @__PURE__ */ new Set();
|
|
620
|
+
this.#marqueeRect = void 0;
|
|
621
|
+
this.requestUpdate();
|
|
622
|
+
},
|
|
623
|
+
autoScroll: (dx, dy) => {
|
|
624
|
+
const vp = this.#viewportRef.value;
|
|
625
|
+
if (!vp) return;
|
|
626
|
+
if (dx !== 0) {
|
|
627
|
+
vp.scrollLeft += dx;
|
|
628
|
+
this._scrollLeft = vp.scrollLeft;
|
|
629
|
+
}
|
|
630
|
+
if (dy !== 0) {
|
|
631
|
+
vp.scrollTop += dy;
|
|
632
|
+
this._scrollTop = vp.scrollTop;
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
shouldStart: (event) => {
|
|
636
|
+
if (!this.itemsDraggable) return true;
|
|
637
|
+
const cell = event.composedPath()[0]?.closest?.(`.cell`);
|
|
638
|
+
if (!cell) return true;
|
|
639
|
+
const key = cell.dataset.key;
|
|
640
|
+
if (!key) return true;
|
|
641
|
+
const index = this.#source.indexOfKey(key);
|
|
642
|
+
if (index < 0) return true;
|
|
643
|
+
return !this.#source.isSelectable(index);
|
|
644
|
+
}
|
|
369
645
|
});
|
|
370
646
|
this.#selectedSnapshot = /* @__PURE__ */ new Set();
|
|
371
647
|
this.#onScroll = (e) => {
|
|
@@ -378,6 +654,32 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
378
654
|
this.#emitViewportChange();
|
|
379
655
|
});
|
|
380
656
|
};
|
|
657
|
+
this.#onDragStart = (e, key) => {
|
|
658
|
+
if (!this.itemsDraggable) return;
|
|
659
|
+
const index = this.#source.indexOfKey(key);
|
|
660
|
+
if (index < 0 || !this.#source.isSelectable(index)) return;
|
|
661
|
+
if (!this.selection.selectedKeys.has(key)) this.selection.replace(key);
|
|
662
|
+
const selectedKeys = this.#source.keys().filter((k) => !isSyntheticKey(k)).filter((k) => this.selection.selectedKeys.has(k));
|
|
663
|
+
const detail = {
|
|
664
|
+
key,
|
|
665
|
+
index: this.#source.indexOfKey(key),
|
|
666
|
+
item: this.#source.resolveKeyToData(key) ?? this.#source.resolveKeyToElement(key),
|
|
667
|
+
selectedKeys
|
|
668
|
+
};
|
|
669
|
+
if (!this._dispatch(`grid-list-native-drag-start`, detail, true)) {
|
|
670
|
+
e.preventDefault();
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
this.#nativeDragging = true;
|
|
674
|
+
this.#dragOriginKey = key;
|
|
675
|
+
this.toggleAttribute(`data-native-dragging`, true);
|
|
676
|
+
const count = selectedKeys.length;
|
|
677
|
+
this.setAttribute(`aria-label`, count === 1 ? `Dragging 1 item` : `Dragging ${count} items`);
|
|
678
|
+
};
|
|
679
|
+
this.#onDragEnd = () => {
|
|
680
|
+
this.#clearNativeDragState();
|
|
681
|
+
this.#startPostDragSuppressTimer();
|
|
682
|
+
};
|
|
381
683
|
this._onKeyDown = (e) => {
|
|
382
684
|
if ((e.ctrlKey || e.metaKey) && e.key === `f`) return;
|
|
383
685
|
if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
|
|
@@ -447,6 +749,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
447
749
|
break;
|
|
448
750
|
}
|
|
449
751
|
case `Escape`:
|
|
752
|
+
if (this.#nativeDragging) this.#clearNativeDragState();
|
|
450
753
|
this.selection.clear();
|
|
451
754
|
break;
|
|
452
755
|
default: return;
|
|
@@ -514,7 +817,18 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
514
817
|
border-radius: var(--grid-list-radius);
|
|
515
818
|
}
|
|
516
819
|
|
|
517
|
-
/* The square that holds the slotted content.
|
|
820
|
+
/* The square that holds the slotted content — the "image well". Its
|
|
821
|
+
background is a set of consumer-settable variables so a Finder-style
|
|
822
|
+
look is possible: on selection the caption takes the accent colouring
|
|
823
|
+
while the well takes a tint of the surface colour. Each variable is
|
|
824
|
+
unset by default, so the fallback (today's look) applies until a
|
|
825
|
+
consumer opts in.
|
|
826
|
+
--grid-list-thumb-bg idle well background
|
|
827
|
+
--grid-list-thumb-bg-tickled under the cursor
|
|
828
|
+
--grid-list-thumb-bg-selected when the cell is selected
|
|
829
|
+
--grid-list-thumb-bg-selected-tickled selected + under the cursor
|
|
830
|
+
--grid-list-thumb-selection-wash colour of the box-mode wash (default: --accent)
|
|
831
|
+
--grid-list-thumb-selection-wash-opacity strength of that wash (default: 0.18; set 0 to drop it) */
|
|
518
832
|
.thumb {
|
|
519
833
|
position: relative;
|
|
520
834
|
flex: 1;
|
|
@@ -524,7 +838,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
524
838
|
box-sizing: border-box;
|
|
525
839
|
overflow: hidden;
|
|
526
840
|
border-radius: 0;
|
|
527
|
-
background: transparent;
|
|
841
|
+
background: var(--grid-list-thumb-bg, transparent);
|
|
528
842
|
border: 1px solid transparent;
|
|
529
843
|
transition: background var(--transition), border-color var(--transition);
|
|
530
844
|
}
|
|
@@ -537,6 +851,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
537
851
|
align-items: center;
|
|
538
852
|
justify-content: center;
|
|
539
853
|
overflow: hidden;
|
|
854
|
+
draggable: false;
|
|
540
855
|
}
|
|
541
856
|
.thumb ::slotted(*:empty)::after {
|
|
542
857
|
content: "Empty";
|
|
@@ -548,19 +863,27 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
548
863
|
}
|
|
549
864
|
|
|
550
865
|
/* Selection / cursor wash — sits over the slotted content so it reads
|
|
551
|
-
on photos and arbitrary DOM alike.
|
|
866
|
+
on photos and arbitrary DOM alike. Set
|
|
867
|
+
--grid-list-thumb-selection-wash-opacity: 0 to drop it in favour of a
|
|
868
|
+
--grid-list-thumb-bg-selected tint. */
|
|
552
869
|
.thumb::after {
|
|
553
870
|
content: "";
|
|
554
871
|
position: absolute;
|
|
555
872
|
inset: 0;
|
|
556
873
|
pointer-events: none;
|
|
557
874
|
border-radius: inherit;
|
|
558
|
-
background: var(--accent);
|
|
875
|
+
background: var(--grid-list-thumb-selection-wash, var(--accent));
|
|
559
876
|
opacity: 0;
|
|
560
877
|
transition: opacity var(--transition, 0.1s ease-out);
|
|
561
878
|
}
|
|
562
879
|
.cell.selected .thumb::after {
|
|
563
|
-
opacity: 0.18;
|
|
880
|
+
opacity: var(--grid-list-thumb-selection-wash-opacity, 0.18);
|
|
881
|
+
}
|
|
882
|
+
:host(:not([caption-style="separate"])) .cell.selected .thumb {
|
|
883
|
+
background: var(--grid-list-thumb-bg-selected, var(--grid-list-thumb-bg, transparent));
|
|
884
|
+
}
|
|
885
|
+
:host(:not([caption-style="separate"])) .cell.selected.tickled .thumb {
|
|
886
|
+
background: var(--grid-list-thumb-bg-selected-tickled, var(--grid-list-thumb-bg-selected, var(--grid-list-thumb-bg, transparent)));
|
|
564
887
|
}
|
|
565
888
|
|
|
566
889
|
/* ---- Caption (base) ---- */
|
|
@@ -578,6 +901,18 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
578
901
|
}
|
|
579
902
|
:host([caption-align="left"]) .caption { text-align: left; }
|
|
580
903
|
:host([caption-align="right"]) .caption { text-align: right; }
|
|
904
|
+
/* Tickled captions swap their plain label for an ixfx-pan-text in loop
|
|
905
|
+
mode so a truncated label scrolls instead of staying an ellipsis. The
|
|
906
|
+
pan fills the caption band (flex in 'separate', block otherwise) and
|
|
907
|
+
inherits its alignment. */
|
|
908
|
+
.caption ixfx-pan-text {
|
|
909
|
+
display: block;
|
|
910
|
+
flex: 1;
|
|
911
|
+
min-width: 0;
|
|
912
|
+
max-width: 100%;
|
|
913
|
+
font: inherit;
|
|
914
|
+
color: inherit;
|
|
915
|
+
}
|
|
581
916
|
|
|
582
917
|
/* ---- Box modes (hidden / under / overlaid): the cell is one box with a
|
|
583
918
|
single selection outline ---- */
|
|
@@ -587,8 +922,8 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
587
922
|
overflow: hidden;
|
|
588
923
|
transition: background var(--transition), border-color var(--transition);
|
|
589
924
|
}
|
|
590
|
-
:host(:not([caption-style="separate"])) .cell
|
|
591
|
-
:host(:not([caption-style="separate"])) .cell
|
|
925
|
+
:host(:not([caption-style="separate"])) .cell.tickled,
|
|
926
|
+
:host(:not([caption-style="separate"]):not([disable-hover-tickle])) .cell:hover {
|
|
592
927
|
background: var(--item-bg-tickled);
|
|
593
928
|
border: var(--item-border-tickled);
|
|
594
929
|
}
|
|
@@ -655,12 +990,12 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
655
990
|
:host([caption-style="separate"]) .thumb {
|
|
656
991
|
flex: none;
|
|
657
992
|
border-radius: var(--grid-list-radius);
|
|
658
|
-
background: var(--grid-list-item-bg);
|
|
993
|
+
background: var(--grid-list-thumb-bg, var(--grid-list-item-bg));
|
|
659
994
|
border: 1px solid transparent;
|
|
660
995
|
}
|
|
661
|
-
:host([caption-style="separate"]) .cell
|
|
662
|
-
:host([caption-style="separate"]) .cell
|
|
663
|
-
background: var(--item-bg-tickled);
|
|
996
|
+
:host([caption-style="separate"]) .cell.tickled .thumb,
|
|
997
|
+
:host([caption-style="separate"]:not([disable-hover-tickle])) .cell:hover .thumb {
|
|
998
|
+
background: var(--grid-list-thumb-bg-tickled, var(--item-bg-tickled));
|
|
664
999
|
border: var(--item-border-tickled);
|
|
665
1000
|
}
|
|
666
1001
|
:host([caption-style="separate"]) .caption {
|
|
@@ -673,14 +1008,17 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
673
1008
|
}
|
|
674
1009
|
:host([caption-style="separate"][caption-align="left"]) .caption { align-self: flex-start; }
|
|
675
1010
|
:host([caption-style="separate"][caption-align="right"]) .caption { align-self: flex-end; }
|
|
1011
|
+
/* Inset the selection ring (negative offset) so it is never clipped by the
|
|
1012
|
+
scroll viewport's overflow when the cell sits against an edge. */
|
|
676
1013
|
:host([caption-style="separate"]) .cell.selected .thumb {
|
|
1014
|
+
background: var(--grid-list-thumb-bg-selected, var(--grid-list-thumb-bg, var(--grid-list-item-bg)));
|
|
677
1015
|
outline: 2px solid var(--accent);
|
|
678
|
-
outline-offset: 2px;
|
|
1016
|
+
outline-offset: -2px;
|
|
679
1017
|
}
|
|
680
1018
|
:host([caption-style="separate"]) .cell.selected.tickled .thumb {
|
|
681
|
-
background: var(--item-bg-selected-tickled);
|
|
1019
|
+
background: var(--grid-list-thumb-bg-selected-tickled, var(--item-bg-selected-tickled));
|
|
682
1020
|
outline: 2px dashed var(--surface-3);
|
|
683
|
-
outline-offset: 2px;
|
|
1021
|
+
outline-offset: -2px;
|
|
684
1022
|
}
|
|
685
1023
|
:host([caption-style="separate"]) .cell.selected .caption {
|
|
686
1024
|
background: var(--accent);
|
|
@@ -718,6 +1056,26 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
718
1056
|
:host([reflowing]) .cell { transition: background var(--transition), border-color var(--transition); }
|
|
719
1057
|
.cell.entering { animation: none; }
|
|
720
1058
|
}
|
|
1059
|
+
|
|
1060
|
+
/* Drag-select (marquee) rectangle + covered-cell preview. The preview
|
|
1061
|
+
reuses the selection wash so covered cells read as "about to be
|
|
1062
|
+
selected". Style hooks: part="marquee", --grid-list-marquee-border,
|
|
1063
|
+
--grid-list-marquee-fill. */
|
|
1064
|
+
.marquee {
|
|
1065
|
+
position: absolute;
|
|
1066
|
+
pointer-events: none;
|
|
1067
|
+
z-index: 5;
|
|
1068
|
+
border: 1px solid var(--grid-list-marquee-border, var(--accent));
|
|
1069
|
+
background: var(--grid-list-marquee-fill, color-mix(in srgb, var(--accent) 15%, transparent));
|
|
1070
|
+
}
|
|
1071
|
+
.cell.marquee .thumb::after {
|
|
1072
|
+
opacity: var(--grid-list-thumb-selection-wash-opacity, 0.18);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/* Native item drag origin cell. */
|
|
1076
|
+
.cell.dragging-origin {
|
|
1077
|
+
opacity: 0.6;
|
|
1078
|
+
}
|
|
721
1079
|
`
|
|
722
1080
|
];
|
|
723
1081
|
}
|
|
@@ -750,6 +1108,62 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
750
1108
|
*/
|
|
751
1109
|
#sourceElement;
|
|
752
1110
|
#source;
|
|
1111
|
+
/** Live drag-select preview: covered keys + the surface-relative rect. */
|
|
1112
|
+
#marqueePreview;
|
|
1113
|
+
#marqueeRect;
|
|
1114
|
+
/** Native item drag state: true while a drag is active. */
|
|
1115
|
+
#nativeDragging;
|
|
1116
|
+
/** Key of the cell that originated the native drag. */
|
|
1117
|
+
#dragOriginKey;
|
|
1118
|
+
/** Timer handle for post-drag click suppression. */
|
|
1119
|
+
#postDragSuppressTimer;
|
|
1120
|
+
/**
|
|
1121
|
+
* The single caption pan-text currently scrolling. At most one caption is
|
|
1122
|
+
* a pan-text in loop mode at a time — when tickle moves, the old one is
|
|
1123
|
+
* stopped before the new one starts (see `#activateTickledPan`).
|
|
1124
|
+
*/
|
|
1125
|
+
#activeCaptionPan;
|
|
1126
|
+
#dragSelect;
|
|
1127
|
+
/**
|
|
1128
|
+
* Map a surface-relative (viewport-visible) rect to covered item keys using
|
|
1129
|
+
* the same `computeGridWindow` geometry the renderer uses — pure arithmetic,
|
|
1130
|
+
* so virtualized off-screen items are covered without DOM measurement.
|
|
1131
|
+
*/
|
|
1132
|
+
#marqueeHitTest(rect) {
|
|
1133
|
+
const count = this.#source.count;
|
|
1134
|
+
if (count === 0) return [];
|
|
1135
|
+
const horizontal = this.orientation === `row`;
|
|
1136
|
+
const win = computeGridWindow(count, this.itemSize, this.#rowHeight(), this.gap, Math.max(1, this._viewportWidth), Math.max(1, this._viewportHeight), horizontal ? this._scrollLeft : this._scrollTop, this.orientation, 0);
|
|
1137
|
+
const out = [];
|
|
1138
|
+
if (horizontal) {
|
|
1139
|
+
const x0 = rect.x + this._scrollLeft;
|
|
1140
|
+
const x1 = x0 + rect.width;
|
|
1141
|
+
const lo = Math.max(0, Math.floor(x0 / win.colStride));
|
|
1142
|
+
const hi = Math.min(count - 1, Math.floor(x1 / win.colStride));
|
|
1143
|
+
for (let i = lo; i <= hi; i++) out.push(i);
|
|
1144
|
+
} else {
|
|
1145
|
+
const x0 = rect.x + this._scrollLeft;
|
|
1146
|
+
const x1 = x0 + rect.width;
|
|
1147
|
+
const y0 = rect.y + this._scrollTop;
|
|
1148
|
+
const y1 = y0 + rect.height;
|
|
1149
|
+
const colLo = Math.max(0, Math.floor(x0 / win.colStride));
|
|
1150
|
+
const colHi = Math.min(win.cols - 1, Math.floor(x1 / win.colStride));
|
|
1151
|
+
const rowLo = Math.max(0, Math.floor(y0 / win.rowStride));
|
|
1152
|
+
const rowHi = Math.floor(y1 / win.rowStride);
|
|
1153
|
+
for (let row = rowLo; row <= rowHi; row++) for (let col = colLo; col <= colHi; col++) {
|
|
1154
|
+
const index = row * win.cols + col;
|
|
1155
|
+
if (index >= 0 && index < count) out.push(index);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
const keys = [];
|
|
1159
|
+
for (const index of out) {
|
|
1160
|
+
const key = this.#source.keyAt(index);
|
|
1161
|
+
if (!key || isSyntheticKey(key)) continue;
|
|
1162
|
+
if (!this.#source.isSelectable(index)) continue;
|
|
1163
|
+
keys.push(key);
|
|
1164
|
+
}
|
|
1165
|
+
return keys;
|
|
1166
|
+
}
|
|
753
1167
|
#searchMode;
|
|
754
1168
|
#searchFilterKeys;
|
|
755
1169
|
/** (Re)build {@link search} for the current mode; a no-op if it already matches. */
|
|
@@ -822,6 +1236,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
822
1236
|
}
|
|
823
1237
|
disconnectedCallback() {
|
|
824
1238
|
super.disconnectedCallback();
|
|
1239
|
+
this.#stopActiveCaptionPan();
|
|
825
1240
|
this.removeEventListener(`keydown`, this._onKeyDown);
|
|
826
1241
|
this.#resizeObserver?.disconnect();
|
|
827
1242
|
this.#resizeObserver = void 0;
|
|
@@ -834,6 +1249,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
834
1249
|
clearTimeout(this.#reflowTimer);
|
|
835
1250
|
this.#reflowTimer = 0;
|
|
836
1251
|
}
|
|
1252
|
+
if (this.#nativeDragging) this.#clearNativeDragState();
|
|
837
1253
|
}
|
|
838
1254
|
#onChildrenChanged(records) {
|
|
839
1255
|
const previousLength = this.#items.length;
|
|
@@ -1021,6 +1437,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1021
1437
|
if (Math.abs(vp.scrollLeft - this._scrollLeft) > .5) vp.scrollLeft = this._scrollLeft;
|
|
1022
1438
|
}
|
|
1023
1439
|
this.#applyZoomAnchor();
|
|
1440
|
+
this.#activateTickledPan();
|
|
1024
1441
|
}
|
|
1025
1442
|
/** Re-anchor the scroll so the item captured in `willUpdate` stays centred. */
|
|
1026
1443
|
#applyZoomAnchor() {
|
|
@@ -1351,15 +1768,19 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1351
1768
|
element
|
|
1352
1769
|
});
|
|
1353
1770
|
}
|
|
1354
|
-
_dispatch(name, detail) {
|
|
1355
|
-
this.dispatchEvent(new CustomEvent(name, {
|
|
1771
|
+
_dispatch(name, detail, cancelable = false) {
|
|
1772
|
+
return this.dispatchEvent(new CustomEvent(name, {
|
|
1356
1773
|
detail,
|
|
1357
1774
|
bubbles: true,
|
|
1358
|
-
composed: true
|
|
1775
|
+
composed: true,
|
|
1776
|
+
cancelable
|
|
1359
1777
|
}));
|
|
1360
1778
|
}
|
|
1361
1779
|
/** Selected keys, snapshotted once per render so the cell renderers don't each rebuild the set. */
|
|
1362
1780
|
#selectedSnapshot;
|
|
1781
|
+
#marqueeStyle(rect) {
|
|
1782
|
+
return `left:${rect.x}px;top:${rect.y}px;width:${Math.max(0, rect.width)}px;height:${Math.max(0, rect.height)}px`;
|
|
1783
|
+
}
|
|
1363
1784
|
render() {
|
|
1364
1785
|
const win = this.#currentWindow();
|
|
1365
1786
|
this.#selectedSnapshot = this.selection.selectedKeys;
|
|
@@ -1376,6 +1797,7 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1376
1797
|
<div class="spacer" style=${spacerStyle}>
|
|
1377
1798
|
${this.#source instanceof DataGridListSource ? this.#renderDataCells(win) : this.#renderElementCells(win)}
|
|
1378
1799
|
</div>
|
|
1800
|
+
${this.#marqueeRect ? html`<div class="marquee" part="marquee" style=${this.#marqueeStyle(this.#marqueeRect)}></div>` : ``}
|
|
1379
1801
|
</div>
|
|
1380
1802
|
${this.search?.renderField()}
|
|
1381
1803
|
`;
|
|
@@ -1387,7 +1809,10 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1387
1809
|
#renderDataCell(index, win) {
|
|
1388
1810
|
const key = this.#source.keyAt(index);
|
|
1389
1811
|
const selected = this.#selectedSnapshot.has(key);
|
|
1812
|
+
const marquee = this.#marqueePreview.has(key);
|
|
1390
1813
|
const tickled = this.tickled.isTickled(key);
|
|
1814
|
+
const selectable = this.#source.isSelectable(index);
|
|
1815
|
+
const draggable = this.itemsDraggable && selectable;
|
|
1391
1816
|
const style = this.captionStyle;
|
|
1392
1817
|
const separate = style === `separate`;
|
|
1393
1818
|
const caption = style === `hidden` ? `` : this.#source.labelAt(index);
|
|
@@ -1398,24 +1823,69 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1398
1823
|
const captionCss = separate ? `height:${Math.max(0, this.captionHeight - 4)}px` : style === `under` ? `height:${this.captionHeight}px` : ``;
|
|
1399
1824
|
return html`
|
|
1400
1825
|
<div
|
|
1401
|
-
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}"
|
|
1826
|
+
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}${marquee ? ` marquee` : ``}${this.#nativeDragging && key === this.#dragOriginKey ? ` dragging-origin` : ``}"
|
|
1402
1827
|
part="item${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}"
|
|
1403
1828
|
role="option"
|
|
1404
1829
|
aria-selected=${selected ? `true` : `false`}
|
|
1405
1830
|
style="width:${this.itemSize}px;height:${cellHeight}px;transform:translate(${x}px,${y}px)"
|
|
1406
1831
|
data-index=${index}
|
|
1407
1832
|
data-key=${key}
|
|
1833
|
+
draggable=${draggable ? `true` : `false`}
|
|
1408
1834
|
?data-selected=${selected}
|
|
1409
1835
|
?data-tickled=${tickled}
|
|
1836
|
+
?data-marquee=${marquee}
|
|
1410
1837
|
@click=${(e) => this.#onCellClick(e, key)}
|
|
1411
1838
|
@dblclick=${() => this.#onCellActivate(key)}
|
|
1412
1839
|
@pointerenter=${() => this.tickled.handlePointerEnter(key)}
|
|
1840
|
+
@dragstart=${(e) => this.#onDragStart(e, key)}
|
|
1841
|
+
@dragend=${() => this.#onDragEnd()}
|
|
1413
1842
|
>
|
|
1414
1843
|
<div class="content" part="content">${this.#source.renderCellContent(index)}</div>
|
|
1415
|
-
${showCaption ?
|
|
1844
|
+
${showCaption ? this.#renderCaption(caption, captionCss, tickled) : ``}
|
|
1416
1845
|
</div>
|
|
1417
1846
|
`;
|
|
1418
1847
|
}
|
|
1848
|
+
/**
|
|
1849
|
+
* A tickled cell swaps its plain label for an `ixfx-pan-text` in loop mode
|
|
1850
|
+
* so a truncated label scrolls instead of staying an ellipsis. Unticked
|
|
1851
|
+
* cells keep the cheap plain-text caption.
|
|
1852
|
+
*/
|
|
1853
|
+
#renderCaption(caption, captionCss, tickled) {
|
|
1854
|
+
if (tickled) return html`<div class="caption" part="caption" style=${captionCss} title=${caption}><ixfx-pan-text mode="loop">${caption}</ixfx-pan-text></div>`;
|
|
1855
|
+
return html`<div class="caption" part="caption" style=${captionCss} title=${caption}>${caption}</div>`;
|
|
1856
|
+
}
|
|
1857
|
+
/** Stop the active caption pan, if any, and forget it. */
|
|
1858
|
+
#stopActiveCaptionPan() {
|
|
1859
|
+
const active = this.#activeCaptionPan;
|
|
1860
|
+
this.#activeCaptionPan = null;
|
|
1861
|
+
try {
|
|
1862
|
+
active?.stopLoop?.();
|
|
1863
|
+
} catch {}
|
|
1864
|
+
}
|
|
1865
|
+
/**
|
|
1866
|
+
* Enforce a single scrolling caption: the tickled cell's pan-text loops,
|
|
1867
|
+
* every other pan-text is stopped. The pan-text also auto-starts when
|
|
1868
|
+
* `mode="loop"` is set; this covers the case where the element was already
|
|
1869
|
+
* connected before overflow was measured.
|
|
1870
|
+
*/
|
|
1871
|
+
#activateTickledPan() {
|
|
1872
|
+
const tickledCell = this.renderRoot.querySelector(`.cell[data-tickled]`);
|
|
1873
|
+
const pans = [...this.renderRoot.querySelectorAll(`ixfx-pan-text[mode="loop"]`)];
|
|
1874
|
+
const current = tickledCell?.querySelector(`ixfx-pan-text[mode="loop"]`) ?? null;
|
|
1875
|
+
for (const pan of pans) if (pan !== current) try {
|
|
1876
|
+
pan.stopLoop?.();
|
|
1877
|
+
} catch {}
|
|
1878
|
+
const active = this.#activeCaptionPan;
|
|
1879
|
+
if (active && active !== current) try {
|
|
1880
|
+
active.stopLoop?.();
|
|
1881
|
+
} catch {}
|
|
1882
|
+
if (!current) {
|
|
1883
|
+
this.#activeCaptionPan = null;
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
this.#activeCaptionPan = current;
|
|
1887
|
+
current.startLoop?.();
|
|
1888
|
+
}
|
|
1419
1889
|
#renderElementCells(win) {
|
|
1420
1890
|
const slice = this.#items.slice(win.startIndex, win.endIndex);
|
|
1421
1891
|
return repeat(slice, (_el, i) => this.#source.keyAt(win.startIndex + i), (el, i) => this.#renderCell(el, win.startIndex + i, win));
|
|
@@ -1423,8 +1893,11 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1423
1893
|
#renderCell(el, index, win) {
|
|
1424
1894
|
const key = this.#source.keyAt(index);
|
|
1425
1895
|
const selected = this.#selectedSnapshot.has(key);
|
|
1896
|
+
const marquee = this.#marqueePreview.has(key);
|
|
1426
1897
|
const tickled = this.tickled.isTickled(key);
|
|
1427
1898
|
const entering = this.#entering.has(el);
|
|
1899
|
+
const selectable = this.#source.isSelectable(index);
|
|
1900
|
+
const draggable = this.itemsDraggable && selectable;
|
|
1428
1901
|
const style = this.captionStyle;
|
|
1429
1902
|
const separate = style === `separate`;
|
|
1430
1903
|
const caption = style === `hidden` ? `` : this.#captionFor(el);
|
|
@@ -1436,23 +1909,27 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1436
1909
|
const captionCss = separate ? `height:${Math.max(0, this.captionHeight - 4)}px` : style === `under` ? `height:${this.captionHeight}px` : ``;
|
|
1437
1910
|
return html`
|
|
1438
1911
|
<div
|
|
1439
|
-
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}${entering ? ` entering` : ``}"
|
|
1912
|
+
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}${entering ? ` entering` : ``}${marquee ? ` marquee` : ``}${this.#nativeDragging && key === this.#dragOriginKey ? ` dragging-origin` : ``}"
|
|
1440
1913
|
part="item${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}"
|
|
1441
1914
|
role="option"
|
|
1442
1915
|
aria-selected=${selected ? `true` : `false`}
|
|
1443
1916
|
style="width:${this.itemSize}px;height:${cellHeight}px;transform:translate(${x}px,${y}px)"
|
|
1444
1917
|
data-index=${index}
|
|
1445
1918
|
data-key=${key}
|
|
1919
|
+
draggable=${draggable ? `true` : `false`}
|
|
1446
1920
|
?data-selected=${selected}
|
|
1447
1921
|
?data-tickled=${tickled}
|
|
1922
|
+
?data-marquee=${marquee}
|
|
1448
1923
|
@click=${(e) => this.#onCellClick(e, key)}
|
|
1449
1924
|
@dblclick=${() => this.#onCellActivate(key)}
|
|
1450
1925
|
@pointerenter=${() => this.tickled.handlePointerEnter(key)}
|
|
1926
|
+
@dragstart=${(e) => this.#onDragStart(e, key)}
|
|
1927
|
+
@dragend=${() => this.#onDragEnd()}
|
|
1451
1928
|
>
|
|
1452
1929
|
<div class="thumb" part="thumb" style=${thumbStyle}>
|
|
1453
1930
|
${this.#source.renderCellContent(index)}
|
|
1454
1931
|
</div>
|
|
1455
|
-
${showCaption ?
|
|
1932
|
+
${showCaption ? this.#renderCaption(caption, captionCss, tickled) : ``}
|
|
1456
1933
|
</div>
|
|
1457
1934
|
`;
|
|
1458
1935
|
}
|
|
@@ -1464,9 +1941,24 @@ let GridListElement = class GridListElement extends LitElement {
|
|
|
1464
1941
|
}
|
|
1465
1942
|
}
|
|
1466
1943
|
#onCellClick(e, key) {
|
|
1944
|
+
if (this.#dragSelect.isDragging || this.#nativeDragging || this.#postDragSuppressTimer !== 0) return;
|
|
1467
1945
|
this.selection.handleClick(key, e);
|
|
1468
1946
|
this.#emitItemEvent(`list-item-click`, key);
|
|
1469
1947
|
}
|
|
1948
|
+
#onDragStart;
|
|
1949
|
+
#onDragEnd;
|
|
1950
|
+
#startPostDragSuppressTimer() {
|
|
1951
|
+
if (this.#postDragSuppressTimer) clearTimeout(this.#postDragSuppressTimer);
|
|
1952
|
+
this.#postDragSuppressTimer = window.setTimeout(() => {
|
|
1953
|
+
this.#postDragSuppressTimer = 0;
|
|
1954
|
+
}, 0);
|
|
1955
|
+
}
|
|
1956
|
+
#clearNativeDragState() {
|
|
1957
|
+
this.#nativeDragging = false;
|
|
1958
|
+
this.#dragOriginKey = void 0;
|
|
1959
|
+
this.toggleAttribute(`data-native-dragging`, false);
|
|
1960
|
+
this.removeAttribute(`aria-label`);
|
|
1961
|
+
}
|
|
1470
1962
|
#onCellActivate(key) {
|
|
1471
1963
|
if (this.interactionMode !== `manual`) this.selection.replace(key);
|
|
1472
1964
|
this.#emitItemEvent(`list-activate`, key);
|
|
@@ -1480,6 +1972,11 @@ __decorate([property({
|
|
|
1480
1972
|
type: String,
|
|
1481
1973
|
attribute: `interaction-mode`
|
|
1482
1974
|
})], GridListElement.prototype, "interactionMode", void 0);
|
|
1975
|
+
__decorate([property({
|
|
1976
|
+
type: Boolean,
|
|
1977
|
+
attribute: `disable-hover-tickle`,
|
|
1978
|
+
reflect: true
|
|
1979
|
+
})], GridListElement.prototype, "disableHoverTickle", void 0);
|
|
1483
1980
|
__decorate([property({
|
|
1484
1981
|
type: Number,
|
|
1485
1982
|
attribute: `item-size`
|
|
@@ -1519,6 +2016,11 @@ __decorate([property({
|
|
|
1519
2016
|
})], GridListElement.prototype, "itemWrap", void 0);
|
|
1520
2017
|
__decorate([property({ attribute: false })], GridListElement.prototype, "filterPredicate", void 0);
|
|
1521
2018
|
__decorate([property({ attribute: false })], GridListElement.prototype, "itemFilterPredicate", void 0);
|
|
2019
|
+
__decorate([property({
|
|
2020
|
+
type: Boolean,
|
|
2021
|
+
attribute: `items-draggable`,
|
|
2022
|
+
reflect: true
|
|
2023
|
+
})], GridListElement.prototype, "itemsDraggable", void 0);
|
|
1522
2024
|
__decorate([property({
|
|
1523
2025
|
type: String,
|
|
1524
2026
|
attribute: `search-modes`,
|
|
@@ -1532,6 +2034,6 @@ __decorate([state()], GridListElement.prototype, "_viewportHeight", void 0);
|
|
|
1532
2034
|
__decorate([state()], GridListElement.prototype, "_viewportWidth", void 0);
|
|
1533
2035
|
GridListElement = __decorate([safeCustomElement(`ixfx-grid-list`)], GridListElement);
|
|
1534
2036
|
//#endregion
|
|
1535
|
-
export { GridListElement as t };
|
|
2037
|
+
export { PanTextElement as n, GridListElement as t };
|
|
1536
2038
|
|
|
1537
|
-
//# sourceMappingURL=grid-list-
|
|
2039
|
+
//# sourceMappingURL=grid-list-BXfY3XXX.js.map
|