@weasel-js/modes 0.5.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/LICENSE +21 -0
- package/README.md +24 -0
- package/dist/chunk-KILROWYB.js +88 -0
- package/dist/chunk-KILROWYB.js.map +1 -0
- package/dist/default-CdTM_d8s.d.ts +50 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/presets/default.d.ts +1 -0
- package/dist/presets/default.js +3 -0
- package/dist/presets/default.js.map +1 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 orochi235
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @weasel-js/modes
|
|
2
|
+
|
|
3
|
+
App-level modality primitives: capability tags, mode definitions, mode registry, and decoration layer.
|
|
4
|
+
|
|
5
|
+
Part of [weasel](https://github.com/orochi235/weasel), a domain-agnostic 2D
|
|
6
|
+
scene-graph canvas kit for React. See the
|
|
7
|
+
[API reference](https://orochi235.github.io/weasel/api/).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @weasel-js/modes
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { /* … */ } from '@weasel-js/modes';
|
|
19
|
+
import { /* … */ } from '@weasel-js/modes/presets/default';
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## License
|
|
23
|
+
|
|
24
|
+
MIT
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// src/presets/default.ts
|
|
2
|
+
var NORMAL = {
|
|
3
|
+
id: "normal",
|
|
4
|
+
kind: "soft",
|
|
5
|
+
allows: [
|
|
6
|
+
"creates-selection",
|
|
7
|
+
"transforms-selection",
|
|
8
|
+
"creates-paths",
|
|
9
|
+
"creates-shapes",
|
|
10
|
+
"creates-text",
|
|
11
|
+
"samples-color",
|
|
12
|
+
"applies-fill",
|
|
13
|
+
"edits-page"
|
|
14
|
+
],
|
|
15
|
+
scoping: false
|
|
16
|
+
};
|
|
17
|
+
var PATH_EDIT = {
|
|
18
|
+
id: "path-edit",
|
|
19
|
+
kind: "soft",
|
|
20
|
+
allows: ["edits-anchors"],
|
|
21
|
+
scoping: true,
|
|
22
|
+
workspace: { tint: "#3b82f6", gradient: "bottom-up", intensity: 0.12 },
|
|
23
|
+
entry: { trigger: "double-click-target", shortcut: "Enter" },
|
|
24
|
+
exit: { shortcut: "Escape" }
|
|
25
|
+
};
|
|
26
|
+
var ISOLATION = {
|
|
27
|
+
id: "isolation",
|
|
28
|
+
kind: "soft",
|
|
29
|
+
allows: [
|
|
30
|
+
"creates-selection",
|
|
31
|
+
"transforms-selection",
|
|
32
|
+
"creates-paths",
|
|
33
|
+
"creates-shapes",
|
|
34
|
+
"creates-text",
|
|
35
|
+
"samples-color",
|
|
36
|
+
"applies-fill"
|
|
37
|
+
],
|
|
38
|
+
scoping: true,
|
|
39
|
+
workspace: { tint: "#8b5cf6", gradient: "bottom-up", intensity: 0.12 },
|
|
40
|
+
entry: { trigger: "double-click-target" },
|
|
41
|
+
exit: { shortcut: "Escape" }
|
|
42
|
+
};
|
|
43
|
+
var FREE_TRANSFORM = {
|
|
44
|
+
id: "free-transform",
|
|
45
|
+
kind: "strict",
|
|
46
|
+
allows: ["transforms-selection"],
|
|
47
|
+
scoping: false,
|
|
48
|
+
workspace: { tint: "#f59e0b", gradient: "bottom-up", intensity: 0.12 },
|
|
49
|
+
entry: { shortcut: "Meta+T" },
|
|
50
|
+
commit: { shortcut: "Enter" },
|
|
51
|
+
cancel: { shortcut: "Escape" }
|
|
52
|
+
};
|
|
53
|
+
var TEXT_EDIT = {
|
|
54
|
+
id: "text-edit",
|
|
55
|
+
kind: "soft",
|
|
56
|
+
allows: ["edits-text"],
|
|
57
|
+
scoping: false,
|
|
58
|
+
workspace: { tint: "#10b981", gradient: "bottom-up", intensity: 0.12 },
|
|
59
|
+
entry: { trigger: "double-click-target" },
|
|
60
|
+
exit: { shortcut: "Escape" }
|
|
61
|
+
};
|
|
62
|
+
var CROP = {
|
|
63
|
+
id: "crop",
|
|
64
|
+
kind: "strict",
|
|
65
|
+
allows: ["edits-page"],
|
|
66
|
+
scoping: false,
|
|
67
|
+
workspace: { tint: "#ef4444", gradient: "bottom-up", intensity: 0.12 },
|
|
68
|
+
entry: { shortcut: "C" },
|
|
69
|
+
commit: { shortcut: "Enter" },
|
|
70
|
+
cancel: { shortcut: "Escape" }
|
|
71
|
+
};
|
|
72
|
+
var DEFAULT_MODES = [
|
|
73
|
+
NORMAL,
|
|
74
|
+
PATH_EDIT,
|
|
75
|
+
ISOLATION,
|
|
76
|
+
FREE_TRANSFORM,
|
|
77
|
+
TEXT_EDIT,
|
|
78
|
+
CROP
|
|
79
|
+
];
|
|
80
|
+
function byId(id) {
|
|
81
|
+
const m = DEFAULT_MODES.find((m2) => m2.id === id);
|
|
82
|
+
if (!m) throw new Error(`Unknown mode id: ${id}`);
|
|
83
|
+
return m;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { CROP, DEFAULT_MODES, FREE_TRANSFORM, ISOLATION, NORMAL, PATH_EDIT, TEXT_EDIT, byId };
|
|
87
|
+
//# sourceMappingURL=chunk-KILROWYB.js.map
|
|
88
|
+
//# sourceMappingURL=chunk-KILROWYB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/presets/default.ts"],"names":["m"],"mappings":"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","file":"chunk-KILROWYB.js","sourcesContent":["import type { ModeDefinition } from '../modeDefinition';\n\nexport const NORMAL: ModeDefinition = {\n id: 'normal',\n kind: 'soft',\n allows: [\n 'creates-selection',\n 'transforms-selection',\n 'creates-paths',\n 'creates-shapes',\n 'creates-text',\n 'samples-color',\n 'applies-fill',\n 'edits-page',\n ],\n scoping: false,\n};\n\nexport const PATH_EDIT: ModeDefinition = {\n id: 'path-edit',\n kind: 'soft',\n allows: ['edits-anchors'],\n scoping: true,\n workspace: { tint: '#3b82f6', gradient: 'bottom-up', intensity: 0.12 },\n entry: { trigger: 'double-click-target', shortcut: 'Enter' },\n exit: { shortcut: 'Escape' },\n};\n\nexport const ISOLATION: ModeDefinition = {\n id: 'isolation',\n kind: 'soft',\n allows: [\n 'creates-selection',\n 'transforms-selection',\n 'creates-paths',\n 'creates-shapes',\n 'creates-text',\n 'samples-color',\n 'applies-fill',\n ],\n scoping: true,\n workspace: { tint: '#8b5cf6', gradient: 'bottom-up', intensity: 0.12 },\n entry: { trigger: 'double-click-target' },\n exit: { shortcut: 'Escape' },\n};\n\nexport const FREE_TRANSFORM: ModeDefinition = {\n id: 'free-transform',\n kind: 'strict',\n allows: ['transforms-selection'],\n scoping: false,\n workspace: { tint: '#f59e0b', gradient: 'bottom-up', intensity: 0.12 },\n entry: { shortcut: 'Meta+T' },\n commit: { shortcut: 'Enter' },\n cancel: { shortcut: 'Escape' },\n};\n\nexport const TEXT_EDIT: ModeDefinition = {\n id: 'text-edit',\n kind: 'soft',\n allows: ['edits-text'],\n scoping: false,\n workspace: { tint: '#10b981', gradient: 'bottom-up', intensity: 0.12 },\n entry: { trigger: 'double-click-target' },\n exit: { shortcut: 'Escape' },\n};\n\nexport const CROP: ModeDefinition = {\n id: 'crop',\n kind: 'strict',\n allows: ['edits-page'],\n scoping: false,\n workspace: { tint: '#ef4444', gradient: 'bottom-up', intensity: 0.12 },\n entry: { shortcut: 'C' },\n commit: { shortcut: 'Enter' },\n cancel: { shortcut: 'Escape' },\n};\n\nexport const DEFAULT_MODES: readonly ModeDefinition[] = [\n NORMAL,\n PATH_EDIT,\n ISOLATION,\n FREE_TRANSFORM,\n TEXT_EDIT,\n CROP,\n];\n\nexport function byId(id: string): ModeDefinition {\n const m = DEFAULT_MODES.find((m) => m.id === id);\n if (!m) throw new Error(`Unknown mode id: ${id}`);\n return m;\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** The full vocabulary of capability tags shipped in the default preset.
|
|
2
|
+
* Apps and other consumers can add their own tags; this list is what
|
|
3
|
+
* `weasel-modes` itself uses. */
|
|
4
|
+
declare const ALL_TAGS: readonly ["navigation", "creates-selection", "creates-paths", "creates-shapes", "creates-text", "edits-anchors", "edits-text", "transforms-selection", "samples-color", "applies-fill", "edits-page"];
|
|
5
|
+
type CapabilityTag = (typeof ALL_TAGS)[number] | (string & {});
|
|
6
|
+
/** Tags that are implicitly allowed in every mode — never listed per-mode.
|
|
7
|
+
* A tool tagged with any of these is always eligible. */
|
|
8
|
+
declare const IMPLICIT_TAGS: readonly CapabilityTag[];
|
|
9
|
+
declare function isCapabilityTag(value: string): value is CapabilityTag;
|
|
10
|
+
|
|
11
|
+
interface WorkspaceVisual {
|
|
12
|
+
tint?: string;
|
|
13
|
+
gradient?: 'top-down' | 'bottom-up';
|
|
14
|
+
intensity?: number;
|
|
15
|
+
}
|
|
16
|
+
interface ModeDefinition {
|
|
17
|
+
id: string;
|
|
18
|
+
kind: 'soft' | 'strict';
|
|
19
|
+
/** Capability tags this mode allows beyond IMPLICIT_TAGS. */
|
|
20
|
+
allows: CapabilityTag[];
|
|
21
|
+
/** When true, out-of-target objects dim at the renderer layer. */
|
|
22
|
+
scoping: boolean;
|
|
23
|
+
workspace?: WorkspaceVisual;
|
|
24
|
+
entry?: {
|
|
25
|
+
shortcut?: string;
|
|
26
|
+
trigger?: 'double-click-target';
|
|
27
|
+
};
|
|
28
|
+
exit?: {
|
|
29
|
+
shortcut?: string;
|
|
30
|
+
};
|
|
31
|
+
commit?: {
|
|
32
|
+
shortcut?: string;
|
|
33
|
+
};
|
|
34
|
+
cancel?: {
|
|
35
|
+
shortcut?: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** True iff a tool carrying `toolTags` is eligible for `mode`. */
|
|
39
|
+
declare function eligibleForMode(mode: ModeDefinition, toolTags: readonly CapabilityTag[]): boolean;
|
|
40
|
+
|
|
41
|
+
declare const NORMAL: ModeDefinition;
|
|
42
|
+
declare const PATH_EDIT: ModeDefinition;
|
|
43
|
+
declare const ISOLATION: ModeDefinition;
|
|
44
|
+
declare const FREE_TRANSFORM: ModeDefinition;
|
|
45
|
+
declare const TEXT_EDIT: ModeDefinition;
|
|
46
|
+
declare const CROP: ModeDefinition;
|
|
47
|
+
declare const DEFAULT_MODES: readonly ModeDefinition[];
|
|
48
|
+
declare function byId(id: string): ModeDefinition;
|
|
49
|
+
|
|
50
|
+
export { ALL_TAGS as A, type CapabilityTag as C, DEFAULT_MODES as D, FREE_TRANSFORM as F, IMPLICIT_TAGS as I, type ModeDefinition as M, NORMAL as N, PATH_EDIT as P, TEXT_EDIT as T, type WorkspaceVisual as W, CROP as a, ISOLATION as b, byId as c, eligibleForMode as e, isCapabilityTag as i };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { M as ModeDefinition, C as CapabilityTag } from './default-CdTM_d8s.js';
|
|
2
|
+
export { A as ALL_TAGS, a as CROP, D as DEFAULT_MODES, F as FREE_TRANSFORM, I as IMPLICIT_TAGS, b as ISOLATION, N as NORMAL, P as PATH_EDIT, T as TEXT_EDIT, W as WorkspaceVisual, c as byId, e as eligibleForMode, i as isCapabilityTag } from './default-CdTM_d8s.js';
|
|
3
|
+
|
|
4
|
+
interface CreateModeRegistryOptions {
|
|
5
|
+
modes: readonly ModeDefinition[];
|
|
6
|
+
initial: string;
|
|
7
|
+
}
|
|
8
|
+
interface ModeRegistry {
|
|
9
|
+
current(): ModeDefinition;
|
|
10
|
+
setMode(id: string): void;
|
|
11
|
+
byId(id: string): ModeDefinition;
|
|
12
|
+
getVersion(): number;
|
|
13
|
+
subscribe(listener: () => void): () => void;
|
|
14
|
+
}
|
|
15
|
+
declare function createModeRegistry(opts: CreateModeRegistryOptions): ModeRegistry;
|
|
16
|
+
|
|
17
|
+
/** Loose draw-command type — the kit's `DrawCommand` union shape is over in
|
|
18
|
+
* `src/renderer`. We keep this opaque to avoid a cross-package import in
|
|
19
|
+
* the type surface; consumers cast to the real DrawCommand at use site. */
|
|
20
|
+
type ModeDrawCommand = unknown;
|
|
21
|
+
type ModeDecorationPainter = () => ModeDrawCommand[];
|
|
22
|
+
interface CreateModeDecorationsOptions {
|
|
23
|
+
registry: ModeRegistry;
|
|
24
|
+
}
|
|
25
|
+
interface ModeDecorations {
|
|
26
|
+
/** Register (or replace) the painter for a mode id. */
|
|
27
|
+
register(modeId: string, painter: ModeDecorationPainter): void;
|
|
28
|
+
/** Paint the active mode's decorations. Returns an empty array if no
|
|
29
|
+
* painter is registered for the active mode. */
|
|
30
|
+
paint(): ModeDrawCommand[];
|
|
31
|
+
/** Monotonic version. Bumps on mode change or painter registration. */
|
|
32
|
+
getVersion(): number;
|
|
33
|
+
}
|
|
34
|
+
declare function createModeDecorations(opts: CreateModeDecorationsOptions): ModeDecorations;
|
|
35
|
+
|
|
36
|
+
interface ToolLike {
|
|
37
|
+
id: string;
|
|
38
|
+
capabilities?: readonly CapabilityTag[];
|
|
39
|
+
}
|
|
40
|
+
/** True iff `tool` is usable in the registry's currently active mode. */
|
|
41
|
+
declare function eligibleTool(reg: ModeRegistry, tool: ToolLike): boolean;
|
|
42
|
+
/** Same predicate against an explicit mode + tag list. Useful for palette
|
|
43
|
+
* preview ("if I were in mode X, would this tool be available?"). */
|
|
44
|
+
declare function eligibleToolByCapabilities(mode: ModeDefinition, capabilities: readonly CapabilityTag[]): boolean;
|
|
45
|
+
|
|
46
|
+
interface CreateScopingDimOptions {
|
|
47
|
+
registry: ModeRegistry;
|
|
48
|
+
/** Returns the set of node ids that are *in* scope for the current mode.
|
|
49
|
+
* The app computes this — typically: selection-only for path-edit,
|
|
50
|
+
* isolated subtree for isolation, empty for non-scoping modes. */
|
|
51
|
+
getTargetIds: () => ReadonlySet<string>;
|
|
52
|
+
/** Alpha for out-of-scope nodes. Default 0.3 (spec). */
|
|
53
|
+
dimAlpha?: number;
|
|
54
|
+
}
|
|
55
|
+
interface ScopingDim {
|
|
56
|
+
/** Multiplier in [0, 1] to apply to a node's render alpha. */
|
|
57
|
+
alphaFor(id: string): number;
|
|
58
|
+
/** Whether the node should respond to pointer hits. */
|
|
59
|
+
isPointerInteractive(id: string): boolean;
|
|
60
|
+
}
|
|
61
|
+
declare function createScopingDim(opts: CreateScopingDimOptions): ScopingDim;
|
|
62
|
+
|
|
63
|
+
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, eligibleToolByCapabilities };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export { CROP, DEFAULT_MODES, FREE_TRANSFORM, ISOLATION, NORMAL, PATH_EDIT, TEXT_EDIT, byId } from './chunk-KILROWYB.js';
|
|
2
|
+
|
|
3
|
+
// src/capabilities.ts
|
|
4
|
+
var ALL_TAGS = [
|
|
5
|
+
"navigation",
|
|
6
|
+
"creates-selection",
|
|
7
|
+
"creates-paths",
|
|
8
|
+
"creates-shapes",
|
|
9
|
+
"creates-text",
|
|
10
|
+
"edits-anchors",
|
|
11
|
+
"edits-text",
|
|
12
|
+
"transforms-selection",
|
|
13
|
+
"samples-color",
|
|
14
|
+
"applies-fill",
|
|
15
|
+
"edits-page"
|
|
16
|
+
];
|
|
17
|
+
var IMPLICIT_TAGS = ["navigation"];
|
|
18
|
+
function isCapabilityTag(value) {
|
|
19
|
+
return ALL_TAGS.includes(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/modeDefinition.ts
|
|
23
|
+
function eligibleForMode(mode, toolTags) {
|
|
24
|
+
if (toolTags.length === 0) return false;
|
|
25
|
+
const allowed = /* @__PURE__ */ new Set([...mode.allows, ...IMPLICIT_TAGS]);
|
|
26
|
+
for (const t of toolTags) {
|
|
27
|
+
if (allowed.has(t)) return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/registry.ts
|
|
33
|
+
function createModeRegistry(opts) {
|
|
34
|
+
const byIdMap = new Map(opts.modes.map((m) => [m.id, m]));
|
|
35
|
+
const initial = byIdMap.get(opts.initial);
|
|
36
|
+
if (!initial) throw new Error(`Initial mode "${opts.initial}" not in modes list`);
|
|
37
|
+
let active = initial;
|
|
38
|
+
let version = 0;
|
|
39
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
40
|
+
function bump() {
|
|
41
|
+
version++;
|
|
42
|
+
for (const l of listeners) l();
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
current: () => active,
|
|
46
|
+
setMode(id) {
|
|
47
|
+
const next = byIdMap.get(id);
|
|
48
|
+
if (!next) throw new Error(`Unknown mode id: ${id}`);
|
|
49
|
+
if (next === active) return;
|
|
50
|
+
active = next;
|
|
51
|
+
bump();
|
|
52
|
+
},
|
|
53
|
+
byId(id) {
|
|
54
|
+
const m = byIdMap.get(id);
|
|
55
|
+
if (!m) throw new Error(`Unknown mode id: ${id}`);
|
|
56
|
+
return m;
|
|
57
|
+
},
|
|
58
|
+
getVersion: () => version,
|
|
59
|
+
subscribe(listener) {
|
|
60
|
+
listeners.add(listener);
|
|
61
|
+
return () => {
|
|
62
|
+
listeners.delete(listener);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/decorations.ts
|
|
69
|
+
function createModeDecorations(opts) {
|
|
70
|
+
const { registry } = opts;
|
|
71
|
+
const painters = /* @__PURE__ */ new Map();
|
|
72
|
+
let ver = 0;
|
|
73
|
+
registry.subscribe(() => {
|
|
74
|
+
ver++;
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
register(modeId, painter) {
|
|
78
|
+
painters.set(modeId, painter);
|
|
79
|
+
ver++;
|
|
80
|
+
},
|
|
81
|
+
paint() {
|
|
82
|
+
const painter = painters.get(registry.current().id);
|
|
83
|
+
if (!painter) return [];
|
|
84
|
+
return painter();
|
|
85
|
+
},
|
|
86
|
+
getVersion: () => ver
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/eligibility.ts
|
|
91
|
+
function eligibleTool(reg, tool) {
|
|
92
|
+
return eligibleForMode(reg.current(), tool.capabilities ?? []);
|
|
93
|
+
}
|
|
94
|
+
function eligibleToolByCapabilities(mode, capabilities) {
|
|
95
|
+
return eligibleForMode(mode, capabilities);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/scopingLayer.ts
|
|
99
|
+
function createScopingDim(opts) {
|
|
100
|
+
const dim = opts.dimAlpha ?? 0.3;
|
|
101
|
+
return {
|
|
102
|
+
alphaFor(id) {
|
|
103
|
+
const mode = opts.registry.current();
|
|
104
|
+
if (!mode.scoping) return 1;
|
|
105
|
+
return opts.getTargetIds().has(id) ? 1 : dim;
|
|
106
|
+
},
|
|
107
|
+
isPointerInteractive(id) {
|
|
108
|
+
const mode = opts.registry.current();
|
|
109
|
+
if (!mode.scoping) return true;
|
|
110
|
+
return opts.getTargetIds().has(id);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { ALL_TAGS, IMPLICIT_TAGS, createModeDecorations, createModeRegistry, createScopingDim, eligibleForMode, eligibleTool, eligibleToolByCapabilities, isCapabilityTag };
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
117
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":"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","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 { ModeDefinition } from './modeDefinition';\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/** Same predicate against an explicit mode + tag list. Useful for palette\n * preview (\"if I were in mode X, would this tool be available?\"). */\nexport function eligibleToolByCapabilities(\n mode: ModeDefinition,\n capabilities: readonly CapabilityTag[],\n): boolean {\n return eligibleForMode(mode, 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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { a as CROP, D as DEFAULT_MODES, F as FREE_TRANSFORM, b as ISOLATION, N as NORMAL, P as PATH_EDIT, T as TEXT_EDIT, c as byId } from '../default-CdTM_d8s.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"default.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@weasel-js/modes",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "App-level modality primitives: capability tags, mode definitions, mode registry, and decoration layer.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./presets/default": {
|
|
16
|
+
"import": "./dist/presets/default.js",
|
|
17
|
+
"types": "./dist/presets/default.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"author": "orochi235",
|
|
22
|
+
"homepage": "https://orochi235.github.io/weasel/",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/orochi235/weasel.git",
|
|
26
|
+
"directory": "packages/modes"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/orochi235/weasel/issues"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup"
|
|
44
|
+
}
|
|
45
|
+
}
|