@design.estate/dees-catalog 13.0.1 → 13.0.2

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.
@@ -184498,9 +184498,9 @@ var demoFunc72 = /* @__PURE__ */ __name(() => {
184498
184498
  init_dist_ts26();
184499
184499
  init_dees_button();
184500
184500
  init_dees_icon();
184501
- var _pending_dec3, _movable_dec, _columns_dec4, _subtasks_dec, _epic_dec, _ticket_dec2, _a107, _DeesKanbanCard_decorators, _init109, _ticket2, _epic, _subtasks, _columns4, _movable, _pending3;
184501
+ var _pointerManaged_dec, _saving_dec3, _pending_dec3, _moveDisabled_dec, _movable_dec, _columns_dec4, _subtasks_dec, _epic_dec, _ticket_dec2, _a107, _DeesKanbanCard_decorators, _init109, _ticket2, _epic, _subtasks, _columns4, _movable, _moveDisabled, _pending3, _saving3, _pointerManaged;
184502
184502
  _DeesKanbanCard_decorators = [customElement("dees-kanban-card")];
184503
- var _DeesKanbanCard = class _DeesKanbanCard extends (_a107 = DeesElement, _ticket_dec2 = [n5({ attribute: false })], _epic_dec = [n5({ attribute: false })], _subtasks_dec = [n5({ attribute: false })], _columns_dec4 = [n5({ attribute: false })], _movable_dec = [n5({ type: Boolean })], _pending_dec3 = [n5({ type: Boolean })], _a107) {
184503
+ var _DeesKanbanCard = class _DeesKanbanCard extends (_a107 = DeesElement, _ticket_dec2 = [n5({ attribute: false })], _epic_dec = [n5({ attribute: false })], _subtasks_dec = [n5({ attribute: false })], _columns_dec4 = [n5({ attribute: false })], _movable_dec = [n5({ type: Boolean })], _moveDisabled_dec = [n5({ type: Boolean })], _pending_dec3 = [n5({ type: Boolean })], _saving_dec3 = [n5({ type: Boolean })], _pointerManaged_dec = [n5({ attribute: false })], _a107) {
184504
184504
  constructor() {
184505
184505
  super(...arguments);
184506
184506
  __privateAdd(this, _ticket2, __runInitializers(_init109, 8, this)), __runInitializers(_init109, 11, this);
@@ -184508,7 +184508,10 @@ var _DeesKanbanCard = class _DeesKanbanCard extends (_a107 = DeesElement, _ticke
184508
184508
  __privateAdd(this, _subtasks, __runInitializers(_init109, 16, this, [])), __runInitializers(_init109, 19, this);
184509
184509
  __privateAdd(this, _columns4, __runInitializers(_init109, 20, this, [])), __runInitializers(_init109, 23, this);
184510
184510
  __privateAdd(this, _movable, __runInitializers(_init109, 24, this, false)), __runInitializers(_init109, 27, this);
184511
- __privateAdd(this, _pending3, __runInitializers(_init109, 28, this, false)), __runInitializers(_init109, 31, this);
184511
+ __privateAdd(this, _moveDisabled, __runInitializers(_init109, 28, this, false)), __runInitializers(_init109, 31, this);
184512
+ __privateAdd(this, _pending3, __runInitializers(_init109, 32, this, false)), __runInitializers(_init109, 35, this);
184513
+ __privateAdd(this, _saving3, __runInitializers(_init109, 36, this, false)), __runInitializers(_init109, 39, this);
184514
+ __privateAdd(this, _pointerManaged, __runInitializers(_init109, 40, this, false)), __runInitializers(_init109, 43, this);
184512
184515
  }
184513
184516
  open(ticketId) {
184514
184517
  kanbanEvent(this, "kanban-ticket-open", { ticketId });
@@ -184517,19 +184520,22 @@ var _DeesKanbanCard = class _DeesKanbanCard extends (_a107 = DeesElement, _ticke
184517
184520
  const ticket = this.ticket;
184518
184521
  if (!ticket) return b2``;
184519
184522
  const completed = this.subtasks.filter((task) => this.columns.some((column) => column.id === task.columnId && column.done)).length;
184520
- return b2`<article aria-busy=${String(this.pending)} draggable=${this.movable && !this.pending ? "true" : "false"}
184523
+ return b2`<article aria-busy=${String(this.pending)} data-movable=${String(this.movable && !this.moveDisabled && !this.pending)}
184524
+ draggable=${String(this.movable && !this.moveDisabled && !this.pending && !this.pointerManaged)}
184521
184525
  @dragstart=${(event) => {
184522
- if (!this.movable || this.pending || !event.dataTransfer) {
184526
+ if (this.pointerManaged || !this.movable || this.moveDisabled || this.pending || !event.dataTransfer) {
184523
184527
  event.preventDefault();
184524
184528
  return;
184525
184529
  }
184526
184530
  event.dataTransfer.setData("application/x-dees-kanban-ticket", ticket.id);
184527
184531
  event.dataTransfer.effectAllowed = "move";
184528
184532
  kanbanEvent(this, "kanban-drag-start", { ticketId: ticket.id });
184529
- }} @dragend=${() => kanbanEvent(this, "kanban-drag-end", {})}>
184533
+ }} @dragend=${() => {
184534
+ if (!this.pointerManaged) kanbanEvent(this, "kanban-drag-end", {});
184535
+ }}>
184530
184536
  <div class="meta"><span class="key">${ticket.key}</span>
184531
184537
  ${this.epic ? b2`<button class="link epic" title=${this.epic.title} @click=${() => this.open(this.epic.id)}>${this.epic.title}</button>` : ""}
184532
- ${this.movable ? b2`<dees-button class="move" size="icon" type="ghost" icon="lucide:Ellipsis" text="Move ticket" .disabled=${this.pending}
184538
+ ${this.saving ? b2`<span class="saving" role="status">Saving…</span>` : this.movable ? b2`<dees-button class="move" size="icon" type="ghost" icon="lucide:Ellipsis" text="Move ticket" .disabled=${this.pending || this.moveDisabled}
184533
184539
  @clicked=${(event) => kanbanEvent(this, "kanban-move-menu", { ticketId: ticket.id, anchor: event.currentTarget })}></dees-button>` : ""}
184534
184540
  </div>
184535
184541
  <button class="title" @click=${() => this.open(ticket.id)}>${ticket.title}</button>
@@ -184550,24 +184556,32 @@ _epic = new WeakMap();
184550
184556
  _subtasks = new WeakMap();
184551
184557
  _columns4 = new WeakMap();
184552
184558
  _movable = new WeakMap();
184559
+ _moveDisabled = new WeakMap();
184553
184560
  _pending3 = new WeakMap();
184561
+ _saving3 = new WeakMap();
184562
+ _pointerManaged = new WeakMap();
184554
184563
  __decorateElement(_init109, 4, "ticket", _ticket_dec2, _DeesKanbanCard, _ticket2);
184555
184564
  __decorateElement(_init109, 4, "epic", _epic_dec, _DeesKanbanCard, _epic);
184556
184565
  __decorateElement(_init109, 4, "subtasks", _subtasks_dec, _DeesKanbanCard, _subtasks);
184557
184566
  __decorateElement(_init109, 4, "columns", _columns_dec4, _DeesKanbanCard, _columns4);
184558
184567
  __decorateElement(_init109, 4, "movable", _movable_dec, _DeesKanbanCard, _movable);
184568
+ __decorateElement(_init109, 4, "moveDisabled", _moveDisabled_dec, _DeesKanbanCard, _moveDisabled);
184559
184569
  __decorateElement(_init109, 4, "pending", _pending_dec3, _DeesKanbanCard, _pending3);
184570
+ __decorateElement(_init109, 4, "saving", _saving_dec3, _DeesKanbanCard, _saving3);
184571
+ __decorateElement(_init109, 4, "pointerManaged", _pointerManaged_dec, _DeesKanbanCard, _pointerManaged);
184560
184572
  _DeesKanbanCard = __decorateElement(_init109, 0, "DeesKanbanCard", _DeesKanbanCard_decorators, _DeesKanbanCard);
184561
184573
  __name(_DeesKanbanCard, "DeesKanbanCard");
184562
184574
  __publicField(_DeesKanbanCard, "styles", [...kanbanStyles, i`
184563
184575
  article { padding: 12px; border: 1px solid var(--dees-color-border-subtle); border-radius: var(--dees-radius-xl); corner-shape: var(--dees-corner-shape); background: var(--dees-color-bg-primary); box-shadow: var(--dees-shadow-xs); }
184564
184576
  article:hover { border-color: var(--dees-color-border-strong); }
184565
- article[aria-busy=true] { opacity: .65; }
184577
+ article[aria-busy=true] > :not(.meta), article[aria-busy=true] .meta > :not(.saving) { opacity: .65; }
184578
+ article[data-movable=true] { cursor: grab; }
184566
184579
  .meta { display: flex; align-items: center; gap: 8px; min-height: 24px; font-size: var(--dees-font-caption1-size); color: var(--dees-color-text-secondary); }
184567
184580
  .key { flex-shrink: 0; font-weight: 500; font-variant-numeric: tabular-nums; }
184568
184581
  .link.epic { min-width: 0; color: var(--dees-color-text-secondary); font-size: var(--dees-font-caption1-size); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
184569
184582
  .link.epic:hover { color: var(--dees-color-link); text-decoration: underline; }
184570
184583
  .move { flex-shrink: 0; margin-left: auto; }
184584
+ .saving { margin-left: auto; font-size: var(--dees-font-caption1-size); white-space: nowrap; }
184571
184585
  .move::part(button) { width: 24px; height: 24px; min-height: 24px; }
184572
184586
  .title { display: block; width: 100%; border: 0; background: transparent; padding: 4px 0 0; color: inherit; text-align: left; cursor: pointer; font: inherit; font-weight: 600; line-height: 22px; overflow-wrap: anywhere; }
184573
184587
  .title:hover { color: var(--dees-color-link); }
@@ -184590,11 +184604,532 @@ __publicField(_DeesKanbanCard, "styles", [...kanbanStyles, i`
184590
184604
  __runInitializers(_init109, 1, _DeesKanbanCard);
184591
184605
  var DeesKanbanCard = _DeesKanbanCard;
184592
184606
 
184607
+ // ts_web/elements/00group-kanban/kanban.dragcontroller.ts
184608
+ init_overlay();
184609
+ init_zindex();
184610
+ var sameMove = /* @__PURE__ */ __name((a4, b4) => a4.ticketId === b4.ticketId && a4.columnId === b4.columnId && a4.beforeTicketId === b4.beforeTicketId, "sameMove");
184611
+ var KanbanDragController = class {
184612
+ constructor(board, commit, canMove) {
184613
+ this.board = board;
184614
+ this.commit = commit;
184615
+ this.canMove = canMove;
184616
+ }
184617
+ board;
184618
+ commit;
184619
+ canMove;
184620
+ static {
184621
+ __name(this, "KanbanDragController");
184622
+ }
184623
+ gesture;
184624
+ listeners;
184625
+ frame = 0;
184626
+ previousFrame = 0;
184627
+ rendering = false;
184628
+ scrollParents = [];
184629
+ scrollSnap = /* @__PURE__ */ new Map();
184630
+ animations = /* @__PURE__ */ new Map();
184631
+ timers = /* @__PURE__ */ new Set();
184632
+ suppressClick;
184633
+ clickTimer;
184634
+ resizeObserver;
184635
+ reducedMotion = matchMedia("(prefers-reduced-motion: reduce)");
184636
+ get busy() {
184637
+ return Boolean(this.gesture && this.gesture.phase !== "armed");
184638
+ }
184639
+ easing(name) {
184640
+ return getComputedStyle(this.board).getPropertyValue(`--dees-ease-${name}`).trim();
184641
+ }
184642
+ get columns() {
184643
+ return [...this.board.shadowRoot?.querySelectorAll("dees-kanban-column") ?? []];
184644
+ }
184645
+ connect() {
184646
+ this.board.addEventListener("pointerdown", this.down);
184647
+ }
184648
+ /** Host updates can remove/filter the source or revoke its move permission during a gesture. */
184649
+ sync() {
184650
+ const gesture = this.gesture;
184651
+ if (!gesture || gesture.phase === "armed") return;
184652
+ const visible = this.columns.some((column) => column.tickets.some((ticket2) => ticket2.id === gesture.motion.ticket.id));
184653
+ const ticket = this.board.tickets.find((item) => item.id === gesture.motion.ticket.id);
184654
+ if (!visible || !this.columns.some((column) => column.column?.id === gesture.motion.move.columnId)) {
184655
+ this.fadeAndClear(gesture);
184656
+ } else if (gesture.phase === "dragging" && (!this.board.provider.moveTicket || ticket?.permissions?.move === false)) {
184657
+ void this.cancel();
184658
+ }
184659
+ }
184660
+ down = /* @__PURE__ */ __name((event) => {
184661
+ if (this.gesture || !this.canMove() || event.button !== 0 || !event.isPrimary || event.pointerType === "touch") return;
184662
+ const path2 = event.composedPath();
184663
+ if (!this.columns.some((column) => path2.includes(column))) return;
184664
+ const source = path2.find((node2) => node2 instanceof DeesKanbanCard);
184665
+ if (!source?.ticket || !source.movable || source.moveDisabled || source.pending) return;
184666
+ if (path2.some((node2) => node2 instanceof Element && node2 !== source && node2.matches("a, input, textarea, select, summary, dees-button, button:not(.title), [contenteditable=true]"))) return;
184667
+ const rect = source.getBoundingClientRect();
184668
+ this.gesture = {
184669
+ pointerId: event.pointerId,
184670
+ source,
184671
+ startX: event.clientX,
184672
+ startY: event.clientY,
184673
+ x: event.clientX,
184674
+ y: event.clientY,
184675
+ offsetX: event.clientX - rect.left,
184676
+ offsetY: event.clientY - rect.top,
184677
+ width: rect.width,
184678
+ expanded: Boolean(source.shadowRoot?.querySelector("details")?.open),
184679
+ restoreFocus: false,
184680
+ phase: "armed",
184681
+ flightRevision: 0,
184682
+ motion: { ticket: source.ticket, move: this.authoritativeMove(source.ticket.id), height: rect.height, placeholder: true, dimmed: false, saving: false }
184683
+ };
184684
+ const signal = (this.listeners = new AbortController()).signal;
184685
+ window.addEventListener("pointermove", this.move, { signal, passive: false });
184686
+ window.addEventListener("pointerup", this.up, { signal });
184687
+ window.addEventListener("pointercancel", this.pointerCancel, { signal });
184688
+ this.board.addEventListener("lostpointercapture", this.pointerCancel, { signal });
184689
+ window.addEventListener("keydown", this.key, { signal, capture: true });
184690
+ window.addEventListener("blur", this.blur, { signal });
184691
+ window.addEventListener("resize", this.blur, { signal });
184692
+ }, "down");
184693
+ move = /* @__PURE__ */ __name((event) => {
184694
+ const gesture = this.gesture;
184695
+ if (!gesture || event.pointerId !== gesture.pointerId || !["armed", "dragging"].includes(gesture.phase)) return;
184696
+ gesture.x = event.clientX;
184697
+ gesture.y = event.clientY;
184698
+ if (gesture.phase === "armed") {
184699
+ if (Math.hypot(gesture.x - gesture.startX, gesture.y - gesture.startY) < 4) return;
184700
+ void this.lift(gesture);
184701
+ }
184702
+ event.preventDefault();
184703
+ window.getSelection()?.removeAllRanges();
184704
+ }, "move");
184705
+ async lift(gesture) {
184706
+ gesture.phase = "dragging";
184707
+ gesture.restoreFocus = Boolean(gesture.source.shadowRoot?.activeElement);
184708
+ this.board.setPointerCapture(gesture.pointerId);
184709
+ const overlay = gesture.overlay = new DeesKanbanCard();
184710
+ overlay.dataset.kanbanPreview = "";
184711
+ overlay.ticket = gesture.source.ticket;
184712
+ overlay.epic = gesture.source.epic;
184713
+ overlay.subtasks = gesture.source.subtasks;
184714
+ overlay.columns = gesture.source.columns;
184715
+ overlay.movable = gesture.source.movable;
184716
+ overlay.pointerManaged = true;
184717
+ overlay.inert = true;
184718
+ overlay.setAttribute("aria-hidden", "true");
184719
+ const styles3 = getComputedStyle(gesture.source);
184720
+ for (const name of styles3) if (name.startsWith("--dees-")) overlay.style.setProperty(name, styles3.getPropertyValue(name));
184721
+ const zIndex = zIndexRegistry.getNextZIndex();
184722
+ zIndexRegistry.register(overlay, zIndex);
184723
+ Object.assign(overlay.style, { position: "fixed", margin: "0", pointerEvents: "none", width: `${gesture.width}px`, zIndex: String(zIndex), transformOrigin: "center" });
184724
+ this.positionPreview(gesture);
184725
+ getOverlayContainer(this.board).append(overlay);
184726
+ this.collectScrollParents();
184727
+ const widths = new Map(this.columns.map((column) => [column, column.getBoundingClientRect().width]));
184728
+ this.resizeObserver = new ResizeObserver((entries) => {
184729
+ if (entries.some((entry) => Math.abs(entry.borderBoxSize[0].inlineSize - widths.get(entry.target)) > 0.5)) void this.cancel();
184730
+ });
184731
+ for (const column of this.columns) this.resizeObserver.observe(column);
184732
+ await overlay.updateComplete;
184733
+ if (this.gesture !== gesture || gesture.phase !== "dragging") return;
184734
+ const details = overlay.shadowRoot?.querySelector("details");
184735
+ if (details) details.open = gesture.expanded;
184736
+ const article = overlay.shadowRoot.querySelector("article");
184737
+ const resting = { boxShadow: getComputedStyle(article).boxShadow, borderColor: getComputedStyle(article).borderColor };
184738
+ article.style.borderColor = "var(--dees-color-border-strong)";
184739
+ article.style.boxShadow = "var(--dees-shadow-lg)";
184740
+ if (!this.reducedMotion.matches) {
184741
+ overlay.style.transform = "scale(1.02)";
184742
+ overlay.animate([{ transform: "scale(1)" }, { transform: "scale(1.02)" }], { duration: 120, easing: this.easing("out") });
184743
+ gesture.elevation = article.animate([resting, { boxShadow: getComputedStyle(article).boxShadow, borderColor: getComputedStyle(article).borderColor }], { duration: 120, easing: this.easing("out") });
184744
+ }
184745
+ await this.renderMotion();
184746
+ if (this.gesture === gesture && gesture.phase === "dragging") this.frame = requestAnimationFrame(this.tick);
184747
+ }
184748
+ positionPreview(gesture) {
184749
+ if (!gesture.overlay) return;
184750
+ gesture.overlay.style.left = `${gesture.x - gesture.offsetX}px`;
184751
+ gesture.overlay.style.top = `${gesture.y - gesture.offsetY}px`;
184752
+ }
184753
+ tick = /* @__PURE__ */ __name((time) => {
184754
+ const gesture = this.gesture;
184755
+ if (!gesture || gesture.phase !== "dragging") return;
184756
+ this.positionPreview(gesture);
184757
+ this.autoScroll(gesture, Math.min(2, (time - (this.previousFrame || time - 16.7)) / 16.7));
184758
+ this.previousFrame = time;
184759
+ if (!this.rendering) {
184760
+ const target = this.targetAt(gesture) ?? this.authoritativeMove(gesture.motion.ticket.id);
184761
+ if (target && !sameMove(target, gesture.motion.move)) {
184762
+ gesture.motion = { ...gesture.motion, move: target };
184763
+ void this.renderMotion();
184764
+ }
184765
+ }
184766
+ this.frame = requestAnimationFrame(this.tick);
184767
+ }, "tick");
184768
+ targetAt(gesture) {
184769
+ const clip = this.visibleRect();
184770
+ if (gesture.x < clip.left - 48 || gesture.x > clip.right + 48 || gesture.y < clip.top - 48 || gesture.y > clip.bottom + 48) return;
184771
+ const centerX = gesture.x - gesture.offsetX + gesture.width / 2;
184772
+ const centerY = gesture.y - gesture.offsetY + gesture.motion.height / 2;
184773
+ const lanes = this.columns.filter((column2) => {
184774
+ const rect = column2.getBoundingClientRect();
184775
+ return rect.right > clip.left && rect.left < clip.right;
184776
+ });
184777
+ let column = lanes.sort((a4, b4) => {
184778
+ const ar = a4.getBoundingClientRect(), br = b4.getBoundingClientRect();
184779
+ return Math.abs(centerX - (ar.left + ar.width / 2)) - Math.abs(centerX - (br.left + br.width / 2));
184780
+ })[0];
184781
+ if (!column?.column) return;
184782
+ const currentLane = lanes.find((item) => item.column?.id === gesture.motion.move.columnId);
184783
+ if (currentLane && currentLane !== column) {
184784
+ const currentRect = currentLane.getBoundingClientRect(), candidateRect = column.getBoundingClientRect();
184785
+ const currentCenter = currentRect.left + currentRect.width / 2, candidateCenter = candidateRect.left + candidateRect.width / 2;
184786
+ if (Math.abs(centerX - currentCenter) < Math.abs(candidateCenter - currentCenter) / 2 + 12) column = currentLane;
184787
+ }
184788
+ const columnId = column.column?.id;
184789
+ if (!columnId) return;
184790
+ const tickets = sortKanbanTickets(column.tickets).filter((ticket) => ticket.id !== gesture.motion.ticket.id);
184791
+ let top = column.shadowRoot.querySelector(".stack").getBoundingClientRect().top;
184792
+ const currentIndex = gesture.motion.move.columnId === columnId ? tickets.findIndex((ticket) => ticket.id === gesture.motion.move.beforeTicketId) : -1;
184793
+ const current = currentIndex < 0 ? tickets.length : currentIndex;
184794
+ let index3 = tickets.length;
184795
+ for (let i11 = 0; i11 < tickets.length; i11++) {
184796
+ const node2 = this.targets(column).find((target) => target.dataset.ticketId === tickets[i11].id);
184797
+ const midpoint = top + node2.offsetHeight / 2;
184798
+ const hysteresis = gesture.motion.move.columnId === columnId ? i11 < current ? -6 : 6 : 0;
184799
+ if (centerY < midpoint + hysteresis) {
184800
+ index3 = i11;
184801
+ break;
184802
+ }
184803
+ top += node2.offsetHeight + 8;
184804
+ }
184805
+ return { ticketId: gesture.motion.ticket.id, columnId, beforeTicketId: tickets[index3]?.id };
184806
+ }
184807
+ up = /* @__PURE__ */ __name((event) => {
184808
+ const gesture = this.gesture;
184809
+ if (!gesture || gesture.pointerId !== event.pointerId || !["armed", "dragging"].includes(gesture.phase)) return;
184810
+ if (gesture.phase === "armed") {
184811
+ this.clear();
184812
+ return;
184813
+ }
184814
+ gesture.x = event.clientX;
184815
+ gesture.y = event.clientY;
184816
+ this.blockClick();
184817
+ const target = this.targetAt(gesture);
184818
+ if (!target) {
184819
+ void this.cancel();
184820
+ return;
184821
+ }
184822
+ gesture.phase = "landing";
184823
+ this.endPointer();
184824
+ gesture.motion = { ...gesture.motion, move: target };
184825
+ void this.land(gesture);
184826
+ if (sameMove(target, this.authoritativeMove(target.ticketId))) {
184827
+ gesture.settled = true;
184828
+ } else {
184829
+ void this.commit(target).then((saved) => this.settle(gesture, saved));
184830
+ }
184831
+ }, "up");
184832
+ pointerCancel = /* @__PURE__ */ __name((event) => {
184833
+ if (event.pointerId === this.gesture?.pointerId && ["armed", "dragging"].includes(this.gesture.phase)) void this.cancel();
184834
+ }, "pointerCancel");
184835
+ key = /* @__PURE__ */ __name((event) => {
184836
+ if (event.key !== "Escape") return;
184837
+ event.preventDefault();
184838
+ event.stopImmediatePropagation();
184839
+ void this.cancel();
184840
+ }, "key");
184841
+ blur = /* @__PURE__ */ __name(() => {
184842
+ void this.cancel();
184843
+ }, "blur");
184844
+ async cancel() {
184845
+ const gesture = this.gesture;
184846
+ if (!gesture || !["armed", "dragging"].includes(gesture.phase)) return;
184847
+ if (gesture.phase === "armed") {
184848
+ this.clear();
184849
+ return;
184850
+ }
184851
+ this.blockClick();
184852
+ gesture.phase = "landing";
184853
+ gesture.settled = false;
184854
+ this.endPointer();
184855
+ const origin = this.authoritativeMove(gesture.motion.ticket.id);
184856
+ if (!origin) {
184857
+ this.fadeAndClear(gesture);
184858
+ return;
184859
+ }
184860
+ gesture.motion = { ...gesture.motion, move: origin };
184861
+ const column = this.columns.find((item) => item.column?.id === origin.columnId);
184862
+ if (gesture.overlay && column) {
184863
+ gesture.overlay.style.width = `${column.getBoundingClientRect().width}px`;
184864
+ gesture.motion.height = gesture.overlay.offsetHeight;
184865
+ }
184866
+ await this.land(gesture);
184867
+ }
184868
+ authoritativeMove(ticketId) {
184869
+ const ticket = this.board.tickets.find((item) => item.id === ticketId);
184870
+ if (!ticket) return;
184871
+ const tickets = sortKanbanTickets(this.columns.find((column) => column.column?.id === ticket.columnId)?.tickets ?? []);
184872
+ return { ticketId, columnId: ticket.columnId, beforeTicketId: tickets[tickets.findIndex((item) => item.id === ticketId) + 1]?.id };
184873
+ }
184874
+ async land(gesture) {
184875
+ const revision = ++gesture.flightRevision;
184876
+ await this.renderMotion();
184877
+ if (this.gesture !== gesture || gesture.flightRevision !== revision) return;
184878
+ const target = this.allTargets().find((node2) => node2.dataset.ticketId === gesture.motion.ticket.id);
184879
+ const overlay = gesture.overlay;
184880
+ if (!target || !overlay) {
184881
+ this.clear();
184882
+ return;
184883
+ }
184884
+ const from3 = overlay.getBoundingClientRect(), to = target.getBoundingClientRect();
184885
+ gesture.flight?.cancel();
184886
+ for (const animation of overlay.getAnimations()) animation.cancel();
184887
+ Object.assign(overlay.style, { left: `${to.left}px`, top: `${to.top}px`, width: `${to.width}px`, transform: "none" });
184888
+ const article = overlay.shadowRoot?.querySelector("article");
184889
+ const raised = article ? { boxShadow: getComputedStyle(article).boxShadow, borderColor: getComputedStyle(article).borderColor } : void 0;
184890
+ gesture.elevation?.cancel();
184891
+ if (article) {
184892
+ article.style.boxShadow = "";
184893
+ article.style.borderColor = "";
184894
+ }
184895
+ if (!this.reducedMotion.matches) {
184896
+ const duration = Math.min(280, Math.max(160, 120 + 0.25 * Math.hypot(to.left - from3.left, to.top - from3.top)));
184897
+ if (article && raised) gesture.elevation = article.animate([raised, { boxShadow: getComputedStyle(article).boxShadow, borderColor: getComputedStyle(article).borderColor }], { duration, easing: this.easing("spring") });
184898
+ const flight = gesture.flight = overlay.animate([
184899
+ { transform: `translate(${from3.left - to.left}px, ${from3.top - to.top}px) scale(${from3.width / to.width}, ${from3.height / to.height})`, transformOrigin: "top left" },
184900
+ { transform: "none", transformOrigin: "top left" }
184901
+ ], { duration, easing: this.easing("spring") });
184902
+ const completed = await flight.finished.then(() => true, () => false);
184903
+ if (!completed) return;
184904
+ }
184905
+ if (this.gesture !== gesture || gesture.flightRevision !== revision) return;
184906
+ if (gesture.settled !== void 0) {
184907
+ await this.clearMotion(gesture);
184908
+ return;
184909
+ }
184910
+ gesture.phase = "pending";
184911
+ gesture.motion = { ...gesture.motion, placeholder: false };
184912
+ await this.renderMotion();
184913
+ if (this.gesture !== gesture) return;
184914
+ this.removeOverlay(gesture);
184915
+ this.delay(() => {
184916
+ if (this.gesture === gesture && gesture.phase === "pending") {
184917
+ gesture.motion = { ...gesture.motion, dimmed: true };
184918
+ void this.renderMotion();
184919
+ }
184920
+ }, 180);
184921
+ this.delay(() => {
184922
+ if (this.gesture === gesture && gesture.phase === "pending") {
184923
+ gesture.motion = { ...gesture.motion, saving: true };
184924
+ void this.renderMotion();
184925
+ }
184926
+ }, 600);
184927
+ }
184928
+ async settle(gesture, saved) {
184929
+ if (this.gesture !== gesture) return;
184930
+ gesture.settled = saved;
184931
+ await this.board.updateComplete;
184932
+ if (this.gesture !== gesture) return;
184933
+ const move = this.authoritativeMove(gesture.motion.ticket.id);
184934
+ if (!move) {
184935
+ this.fadeAndClear(gesture);
184936
+ return;
184937
+ }
184938
+ const unchanged = sameMove(move, gesture.motion.move);
184939
+ gesture.motion = { ...gesture.motion, move, ticket: this.board.tickets.find((ticket) => ticket.id === move.ticketId), dimmed: false, saving: false };
184940
+ if (gesture.phase === "landing") {
184941
+ if (!unchanged) await this.land(gesture);
184942
+ } else {
184943
+ gesture.phase = "settling";
184944
+ await this.clearMotion(gesture, saved ? 200 : 240);
184945
+ }
184946
+ }
184947
+ targets(column) {
184948
+ return [...column.shadowRoot?.querySelectorAll(".target") ?? []];
184949
+ }
184950
+ allTargets() {
184951
+ return this.columns.flatMap((column) => this.targets(column));
184952
+ }
184953
+ capture() {
184954
+ return new Map(this.allTargets().map((node2) => [node2.dataset.ticketId, node2.getBoundingClientRect()]));
184955
+ }
184956
+ async animateFrom(before, duration = 200) {
184957
+ await Promise.all(this.columns.map((column) => column.updateComplete));
184958
+ for (const animation of this.animations.values()) animation.cancel();
184959
+ this.animations.clear();
184960
+ if (this.reducedMotion.matches || !this.board.isConnected) return;
184961
+ const easing = this.easing("spring");
184962
+ for (const node2 of this.allTargets()) {
184963
+ if (node2.querySelector(".placeholder")) continue;
184964
+ const old = before.get(node2.dataset.ticketId), rect = node2.getBoundingClientRect();
184965
+ if (!old || Math.abs(old.x - rect.x) + Math.abs(old.y - rect.y) < 0.5) continue;
184966
+ const animation = node2.animate([{ transform: `translate(${old.x - rect.x}px, ${old.y - rect.y}px)` }, { transform: "none" }], { duration, easing });
184967
+ this.animations.set(node2, animation);
184968
+ void animation.finished.then(() => {
184969
+ if (this.animations.get(node2) === animation) this.animations.delete(node2);
184970
+ }, () => {
184971
+ });
184972
+ }
184973
+ }
184974
+ async renderMotion() {
184975
+ this.rendering = true;
184976
+ const before = this.capture();
184977
+ for (const column of this.columns) column.motion = this.gesture?.motion;
184978
+ await Promise.all(this.columns.map((column) => column.updateComplete));
184979
+ const gesture = this.gesture;
184980
+ if (gesture && !gesture.motion.placeholder) await this.restoreExpansion(gesture);
184981
+ await this.animateFrom(before);
184982
+ this.rendering = false;
184983
+ }
184984
+ async restoreExpansion(gesture) {
184985
+ const card = this.allTargets().find((node2) => node2.dataset.ticketId === gesture.motion.ticket.id)?.querySelector("dees-kanban-card");
184986
+ if (!card) return;
184987
+ await card.updateComplete;
184988
+ const details = card.shadowRoot?.querySelector("details");
184989
+ if (details) details.open = gesture.expanded;
184990
+ }
184991
+ async clearMotion(gesture, duration = 200) {
184992
+ const before = this.capture();
184993
+ for (const column of this.columns) column.motion = void 0;
184994
+ await Promise.all(this.columns.map((column) => column.updateComplete));
184995
+ if (this.gesture !== gesture) return;
184996
+ await this.restoreExpansion(gesture);
184997
+ this.removeOverlay(gesture);
184998
+ await this.animateFrom(before, duration);
184999
+ await Promise.all([...this.animations.values()].map((animation) => animation.finished.catch(() => {
185000
+ })));
185001
+ if (this.gesture === gesture) this.clear();
185002
+ }
185003
+ collectScrollParents() {
185004
+ this.scrollParents = [];
185005
+ let node2 = this.board.shadowRoot.querySelector(".columns");
185006
+ while (node2) {
185007
+ if (node2 instanceof HTMLElement) {
185008
+ const style2 = getComputedStyle(node2);
185009
+ if (/(auto|scroll)/.test(style2.overflowX + style2.overflowY) || node2 === document.scrollingElement) {
185010
+ this.scrollParents.push(node2);
185011
+ this.scrollSnap.set(node2, node2.style.scrollSnapType);
185012
+ node2.style.scrollSnapType = "none";
185013
+ }
185014
+ }
185015
+ node2 = node2 instanceof Element && node2.assignedSlot || node2.parentNode || (node2 instanceof ShadowRoot ? node2.host : null);
185016
+ }
185017
+ }
185018
+ visibleRect() {
185019
+ const board = this.board.shadowRoot.querySelector(".columns").getBoundingClientRect();
185020
+ const clip = { left: Math.max(0, board.left), right: Math.min(innerWidth, board.right), top: Math.max(0, board.top), bottom: Math.min(innerHeight, board.bottom) };
185021
+ for (const parent of this.scrollParents) {
185022
+ if (parent === document.scrollingElement) continue;
185023
+ const rect = parent.getBoundingClientRect();
185024
+ clip.left = Math.max(clip.left, rect.left);
185025
+ clip.right = Math.min(clip.right, rect.right);
185026
+ clip.top = Math.max(clip.top, rect.top);
185027
+ clip.bottom = Math.min(clip.bottom, rect.bottom);
185028
+ }
185029
+ return clip;
185030
+ }
185031
+ autoScroll(gesture, elapsed) {
185032
+ const velocity = /* @__PURE__ */ __name((point4, start, end, edge) => point4 < start + edge ? -Math.min(1, Math.max(0, (start + edge - point4) / edge)) * 14 * elapsed : point4 > end - edge ? Math.min(1, Math.max(0, (point4 - end + edge) / edge)) * 14 * elapsed : 0, "velocity");
185033
+ let movedX = false, movedY = false;
185034
+ for (const parent of this.scrollParents) {
185035
+ const rect = parent === document.scrollingElement ? { left: 0, top: 0, right: innerWidth, bottom: innerHeight } : parent.getBoundingClientRect();
185036
+ const left = Math.max(0, rect.left), top = Math.max(0, rect.top), right = Math.min(innerWidth, rect.right), bottom = Math.min(innerHeight, rect.bottom);
185037
+ if (gesture.x < left - 48 || gesture.x > right + 48 || gesture.y < top - 56 || gesture.y > bottom + 56) continue;
185038
+ const x3 = parent.scrollLeft, y3 = parent.scrollTop;
185039
+ if (!movedX) parent.scrollLeft += velocity(gesture.x, left, right, 48);
185040
+ if (!movedY) parent.scrollTop += velocity(gesture.y, top, bottom, 56);
185041
+ movedX ||= parent.scrollLeft !== x3;
185042
+ movedY ||= parent.scrollTop !== y3;
185043
+ }
185044
+ }
185045
+ endPointer() {
185046
+ this.listeners?.abort();
185047
+ this.listeners = void 0;
185048
+ cancelAnimationFrame(this.frame);
185049
+ this.frame = 0;
185050
+ this.previousFrame = 0;
185051
+ if (this.gesture && this.board.hasPointerCapture(this.gesture.pointerId)) this.board.releasePointerCapture(this.gesture.pointerId);
185052
+ this.resizeObserver?.disconnect();
185053
+ this.resizeObserver = void 0;
185054
+ }
185055
+ blockClick() {
185056
+ this.suppressClick?.abort();
185057
+ const controller = this.suppressClick = new AbortController();
185058
+ window.addEventListener("click", (event) => {
185059
+ event.preventDefault();
185060
+ event.stopImmediatePropagation();
185061
+ controller.abort();
185062
+ }, { capture: true, once: true, signal: controller.signal });
185063
+ clearTimeout(this.clickTimer);
185064
+ this.clickTimer = setTimeout(() => controller.abort(), 0);
185065
+ }
185066
+ delay(callback, duration) {
185067
+ const timer2 = setTimeout(() => {
185068
+ this.timers.delete(timer2);
185069
+ callback();
185070
+ }, duration);
185071
+ this.timers.add(timer2);
185072
+ }
185073
+ removeOverlay(gesture) {
185074
+ if (!gesture.overlay) return;
185075
+ gesture.elevation?.cancel();
185076
+ zIndexRegistry.unregister(gesture.overlay);
185077
+ gesture.overlay.remove();
185078
+ gesture.overlay = void 0;
185079
+ }
185080
+ fadeAndClear(gesture) {
185081
+ if (gesture.phase === "settling") return;
185082
+ gesture.phase = "settling";
185083
+ this.endPointer();
185084
+ const element4 = gesture.overlay ?? this.allTargets().find((node2) => node2.dataset.ticketId === gesture.motion.ticket.id);
185085
+ if (!element4 || this.reducedMotion.matches) {
185086
+ this.clear();
185087
+ return;
185088
+ }
185089
+ const transform2 = getComputedStyle(element4).transform;
185090
+ gesture.flight?.cancel();
185091
+ element4.style.transform = transform2;
185092
+ const fade = gesture.flight = element4.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 120, fill: "forwards" });
185093
+ void fade.finished.then(() => {
185094
+ if (this.gesture === gesture) void this.clearMotion(gesture);
185095
+ }, () => {
185096
+ });
185097
+ }
185098
+ clear() {
185099
+ const gesture = this.gesture;
185100
+ this.endPointer();
185101
+ this.gesture = void 0;
185102
+ for (const [parent, value2] of this.scrollSnap) parent.style.scrollSnapType = value2;
185103
+ this.scrollSnap.clear();
185104
+ this.scrollParents = [];
185105
+ for (const timer2 of this.timers) clearTimeout(timer2);
185106
+ this.timers.clear();
185107
+ for (const animation of this.animations.values()) animation.cancel();
185108
+ this.animations.clear();
185109
+ for (const column of this.columns) column.motion = void 0;
185110
+ if (!gesture) return;
185111
+ gesture.flight?.cancel();
185112
+ this.removeOverlay(gesture);
185113
+ let focused = document.activeElement;
185114
+ while (focused?.shadowRoot?.activeElement) focused = focused.shadowRoot.activeElement;
185115
+ if (gesture.restoreFocus && this.board.isConnected && (focused === document.body || focused === this.board)) {
185116
+ const card = this.allTargets().find((node2) => node2.dataset.ticketId === gesture.motion.ticket.id)?.querySelector("dees-kanban-card");
185117
+ card?.shadowRoot?.querySelector(".title")?.focus({ preventScroll: true });
185118
+ }
185119
+ }
185120
+ disconnect() {
185121
+ this.board.removeEventListener("pointerdown", this.down);
185122
+ this.suppressClick?.abort();
185123
+ clearTimeout(this.clickTimer);
185124
+ this.clear();
185125
+ }
185126
+ };
185127
+
184593
185128
  // ts_web/elements/00group-kanban/dees-kanban-column/dees-kanban-column.ts
184594
185129
  init_dist_ts26();
184595
- var _draggingOver_dec, _dropBefore_dec, _draggingTicketId_dec, _pendingTicketId_dec, _canCreate_dec, _movable_dec2, _columns_dec5, _allTickets_dec, _tickets_dec2, _column_dec, _a108, _DeesKanbanColumn_decorators, _init110, _column, _tickets2, _allTickets, _columns5, _movable2, _canCreate, _pendingTicketId, _draggingTicketId, _dropBefore, _draggingOver;
185130
+ var _motion_dec, _nativeOver_dec, _nativeDropBefore_dec, _pointerManaged_dec2, _draggingTicketId_dec, _pendingTicketId_dec, _canCreate_dec, _movesDisabled_dec, _movable_dec2, _columns_dec5, _allTickets_dec, _tickets_dec2, _column_dec, _a108, _DeesKanbanColumn_decorators, _init110, _column, _tickets2, _allTickets, _columns5, _movable2, _movesDisabled, _canCreate, _pendingTicketId, _draggingTicketId, _pointerManaged2, _nativeDropBefore, _nativeOver, _motion;
184596
185131
  _DeesKanbanColumn_decorators = [customElement("dees-kanban-column")];
184597
- var _DeesKanbanColumn = class _DeesKanbanColumn extends (_a108 = DeesElement, _column_dec = [n5({ attribute: false })], _tickets_dec2 = [n5({ attribute: false })], _allTickets_dec = [n5({ attribute: false })], _columns_dec5 = [n5({ attribute: false })], _movable_dec2 = [n5({ type: Boolean })], _canCreate_dec = [n5({ type: Boolean })], _pendingTicketId_dec = [n5({ type: String })], _draggingTicketId_dec = [n5({ type: String })], _dropBefore_dec = [r5()], _draggingOver_dec = [r5()], _a108) {
185132
+ var _DeesKanbanColumn = class _DeesKanbanColumn extends (_a108 = DeesElement, _column_dec = [n5({ attribute: false })], _tickets_dec2 = [n5({ attribute: false })], _allTickets_dec = [n5({ attribute: false })], _columns_dec5 = [n5({ attribute: false })], _movable_dec2 = [n5({ type: Boolean })], _movesDisabled_dec = [n5({ type: Boolean })], _canCreate_dec = [n5({ type: Boolean })], _pendingTicketId_dec = [n5({ type: String })], _draggingTicketId_dec = [n5({ type: String })], _pointerManaged_dec2 = [n5({ attribute: false })], _nativeDropBefore_dec = [r5()], _nativeOver_dec = [r5()], _motion_dec = [n5({ attribute: false })], _a108) {
184598
185133
  constructor() {
184599
185134
  super(...arguments);
184600
185135
  __privateAdd(this, _column, __runInitializers(_init110, 8, this)), __runInitializers(_init110, 11, this);
@@ -184602,53 +185137,66 @@ var _DeesKanbanColumn = class _DeesKanbanColumn extends (_a108 = DeesElement, _c
184602
185137
  __privateAdd(this, _allTickets, __runInitializers(_init110, 16, this, [])), __runInitializers(_init110, 19, this);
184603
185138
  __privateAdd(this, _columns5, __runInitializers(_init110, 20, this, [])), __runInitializers(_init110, 23, this);
184604
185139
  __privateAdd(this, _movable2, __runInitializers(_init110, 24, this, false)), __runInitializers(_init110, 27, this);
184605
- __privateAdd(this, _canCreate, __runInitializers(_init110, 28, this, false)), __runInitializers(_init110, 31, this);
184606
- __privateAdd(this, _pendingTicketId, __runInitializers(_init110, 32, this, "")), __runInitializers(_init110, 35, this);
184607
- __privateAdd(this, _draggingTicketId, __runInitializers(_init110, 36, this, "")), __runInitializers(_init110, 39, this);
184608
- __privateAdd(this, _dropBefore, __runInitializers(_init110, 40, this)), __runInitializers(_init110, 43, this);
184609
- __privateAdd(this, _draggingOver, __runInitializers(_init110, 44, this, false)), __runInitializers(_init110, 47, this);
185140
+ __privateAdd(this, _movesDisabled, __runInitializers(_init110, 28, this, false)), __runInitializers(_init110, 31, this);
185141
+ __privateAdd(this, _canCreate, __runInitializers(_init110, 32, this, false)), __runInitializers(_init110, 35, this);
185142
+ __privateAdd(this, _pendingTicketId, __runInitializers(_init110, 36, this, "")), __runInitializers(_init110, 39, this);
185143
+ __privateAdd(this, _draggingTicketId, __runInitializers(_init110, 40, this, "")), __runInitializers(_init110, 43, this);
185144
+ __privateAdd(this, _pointerManaged2, __runInitializers(_init110, 44, this, false)), __runInitializers(_init110, 47, this);
185145
+ __privateAdd(this, _nativeDropBefore, __runInitializers(_init110, 48, this)), __runInitializers(_init110, 51, this);
185146
+ __privateAdd(this, _nativeOver, __runInitializers(_init110, 52, this, false)), __runInitializers(_init110, 55, this);
185147
+ __privateAdd(this, _motion, __runInitializers(_init110, 56, this)), __runInitializers(_init110, 59, this);
184610
185148
  }
184611
185149
  updated() {
184612
- if (!this.draggingTicketId) this.draggingOver = false;
185150
+ if (!this.draggingTicketId) this.nativeOver = false;
184613
185151
  }
184614
185152
  render() {
184615
185153
  if (!this.column) return b2``;
184616
- return b2`<section class=${this.draggingOver ? "over" : ""} aria-label=${this.column.title}
185154
+ const motion = this.motion;
185155
+ const tickets = sortKanbanTickets(this.tickets).filter((ticket) => ticket.id !== motion?.move.ticketId);
185156
+ const active = motion?.move.columnId === this.column.id;
185157
+ if (motion && active) {
185158
+ const index3 = tickets.findIndex((ticket) => ticket.id === motion.move.beforeTicketId);
185159
+ tickets.splice(index3 < 0 ? tickets.length : index3, 0, motion.ticket);
185160
+ }
185161
+ return b2`<section class=${active && motion?.placeholder || this.nativeOver ? "over" : ""} aria-label=${this.column.title}
184617
185162
  @dragover=${(event) => {
184618
- if (this.draggingTicketId && this.movable) {
185163
+ if (!this.pointerManaged && this.draggingTicketId && this.movable && !this.movesDisabled) {
184619
185164
  event.preventDefault();
184620
- this.draggingOver = true;
185165
+ this.nativeOver = true;
184621
185166
  if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
184622
185167
  }
184623
185168
  }}
184624
185169
  @dragleave=${(event) => {
184625
- if (!(event.relatedTarget instanceof Node) || !event.currentTarget.contains(event.relatedTarget)) this.draggingOver = false;
185170
+ if (!(event.relatedTarget instanceof Node) || !event.currentTarget.contains(event.relatedTarget)) this.nativeOver = false;
184626
185171
  }}
184627
185172
  @drop=${(event) => {
185173
+ if (this.pointerManaged) return;
184628
185174
  event.preventDefault();
184629
- this.draggingOver = false;
184630
- if (this.movable && this.draggingTicketId && event.dataTransfer?.getData("application/x-dees-kanban-ticket") === this.draggingTicketId)
184631
- kanbanEvent(this, "kanban-ticket-move", { ticketId: this.draggingTicketId, columnId: this.column.id, beforeTicketId: this.dropBefore });
185175
+ this.nativeOver = false;
185176
+ if (this.movable && !this.movesDisabled && this.draggingTicketId && event.dataTransfer?.getData("application/x-dees-kanban-ticket") === this.draggingTicketId)
185177
+ kanbanEvent(this, "kanban-ticket-move", { ticketId: this.draggingTicketId, columnId: this.column.id, beforeTicketId: this.nativeDropBefore });
184632
185178
  }}>
184633
- <header><span class="status ${this.column.done ? "done" : ""}" aria-hidden="true"></span><h3>${this.column.title}</h3><span class="count">${this.tickets.length}</span><span class="spacer"></span>
185179
+ <header><span class="status ${this.column.done ? "done" : ""}" aria-hidden="true"></span><h3>${this.column.title}</h3><span class="count">${tickets.length}</span><span class="spacer"></span>
184634
185180
  ${this.canCreate ? b2`<dees-button type="ghost" size="icon" icon="lucide:Plus" text=${`Add task to ${this.column.title}`}
184635
185181
  @clicked=${() => kanbanEvent(this, "kanban-ticket-create", { kind: "task", columnId: this.column.id })}></dees-button>` : ""}</header>
184636
- <div class="stack">${sortKanbanTickets(this.tickets).map((ticket) => b2`
184637
- <div class="target ${this.draggingOver && this.dropBefore === ticket.id ? "before" : ""} ${this.draggingTicketId === ticket.id ? "dragging" : ""}"
185182
+ <div class="stack">${directives_exports.repeat(tickets, (ticket) => ticket.id, (ticket) => b2`
185183
+ <div class="target ${this.nativeOver && this.nativeDropBefore === ticket.id ? "native-before" : ""}" data-ticket-id=${ticket.id}
184638
185184
  @dragover=${() => {
184639
- this.dropBefore = ticket.id;
185185
+ if (!this.pointerManaged) this.nativeDropBefore = ticket.id;
184640
185186
  }}>
184641
- <dees-kanban-card .ticket=${ticket} .columns=${this.columns}
185187
+ ${motion?.move.ticketId === ticket.id && motion.placeholder ? b2`<div class="placeholder" style=${`height: ${motion.height}px`} aria-label="Drop ticket here"></div>` : b2`<dees-kanban-card .ticket=${ticket} .columns=${this.columns}
184642
185188
  .epic=${this.allTickets.find((item) => item.id === ticket.parentId && item.kind === "epic")}
184643
185189
  .subtasks=${sortKanbanTickets(this.allTickets.filter((item) => item.parentId === ticket.id && item.kind === "subtask"))}
184644
- .movable=${this.movable && ticket.permissions?.move !== false} .pending=${this.pendingTicketId === ticket.id}></dees-kanban-card>
185190
+ .movable=${this.movable && ticket.permissions?.move !== false} .pending=${motion?.move.ticketId === ticket.id ? motion.dimmed : this.pendingTicketId === ticket.id}
185191
+ .moveDisabled=${this.movesDisabled}
185192
+ .saving=${motion?.move.ticketId === ticket.id && motion.saving} .pointerManaged=${this.pointerManaged}></dees-kanban-card>`}
184645
185193
  </div>`)}
184646
- ${!this.tickets.length ? b2`<div class="empty" @dragover=${() => {
184647
- this.dropBefore = void 0;
185194
+ ${!tickets.length ? b2`<div class="empty" @dragover=${() => {
185195
+ this.nativeDropBefore = void 0;
184648
185196
  }}>No tasks</div>` : ""}
184649
185197
  </div>
184650
- <div class="end-target ${this.draggingOver && !this.dropBefore ? "before" : ""}" @dragover=${() => {
184651
- this.dropBefore = void 0;
185198
+ <div class="end-target ${this.nativeOver && !this.nativeDropBefore ? "native-before" : ""}" @dragover=${() => {
185199
+ this.nativeDropBefore = void 0;
184652
185200
  }}></div>
184653
185201
  </section>`;
184654
185202
  }
@@ -184659,26 +185207,32 @@ _tickets2 = new WeakMap();
184659
185207
  _allTickets = new WeakMap();
184660
185208
  _columns5 = new WeakMap();
184661
185209
  _movable2 = new WeakMap();
185210
+ _movesDisabled = new WeakMap();
184662
185211
  _canCreate = new WeakMap();
184663
185212
  _pendingTicketId = new WeakMap();
184664
185213
  _draggingTicketId = new WeakMap();
184665
- _dropBefore = new WeakMap();
184666
- _draggingOver = new WeakMap();
185214
+ _pointerManaged2 = new WeakMap();
185215
+ _nativeDropBefore = new WeakMap();
185216
+ _nativeOver = new WeakMap();
185217
+ _motion = new WeakMap();
184667
185218
  __decorateElement(_init110, 4, "column", _column_dec, _DeesKanbanColumn, _column);
184668
185219
  __decorateElement(_init110, 4, "tickets", _tickets_dec2, _DeesKanbanColumn, _tickets2);
184669
185220
  __decorateElement(_init110, 4, "allTickets", _allTickets_dec, _DeesKanbanColumn, _allTickets);
184670
185221
  __decorateElement(_init110, 4, "columns", _columns_dec5, _DeesKanbanColumn, _columns5);
184671
185222
  __decorateElement(_init110, 4, "movable", _movable_dec2, _DeesKanbanColumn, _movable2);
185223
+ __decorateElement(_init110, 4, "movesDisabled", _movesDisabled_dec, _DeesKanbanColumn, _movesDisabled);
184672
185224
  __decorateElement(_init110, 4, "canCreate", _canCreate_dec, _DeesKanbanColumn, _canCreate);
184673
185225
  __decorateElement(_init110, 4, "pendingTicketId", _pendingTicketId_dec, _DeesKanbanColumn, _pendingTicketId);
184674
185226
  __decorateElement(_init110, 4, "draggingTicketId", _draggingTicketId_dec, _DeesKanbanColumn, _draggingTicketId);
184675
- __decorateElement(_init110, 4, "dropBefore", _dropBefore_dec, _DeesKanbanColumn, _dropBefore);
184676
- __decorateElement(_init110, 4, "draggingOver", _draggingOver_dec, _DeesKanbanColumn, _draggingOver);
185227
+ __decorateElement(_init110, 4, "pointerManaged", _pointerManaged_dec2, _DeesKanbanColumn, _pointerManaged2);
185228
+ __decorateElement(_init110, 4, "nativeDropBefore", _nativeDropBefore_dec, _DeesKanbanColumn, _nativeDropBefore);
185229
+ __decorateElement(_init110, 4, "nativeOver", _nativeOver_dec, _DeesKanbanColumn, _nativeOver);
185230
+ __decorateElement(_init110, 4, "motion", _motion_dec, _DeesKanbanColumn, _motion);
184677
185231
  _DeesKanbanColumn = __decorateElement(_init110, 0, "DeesKanbanColumn", _DeesKanbanColumn_decorators, _DeesKanbanColumn);
184678
185232
  __name(_DeesKanbanColumn, "DeesKanbanColumn");
184679
185233
  __publicField(_DeesKanbanColumn, "styles", [...kanbanStyles, i`
184680
185234
  :host { display: flex; flex-direction: column; min-width: 272px; max-width: 360px; flex: 1 0 272px; }
184681
- section { min-height: 220px; height: 100%; border-radius: var(--dees-radius-xl); }
185235
+ section { min-height: 220px; height: 100%; border-radius: var(--dees-radius-xl); transition: background var(--dees-transition-default) var(--dees-ease-out); }
184682
185236
  header { display: flex; align-items: center; gap: 8px; min-height: 40px; margin-bottom: 10px; padding: 0 2px 8px; border-bottom: 1px solid var(--dees-color-border-subtle); }
184683
185237
  h3 { font-size: var(--dees-font-footnote-size); font-weight: 600; }
184684
185238
  header dees-button::part(button) { width: 24px; height: 24px; min-height: 24px; }
@@ -184686,10 +185240,11 @@ __publicField(_DeesKanbanColumn, "styles", [...kanbanStyles, i`
184686
185240
  .status.done { background: var(--dees-color-accent-success); border-color: var(--dees-color-accent-success); }
184687
185241
  .stack { display: grid; gap: 8px; min-height: 120px; align-content: start; }
184688
185242
  .target { position: relative; }
184689
- .target.dragging { opacity: .4; }
184690
- .target.before::before, .end-target.before::before { content: ''; position: absolute; top: -5px; left: 0; right: 0; height: 2px; background: var(--dees-color-accent-primary); border-radius: 2px; }
185243
+ .native-before::before { content: ''; position: absolute; top: -5px; left: 0; right: 0; height: 2px; background: var(--dees-color-accent-primary); border-radius: 2px; }
185244
+ .placeholder { border-radius: var(--dees-radius-xl); background: var(--dees-color-fill-tertiary); box-shadow: inset 0 0 0 1px var(--dees-color-border-default); }
184691
185245
  .end-target { position: relative; min-height: 32px; margin-top: 8px; }
184692
185246
  section.over { background: var(--dees-color-row-hover); }
185247
+ @media (prefers-reduced-motion: reduce) { section { transition: none; } }
184693
185248
  @media (pointer: coarse) { header dees-button::part(button) { width: 32px; height: 32px; min-height: 32px; } }
184694
185249
  `]);
184695
185250
  __runInitializers(_init110, 1, _DeesKanbanColumn);
@@ -184699,7 +185254,7 @@ var DeesKanbanColumn = _DeesKanbanColumn;
184699
185254
  init_dist_ts26();
184700
185255
  init_dees_modal();
184701
185256
  init_dees_contextmenu();
184702
- var _openingTicket_dec, _draggingTicketId_dec2, _pendingTicketId_dec2, _operationError_dec, _epicId_dec, _query_dec2, _error_dec4, _loading_dec8, _provider_dec3, _people_dec2, _columns_dec6, _tickets_dec3, _heading_dec8, _a109, _DeesKanban_decorators, _init111, _heading8, _tickets3, _columns6, _people2, _provider3, _loading8, _error4, _query2, _epicId, _operationError, _pendingTicketId2, _draggingTicketId2, _openingTicket;
185257
+ var _openingTicket_dec, _pendingTicketId_dec2, _operationError_dec, _epicId_dec, _query_dec2, _error_dec4, _loading_dec8, _provider_dec3, _people_dec2, _columns_dec6, _tickets_dec3, _heading_dec8, _a109, _DeesKanban_decorators, _init111, _heading8, _tickets3, _columns6, _people2, _provider3, _loading8, _error4, _query2, _epicId, _operationError, _pendingTicketId2, _openingTicket;
184703
185258
  var interactionEvents = [
184704
185259
  "kanban-ticket-open",
184705
185260
  "kanban-ticket-move",
@@ -184710,12 +185265,10 @@ var interactionEvents = [
184710
185265
  "kanban-comment-draft",
184711
185266
  "kanban-comment-added",
184712
185267
  "kanban-comments-refresh",
184713
- "kanban-detail-back",
184714
- "kanban-drag-start",
184715
- "kanban-drag-end"
185268
+ "kanban-detail-back"
184716
185269
  ];
184717
185270
  _DeesKanban_decorators = [customElement("dees-kanban")];
184718
- var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8 = [n5({ type: String })], _tickets_dec3 = [n5({ attribute: false })], _columns_dec6 = [n5({ attribute: false })], _people_dec2 = [n5({ attribute: false })], _provider_dec3 = [n5({ attribute: false })], _loading_dec8 = [n5({ type: Boolean })], _error_dec4 = [n5({ type: String })], _query_dec2 = [r5()], _epicId_dec = [r5()], _operationError_dec = [r5()], _pendingTicketId_dec2 = [r5()], _draggingTicketId_dec2 = [r5()], _openingTicket_dec = [r5()], _a109) {
185271
+ var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8 = [n5({ type: String })], _tickets_dec3 = [n5({ attribute: false })], _columns_dec6 = [n5({ attribute: false })], _people_dec2 = [n5({ attribute: false })], _provider_dec3 = [n5({ attribute: false })], _loading_dec8 = [n5({ type: Boolean })], _error_dec4 = [n5({ type: String })], _query_dec2 = [r5()], _epicId_dec = [r5()], _operationError_dec = [r5()], _pendingTicketId_dec2 = [r5()], _openingTicket_dec = [r5()], _a109) {
184719
185272
  constructor() {
184720
185273
  super(...arguments);
184721
185274
  __privateAdd(this, _heading8, __runInitializers(_init111, 8, this, "Board")), __runInitializers(_init111, 11, this);
@@ -184729,8 +185282,7 @@ var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8
184729
185282
  __privateAdd(this, _epicId, __runInitializers(_init111, 40, this, "")), __runInitializers(_init111, 43, this);
184730
185283
  __privateAdd(this, _operationError, __runInitializers(_init111, 44, this, "")), __runInitializers(_init111, 47, this);
184731
185284
  __privateAdd(this, _pendingTicketId2, __runInitializers(_init111, 48, this, "")), __runInitializers(_init111, 51, this);
184732
- __privateAdd(this, _draggingTicketId2, __runInitializers(_init111, 52, this, "")), __runInitializers(_init111, 55, this);
184733
- __privateAdd(this, _openingTicket, __runInitializers(_init111, 56, this, false)), __runInitializers(_init111, 59, this);
185285
+ __privateAdd(this, _openingTicket, __runInitializers(_init111, 52, this, false)), __runInitializers(_init111, 55, this);
184734
185286
  __publicField(this, "modal");
184735
185287
  __publicField(this, "modalOpening");
184736
185288
  __publicField(this, "detail");
@@ -184743,6 +185295,8 @@ var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8
184743
185295
  __publicField(this, "commentDrafts", /* @__PURE__ */ new Map());
184744
185296
  __publicField(this, "ticketDrafts", /* @__PURE__ */ new Map());
184745
185297
  __publicField(this, "resolvedTickets", /* @__PURE__ */ new Map());
185298
+ __publicField(this, "activeMove");
185299
+ __publicField(this, "dragController", new KanbanDragController(this, (input) => this.persistMove(input), () => !this.pendingTicketId));
184746
185300
  __publicField(this, "searchTickets", /* @__PURE__ */ __name(async (query3, signal) => {
184747
185301
  const tickets = this.provider.searchTickets ? await this.provider.searchTickets(query3, signal) : this.tickets.filter((ticket) => ticketLabel(ticket).toLocaleLowerCase().includes(query3.toLocaleLowerCase()));
184748
185302
  if (!signal.aborted) for (const ticket of tickets) this.resolvedTickets.set(ticket.id, ticket);
@@ -184792,22 +185346,18 @@ var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8
184792
185346
  if (previous3) void this.openTicket(previous3, false);
184793
185347
  break;
184794
185348
  }
184795
- case "kanban-drag-start":
184796
- this.draggingTicketId = detail.ticketId;
184797
- break;
184798
- case "kanban-drag-end":
184799
- this.draggingTicketId = "";
184800
- break;
184801
185349
  }
184802
185350
  }, "handleInteraction"));
184803
185351
  }
184804
185352
  async connectedCallback() {
184805
185353
  const connection = super.connectedCallback();
184806
185354
  for (const name of interactionEvents) this.addEventListener(name, this.handleInteraction);
185355
+ this.dragController.connect();
184807
185356
  await connection;
184808
185357
  }
184809
185358
  updated() {
184810
185359
  this.syncDetail();
185360
+ this.dragController.sync();
184811
185361
  }
184812
185362
  render() {
184813
185363
  const epics = sortKanbanTickets(this.tickets.filter((ticket) => ticket.kind === "epic"));
@@ -184845,10 +185395,12 @@ var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8
184845
185395
  ${this.loading || this.openingTicket ? b2`<p class="caption" role="status">${this.loading ? "Loading board\u2026" : "Opening ticket\u2026"}</p>` : ""}
184846
185396
  ${this.error || this.operationError ? b2`<p class="error" role="alert">${this.error || this.operationError}</p>` : ""}
184847
185397
  ${!this.columns.length ? b2`<p class="empty">No columns configured.</p>` : b2`<div class="columns" aria-label=${this.heading}>
184848
- ${this.columns.map((column) => b2`<dees-kanban-column .column=${column} .columns=${this.columns}
185398
+ ${directives_exports.repeat(this.columns, (column) => column.id, (column) => b2`<dees-kanban-column .column=${column} .columns=${this.columns}
185399
+ .pointerManaged=${true}
184849
185400
  .tickets=${tasks.filter((ticket) => ticket.columnId === column.id)} .allTickets=${this.tickets}
184850
- .movable=${Boolean(this.provider.moveTicket) && !this.pendingTicketId} .canCreate=${Boolean(this.provider.createTicket)}
184851
- .pendingTicketId=${this.pendingTicketId} .draggingTicketId=${this.draggingTicketId}></dees-kanban-column>`)}</div>`}`;
185401
+ .movable=${Boolean(this.provider.moveTicket)} .canCreate=${Boolean(this.provider.createTicket)}
185402
+ .movesDisabled=${Boolean(this.pendingTicketId)}
185403
+ .pendingTicketId=${this.pendingTicketId}></dees-kanban-column>`)}</div>`}`;
184852
185404
  }
184853
185405
  findTicket(id) {
184854
185406
  return this.tickets.find((ticket) => ticket.id === id) ?? this.resolvedTickets.get(id);
@@ -184972,29 +185524,44 @@ var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8
184972
185524
  }
184973
185525
  /** Provider commits the move and supplies the new ordering. Hierarchy is never part of a move request. */
184974
185526
  async moveTicket(input) {
185527
+ if (this.dragController.busy) return;
185528
+ await this.persistMove(input, true);
185529
+ }
185530
+ async persistMove(input, animate = false) {
184975
185531
  const ticket = this.findTicket(input.ticketId);
184976
- if (!ticket || !this.provider.moveTicket || ticket.permissions?.move === false || this.pendingTicketId || input.beforeTicketId === ticket.id) return;
185532
+ if (!ticket || !this.provider.moveTicket || ticket.permissions?.move === false || this.pendingTicketId || input.beforeTicketId === ticket.id) return false;
184977
185533
  if (!this.columns.some((column) => column.id === input.columnId)) {
184978
185534
  this.reportError(new Error("Unknown destination column."));
184979
- return;
185535
+ return false;
184980
185536
  }
184981
185537
  const before = input.beforeTicketId ? this.findTicket(input.beforeTicketId) : void 0;
184982
185538
  if (input.beforeTicketId && (!before || before.columnId !== input.columnId || before.kind !== ticket.kind)) {
184983
185539
  this.reportError(new Error("Invalid insertion target."));
184984
- return;
185540
+ return false;
184985
185541
  }
185542
+ const operation = this.activeMove = /* @__PURE__ */ Symbol();
184986
185543
  this.pendingTicketId = ticket.id;
184987
185544
  this.operationError = "";
184988
- this.draggingTicketId = "";
184989
185545
  try {
184990
185546
  const changed2 = await this.provider.moveTicket(input);
185547
+ if (this.activeMove !== operation) return false;
184991
185548
  if (!changed2.some((item) => item.id === ticket.id)) throw new Error("The move provider did not return the moved ticket.");
185549
+ const positions = animate ? this.dragController.capture() : void 0;
184992
185550
  this.mergeTickets(changed2);
185551
+ if (positions) {
185552
+ await this.updateComplete;
185553
+ await this.dragController.animateFrom(positions);
185554
+ }
185555
+ return true;
184993
185556
  } catch (error) {
184994
- this.reportError(error);
185557
+ if (this.activeMove === operation) this.reportError(error);
185558
+ return false;
184995
185559
  } finally {
184996
- this.pendingTicketId = "";
184997
- this.syncDetail();
185560
+ if (this.activeMove === operation) {
185561
+ this.activeMove = void 0;
185562
+ this.pendingTicketId = "";
185563
+ this.syncDetail();
185564
+ }
184998
185565
  }
184999
185566
  }
185000
185567
  async saveTicket(ticketId, draft) {
@@ -185069,6 +185636,11 @@ var _DeesKanban = class _DeesKanban extends (_a109 = DeesElement, _heading_dec8
185069
185636
  }
185070
185637
  async disconnectedCallback() {
185071
185638
  for (const name of interactionEvents) this.removeEventListener(name, this.handleInteraction);
185639
+ this.dragController.disconnect();
185640
+ if (this.activeMove) {
185641
+ this.activeMove = void 0;
185642
+ this.pendingTicketId = "";
185643
+ }
185072
185644
  this.openAbort?.abort();
185073
185645
  this.commentsAbort?.abort();
185074
185646
  void this.modal?.destroy();
@@ -185087,7 +185659,6 @@ _query2 = new WeakMap();
185087
185659
  _epicId = new WeakMap();
185088
185660
  _operationError = new WeakMap();
185089
185661
  _pendingTicketId2 = new WeakMap();
185090
- _draggingTicketId2 = new WeakMap();
185091
185662
  _openingTicket = new WeakMap();
185092
185663
  __decorateElement(_init111, 4, "heading", _heading_dec8, _DeesKanban, _heading8);
185093
185664
  __decorateElement(_init111, 4, "tickets", _tickets_dec3, _DeesKanban, _tickets3);
@@ -185100,7 +185671,6 @@ __decorateElement(_init111, 4, "query", _query_dec2, _DeesKanban, _query2);
185100
185671
  __decorateElement(_init111, 4, "epicId", _epicId_dec, _DeesKanban, _epicId);
185101
185672
  __decorateElement(_init111, 4, "operationError", _operationError_dec, _DeesKanban, _operationError);
185102
185673
  __decorateElement(_init111, 4, "pendingTicketId", _pendingTicketId_dec2, _DeesKanban, _pendingTicketId2);
185103
- __decorateElement(_init111, 4, "draggingTicketId", _draggingTicketId_dec2, _DeesKanban, _draggingTicketId2);
185104
185674
  __decorateElement(_init111, 4, "openingTicket", _openingTicket_dec, _DeesKanban, _openingTicket);
185105
185675
  _DeesKanban = __decorateElement(_init111, 0, "DeesKanban", _DeesKanban_decorators, _DeesKanban);
185106
185676
  __name(_DeesKanban, "DeesKanban");
@@ -196892,9 +197462,9 @@ var AnnotationEditor = class _AnnotationEditor {
196892
197462
  } = this.getClientDimensions();
196893
197463
  const {
196894
197464
  innerHeight: innerHeight2,
196895
- innerWidth
197465
+ innerWidth: innerWidth2
196896
197466
  } = window;
196897
- return left < innerWidth && right > 0 && top < innerHeight2 && bottom > 0;
197467
+ return left < innerWidth2 && right > 0 && top < innerHeight2 && bottom > 0;
196898
197468
  }
196899
197469
  #addFocusListeners() {
196900
197470
  if (this.#focusAC || !this.div) {
@@ -226533,7 +227103,7 @@ init_group_runtime();
226533
227103
  // ts_web/00_commitinfo_data.ts
226534
227104
  var commitinfo = {
226535
227105
  name: "@design.estate/dees-catalog",
226536
- version: "13.0.1",
227106
+ version: "13.0.2",
226537
227107
  description: "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript."
226538
227108
  };
226539
227109