diff --git a/_regroup/package.json b/_regroup/package.json index b6a98a290..2875c903c 100644 --- a/_regroup/package.json +++ b/_regroup/package.json @@ -40,7 +40,7 @@ "@types/express": "5.0.5", "@types/node": "24.10.1", "@types/yargs": "17.0.35", - "@vitest/coverage-v8": "4.0.12", + "@vitest/coverage-v8": "4.0.13", "eslint": "9.39.1", "eslint-plugin-simple-import-sort": "12.1.1", "esm": "3.2.25", diff --git a/apps/client/src/components/app_context.ts b/apps/client/src/components/app_context.ts index c73fe5a42..bda3536da 100644 --- a/apps/client/src/components/app_context.ts +++ b/apps/client/src/components/app_context.ts @@ -445,6 +445,7 @@ type EventMappings = { error: string; }; searchRefreshed: { ntxId?: string | null }; + textEditorRefreshed: { ntxId?: string | null, editor: CKTextEditor }; hoistedNoteChanged: { noteId: string; ntxId: string | null; diff --git a/apps/client/src/layouts/desktop_layout.tsx b/apps/client/src/layouts/desktop_layout.tsx index 17c77f8d8..cbce8fb18 100644 --- a/apps/client/src/layouts/desktop_layout.tsx +++ b/apps/client/src/layouts/desktop_layout.tsx @@ -44,6 +44,7 @@ import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js"; import utils from "../services/utils.js"; import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js"; import NoteDetail from "../widgets/NoteDetail.jsx"; +import RightPanelWidget from "../widgets/sidebar/RightPanelWidget.jsx"; export default class DesktopLayout { diff --git a/apps/client/src/layouts/layout_commons.tsx b/apps/client/src/layouts/layout_commons.tsx index 031ef03de..62f810430 100644 --- a/apps/client/src/layouts/layout_commons.tsx +++ b/apps/client/src/layouts/layout_commons.tsx @@ -22,16 +22,8 @@ import RevisionsDialog from "../widgets/dialogs/revisions.js"; import DeleteNotesDialog from "../widgets/dialogs/delete_notes.js"; import InfoDialog from "../widgets/dialogs/info.js"; import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js"; -import PopupEditorDialog from "../widgets/dialogs/popup_editor.js"; -import FlexContainer from "../widgets/containers/flex_container.js"; -import NoteIconWidget from "../widgets/note_icon"; -import PromotedAttributesWidget from "../widgets/promoted_attributes.js"; import CallToActionDialog from "../widgets/dialogs/call_to_action.jsx"; -import NoteTitleWidget from "../widgets/note_title.jsx"; -import FormattingToolbar from "../widgets/ribbon/FormattingToolbar.js"; -import NoteList from "../widgets/collections/NoteList.jsx"; -import NoteDetail from "../widgets/NoteDetail.jsx"; -import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx"; +import PopupEditorDialog from "../widgets/dialogs/PopupEditor.jsx"; export function applyModals(rootContainer: RootContainer) { rootContainer @@ -57,16 +49,6 @@ export function applyModals(rootContainer: RootContainer) { .child() .child() .child() - .child(new PopupEditorDialog() - .child(new FlexContainer("row") - .class("title-row") - .css("align-items", "center") - .cssBlock(".title-row > * { margin: 5px; }") - .child() - .child()) - .child() - .child(new PromotedAttributesWidget()) - .child() - .child()) + .child() .child(); } diff --git a/apps/client/src/menus/context_menu.ts b/apps/client/src/menus/context_menu.ts index 4e28d7768..7096953e2 100644 --- a/apps/client/src/menus/context_menu.ts +++ b/apps/client/src/menus/context_menu.ts @@ -165,16 +165,19 @@ class ContextMenu { let $group = $parent; // The current group or parent element to which items are being appended let shouldStartNewGroup = false; // If true, the next item will start a new group let shouldResetGroup = false; // If true, the next item will be the last one from the group + let prevItemKind: string = ""; for (let index = 0; index < items.length; index++) { const item = items[index]; + const itemKind = ("kind" in item) ? item.kind : ""; + if (!item) { continue; } // If the current item is a header, start a new group. This group will contain the // header and the next item that follows the header. - if ("kind" in item && item.kind === "header") { + if (itemKind === "header") { if (multicolumn && !shouldResetGroup) { shouldStartNewGroup = true; } @@ -200,19 +203,23 @@ class ContextMenu { shouldStartNewGroup = false; } - if ("kind" in item && item.kind === "separator") { + if (itemKind === "separator") { + if (prevItemKind === "separator") { + // Skip consecutive separators + continue; + } $group.append($("
").addClass("dropdown-divider")); shouldResetGroup = true; // End the group after the next item - } else if ("kind" in item && item.kind === "header") { - $group.append($("
").addClass("dropdown-header").text(item.title)); + } else if (itemKind === "header") { + $group.append($("
").addClass("dropdown-header").text((item as MenuHeader).title)); shouldResetGroup = true; } else { - if ("kind" in item && item.kind === "custom") { + if (itemKind === "custom") { // Custom menu item - $group.append(this.createCustomMenuItem(item)); + $group.append(this.createCustomMenuItem(item as CustomMenuItem)); } else { // Standard menu item - $group.append(this.createMenuItem(item)); + $group.append(this.createMenuItem(item as MenuCommandItem)); } // After adding a menu item, if the previous item was a separator or header, @@ -222,6 +229,9 @@ class ContextMenu { shouldResetGroup = false; }; } + + prevItemKind = itemKind; + } } diff --git a/apps/client/src/menus/tree_context_menu.ts b/apps/client/src/menus/tree_context_menu.ts index 19e6f4e16..901a16559 100644 --- a/apps/client/src/menus/tree_context_menu.ts +++ b/apps/client/src/menus/tree_context_menu.ts @@ -244,16 +244,12 @@ export default class TreeContextMenu implements SelectMenuItemEventListener { - if (notOptionsOrHelp && selectedNotes.length === 1) { - return NoteColorPicker({note}); - } else { - return null; - } + return NoteColorPicker({note}); } - }, + } : null, { kind: "separator" }, diff --git a/apps/client/src/services/keyboard_actions.ts b/apps/client/src/services/keyboard_actions.ts index 5678d6196..d447a9001 100644 --- a/apps/client/src/services/keyboard_actions.ts +++ b/apps/client/src/services/keyboard_actions.ts @@ -28,7 +28,7 @@ async function getActionsForScope(scope: string) { return actions.filter((action) => action.scope === scope); } -async function setupActionsForElement(scope: string, $el: JQuery, component: Component) { +async function setupActionsForElement(scope: string, $el: JQuery, component: Component, ntxId: string | null | undefined) { if (!$el[0]) return []; const actions = await getActionsForScope(scope); @@ -36,7 +36,9 @@ async function setupActionsForElement(scope: string, $el: JQuery, c for (const action of actions) { for (const shortcut of action.effectiveShortcuts ?? []) { - const binding = shortcutService.bindElShortcut($el, shortcut, () => component.triggerCommand(action.actionName, { ntxId: appContext.tabManager.activeNtxId })); + const binding = shortcutService.bindElShortcut($el, shortcut, () => { + component.triggerCommand(action.actionName, { ntxId }); + }); if (binding) { bindings.push(binding); } diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index 9ef1c5e2d..36805a3d4 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -2591,7 +2591,7 @@ iframe.print-iframe { flex-direction: column; } -.scrolling-container > .note-detail.full-height, +.note-detail.full-height, .scrolling-container > .note-list-widget.full-height { position: relative; flex-grow: 1; diff --git a/apps/client/src/translations/cn/translation.json b/apps/client/src/translations/cn/translation.json index 8a6d19554..95e2c73a3 100644 --- a/apps/client/src/translations/cn/translation.json +++ b/apps/client/src/translations/cn/translation.json @@ -2091,5 +2091,10 @@ "auto-read-only-note": "这条笔记以只读模式显示便于快速加载。", "auto-read-only-learn-more": "了解更多", "edit-note": "编辑笔记" + }, + "note-color": { + "clear-color": "清除笔记颜色", + "set-color": "设置笔记颜色", + "set-custom-color": "设置自定义笔记颜色" } } diff --git a/apps/client/src/translations/fr/translation.json b/apps/client/src/translations/fr/translation.json index fe9e28ba9..71222b6e9 100644 --- a/apps/client/src/translations/fr/translation.json +++ b/apps/client/src/translations/fr/translation.json @@ -39,7 +39,10 @@ "help_on_tree_prefix": "Aide sur le préfixe de l'arbre", "prefix": "Préfixe : ", "save": "Sauvegarder", - "branch_prefix_saved": "Le préfixe de la branche a été enregistré." + "branch_prefix_saved": "Le préfixe de la branche a été enregistré.", + "edit_branch_prefix_multiple": "Modifier le préfixe de branche pour {{count}} branches", + "branch_prefix_saved_multiple": "Le préfixe de la branche a été sauvegardé pour {{count}} branches.", + "affected_branches": "Branches impactées ({{count}}):" }, "bulk_actions": { "bulk_actions": "Actions groupées", diff --git a/apps/client/src/translations/ja/translation.json b/apps/client/src/translations/ja/translation.json index 20b0d786c..6c9f9b924 100644 --- a/apps/client/src/translations/ja/translation.json +++ b/apps/client/src/translations/ja/translation.json @@ -1930,7 +1930,7 @@ "search-for": "「{{term}}」を検索", "create-note": "子ノート「{{term}}」を作成してリンクする", "insert-external-link": "「{{term}}」への外部リンクを挿入", - "clear-text-field": "テキストフィールドを消去", + "clear-text-field": "テキストフィールドをクリア", "show-recent-notes": "最近のノートを表示", "full-text-search": "全文検索" }, @@ -2091,5 +2091,10 @@ "auto-read-only-note": "このノートは読み込みを高速化するために読み取り専用モードで表示されています。", "auto-read-only-learn-more": "さらに詳しく", "edit-note": "ノートを編集" + }, + "note-color": { + "clear-color": "ノートの色をクリア", + "set-color": "ノートの色を設定", + "set-custom-color": "ノートの色をカスタム設定" } } diff --git a/apps/client/src/translations/tw/translation.json b/apps/client/src/translations/tw/translation.json index 767bb8ffc..6efe59822 100644 --- a/apps/client/src/translations/tw/translation.json +++ b/apps/client/src/translations/tw/translation.json @@ -2091,5 +2091,10 @@ "auto-read-only-note": "此筆記以唯讀模式顯示以加快載入速度。", "auto-read-only-learn-more": "了解更多", "edit-note": "編輯筆記" + }, + "note-color": { + "clear-color": "清除筆記顏色", + "set-color": "設定筆記顏色", + "set-custom-color": "設定自訂筆記顏色" } } diff --git a/apps/client/src/widgets/collections/NoteList.tsx b/apps/client/src/widgets/collections/NoteList.tsx index c613f8d39..1081cd6df 100644 --- a/apps/client/src/widgets/collections/NoteList.tsx +++ b/apps/client/src/widgets/collections/NoteList.tsx @@ -2,19 +2,13 @@ import { allViewTypes, ViewModeMedia, ViewModeProps, ViewTypeOptions } from "./i import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "../react/hooks"; import FNote from "../../entities/fnote"; import "./NoteList.css"; -import { ListView, GridView } from "./legacy/ListOrGridView"; import { useEffect, useRef, useState } from "preact/hooks"; -import GeoView from "./geomap"; import ViewModeStorage from "./view_mode_storage"; -import CalendarView from "./calendar"; -import TableView from "./table"; -import BoardView from "./board"; import { subscribeToMessages, unsubscribeToMessage as unsubscribeFromMessage } from "../../services/ws"; import { WebSocketMessage } from "@triliumnext/commons"; import froca from "../../services/froca"; -import PresentationView from "./presentation"; -import { ListPrintView } from "./legacy/ListPrintView"; - +import { lazy, Suspense } from "preact/compat"; +import { VNode } from "preact"; interface NoteListProps { note: FNote | null | undefined; notePath: string | null | undefined; @@ -29,6 +23,33 @@ interface NoteListProps { onProgressChanged?(progress: number): void; } +type LazyLoadedComponent = ((props: ViewModeProps) => VNode | undefined); +const ViewComponents: Record = { + list: { + normal: lazy(() => import("./legacy/ListOrGridView.js").then(i => i.ListView)), + print: lazy(() => import("./legacy/ListPrintView.js").then(i => i.ListPrintView)) + }, + grid: { + normal: lazy(() => import("./legacy/ListOrGridView.js").then(i => i.GridView)), + }, + geoMap: { + normal: lazy(() => import("./geomap/index.js")), + }, + calendar: { + normal: lazy(() => import("./calendar/index.js")) + }, + table: { + normal: lazy(() => import("./table/index.js")), + print: lazy(() => import("./table/TablePrintView.js")) + }, + board: { + normal: lazy(() => import("./board/index.js")) + }, + presentation: { + normal: lazy(() => import("./presentation/index.js")) + } +} + export default function NoteList(props: Pick) { const { note, noteContext, notePath, ntxId } = useNoteContext(); const viewType = useNoteViewType(note); @@ -93,40 +114,23 @@ export function CustomNoteList({ note, viewType, isEnabled: shouldEnable, notePa } } + const ComponentToRender = viewType && props && isEnabled && ( + props.media === "print" ? ViewComponents[viewType].print : ViewComponents[viewType].normal + ); + return (
- {props && isEnabled && ( + {ComponentToRender && props && (
- {getComponentByViewType(viewType, props)} + + +
)}
); } -function getComponentByViewType(viewType: ViewTypeOptions, props: ViewModeProps) { - switch (viewType) { - case "list": - if (props.media !== "print") { - return ; - } else { - return ; - } - case "grid": - return ; - case "geoMap": - return ; - case "calendar": - return - case "table": - return - case "board": - return - case "presentation": - return - } -} - export function useNoteViewType(note?: FNote | null): ViewTypeOptions | undefined { const [ viewType ] = useNoteLabel(note, "viewType"); diff --git a/apps/client/src/widgets/collections/board/index.css b/apps/client/src/widgets/collections/board/index.css index 8b6ab9180..28cc98a2c 100644 --- a/apps/client/src/widgets/collections/board/index.css +++ b/apps/client/src/widgets/collections/board/index.css @@ -2,6 +2,7 @@ position: relative; height: 100%; user-select: none; + overflow-x: auto; --card-font-size: 0.9em; --card-line-height: 1.2; diff --git a/apps/client/src/widgets/collections/table/TablePrintView.css b/apps/client/src/widgets/collections/table/TablePrintView.css new file mode 100644 index 000000000..fef53c299 --- /dev/null +++ b/apps/client/src/widgets/collections/table/TablePrintView.css @@ -0,0 +1,20 @@ +.table-print-view .tabulator-print-table table, +.table-print-view .tabulator-print-table th, +.table-print-view .tabulator-print-table tr, +.table-print-view .tabulator-print-table td { + border: 1px solid black; + border-collapse: collapse; +} + +.table-print-view .tabulator-print-table th { + background-color: #f0f0f0; +} + +.table-print-view .tabulator-print-table th, +.table-print-view .tabulator-print-table td { + padding: 0.25rem 0.5rem; +} + +.table-print-view .tabulator-print-table td[aria-checked] svg path { + fill: currentColor; +} \ No newline at end of file diff --git a/apps/client/src/widgets/collections/table/TablePrintView.tsx b/apps/client/src/widgets/collections/table/TablePrintView.tsx new file mode 100644 index 000000000..534ba5764 --- /dev/null +++ b/apps/client/src/widgets/collections/table/TablePrintView.tsx @@ -0,0 +1,49 @@ +import { useEffect, useRef, useState } from "preact/hooks"; +import { ViewModeProps } from "../interface"; +import useData, { TableConfig } from "./data"; +import { ExportModule, FormatModule, Tabulator as VanillaTabulator} from 'tabulator-tables'; +import Tabulator from "./tabulator"; +import { RawHtmlBlock } from "../../react/RawHtml"; +import "./TablePrintView.css"; + +export default function TablePrintView({ note, noteIds, viewConfig, onReady }: ViewModeProps) { + const tabulatorRef = useRef(null); + const { columnDefs, rowData, hasChildren } = useData(note, noteIds, viewConfig, undefined, () => {}); + const [ html, setHtml ] = useState(); + + useEffect(() => { + if (!html) return; + onReady?.(); + }, [ html ]); + + return rowData && ( + <> +

{note.title}

+ +
+ + {!html ? ( + { + const tabulator = tabulatorRef.current; + if (!tabulator) return; + setHtml(tabulator.getHtml()); + }} + /> + ) : ( + + )} +
+ + + ) +} diff --git a/apps/client/src/widgets/collections/table/data.tsx b/apps/client/src/widgets/collections/table/data.tsx new file mode 100644 index 000000000..94909939d --- /dev/null +++ b/apps/client/src/widgets/collections/table/data.tsx @@ -0,0 +1,77 @@ +import type { ColumnDefinition } from "tabulator-tables"; +import FNote from "../../../entities/fnote"; +import { useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks"; +import { useEffect, useState } from "preact/hooks"; +import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows"; +import froca from "../../../services/froca"; +import { buildColumnDefinitions } from "./columns"; +import attributes from "../../../services/attributes"; +import { RefObject } from "preact"; + +export interface TableConfig { + tableData: { + columns?: ColumnDefinition[]; + }; +} + +export default function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undefined, newAttributePosition: RefObject | undefined, resetNewAttributePosition: () => void) { + const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth"); + const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived"); + + const [ columnDefs, setColumnDefs ] = useState(); + const [ rowData, setRowData ] = useState(); + const [ hasChildren, setHasChildren ] = useState(); + const [ isSorted ] = useNoteLabelBoolean(note, "sorted"); + const [ movableRows, setMovableRows ] = useState(false); + + async function refresh() { + const info = getAttributeDefinitionInformation(note); + + // Ensure all note IDs are loaded. + await froca.getNotes(noteIds); + + const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth); + const columnDefs = buildColumnDefinitions({ + info, + movableRows, + existingColumnData: viewConfig?.tableData?.columns, + rowNumberHint: rowNumber, + position: newAttributePosition?.current ?? undefined + }); + setColumnDefs(columnDefs); + setRowData(rowData); + setHasChildren(hasChildren); + resetNewAttributePosition(); + } + + useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]); + + useTriliumEvent("entitiesReloaded", ({ loadResults}) => { + if (glob.device === "print") return; + + // React to column changes. + if (loadResults.getAttributeRows().find(attr => + attr.type === "label" && + (attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) && + attributes.isAffecting(attr, note))) { + refresh(); + return; + } + + // React to external row updates. + if (loadResults.getBranchRows().some(branch => branch.parentNoteId === note.noteId || noteIds.includes(branch.parentNoteId ?? "")) + || loadResults.getNoteIds().some(noteId => noteIds.includes(noteId)) + || loadResults.getAttributeRows().some(attr => noteIds.includes(attr.noteId!)) + || loadResults.getAttributeRows().some(attr => attr.name === "archived" && attr.noteId && noteIds.includes(attr.noteId))) { + refresh(); + return; + } + }); + + // Identify if movable rows. + useEffect(() => { + setMovableRows(!isSorted && note.type !== "search" && !hasChildren); + }, [ isSorted, note, hasChildren ]); + + return { columnDefs, rowData, movableRows, hasChildren }; +} diff --git a/apps/client/src/widgets/collections/table/index.tsx b/apps/client/src/widgets/collections/table/index.tsx index f6ae82009..d557f12d3 100644 --- a/apps/client/src/widgets/collections/table/index.tsx +++ b/apps/client/src/widgets/collections/table/index.tsx @@ -1,10 +1,9 @@ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "preact/hooks"; import { ViewModeProps } from "../interface"; -import { buildColumnDefinitions } from "./columns"; -import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows"; -import { useLegacyWidget, useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks"; +import { TableData } from "./rows"; +import { useLegacyWidget } from "../../react/hooks"; import Tabulator from "./tabulator"; -import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent} from 'tabulator-tables'; +import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, DataTreeModule, Options, RowComponent} from 'tabulator-tables'; import { useContextMenu } from "./context_menu"; import { ParentComponent } from "../../react/react_utils"; import FNote from "../../../entities/fnote"; @@ -14,16 +13,8 @@ import "./index.css"; import useRowTableEditing from "./row_editing"; import useColTableEditing from "./col_editing"; import AttributeDetailWidget from "../../attribute_widgets/attribute_detail"; -import attributes from "../../../services/attributes"; -import { RefObject } from "preact"; import SpacedUpdate from "../../../services/spaced_update"; -import froca from "../../../services/froca"; - -interface TableConfig { - tableData: { - columns?: ColumnDefinition[]; - }; -} +import useData, { TableConfig } from "./data"; export default function TableView({ note, noteIds, notePath, viewConfig, saveConfig }: ViewModeProps) { const tabulatorRef = useRef(null); @@ -118,67 +109,7 @@ function usePersistence(viewConfig: TableConfig | null | undefined, saveConfig: return () => { spacedUpdate.updateNowIfNecessary(); }; - }, [ viewConfig, saveConfig ]) + }, [ viewConfig, saveConfig ]); return persistenceProps; } - -function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undefined, newAttributePosition: RefObject, resetNewAttributePosition: () => void) { - const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1; - const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived"); - - const [ columnDefs, setColumnDefs ] = useState(); - const [ rowData, setRowData ] = useState(); - const [ hasChildren, setHasChildren ] = useState(); - const [ isSorted ] = useNoteLabelBoolean(note, "sorted"); - const [ movableRows, setMovableRows ] = useState(false); - - async function refresh() { - const info = getAttributeDefinitionInformation(note); - - // Ensure all note IDs are loaded. - await froca.getNotes(noteIds); - - const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth); - const columnDefs = buildColumnDefinitions({ - info, - movableRows, - existingColumnData: viewConfig?.tableData?.columns, - rowNumberHint: rowNumber, - position: newAttributePosition.current ?? undefined - }); - setColumnDefs(columnDefs); - setRowData(rowData); - setHasChildren(hasChildren); - resetNewAttributePosition(); - } - - useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]); - - useTriliumEvent("entitiesReloaded", ({ loadResults}) => { - // React to column changes. - if (loadResults.getAttributeRows().find(attr => - attr.type === "label" && - (attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) && - attributes.isAffecting(attr, note))) { - refresh(); - return; - } - - // React to external row updates. - if (loadResults.getBranchRows().some(branch => branch.parentNoteId === note.noteId || noteIds.includes(branch.parentNoteId ?? "")) - || loadResults.getNoteIds().some(noteId => noteIds.includes(noteId)) - || loadResults.getAttributeRows().some(attr => noteIds.includes(attr.noteId!)) - || loadResults.getAttributeRows().some(attr => attr.name === "archived" && attr.noteId && noteIds.includes(attr.noteId))) { - refresh(); - return; - } - }); - - // Identify if movable rows. - useEffect(() => { - setMovableRows(!isSorted && note.type !== "search" && !hasChildren); - }, [ isSorted, note, hasChildren ]); - - return { columnDefs, rowData, movableRows, hasChildren }; -} diff --git a/apps/client/src/widgets/collections/table/tabulator.tsx b/apps/client/src/widgets/collections/table/tabulator.tsx index 6301d5b38..31fb8d4f8 100644 --- a/apps/client/src/widgets/collections/table/tabulator.tsx +++ b/apps/client/src/widgets/collections/table/tabulator.tsx @@ -14,9 +14,10 @@ interface TableProps extends Omit; index: keyof T; footerElement?: string | HTMLElement | JSX.Element; + onReady?: () => void; } -export default function Tabulator({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, ...restProps }: TableProps) { +export default function Tabulator({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, onReady, ...restProps }: TableProps) { const parentComponent = useContext(ParentComponent); const containerRef = useRef(null); const tabulatorRef = useRef(null); @@ -43,6 +44,7 @@ export default function Tabulator({ className, columns, data, modules, tabula tabulator.on("tableBuilt", () => { tabulatorRef.current = tabulator; externalTabulatorRef.current = tabulator; + onReady?.(); }); return () => tabulator.destroy(); diff --git a/apps/client/src/widgets/containers/right_pane_container.ts b/apps/client/src/widgets/containers/right_pane_container.ts index 84875bec1..1c88f3695 100644 --- a/apps/client/src/widgets/containers/right_pane_container.ts +++ b/apps/client/src/widgets/containers/right_pane_container.ts @@ -5,6 +5,7 @@ import type { EventData, EventNames } from "../../components/app_context.js"; export default class RightPaneContainer extends FlexContainer { private rightPaneHidden: boolean; + private firstRender: boolean; constructor() { super("column"); @@ -14,6 +15,7 @@ export default class RightPaneContainer extends FlexContainer this.collapsible(); this.rightPaneHidden = false; + this.firstRender = true; } isEnabled() { @@ -41,10 +43,11 @@ export default class RightPaneContainer extends FlexContainer const oldToggle = !this.isHiddenInt(); const newToggle = this.isEnabled(); - if (oldToggle !== newToggle) { + if (oldToggle !== newToggle || this.firstRender) { this.toggleInt(newToggle); splitService.setupRightPaneResizer(); + this.firstRender = false; } } diff --git a/apps/client/src/widgets/dialogs/PopupEditor.css b/apps/client/src/widgets/dialogs/PopupEditor.css new file mode 100644 index 000000000..325d9ea47 --- /dev/null +++ b/apps/client/src/widgets/dialogs/PopupEditor.css @@ -0,0 +1,64 @@ +/** Reduce the z-index of modals so that ckeditor popups are properly shown on top of it. */ +body.popup-editor-open > .modal-backdrop { z-index: 998; } +body.popup-editor-open .popup-editor-dialog { z-index: 999; } +body.popup-editor-open .ck-clipboard-drop-target-line { z-index: 1000; } + +body.desktop .modal.popup-editor-dialog .modal-dialog { + max-width: 75vw; +} + +.modal.popup-editor-dialog .modal-header .modal-title { + font-size: 1.1em; +} + +.modal.popup-editor-dialog .modal-header .title-row { + flex-grow: 1; + display: flex; + align-items: center; +} + +.modal.popup-editor-dialog .modal-header .title-row > * { + margin: 5px; +} + +.modal.popup-editor-dialog .modal-body { + padding: 0; + height: 75vh; + overflow: auto; + display: flex; + flex-direction: column; +} + +.modal.popup-editor-dialog .note-detail-editable-text { + padding: 0 1em; +} + +.modal.popup-editor-dialog .title-row, +.modal.popup-editor-dialog .modal-title, +.modal.popup-editor-dialog .note-icon-widget { + height: 32px; +} + +.modal.popup-editor-dialog .note-icon-widget { + width: 32px; + margin: 0; + padding: 0; +} + +.modal.popup-editor-dialog .note-icon-widget button.note-icon, +.modal.popup-editor-dialog .note-title-widget input.note-title { + font-size: 1em; +} + +.modal.popup-editor-dialog .classic-toolbar-widget { + position: sticky; + top: 0; + inset-inline-start: 0; + inset-inline-end: 0; + background: var(--modal-background-color); + z-index: 998; +} + +.modal.popup-editor-dialog .note-detail-file { + padding: 0; +} \ No newline at end of file diff --git a/apps/client/src/widgets/dialogs/PopupEditor.tsx b/apps/client/src/widgets/dialogs/PopupEditor.tsx new file mode 100644 index 000000000..c2d98b544 --- /dev/null +++ b/apps/client/src/widgets/dialogs/PopupEditor.tsx @@ -0,0 +1,85 @@ +import { useContext, useEffect, useRef, useState } from "preact/hooks"; +import Modal from "../react/Modal"; +import "./PopupEditor.css"; +import { useNoteContext, useTriliumEvent } from "../react/hooks"; +import NoteTitleWidget from "../note_title"; +import NoteIcon from "../note_icon"; +import NoteContext from "../../components/note_context"; +import { NoteContextContext, ParentComponent } from "../react/react_utils"; +import NoteDetail from "../NoteDetail"; +import { ComponentChildren } from "preact"; +import NoteList from "../collections/NoteList"; +import StandaloneRibbonAdapter from "../ribbon/components/StandaloneRibbonAdapter"; +import FormattingToolbar from "../ribbon/FormattingToolbar"; + +export default function PopupEditor() { + const [ shown, setShown ] = useState(false); + const parentComponent = useContext(ParentComponent); + const [ noteContext, setNoteContext ] = useState(new NoteContext("_popup-editor")); + + useTriliumEvent("openInPopup", async ({ noteIdOrPath }) => { + const noteContext = new NoteContext("_popup-editor"); + await noteContext.setNote(noteIdOrPath, { + viewScope: { + readOnlyTemporarilyDisabled: true + } + }); + + setNoteContext(noteContext); + setShown(true); + }); + + // Add a global class to be able to handle issues with z-index due to rendering in a popup. + useEffect(() => { + document.body.classList.toggle("popup-editor-open", shown); + }, [shown]); + + return ( + + + } + className="popup-editor-dialog" + size="lg" + show={shown} + onShown={() => { + parentComponent?.handleEvent("focusOnDetail", { ntxId: noteContext.ntxId }); + }} + onHidden={() => setShown(false)} + > + + + + + + + ) +} + +export function DialogWrapper({ children }: { children: ComponentChildren }) { + const { note } = useNoteContext(); + const wrapperRef = useRef(null); + const [ hasTint, setHasTint ] = useState(false); + + // Apply the tinted-dialog class only if the custom color CSS class specifies a hue + useEffect(() => { + if (!wrapperRef.current) return; + const customHue = getComputedStyle(wrapperRef.current).getPropertyValue("--custom-color-hue"); + setHasTint(!!customHue); + }, [ note ]); + + return ( +
+ {children} +
+ ) +} + +export function TitleRow() { + return ( +
+ + +
+ ) +} diff --git a/apps/client/src/widgets/dialogs/popup_editor.ts b/apps/client/src/widgets/dialogs/popup_editor.ts deleted file mode 100644 index 80f8f5915..000000000 --- a/apps/client/src/widgets/dialogs/popup_editor.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { EventNames, EventData } from "../../components/app_context.js"; -import NoteContext from "../../components/note_context.js"; -import { openDialog } from "../../services/dialog.js"; -import BasicWidget, { ReactWrappedWidget } from "../basic_widget.js"; -import Container from "../containers/container.js"; - -const TPL = /*html*/`\ - -`; - -export default class PopupEditorDialog extends Container { - - private noteContext: NoteContext; - private $modalHeader!: JQuery; - private $modalBody!: JQuery; - private $wrapper!: JQuery; - - constructor() { - super(); - this.noteContext = new NoteContext("_popup-editor"); - } - - doRender() { - // This will populate this.$widget with the content of the children. - super.doRender(); - - // Now we wrap it in the modal. - const $newWidget = $(TPL); - this.$modalHeader = $newWidget.find(".modal-title"); - this.$modalBody = $newWidget.find(".modal-body"); - this.$wrapper = $newWidget.find(".quick-edit-dialog-wrapper"); - - const children = this.$widget.children(); - this.$modalHeader.append(children[0]); - this.$modalBody.append(children.slice(1)); - this.$widget = $newWidget; - this.setVisibility(false); - } - - async openInPopupEvent({ noteIdOrPath }: EventData<"openInPopup">) { - const $dialog = await openDialog(this.$widget, false, { - focus: false - }); - - await this.noteContext.setNote(noteIdOrPath, { - viewScope: { - readOnlyTemporarilyDisabled: true - } - }); - - const colorClass = this.noteContext.note?.getColorClass(); - const wrapperElement = this.$wrapper.get(0)!; - - if (colorClass) { - wrapperElement.className = "quick-edit-dialog-wrapper " + colorClass; - } else { - wrapperElement.className = "quick-edit-dialog-wrapper"; - } - - const customHue = getComputedStyle(wrapperElement).getPropertyValue("--custom-color-hue"); - if (customHue) { - /* Apply the tinted-dialog class only if the custom color CSS class specifies a hue */ - wrapperElement.classList.add("tinted-quick-edit-dialog"); - } - - const activeEl = document.activeElement; - if (activeEl && "blur" in activeEl) { - (activeEl as HTMLElement).blur(); - } - - $dialog.on("shown.bs.modal", async () => { - await this.handleEventInChildren("activeContextChanged", { noteContext: this.noteContext }); - this.setVisibility(true); - await this.handleEventInChildren("focusOnDetail", { ntxId: this.noteContext.ntxId }); - }); - $dialog.on("hidden.bs.modal", () => { - const $typeWidgetEl = $dialog.find(".note-detail-printable"); - if ($typeWidgetEl.length) { - const typeWidget = glob.getComponentByEl($typeWidgetEl[0]) as ReactWrappedWidget; - typeWidget.cleanup(); - } - - this.setVisibility(false); - }); - } - - setVisibility(visible: boolean) { - const $bodyItems = this.$modalBody.find("> div"); - if (visible) { - $bodyItems.fadeIn(); - this.$modalHeader.children().show(); - document.body.classList.add("popup-editor-open"); - - } else { - $bodyItems.hide(); - this.$modalHeader.children().hide(); - document.body.classList.remove("popup-editor-open"); - } - } - - handleEventInChildren(name: T, data: EventData): Promise | null { - // Avoid events related to the current tab interfere with our popup. - if (["noteSwitched", "noteSwitchedAndActivated", "exportAsPdf", "printActiveNote"].includes(name)) { - return Promise.resolve(); - } - - // Avoid not showing recent notes when creating a new empty tab. - if ("noteContext" in data && data.noteContext.ntxId !== "_popup-editor") { - return Promise.resolve(); - } - - return super.handleEventInChildren(name, data); - } - -} diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 0ee92f8af..34a7c9ed8 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -2,7 +2,7 @@ import { CSSProperties } from "preact/compat"; import { DragData } from "../note_tree"; import { FilterLabelsByType, KeyboardActionNames, OptionNames, RelationNames } from "@triliumnext/commons"; import { MutableRef, useCallback, useContext, useDebugValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks"; -import { ParentComponent, refToJQuerySelector } from "./react_utils"; +import { NoteContextContext, ParentComponent, refToJQuerySelector } from "./react_utils"; import { RefObject, VNode } from "preact"; import { Tooltip } from "bootstrap"; import { ViewMode, ViewScope } from "../../services/link"; @@ -257,18 +257,29 @@ export function useUniqueName(prefix?: string) { } export function useNoteContext() { - const [ noteContext, setNoteContext ] = useState(); + const noteContextContext = useContext(NoteContextContext); + const [ noteContext, setNoteContext ] = useState(noteContextContext ?? undefined); const [ notePath, setNotePath ] = useState(); const [ note, setNote ] = useState(); const [ , setViewScope ] = useState(); const [ isReadOnlyTemporarilyDisabled, setIsReadOnlyTemporarilyDisabled ] = useState(noteContext?.viewScope?.isReadOnly); const [ refreshCounter, setRefreshCounter ] = useState(0); + useEffect(() => { + if (!noteContextContext) return; + setNoteContext(noteContextContext); + setNote(noteContextContext.note); + setNotePath(noteContextContext.notePath); + setViewScope(noteContextContext.viewScope); + setIsReadOnlyTemporarilyDisabled(noteContextContext?.viewScope?.readOnlyTemporarilyDisabled); + }, [ noteContextContext ]); + useEffect(() => { setNote(noteContext?.note); }, [ notePath ]); useTriliumEvents([ "setNoteContext", "activeContextChanged", "noteSwitchedAndActivated", "noteSwitched" ], ({ noteContext }) => { + if (noteContextContext) return; setNoteContext(noteContext); setNotePath(noteContext.notePath); setViewScope(noteContext.viewScope); @@ -282,6 +293,7 @@ export function useNoteContext() { } }); useTriliumEvent("readOnlyTemporarilyDisabled", ({ noteContext: eventNoteContext }) => { + if (noteContextContext) return; if (eventNoteContext.ntxId === noteContext?.ntxId) { setIsReadOnlyTemporarilyDisabled(eventNoteContext?.viewScope?.readOnlyTemporarilyDisabled); } @@ -760,18 +772,18 @@ export function useResizeObserver(ref: RefObject, callback: () => v }, [ callback, ref ]); } -export function useKeyboardShortcuts(scope: "code-detail" | "text-detail", containerRef: RefObject, parentComponent: Component | undefined) { +export function useKeyboardShortcuts(scope: "code-detail" | "text-detail", containerRef: RefObject, parentComponent: Component | undefined, ntxId: string | null | undefined) { useEffect(() => { if (!parentComponent) return; const $container = refToJQuerySelector(containerRef); - const bindingPromise = keyboard_actions.setupActionsForElement(scope, $container, parentComponent); + const bindingPromise = keyboard_actions.setupActionsForElement(scope, $container, parentComponent, ntxId); return async () => { const bindings = await bindingPromise; for (const binding of bindings) { removeIndividualBinding(binding); } } - }, []); + }, [ scope, containerRef, parentComponent, ntxId ]); } /** diff --git a/apps/client/src/widgets/react/react_utils.tsx b/apps/client/src/widgets/react/react_utils.tsx index d752662f5..468a0e73e 100644 --- a/apps/client/src/widgets/react/react_utils.tsx +++ b/apps/client/src/widgets/react/react_utils.tsx @@ -1,8 +1,11 @@ import { ComponentChild, createContext, render, type JSX, type RefObject } from "preact"; import Component from "../../components/component"; +import NoteContext from "../../components/note_context"; export const ParentComponent = createContext(null); +export const NoteContextContext = createContext(null); + /** * Takes in a React ref and returns a corresponding JQuery selector. * diff --git a/apps/client/src/widgets/ribbon/FormattingToolbar.tsx b/apps/client/src/widgets/ribbon/FormattingToolbar.tsx index 8828b15ee..47963b2bf 100644 --- a/apps/client/src/widgets/ribbon/FormattingToolbar.tsx +++ b/apps/client/src/widgets/ribbon/FormattingToolbar.tsx @@ -1,4 +1,5 @@ -import { useTriliumOption } from "../react/hooks"; +import { useRef } from "preact/hooks"; +import { useTriliumEvent, useTriliumOption } from "../react/hooks"; import { TabContext } from "./ribbon-interface"; /** @@ -9,11 +10,28 @@ import { TabContext } from "./ribbon-interface"; * The ribbon item is active by default for text notes, as long as they are not in read-only mode. * * ! The toolbar is not only used in the ribbon, but also in the quick edit feature. + * * The mobile toolbar is handled separately (see `MobileEditorToolbar`). */ -export default function FormattingToolbar({ hidden }: TabContext) { +export default function FormattingToolbar({ hidden, ntxId }: TabContext) { + const containerRef = useRef(null); const [ textNoteEditorType ] = useTriliumOption("textNoteEditorType"); + // Attach the toolbar from the CKEditor. + useTriliumEvent("textEditorRefreshed", ({ ntxId: eventNtxId, editor }) => { + if (eventNtxId !== ntxId || !containerRef.current) return; + const toolbar = editor.ui.view.toolbar?.element; + + if (toolbar) { + containerRef.current.replaceChildren(toolbar); + } else { + containerRef.current.replaceChildren(); + } + }); + return (textNoteEditorType === "ckeditor-classic" && -
+
) }; diff --git a/apps/client/src/widgets/ribbon/NoteActions.tsx b/apps/client/src/widgets/ribbon/NoteActions.tsx index d7e344dd8..33017221b 100644 --- a/apps/client/src/widgets/ribbon/NoteActions.tsx +++ b/apps/client/src/widgets/ribbon/NoteActions.tsx @@ -49,7 +49,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not const canBeConvertedToAttachment = note?.isEligibleForConversionToAttachment(); const isSearchable = ["text", "code", "book", "mindMap", "doc"].includes(note.type); const isInOptionsOrHelp = note?.noteId.startsWith("_options") || note?.noteId.startsWith("_help"); - const isPrintable = ["text", "code"].includes(note.type) || (note.type === "book" && ["presentation", "list"].includes(note.getLabelValue("viewType") ?? "")); + const isPrintable = ["text", "code"].includes(note.type) || (note.type === "book" && ["presentation", "list", "table"].includes(note.getLabelValue("viewType") ?? "")); const isElectron = getIsElectron(); const isMac = getIsMac(); const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap", "aiChat"].includes(note.type); diff --git a/apps/client/src/widgets/sidebar/RightPanelWidget.tsx b/apps/client/src/widgets/sidebar/RightPanelWidget.tsx new file mode 100644 index 000000000..94a5cf04c --- /dev/null +++ b/apps/client/src/widgets/sidebar/RightPanelWidget.tsx @@ -0,0 +1,33 @@ +import { useContext, useRef } from "preact/hooks"; +import { ParentComponent } from "../react/react_utils"; +import { ComponentChildren } from "preact"; + +interface RightPanelWidgetProps { + title: string; + children: ComponentChildren; + buttons?: ComponentChildren; +} + +export default function RightPanelWidget({ title, buttons, children }: RightPanelWidgetProps) { + const containerRef = useRef(null); + const parentComponent = useContext(ParentComponent); + + if (parentComponent) { + parentComponent.initialized = Promise.resolve(); + } + + return ( +
+
+
{title}
+
{buttons}
+
+ +
+
+ {children} +
+
+
+ ); +} diff --git a/apps/client/src/widgets/toc.ts b/apps/client/src/widgets/toc.ts index a58ea2fa7..49e311149 100644 --- a/apps/client/src/widgets/toc.ts +++ b/apps/client/src/widgets/toc.ts @@ -199,6 +199,7 @@ export default class TocWidget extends RightPanelWidget { * For document note types, we obtain the content directly from the DOM since it allows us to obtain processed data without * requesting data twice. However, when immediately navigating to a new note the new document is not yet attached to the hierarchy, * resulting in an empty TOC. The fix is to simply wait for it to pop up. + * TODO: Use a better method that is not prone to unnecessary delays and race conditions. */ setTimeout(async () => { const $contentEl = await this.noteContext?.getContentElement(); @@ -209,7 +210,7 @@ export default class TocWidget extends RightPanelWidget { } else { console.warn("Unable to get content element for doctype"); } - }, 10); + }, 250); } } diff --git a/apps/client/src/widgets/type_widgets/code/Code.tsx b/apps/client/src/widgets/type_widgets/code/Code.tsx index 0c089b9a8..02117f19f 100644 --- a/apps/client/src/widgets/type_widgets/code/Code.tsx +++ b/apps/client/src/widgets/type_widgets/code/Code.tsx @@ -100,7 +100,7 @@ export function EditableCode({ note, ntxId, noteContext, debounceUpdate, parentC } }); - useKeyboardShortcuts("code-detail", containerRef, parentComponent); + useKeyboardShortcuts("code-detail", containerRef, parentComponent, ntxId); return ( <> diff --git a/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx b/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx index 8a9e64a24..7f95bfb1b 100644 --- a/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx +++ b/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx @@ -163,7 +163,12 @@ function useResizer(containerRef: RefObject, noteId: string, svg pan: zoomInstance.getPan(), zoom: zoomInstance.getZoom() } - zoomInstance.destroy(); + try { + zoomInstance.destroy(); + } catch (e) { + // Sometimes crashes with "Matrix is not invertible" which can cause havoc such as breaking the popup editor from ever showing up again. + console.warn(e); + } }; }, [ svg ]); diff --git a/apps/client/src/widgets/type_widgets/text/CKEditorWithWatchdog.tsx b/apps/client/src/widgets/type_widgets/text/CKEditorWithWatchdog.tsx index fd6814528..e19032d46 100644 --- a/apps/client/src/widgets/type_widgets/text/CKEditorWithWatchdog.tsx +++ b/apps/client/src/widgets/type_widgets/text/CKEditorWithWatchdog.tsx @@ -20,7 +20,6 @@ export interface CKEditorApi { } interface CKEditorWithWatchdogProps extends Pick, "className" | "tabIndex"> { - content: string | undefined; contentLanguage: string | null | undefined; isClassicEditor?: boolean; watchdogRef: RefObject; @@ -35,14 +34,14 @@ interface CKEditorWithWatchdogProps extends Pick, "cla containerRef?: RefObject; } -export default function CKEditorWithWatchdog({ containerRef: externalContainerRef, content, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi, templates }: CKEditorWithWatchdogProps) { +export default function CKEditorWithWatchdog({ containerRef: externalContainerRef, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi, templates }: CKEditorWithWatchdogProps) { const containerRef = useSyncedRef(externalContainerRef, null); const watchdogRef = useRef(null); const [ uiLanguage ] = useTriliumOption("locale"); const [ editor, setEditor ] = useState(); - const { parentComponent } = useNoteContext(); + const { parentComponent, ntxId } = useNoteContext(); - useKeyboardShortcuts("text-detail", containerRef, parentComponent); + useKeyboardShortcuts("text-detail", containerRef, parentComponent, ntxId); useImperativeHandle(editorApi, () => ({ hasSelection() { @@ -185,9 +184,6 @@ export default function CKEditorWithWatchdog({ containerRef: externalContainerRe return () => watchdog.destroy(); }, [ contentLanguage, templates, uiLanguage ]); - // React to content changes. - useEffect(() => editor?.setData(content ?? ""), [ editor, content ]); - // React to notification warning callback. useEffect(() => { if (!onNotificationWarning || !editor) return; diff --git a/apps/client/src/widgets/type_widgets/text/EditableText.tsx b/apps/client/src/widgets/type_widgets/text/EditableText.tsx index 15c235f3f..828989671 100644 --- a/apps/client/src/widgets/type_widgets/text/EditableText.tsx +++ b/apps/client/src/widgets/type_widgets/text/EditableText.tsx @@ -2,12 +2,11 @@ import { useEffect, useRef, useState } from "preact/hooks"; import dialog from "../../../services/dialog"; import toast from "../../../services/toast"; import utils, { hasTouchBar, isMobile } from "../../../services/utils"; -import { useEditorSpacedUpdate, useKeyboardShortcuts, useLegacyImperativeHandlers, useNoteLabel, useTriliumEvent, useTriliumOption, useTriliumOptionBool } from "../../react/hooks"; +import { useEditorSpacedUpdate, useLegacyImperativeHandlers, useNoteLabel, useTriliumEvent, useTriliumOption, useTriliumOptionBool } from "../../react/hooks"; import { TypeWidgetProps } from "../type_widget"; import CKEditorWithWatchdog, { CKEditorApi } from "./CKEditorWithWatchdog"; import "./EditableText.css"; -import { CKTextEditor, ClassicEditor, EditorWatchdog, TemplateDefinition } from "@triliumnext/ckeditor5"; -import Component from "../../../components/component"; +import { CKTextEditor, EditorWatchdog, TemplateDefinition } from "@triliumnext/ckeditor5"; import options from "../../../services/options"; import { loadIncludedNote, refreshIncludedNote, setupImageOpening } from "./utils"; import getTemplates, { updateTemplateCache } from "./snippets.js"; @@ -27,7 +26,7 @@ import { deferred } from "@triliumnext/commons"; */ export default function EditableText({ note, parentComponent, ntxId, noteContext }: TypeWidgetProps) { const containerRef = useRef(null); - const [ content, setContent ] = useState(); + const contentRef = useRef(""); const watchdogRef = useRef(null); const editorApiRef = useRef(null); const refreshTouchBarRef = useRef<() => void>(null); @@ -55,7 +54,8 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext }; }, onContentChange(newContent) { - setContent(newContent); + contentRef.current = newContent; + watchdogRef.current?.editor?.setData(newContent); } }); const templates = useTemplates(); @@ -215,7 +215,6 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext containerRef={containerRef} className={`note-detail-editable-text-editor use-tn-links ${codeBlockWordWrap ? "word-wrap" : ""}`} tabIndex={300} - content={content} contentLanguage={language} isClassicEditor={isClassicEditor} editorApi={editorApiRef} @@ -233,12 +232,6 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext onWatchdogStateChange={onWatchdogStateChange} onChange={() => spacedUpdate.scheduleUpdate()} onEditorInitialized={(editor) => { - console.log("Editor has been initialized!", parentComponent, editor); - - if (isClassicEditor) { - setupClassicEditor(editor, parentComponent); - } - if (hasTouchBar) { const handler = () => refreshTouchBarRef.current?.(); for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) { @@ -251,6 +244,8 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext } initialized.current.resolve(); + editor.setData(contentRef.current ?? ""); + parentComponent?.triggerEvent("textEditorRefreshed", { ntxId, editor }); }} />} @@ -302,55 +297,6 @@ function onNotificationWarning(data, evt) { evt.stop(); } -function setupClassicEditor(editor: CKTextEditor, parentComponent: Component | undefined) { - if (!parentComponent) return; - const $classicToolbarWidget = findClassicToolbar(parentComponent); - - $classicToolbarWidget.empty(); - if ($classicToolbarWidget.length) { - const toolbarView = (editor as ClassicEditor).ui.view.toolbar; - if (toolbarView.element) { - $classicToolbarWidget[0].appendChild(toolbarView.element); - } - } - - if (utils.isMobile()) { - $classicToolbarWidget.addClass("visible"); - - // Reposition all dropdowns to point upwards instead of downwards. - // See https://ckeditor.com/docs/ckeditor5/latest/examples/framework/bottom-toolbar-editor.html for more info. - const toolbarView = (editor as ClassicEditor).ui.view.toolbar; - for (const item of toolbarView.items) { - if (!("panelView" in item)) continue; - - item.on("change:isOpen", () => { - if (!("isOpen" in item) || !item.isOpen) return; - - // @ts-ignore - item.panelView.position = item.panelView.position.replace("s", "n"); - }); - } - } -} - -function findClassicToolbar(parentComponent: Component): JQuery { - const $widget = $(parentComponent.$widget); - - if (!utils.isMobile()) { - const $parentSplit = $widget.parents(".note-split.type-text"); - - if ($parentSplit.length) { - // The editor is in a normal tab. - return $parentSplit.find("> .ribbon-container .classic-toolbar-widget"); - } else { - // The editor is in a popup. - return $widget.closest(".modal-body").find(".classic-toolbar-widget"); - } - } else { - return $("body").find(".classic-toolbar-widget"); - } -} - function EditableTextTouchBar({ watchdogRef, refreshTouchBarRef }: { watchdogRef: RefObject, refreshTouchBarRef: RefObject<() => void> }) { const [ headingSelectedIndex, setHeadingSelectedIndex ] = useState(); diff --git a/apps/client/src/widgets/type_widgets/text/mobile_editor_toolbar.tsx b/apps/client/src/widgets/type_widgets/text/mobile_editor_toolbar.tsx index 71965761b..4b2ac7e1c 100644 --- a/apps/client/src/widgets/type_widgets/text/mobile_editor_toolbar.tsx +++ b/apps/client/src/widgets/type_widgets/text/mobile_editor_toolbar.tsx @@ -1,7 +1,8 @@ import { MutableRef, useCallback, useEffect, useRef, useState } from "preact/hooks"; -import { useNoteContext } from "../../react/hooks"; +import { useNoteContext, useTriliumEvent } from "../../react/hooks"; import "./mobile_editor_toolbar.css"; import { isIOS } from "../../../services/utils"; +import { CKTextEditor, ClassicEditor } from "@triliumnext/ckeditor5"; /** * Handles the editing toolbar for CKEditor in mobile mode. The toolbar acts as a floating bar, with two different mechanism: @@ -10,12 +11,12 @@ import { isIOS } from "../../../services/utils"; * - On Android, the viewport change makes the keyboard resize the content area, all we have to do is to hide the tab bar and global menu (handled in the global style). */ export default function MobileEditorToolbar() { - const wrapperRef = useRef(null); - const { note, noteContext } = useNoteContext(); + const containerRef = useRef(null); + const { note, noteContext, ntxId } = useNoteContext(); const [ shouldDisplay, setShouldDisplay ] = useState(false); const [ dropdownActive, setDropdownActive ] = useState(false); - usePositioningOniOS(wrapperRef); + usePositioningOniOS(containerRef); useEffect(() => { noteContext?.isReadOnly().then(isReadOnly => { @@ -23,15 +24,28 @@ export default function MobileEditorToolbar() { }); }, [ note ]); + // Attach the toolbar from the CKEditor. + useTriliumEvent("textEditorRefreshed", ({ ntxId: eventNtxId, editor }) => { + if (eventNtxId !== ntxId || !containerRef.current) return; + const toolbar = editor.ui.view.toolbar?.element; + + repositionDropdowns(editor); + if (toolbar) { + containerRef.current.replaceChildren(toolbar); + } else { + containerRef.current.replaceChildren(); + } + }); + // Observe when a dropdown is expanded to apply a style that allows the dropdown to be visible, since we can't have the element both visible and the toolbar scrollable. useEffect(() => { - if (!wrapperRef.current) return; + if (!containerRef.current) return; const observer = new MutationObserver(e => { setDropdownActive(e.map((e) => (e.target as any).ariaExpanded === "true").reduce((acc, e) => acc && e)); }); - observer.observe(wrapperRef.current, { + observer.observe(containerRef.current, { attributeFilter: ["aria-expanded"], subtree: true }); @@ -41,7 +55,7 @@ export default function MobileEditorToolbar() { return (
-
+
) } @@ -50,7 +64,7 @@ function usePositioningOniOS(wrapperRef: MutableRef) { const adjustPosition = useCallback(() => { if (!wrapperRef.current) return; let bottom = window.innerHeight - (window.visualViewport?.height || 0); - wrapperRef.current.style.bottom = `${bottom}px`; + wrapperRef.current.style.bottom = `${bottom}px`; }, []); useEffect(() => { @@ -65,3 +79,22 @@ function usePositioningOniOS(wrapperRef: MutableRef) { }; }, []); } + +/** + * Reposition all dropdowns to point upwards instead of downwards. + * See https://ckeditor.com/docs/ckeditor5/latest/examples/framework/bottom-toolbar-editor.html for more info. + * @param editor + */ +function repositionDropdowns(editor: CKTextEditor) { + const toolbarView = (editor as ClassicEditor).ui.view.toolbar; + for (const item of toolbarView.items) { + if (!("panelView" in item)) continue; + + item.on("change:isOpen", () => { + if (!("isOpen" in item) || !item.isOpen) return; + + // @ts-ignore + item.panelView.position = item.panelView.position.replace("s", "n"); + }); + } +} diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 284551e29..0753e7bb3 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -23,7 +23,7 @@ }, "dependencies": { "@electron/remote": "2.1.3", - "better-sqlite3": "12.4.1", + "better-sqlite3": "12.4.6", "electron-debug": "4.1.0", "electron-dl": "4.0.0", "electron-squirrel-startup": "1.0.1", diff --git a/apps/dump-db/package.json b/apps/dump-db/package.json index 029eca464..ccbd40097 100644 --- a/apps/dump-db/package.json +++ b/apps/dump-db/package.json @@ -4,8 +4,8 @@ "description": "Standalone tool to dump contents of Trilium document.db file into a directory tree of notes", "private": true, "dependencies": { - "better-sqlite3": "12.4.1", - "mime-types": "3.0.1", + "better-sqlite3": "12.4.6", + "mime-types": "3.0.2", "sanitize-filename": "1.6.3", "tsx": "4.20.6", "yargs": "18.0.0" diff --git a/apps/edit-docs/package.json b/apps/edit-docs/package.json index af66c3623..9aa8ebe82 100644 --- a/apps/edit-docs/package.json +++ b/apps/edit-docs/package.json @@ -5,7 +5,7 @@ "description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.", "dependencies": { "archiver": "7.0.1", - "better-sqlite3": "12.4.1" + "better-sqlite3": "12.4.6" }, "devDependencies": { "@triliumnext/client": "workspace:*", diff --git a/apps/server/docker/package.json b/apps/server/docker/package.json index 73a44e831..6ed152f94 100644 --- a/apps/server/docker/package.json +++ b/apps/server/docker/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "better-sqlite3": "12.4.1" + "better-sqlite3": "12.4.6" } } \ No newline at end of file diff --git a/apps/server/package.json b/apps/server/package.json index 97038b99d..eb4494d5d 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -25,12 +25,12 @@ "docker-start-rootless-alpine": "pnpm docker-build-rootless-alpine && docker run -p 8081:8080 triliumnext-rootless-alpine" }, "dependencies": { - "better-sqlite3": "12.4.1", + "better-sqlite3": "12.4.6", "html-to-text": "9.0.5", "node-html-parser": "7.0.1" }, "devDependencies": { - "@anthropic-ai/sdk": "0.70.0", + "@anthropic-ai/sdk": "0.70.1", "@braintree/sanitize-url": "7.1.1", "@electron/remote": "2.1.3", "@preact/preset-vite": "2.10.2", @@ -86,7 +86,7 @@ "escape-html": "1.0.3", "express": "5.1.0", "express-http-proxy": "2.1.2", - "express-openid-connect": "2.19.2", + "express-openid-connect": "2.19.3", "express-rate-limit": "8.2.1", "express-session": "1.18.2", "file-uri-to-path": "2.0.0", @@ -104,7 +104,7 @@ "is-svg": "6.1.0", "jimp": "1.6.0", "marked": "17.0.1", - "mime-types": "3.0.1", + "mime-types": "3.0.2", "multer": "2.0.2", "normalize-strings": "1.1.1", "ollama": "0.6.3", diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html index 35ae5862b..744d1d5e5 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html @@ -4,6 +4,7 @@
Screenshot of the note contextual menu indicating the “Export as PDF” option.
+

Printing

This feature allows printing of notes. It works on both the desktop client, but also on the web.

@@ -59,9 +60,9 @@ class="admonition note"> orientation, size. However, there are a few Attributes to adjust some of the settings:

    -
  • To print in landscape mode instead of portrait (useful for big diagrams +
  • To print in landscape mode instead of portrait (useful for big diagrams or slides), add #printLandscape.
  • -
  • By default, the resulting PDF will be in Letter format. It is possible +
  • By default, the resulting PDF will be in Letter format. It is possible to adjust it to another page size via the #printPageSize attribute, with one of the following values: A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.
@@ -71,12 +72,11 @@ class="admonition note">

Printing multiple notes

Since v0.100.0, it is possible to print more than one note at the time - by using Collections:

+ by using Collections:

    -
  1. First create a collection.
  2. -
  3. Configure it to use List View.
  4. -
  5. Print the collection note normally.
  6. +
  7. First create a collection.
  8. +
  9. Configure it to use List View.
  10. +
  11. Print the collection note normally.

The resulting collection will contain all the children of the collection, while maintaining the hierarchy.

@@ -86,9 +86,9 @@ class="admonition note"> href="#root/_help_4TIF1oA4VQRO">Options and assigning a key combination for:

    -
  • Print Active Note +
  • Print Active Note
  • -
  • Export Active Note as PDF +
  • Export Active Note as PDF

Constraints & limitations

@@ -96,28 +96,39 @@ class="admonition note"> supported when printing, in which case the Print and Export as PDF options will be disabled.

    -
  • For Code notes: +
  • For Code notes:
      -
    • Line numbers are not printed.
    • -
    • Syntax highlighting is enabled, however a default theme (Visual Studio) +
    • Line numbers are not printed.
    • +
    • Syntax highlighting is enabled, however a default theme (Visual Studio) is enforced.
  • -
  • For Collections: +
  • For Collections, + the following are supported:
      -
    • List View is - supported, allowing to print multiple notes at once while preserving hierarchy - (similar to a book).
    • -
    • Presentation is - also supported, where each slide/subnote is displayed.
    • -
    • The rest of the collections are not supported, but we plan to add support +
    • List View, allowing + to print multiple notes at once while preserving hierarchy (similar to + a book).
    • +
    • Presentation, + where each slide/sub-note is displayed.
    • +
    • Table, where the + table is rendered in a print-friendly way. +
        +
      • Tables that are too complex (especially if they have multiple columns) + might not fit properly, however tables with a large number of rows are + supported thanks to pagination.
      • +
      • Consider printing in landscape mode, or using #printLandscape if + exporting to PDF.
      • +
      +
    • +
    • The rest of the collections are not supported, but we plan to add support for all the collection types at some point.
  • -
  • Using Custom app-wide CSS for +
  • Using Custom app-wide CSS for printing is not longer supported, due to a more stable but isolated mechanism.
      -
    • We plan to introduce a new mechanism specifically for a print CSS.
    • +
    • We plan to introduce a new mechanism specifically for a print CSS.
@@ -128,10 +139,10 @@ class="admonition note"> printing.

To do so:

    -
  • Create a CSS code note.
  • -
  • On the note being printed, apply the ~printCss relation to +
  • Create a CSS code note.
  • +
  • On the note being printed, apply the ~printCss relation to point to the newly created CSS code note.
  • -
  • To apply the CSS to multiple notes, consider using inheritable attributes or  +
  • To apply the CSS to multiple notes, consider using inheritable attributes or  Templates.
@@ -142,13 +153,12 @@ class="admonition note"> }

To remark:

    -
  • Multiple CSS notes can be add by using multiple ~printCss relations.
  • -
  • If the note pointing to the printCss doesn't have the right +
  • Multiple CSS notes can be add by using multiple ~printCss relations.
  • +
  • If the note pointing to the printCss doesn't have the right note type or mime type, it will be ignored.
  • -
  • If migrating from a previous version where Custom app-wide CSS, there's no need for @media print {  since - the style-sheet is used only for printing.
  • +
  • If migrating from a previous version where Custom app-wide CSS, there's no need for @media print {  since + the style-sheet is used only for printing.

Under the hood

Both printing and exporting as PDF use the same mechanism: a note is rendered diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html index 64c09e024..4c8a97257 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html @@ -12,22 +12,21 @@ as a single continuous document.

Interaction

    -
  • Each note can be expanded or collapsed by clicking on the arrow to the +
  • Each note can be expanded or collapsed by clicking on the arrow to the left of the title.
  • -
  • In the Ribbon, +
  • In the Ribbon, in the Collection tab there are options to expand and to collapse all notes easily.

Printing and exporting to PDF

-

Since v0.100.0, list collections can be printed or exported to PDF.

+

Since v0.100.0, list collections can be printed or exported to PDF.

A printed list collection will print all the notes in the collection, in the right order and preserving the full hierarchy.

If exported to PDF within the desktop application, there is additional functionality:

    -
  • The table of contents of the PDF will reflect the structure of the notes.
  • -
  • Reference and inline links to other notes within the same hierarchy will +
  • The table of contents of the PDF will reflect the structure of the notes.
  • +
  • Reference and inline links to other notes within the same hierarchy will be functional (will jump to the corresponding page). If a link refers to a note that is not in the printed hierarchy, it will be unlinked.
\ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html index 27437786f..e4706e317 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html @@ -1,12 +1,13 @@
    -
  • doRender must not be overridden, instead doRenderBody() has +
  • doRender must not be overridden, instead doRenderBody() has to be overridden.
      -
    • doRenderBody can optionally be async.
    • +
    • doRenderBody can optionally be async.
  • -
  • parentWidget() must be set to “rightPane”.
  • -
  • widgetTitle() getter can optionally be overriden, otherwise +
  • parentWidget() must be set to “rightPane”.
  • +
  • widgetTitle() getter can optionally be overriden, otherwise the widget will be displayed as “Untitled widget”.
const template = `<div>Hi</div>`;
 
@@ -23,12 +24,13 @@ class ToDoListWidget extends api.RightPanelWidget {
     }   
     
     async refreshWithNote(note) {
-        this.toggleInt(false);                
-        this.triggerCommand("reEvaluateRightPaneVisibility");
-        this.toggleInt(true);
-        this.triggerCommand("reEvaluateRightPaneVisibility");
+    	// Do something when the note changes.
     }
 }
 
 module.exports = new ToDoListWidget();
-

The implementation is in src/public/app/widgets/right_panel_widget.js.

\ No newline at end of file +

The implementation is in src/public/app/widgets/right_panel_widget.js.

+

Conditionally changing visibility

+

In refreshWithNote:

const visible = true;	// replace with your own visibility logic
+this.toggleInt(visible);
+this.triggerCommand("reEvaluateRightPaneVisibility");
\ No newline at end of file diff --git a/apps/server/src/services/import/mime.ts b/apps/server/src/services/import/mime.ts index 0a129ae1e..b25e98926 100644 --- a/apps/server/src/services/import/mime.ts +++ b/apps/server/src/services/import/mime.ts @@ -73,8 +73,7 @@ const EXTENSION_TO_MIME = new Map([ [".ts", "text/x-typescript"], [".excalidraw", "application/json"], [".mermaid", "text/vnd.mermaid"], - [".mmd", "text/vnd.mermaid"], - [".mp4", "video/mp4"] // https://github.com/jshttp/mime-types/issues/138 + [".mmd", "text/vnd.mermaid"] ]); /** @returns false if MIME is not detected */ diff --git a/apps/server/src/services/window.ts b/apps/server/src/services/window.ts index 626ab851f..4431226ab 100644 --- a/apps/server/src/services/window.ts +++ b/apps/server/src/services/window.ts @@ -82,7 +82,7 @@ interface ExportAsPdfOpts { electron.ipcMain.on("print-note", async (e, { notePath }: PrintOpts) => { const browserWindow = await getBrowserWindowForPrinting(e, notePath, "printing"); browserWindow.webContents.print({}, (success, failureReason) => { - if (!success) { + if (!success && failureReason !== "Print job canceled") { electron.dialog.showErrorBox(t("pdf.unable-to-print"), failureReason); } e.sender.send("print-done"); diff --git a/apps/website/package.json b/apps/website/package.json index 6f5c81858..aea8a520f 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -23,7 +23,7 @@ "typescript": "5.9.3", "user-agent-data-types": "0.4.2", "vite": "7.2.4", - "vitest": "4.0.12" + "vitest": "4.0.13" }, "eslintConfig": { "extends": "preact" diff --git a/apps/website/src/translations/fr/translation.json b/apps/website/src/translations/fr/translation.json index b464b2d71..4724c2ac5 100644 --- a/apps/website/src/translations/fr/translation.json +++ b/apps/website/src/translations/fr/translation.json @@ -51,7 +51,8 @@ "mermaid_description": "Créez des diagrammes tels que des organigrammes, des diagrammes de classes et de séquences, des diagrammes de Gantt et bien d'autres, en utilisant la syntaxe Mermaid.", "mindmap_title": "Carte mentale", "mindmap_description": "Organisez vos pensées visuellement ou faites une séance de brainstorming.", - "others_list": "et autres : <0>carte de notes, <1>carte de relations, <2>recherches enregistrées, <3>note de rendu et <4>vues Web." + "others_list": "et autres : <0>carte de notes, <1>carte de relations, <2>recherches enregistrées, <3>note de rendu et <4>vues Web.", + "title": "Plusieurs façons de représenter vos informations" }, "faq": { "database_question": "Où sont les données stockées?", @@ -168,7 +169,9 @@ "board_title": "Tableau de bord", "board_description": "Organisez vos tâches ou l'état de vos projets dans un tableau Kanban avec un moyen simple de créer de nouveaux éléments et colonnes et de modifier simplement leur état en les faisant glisser sur le tableau.", "geomap_title": "Géocarte", - "geomap_description": "Planifiez vos vacances ou marquez vos points d'intérêt directement sur une carte géographique grâce à des marqueurs personnalisables. Affichez les traces GPX enregistrées pour suivre vos itinéraires." + "geomap_description": "Planifiez vos vacances ou marquez vos points d'intérêt directement sur une carte géographique grâce à des marqueurs personnalisables. Affichez les traces GPX enregistrées pour suivre vos itinéraires.", + "title": "Collections", + "presentation_title": "Présentation" }, "download_now": { "text": "Télécharger maintenant. ", diff --git a/docs/Developer Guide/Developer Guide/Documentation.md b/docs/Developer Guide/Developer Guide/Documentation.md index b8eca125b..f891e39c9 100644 --- a/docs/Developer Guide/Developer Guide/Documentation.md +++ b/docs/Developer Guide/Developer Guide/Documentation.md @@ -1,5 +1,5 @@ # Documentation -There are multiple types of documentation for Trilium: +There are multiple types of documentation for Trilium: * The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing F1. * The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers. diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json index 7b77cb46a..9932db6be 100644 --- a/docs/User Guide/!!!meta.json +++ b/docs/User Guide/!!!meta.json @@ -4062,66 +4062,80 @@ { "type": "relation", "name": "internalLink", - "value": "4TIF1oA4VQRO", + "value": "GTwFsgaA0lCt", "isInheritable": false, "position": 40 }, { "type": "relation", "name": "internalLink", - "value": "KSZ04uQ2D1St", + "value": "mULW0Q3VojwY", "isInheritable": false, "position": 50 }, { "type": "relation", "name": "internalLink", - "value": "6f9hih2hXXZk", + "value": "4TIF1oA4VQRO", "isInheritable": false, "position": 60 }, { "type": "relation", "name": "internalLink", - "value": "GTwFsgaA0lCt", + "value": "KSZ04uQ2D1St", "isInheritable": false, "position": 70 }, { "type": "relation", "name": "internalLink", - "value": "zP3PMqaG71Ct", + "value": "6f9hih2hXXZk", "isInheritable": false, "position": 80 }, { "type": "relation", "name": "internalLink", - "value": "AlhDUqhENtH7", + "value": "zP3PMqaG71Ct", "isInheritable": false, "position": 90 }, { "type": "relation", "name": "internalLink", - "value": "bwZpz2ajCEwO", + "value": "2FvYrpmOXm29", "isInheritable": false, "position": 100 }, { "type": "relation", "name": "internalLink", - "value": "KC1HB96bqqHX", + "value": "AlhDUqhENtH7", "isInheritable": false, "position": 110 }, { "type": "relation", "name": "internalLink", - "value": "0ESUbbAxVnoK", + "value": "bwZpz2ajCEwO", "isInheritable": false, "position": 120 }, + { + "type": "relation", + "name": "internalLink", + "value": "KC1HB96bqqHX", + "isInheritable": false, + "position": 130 + }, + { + "type": "relation", + "name": "internalLink", + "value": "0ESUbbAxVnoK", + "isInheritable": false, + "position": 140 + }, { "type": "label", "name": "iconClass", @@ -4135,13 +4149,6 @@ "value": "printing-and-pdf-export", "isInheritable": false, "position": 110 - }, - { - "type": "relation", - "name": "internalLink", - "value": "mULW0Q3VojwY", - "isInheritable": false, - "position": 130 } ], "format": "markdown", @@ -10472,6 +10479,13 @@ "isInheritable": false, "position": 20 }, + { + "type": "relation", + "name": "internalLink", + "value": "NRnIZmSMc5sj", + "isInheritable": false, + "position": 30 + }, { "type": "label", "name": "iconClass", @@ -10485,13 +10499,6 @@ "value": "list", "isInheritable": false, "position": 30 - }, - { - "type": "relation", - "name": "internalLink", - "value": "NRnIZmSMc5sj", - "isInheritable": false, - "position": 40 } ], "format": "markdown", diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md index 083ad6ec7..56b0adb74 100644 --- a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md +++ b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md @@ -73,9 +73,12 @@ Not all Note Types  * For Code notes: * Line numbers are not printed. * Syntax highlighting is enabled, however a default theme (Visual Studio) is enforced. -* For Collections: - * List View is supported, allowing to print multiple notes at once while preserving hierarchy (similar to a book). - * Presentation is also supported, where each slide/subnote is displayed. +* For Collections, the following are supported: + * List View, allowing to print multiple notes at once while preserving hierarchy (similar to a book). + * Presentation, where each slide/sub-note is displayed. + * Table, where the table is rendered in a print-friendly way. + * Tables that are too complex (especially if they have multiple columns) might not fit properly, however tables with a large number of rows are supported thanks to pagination. + * Consider printing in landscape mode, or using `#printLandscape` if exporting to PDF. * The rest of the collections are not supported, but we plan to add support for all the collection types at some point. * Using Custom app-wide CSS for printing is not longer supported, due to a more stable but isolated mechanism. * We plan to introduce a new mechanism specifically for a print CSS. diff --git a/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.md index 7a8cf8cd4..e64364fc8 100644 --- a/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.md +++ b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.md @@ -20,14 +20,21 @@ class ToDoListWidget extends api.RightPanelWidget { } async refreshWithNote(note) { - this.toggleInt(false); - this.triggerCommand("reEvaluateRightPaneVisibility"); - this.toggleInt(true); - this.triggerCommand("reEvaluateRightPaneVisibility"); + // Do something when the note changes. } } module.exports = new ToDoListWidget(); ``` -The implementation is in `src/public/app/widgets/right_panel_widget.js`. \ No newline at end of file +The implementation is in `src/public/app/widgets/right_panel_widget.js`. + +## Conditionally changing visibility + +In `refreshWithNote`: + +``` +const visible = true; // replace with your own visibility logic +this.toggleInt(visible); +this.triggerCommand("reEvaluateRightPaneVisibility"); +``` \ No newline at end of file diff --git a/package.json b/package.json index c69db6253..0b68b16f1 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,9 @@ "@triliumnext/server": "workspace:*", "@types/express": "5.0.5", "@types/node": "24.10.1", - "@vitest/browser-webdriverio": "4.0.12", - "@vitest/coverage-v8": "4.0.12", - "@vitest/ui": "4.0.12", + "@vitest/browser-webdriverio": "4.0.13", + "@vitest/coverage-v8": "4.0.13", + "@vitest/ui": "4.0.13", "chalk": "5.6.2", "cross-env": "10.1.0", "dpdm": "3.14.0", @@ -68,7 +68,7 @@ "upath": "2.0.1", "vite": "7.2.4", "vite-plugin-dts": "~4.5.0", - "vitest": "4.0.12" + "vitest": "4.0.13" }, "license": "AGPL-3.0-only", "author": { diff --git a/packages/ckeditor5-admonition/package.json b/packages/ckeditor5-admonition/package.json index 0d01ce409..a0babdad9 100644 --- a/packages/ckeditor5-admonition/package.json +++ b/packages/ckeditor5-admonition/package.json @@ -26,19 +26,19 @@ "@ckeditor/ckeditor5-package-tools": "5.0.1", "@typescript-eslint/eslint-plugin": "~8.47.0", "@typescript-eslint/parser": "8.47.0", - "@vitest/browser": "4.0.12", - "@vitest/coverage-istanbul": "4.0.12", + "@vitest/browser": "4.0.13", + "@vitest/coverage-istanbul": "4.0.13", "ckeditor5": "47.2.0", "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "16.25.0", + "stylelint": "16.26.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", "vite-plugin-svgo": "~2.0.0", - "vitest": "4.0.12", + "vitest": "4.0.13", "webdriverio": "9.20.1" }, "peerDependencies": { diff --git a/packages/ckeditor5-footnotes/package.json b/packages/ckeditor5-footnotes/package.json index 974da5771..a61a8cf19 100644 --- a/packages/ckeditor5-footnotes/package.json +++ b/packages/ckeditor5-footnotes/package.json @@ -27,19 +27,19 @@ "@ckeditor/ckeditor5-package-tools": "5.0.1", "@typescript-eslint/eslint-plugin": "~8.47.0", "@typescript-eslint/parser": "8.47.0", - "@vitest/browser": "4.0.12", - "@vitest/coverage-istanbul": "4.0.12", + "@vitest/browser": "4.0.13", + "@vitest/coverage-istanbul": "4.0.13", "ckeditor5": "47.2.0", "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "16.25.0", + "stylelint": "16.26.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", "vite-plugin-svgo": "~2.0.0", - "vitest": "4.0.12", + "vitest": "4.0.13", "webdriverio": "9.20.1" }, "peerDependencies": { diff --git a/packages/ckeditor5-keyboard-marker/package.json b/packages/ckeditor5-keyboard-marker/package.json index c076f208f..1385ba605 100644 --- a/packages/ckeditor5-keyboard-marker/package.json +++ b/packages/ckeditor5-keyboard-marker/package.json @@ -29,19 +29,19 @@ "@ckeditor/ckeditor5-package-tools": "5.0.1", "@typescript-eslint/eslint-plugin": "~8.47.0", "@typescript-eslint/parser": "8.47.0", - "@vitest/browser": "4.0.12", - "@vitest/coverage-istanbul": "4.0.12", + "@vitest/browser": "4.0.13", + "@vitest/coverage-istanbul": "4.0.13", "ckeditor5": "47.2.0", "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "16.25.0", + "stylelint": "16.26.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", "vite-plugin-svgo": "~2.0.0", - "vitest": "4.0.12", + "vitest": "4.0.13", "webdriverio": "9.20.1" }, "peerDependencies": { diff --git a/packages/ckeditor5-math/package.json b/packages/ckeditor5-math/package.json index fbd21f7d1..fad4a8ae7 100644 --- a/packages/ckeditor5-math/package.json +++ b/packages/ckeditor5-math/package.json @@ -30,19 +30,19 @@ "@ckeditor/ckeditor5-package-tools": "5.0.1", "@typescript-eslint/eslint-plugin": "~8.47.0", "@typescript-eslint/parser": "8.47.0", - "@vitest/browser": "4.0.12", - "@vitest/coverage-istanbul": "4.0.12", + "@vitest/browser": "4.0.13", + "@vitest/coverage-istanbul": "4.0.13", "ckeditor5": "47.2.0", "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "16.25.0", + "stylelint": "16.26.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", "vite-plugin-svgo": "~2.0.0", - "vitest": "4.0.12", + "vitest": "4.0.13", "webdriverio": "9.20.1" }, "peerDependencies": { diff --git a/packages/ckeditor5-mermaid/package.json b/packages/ckeditor5-mermaid/package.json index 76e0e9df9..0b3b85649 100644 --- a/packages/ckeditor5-mermaid/package.json +++ b/packages/ckeditor5-mermaid/package.json @@ -29,19 +29,19 @@ "@ckeditor/ckeditor5-package-tools": "5.0.1", "@typescript-eslint/eslint-plugin": "~8.47.0", "@typescript-eslint/parser": "8.47.0", - "@vitest/browser": "4.0.12", - "@vitest/coverage-istanbul": "4.0.12", + "@vitest/browser": "4.0.13", + "@vitest/coverage-istanbul": "4.0.13", "ckeditor5": "47.2.0", "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "16.25.0", + "stylelint": "16.26.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", "vite-plugin-svgo": "~2.0.0", - "vitest": "4.0.12", + "vitest": "4.0.13", "webdriverio": "9.20.1" }, "peerDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d66f9bfa2..e52befe92 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,14 +56,14 @@ importers: specifier: 24.10.1 version: 24.10.1 '@vitest/browser-webdriverio': - specifier: 4.0.12 - version: 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)) + specifier: 4.0.13 + version: 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)) '@vitest/coverage-v8': - specifier: 4.0.12 - version: 4.0.12(@vitest/browser@4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12))(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(@vitest/browser@4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13))(vitest@4.0.13) '@vitest/ui': - specifier: 4.0.12 - version: 4.0.12(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(vitest@4.0.13) chalk: specifier: 5.6.2 version: 5.6.2 @@ -128,8 +128,8 @@ importers: specifier: ~4.5.0 version: 4.5.4(@types/node@24.10.1)(rollup@4.52.0)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) vitest: - specifier: 4.0.12 - version: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 4.0.13 + version: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) apps/build-docs: devDependencies: @@ -369,8 +369,8 @@ importers: specifier: 2.1.3 version: 2.1.3(electron@38.7.1) better-sqlite3: - specifier: 12.4.1 - version: 12.4.1 + specifier: 12.4.6 + version: 12.4.6 electron-debug: specifier: 4.1.0 version: 4.1.0 @@ -433,11 +433,11 @@ importers: apps/dump-db: dependencies: better-sqlite3: - specifier: 12.4.1 - version: 12.4.1 + specifier: 12.4.6 + version: 12.4.6 mime-types: - specifier: 3.0.1 - version: 3.0.1 + specifier: 3.0.2 + version: 3.0.2 sanitize-filename: specifier: 1.6.3 version: 1.6.3 @@ -464,8 +464,8 @@ importers: specifier: 7.0.1 version: 7.0.1 better-sqlite3: - specifier: 12.4.1 - version: 12.4.1 + specifier: 12.4.6 + version: 12.4.6 devDependencies: '@triliumnext/client': specifier: workspace:* @@ -489,8 +489,8 @@ importers: apps/server: dependencies: better-sqlite3: - specifier: 12.4.1 - version: 12.4.1 + specifier: 12.4.6 + version: 12.4.6 html-to-text: specifier: 9.0.5 version: 9.0.5 @@ -499,8 +499,8 @@ importers: version: 7.0.1 devDependencies: '@anthropic-ai/sdk': - specifier: 0.70.0 - version: 0.70.0(zod@4.1.12) + specifier: 0.70.1 + version: 0.70.1(zod@4.1.12) '@braintree/sanitize-url': specifier: 7.1.1 version: 7.1.1 @@ -667,8 +667,8 @@ importers: specifier: 2.1.2 version: 2.1.2 express-openid-connect: - specifier: 2.19.2 - version: 2.19.2(express@5.1.0) + specifier: 2.19.3 + version: 2.19.3(express@5.1.0) express-rate-limit: specifier: 8.2.1 version: 8.2.1(express@5.1.0) @@ -721,8 +721,8 @@ importers: specifier: 17.0.1 version: 17.0.1 mime-types: - specifier: 3.0.1 - version: 3.0.1 + specifier: 3.0.2 + version: 3.0.2 multer: specifier: 2.0.2 version: 2.0.2 @@ -839,8 +839,8 @@ importers: specifier: 7.2.4 version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: - specifier: 4.0.12 - version: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 4.0.13 + version: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/ckeditor5: dependencies: @@ -894,11 +894,11 @@ importers: specifier: 8.47.0 version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': - specifier: 4.0.12 - version: 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13) '@vitest/coverage-istanbul': - specifier: 4.0.12 - version: 4.0.12(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(vitest@4.0.13) ckeditor5: specifier: 47.2.0 version: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) @@ -915,11 +915,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 16.25.0 - version: 16.25.0(typescript@5.9.3) + specifier: 16.26.0 + version: 16.26.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@16.25.0(typescript@5.9.3)) + version: 13.0.0(stylelint@16.26.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3) @@ -930,8 +930,8 @@ importers: specifier: ~2.0.0 version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) vitest: - specifier: 4.0.12 - version: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 4.0.13 + version: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) webdriverio: specifier: 9.20.1 version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -954,11 +954,11 @@ importers: specifier: 8.47.0 version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': - specifier: 4.0.12 - version: 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13) '@vitest/coverage-istanbul': - specifier: 4.0.12 - version: 4.0.12(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(vitest@4.0.13) ckeditor5: specifier: 47.2.0 version: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) @@ -975,11 +975,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 16.25.0 - version: 16.25.0(typescript@5.9.3) + specifier: 16.26.0 + version: 16.26.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@16.25.0(typescript@5.9.3)) + version: 13.0.0(stylelint@16.26.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3) @@ -990,8 +990,8 @@ importers: specifier: ~2.0.0 version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) vitest: - specifier: 4.0.12 - version: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 4.0.13 + version: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) webdriverio: specifier: 9.20.1 version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -1014,11 +1014,11 @@ importers: specifier: 8.47.0 version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': - specifier: 4.0.12 - version: 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13) '@vitest/coverage-istanbul': - specifier: 4.0.12 - version: 4.0.12(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(vitest@4.0.13) ckeditor5: specifier: 47.2.0 version: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) @@ -1035,11 +1035,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 16.25.0 - version: 16.25.0(typescript@5.9.3) + specifier: 16.26.0 + version: 16.26.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@16.25.0(typescript@5.9.3)) + version: 13.0.0(stylelint@16.26.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3) @@ -1050,8 +1050,8 @@ importers: specifier: ~2.0.0 version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) vitest: - specifier: 4.0.12 - version: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 4.0.13 + version: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) webdriverio: specifier: 9.20.1 version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -1081,11 +1081,11 @@ importers: specifier: 8.47.0 version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': - specifier: 4.0.12 - version: 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13) '@vitest/coverage-istanbul': - specifier: 4.0.12 - version: 4.0.12(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(vitest@4.0.13) ckeditor5: specifier: 47.2.0 version: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) @@ -1102,11 +1102,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 16.25.0 - version: 16.25.0(typescript@5.9.3) + specifier: 16.26.0 + version: 16.26.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@16.25.0(typescript@5.9.3)) + version: 13.0.0(stylelint@16.26.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3) @@ -1117,8 +1117,8 @@ importers: specifier: ~2.0.0 version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) vitest: - specifier: 4.0.12 - version: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 4.0.13 + version: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) webdriverio: specifier: 9.20.1 version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -1148,11 +1148,11 @@ importers: specifier: 8.47.0 version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': - specifier: 4.0.12 - version: 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13) '@vitest/coverage-istanbul': - specifier: 4.0.12 - version: 4.0.12(vitest@4.0.12) + specifier: 4.0.13 + version: 4.0.13(vitest@4.0.13) ckeditor5: specifier: 47.2.0 version: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) @@ -1169,11 +1169,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 16.25.0 - version: 16.25.0(typescript@5.9.3) + specifier: 16.26.0 + version: 16.26.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@16.25.0(typescript@5.9.3)) + version: 13.0.0(stylelint@16.26.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3) @@ -1184,8 +1184,8 @@ importers: specifier: ~2.0.0 version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) vitest: - specifier: 4.0.12 - version: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 4.0.13 + version: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) webdriverio: specifier: 9.20.1 version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) @@ -1439,8 +1439,8 @@ packages: '@antfu/utils@9.2.0': resolution: {integrity: sha512-Oq1d9BGZakE/FyoEtcNeSwM7MpDO2vUBi11RWBZXf75zPsbUVWmUs03EqkRFrcgbXyKTas0BdZWC1wcuSoqSAw==} - '@anthropic-ai/sdk@0.70.0': - resolution: {integrity: sha512-FYIuhF/lSCa+pgtaMGgsTF14aOIiWtBnu3azXITDOELv6yxsDNJwcjjt+Zr7vwyuTUjZJE/YL7s9m5r1jXkoeQ==} + '@anthropic-ai/sdk@0.70.1': + resolution: {integrity: sha512-AGEhifuvE22VxfQ5ROxViTgM8NuVQzEvqcN8bttR4AP24ythmNE/cL/SrOz79xiv7/osrsmCyErjsistJi7Z8A==} hasBin: true peerDependencies: zod: ^3.25.0 || ^4.0.0 @@ -1748,6 +1748,12 @@ packages: '@bundled-es-modules/tough-cookie@0.1.6': resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + '@cacheable/memory@2.0.5': + resolution: {integrity: sha512-fkiAxCvssEyJZ5fxX4tcdZFRmW9JehSTGvvqmXn6rTzG5cH6V/3C4ad8yb01vOjp2xBydHkHrgpW0qeGtzt6VQ==} + + '@cacheable/utils@2.3.1': + resolution: {integrity: sha512-38NJXjIr4W1Sghun8ju+uYWD8h2c61B4dKwfnQHVDFpAJ9oS28RpfqZQJ6Dgd3RceGkILDY9YT+72HJR3LoeSQ==} + '@chevrotain/cst-dts-gen@11.0.3': resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} @@ -3477,8 +3483,14 @@ packages: peerDependencies: tslib: '2' - '@keyv/serialize@1.1.0': - resolution: {integrity: sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g==} + '@keyv/bigmap@1.3.0': + resolution: {integrity: sha512-KT01GjzV6AQD5+IYrcpoYLkCu1Jod3nau1Z7EsEuViO3TZGRacSbO9MfHmbJ1WaOXFtWLxPVj169cn2WNKPkIg==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.5.4 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} '@kwsites/file-exists@1.1.1': resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} @@ -5732,36 +5744,36 @@ packages: resolution: {integrity: sha512-ir6xo6HLy3TVn4lVJ+9fOOcq8vvgMmcXoSP/mM+l1CTKKJmd0hzXqNkZ1CYyz7PiRhLPUC6fprmUuA7rnVC87g==} engines: {node: '>=16'} - '@vitest/browser-webdriverio@4.0.12': - resolution: {integrity: sha512-Z9aiTXwI9wqocxE6pnZRoC+lypbFVfOGUYGhUnlRDQx4DGYRUgWhHwQvBGiLLAOrJdWERkrcRdp+Keu9G2VdDA==} + '@vitest/browser-webdriverio@4.0.13': + resolution: {integrity: sha512-eDKpZx3Y6ciiOrO+ZVdAd2p7vwfG/amN1Sp6lkQPoGpD2kxNcgP0MpfoV0gE9p6WAauyuwEH6lO64cmivRu6Pw==} peerDependencies: - vitest: 4.0.12 + vitest: 4.0.13 webdriverio: '*' - '@vitest/browser@4.0.12': - resolution: {integrity: sha512-8zE2ksJ7V4B7Mc++L6rBRZOZHnE/f9URvj7oLYKIS5wcDaSi6EhfalN0EG6+R/OlTYZarbK6RqmhKDLYNC9KfQ==} + '@vitest/browser@4.0.13': + resolution: {integrity: sha512-lruSgrYPVAJzKmX6EJYCg9nY+0A4VkeTLpTzf1jRD/XMjNbzD9yy7D499xmVKglwJczANYJXBvZSPGcRlon+0w==} peerDependencies: - vitest: 4.0.12 + vitest: 4.0.13 - '@vitest/coverage-istanbul@4.0.12': - resolution: {integrity: sha512-2cdoONLhTCxAxbQmjeiguupFSSyVSMKWXmPOAffUGzAnH3uPMigX5Mf2F8fUuciKo0WxM6vdSucA9K7qxRTFwA==} + '@vitest/coverage-istanbul@4.0.13': + resolution: {integrity: sha512-bkoHarZBdrLDMLEQV3AJ+wcD3cETOLCjZrKO+nA4IbIY74uPPJ2pT7CEvdp8OF5AR5NNSYyafn6kAXTJBbDAaA==} peerDependencies: - vitest: 4.0.12 + vitest: 4.0.13 - '@vitest/coverage-v8@4.0.12': - resolution: {integrity: sha512-d+w9xAFJJz6jyJRU4BUU7MH409Ush7FWKNkxJU+jASKg6WX33YT0zc+YawMR1JesMWt9QRFQY/uAD3BTn23FaA==} + '@vitest/coverage-v8@4.0.13': + resolution: {integrity: sha512-w77N6bmtJ3CFnL/YHiYotwW/JI3oDlR3K38WEIqegRfdMSScaYxwYKB/0jSNpOTZzUjQkG8HHEz4sdWQMWpQ5g==} peerDependencies: - '@vitest/browser': 4.0.12 - vitest: 4.0.12 + '@vitest/browser': 4.0.13 + vitest: 4.0.13 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.0.12': - resolution: {integrity: sha512-is+g0w8V3/ZhRNrRizrJNr8PFQKwYmctWlU4qg8zy5r9aIV5w8IxXLlfbbxJCwSpsVl2PXPTm2/zruqTqz3QSg==} + '@vitest/expect@4.0.13': + resolution: {integrity: sha512-zYtcnNIBm6yS7Gpr7nFTmq8ncowlMdOJkWLqYvhr/zweY6tFbDkDi8BPPOeHxEtK1rSI69H7Fd4+1sqvEGli6w==} - '@vitest/mocker@4.0.12': - resolution: {integrity: sha512-GsmA/tD5Ht3RUFoz41mZsMU1AXch3lhmgbTnoSPTdH231g7S3ytNN1aU0bZDSyxWs8WA7KDyMPD5L4q6V6vj9w==} + '@vitest/mocker@4.0.13': + resolution: {integrity: sha512-eNCwzrI5djoauklwP1fuslHBjrbR8rqIVbvNlAnkq1OTa6XT+lX68mrtPirNM9TnR69XUPt4puBCx2Wexseylg==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -5771,25 +5783,25 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.12': - resolution: {integrity: sha512-R7nMAcnienG17MvRN8TPMJiCG8rrZJblV9mhT7oMFdBXvS0x+QD6S1G4DxFusR2E0QIS73f7DqSR1n87rrmE+g==} + '@vitest/pretty-format@4.0.13': + resolution: {integrity: sha512-ooqfze8URWbI2ozOeLDMh8YZxWDpGXoeY3VOgcDnsUxN0jPyPWSUvjPQWqDGCBks+opWlN1E4oP1UYl3C/2EQA==} - '@vitest/runner@4.0.12': - resolution: {integrity: sha512-hDlCIJWuwlcLumfukPsNfPDOJokTv79hnOlf11V+n7E14rHNPz0Sp/BO6h8sh9qw4/UjZiKyYpVxK2ZNi+3ceQ==} + '@vitest/runner@4.0.13': + resolution: {integrity: sha512-9IKlAru58wcVaWy7hz6qWPb2QzJTKt+IOVKjAx5vb5rzEFPTL6H4/R9BMvjZ2ppkxKgTrFONEJFtzvnyEpiT+A==} - '@vitest/snapshot@4.0.12': - resolution: {integrity: sha512-2jz9zAuBDUSbnfyixnyOd1S2YDBrZO23rt1bicAb6MA/ya5rHdKFRikPIDpBj/Dwvh6cbImDmudegnDAkHvmRQ==} + '@vitest/snapshot@4.0.13': + resolution: {integrity: sha512-hb7Usvyika1huG6G6l191qu1urNPsq1iFc2hmdzQY3F5/rTgqQnwwplyf8zoYHkpt7H6rw5UfIw6i/3qf9oSxQ==} - '@vitest/spy@4.0.12': - resolution: {integrity: sha512-GZjI9PPhiOYNX8Nsyqdw7JQB+u0BptL5fSnXiottAUBHlcMzgADV58A7SLTXXQwcN1yZ6gfd1DH+2bqjuUlCzw==} + '@vitest/spy@4.0.13': + resolution: {integrity: sha512-hSu+m4se0lDV5yVIcNWqjuncrmBgwaXa2utFLIrBkQCQkt+pSwyZTPFQAZiiF/63j8jYa8uAeUZ3RSfcdWaYWw==} - '@vitest/ui@4.0.12': - resolution: {integrity: sha512-RCqeApCnbwd5IFvxk6OeKMXTvzHU/cVqY8HAW0gWk0yAO6wXwQJMKhDfDtk2ss7JCy9u7RNC3kyazwiaDhBA/g==} + '@vitest/ui@4.0.13': + resolution: {integrity: sha512-MFV6GhTflgBj194+vowTB2iLI5niMZhqiW7/NV7U4AfWbX/IAtsq4zA+gzCLyGzpsQUdJlX26hrQ1vuWShq2BQ==} peerDependencies: - vitest: 4.0.12 + vitest: 4.0.13 - '@vitest/utils@4.0.12': - resolution: {integrity: sha512-DVS/TLkLdvGvj1avRy0LSmKfrcI9MNFvNGN6ECjTUHWJdlcgPDOXhjMis5Dh7rBH62nAmSXnkPbE+DZ5YD75Rw==} + '@vitest/utils@4.0.13': + resolution: {integrity: sha512-ydozWyQ4LZuu8rLp47xFUWis5VOKMdHjXCWhs1LuJsTNKww+pTHQNK4e0assIB9K80TxFyskENL6vCu3j34EYA==} '@volar/language-core@2.4.13': resolution: {integrity: sha512-MnQJ7eKchJx5Oz+YdbqyFUk8BN6jasdJv31n/7r6/WwlOOv7qzvot6B66887l2ST3bUW4Mewml54euzpJWA6bg==} @@ -6342,9 +6354,9 @@ packages: peerDependencies: ajv: 4.11.8 - 8 - better-sqlite3@12.4.1: - resolution: {integrity: sha512-3yVdyZhklTiNrtg+4WqHpJpFDd+WHTg2oM7UcR80GqL05AOV0xEJzc6qNvFYoEtE+hRp1n9MpN6/+4yhlGkDXQ==} - engines: {node: 20.x || 22.x || 23.x || 24.x} + better-sqlite3@12.4.6: + resolution: {integrity: sha512-gaYt9yqTbQ1iOxLpJA8FPR5PiaHP+jlg8I5EX0Rs2KFwNzhBsF40KzMZS5FwelY7RG0wzaucWdqSAJM3uNCPCg==} + engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} bezier-easing@2.1.0: resolution: {integrity: sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==} @@ -6507,8 +6519,8 @@ packages: resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} engines: {node: '>=8'} - cacheable@1.10.4: - resolution: {integrity: sha512-Gd7ccIUkZ9TE2odLQVS+PDjIvQCdJKUlLdJRVvZu0aipj07Qfx+XIej7hhDrKGGoIxV5m5fT/kOJNJPQhQneRg==} + cacheable@2.2.0: + resolution: {integrity: sha512-LEJxRqfeomiiRd2t0uON6hxAtgOoWDfY3fugebbz+J3vDLO+SkdfFChQcOHTZhj9SYa9iwE9MGYNX72dKiOE4w==} call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} @@ -8196,8 +8208,8 @@ packages: resolution: {integrity: sha512-FXcAcs7Nf/hF73Mzh0WDWPwaOlsEUL/fCHW3L4wU6DH79dypsaxmbnAildCLniFs7HQuuvoiR6bjNVUvGuTb5g==} engines: {node: '>=6.0.0'} - express-openid-connect@2.19.2: - resolution: {integrity: sha512-hRRRBS+mH9hrhVcbg7+APe+dIsYB4BDLILv7QfTmM1jSDyaU9NYpTxqWourAnlud/E4Gf4Q0qCVmSJguh4BTaA==} + express-openid-connect@2.19.3: + resolution: {integrity: sha512-3XTQBa6Bzuw1GozlIQcruJ7vaWkjHaSDHTTJFuAvQwq/B42Brzn/MiVQUsxPXHnLCs/tN9Scg+G12dS2RGgT4Q==} engines: {node: ^10.19.0 || >=12.0.0 < 13 || >=13.7.0 < 14 || >= 14.2.0} peerDependencies: express: '>= 4.17.0' @@ -8317,8 +8329,8 @@ packages: fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - file-entry-cache@10.1.4: - resolution: {integrity: sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA==} + file-entry-cache@11.1.1: + resolution: {integrity: sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A==} file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} @@ -8394,8 +8406,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flat-cache@6.1.13: - resolution: {integrity: sha512-gmtS2PaUjSPa4zjObEIn4WWliKyZzYljgxODBfxugpK6q6HU9ClXzgCJ+nlcPKY9Bt090ypTOLIFWkV0jbKFjw==} + flat-cache@6.1.19: + resolution: {integrity: sha512-l/K33newPTZMTGAnnzaiqSl6NnH7Namh8jBNjrgjprWxGmZUuxx/sJNIRaijOh3n7q7ESbhNZC+pvVZMFdeU4A==} flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} @@ -8822,6 +8834,10 @@ packages: resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} engines: {node: '>= 0.4.0'} + hashery@1.2.0: + resolution: {integrity: sha512-43XJKpwle72Ik5Zpam7MuzRWyNdwwdf6XHlh8wCj2PggvWf+v/Dm5B0dxGZOmddidgeO6Ofu9As/o231Ti/9PA==} + engines: {node: '>=20'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -8901,8 +8917,8 @@ packages: hoist-non-react-statics@2.5.5: resolution: {integrity: sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==} - hookified@1.12.0: - resolution: {integrity: sha512-hMr1Y9TCLshScrBbV2QxJ9BROddxZ12MX9KsCtuGGy/3SmmN5H1PllKerrVlSotur9dlE8hmUKAOSa3WDzsZmQ==} + hookified@1.13.0: + resolution: {integrity: sha512-6sPYUY8olshgM/1LDNW4QZQN0IqgKhtl/1C8koNZBJrKLBk3AZl6chQtNwpNztvfiApHMEwMHek5rv993PRbWw==} hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -9755,8 +9771,8 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - keyv@5.5.0: - resolution: {integrity: sha512-QG7qR2tijh1ftOvClut4YKKg1iW6cx3GZsKoGyJPxHkGWK9oJhG9P3j5deP0QQOGDowBMVQFaP+Vm4NpGYvmIQ==} + keyv@5.5.4: + resolution: {integrity: sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ==} khroma@2.1.0: resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} @@ -10369,9 +10385,9 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} @@ -12261,6 +12277,10 @@ packages: pwacompat@2.0.17: resolution: {integrity: sha512-6Du7IZdIy7cHiv7AhtDy4X2QRM8IAD5DII69mt5qWibC2d15ZU8DmBG1WdZKekG11cChSu4zkSUGPF9sweOl6w==} + qified@0.5.2: + resolution: {integrity: sha512-7gJ6mxcQb9vUBOtbKm5mDevbe2uRcOEVp1g4gb/Q+oLntB3HY8eBhOYRxFI2mlDFlY1e4DOSCptzxarXRvzxCA==} + engines: {node: '>=20'} + qjobs@1.2.0: resolution: {integrity: sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==} engines: {node: '>=0.9'} @@ -13568,8 +13588,8 @@ packages: peerDependencies: stylelint: '>=16.0.0' - stylelint@16.25.0: - resolution: {integrity: sha512-Li0avYWV4nfv1zPbdnxLYBGq4z8DVZxbRgx4Kn6V+Uftz1rMoF1qiEI3oL4kgWqyYgCgs7gT5maHNZ82Gk03vQ==} + stylelint@16.26.0: + resolution: {integrity: sha512-Y/3AVBefrkqqapVYH3LBF5TSDZ1kw+0XpdKN2KchfuhMK6lQ85S4XOG4lIZLcrcS4PWBmvcY6eS2kCQFz0jukQ==} engines: {node: '>=18.12.0'} hasBin: true @@ -14245,6 +14265,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util-promisify@3.0.0: + resolution: {integrity: sha512-uWRZJMjSWt/A1J1exfqz7xiKx2kVpAHR5qIDr6WwwBMQHDoKbo2I1kQN62iA2uXHxOSVpZRDvbm8do+4ijfkNA==} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -14363,8 +14386,8 @@ packages: yaml: optional: true - vitest@4.0.12: - resolution: {integrity: sha512-pmW4GCKQ8t5Ko1jYjC3SqOr7TUKN7uHOHB/XGsAIb69eYu6d1ionGSsb5H9chmPf+WeXt0VE7jTXsB1IvWoNbw==} + vitest@4.0.13: + resolution: {integrity: sha512-QSD4I0fN6uZQfftryIXuqvqgBxTvJ3ZNkF6RWECd82YGAYAfhcppBLFXzXJHQAAhVFyYEuFTrq6h0hQqjB7jIQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: @@ -14372,10 +14395,10 @@ packages: '@opentelemetry/api': ^1.9.0 '@types/debug': ^4.1.12 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.12 - '@vitest/browser-preview': 4.0.12 - '@vitest/browser-webdriverio': 4.0.12 - '@vitest/ui': 4.0.12 + '@vitest/browser-playwright': 4.0.13 + '@vitest/browser-preview': 4.0.13 + '@vitest/browser-webdriverio': 4.0.13 + '@vitest/ui': 4.0.13 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -14910,7 +14933,7 @@ snapshots: '@antfu/utils@9.2.0': {} - '@anthropic-ai/sdk@0.70.0(zod@4.1.12)': + '@anthropic-ai/sdk@0.70.1(zod@4.1.12)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: @@ -15537,6 +15560,18 @@ snapshots: tough-cookie: 4.1.4 optional: true + '@cacheable/memory@2.0.5': + dependencies: + '@cacheable/utils': 2.3.1 + '@keyv/bigmap': 1.3.0(keyv@5.5.4) + hookified: 1.13.0 + keyv: 5.5.4 + + '@cacheable/utils@2.3.1': + dependencies: + hashery: 1.2.0 + keyv: 5.5.4 + '@chevrotain/cst-dts-gen@11.0.3': dependencies: '@chevrotain/gast': 11.0.3 @@ -16169,8 +16204,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.2.0 '@ckeditor/ckeditor5-widget': 47.2.0 ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.2.0': dependencies: @@ -16403,8 +16436,8 @@ snapshots: process: 0.11.10 raw-loader: 4.0.2(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0)) style-loader: 2.0.0(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0)) - stylelint: 16.25.0(typescript@5.0.4) - stylelint-config-ckeditor5: 2.0.1(stylelint@16.25.0(typescript@5.9.3)) + stylelint: 16.26.0(typescript@5.0.4) + stylelint-config-ckeditor5: 2.0.1(stylelint@16.26.0(typescript@5.9.3)) terser-webpack-plugin: 5.3.14(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0)(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0)) ts-loader: 9.5.4(typescript@5.0.4)(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0)) ts-node: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.0.4) @@ -16587,8 +16620,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.2.0 '@ckeditor/ckeditor5-utils': 47.2.0 ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.2.0': dependencies: @@ -18451,7 +18482,13 @@ snapshots: '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) tslib: 2.8.1 - '@keyv/serialize@1.1.0': {} + '@keyv/bigmap@1.3.0(keyv@5.5.4)': + dependencies: + hashery: 1.2.0 + hookified: 1.13.0 + keyv: 5.5.4 + + '@keyv/serialize@1.1.1': {} '@kwsites/file-exists@1.1.1': dependencies: @@ -20193,7 +20230,7 @@ snapshots: - supports-color - typescript - '@stylistic/stylelint-plugin@3.1.3(stylelint@16.25.0(typescript@5.9.3))': + '@stylistic/stylelint-plugin@3.1.3(stylelint@16.26.0(typescript@5.9.3))': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -20203,7 +20240,7 @@ snapshots: postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 style-search: 0.1.0 - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) '@swc/core-darwin-arm64@1.11.29': optional: true @@ -21076,10 +21113,10 @@ snapshots: - bufferutil - utf-8-validate - '@vitest/browser-webdriverio@4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))': + '@vitest/browser-webdriverio@4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))': dependencies: - '@vitest/browser': 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12) - vitest: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + '@vitest/browser': 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13) + vitest: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) webdriverio: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: - bufferutil @@ -21087,16 +21124,16 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12)': + '@vitest/browser@4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13)': dependencies: - '@vitest/mocker': 4.0.12(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/utils': 4.0.12 + '@vitest/mocker': 4.0.13(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/utils': 4.0.13 magic-string: 0.30.21 pixelmatch: 7.1.0 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: - bufferutil @@ -21104,7 +21141,7 @@ snapshots: - utf-8-validate - vite - '@vitest/coverage-istanbul@4.0.12(vitest@4.0.12)': + '@vitest/coverage-istanbul@4.0.13(vitest@4.0.13)': dependencies: '@istanbuljs/schema': 0.1.3 debug: 4.4.3(supports-color@6.0.0) @@ -21115,14 +21152,14 @@ snapshots: istanbul-reports: 3.2.0 magicast: 0.5.1 tinyrainbow: 3.0.3 - vitest: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.12(@vitest/browser@4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12))(vitest@4.0.12)': + '@vitest/coverage-v8@4.0.13(@vitest/browser@4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13))(vitest@4.0.13)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.12 + '@vitest/utils': 4.0.13 ast-v8-to-istanbul: 0.3.8 debug: 4.4.3(supports-color@6.0.0) istanbul-lib-coverage: 3.2.2 @@ -21132,61 +21169,61 @@ snapshots: magicast: 0.5.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) optionalDependencies: - '@vitest/browser': 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12) + '@vitest/browser': 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.12': + '@vitest/expect@4.0.13': dependencies: '@standard-schema/spec': 1.0.0 '@types/chai': 5.2.2 - '@vitest/spy': 4.0.12 - '@vitest/utils': 4.0.12 + '@vitest/spy': 4.0.13 + '@vitest/utils': 4.0.13 chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.12(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/mocker@4.0.13(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@vitest/spy': 4.0.12 + '@vitest/spy': 4.0.13 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.7.5(@types/node@24.10.1)(typescript@5.9.3) vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/pretty-format@4.0.12': + '@vitest/pretty-format@4.0.13': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.12': + '@vitest/runner@4.0.13': dependencies: - '@vitest/utils': 4.0.12 + '@vitest/utils': 4.0.13 pathe: 2.0.3 - '@vitest/snapshot@4.0.12': + '@vitest/snapshot@4.0.13': dependencies: - '@vitest/pretty-format': 4.0.12 + '@vitest/pretty-format': 4.0.13 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.12': {} + '@vitest/spy@4.0.13': {} - '@vitest/ui@4.0.12(vitest@4.0.12)': + '@vitest/ui@4.0.13(vitest@4.0.13)': dependencies: - '@vitest/utils': 4.0.12 + '@vitest/utils': 4.0.13 fflate: 0.8.2 flatted: 3.3.3 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/utils@4.0.12': + '@vitest/utils@4.0.13': dependencies: - '@vitest/pretty-format': 4.0.12 + '@vitest/pretty-format': 4.0.13 tinyrainbow: 3.0.3 '@volar/language-core@2.4.13': @@ -21389,7 +21426,7 @@ snapshots: accepts@2.0.0: dependencies: - mime-types: 3.0.1 + mime-types: 3.0.2 negotiator: 1.0.0 accessor-fn@1.5.3: {} @@ -21813,7 +21850,7 @@ snapshots: jsonpointer: 5.0.1 leven: 3.1.0 - better-sqlite3@12.4.1: + better-sqlite3@12.4.6: dependencies: bindings: 1.5.0 prebuild-install: 7.1.3 @@ -22079,10 +22116,13 @@ snapshots: normalize-url: 6.1.0 responselike: 2.0.1 - cacheable@1.10.4: + cacheable@2.2.0: dependencies: - hookified: 1.12.0 - keyv: 5.5.0 + '@cacheable/memory': 2.0.5 + '@cacheable/utils': 2.3.1 + hookified: 1.13.0 + keyv: 5.5.4 + qified: 0.5.2 call-bind-apply-helpers@1.0.2: dependencies: @@ -24356,7 +24396,7 @@ snapshots: transitivePeerDependencies: - supports-color - express-openid-connect@2.19.2(express@5.1.0): + express-openid-connect@2.19.3(express@5.1.0): dependencies: base64url: 3.0.1 clone: 2.1.2 @@ -24370,6 +24410,7 @@ snapshots: on-headers: 1.1.0 openid-client: 4.9.1 url-join: 4.0.1 + util-promisify: 3.0.0 transitivePeerDependencies: - supports-color @@ -24443,7 +24484,7 @@ snapshots: fresh: 2.0.0 http-errors: 2.0.0 merge-descriptors: 2.0.0 - mime-types: 3.0.1 + mime-types: 3.0.2 on-finished: 2.4.1 once: 1.4.0 parseurl: 1.3.3 @@ -24555,9 +24596,9 @@ snapshots: fflate@0.8.2: {} - file-entry-cache@10.1.4: + file-entry-cache@11.1.1: dependencies: - flat-cache: 6.1.13 + flat-cache: 6.1.19 file-entry-cache@8.0.0: dependencies: @@ -24664,11 +24705,11 @@ snapshots: flatted: 3.3.3 keyv: 4.5.4 - flat-cache@6.1.13: + flat-cache@6.1.19: dependencies: - cacheable: 1.10.4 + cacheable: 2.2.0 flatted: 3.3.3 - hookified: 1.12.0 + hookified: 1.13.0 flat@5.0.2: {} @@ -25171,6 +25212,10 @@ snapshots: has@1.0.4: {} + hashery@1.2.0: + dependencies: + hookified: 1.13.0 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -25310,7 +25355,7 @@ snapshots: hoist-non-react-statics@2.5.5: {} - hookified@1.12.0: {} + hookified@1.13.0: {} hosted-git-info@2.8.9: {} @@ -26243,9 +26288,9 @@ snapshots: dependencies: json-buffer: 3.0.1 - keyv@5.5.0: + keyv@5.5.4: dependencies: - '@keyv/serialize': 1.1.0 + '@keyv/serialize': 1.1.1 khroma@2.1.0: {} @@ -27139,7 +27184,7 @@ snapshots: dependencies: mime-db: 1.52.0 - mime-types@3.0.1: + mime-types@3.0.2: dependencies: mime-db: 1.54.0 @@ -29105,6 +29150,10 @@ snapshots: pwacompat@2.0.17: {} + qified@0.5.2: + dependencies: + hookified: 1.13.0 + qjobs@1.2.0: {} qs@6.13.0: @@ -29988,7 +30037,7 @@ snapshots: etag: 1.8.1 fresh: 2.0.0 http-errors: 2.0.0 - mime-types: 3.0.1 + mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 @@ -30683,31 +30732,31 @@ snapshots: postcss: 8.5.6 postcss-selector-parser: 7.1.0 - stylelint-config-ckeditor5@13.0.0(stylelint@16.25.0(typescript@5.9.3)): + stylelint-config-ckeditor5@13.0.0(stylelint@16.26.0(typescript@5.9.3)): dependencies: - '@stylistic/stylelint-plugin': 3.1.3(stylelint@16.25.0(typescript@5.9.3)) - stylelint: 16.25.0(typescript@5.9.3) - stylelint-config-recommended: 16.0.0(stylelint@16.25.0(typescript@5.9.3)) - stylelint-plugin-ckeditor5-rules: 13.0.0(stylelint@16.25.0(typescript@5.9.3)) + '@stylistic/stylelint-plugin': 3.1.3(stylelint@16.26.0(typescript@5.9.3)) + stylelint: 16.26.0(typescript@5.9.3) + stylelint-config-recommended: 16.0.0(stylelint@16.26.0(typescript@5.9.3)) + stylelint-plugin-ckeditor5-rules: 13.0.0(stylelint@16.26.0(typescript@5.9.3)) - stylelint-config-ckeditor5@2.0.1(stylelint@16.25.0(typescript@5.9.3)): + stylelint-config-ckeditor5@2.0.1(stylelint@16.26.0(typescript@5.9.3)): dependencies: - stylelint: 16.25.0(typescript@5.9.3) - stylelint-config-recommended: 3.0.0(stylelint@16.25.0(typescript@5.9.3)) + stylelint: 16.26.0(typescript@5.9.3) + stylelint-config-recommended: 3.0.0(stylelint@16.26.0(typescript@5.9.3)) - stylelint-config-recommended@16.0.0(stylelint@16.25.0(typescript@5.9.3)): + stylelint-config-recommended@16.0.0(stylelint@16.26.0(typescript@5.9.3)): dependencies: - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) - stylelint-config-recommended@3.0.0(stylelint@16.25.0(typescript@5.9.3)): + stylelint-config-recommended@3.0.0(stylelint@16.26.0(typescript@5.9.3)): dependencies: - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) - stylelint-plugin-ckeditor5-rules@13.0.0(stylelint@16.25.0(typescript@5.9.3)): + stylelint-plugin-ckeditor5-rules@13.0.0(stylelint@16.26.0(typescript@5.9.3)): dependencies: - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) - stylelint@16.25.0(typescript@5.0.4): + stylelint@16.26.0(typescript@5.0.4): dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -30722,7 +30771,7 @@ snapshots: debug: 4.4.3(supports-color@6.0.0) fast-glob: 3.3.3 fastest-levenshtein: 1.0.16 - file-entry-cache: 10.1.4 + file-entry-cache: 11.1.1 global-modules: 2.0.0 globby: 11.1.0 globjoin: 0.1.4 @@ -30751,7 +30800,7 @@ snapshots: - supports-color - typescript - stylelint@16.25.0(typescript@5.9.3): + stylelint@16.26.0(typescript@5.9.3): dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -30766,7 +30815,7 @@ snapshots: debug: 4.4.3(supports-color@6.0.0) fast-glob: 3.3.3 fastest-levenshtein: 1.0.16 - file-entry-cache: 10.1.4 + file-entry-cache: 11.1.1 global-modules: 2.0.0 globby: 11.1.0 globjoin: 0.1.4 @@ -31319,7 +31368,7 @@ snapshots: dependencies: content-type: 1.0.5 media-typer: 1.1.0 - mime-types: 3.0.1 + mime-types: 3.0.2 typed-array-buffer@1.0.3: dependencies: @@ -31602,6 +31651,10 @@ snapshots: util-deprecate@1.0.2: {} + util-promisify@3.0.0: + dependencies: + object.getownpropertydescriptors: 2.1.8 + utils-merge@1.0.1: {} uuid@11.1.0: {} @@ -31705,15 +31758,15 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vitest@4.0.12(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.12)(@vitest/ui@4.0.12)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vitest@4.0.13(@opentelemetry/api@1.9.0)(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.13)(@vitest/ui@4.0.13)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: - '@vitest/expect': 4.0.12 - '@vitest/mocker': 4.0.12(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/pretty-format': 4.0.12 - '@vitest/runner': 4.0.12 - '@vitest/snapshot': 4.0.12 - '@vitest/spy': 4.0.12 - '@vitest/utils': 4.0.12 + '@vitest/expect': 4.0.13 + '@vitest/mocker': 4.0.13(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/pretty-format': 4.0.13 + '@vitest/runner': 4.0.13 + '@vitest/snapshot': 4.0.13 + '@vitest/spy': 4.0.13 + '@vitest/utils': 4.0.13 debug: 4.4.3(supports-color@6.0.0) es-module-lexer: 1.7.0 expect-type: 1.2.2 @@ -31731,8 +31784,8 @@ snapshots: '@opentelemetry/api': 1.9.0 '@types/debug': 4.1.12 '@types/node': 24.10.1 - '@vitest/browser-webdriverio': 4.0.12(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.12)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)) - '@vitest/ui': 4.0.12(vitest@4.0.12) + '@vitest/browser-webdriverio': 4.0.13(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.13)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)) + '@vitest/ui': 4.0.13(vitest@4.0.13) happy-dom: 20.0.10 jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: @@ -31887,7 +31940,7 @@ snapshots: dependencies: colorette: 2.0.20 memfs: 4.42.0 - mime-types: 3.0.1 + mime-types: 3.0.2 on-finished: 2.4.1 range-parser: 1.2.1 schema-utils: 4.3.2