@fieldnotes/svelte 0.0.0-stage → 0.1.1
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 +215 -2
- package/dist/CanvasElement.svelte +59 -0
- package/dist/CanvasElement.svelte.d.ts +25 -0
- package/dist/CanvasElement.svelte.d.ts.map +1 -0
- package/dist/FieldNotesCanvas.svelte +128 -0
- package/dist/FieldNotesCanvas.svelte.d.ts +41 -0
- package/dist/FieldNotesCanvas.svelte.d.ts.map +1 -0
- package/dist/Minimap.svelte +85 -0
- package/dist/Minimap.svelte.d.ts +25 -0
- package/dist/Minimap.svelte.d.ts.map +1 -0
- package/dist/ViewportProvider.svelte +13 -0
- package/dist/ViewportProvider.svelte.d.ts +10 -0
- package/dist/ViewportProvider.svelte.d.ts.map +1 -0
- package/dist/context.d.ts +6 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +14 -0
- package/dist/helpers/from-source.svelte.d.ts +5 -0
- package/dist/helpers/from-source.svelte.d.ts.map +1 -0
- package/dist/helpers/from-source.svelte.js +25 -0
- package/dist/helpers/use-active-tool.svelte.d.ts +4 -0
- package/dist/helpers/use-active-tool.svelte.d.ts.map +1 -0
- package/dist/helpers/use-active-tool.svelte.js +8 -0
- package/dist/helpers/use-camera.svelte.d.ts +5 -0
- package/dist/helpers/use-camera.svelte.d.ts.map +1 -0
- package/dist/helpers/use-camera.svelte.js +7 -0
- package/dist/helpers/use-element-rects.svelte.d.ts +9 -0
- package/dist/helpers/use-element-rects.svelte.d.ts.map +1 -0
- package/dist/helpers/use-element-rects.svelte.js +17 -0
- package/dist/helpers/use-elements.svelte.d.ts +16 -0
- package/dist/helpers/use-elements.svelte.d.ts.map +1 -0
- package/dist/helpers/use-elements.svelte.js +10 -0
- package/dist/helpers/use-history.svelte.d.ts +10 -0
- package/dist/helpers/use-history.svelte.d.ts.map +1 -0
- package/dist/helpers/use-history.svelte.js +13 -0
- package/dist/helpers/use-layers.svelte.d.ts +21 -0
- package/dist/helpers/use-layers.svelte.d.ts.map +1 -0
- package/dist/helpers/use-layers.svelte.js +25 -0
- package/dist/helpers/use-selection-ops.svelte.d.ts +22 -0
- package/dist/helpers/use-selection-ops.svelte.d.ts.map +1 -0
- package/dist/helpers/use-selection-ops.svelte.js +27 -0
- package/dist/helpers/use-selection-style-details.svelte.d.ts +12 -0
- package/dist/helpers/use-selection-style-details.svelte.d.ts.map +1 -0
- package/dist/helpers/use-selection-style-details.svelte.js +15 -0
- package/dist/helpers/use-selection-style.svelte.d.ts +12 -0
- package/dist/helpers/use-selection-style.svelte.d.ts.map +1 -0
- package/dist/helpers/use-selection-style.svelte.js +15 -0
- package/dist/helpers/use-selection.svelte.d.ts +4 -0
- package/dist/helpers/use-selection.svelte.d.ts.map +1 -0
- package/dist/helpers/use-selection.svelte.js +7 -0
- package/dist/helpers/use-tool-options.svelte.d.ts +8 -0
- package/dist/helpers/use-tool-options.svelte.d.ts.map +1 -0
- package/dist/helpers/use-tool-options.svelte.js +28 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/package.json +58 -3
package/dist/context.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
const key = Symbol('fieldnotes.viewport');
|
|
3
|
+
/** Provides `viewport` to descendants' `useViewport()`; call during component init. */
|
|
4
|
+
export function setViewportContext(viewport) {
|
|
5
|
+
setContext(key, viewport);
|
|
6
|
+
}
|
|
7
|
+
/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */
|
|
8
|
+
export function useViewport() {
|
|
9
|
+
const viewport = getContext(key);
|
|
10
|
+
if (!viewport) {
|
|
11
|
+
throw new Error('useViewport must be used inside <FieldNotesCanvas>');
|
|
12
|
+
}
|
|
13
|
+
return viewport;
|
|
14
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { ViewportSource } from '@fieldnotes/core';
|
|
3
|
+
/** A store over `source`, live while subscribed; each `input` value resubscribes the source. */
|
|
4
|
+
export declare function fromSource<T>(source: ViewportSource<T>, input?: Readable<unknown>): Readable<T>;
|
|
5
|
+
//# sourceMappingURL=from-source.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from-source.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/from-source.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,gGAAgG;AAChG,wBAAgB,UAAU,CAAC,CAAC,EAC1B,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,EACzB,KAAK,GAAE,QAAQ,CAAC,OAAO,CAAkB,GACxC,QAAQ,CAAC,CAAC,CAAC,CAqBb"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readable } from 'svelte/store';
|
|
2
|
+
/** A store over `source`, live while subscribed; each `input` value resubscribes the source. */
|
|
3
|
+
export function fromSource(source, input = readable(null)) {
|
|
4
|
+
let current = source.getSnapshot();
|
|
5
|
+
return readable(current, (set) => {
|
|
6
|
+
// Svelte's store equality treats every object as changed, so compare references here.
|
|
7
|
+
const update = () => {
|
|
8
|
+
const next = source.getSnapshot();
|
|
9
|
+
if (next === current)
|
|
10
|
+
return;
|
|
11
|
+
current = next;
|
|
12
|
+
set(next);
|
|
13
|
+
};
|
|
14
|
+
let off;
|
|
15
|
+
const offInput = input.subscribe(() => {
|
|
16
|
+
off?.();
|
|
17
|
+
off = source.subscribe(update);
|
|
18
|
+
update();
|
|
19
|
+
});
|
|
20
|
+
return () => {
|
|
21
|
+
offInput();
|
|
22
|
+
off?.();
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
/** `[activeToolName, setTool]` — the name updates on tool switches; `''` with no active tool. */
|
|
3
|
+
export declare function useActiveTool(): [Readable<string>, (name: string) => void];
|
|
4
|
+
//# sourceMappingURL=use-active-tool.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-active-tool.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-active-tool.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C,iGAAiG;AACjG,wBAAgB,aAAa,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,CAG1E"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createActiveToolSource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
/** `[activeToolName, setTool]` — the name updates on tool switches; `''` with no active tool. */
|
|
5
|
+
export function useActiveTool() {
|
|
6
|
+
const viewport = useViewport();
|
|
7
|
+
return [fromSource(createActiveToolSource(viewport)), (name) => viewport.setTool(name)];
|
|
8
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { CameraState } from '@fieldnotes/core';
|
|
3
|
+
/** Current camera position and zoom level — updates whenever the camera moves or zoom changes. */
|
|
4
|
+
export declare function useCamera(): Readable<CameraState>;
|
|
5
|
+
//# sourceMappingURL=use-camera.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-camera.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-camera.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,kGAAkG;AAClG,wBAAgB,SAAS,IAAI,QAAQ,CAAC,WAAW,CAAC,CAEjD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createCameraSource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
/** Current camera position and zoom level — updates whenever the camera moves or zoom changes. */
|
|
5
|
+
export function useCamera() {
|
|
6
|
+
return fromSource(createCameraSource(useViewport()));
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { ElementRect, ElementRectMatch } from '@fieldnotes/core';
|
|
3
|
+
/**
|
|
4
|
+
* World rects of the elements a host matcher selects, updating only when a
|
|
5
|
+
* tracked field changes. Camera motion never updates: position content under
|
|
6
|
+
* one camera transform and let the browser composite it. `match` is fixed at init.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useElementRects(match: ElementRectMatch): Readable<readonly ElementRect[]>;
|
|
9
|
+
//# sourceMappingURL=use-element-rects.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-element-rects.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-element-rects.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGtE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,QAAQ,CAAC,SAAS,WAAW,EAAE,CAAC,CAQzF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { readable } from 'svelte/store';
|
|
2
|
+
import { ElementRectTracker } from '@fieldnotes/core';
|
|
3
|
+
import { useViewport } from '../context.js';
|
|
4
|
+
/**
|
|
5
|
+
* World rects of the elements a host matcher selects, updating only when a
|
|
6
|
+
* tracked field changes. Camera motion never updates: position content under
|
|
7
|
+
* one camera transform and let the browser composite it. `match` is fixed at init.
|
|
8
|
+
*/
|
|
9
|
+
export function useElementRects(match) {
|
|
10
|
+
const viewport = useViewport();
|
|
11
|
+
return readable([], (set) => {
|
|
12
|
+
const tracker = new ElementRectTracker(viewport, { match });
|
|
13
|
+
set(tracker.getRects());
|
|
14
|
+
tracker.onChange(set);
|
|
15
|
+
return () => tracker.dispose();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { CanvasElement, ElementType } from '@fieldnotes/core';
|
|
3
|
+
/** All elements; updates on every store mutation (use a selector for hot paths). */
|
|
4
|
+
export declare function useElements(): Readable<CanvasElement[]>;
|
|
5
|
+
/** Elements of one type; updates on every store mutation. */
|
|
6
|
+
export declare function useElements<T extends ElementType>(type: T): Readable<Extract<CanvasElement, {
|
|
7
|
+
type: T;
|
|
8
|
+
}>[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Derived value; updates only when the selected value changes (per `isEqual`,
|
|
11
|
+
* default: one-level shallow compare — arrays by index, plain objects by key, primitives by
|
|
12
|
+
* Object.is). Supply `isEqual` for deeper structures: selectors returning nested fresh objects
|
|
13
|
+
* still need a custom comparator because the default only compares one level deep.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useElements<R>(selector: (elements: CanvasElement[]) => R, isEqual?: (a: R, b: R) => boolean): Readable<R>;
|
|
16
|
+
//# sourceMappingURL=use-elements.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-elements.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-elements.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAInE,oFAAoF;AACpF,wBAAgB,WAAW,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;AACzD,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,CAAC,SAAS,WAAW,EAC/C,IAAI,EAAE,CAAC,GACN,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,EAAE,CAAC,CAAC;AACnD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,QAAQ,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,CAAC,EAC1C,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,GAChC,QAAQ,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createElementsSelectorSource, createElementsSource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
export function useElements(arg, isEqual) {
|
|
5
|
+
const viewport = useViewport();
|
|
6
|
+
if (typeof arg === 'function') {
|
|
7
|
+
return fromSource(createElementsSelectorSource(viewport, () => arg, () => isEqual));
|
|
8
|
+
}
|
|
9
|
+
return fromSource(createElementsSource(viewport, () => arg));
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { HistoryState } from '@fieldnotes/core';
|
|
3
|
+
/** Result of {@link useHistory}. */
|
|
4
|
+
export type UseHistoryResult = Readable<HistoryState> & {
|
|
5
|
+
undo(): void;
|
|
6
|
+
redo(): void;
|
|
7
|
+
};
|
|
8
|
+
/** `$history` is `{ canUndo, canRedo }`; `history.undo()` / `history.redo()` act on the viewport. */
|
|
9
|
+
export declare function useHistory(): UseHistoryResult;
|
|
10
|
+
//# sourceMappingURL=use-history.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-history.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-history.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,oCAAoC;AACpC,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,YAAY,CAAC,GAAG;IAAE,IAAI,IAAI,IAAI,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,CAAC;AAEvF,qGAAqG;AACrG,wBAAgB,UAAU,IAAI,gBAAgB,CAQ7C"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createHistorySource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
/** `$history` is `{ canUndo, canRedo }`; `history.undo()` / `history.redo()` act on the viewport. */
|
|
5
|
+
export function useHistory() {
|
|
6
|
+
const viewport = useViewport();
|
|
7
|
+
const { subscribe } = fromSource(createHistorySource(viewport));
|
|
8
|
+
return {
|
|
9
|
+
subscribe,
|
|
10
|
+
undo: () => viewport.undo(),
|
|
11
|
+
redo: () => viewport.redo(),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { Layer, LayersState } from '@fieldnotes/core';
|
|
3
|
+
/** Result of {@link useLayers}. */
|
|
4
|
+
export type UseLayersResult = Readable<LayersState> & {
|
|
5
|
+
createLayer: (name?: string) => Layer;
|
|
6
|
+
removeLayer: (id: string) => void;
|
|
7
|
+
renameLayer: (id: string, name: string) => void;
|
|
8
|
+
reorderLayer: (id: string, newOrder: number) => void;
|
|
9
|
+
setVisible: (id: string, visible: boolean) => void;
|
|
10
|
+
setLocked: (id: string, locked: boolean) => void;
|
|
11
|
+
setOpacity: (id: string, opacity: number) => void;
|
|
12
|
+
setActiveLayer: (id: string) => void;
|
|
13
|
+
moveElement: (elementId: string, layerId: string) => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Current layer list (`$layers.layers`, `$layers.activeLayerId`) and mutation helpers — updates
|
|
17
|
+
* whenever a layer is added, removed, reordered, renamed, or its visibility/lock/opacity/active
|
|
18
|
+
* state changes.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useLayers(): UseLayersResult;
|
|
21
|
+
//# sourceMappingURL=use-layers.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-layers.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-layers.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI3D,mCAAmC;AACnC,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG;IACpD,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,KAAK,CAAC;IACtC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACnD,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,eAAe,CAgB3C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createLayersSource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
/**
|
|
5
|
+
* Current layer list (`$layers.layers`, `$layers.activeLayerId`) and mutation helpers — updates
|
|
6
|
+
* whenever a layer is added, removed, reordered, renamed, or its visibility/lock/opacity/active
|
|
7
|
+
* state changes.
|
|
8
|
+
*/
|
|
9
|
+
export function useLayers() {
|
|
10
|
+
const viewport = useViewport();
|
|
11
|
+
const layerManager = viewport.layerManager;
|
|
12
|
+
const { subscribe } = fromSource(createLayersSource(viewport));
|
|
13
|
+
return {
|
|
14
|
+
subscribe,
|
|
15
|
+
createLayer: (name) => layerManager.createLayer(name),
|
|
16
|
+
removeLayer: (id) => layerManager.removeLayer(id),
|
|
17
|
+
renameLayer: (id, name) => layerManager.renameLayer(id, name),
|
|
18
|
+
reorderLayer: (id, newOrder) => layerManager.reorderLayer(id, newOrder),
|
|
19
|
+
setVisible: (id, visible) => layerManager.setLayerVisible(id, visible),
|
|
20
|
+
setLocked: (id, locked) => layerManager.setLayerLocked(id, locked),
|
|
21
|
+
setOpacity: (id, opacity) => layerManager.setLayerOpacity(id, opacity),
|
|
22
|
+
setActiveLayer: (id) => layerManager.setActiveLayer(id),
|
|
23
|
+
moveElement: (elementId, layerId) => layerManager.moveElementToLayer(elementId, layerId),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { AlignEdge, DistributeAxis, SelectionOpsState } from '@fieldnotes/core';
|
|
3
|
+
/** Result of {@link useSelectionOps}. */
|
|
4
|
+
export type UseSelectionOpsResult = Readable<SelectionOpsState & {
|
|
5
|
+
selectedCount: number;
|
|
6
|
+
}> & {
|
|
7
|
+
group: () => void;
|
|
8
|
+
ungroup: () => void;
|
|
9
|
+
toggleLock: () => void;
|
|
10
|
+
align: (edge: AlignEdge) => void;
|
|
11
|
+
distribute: (axis: DistributeAxis) => void;
|
|
12
|
+
rotateCW: () => void;
|
|
13
|
+
rotateCCW: () => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Selection operations + derived predicates for the current selection.
|
|
17
|
+
* Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;
|
|
18
|
+
* `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,
|
|
19
|
+
* and `null` when empty or mixed. Actions delegate to the core Viewport.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useSelectionOps(): UseSelectionOpsResult;
|
|
22
|
+
//# sourceMappingURL=use-selection-ops.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-selection-ops.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-selection-ops.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrF,yCAAyC;AACzC,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC,iBAAiB,GAAG;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG;IAC5F,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,KAAK,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,qBAAqB,CAgBvD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { derived } from 'svelte/store';
|
|
2
|
+
import { createSelectionOpsSource } from '@fieldnotes/core';
|
|
3
|
+
import { useViewport } from '../context.js';
|
|
4
|
+
import { fromSource } from './from-source.svelte.js';
|
|
5
|
+
/**
|
|
6
|
+
* Selection operations + derived predicates for the current selection.
|
|
7
|
+
* Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;
|
|
8
|
+
* `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,
|
|
9
|
+
* and `null` when empty or mixed. Actions delegate to the core Viewport.
|
|
10
|
+
*/
|
|
11
|
+
export function useSelectionOps() {
|
|
12
|
+
const viewport = useViewport();
|
|
13
|
+
const { subscribe } = derived(fromSource(createSelectionOpsSource(viewport)), (state) => ({
|
|
14
|
+
...state,
|
|
15
|
+
selectedCount: state.selectedIds.length,
|
|
16
|
+
}));
|
|
17
|
+
return {
|
|
18
|
+
subscribe,
|
|
19
|
+
group: () => viewport.groupSelection(),
|
|
20
|
+
ungroup: () => viewport.ungroupSelection(),
|
|
21
|
+
toggleLock: () => viewport.toggleLockSelection(),
|
|
22
|
+
align: (edge) => viewport.alignSelection(edge),
|
|
23
|
+
distribute: (axis) => viewport.distributeSelection(axis),
|
|
24
|
+
rotateCW: () => viewport.rotateSelection('cw'),
|
|
25
|
+
rotateCCW: () => viewport.rotateSelection('ccw'),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';
|
|
3
|
+
/**
|
|
4
|
+
* Style details of the current selection: per-field applicability and
|
|
5
|
+
* mixed-state, plus the common style. `null` when nothing valid is selected.
|
|
6
|
+
* The apply function delegates to `applyStyleToSelection` (one undo step).
|
|
7
|
+
*/
|
|
8
|
+
export declare function useSelectionStyleDetails(): [
|
|
9
|
+
Readable<SelectionStyleDetails | null>,
|
|
10
|
+
(style: ElementStyle) => void
|
|
11
|
+
];
|
|
12
|
+
//# sourceMappingURL=use-selection-style-details.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-selection-style-details.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-selection-style-details.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAI5E;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI;IAC1C,QAAQ,CAAC,qBAAqB,GAAG,IAAI,CAAC;IACtC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI;CAC9B,CAMA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createSelectionStyleDetailsSource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
/**
|
|
5
|
+
* Style details of the current selection: per-field applicability and
|
|
6
|
+
* mixed-state, plus the common style. `null` when nothing valid is selected.
|
|
7
|
+
* The apply function delegates to `applyStyleToSelection` (one undo step).
|
|
8
|
+
*/
|
|
9
|
+
export function useSelectionStyleDetails() {
|
|
10
|
+
const viewport = useViewport();
|
|
11
|
+
return [
|
|
12
|
+
fromSource(createSelectionStyleDetailsSource(viewport)),
|
|
13
|
+
(style) => viewport.applyStyleToSelection(style),
|
|
14
|
+
];
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
import type { ElementStyle } from '@fieldnotes/core';
|
|
3
|
+
/**
|
|
4
|
+
* Normalized style of the current selection.
|
|
5
|
+
* Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.
|
|
6
|
+
* `applyPatch` applies an `ElementStyle` patch to every selected element.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useSelectionStyle(): [
|
|
9
|
+
Readable<ElementStyle | null>,
|
|
10
|
+
(style: ElementStyle) => void
|
|
11
|
+
];
|
|
12
|
+
//# sourceMappingURL=use-selection-style.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-selection-style.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-selection-style.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI;IACnC,QAAQ,CAAC,YAAY,GAAG,IAAI,CAAC;IAC7B,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI;CAC9B,CAMA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createSelectionStyleSource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
/**
|
|
5
|
+
* Normalized style of the current selection.
|
|
6
|
+
* Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.
|
|
7
|
+
* `applyPatch` applies an `ElementStyle` patch to every selected element.
|
|
8
|
+
*/
|
|
9
|
+
export function useSelectionStyle() {
|
|
10
|
+
const viewport = useViewport();
|
|
11
|
+
return [
|
|
12
|
+
fromSource(createSelectionStyleSource(viewport)),
|
|
13
|
+
(style) => viewport.applyStyleToSelection(style),
|
|
14
|
+
];
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-selection.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-selection.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C,8FAA8F;AAC9F,wBAAgB,YAAY,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC,CAEjD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createSelectionSource } from '@fieldnotes/core';
|
|
2
|
+
import { useViewport } from '../context.js';
|
|
3
|
+
import { fromSource } from './from-source.svelte.js';
|
|
4
|
+
/** Selected element ids. Stable array reference — only changes when the selection changes. */
|
|
5
|
+
export function useSelection() {
|
|
6
|
+
return fromSource(createSelectionSource(useViewport()));
|
|
7
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Readable } from 'svelte/store';
|
|
2
|
+
/**
|
|
3
|
+
* `[options, setOptions]` for the named tool — updates when the tool's options change.
|
|
4
|
+
* `options` is `null` if the tool is not registered or does not expose options.
|
|
5
|
+
* A getter `toolName` is tracked: the store resubscribes to the new tool.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useToolOptions<T extends Record<string, unknown>>(toolName: string | (() => string)): [Readable<T | null>, (partial: Partial<T>) => void];
|
|
8
|
+
//# sourceMappingURL=use-tool-options.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tool-options.svelte.d.ts","sourceRoot":"","sources":["../../src/helpers/use-tool-options.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,QAAQ,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,GAChC,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAiBrD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { get, writable } from 'svelte/store';
|
|
2
|
+
import { createToolOptionsSource } from '@fieldnotes/core';
|
|
3
|
+
import { useViewport } from '../context.js';
|
|
4
|
+
import { fromSource } from './from-source.svelte.js';
|
|
5
|
+
/**
|
|
6
|
+
* `[options, setOptions]` for the named tool — updates when the tool's options change.
|
|
7
|
+
* `options` is `null` if the tool is not registered or does not expose options.
|
|
8
|
+
* A getter `toolName` is tracked: the store resubscribes to the new tool.
|
|
9
|
+
*/
|
|
10
|
+
export function useToolOptions(toolName) {
|
|
11
|
+
const viewport = useViewport();
|
|
12
|
+
let getName;
|
|
13
|
+
let input;
|
|
14
|
+
if (typeof toolName === 'string') {
|
|
15
|
+
getName = () => toolName;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const name = writable(toolName());
|
|
19
|
+
$effect.pre(() => name.set(toolName()));
|
|
20
|
+
getName = () => get(name);
|
|
21
|
+
input = name;
|
|
22
|
+
}
|
|
23
|
+
const options = fromSource(createToolOptionsSource(viewport, getName), input);
|
|
24
|
+
const setOptions = (partial) => {
|
|
25
|
+
viewport.toolManager.getTool(getName())?.setOptions?.(partial);
|
|
26
|
+
};
|
|
27
|
+
return [options, setOptions];
|
|
28
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { default as FieldNotesCanvas } from './FieldNotesCanvas.svelte';
|
|
2
|
+
export type { FieldNotesCanvasProps } from './FieldNotesCanvas.svelte';
|
|
3
|
+
export { setViewportContext, useViewport } from './context.js';
|
|
4
|
+
export { default as CanvasElement } from './CanvasElement.svelte';
|
|
5
|
+
export type { CanvasElementProps } from './CanvasElement.svelte';
|
|
6
|
+
export { default as Minimap } from './Minimap.svelte';
|
|
7
|
+
export type { MinimapProps } from './Minimap.svelte';
|
|
8
|
+
export { useCamera } from './helpers/use-camera.svelte.js';
|
|
9
|
+
export { useElements } from './helpers/use-elements.svelte.js';
|
|
10
|
+
export { useSelection } from './helpers/use-selection.svelte.js';
|
|
11
|
+
export { useActiveTool } from './helpers/use-active-tool.svelte.js';
|
|
12
|
+
export { useToolOptions } from './helpers/use-tool-options.svelte.js';
|
|
13
|
+
export { useSelectionStyle } from './helpers/use-selection-style.svelte.js';
|
|
14
|
+
export { useSelectionStyleDetails } from './helpers/use-selection-style-details.svelte.js';
|
|
15
|
+
export { useHistory } from './helpers/use-history.svelte.js';
|
|
16
|
+
export type { UseHistoryResult } from './helpers/use-history.svelte.js';
|
|
17
|
+
export { useLayers } from './helpers/use-layers.svelte.js';
|
|
18
|
+
export type { UseLayersResult } from './helpers/use-layers.svelte.js';
|
|
19
|
+
export { useSelectionOps } from './helpers/use-selection-ops.svelte.js';
|
|
20
|
+
export type { UseSelectionOpsResult } from './helpers/use-selection-ops.svelte.js';
|
|
21
|
+
export { useElementRects } from './helpers/use-element-rects.svelte.js';
|
|
22
|
+
export type { AlignEdge, CameraState, DistributeAxis, ElementRect, ElementStyle, HistoryState, LayersState, SelectionOpsState, SelectionStyleDetails, } from '@fieldnotes/core';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAC3F,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,YAAY,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,YAAY,EACV,SAAS,EACT,WAAW,EACX,cAAc,EACd,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { default as FieldNotesCanvas } from './FieldNotesCanvas.svelte';
|
|
2
|
+
export { setViewportContext, useViewport } from './context.js';
|
|
3
|
+
export { default as CanvasElement } from './CanvasElement.svelte';
|
|
4
|
+
export { default as Minimap } from './Minimap.svelte';
|
|
5
|
+
export { useCamera } from './helpers/use-camera.svelte.js';
|
|
6
|
+
export { useElements } from './helpers/use-elements.svelte.js';
|
|
7
|
+
export { useSelection } from './helpers/use-selection.svelte.js';
|
|
8
|
+
export { useActiveTool } from './helpers/use-active-tool.svelte.js';
|
|
9
|
+
export { useToolOptions } from './helpers/use-tool-options.svelte.js';
|
|
10
|
+
export { useSelectionStyle } from './helpers/use-selection-style.svelte.js';
|
|
11
|
+
export { useSelectionStyleDetails } from './helpers/use-selection-style-details.svelte.js';
|
|
12
|
+
export { useHistory } from './helpers/use-history.svelte.js';
|
|
13
|
+
export { useLayers } from './helpers/use-layers.svelte.js';
|
|
14
|
+
export { useSelectionOps } from './helpers/use-selection-ops.svelte.js';
|
|
15
|
+
export { useElementRects } from './helpers/use-element-rects.svelte.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fieldnotes/svelte",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Svelte wrapper for Field Notes canvas SDK",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"svelte": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"svelte": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"!dist/**/*.test.*",
|
|
19
|
+
"!dist/test-fixtures",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/IrakliDevelop/fieldnotes.git",
|
|
26
|
+
"directory": "packages/svelte"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/IrakliDevelop/fieldnotes/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/IrakliDevelop/fieldnotes/tree/master/packages/svelte#readme",
|
|
32
|
+
"keywords": [
|
|
33
|
+
"canvas",
|
|
34
|
+
"infinite-canvas",
|
|
35
|
+
"svelte",
|
|
36
|
+
"html-embedding",
|
|
37
|
+
"fieldnotes"
|
|
38
|
+
],
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@fieldnotes/core": ">=0.98.0 <1.0.0",
|
|
41
|
+
"svelte": ">=5 <6"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@sveltejs/package": "^3.0.1",
|
|
45
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
46
|
+
"@testing-library/svelte": "^5.4.2",
|
|
47
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
48
|
+
"jsdom": "^29.1.1",
|
|
49
|
+
"svelte": "^5.57.2",
|
|
50
|
+
"svelte-check": "^4.7.7",
|
|
51
|
+
"vitest": "^5.0.5",
|
|
52
|
+
"@fieldnotes/core": "0.98.0"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "svelte-package -i src -o dist",
|
|
56
|
+
"typecheck": "svelte-check --tsconfig ./tsconfig.json --fail-on-warnings",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:coverage": "vitest run --coverage",
|
|
59
|
+
"test:watch": "vitest"
|
|
60
|
+
}
|
|
6
61
|
}
|