zudo-text

検索したい単語を入力

いつでも検索バーを開ける

@takazudo/app-defaults

Single source of truth for the zudotext app configuration schema, default values, and validation. Every consumer (Tauri app, scaffold tool, settings UI) imports types and defaults from this package.

Main Exports

// Types
import type {
  AppSettings,
  AppInstanceConfig,
  FramesetTree,
  HeaderLeftPin,
  PinTemplate,
  QuickAction,
  QuickActionStep,
  PinProviderPropsByProviderId,
  DeviceOverride,
  SyncSettings,
  VimSettings,
  ColorMode, // "system" | "light" | "dark" — general.colorMode (epic #5893)
} from "@takazudo/app-defaults";

// Color types re-exported from @takazudo/color-themes — see that package's docs
import type { ColorStructure, ColorSettings, ColorScheme, RampRef, Ramps, SemanticKey } from "@takazudo/color-themes";

// Default values
import {
  defaultSettings,
  defaultEditorSettings,
  defaultVimSettings,
  defaultShortcuts,
  defaultLayoutSettings,
  defaultGeneralSettings,
  defaultColorStructure,
  defaultResolvedColors,
  defaultSyncSettings,
  defaultActiveDraft,
  defaultDraftCount,
  defaultHeaderLeftPins,
  defaultFramesetTree,
  defaultDocCloudSettings,
  defaultDirectoryViewSettings,
  VIMRC_MAX_LENGTH,
  COLOR_MODES, // readonly ["system", "light", "dark"] — the colorMode option list
} from "@takazudo/app-defaults";

// Validation
import { validateSettings } from "@takazudo/app-defaults";

// Toolbar surfaces (#6566, epic #6545 topic 8)
import type { ToolbarSurfaceId, ToolbarSurfaceItem, ToolbarSurfaceDef } from "@takazudo/app-defaults";
import {
  TOOLBAR_SURFACES,
  HEADER_ACTIONS_SURFACE_BY_PROVIDER,
  isToolbarItemVisible,
  withToolbarItemVisible,
  defaultToolbarSettings,
} from "@takazudo/app-defaults";

AppSettings Type

The AppSettings interface defines the full configuration shape stored in .zudotext.settings.json:

interface AppSettings {
  general: {
    colorScheme: string;
    colorMode: ColorMode;            // "system" | "light" | "dark" — see below
    formatOnArchive: boolean;
    windowOpacity: number;           // 0.3–1.0
    displayScale: number;            // discrete steps: 0.75–2.0
    appTitle?: string | null;        // OS window title override (clamped to 64 chars)
    disableSpotlightSearch: boolean; // fall through to native OS picker when true
    showMinimap: boolean;            // minimap rail in vertical timeline layout
  };
  color: ColorStructure;  // { ramps, map } — see @takazudo/color-themes
  activeDraft: number;   // 1–99
  draftCount: number;    // 1–99
  editor: {
    vimMode: boolean;
    fontFamily: string;
    fontSize: number;
    lineHeight: number;
    paddingHorizontal: number;
    paddingVertical: number;
    typewriterScrolling: boolean;
    showStatusBar: boolean;
    markdownListIndent: boolean;
    listHangingIndent: boolean;
    showLineNumbers: boolean;
    lineNumberLeftPadding: number;   // gutter left padding, range 0–40 px
    showIndentGuides: boolean;
    indentType: "tab" | "spaces";
    indentSize: number;
    directiveCompletion: boolean;
    spellcheck: boolean;         // underlines misspelled words via the OS dictionary; macOS only
    inlineStyles: {
      italic:   { fontStyle: "normal" | "italic"; fontWeight: number };
      emphasis: { fontStyle: "normal" | "italic"; fontWeight: number };
      strong:   { fontStyle: "normal" | "italic"; fontWeight: number };
    };
  };
  vim: VimSettings;
  fontCandidates: string[];
  shortcuts: {
    // Every shortcut value is string[] — multiple keys per action are supported.
    // An empty array [] means unbound.
    toggleEditorPreview: string[];
    commandPalette: string[];
    navInbox: string[];
    navArchives: string[];
    navSearch: string[];
    navTags: string[];              // was navPins in old docs — the actual key is navTags
    equalizeLayout: string[];
    layoutResetSplit: string[];
    toggleVimMode: string[];
    openSettings: string[];
    reloadApp: string[];
    formatMarkdown: string[];
    summarizedDraftList: string[];
    toggleTodoView: string[];
    toggleMindmapView: string[];
    printPreview: string[];
    showShortcutPanel: string[];
    draft1: string[];
    // ... draft2 through draft9 (draft10 does not exist)
    newDraft: string[];
    previousDraft: string[];
    nextDraft: string[];
    splitFrameRight: string[];
    splitFrameLeft: string[];
    splitFrameTop: string[];
    splitFrameBottom: string[];
    focusFrameRight: string[];
    focusFrameLeft: string[];
    focusFrameTop: string[];
    focusFrameBottom: string[];
    kanbanMoveDown: string[];
    kanbanMoveUp: string[];
    kanbanMoveLeft: string[];
    kanbanMoveRight: string[];
    kanbanEditCard: string[];
    kanbanNewCard: string[];
    kanbanDeleteCard: string[];
    kanbanToggleNotify: string[];
    // Pile View shortcuts
    pileView: string[];
    togglePileViewDirection: string[];
    togglePileViewFullContent: string[];
    pileViewNext: string[];
    pileViewPrev: string[];
    pileViewOpenItem: string[];
    pileViewArchiveItem: string[];
    // Frame-level shortcuts (W5.5)
    frameToggleZoom: string[];
    frameCollapse: string[];
    frameClose: string[];
    frameNext: string[];
    framePrev: string[];
    frameSplitRight: string[];
    frameSplitLeft: string[];
    frameSplitTop: string[];
    frameSplitBottom: string[];
    // Open-provider shortcuts (W5.5)
    // ... and many more; see AppSettings["shortcuts"] in types.ts for the full list
  };
  pileView: {
    cardWidth: number;  // card width in pixels, range 400–800, default 400
  };
  layout: {
    sidebarPosition: "left" | "right";
    draftBarCollapsed: boolean;
  };
  sync: SyncSettings;
  /** Preferences only. Calling tokens are never settings. */
  docCloud: {
    defaultProjectSlug: string | null;
    checkpointOnEdit: boolean;
    publishNotifications: boolean;
    serverOrigin: string;
  };
  /** Retained name: now the global width of EFE's embedded tree only. */
  directoryView: { lastSidebarWidthPx: number };
  subscription: SubscriptionInfo;
  quickActions: { tiles: QuickAction[] };
  /**
   * Singleton frameset tree — the live layout for the current app window.
   * Replaces the old framesets[]/currentFramesetId pair from Frameset Arch v1.
   */
  frameset: FramesetTree;
  /**
   * Header pin entries displayed as icon buttons in the app toolbar.
   * Each pin carries a structural template installed wholesale on activation.
   */
  headerLeftPins: HeaderLeftPin[];
  /**
   * Per-leaf UI state cache, keyed by cache namespace then by leaf frameId.
   * Default: {} (empty).
   */
  framesetLeafState: Record<string, Record<string, JsonValue>>;
  /**
   * Most-recently-used ViewProvider ids for the empty-frame nav.
   * Order is most-recent-first. Default: [].
   */
  framesetRecentProviders: string[];
  /** Only docCloud.defaultProjectSlug is in the Doc Cloud override surface. */
  deviceOverrides: Record<string, DeviceOverride>;
  /**
   * Per-surface toolbar item visibility (#6566). Keyed by ToolbarSurfaceId;
   * a missing key means every item on that surface is visible. Default: {}.
   * `menu-bar-right` is excluded — its visibility lives in
   * `menuBar.rightIcons[].visible` instead. See "Toolbar Surfaces" below.
   */
  toolbars: Partial<Record<ToolbarSurfaceId, { hidden: string[] }>>;
}

Toolbar Surfaces

toolbar-surfaces.ts is the registry every toolbar/header-action surface in the app is declared in once, up front, so adoption sub-tasks never need to touch this package — they read TOOLBAR_SURFACES[surfaceId] instead.

interface ToolbarSurfaceItem {
  id: string;
  label: string;
}

interface ToolbarSurfaceDef {
  label: string;
  items: ToolbarSurfaceItem[];
  /** Present only for surfaces whose visibility lives outside `toolbars`. */
  storage?: "menuBar.rightIcons" | "noteTrayUtility.pinned";
}

const TOOLBAR_SURFACES: Record<ToolbarSurfaceId, ToolbarSurfaceDef>;

items lists only items a user may hide — anything that must never be hidden (close, a settings entry point, navigation, tabs) is simply not registered; there is no "locked" state.

HEADER_ACTIONS_SURFACE_BY_PROVIDER: Record<string, ToolbarSurfaceId> maps a ViewProvider.id ("core.kanban-board", "core.dashboard") to the *-header-actions surface its HeaderActions component renders. The Inbox mapping and the note-tray-header-actions surface were removed: History, Pile View and Find similar are Note Tray utilities now (see the next section).

menu-bar-right (storage: "menuBar.rightIcons") and note-tray-utility (storage: "noteTrayUtility.pinned") are the two storage-routed surfaces. For menu-bar-right, that block also carries display order, so it stays the sole authoritative representation and validateSettings() discards any competing toolbars["menu-bar-right"] entry.

Two pure helpers read and write visibility without callers needing to know which storage a surface actually uses:

function isToolbarItemVisible(
  settings: Pick<AppSettings, "toolbars" | "menuBar">,
  surfaceId: ToolbarSurfaceId,
  itemId: string,
): boolean;

function withToolbarItemVisible(
  settings: Pick<AppSettings, "toolbars" | "menuBar">,
  surfaceId: ToolbarSurfaceId,
  itemId: string,
  visible: boolean,
): Partial<AppSettings>;

withToolbarItemVisible returns the minimal patch: for menu-bar-right it flips visible on the matching rightIcons entry in place (never reordering); for every other surface it patches toolbars[surfaceId].hidden, dropping the surface entry entirely once nothing on it is hidden.

noteTrayUtility (Note Tray utility bar)

AppSettings.noteTrayUtility is the workspace-wide setting for the Note Tray utility bar (the Pattern 4 bar between the tray scope row and the note tabs). Its helpers live in src/note-tray-utility.ts.

interface NoteTrayUtilitySettings {
  orientation: "horizontal" | "vertical";
  showLabels: boolean;
  /** Ordered pinned action ids; [] is a valid explicit choice. */
  pinned: string[];
  /** Vertical width per label mode, in unscaled design px. */
  verticalWidth: { labels: number; icons: number };
}
FieldDefaultValidation (validateNoteTrayUtility)
orientation"horizontal"Unknown value falls back to the default
showLabelstrueNon-boolean falls back to the default
pinned["to-ai", "sticker", "preview", "pile-view"]Duplicates removed, unknown ids dropped, an explicit [] is kept
verticalWidth.labels144 (96–240, step 8)Missing, non-finite or out-of-range falls back to the mode default; in-range values snap to the 8 px step
verticalWidth.icons48 (48–160, step 8)Same rule

Exports: NOTE_TRAY_UTILITY_ACTIONS (the pinnable ids, their labels and More groups Current note / Organize / Tray), NOTE_TRAY_UTILITY_DEFAULT_PINNED, NOTE_TRAY_UTILITY_WIDTH, NOTE_TRAY_UTILITY_MIN_EDITOR_PX (160), defaultNoteTrayUtilitySettings, noteTrayUtilityWidthMode, validNoteTrayUtilityWidth, validateNoteTrayUtility, withNoteTrayUtilityPinMoved and activeNoteTrayUtilityWidth.

More and Customize are deliberately absent from NOTE_TRAY_UTILITY_ACTIONS, so they can never be unpinned. The renderer applies --display-scale once and clamps the rendered width to leave NOTE_TRAY_UTILITY_MIN_EDITOR_PX for the editor; that clamp is never written back to the setting. The bundled tauri-app/core/defaults/default-settings.json carries the same defaults.

general.colorMode

general.colorMode is a ColorMode — COLOR_MODES gives the three values as ["system", "light", "dark"] as const. It is distinct from SchemeMode (@takazudo/color-themes), which has only the resolved two-valued "light" | "dark": "system" follows the OS appearance and is resolved down to a SchemeMode at runtime by the effective-mode store, not by this package. colorScheme still names which registry scheme is active (currently always "default" — see @takazudo/color-themes); colorMode picks which of that scheme's two palettes is displayed. validateSettings() enum-validates colorMode against COLOR_MODES and falls back to the default ("system") on an unknown value. colorScheme itself is only checked for being a string here — healing an unknown scheme name (e.g. a pre-restructure default-dark/default-light) is the Settings Doctor's job, not validateSettings()'s; see Settings Doctor.

HeaderLeftPin

interface HeaderLeftPin {
  id: string;           // stable kebab-case id, e.g. "inbox-default"
  template: PinTemplate;
  label: string;        // display label and tooltip text
  iconId: string;       // Lucide icon name, e.g. "inbox", "archive"
  routeSlug: string | null; // used for /p/:slug routes; null for built-in pins
  visible: boolean;
  providerProps?: Record<string, unknown>; // known shapes catalogued by PinProviderPropsByProviderId
}

interface PinTemplate {
  tree: FramesetTree;
  activeFrameId?: string;
}

PinProviderPropsByProviderId["core.doc-cloud"] permits only projectSlug, initialSurface, editorLayout, and outlineCollapsed. Doc Cloud pins are one-leaf templates. PinProviderPropsByProviderId["core.external-file-editor"] permits initialFiles, initialTreeRoot, and treeCollapsed; the former Directory View is not a provider-props target.

QuickAction

type QuickActionStep = { commandId: string };
type QuickAction = {
  id: string;
  name: string;
  iconId: string;
  aliases: string[];
  steps: QuickActionStep[];
};

SyncSettings

interface SyncSettings {
  // Cloud sync
  cloudDeviceId: string;
  cloudDeviceName: string;
  cloudRealtimeEnabled: boolean;
}

VimSettings

interface VimSettings {
  clipboardSync: boolean;
  showModeIndicator: boolean;
  vimrc: string;
}

Default Values

Editor

SettingDefault
vimModetrue
fontFamily"JetBrains Mono"
fontSize16
lineHeight1.6
paddingHorizontal12
paddingVertical8
typewriterScrollingfalse
showStatusBartrue
markdownListIndenttrue
listHangingIndenttrue
showLineNumberstrue
lineNumberLeftPadding12
showIndentGuidestrue
indentType"spaces"
indentSize2
directiveCompletiontrue
spellcheckfalse
inlineStyles.italic{ fontStyle: "italic", fontWeight: 400 }
inlineStyles.emphasis{ fontStyle: "italic", fontWeight: 400 }
inlineStyles.strong{ fontStyle: "normal", fontWeight: 700 }

Vim

SettingDefault
clipboardSynctrue
showModeIndicatortrue
vimrc""

Shortcuts

Every shortcut value is string[]. An empty array [] means the action is unbound. Multiple key chords can be assigned to the same action — all of them trigger it.

Runtime shortcut profiles

ShortcutProfileId is either "desktop" or "web". applyShortcutProfile(base, profile, options?) returns an effective shortcut map and a provenance map without mutating base. The desktop profile is an identity copy. The web profile remaps only defaults that still match their value in defaultShortcuts; a customized base binding is left as the user set it. The workspace-synced shortcut arrays remain the base map.

Default actionBase comboWeb-profile combo
newDraftMod+NMod+Alt+Shift+N
openNotificationCenterMod+Shift+NMod+Alt+Shift+B
toggleTodoViewMod+Shift+TMod+Alt+Shift+T
previousDraft / nextDraftMod+Shift+[ / Mod+Shift+]Mod+Alt+Shift+[ / Mod+Alt+Shift+]
frameNext / framePrevCtrl+Tab / Ctrl+Shift+TabMod+Alt+Shift+. / Mod+Alt+Shift+,
reloadAppMod+Rdisabled (the browser reloads the page)
openSnippetPaletteMod+Shift+IMod+Alt+Shift+I
insertComponentMod+Alt+CMod+Alt+Shift+C
openAuthoringHelpMod+Shift+/Mod+Alt+Shift+/
frameSplitRightMod+Shift+BackslashMod+Alt+Shift+Backslash
checkDiffMod+Shift+DMod+Alt+Shift+D
commandPaletteMod+Kkeeps Mod+K and adds Mod+Alt+Shift+K
inlineAiCommandTriggerMod-jkeeps Mod-j and adds Mod-Alt-Shift-j (CodeMirror syntax)

For a replacement, provenance records the effective combo with origin: "replaced" and its baseCombo. A keep-and-add alias has origin: "added" and also records its source combo; an unchanged binding has origin: "base". reloadApp has an empty effective combo provenance entry to record that its default was disabled; it is not an executable binding.

When a user edits the effective map, call translateShortcutEdit(base, provenance, edit) and assign the returned array to base[edit.key]. This maps a web-view edit back to the underlying base: removing a generated replacement removes its source binding, while removing an added alias leaves the original binding in place. Saving an unchanged effective value also preserves defaults that have no web binding.

The two keep-and-add aliases (commandPalette and inlineAiCommandTrigger) can be hidden on one web device. Pass their shortcut keys in applyShortcutProfile's optional suppressedAddedAliases set. After an edit, pass the current set, provenance, and edit to updateWebShortcutAliasSuppressions; persist and reload the returned set with writeWebShortcutAliasSuppressions() and readWebShortcutAliasSuppressions() in the renderer helper tauri-app/renderer/lib/web-shortcut-alias-suppressions.ts, which uses device-local localStorage. These suppressions are local preferences, not fields in AppSettings, so suppressing an alias does not change the synced base shortcut.

Browser-reserved shortcut inventory

BROWSER_RESERVED_SHORTCUTS lists confirmed browser-chrome shortcuts that are swallowed before the page receives them. The table intentionally omits combinations marked preventable or unverified in the investigation. findBrowserConflicts(shortcuts, browser) checks this inventory and includes a suggested alternative when one is available; suggestWebAlternative uses the explicit web remap for known defaults and otherwise applies the reserved-prefix rule while retaining the final key.

Browser familyOSConfirmed reserved combinations
ChromiummacOSMod+N, Mod+Shift+N, Mod+Shift+T, Mod+Shift+[, Mod+Shift+], Ctrl+Tab, Ctrl+Shift+Tab
ChromiumWindowsMod+N, Mod+Shift+N, Mod+Shift+T, Ctrl+Tab, Ctrl+Shift+Tab, Mod+Shift+I
SafarimacOSMod+N, Mod+Shift+N, Ctrl+Tab, Ctrl+Shift+Tab
SafariiPadOSMod+N, Mod+Shift+T

The inventory is browser-specific: an absent family/OS entry means this table currently has no confirmed reserved combos for that pair, not that every shortcut is guaranteed to reach the app. Update the table when browser verification changes the evidence.

ActionDefault
toggleEditorPreview["Mod+E"]
commandPalette["Mod+K"]
openSettings["Mod+,"]
draft1–draft9["Mod+1"]–["Mod+9"]
newDraft["Mod+N"]
previousDraft["Mod+Shift+["]
nextDraft["Mod+Shift+]"]
kanbanMoveDown / Up / Left / Right["J"] / ["K"] / ["H"] / ["L"]
kanbanEditCard["E"]
kanbanNewCard["N"]
kanbanDeleteCard["D"]
showShortcutPanel["?"]
mindmapMoveDown / Up["ArrowDown"] / ["ArrowUp"]
mindmapCollapse / Expand["ArrowLeft"] / ["ArrowRight"]
mindmapAddChild["Tab"]
mindmapAddSibling["Enter"]
mindmapInsertParent["Alt+Tab"]
mindmapOutdentNode["Mod+ArrowLeft", "Shift+Tab"]
mindmapDeleteNode["Backspace", "Delete"]
mindmapDeleteKeepChildren["Alt+Backspace"]
mindmapEditNode["Mod+Enter"]
mindmapSelectAll["Mod+A"]
frameNext["Ctrl+Tab"]
framePrev["Ctrl+Shift+Tab"]
frameSplitRight["Mod+Shift+Backslash"]

Pile View shortcuts:

ActionDefault
pileView[] (unbound — assign in Settings → Shortcuts)
togglePileViewDirection[] (opt-in)
togglePileViewFullContent[] (opt-in)
pileViewNext["J", "L", "ArrowRight", "ArrowDown"]
pileViewPrev["K", "H", "ArrowLeft", "ArrowUp"]
pileViewOpenItem["Enter"]
pileViewArchiveItem["A"]

Shortcuts for split frame operations, focus frame navigation, and most navigation keys (navInbox, navArchives, navSearch, navTags, equalizeLayout, layoutResetSplit, toggleVimMode, reloadApp, formatMarkdown, summarizedDraftList, toggleTodoView, toggleMindmapView, printPreview) all default to [] (unbound).

Layout

SettingDefault
sidebarPosition"left"
draftBarCollapsedfalse

General

SettingDefault
colorScheme"default"
colorMode"system"
formatOnArchivefalse
windowOpacity1.0
displayScale1.0
appTitlenull
disableSpotlightSearchfalse
showMinimaptrue

Color

AppSettings["color"] defaults to defaultColorStructure, which is seedColorStructure(getSchemeByName(defaultThemeName)) — a deep clone of the default scheme's { ramps, modes: { light, dark } }. This is the persisted shape: since epic #5893 one scheme owns both appearances, so the block carries BOTH mode maps and validateColorStructure() rejects (and reseeds) anything that supplies only one.

A second export, defaultResolvedColors (= resolveScheme(getSchemeByName(defaultThemeName))), is the same default scheme already walked through every RampRef into concrete ColorSettings colors — used wherever a component needs resolved colors rather than the ramp structure (e.g. before the first applyColors() call). defaultColorSettings is a deprecated alias for defaultResolvedColors, kept only until call sites migrate.

Pile View

SettingDefault
cardWidth400 (range 400–800 px)

Sync

SettingDefault
cloudDeviceId""
cloudDeviceName""
cloudRealtimeEnabledtrue

Doc Cloud

SettingDefault
defaultProjectSlugnull (open Projects)
checkpointOnEdittrue
publishNotificationstrue
serverOrigin"" (use adapter origin)

Credentials are intentionally absent. The only device-overridable Doc Cloud field is defaultProjectSlug; an explicit null override means Projects.

Embedded EFE tree width

defaultDirectoryViewSettings is { lastSidebarWidthPx: 240 }. The historical settings key remains, but it controls the tree pane inside External File Editor; there is no registered standalone Directory View provider.

Quick Actions

Default: { tiles: [] } (no quick actions)

Drafts

SettingDefault
activeDraft1
draftCount1

Toolbars

Default: {} (every item on every registered surface is visible).

Font Candidates

Default list of font families including JetBrains Mono, Fira Code, Hack, Menlo, Monaco, SF Mono, and Nerd Font variants. Used by the FontPicker component.

validateSettings()

Validates and sanitizes an unknown input into a valid AppSettings object. Returns null if the input is not an object.

function validateSettings(settings: unknown): AppSettings | null;

Used in both the settings context (on load) and the settings dialog (on save) to enforce valid configuration at all times.

Key behaviors:

  • Falls back to defaults — missing or invalid fields are replaced with defaults

  • Range validation — numeric fields are clamped (e.g., fontSize 10–24, lineHeight 1.0–2.0, windowOpacity 0.3–1.0, activeDraft/draftCount 1–99 integer, pileView.cardWidth 400–800, lineNumberLeftPadding 0–40)

  • String length limits — vimrc is reset to empty string if it exceeds 4096 characters; appTitle is clamped to 64 characters

  • Schema migration — handles renamed fields:

    • general.theme / general.colorSchema → general.colorScheme

    • activeTab → activeDraft, tabCount → draftCount

    • shortcuts.tab1–tab9 → shortcuts.draft1–draft9

    • shortcuts.draft10 is deleted (Mod+0 is reserved for display scale reset)

    • mindmap.depthColor* block is dropped (now controlled by color scheme tokens)

  • Color validation — color is validated as a whole ColorStructure: ramp array lengths (base 5, accent 3), every color string (hex, oklch(...), or transparent), and every RampRef (a literal color string, or a { base | accent: n } index within range / { state: role }) must all be structurally valid, or the entire color field is discarded and re-seeded from defaultColorStructure — there is no per-field fallback the way other settings sections work

  • Frameset validation — validates frameset tree structure; falls back to defaultFramesetTree on invalid input; wipes framesetLeafState on v1→v2 migration

  • Doc Cloud validation — validates the default-project slug, booleans, and bare server origin; drops credential-like unknown fields; validates Doc Cloud pin props to the four safe seeds

  • Retired-provider no-migration behavior — provider ids are opaque. Old pre-release Directory View pins are preserved without a compatibility reader and may show provider-not-found until the user removes them or resets settings

  • Vim settings validation — validates clipboardSync, showModeIndicator (booleans), and vimrc (string with length cap)

  • Note Tray utility validation — noteTrayUtility is normalised by validateNoteTrayUtility (see above); a missing block takes the defaults

  • Toolbar visibility validation (#6566) — for each toolbars entry: unknown surface ids are dropped, malformed surface objects (non-object, or missing hidden) are dropped, unknown item ids and non-string entries are filtered out of hidden, duplicates are removed, a non-array hidden becomes [], and any toolbars["menu-bar-right"] entry is discarded (that surface's sole representation is menuBar.rightIcons)

Dependencies

  • @takazudo/color-themes — used to generate default color values from the default theme

  • @takazudo/shortcut-engine — used for shortcut normalization and deduplication in validateSettings

  • @takazudo/view-provider — provides FramesetTree type and validateFramesetTree used by validation