diff --git a/apps/client/src/widgets/view_widgets/board_view/api.ts b/apps/client/src/widgets/view_widgets/board_view/api.ts index 66bcc0f10..4b6f55e3c 100644 --- a/apps/client/src/widgets/view_widgets/board_view/api.ts +++ b/apps/client/src/widgets/view_widgets/board_view/api.ts @@ -110,12 +110,40 @@ export default class BoardApi { return columnValue; } + async reorderColumns(newColumnOrder: string[]) { + // Update the column order in persisted data + if (!this.persistedData.columns) { + this.persistedData.columns = []; + } + + // Create a map of existing column data + const columnDataMap = new Map(); + this.persistedData.columns.forEach(col => { + columnDataMap.set(col.value, col); + }); + + // Reorder columns based on new order + this.persistedData.columns = newColumnOrder.map(columnValue => { + return columnDataMap.get(columnValue) || { value: columnValue }; + }); + + // Update internal columns array + this._columns = newColumnOrder; + + await this.viewStorage.store(this.persistedData); + } + static async build(parentNote: FNote, viewStorage: ViewModeStorage) { const statusAttribute = parentNote.getLabelValue("board:groupBy") ?? "status"; let persistedData = await viewStorage.restore() ?? {}; const { byColumn, newPersistedData } = await getBoardData(parentNote, statusAttribute, persistedData); - const columns = Array.from(byColumn.keys()) || []; + + // Use the order from persistedData.columns, then add any new columns found + const orderedColumns = persistedData.columns?.map(col => col.value) || []; + const allColumns = Array.from(byColumn.keys()); + const newColumns = allColumns.filter(col => !orderedColumns.includes(col)); + const columns = [...orderedColumns, ...newColumns]; if (newPersistedData) { persistedData = newPersistedData; diff --git a/apps/client/src/widgets/view_widgets/board_view/column_drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/column_drag_handler.ts new file mode 100644 index 000000000..18fd9a945 --- /dev/null +++ b/apps/client/src/widgets/view_widgets/board_view/column_drag_handler.ts @@ -0,0 +1,240 @@ +import BoardApi from "./api"; +import { DragContext, BaseDragHandler } from "./drag_types"; + +export class ColumnDragHandler implements BaseDragHandler { + private $container: JQuery; + private api: BoardApi; + private context: DragContext; + private onBoardRefresh: () => Promise; + + constructor( + $container: JQuery, + api: BoardApi, + context: DragContext, + onBoardRefresh: () => Promise + ) { + this.$container = $container; + this.api = api; + this.context = context; + this.onBoardRefresh = onBoardRefresh; + } + + setupColumnDrag($columnEl: JQuery, columnValue: string) { + const $dragHandle = $columnEl.find('.column-drag-handle'); + + $dragHandle.attr("draggable", "true"); + + $dragHandle.on("dragstart", (e) => { + this.context.draggedColumn = columnValue; + this.context.draggedColumnElement = $columnEl; + $columnEl.addClass("column-dragging"); + + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.effectAllowed = "move"; + originalEvent.dataTransfer.setData("text/plain", columnValue); + } + + // Prevent note dragging when column is being dragged + e.stopPropagation(); + + // Setup global drag tracking for better drop indicator positioning + this.setupGlobalColumnDragTracking(); + }); + + $dragHandle.on("dragend", () => { + $columnEl.removeClass("column-dragging"); + this.context.draggedColumn = null; + this.context.draggedColumnElement = null; + this.cleanupColumnDropIndicators(); + this.cleanupGlobalColumnDragTracking(); + }); + } + + setupColumnDropZone($columnEl: JQuery, columnValue: string) { + $columnEl.on("dragover", (e) => { + // Only handle column drops when a column is being dragged + if (this.context.draggedColumn && !this.context.draggedNote) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.dropEffect = "move"; + } + + // Don't highlight columns - we only care about the drop indicator position + } + }); + + $columnEl.on("drop", async (e) => { + if (this.context.draggedColumn && !this.context.draggedNote) { + e.preventDefault(); + console.log("Column drop event triggered for column:", this.context.draggedColumn); + + // Use the drop indicator position to determine where to place the column + await this.handleColumnDrop(); + } + }); + } + + updateApi(newApi: BoardApi) { + this.api = newApi; + } + + cleanup() { + this.cleanupColumnDropIndicators(); + this.context.draggedColumn = null; + this.context.draggedColumnElement = null; + this.cleanupGlobalColumnDragTracking(); + } + + private setupGlobalColumnDragTracking() { + // Add container-level drag tracking for better indicator positioning + this.$container.on("dragover.columnDrag", (e) => { + if (this.context.draggedColumn) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + this.showColumnDropIndicator(originalEvent.clientX); + } + }); + + // Add container-level drop handler for column reordering + this.$container.on("drop.columnDrag", async (e) => { + if (this.context.draggedColumn) { + e.preventDefault(); + console.log("Container drop event triggered for column:", this.context.draggedColumn); + await this.handleColumnDrop(); + } + }); + } + + private cleanupGlobalColumnDragTracking() { + this.$container.off("dragover.columnDrag"); + this.$container.off("drop.columnDrag"); + } + + private cleanupColumnDropIndicators() { + // Remove column drop indicators + this.$container.find(".column-drop-indicator").remove(); + } + + private showColumnDropIndicator(mouseX: number) { + // Clean up existing indicators + this.cleanupColumnDropIndicators(); + + // Get all columns (excluding the dragged one if it exists) + let $allColumns = this.$container.find('.board-column'); + if (this.context.draggedColumnElement) { + $allColumns = $allColumns.not(this.context.draggedColumnElement); + } + + let $targetColumn: JQuery = $(); + let insertBefore = false; + + // Find which column the mouse is closest to + $allColumns.each((_, columnEl) => { + const $column = $(columnEl); + const rect = columnEl.getBoundingClientRect(); + const columnMiddle = rect.left + rect.width / 2; + + if (mouseX >= rect.left && mouseX <= rect.right) { + // Mouse is over this column + $targetColumn = $column; + insertBefore = mouseX < columnMiddle; + return false; // Break the loop + } + }); + + // If no column found under mouse, find the closest one + if ($targetColumn.length === 0) { + let closestDistance = Infinity; + $allColumns.each((_, columnEl) => { + const $column = $(columnEl); + const rect = columnEl.getBoundingClientRect(); + const columnCenter = rect.left + rect.width / 2; + const distance = Math.abs(mouseX - columnCenter); + + if (distance < closestDistance) { + closestDistance = distance; + $targetColumn = $column; + insertBefore = mouseX < columnCenter; + } + }); + } + + if ($targetColumn.length > 0) { + const $dropIndicator = $("
").addClass("column-drop-indicator"); + + if (insertBefore) { + $targetColumn.before($dropIndicator); + } else { + $targetColumn.after($dropIndicator); + } + + $dropIndicator.addClass("show"); + } + } + + private async handleColumnDrop() { + console.log("handleColumnDrop called for:", this.context.draggedColumn); + + if (!this.context.draggedColumn || !this.context.draggedColumnElement) { + console.log("No dragged column or element found"); + return; + } + + try { + // Find the drop indicator to determine insert position + const $dropIndicator = this.$container.find(".column-drop-indicator.show"); + console.log("Drop indicator found:", $dropIndicator.length > 0); + + if ($dropIndicator.length > 0) { + // Get current column order from the API (source of truth) + const currentOrder = [...this.api.columns]; + + let newOrder = [...currentOrder]; + + // Remove dragged column from current position + newOrder = newOrder.filter(col => col !== this.context.draggedColumn); + + // Determine insertion position based on drop indicator position + const $nextColumn = $dropIndicator.next('.board-column'); + const $prevColumn = $dropIndicator.prev('.board-column'); + + let insertIndex = -1; + + if ($nextColumn.length > 0) { + // Insert before the next column + const nextColumnValue = $nextColumn.attr('data-column'); + insertIndex = newOrder.indexOf(nextColumnValue!); + } else if ($prevColumn.length > 0) { + // Insert after the previous column + const prevColumnValue = $prevColumn.attr('data-column'); + insertIndex = newOrder.indexOf(prevColumnValue!) + 1; + } else { + // Insert at the beginning + insertIndex = 0; + } + + // Insert the dragged column at the determined position + if (insertIndex >= 0 && insertIndex <= newOrder.length) { + newOrder.splice(insertIndex, 0, this.context.draggedColumn); + } else { + // Fallback: insert at the end + newOrder.push(this.context.draggedColumn); + } + + // Update column order in API + await this.api.reorderColumns(newOrder); + + // Refresh the board to reflect the changes + await this.onBoardRefresh(); + } else { + console.warn("No drop indicator found for column drop"); + } + } catch (error) { + console.error("Failed to reorder columns:", error); + } finally { + this.cleanupColumnDropIndicators(); + } + } +} diff --git a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts index 797a525b5..a5ab3c9a8 100644 --- a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts +++ b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts @@ -133,6 +133,14 @@ export class DifferentialBoardRenderer { } private updateColumns(oldState: BoardState, newState: BoardState): void { + // Check if column order has changed + const orderChanged = !this.arraysEqual(oldState.columnOrder, newState.columnOrder); + + if (orderChanged) { + // If order changed, we need to reorder the columns in the DOM + this.reorderColumns(newState.columnOrder); + } + // Remove columns that no longer exist for (const oldColumn of oldState.columnOrder) { if (!newState.columnOrder.includes(oldColumn)) { @@ -161,6 +169,49 @@ export class DifferentialBoardRenderer { } } + private arraysEqual(a: string[], b: string[]): boolean { + return a.length === b.length && a.every((val, index) => val === b[index]); + } + + private reorderColumns(newOrder: string[]): void { + // Get all existing column elements + const $columns = this.$container.find('.board-column'); + const $addColumnButton = this.$container.find('.board-add-column'); + + // Create a map of column elements by their data-column attribute + const columnElements = new Map>(); + $columns.each((_, el) => { + const $el = $(el); + const columnValue = $el.attr('data-column'); + if (columnValue) { + columnElements.set(columnValue, $el); + } + }); + + // Remove all columns from DOM (but keep references) + $columns.detach(); + + // Re-insert columns in the new order + let $insertAfter: JQuery | null = null; + for (const columnValue of newOrder) { + const $columnEl = columnElements.get(columnValue); + if ($columnEl) { + if ($insertAfter) { + $insertAfter.after($columnEl); + } else { + // Insert at the beginning + this.$container.prepend($columnEl); + } + $insertAfter = $columnEl; + } + } + + // Ensure add column button is at the end + if ($addColumnButton.length) { + this.$container.append($addColumnButton); + } + } + private updateColumnCards(column: string, oldCards: { note: any; branch: any }[], newCards: { note: any; branch: any }[]): void { const $column = this.$container.find(`[data-column="${column}"]`); if (!$column.length) return; @@ -241,15 +292,33 @@ export class DifferentialBoardRenderer { .addClass("board-column") .attr("data-column", column); - // Create header + // Create header with drag handle const $titleEl = $("

").attr("data-column-value", column); + + // Create drag handle + const $dragHandle = $("") + .addClass("column-drag-handle icon bx bx-menu") + .attr("title", "Drag to reorder column"); + + // Create title text const $titleText = $("").text(column); + + // Create title content container + const $titleContent = $("
") + .addClass("column-title-content") + .append($dragHandle, $titleText); + + // Create edit icon const $editIcon = $("") .addClass("edit-icon icon bx bx-edit-alt") .attr("title", "Click to edit column title"); - $titleEl.append($titleText, $editIcon); + + $titleEl.append($titleContent, $editIcon); $columnEl.append($titleEl); + // Setup column dragging + this.dragHandler.setupColumnDrag($columnEl, column); + // Handle wheel events for scrolling $columnEl.on("wheel", (event) => { const el = $columnEl[0]; @@ -259,7 +328,8 @@ export class DifferentialBoardRenderer { } }); - // Setup drop zone + // Setup drop zones for both notes and columns + this.dragHandler.setupNoteDropZone($columnEl, column); this.dragHandler.setupColumnDropZone($columnEl, column); // Add cards diff --git a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts index c11a68b8a..4f8866cd2 100644 --- a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts +++ b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts @@ -1,17 +1,16 @@ -import branchService from "../../../services/branches"; import BoardApi from "./api"; - -export interface DragContext { - draggedNote: any; - draggedBranch: any; - draggedNoteElement: JQuery | null; -} +import { DragContext } from "./drag_types"; +import { NoteDragHandler } from "./note_drag_handler"; +import { ColumnDragHandler } from "./column_drag_handler"; export class BoardDragHandler { private $container: JQuery; private api: BoardApi; private context: DragContext; private onBoardRefresh: () => Promise; + + private noteDragHandler: NoteDragHandler; + private columnDragHandler: ColumnDragHandler; constructor( $container: JQuery, @@ -23,318 +22,42 @@ export class BoardDragHandler { this.api = api; this.context = context; this.onBoardRefresh = onBoardRefresh; + + // Initialize specialized drag handlers + this.noteDragHandler = new NoteDragHandler($container, api, context, onBoardRefresh); + this.columnDragHandler = new ColumnDragHandler($container, api, context, onBoardRefresh); } + // Note drag methods - delegate to NoteDragHandler setupNoteDrag($noteEl: JQuery, note: any, branch: any) { - $noteEl.attr("draggable", "true"); - - // Mouse drag events - this.setupMouseDrag($noteEl, note, branch); - - // Touch drag events - this.setupTouchDrag($noteEl, note, branch); + this.noteDragHandler.setupNoteDrag($noteEl, note, branch); } + setupNoteDropZone($columnEl: JQuery, column: string) { + this.noteDragHandler.setupNoteDropZone($columnEl, column); + } + + // Column drag methods - delegate to ColumnDragHandler + setupColumnDrag($columnEl: JQuery, columnValue: string) { + this.columnDragHandler.setupColumnDrag($columnEl, columnValue); + } + + setupColumnDropZone($columnEl: JQuery, columnValue: string) { + this.columnDragHandler.setupColumnDropZone($columnEl, columnValue); + } + + // Common methods updateApi(newApi: BoardApi) { this.api = newApi; + this.noteDragHandler.updateApi(newApi); + this.columnDragHandler.updateApi(newApi); } - private cleanupAllDropIndicators() { - // Remove all drop indicators from the DOM to prevent layout issues - this.$container.find(".board-drop-indicator").remove(); - } - - private cleanupColumnDropIndicators($columnEl: JQuery) { - // Remove drop indicators from a specific column - $columnEl.find(".board-drop-indicator").remove(); - } - - // Public method to clean up any stray indicators - can be called externally cleanup() { - this.cleanupAllDropIndicators(); - this.$container.find('.board-column').removeClass('drag-over'); - } - - private setupMouseDrag($noteEl: JQuery, note: any, branch: any) { - $noteEl.on("dragstart", (e) => { - this.context.draggedNote = note; - this.context.draggedBranch = branch; - this.context.draggedNoteElement = $noteEl; - $noteEl.addClass("dragging"); - - // Set drag data - const originalEvent = e.originalEvent as DragEvent; - if (originalEvent.dataTransfer) { - originalEvent.dataTransfer.effectAllowed = "move"; - originalEvent.dataTransfer.setData("text/plain", note.noteId); - } - }); - - $noteEl.on("dragend", () => { - $noteEl.removeClass("dragging"); - this.context.draggedNote = null; - this.context.draggedBranch = null; - this.context.draggedNoteElement = null; - - // Clean up all drop indicators properly - this.cleanupAllDropIndicators(); - }); - } - - private setupTouchDrag($noteEl: JQuery, note: any, branch: any) { - let isDragging = false; - let startY = 0; - let startX = 0; - let dragThreshold = 10; // Minimum distance to start dragging - let $dragPreview: JQuery | null = null; - - $noteEl.on("touchstart", (e) => { - const touch = (e.originalEvent as TouchEvent).touches[0]; - startX = touch.clientX; - startY = touch.clientY; - isDragging = false; - $dragPreview = null; - }); - - $noteEl.on("touchmove", (e) => { - e.preventDefault(); // Prevent scrolling - const touch = (e.originalEvent as TouchEvent).touches[0]; - const deltaX = Math.abs(touch.clientX - startX); - const deltaY = Math.abs(touch.clientY - startY); - - // Start dragging if we've moved beyond threshold - if (!isDragging && (deltaX > dragThreshold || deltaY > dragThreshold)) { - isDragging = true; - this.context.draggedNote = note; - this.context.draggedBranch = branch; - this.context.draggedNoteElement = $noteEl; - $noteEl.addClass("dragging"); - - // Create drag preview - $dragPreview = this.createDragPreview($noteEl, touch.clientX, touch.clientY); - } - - if (isDragging && $dragPreview) { - // Update drag preview position - $dragPreview.css({ - left: touch.clientX - ($dragPreview.outerWidth() || 0) / 2, - top: touch.clientY - ($dragPreview.outerHeight() || 0) / 2 - }); - - // Find element under touch point - const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); - if (elementBelow) { - const $columnEl = $(elementBelow).closest('.board-column'); - - if ($columnEl.length > 0) { - // Remove drag-over from all columns - this.$container.find('.board-column').removeClass('drag-over'); - $columnEl.addClass('drag-over'); - - // Show drop indicator - this.showDropIndicatorAtPoint($columnEl, touch.clientY); - } else { - // Remove all drag indicators if not over a column - this.$container.find('.board-column').removeClass('drag-over'); - this.cleanupAllDropIndicators(); - } - } - } - }); - - $noteEl.on("touchend", async (e) => { - if (isDragging) { - const touch = (e.originalEvent as TouchEvent).changedTouches[0]; - const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); - if (elementBelow) { - const $columnEl = $(elementBelow).closest('.board-column'); - - if ($columnEl.length > 0) { - const column = $columnEl.attr('data-column'); - if (column && this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { - await this.handleNoteDrop($columnEl, column); - } - } - } - - // Clean up - $noteEl.removeClass("dragging"); - this.context.draggedNote = null; - this.context.draggedBranch = null; - this.context.draggedNoteElement = null; - this.$container.find('.board-column').removeClass('drag-over'); - this.cleanupAllDropIndicators(); - - // Remove drag preview - if ($dragPreview) { - $dragPreview.remove(); - $dragPreview = null; - } - } - isDragging = false; - }); - } - - setupColumnDropZone($columnEl: JQuery, column: string) { - $columnEl.on("dragover", (e) => { - e.preventDefault(); - const originalEvent = e.originalEvent as DragEvent; - if (originalEvent.dataTransfer) { - originalEvent.dataTransfer.dropEffect = "move"; - } - - if (this.context.draggedNote) { - $columnEl.addClass("drag-over"); - this.showDropIndicator($columnEl, e); - } - }); - - $columnEl.on("dragleave", (e) => { - // Only remove drag-over if we're leaving the column entirely - const rect = $columnEl[0].getBoundingClientRect(); - const originalEvent = e.originalEvent as DragEvent; - const x = originalEvent.clientX; - const y = originalEvent.clientY; - - if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) { - $columnEl.removeClass("drag-over"); - this.cleanupColumnDropIndicators($columnEl); - } - }); - - $columnEl.on("drop", async (e) => { - e.preventDefault(); - $columnEl.removeClass("drag-over"); - - if (this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { - await this.handleNoteDrop($columnEl, column); - } - }); - } - - private createDragPreview($noteEl: JQuery, x: number, y: number): JQuery { - // Clone the note element for the preview - const $preview = $noteEl.clone(); - - $preview - .addClass('board-drag-preview') - .css({ - position: 'fixed', - left: x - ($noteEl.outerWidth() || 0) / 2, - top: y - ($noteEl.outerHeight() || 0) / 2, - pointerEvents: 'none', - zIndex: 10000 - }) - .appendTo('body'); - - return $preview; - } - - private showDropIndicator($columnEl: JQuery, e: JQuery.DragOverEvent) { - const originalEvent = e.originalEvent as DragEvent; - const mouseY = originalEvent.clientY; - this.showDropIndicatorAtY($columnEl, mouseY); - } - - private showDropIndicatorAtPoint($columnEl: JQuery, touchY: number) { - this.showDropIndicatorAtY($columnEl, touchY); - } - - private showDropIndicatorAtY($columnEl: JQuery, y: number) { - const columnRect = $columnEl[0].getBoundingClientRect(); - const relativeY = y - columnRect.top; - - // Clean up any existing drop indicators in this column first - this.cleanupColumnDropIndicators($columnEl); - - // Create a new drop indicator - const $dropIndicator = $("
").addClass("board-drop-indicator"); - - // Find the best position to insert the note - const $notes = this.context.draggedNoteElement ? - $columnEl.find(".board-note").not(this.context.draggedNoteElement) : - $columnEl.find(".board-note"); - let insertAfterElement: HTMLElement | null = null; - - $notes.each((_, noteEl) => { - const noteRect = noteEl.getBoundingClientRect(); - const noteMiddle = noteRect.top + noteRect.height / 2 - columnRect.top; - - if (relativeY > noteMiddle) { - insertAfterElement = noteEl; - } - }); - - // Position the drop indicator - if (insertAfterElement) { - $(insertAfterElement).after($dropIndicator); - } else { - // Insert at the beginning (after the header) - const $header = $columnEl.find("h3"); - $header.after($dropIndicator); - } - - $dropIndicator.addClass("show"); - } - - private async handleNoteDrop($columnEl: JQuery, column: string) { - const draggedNoteElement = this.context.draggedNoteElement; - const draggedNote = this.context.draggedNote; - const draggedBranch = this.context.draggedBranch; - - if (draggedNote && draggedNoteElement && draggedBranch) { - const currentColumn = draggedNoteElement.attr("data-current-column"); - - // Capture drop indicator position BEFORE removing it - const dropIndicator = $columnEl.find(".board-drop-indicator.show"); - let targetBranchId: string | null = null; - let moveType: "before" | "after" | null = null; - - if (dropIndicator.length > 0) { - // Find the note element that the drop indicator is positioned relative to - const nextNote = dropIndicator.next(".board-note"); - const prevNote = dropIndicator.prev(".board-note"); - - if (nextNote.length > 0) { - targetBranchId = nextNote.attr("data-branch-id") || null; - moveType = "before"; - } else if (prevNote.length > 0) { - targetBranchId = prevNote.attr("data-branch-id") || null; - moveType = "after"; - } - } - - try { - // Handle column change - if (currentColumn !== column) { - await this.api.changeColumn(draggedNote.noteId, column); - } - - // Handle position change (works for both same column and different column moves) - if (targetBranchId && moveType) { - if (moveType === "before") { - console.log("Move before branch:", draggedBranch.branchId, "to", targetBranchId); - await branchService.moveBeforeBranch([draggedBranch.branchId], targetBranchId); - } else if (moveType === "after") { - console.log("Move after branch:", draggedBranch.branchId, "to", targetBranchId); - await branchService.moveAfterBranch([draggedBranch.branchId], targetBranchId); - } - } - - // Update the data attributes - draggedNoteElement.attr("data-current-column", column); - - // Show success feedback - console.log(`Moved note "${draggedNote.title}" from "${currentColumn}" to "${column}"`); - - // Refresh the board to reflect the changes - await this.onBoardRefresh(); - } catch (error) { - console.error("Failed to update note position:", error); - } finally { - // Always clean up drop indicators after drop operation - this.cleanupAllDropIndicators(); - } - } + this.noteDragHandler.cleanup(); + this.columnDragHandler.cleanup(); } } + +// Export the drag context type for external use +export type { DragContext } from "./drag_types"; diff --git a/apps/client/src/widgets/view_widgets/board_view/drag_types.ts b/apps/client/src/widgets/view_widgets/board_view/drag_types.ts new file mode 100644 index 000000000..ff3cde8c7 --- /dev/null +++ b/apps/client/src/widgets/view_widgets/board_view/drag_types.ts @@ -0,0 +1,12 @@ +export interface DragContext { + draggedNote: any; + draggedBranch: any; + draggedNoteElement: JQuery | null; + draggedColumn: string | null; + draggedColumnElement: JQuery | null; +} + +export interface BaseDragHandler { + cleanup(): void; + updateApi(api: any): void; +} diff --git a/apps/client/src/widgets/view_widgets/board_view/index.ts b/apps/client/src/widgets/view_widgets/board_view/index.ts index a438d6282..1bdf7d21e 100644 --- a/apps/client/src/widgets/view_widgets/board_view/index.ts +++ b/apps/client/src/widgets/view_widgets/board_view/index.ts @@ -70,6 +70,42 @@ const TPL = /*html*/` border-radius: 4px; } + .board-view-container .board-column h3 .column-title-content { + display: flex; + align-items: center; + flex: 1; + min-width: 0; /* Allow text to truncate */ + } + + .board-view-container .board-column h3 .column-drag-handle { + margin-right: 0.5em; + color: var(--muted-text-color); + cursor: grab; + opacity: 0; + transition: opacity 0.2s ease; + padding: 0.25em; + border-radius: 3px; + } + + .board-view-container .board-column h3:hover .column-drag-handle { + opacity: 1; + } + + .board-view-container .board-column h3 .column-drag-handle:hover { + background-color: var(--main-background-color); + color: var(--main-text-color); + } + + .board-view-container .board-column h3 .column-drag-handle:active { + cursor: grabbing; + } + + .board-view-container .board-column.column-dragging { + opacity: 0.6; + transform: scale(0.98); + transition: opacity 0.2s ease, transform 0.2s ease; + } + .board-view-container .board-column h3 input { background: transparent; border: none; @@ -172,6 +208,22 @@ const TPL = /*html*/` opacity: 1; } + .column-drop-indicator { + width: 4px; + background-color: var(--main-text-color); + border-radius: 2px; + opacity: 0; + transition: opacity 0.2s ease; + height: 100%; + z-index: 1000; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); + flex-shrink: 0; + } + + .column-drop-indicator.show { + opacity: 1; + } + .board-new-item { margin-top: 0.5em; padding: 0.5em; @@ -274,7 +326,9 @@ export default class BoardView extends ViewMode { this.dragContext = { draggedNote: null, draggedBranch: null, - draggedNoteElement: null + draggedNoteElement: null, + draggedColumn: null, + draggedColumnElement: null }; args.$parent.append(this.$root); @@ -320,10 +374,10 @@ export default class BoardView extends ViewMode { } private setupBoardInteractions() { - // Handle column title editing - this.$container.on('click', 'h3[data-column-value]', (e) => { + // Handle column title editing - listen for clicks on the title content, not the drag handle + this.$container.on('click', 'h3[data-column-value] .column-title-content span:not(.column-drag-handle)', (e) => { e.stopPropagation(); - const $titleEl = $(e.currentTarget); + const $titleEl = $(e.currentTarget).closest('h3[data-column-value]'); const columnValue = $titleEl.attr('data-column-value'); if (columnValue) { const columnItems = this.api?.getColumn(columnValue) || []; @@ -331,6 +385,24 @@ export default class BoardView extends ViewMode { } }); + // Also handle clicks on the h3 element itself (but not on the drag handle) + this.$container.on('click', 'h3[data-column-value]', (e) => { + // Only proceed if the click wasn't on the drag handle or edit icon + if (!$(e.target).hasClass('column-drag-handle') && + !$(e.target).hasClass('edit-icon') && + !$(e.target).hasClass('bx-menu') && + !$(e.target).hasClass('bx-edit-alt')) { + + e.stopPropagation(); + const $titleEl = $(e.currentTarget); + const columnValue = $titleEl.attr('data-column-value'); + if (columnValue) { + const columnItems = this.api?.getColumn(columnValue) || []; + this.startEditingColumnTitle($titleEl, columnValue, columnItems); + } + } + }); + // Handle add column button this.$container.on('click', '.board-add-column', (e) => { e.stopPropagation(); @@ -339,12 +411,21 @@ export default class BoardView extends ViewMode { } private createTitleStructure(title: string): { $titleText: JQuery; $editIcon: JQuery } { + const $dragHandle = $("") + .addClass("column-drag-handle icon bx bx-menu") + .attr("title", "Drag to reorder column"); + const $titleText = $("").text(title); + + const $titleContent = $("
") + .addClass("column-title-content") + .append($dragHandle, $titleText); + const $editIcon = $("") .addClass("edit-icon icon bx bx-edit-alt") .attr("title", "Click to edit column title"); - return { $titleText, $editIcon }; + return { $titleText: $titleContent, $editIcon }; } private startEditingColumnTitle($titleEl: JQuery, columnValue: string, columnItems: { branch: any; note: any; }[]) { @@ -352,8 +433,9 @@ export default class BoardView extends ViewMode { return; // Already editing } - const $titleText = $titleEl.find("span").first(); - const currentTitle = $titleText.text(); + const $titleContent = $titleEl.find(".column-title-content"); + const $titleSpan = $titleContent.find("span").last(); // Get the text span, not the drag handle + const currentTitle = $titleSpan.text(); $titleEl.addClass("editing"); const $input = $("") diff --git a/apps/client/src/widgets/view_widgets/board_view/note_drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/note_drag_handler.ts new file mode 100644 index 000000000..042f1a630 --- /dev/null +++ b/apps/client/src/widgets/view_widgets/board_view/note_drag_handler.ts @@ -0,0 +1,332 @@ +import branchService from "../../../services/branches"; +import BoardApi from "./api"; +import { DragContext, BaseDragHandler } from "./drag_types"; + +export class NoteDragHandler implements BaseDragHandler { + private $container: JQuery; + private api: BoardApi; + private context: DragContext; + private onBoardRefresh: () => Promise; + + constructor( + $container: JQuery, + api: BoardApi, + context: DragContext, + onBoardRefresh: () => Promise + ) { + this.$container = $container; + this.api = api; + this.context = context; + this.onBoardRefresh = onBoardRefresh; + } + + setupNoteDrag($noteEl: JQuery, note: any, branch: any) { + $noteEl.attr("draggable", "true"); + + // Mouse drag events + this.setupMouseDrag($noteEl, note, branch); + + // Touch drag events + this.setupTouchDrag($noteEl, note, branch); + } + + setupNoteDropZone($columnEl: JQuery, column: string) { + $columnEl.on("dragover", (e) => { + // Only handle note drops when a note is being dragged + if (this.context.draggedNote && !this.context.draggedColumn) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.dropEffect = "move"; + } + + $columnEl.addClass("drag-over"); + this.showDropIndicator($columnEl, e); + } + }); + + $columnEl.on("dragleave", (e) => { + // Only remove drag-over if we're leaving the column entirely + const rect = $columnEl[0].getBoundingClientRect(); + const originalEvent = e.originalEvent as DragEvent; + const x = originalEvent.clientX; + const y = originalEvent.clientY; + + if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) { + $columnEl.removeClass("drag-over"); + this.cleanupNoteDropIndicators($columnEl); + } + }); + + $columnEl.on("drop", async (e) => { + if (this.context.draggedNote && !this.context.draggedColumn) { + e.preventDefault(); + $columnEl.removeClass("drag-over"); + + if (this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { + await this.handleNoteDrop($columnEl, column); + } + } + }); + } + + updateApi(newApi: BoardApi) { + this.api = newApi; + } + + cleanup() { + this.cleanupAllDropIndicators(); + this.$container.find('.board-column').removeClass('drag-over'); + } + + private setupMouseDrag($noteEl: JQuery, note: any, branch: any) { + $noteEl.on("dragstart", (e) => { + this.context.draggedNote = note; + this.context.draggedBranch = branch; + this.context.draggedNoteElement = $noteEl; + $noteEl.addClass("dragging"); + + // Set drag data + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.effectAllowed = "move"; + originalEvent.dataTransfer.setData("text/plain", note.noteId); + } + }); + + $noteEl.on("dragend", () => { + $noteEl.removeClass("dragging"); + this.context.draggedNote = null; + this.context.draggedBranch = null; + this.context.draggedNoteElement = null; + + // Clean up all drop indicators properly + this.cleanupAllDropIndicators(); + }); + } + + private setupTouchDrag($noteEl: JQuery, note: any, branch: any) { + let isDragging = false; + let startY = 0; + let startX = 0; + let dragThreshold = 10; // Minimum distance to start dragging + let $dragPreview: JQuery | null = null; + + $noteEl.on("touchstart", (e) => { + const touch = (e.originalEvent as TouchEvent).touches[0]; + startX = touch.clientX; + startY = touch.clientY; + isDragging = false; + $dragPreview = null; + }); + + $noteEl.on("touchmove", (e) => { + e.preventDefault(); // Prevent scrolling + const touch = (e.originalEvent as TouchEvent).touches[0]; + const deltaX = Math.abs(touch.clientX - startX); + const deltaY = Math.abs(touch.clientY - startY); + + // Start dragging if we've moved beyond threshold + if (!isDragging && (deltaX > dragThreshold || deltaY > dragThreshold)) { + isDragging = true; + this.context.draggedNote = note; + this.context.draggedBranch = branch; + this.context.draggedNoteElement = $noteEl; + $noteEl.addClass("dragging"); + + // Create drag preview + $dragPreview = this.createDragPreview($noteEl, touch.clientX, touch.clientY); + } + + if (isDragging && $dragPreview) { + // Update drag preview position + $dragPreview.css({ + left: touch.clientX - ($dragPreview.outerWidth() || 0) / 2, + top: touch.clientY - ($dragPreview.outerHeight() || 0) / 2 + }); + + // Find element under touch point + const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); + if (elementBelow) { + const $columnEl = $(elementBelow).closest('.board-column'); + + if ($columnEl.length > 0) { + // Remove drag-over from all columns + this.$container.find('.board-column').removeClass('drag-over'); + $columnEl.addClass('drag-over'); + + // Show drop indicator + this.showDropIndicatorAtPoint($columnEl, touch.clientY); + } else { + // Remove all drag indicators if not over a column + this.$container.find('.board-column').removeClass('drag-over'); + this.cleanupAllDropIndicators(); + } + } + } + }); + + $noteEl.on("touchend", async (e) => { + if (isDragging) { + const touch = (e.originalEvent as TouchEvent).changedTouches[0]; + const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); + if (elementBelow) { + const $columnEl = $(elementBelow).closest('.board-column'); + + if ($columnEl.length > 0) { + const column = $columnEl.attr('data-column'); + if (column && this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { + await this.handleNoteDrop($columnEl, column); + } + } + } + + // Clean up + $noteEl.removeClass("dragging"); + this.context.draggedNote = null; + this.context.draggedBranch = null; + this.context.draggedNoteElement = null; + this.$container.find('.board-column').removeClass('drag-over'); + this.cleanupAllDropIndicators(); + + // Remove drag preview + if ($dragPreview) { + $dragPreview.remove(); + $dragPreview = null; + } + } + isDragging = false; + }); + } + + private createDragPreview($noteEl: JQuery, x: number, y: number): JQuery { + // Clone the note element for the preview + const $preview = $noteEl.clone(); + + $preview + .addClass('board-drag-preview') + .css({ + position: 'fixed', + left: x - ($noteEl.outerWidth() || 0) / 2, + top: y - ($noteEl.outerHeight() || 0) / 2, + pointerEvents: 'none', + zIndex: 10000 + }) + .appendTo('body'); + + return $preview; + } + + private showDropIndicator($columnEl: JQuery, e: JQuery.DragOverEvent) { + const originalEvent = e.originalEvent as DragEvent; + const mouseY = originalEvent.clientY; + this.showDropIndicatorAtY($columnEl, mouseY); + } + + private showDropIndicatorAtPoint($columnEl: JQuery, touchY: number) { + this.showDropIndicatorAtY($columnEl, touchY); + } + + private showDropIndicatorAtY($columnEl: JQuery, y: number) { + const columnRect = $columnEl[0].getBoundingClientRect(); + const relativeY = y - columnRect.top; + + // Clean up any existing drop indicators in this column first + this.cleanupNoteDropIndicators($columnEl); + + // Create a new drop indicator + const $dropIndicator = $("
").addClass("board-drop-indicator"); + + // Find the best position to insert the note + const $notes = this.context.draggedNoteElement ? + $columnEl.find(".board-note").not(this.context.draggedNoteElement) : + $columnEl.find(".board-note"); + let insertAfterElement: HTMLElement | null = null; + + $notes.each((_, noteEl) => { + const noteRect = noteEl.getBoundingClientRect(); + const noteMiddle = noteRect.top + noteRect.height / 2 - columnRect.top; + + if (relativeY > noteMiddle) { + insertAfterElement = noteEl; + } + }); + + // Position the drop indicator + if (insertAfterElement) { + $(insertAfterElement).after($dropIndicator); + } else { + // Insert at the beginning (after the header) + const $header = $columnEl.find("h3"); + $header.after($dropIndicator); + } + + $dropIndicator.addClass("show"); + } + + private async handleNoteDrop($columnEl: JQuery, column: string) { + const draggedNoteElement = this.context.draggedNoteElement; + const draggedNote = this.context.draggedNote; + const draggedBranch = this.context.draggedBranch; + + if (draggedNote && draggedNoteElement && draggedBranch) { + const currentColumn = draggedNoteElement.attr("data-current-column"); + + // Capture drop indicator position BEFORE removing it + const dropIndicator = $columnEl.find(".board-drop-indicator.show"); + let targetBranchId: string | null = null; + let moveType: "before" | "after" | null = null; + + if (dropIndicator.length > 0) { + // Find the note element that the drop indicator is positioned relative to + const nextNote = dropIndicator.next(".board-note"); + const prevNote = dropIndicator.prev(".board-note"); + + if (nextNote.length > 0) { + targetBranchId = nextNote.attr("data-branch-id") || null; + moveType = "before"; + } else if (prevNote.length > 0) { + targetBranchId = prevNote.attr("data-branch-id") || null; + moveType = "after"; + } + } + + try { + // Handle column change + if (currentColumn !== column) { + await this.api.changeColumn(draggedNote.noteId, column); + } + + // Handle position change (works for both same column and different column moves) + if (targetBranchId && moveType) { + if (moveType === "before") { + await branchService.moveBeforeBranch([draggedBranch.branchId], targetBranchId); + } else if (moveType === "after") { + await branchService.moveAfterBranch([draggedBranch.branchId], targetBranchId); + } + } + + // Update the data attributes + draggedNoteElement.attr("data-current-column", column); + + // Refresh the board to reflect the changes + await this.onBoardRefresh(); + } catch (error) { + console.error("Failed to update note position:", error); + } finally { + // Always clean up drop indicators after drop operation + this.cleanupAllDropIndicators(); + } + } + } + + private cleanupAllDropIndicators() { + // Remove all drop indicators from the DOM to prevent layout issues + this.$container.find(".board-drop-indicator").remove(); + } + + private cleanupNoteDropIndicators($columnEl: JQuery) { + // Remove note drop indicators from a specific column + $columnEl.find(".board-drop-indicator").remove(); + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4d4012f8c..132e507e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -810,13 +810,13 @@ importers: version: 9.31.0 '@sveltejs/adapter-auto': specifier: ^6.0.0 - version: 6.0.1(@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))) + version: 6.0.1(@sveltejs/kit@2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))) '@sveltejs/kit': specifier: ^2.16.0 - version: 2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + version: 2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) '@sveltejs/vite-plugin-svelte': specifier: ^6.0.0 - version: 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + version: 6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) '@tailwindcss/typography': specifier: ^0.5.15 version: 0.5.16(tailwindcss@4.1.11) @@ -828,19 +828,19 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-plugin-svelte: specifier: ^3.0.0 - version: 3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.14)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)) + version: 3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.16)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)) globals: specifier: ^16.0.0 version: 16.3.0 mdsvex: specifier: ^0.12.3 - version: 0.12.6(svelte@5.36.14) + version: 0.12.6(svelte@5.36.16) svelte: specifier: ^5.0.0 - version: 5.36.14 + version: 5.36.16 svelte-check: specifier: ^4.0.0 - version: 4.3.0(picomatch@4.0.3)(svelte@5.36.14)(typescript@5.8.3) + version: 4.3.0(picomatch@4.0.3)(svelte@5.36.16)(typescript@5.8.3) tailwindcss: specifier: ^4.0.0 version: 4.1.11 @@ -913,7 +913,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -925,7 +925,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -973,7 +973,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -985,7 +985,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -1033,7 +1033,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -1045,7 +1045,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -1100,7 +1100,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -1112,7 +1112,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -1167,7 +1167,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -1179,7 +1179,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -3154,6 +3154,10 @@ packages: resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.3.4': + resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@excalidraw/excalidraw@0.18.0': resolution: {integrity: sha512-QkIiS+5qdy8lmDWTKsuy0sK/fen/LRDtbhm2lc2xcFcqhv2/zdg95bYnl+wnwwXGHo7kEmP65BSiMHE7PJ3Zpw==} peerDependencies: @@ -5195,8 +5199,8 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/kit@2.25.2': - resolution: {integrity: sha512-aKfj82vqEINedoH9Pw4Ip16jj3w8soNq9F3nJqc56kxXW74TcEu/gdTAuLUI+gsl8i+KXfetRqg1F+gG/AZRVQ==} + '@sveltejs/kit@2.26.0': + resolution: {integrity: sha512-TUxMYoK6Yim4uRIW0L7TXtlEtyLchy90PmInI7d1lPAPMchkBEvN3nVMkn5iTMUobxdLE5nR/YEU/4aYqezMuQ==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -5961,14 +5965,6 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.36.0': - resolution: {integrity: sha512-lZNihHUVB6ZZiPBNgOQGSxUASI7UJWhT8nHyUGCnaQ28XFCw98IfrMCG3rUl1uwUWoAvodJQby2KTs79UTcrAg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.36.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/eslint-plugin@8.38.0': resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5977,13 +5973,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.36.0': - resolution: {integrity: sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.38.0': resolution: {integrity: sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5991,45 +5980,22 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/project-service@8.36.0': - resolution: {integrity: sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/project-service@8.38.0': resolution: {integrity: sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/scope-manager@8.36.0': - resolution: {integrity: sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.38.0': resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.36.0': - resolution: {integrity: sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/tsconfig-utils@8.38.0': resolution: {integrity: sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.36.0': - resolution: {integrity: sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.38.0': resolution: {integrity: sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6037,33 +6003,16 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/types@8.36.0': - resolution: {integrity: sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.38.0': resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.36.0': - resolution: {integrity: sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/typescript-estree@8.38.0': resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.36.0': - resolution: {integrity: sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.38.0': resolution: {integrity: sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6071,10 +6020,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/visitor-keys@8.36.0': - resolution: {integrity: sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.38.0': resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8497,8 +8442,8 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-config-ckeditor5@12.0.0: - resolution: {integrity: sha512-7slnS3fBU1Qv+CA+haTfFF09p/ShQWMWUysSuUdeIZrLKJ+AaQvWV8R0yx+bLVC5PBRA5q9utrTix916l+2PQg==} + eslint-config-ckeditor5@12.1.0: + resolution: {integrity: sha512-lbmgyvrIEIm7MhzlFkBkegeMPhpiJzJCHw5ZNu8zhxOxVisSron0+4+enjy2CSEXmsolWk4tl4vpB5dSwID7Fg==} peerDependencies: eslint: ^9.0.0 typescript: ^5.0.0 @@ -8512,8 +8457,8 @@ packages: eslint-linter-browserify@9.31.0: resolution: {integrity: sha512-Utv/GchpL5EkPK1FcYvPjdfcYl6nEr2SaJgY4cZHRt/IVGxvojhdZQLHSC9CTpWVWt1fQ7McrzyfCCD1QxB9ow==} - eslint-plugin-ckeditor5-rules@12.0.0: - resolution: {integrity: sha512-DGQa6rYuZhSq0I8zr8iD/l7PPl3owDLIdFsvOX36uJsykO0onNtKCSSNs6jhc55WJWchqdKPtKCxNSbEAQeT6w==} + eslint-plugin-ckeditor5-rules@12.1.0: + resolution: {integrity: sha512-tu8xYJkQ9CZzS+cDsBvnaKdADJVNzGNl/4a8i7A538y/YifyAiSMCSQOeefx5Ej27bBL+Wo9WlgeuLmjiyTP+A==} eslint-plugin-mocha@11.1.0: resolution: {integrity: sha512-rKntVWRsQFPbf8OkSgVNRVRrcVAPaGTyEgWCEyXaPDJkTl0v5/lwu1vTk5sWiUJU8l2sxwvGUZzSNrEKdVMeQw==} @@ -13922,8 +13867,8 @@ packages: peerDependencies: postcss: ^8.4.32 - stylelint-config-ckeditor5@12.0.0: - resolution: {integrity: sha512-PviRRAUJ2JpKhAO4UYw6dykAFpy/DHb58wRKDDwoVf9l/mup7l1Q3AFFVQO8zYVHxVlhQXqcWrAfYCPMhX3JjQ==} + stylelint-config-ckeditor5@12.1.0: + resolution: {integrity: sha512-6JDfp60U2XNba8xmXl4K4R5ix+YM/0ZoWUbdIhVl+WNVVJG0P21jRzQjIb1QbTVE8xjS3kdc9S7kErY3ch5zgw==} peerDependencies: stylelint: '>=16.0.0' @@ -13943,8 +13888,8 @@ packages: peerDependencies: stylelint: '>=10.1.0' - stylelint-plugin-ckeditor5-rules@12.0.0: - resolution: {integrity: sha512-DDs3+MKDh4SUO63AObc3jY9NJpTrAgtbLDpgiirxh49ib40OrlzAHZxy6quJeoPxmkS/ZFU7ocVBrycFGTGRfw==} + stylelint-plugin-ckeditor5-rules@12.1.0: + resolution: {integrity: sha512-RKTrDvmVOH4vb1oLjcuIql7sq/JzbFCmkd6St5S9eDo8mvquzbjIi0fq9DT+oAhdb3dM4G+eNpniF12L68VLmw==} peerDependencies: stylelint: '>=16.0.0' @@ -14022,8 +13967,8 @@ packages: svelte: optional: true - svelte@5.36.14: - resolution: {integrity: sha512-okgNwfVa4FfDGOgd0ndooKjQz1LknUFDGfEJp6QNjYP6B4hDG0KktOP+Pta3ZtE8s+JELsYP+7nqMrJzQLkf5A==} + svelte@5.36.16: + resolution: {integrity: sha512-C7HnyISfvZEofs7T4p7+bmjrbQlhd6lZfgV2tLYg6Eb3nUFM/Zu9dGlSg+GWbUBU/WPw6zDPOFNZAx9qXsoCkg==} engines: {node: '>=18'} svg-pan-zoom@3.6.2: @@ -14432,13 +14377,6 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.36.0: - resolution: {integrity: sha512-fTCqxthY+h9QbEgSIBfL9iV6CvKDFuoxg6bHPNpJ9HIUzS+jy2lCEyCmGyZRWEBSaykqcDPf1SJ+BfCI8DRopA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - typescript-eslint@8.38.0: resolution: {integrity: sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -14708,10 +14646,6 @@ packages: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - validate-npm-package-name@6.0.1: - resolution: {integrity: sha512-OaI//3H0J7ZkR1OqlhGA8cA+Cbk/2xFOQpJOt5+s27/ta9eZwpeervh4Mxh4w0im/kdgktowaqVNR7QOrUd7Yg==} - engines: {node: ^18.17.0 || >=20.5.0} - validate-npm-package-name@6.0.2: resolution: {integrity: sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -16849,8 +16783,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-watchdog': 46.0.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-dev-build-tools@43.1.0(@swc/helpers@0.5.17)(tslib@2.8.1)(typescript@5.8.3)': dependencies: @@ -17046,6 +16978,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 46.0.0 ckeditor5: 46.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-multi-root@46.0.0': dependencies: @@ -17535,8 +17469,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 46.0.0 '@ckeditor/ckeditor5-utils': 46.0.0 ckeditor5: 46.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@46.0.0': dependencies: @@ -18600,7 +18532,7 @@ snapshots: '@eslint/markdown@6.6.0': dependencies: '@eslint/core': 0.14.0 - '@eslint/plugin-kit': 0.3.3 + '@eslint/plugin-kit': 0.3.4 github-slugger: 2.0.0 mdast-util-from-markdown: 2.0.2 mdast-util-frontmatter: 2.0.1 @@ -18617,6 +18549,11 @@ snapshots: '@eslint/core': 0.15.1 levn: 0.4.1 + '@eslint/plugin-kit@0.3.4': + dependencies: + '@eslint/core': 0.15.1 + levn: 0.4.1 + '@excalidraw/excalidraw@0.18.0(@types/react-dom@19.1.6(@types/react@19.1.7))(@types/react@19.1.7)(react-dom@19.1.0(react@16.14.0))(react@16.14.0)': dependencies: '@braintree/sanitize-url': 6.0.2 @@ -21127,12 +21064,12 @@ snapshots: '@stylistic/eslint-plugin@4.4.1(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + '@typescript-eslint/utils': 8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) eslint: 9.31.0(jiti@2.5.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 - picomatch: 4.0.2 + picomatch: 4.0.3 transitivePeerDependencies: - supports-color - typescript @@ -21153,14 +21090,14 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-auto@6.0.1(@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))': + '@sveltejs/adapter-auto@6.0.1(@sveltejs/kit@2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))': dependencies: - '@sveltejs/kit': 2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/kit': 2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) - '@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': + '@sveltejs/kit@2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': dependencies: '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 1.0.2 @@ -21172,26 +21109,26 @@ snapshots: sade: 1.8.1 set-cookie-parser: 2.7.1 sirv: 3.0.1 - svelte: 5.36.14 + svelte: 5.36.16 vite: 7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0) - '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) debug: 4.4.1(supports-color@6.0.0) - svelte: 5.36.14 + svelte: 5.36.16 vite: 7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) debug: 4.4.1(supports-color@6.0.0) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.17 - svelte: 5.36.14 + svelte: 5.36.16 vite: 7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0) vitefu: 1.1.1(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) transitivePeerDependencies: @@ -22001,23 +21938,6 @@ snapshots: '@types/node': 22.16.5 optional: true - '@typescript-eslint/eslint-plugin@8.36.0(@typescript-eslint/parser@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.36.0 - '@typescript-eslint/type-utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.36.0 - eslint: 9.31.0(jiti@2.5.0) - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -22035,18 +21955,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.36.0 - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.36.0 - debug: 4.4.1(supports-color@6.0.0) - eslint: 9.31.0(jiti@2.5.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.38.0 @@ -22059,15 +21967,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.36.0(typescript@5.8.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.36.0(typescript@5.8.3) - '@typescript-eslint/types': 8.36.0 - debug: 4.4.1(supports-color@6.0.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/project-service@8.38.0(typescript@5.8.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.8.3) @@ -22077,35 +21976,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.36.0': - dependencies: - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/visitor-keys': 8.36.0 - '@typescript-eslint/scope-manager@8.38.0': dependencies: '@typescript-eslint/types': 8.38.0 '@typescript-eslint/visitor-keys': 8.38.0 - '@typescript-eslint/tsconfig-utils@8.36.0(typescript@5.8.3)': - dependencies: - typescript: 5.8.3 - '@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.8.3)': dependencies: typescript: 5.8.3 - '@typescript-eslint/type-utils@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - debug: 4.4.1(supports-color@6.0.0) - eslint: 9.31.0(jiti@2.5.0) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/type-utils@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 8.38.0 @@ -22118,26 +21997,8 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.36.0': {} - '@typescript-eslint/types@8.38.0': {} - '@typescript-eslint/typescript-estree@8.36.0(typescript@5.8.3)': - dependencies: - '@typescript-eslint/project-service': 8.36.0(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.36.0(typescript@5.8.3) - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/visitor-keys': 8.36.0 - debug: 4.4.1(supports-color@6.0.0) - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@8.38.0(typescript@5.8.3)': dependencies: '@typescript-eslint/project-service': 8.38.0(typescript@5.8.3) @@ -22154,17 +22015,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.5.0)) - '@typescript-eslint/scope-manager': 8.36.0 - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3) - eslint: 9.31.0(jiti@2.5.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/utils@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.5.0)) @@ -22176,11 +22026,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.36.0': - dependencies: - '@typescript-eslint/types': 8.36.0 - eslint-visitor-keys: 4.2.1 - '@typescript-eslint/visitor-keys@8.38.0': dependencies: '@typescript-eslint/types': 8.38.0 @@ -25231,17 +25076,17 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-ckeditor5@12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): + eslint-config-ckeditor5@12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): dependencies: '@eslint/js': 9.31.0 '@eslint/markdown': 6.6.0 '@stylistic/eslint-plugin': 4.4.1(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) eslint: 9.31.0(jiti@2.5.0) - eslint-plugin-ckeditor5-rules: 12.0.0 + eslint-plugin-ckeditor5-rules: 12.1.0 eslint-plugin-mocha: 11.1.0(eslint@9.31.0(jiti@2.5.0)) globals: 16.3.0 typescript: 5.8.3 - typescript-eslint: 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + typescript-eslint: 8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) transitivePeerDependencies: - supports-color @@ -25251,14 +25096,14 @@ snapshots: eslint-linter-browserify@9.31.0: {} - eslint-plugin-ckeditor5-rules@12.0.0: + eslint-plugin-ckeditor5-rules@12.1.0: dependencies: '@es-joy/jsdoccomment': 0.50.2 enhanced-resolve: 5.18.2 fs-extra: 11.3.0 resolve.exports: 2.0.3 upath: 2.0.1 - validate-npm-package-name: 6.0.1 + validate-npm-package-name: 6.0.2 yaml: 2.8.0 eslint-plugin-mocha@11.1.0(eslint@9.31.0(jiti@2.5.0)): @@ -25272,7 +25117,7 @@ snapshots: eslint: 9.31.0(jiti@2.5.0) globals: 13.24.0 - eslint-plugin-svelte@3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.14)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)): + eslint-plugin-svelte@3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.16)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)): dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.5.0)) '@jridgewell/sourcemap-codec': 1.5.4 @@ -25284,9 +25129,9 @@ snapshots: postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)) postcss-safe-parser: 7.0.1(postcss@8.5.6) semver: 7.7.2 - svelte-eslint-parser: 1.3.0(svelte@5.36.14) + svelte-eslint-parser: 1.3.0(svelte@5.36.16) optionalDependencies: - svelte: 5.36.14 + svelte: 5.36.16 transitivePeerDependencies: - ts-node @@ -28110,13 +27955,13 @@ snapshots: mdn-data@2.12.2: {} - mdsvex@0.12.6(svelte@5.36.14): + mdsvex@0.12.6(svelte@5.36.16): dependencies: '@types/mdast': 4.0.4 '@types/unist': 2.0.11 prism-svelte: 0.4.7 prismjs: 1.30.0 - svelte: 5.36.14 + svelte: 5.36.16 unist-util-visit: 2.0.3 vfile-message: 2.0.4 @@ -31774,12 +31619,12 @@ snapshots: postcss: 8.5.6 postcss-selector-parser: 7.1.0 - stylelint-config-ckeditor5@12.0.0(stylelint@16.22.0(typescript@5.8.3)): + stylelint-config-ckeditor5@12.1.0(stylelint@16.22.0(typescript@5.8.3)): dependencies: '@stylistic/stylelint-plugin': 3.1.3(stylelint@16.22.0(typescript@5.8.3)) stylelint: 16.22.0(typescript@5.8.3) stylelint-config-recommended: 16.0.0(stylelint@16.22.0(typescript@5.8.3)) - stylelint-plugin-ckeditor5-rules: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + stylelint-plugin-ckeditor5-rules: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) stylelint-config-ckeditor5@2.0.1(stylelint@16.22.0(typescript@5.8.3)): dependencies: @@ -31794,7 +31639,7 @@ snapshots: dependencies: stylelint: 16.22.0(typescript@5.8.3) - stylelint-plugin-ckeditor5-rules@12.0.0(stylelint@16.22.0(typescript@5.8.3)): + stylelint-plugin-ckeditor5-rules@12.1.0(stylelint@16.22.0(typescript@5.8.3)): dependencies: stylelint: 16.22.0(typescript@5.8.3) @@ -31952,19 +31797,19 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.3.0(picomatch@4.0.3)(svelte@5.36.14)(typescript@5.8.3): + svelte-check@4.3.0(picomatch@4.0.3)(svelte@5.36.16)(typescript@5.8.3): dependencies: '@jridgewell/trace-mapping': 0.3.29 chokidar: 4.0.3 fdir: 6.4.6(picomatch@4.0.3) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.36.14 + svelte: 5.36.16 typescript: 5.8.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.3.0(svelte@5.36.14): + svelte-eslint-parser@1.3.0(svelte@5.36.16): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -31973,9 +31818,9 @@ snapshots: postcss-scss: 4.0.9(postcss@8.5.6) postcss-selector-parser: 7.1.0 optionalDependencies: - svelte: 5.36.14 + svelte: 5.36.16 - svelte@5.36.14: + svelte@5.36.16: dependencies: '@ampproject/remapping': 2.3.0 '@jridgewell/sourcemap-codec': 1.5.4 @@ -32532,16 +32377,6 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.36.0(@typescript-eslint/parser@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/parser': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - eslint: 9.31.0(jiti@2.5.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - typescript-eslint@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): dependencies: '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) @@ -32817,8 +32652,6 @@ snapshots: validate-npm-package-name@5.0.1: {} - validate-npm-package-name@6.0.1: {} - validate-npm-package-name@6.0.2: {} validator@13.15.0: {}