@weasel-js/modes 0.8.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +8 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,13 @@ interface ToolLike {
|
|
|
39
39
|
}
|
|
40
40
|
/** True iff `tool` is usable in the registry's currently active mode. */
|
|
41
41
|
declare function eligibleTool(reg: ModeRegistry, tool: ToolLike): boolean;
|
|
42
|
+
/** True iff a contribution is usable in the registry's active mode. */
|
|
43
|
+
declare function eligibleContribution(reg: ModeRegistry, entry: {
|
|
44
|
+
id: string;
|
|
45
|
+
eligibility?: {
|
|
46
|
+
capabilities?: readonly CapabilityTag[];
|
|
47
|
+
};
|
|
48
|
+
}): boolean;
|
|
42
49
|
|
|
43
50
|
interface CreateScopingDimOptions {
|
|
44
51
|
registry: ModeRegistry;
|
|
@@ -57,4 +64,4 @@ interface ScopingDim {
|
|
|
57
64
|
}
|
|
58
65
|
declare function createScopingDim(opts: CreateScopingDimOptions): ScopingDim;
|
|
59
66
|
|
|
60
|
-
export { CapabilityTag, type CreateModeDecorationsOptions, type CreateModeRegistryOptions, type CreateScopingDimOptions, type ModeDecorationPainter, type ModeDecorations, ModeDefinition, type ModeDrawCommand, type ModeRegistry, type ScopingDim, type ToolLike, createModeDecorations, createModeRegistry, createScopingDim, eligibleTool };
|
|
67
|
+
export { CapabilityTag, type CreateModeDecorationsOptions, type CreateModeRegistryOptions, type CreateScopingDimOptions, type ModeDecorationPainter, type ModeDecorations, ModeDefinition, type ModeDrawCommand, type ModeRegistry, type ScopingDim, type ToolLike, createModeDecorations, createModeRegistry, createScopingDim, eligibleContribution, eligibleTool };
|
package/dist/index.js
CHANGED
|
@@ -91,6 +91,9 @@ function createModeDecorations(opts) {
|
|
|
91
91
|
function eligibleTool(reg, tool) {
|
|
92
92
|
return eligibleForMode(reg.current(), tool.capabilities ?? []);
|
|
93
93
|
}
|
|
94
|
+
function eligibleContribution(reg, entry) {
|
|
95
|
+
return eligibleForMode(reg.current(), entry.eligibility?.capabilities ?? []);
|
|
96
|
+
}
|
|
94
97
|
|
|
95
98
|
// src/scopingLayer.ts
|
|
96
99
|
function createScopingDim(opts) {
|
|
@@ -109,6 +112,6 @@ function createScopingDim(opts) {
|
|
|
109
112
|
};
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
export { ALL_TAGS, IMPLICIT_TAGS, createModeDecorations, createModeRegistry, createScopingDim, eligibleForMode, eligibleTool, isCapabilityTag };
|
|
115
|
+
export { ALL_TAGS, IMPLICIT_TAGS, createModeDecorations, createModeRegistry, createScopingDim, eligibleContribution, eligibleForMode, eligibleTool, isCapabilityTag };
|
|
113
116
|
//# sourceMappingURL=index.js.map
|
|
114
117
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/capabilities.ts","../src/modeDefinition.ts","../src/registry.ts","../src/decorations.ts","../src/eligibility.ts","../src/scopingLayer.ts"],"names":[],"mappings":";;;AAGO,IAAM,QAAA,GAAW;AAAA,EACtB,YAAA;AAAA,EACA,mBAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,sBAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF;AAMO,IAAM,aAAA,GAA0C,CAAC,YAAY;AAE7D,SAAS,gBAAgB,KAAA,EAAuC;AACrE,EAAA,OAAQ,QAAA,CAA+B,SAAS,KAAK,CAAA;AACvD;;;ACFO,SAAS,eAAA,CAAgB,MAAsB,QAAA,EAA6C;AACjG,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAClC,EAAA,MAAM,OAAA,uBAAc,GAAA,CAAmB,CAAC,GAAG,IAAA,CAAK,MAAA,EAAQ,GAAG,aAAa,CAAC,CAAA;AACzE,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,EAAG,OAAO,IAAA;AAAA,EAC7B;AACA,EAAA,OAAO,KAAA;AACT;;;ACfO,SAAS,mBAAmB,IAAA,EAA+C;AAChF,EAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAC,CAAC,CAAC,CAAA;AACxD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA;AACxC,EAAA,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,CAAA,cAAA,EAAiB,IAAA,CAAK,OAAO,CAAA,mBAAA,CAAqB,CAAA;AAEhF,EAAA,IAAI,MAAA,GAAyB,OAAA;AAC7B,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAgB;AAEtC,EAAA,SAAS,IAAA,GAAa;AACpB,IAAA,OAAA,EAAA;AACA,IAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAAA,EAC/B;AAEA,EAAA,OAAO;AAAA,IACL,SAAS,MAAM,MAAA;AAAA,IACf,QAAQ,EAAA,EAAkB;AACxB,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAC3B,MAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,EAAE,CAAA,CAAE,CAAA;AACnD,MAAA,IAAI,SAAS,MAAA,EAAQ;AACrB,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,IACA,KAAK,EAAA,EAA4B;AAC/B,MAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AACxB,MAAA,IAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,EAAE,CAAA,CAAE,CAAA;AAChD,MAAA,OAAO,CAAA;AAAA,IACT,CAAA;AAAA,IACA,YAAY,MAAM,OAAA;AAAA,IAClB,UAAU,QAAA,EAAkC;AAC1C,MAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,MAAA,OAAO,MAAM;AAAE,QAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,MAAG,CAAA;AAAA,IAC7C;AAAA,GACF;AACF;;;AC1BO,SAAS,sBAAsB,IAAA,EAAqD;AACzF,EAAA,MAAM,EAAE,UAAS,GAAI,IAAA;AACrB,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAmC;AACxD,EAAA,IAAI,GAAA,GAAM,CAAA;AAEV,EAAA,QAAA,CAAS,UAAU,MAAM;AACvB,IAAA,GAAA,EAAA;AAAA,EACF,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,QAAA,CAAS,QAAgB,OAAA,EAAsC;AAC7D,MAAA,QAAA,CAAS,GAAA,CAAI,QAAQ,OAAO,CAAA;AAC5B,MAAA,GAAA,EAAA;AAAA,IACF,CAAA;AAAA,IACA,KAAA,GAA2B;AACzB,MAAA,MAAM,UAAU,QAAA,CAAS,GAAA,CAAI,QAAA,CAAS,OAAA,GAAU,EAAE,CAAA;AAClD,MAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AACtB,MAAA,OAAO,OAAA,EAAQ;AAAA,IACjB,CAAA;AAAA,IACA,YAAY,MAAM;AAAA,GACpB;AACF;;;AClCO,SAAS,YAAA,CAAa,KAAmB,IAAA,EAAyB;AACvE,EAAA,OAAO,gBAAgB,GAAA,CAAI,OAAA,IAAW,IAAA,CAAK,YAAA,IAAgB,EAAE,CAAA;AAC/D;;;ACOO,SAAS,iBAAiB,IAAA,EAA2C;AAC1E,EAAA,MAAM,GAAA,GAAM,KAAK,QAAA,IAAY,GAAA;AAC7B,EAAA,OAAO;AAAA,IACL,SAAS,EAAA,EAAI;AACX,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,OAAA,EAAQ;AACnC,MAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAO,CAAA;AAC1B,MAAA,OAAO,KAAK,YAAA,EAAa,CAAE,GAAA,CAAI,EAAE,IAAI,CAAA,GAAI,GAAA;AAAA,IAC3C,CAAA;AAAA,IACA,qBAAqB,EAAA,EAAI;AACvB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,OAAA,EAAQ;AACnC,MAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAO,IAAA;AAC1B,MAAA,OAAO,IAAA,CAAK,YAAA,EAAa,CAAE,GAAA,CAAI,EAAE,CAAA;AAAA,IACnC;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/** The full vocabulary of capability tags shipped in the default preset.\n * Apps and other consumers can add their own tags; this list is what\n * `weasel-modes` itself uses. */\nexport const ALL_TAGS = [\n 'navigation',\n 'creates-selection',\n 'creates-paths',\n 'creates-shapes',\n 'creates-text',\n 'edits-anchors',\n 'edits-text',\n 'transforms-selection',\n 'samples-color',\n 'applies-fill',\n 'edits-page',\n] as const;\n\nexport type CapabilityTag = (typeof ALL_TAGS)[number] | (string & {});\n\n/** Tags that are implicitly allowed in every mode — never listed per-mode.\n * A tool tagged with any of these is always eligible. */\nexport const IMPLICIT_TAGS: readonly CapabilityTag[] = ['navigation'];\n\nexport function isCapabilityTag(value: string): value is CapabilityTag {\n return (ALL_TAGS as readonly string[]).includes(value);\n}\n","import { IMPLICIT_TAGS, type CapabilityTag } from './capabilities';\n\nexport interface WorkspaceVisual {\n tint?: string;\n gradient?: 'top-down' | 'bottom-up';\n intensity?: number;\n}\n\nexport interface ModeDefinition {\n id: string;\n kind: 'soft' | 'strict';\n /** Capability tags this mode allows beyond IMPLICIT_TAGS. */\n allows: CapabilityTag[];\n /** When true, out-of-target objects dim at the renderer layer. */\n scoping: boolean;\n workspace?: WorkspaceVisual;\n entry?: { shortcut?: string; trigger?: 'double-click-target' };\n exit?: { shortcut?: string };\n commit?: { shortcut?: string };\n cancel?: { shortcut?: string };\n}\n\n/** True iff a tool carrying `toolTags` is eligible for `mode`. */\nexport function eligibleForMode(mode: ModeDefinition, toolTags: readonly CapabilityTag[]): boolean {\n if (toolTags.length === 0) return false;\n const allowed = new Set<CapabilityTag>([...mode.allows, ...IMPLICIT_TAGS]);\n for (const t of toolTags) {\n if (allowed.has(t)) return true;\n }\n return false;\n}\n","import type { ModeDefinition } from './modeDefinition';\n\nexport interface CreateModeRegistryOptions {\n modes: readonly ModeDefinition[];\n initial: string;\n}\n\nexport interface ModeRegistry {\n current(): ModeDefinition;\n setMode(id: string): void;\n byId(id: string): ModeDefinition;\n getVersion(): number;\n subscribe(listener: () => void): () => void;\n}\n\nexport function createModeRegistry(opts: CreateModeRegistryOptions): ModeRegistry {\n const byIdMap = new Map(opts.modes.map((m) => [m.id, m]));\n const initial = byIdMap.get(opts.initial);\n if (!initial) throw new Error(`Initial mode \"${opts.initial}\" not in modes list`);\n\n let active: ModeDefinition = initial;\n let version = 0;\n const listeners = new Set<() => void>();\n\n function bump(): void {\n version++;\n for (const l of listeners) l();\n }\n\n return {\n current: () => active,\n setMode(id: string): void {\n const next = byIdMap.get(id);\n if (!next) throw new Error(`Unknown mode id: ${id}`);\n if (next === active) return;\n active = next;\n bump();\n },\n byId(id: string): ModeDefinition {\n const m = byIdMap.get(id);\n if (!m) throw new Error(`Unknown mode id: ${id}`);\n return m;\n },\n getVersion: () => version,\n subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => { listeners.delete(listener); };\n },\n };\n}\n","import type { ModeRegistry } from './registry';\n\n/** Loose draw-command type — the kit's `DrawCommand` union shape is over in\n * `src/renderer`. We keep this opaque to avoid a cross-package import in\n * the type surface; consumers cast to the real DrawCommand at use site. */\nexport type ModeDrawCommand = unknown;\n\nexport type ModeDecorationPainter = () => ModeDrawCommand[];\n\nexport interface CreateModeDecorationsOptions {\n registry: ModeRegistry;\n}\n\nexport interface ModeDecorations {\n /** Register (or replace) the painter for a mode id. */\n register(modeId: string, painter: ModeDecorationPainter): void;\n /** Paint the active mode's decorations. Returns an empty array if no\n * painter is registered for the active mode. */\n paint(): ModeDrawCommand[];\n /** Monotonic version. Bumps on mode change or painter registration. */\n getVersion(): number;\n}\n\nexport function createModeDecorations(opts: CreateModeDecorationsOptions): ModeDecorations {\n const { registry } = opts;\n const painters = new Map<string, ModeDecorationPainter>();\n let ver = 0;\n\n registry.subscribe(() => {\n ver++;\n });\n\n return {\n register(modeId: string, painter: ModeDecorationPainter): void {\n painters.set(modeId, painter);\n ver++;\n },\n paint(): ModeDrawCommand[] {\n const painter = painters.get(registry.current().id);\n if (!painter) return [];\n return painter();\n },\n getVersion: () => ver,\n };\n}\n","import type { ModeRegistry } from './registry';\nimport type { CapabilityTag } from './capabilities';\nimport { eligibleForMode } from './modeDefinition';\n\nexport interface ToolLike {\n id: string;\n capabilities?: readonly CapabilityTag[];\n}\n\n/** True iff `tool` is usable in the registry's currently active mode. */\nexport function eligibleTool(reg: ModeRegistry, tool: ToolLike): boolean {\n return eligibleForMode(reg.current(), tool.capabilities ?? []);\n}\n","import type { ModeRegistry } from './registry';\n\nexport interface CreateScopingDimOptions {\n registry: ModeRegistry;\n /** Returns the set of node ids that are *in* scope for the current mode.\n * The app computes this — typically: selection-only for path-edit,\n * isolated subtree for isolation, empty for non-scoping modes. */\n getTargetIds: () => ReadonlySet<string>;\n /** Alpha for out-of-scope nodes. Default 0.3 (spec). */\n dimAlpha?: number;\n}\n\nexport interface ScopingDim {\n /** Multiplier in [0, 1] to apply to a node's render alpha. */\n alphaFor(id: string): number;\n /** Whether the node should respond to pointer hits. */\n isPointerInteractive(id: string): boolean;\n}\n\nexport function createScopingDim(opts: CreateScopingDimOptions): ScopingDim {\n const dim = opts.dimAlpha ?? 0.3;\n return {\n alphaFor(id) {\n const mode = opts.registry.current();\n if (!mode.scoping) return 1;\n return opts.getTargetIds().has(id) ? 1 : dim;\n },\n isPointerInteractive(id) {\n const mode = opts.registry.current();\n if (!mode.scoping) return true;\n return opts.getTargetIds().has(id);\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/capabilities.ts","../src/modeDefinition.ts","../src/registry.ts","../src/decorations.ts","../src/eligibility.ts","../src/scopingLayer.ts"],"names":[],"mappings":";;;AAGO,IAAM,QAAA,GAAW;AAAA,EACtB,YAAA;AAAA,EACA,mBAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,sBAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF;AAMO,IAAM,aAAA,GAA0C,CAAC,YAAY;AAE7D,SAAS,gBAAgB,KAAA,EAAuC;AACrE,EAAA,OAAQ,QAAA,CAA+B,SAAS,KAAK,CAAA;AACvD;;;ACFO,SAAS,eAAA,CAAgB,MAAsB,QAAA,EAA6C;AACjG,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAClC,EAAA,MAAM,OAAA,uBAAc,GAAA,CAAmB,CAAC,GAAG,IAAA,CAAK,MAAA,EAAQ,GAAG,aAAa,CAAC,CAAA;AACzE,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,EAAG,OAAO,IAAA;AAAA,EAC7B;AACA,EAAA,OAAO,KAAA;AACT;;;ACfO,SAAS,mBAAmB,IAAA,EAA+C;AAChF,EAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAC,CAAC,CAAC,CAAA;AACxD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA;AACxC,EAAA,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,CAAA,cAAA,EAAiB,IAAA,CAAK,OAAO,CAAA,mBAAA,CAAqB,CAAA;AAEhF,EAAA,IAAI,MAAA,GAAyB,OAAA;AAC7B,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAgB;AAEtC,EAAA,SAAS,IAAA,GAAa;AACpB,IAAA,OAAA,EAAA;AACA,IAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAAA,EAC/B;AAEA,EAAA,OAAO;AAAA,IACL,SAAS,MAAM,MAAA;AAAA,IACf,QAAQ,EAAA,EAAkB;AACxB,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAC3B,MAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,EAAE,CAAA,CAAE,CAAA;AACnD,MAAA,IAAI,SAAS,MAAA,EAAQ;AACrB,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,IACA,KAAK,EAAA,EAA4B;AAC/B,MAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AACxB,MAAA,IAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,EAAE,CAAA,CAAE,CAAA;AAChD,MAAA,OAAO,CAAA;AAAA,IACT,CAAA;AAAA,IACA,YAAY,MAAM,OAAA;AAAA,IAClB,UAAU,QAAA,EAAkC;AAC1C,MAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,MAAA,OAAO,MAAM;AAAE,QAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,MAAG,CAAA;AAAA,IAC7C;AAAA,GACF;AACF;;;AC1BO,SAAS,sBAAsB,IAAA,EAAqD;AACzF,EAAA,MAAM,EAAE,UAAS,GAAI,IAAA;AACrB,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAmC;AACxD,EAAA,IAAI,GAAA,GAAM,CAAA;AAEV,EAAA,QAAA,CAAS,UAAU,MAAM;AACvB,IAAA,GAAA,EAAA;AAAA,EACF,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,QAAA,CAAS,QAAgB,OAAA,EAAsC;AAC7D,MAAA,QAAA,CAAS,GAAA,CAAI,QAAQ,OAAO,CAAA;AAC5B,MAAA,GAAA,EAAA;AAAA,IACF,CAAA;AAAA,IACA,KAAA,GAA2B;AACzB,MAAA,MAAM,UAAU,QAAA,CAAS,GAAA,CAAI,QAAA,CAAS,OAAA,GAAU,EAAE,CAAA;AAClD,MAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AACtB,MAAA,OAAO,OAAA,EAAQ;AAAA,IACjB,CAAA;AAAA,IACA,YAAY,MAAM;AAAA,GACpB;AACF;;;AClCO,SAAS,YAAA,CAAa,KAAmB,IAAA,EAAyB;AACvE,EAAA,OAAO,gBAAgB,GAAA,CAAI,OAAA,IAAW,IAAA,CAAK,YAAA,IAAgB,EAAE,CAAA;AAC/D;AAGO,SAAS,oBAAA,CACd,KACA,KAAA,EACS;AACT,EAAA,OAAO,eAAA,CAAgB,IAAI,OAAA,EAAQ,EAAG,MAAM,WAAA,EAAa,YAAA,IAAgB,EAAE,CAAA;AAC7E;;;ACDO,SAAS,iBAAiB,IAAA,EAA2C;AAC1E,EAAA,MAAM,GAAA,GAAM,KAAK,QAAA,IAAY,GAAA;AAC7B,EAAA,OAAO;AAAA,IACL,SAAS,EAAA,EAAI;AACX,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,OAAA,EAAQ;AACnC,MAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAO,CAAA;AAC1B,MAAA,OAAO,KAAK,YAAA,EAAa,CAAE,GAAA,CAAI,EAAE,IAAI,CAAA,GAAI,GAAA;AAAA,IAC3C,CAAA;AAAA,IACA,qBAAqB,EAAA,EAAI;AACvB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,OAAA,EAAQ;AACnC,MAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAO,IAAA;AAC1B,MAAA,OAAO,IAAA,CAAK,YAAA,EAAa,CAAE,GAAA,CAAI,EAAE,CAAA;AAAA,IACnC;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/** The full vocabulary of capability tags shipped in the default preset.\n * Apps and other consumers can add their own tags; this list is what\n * `weasel-modes` itself uses. */\nexport const ALL_TAGS = [\n 'navigation',\n 'creates-selection',\n 'creates-paths',\n 'creates-shapes',\n 'creates-text',\n 'edits-anchors',\n 'edits-text',\n 'transforms-selection',\n 'samples-color',\n 'applies-fill',\n 'edits-page',\n] as const;\n\nexport type CapabilityTag = (typeof ALL_TAGS)[number] | (string & {});\n\n/** Tags that are implicitly allowed in every mode — never listed per-mode.\n * A tool tagged with any of these is always eligible. */\nexport const IMPLICIT_TAGS: readonly CapabilityTag[] = ['navigation'];\n\nexport function isCapabilityTag(value: string): value is CapabilityTag {\n return (ALL_TAGS as readonly string[]).includes(value);\n}\n","import { IMPLICIT_TAGS, type CapabilityTag } from './capabilities';\n\nexport interface WorkspaceVisual {\n tint?: string;\n gradient?: 'top-down' | 'bottom-up';\n intensity?: number;\n}\n\nexport interface ModeDefinition {\n id: string;\n kind: 'soft' | 'strict';\n /** Capability tags this mode allows beyond IMPLICIT_TAGS. */\n allows: CapabilityTag[];\n /** When true, out-of-target objects dim at the renderer layer. */\n scoping: boolean;\n workspace?: WorkspaceVisual;\n entry?: { shortcut?: string; trigger?: 'double-click-target' };\n exit?: { shortcut?: string };\n commit?: { shortcut?: string };\n cancel?: { shortcut?: string };\n}\n\n/** True iff a tool carrying `toolTags` is eligible for `mode`. */\nexport function eligibleForMode(mode: ModeDefinition, toolTags: readonly CapabilityTag[]): boolean {\n if (toolTags.length === 0) return false;\n const allowed = new Set<CapabilityTag>([...mode.allows, ...IMPLICIT_TAGS]);\n for (const t of toolTags) {\n if (allowed.has(t)) return true;\n }\n return false;\n}\n","import type { ModeDefinition } from './modeDefinition';\n\nexport interface CreateModeRegistryOptions {\n modes: readonly ModeDefinition[];\n initial: string;\n}\n\nexport interface ModeRegistry {\n current(): ModeDefinition;\n setMode(id: string): void;\n byId(id: string): ModeDefinition;\n getVersion(): number;\n subscribe(listener: () => void): () => void;\n}\n\nexport function createModeRegistry(opts: CreateModeRegistryOptions): ModeRegistry {\n const byIdMap = new Map(opts.modes.map((m) => [m.id, m]));\n const initial = byIdMap.get(opts.initial);\n if (!initial) throw new Error(`Initial mode \"${opts.initial}\" not in modes list`);\n\n let active: ModeDefinition = initial;\n let version = 0;\n const listeners = new Set<() => void>();\n\n function bump(): void {\n version++;\n for (const l of listeners) l();\n }\n\n return {\n current: () => active,\n setMode(id: string): void {\n const next = byIdMap.get(id);\n if (!next) throw new Error(`Unknown mode id: ${id}`);\n if (next === active) return;\n active = next;\n bump();\n },\n byId(id: string): ModeDefinition {\n const m = byIdMap.get(id);\n if (!m) throw new Error(`Unknown mode id: ${id}`);\n return m;\n },\n getVersion: () => version,\n subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => { listeners.delete(listener); };\n },\n };\n}\n","import type { ModeRegistry } from './registry';\n\n/** Loose draw-command type — the kit's `DrawCommand` union shape is over in\n * `src/renderer`. We keep this opaque to avoid a cross-package import in\n * the type surface; consumers cast to the real DrawCommand at use site. */\nexport type ModeDrawCommand = unknown;\n\nexport type ModeDecorationPainter = () => ModeDrawCommand[];\n\nexport interface CreateModeDecorationsOptions {\n registry: ModeRegistry;\n}\n\nexport interface ModeDecorations {\n /** Register (or replace) the painter for a mode id. */\n register(modeId: string, painter: ModeDecorationPainter): void;\n /** Paint the active mode's decorations. Returns an empty array if no\n * painter is registered for the active mode. */\n paint(): ModeDrawCommand[];\n /** Monotonic version. Bumps on mode change or painter registration. */\n getVersion(): number;\n}\n\nexport function createModeDecorations(opts: CreateModeDecorationsOptions): ModeDecorations {\n const { registry } = opts;\n const painters = new Map<string, ModeDecorationPainter>();\n let ver = 0;\n\n registry.subscribe(() => {\n ver++;\n });\n\n return {\n register(modeId: string, painter: ModeDecorationPainter): void {\n painters.set(modeId, painter);\n ver++;\n },\n paint(): ModeDrawCommand[] {\n const painter = painters.get(registry.current().id);\n if (!painter) return [];\n return painter();\n },\n getVersion: () => ver,\n };\n}\n","import type { ModeRegistry } from './registry';\nimport type { CapabilityTag } from './capabilities';\nimport { eligibleForMode } from './modeDefinition';\n\nexport interface ToolLike {\n id: string;\n capabilities?: readonly CapabilityTag[];\n}\n\n/** True iff `tool` is usable in the registry's currently active mode. */\nexport function eligibleTool(reg: ModeRegistry, tool: ToolLike): boolean {\n return eligibleForMode(reg.current(), tool.capabilities ?? []);\n}\n\n/** True iff a contribution is usable in the registry's active mode. */\nexport function eligibleContribution(\n reg: ModeRegistry,\n entry: { id: string; eligibility?: { capabilities?: readonly CapabilityTag[] } },\n): boolean {\n return eligibleForMode(reg.current(), entry.eligibility?.capabilities ?? []);\n}\n","import type { ModeRegistry } from './registry';\n\nexport interface CreateScopingDimOptions {\n registry: ModeRegistry;\n /** Returns the set of node ids that are *in* scope for the current mode.\n * The app computes this — typically: selection-only for path-edit,\n * isolated subtree for isolation, empty for non-scoping modes. */\n getTargetIds: () => ReadonlySet<string>;\n /** Alpha for out-of-scope nodes. Default 0.3 (spec). */\n dimAlpha?: number;\n}\n\nexport interface ScopingDim {\n /** Multiplier in [0, 1] to apply to a node's render alpha. */\n alphaFor(id: string): number;\n /** Whether the node should respond to pointer hits. */\n isPointerInteractive(id: string): boolean;\n}\n\nexport function createScopingDim(opts: CreateScopingDimOptions): ScopingDim {\n const dim = opts.dimAlpha ?? 0.3;\n return {\n alphaFor(id) {\n const mode = opts.registry.current();\n if (!mode.scoping) return 1;\n return opts.getTargetIds().has(id) ? 1 : dim;\n },\n isPointerInteractive(id) {\n const mode = opts.registry.current();\n if (!mode.scoping) return true;\n return opts.getTargetIds().has(id);\n },\n };\n}\n"]}
|