@bensitu/image-editor 1.5.2 → 2.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/README.md +367 -518
- package/dist/cjs/index.cjs +5422 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/esm/animation/animation-queue.js +67 -0
- package/dist/esm/animation/animation-queue.js.map +1 -0
- package/dist/esm/core/callback-reporter.js +23 -0
- package/dist/esm/core/callback-reporter.js.map +1 -0
- package/dist/esm/core/default-options.js +322 -0
- package/dist/esm/core/default-options.js.map +1 -0
- package/dist/esm/core/errors.js +156 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/operation-guard.js +129 -0
- package/dist/esm/core/operation-guard.js.map +1 -0
- package/dist/esm/core/public-types.js +4 -0
- package/dist/esm/core/public-types.js.map +1 -0
- package/dist/esm/core/state-serializer.js +251 -0
- package/dist/esm/core/state-serializer.js.map +1 -0
- package/dist/esm/crop/crop-controller.js +403 -0
- package/dist/esm/crop/crop-controller.js.map +1 -0
- package/dist/esm/export/export-format.js +53 -0
- package/dist/esm/export/export-format.js.map +1 -0
- package/dist/esm/export/export-service.js +596 -0
- package/dist/esm/export/export-service.js.map +1 -0
- package/dist/esm/fabric/fabric-adapter.js +37 -0
- package/dist/esm/fabric/fabric-adapter.js.map +1 -0
- package/dist/esm/fabric/fabric-animation.js +37 -0
- package/dist/esm/fabric/fabric-animation.js.map +1 -0
- package/dist/esm/history/command.js +2 -0
- package/dist/esm/history/command.js.map +1 -0
- package/dist/esm/history/history-manager.js +103 -0
- package/dist/esm/history/history-manager.js.map +1 -0
- package/dist/esm/image/image-loader.js +245 -0
- package/dist/esm/image/image-loader.js.map +1 -0
- package/dist/esm/image/image-resampler.js +55 -0
- package/dist/esm/image/image-resampler.js.map +1 -0
- package/dist/esm/image/layout-manager.js +224 -0
- package/dist/esm/image/layout-manager.js.map +1 -0
- package/dist/esm/image/transform-controller.js +132 -0
- package/dist/esm/image/transform-controller.js.map +1 -0
- package/dist/esm/image-editor.js +1740 -0
- package/dist/esm/image-editor.js.map +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/mask/mask-factory.js +332 -0
- package/dist/esm/mask/mask-factory.js.map +1 -0
- package/dist/esm/mask/mask-label-manager.js +120 -0
- package/dist/esm/mask/mask-label-manager.js.map +1 -0
- package/dist/esm/mask/mask-list.js +47 -0
- package/dist/esm/mask/mask-list.js.map +1 -0
- package/dist/esm/mask/mask-style.js +182 -0
- package/dist/esm/mask/mask-style.js.map +1 -0
- package/dist/esm/ui/dom-bindings.js +60 -0
- package/dist/esm/ui/dom-bindings.js.map +1 -0
- package/dist/esm/ui/ui-state.js +25 -0
- package/dist/esm/ui/ui-state.js.map +1 -0
- package/dist/esm/ui/visibility-state.js +11 -0
- package/dist/esm/ui/visibility-state.js.map +1 -0
- package/dist/esm/utils/canvas-region.js +100 -0
- package/dist/esm/utils/canvas-region.js.map +1 -0
- package/dist/esm/utils/dom.js +6 -0
- package/dist/esm/utils/dom.js.map +1 -0
- package/dist/esm/utils/file.js +53 -0
- package/dist/esm/utils/file.js.map +1 -0
- package/dist/esm/utils/number.js +24 -0
- package/dist/esm/utils/number.js.map +1 -0
- package/dist/esm/utils/timeout.js +17 -0
- package/dist/esm/utils/timeout.js.map +1 -0
- package/dist/types/animation/animation-queue.d.ts +111 -0
- package/dist/types/animation/animation-queue.d.ts.map +1 -0
- package/dist/types/core/callback-reporter.d.ts +125 -0
- package/dist/types/core/callback-reporter.d.ts.map +1 -0
- package/dist/types/core/default-options.d.ts +56 -0
- package/dist/types/core/default-options.d.ts.map +1 -0
- package/dist/types/core/errors.d.ts +142 -0
- package/dist/types/core/errors.d.ts.map +1 -0
- package/dist/types/core/operation-guard.d.ts +192 -0
- package/dist/types/core/operation-guard.d.ts.map +1 -0
- package/dist/types/core/public-types.d.ts +678 -0
- package/dist/types/core/public-types.d.ts.map +1 -0
- package/dist/types/core/state-serializer.d.ts +301 -0
- package/dist/types/core/state-serializer.d.ts.map +1 -0
- package/dist/types/crop/crop-controller.d.ts +407 -0
- package/dist/types/crop/crop-controller.d.ts.map +1 -0
- package/dist/types/export/export-format.d.ts +136 -0
- package/dist/types/export/export-format.d.ts.map +1 -0
- package/dist/types/export/export-service.d.ts +333 -0
- package/dist/types/export/export-service.d.ts.map +1 -0
- package/dist/types/fabric/fabric-adapter.d.ts +74 -0
- package/dist/types/fabric/fabric-adapter.d.ts.map +1 -0
- package/dist/types/fabric/fabric-animation.d.ts +141 -0
- package/dist/types/fabric/fabric-animation.d.ts.map +1 -0
- package/dist/types/history/command.d.ts +16 -0
- package/dist/types/history/command.d.ts.map +1 -0
- package/dist/types/history/history-manager.d.ts +129 -0
- package/dist/types/history/history-manager.d.ts.map +1 -0
- package/dist/types/image/image-loader.d.ts +265 -0
- package/dist/types/image/image-loader.d.ts.map +1 -0
- package/dist/types/image/image-resampler.d.ts +139 -0
- package/dist/types/image/image-resampler.d.ts.map +1 -0
- package/dist/types/image/layout-manager.d.ts +255 -0
- package/dist/types/image/layout-manager.d.ts.map +1 -0
- package/dist/types/image/transform-controller.d.ts +287 -0
- package/dist/types/image/transform-controller.d.ts.map +1 -0
- package/dist/types/image-editor.d.ts +650 -0
- package/dist/types/image-editor.d.ts.map +1 -0
- package/dist/types/index.d.cts +31 -0
- package/dist/types/index.d.cts.map +1 -0
- package/dist/types/index.d.ts +31 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/mask/mask-factory.d.ts +209 -0
- package/dist/types/mask/mask-factory.d.ts.map +1 -0
- package/dist/types/mask/mask-label-manager.d.ts +171 -0
- package/dist/types/mask/mask-label-manager.d.ts.map +1 -0
- package/dist/types/mask/mask-list.d.ts +144 -0
- package/dist/types/mask/mask-list.d.ts.map +1 -0
- package/dist/types/mask/mask-style.d.ts +338 -0
- package/dist/types/mask/mask-style.d.ts.map +1 -0
- package/dist/types/ui/dom-bindings.d.ts +103 -0
- package/dist/types/ui/dom-bindings.d.ts.map +1 -0
- package/dist/types/ui/ui-state.d.ts +112 -0
- package/dist/types/ui/ui-state.d.ts.map +1 -0
- package/dist/types/ui/visibility-state.d.ts +77 -0
- package/dist/types/ui/visibility-state.d.ts.map +1 -0
- package/dist/types/utils/canvas-region.d.ts +177 -0
- package/dist/types/utils/canvas-region.d.ts.map +1 -0
- package/dist/types/utils/dom.d.ts +26 -0
- package/dist/types/utils/dom.d.ts.map +1 -0
- package/dist/types/utils/file.d.ts +80 -0
- package/dist/types/utils/file.d.ts.map +1 -0
- package/dist/types/utils/number.d.ts +132 -0
- package/dist/types/utils/number.d.ts.map +1 -0
- package/dist/types/utils/timeout.d.ts +84 -0
- package/dist/types/utils/timeout.d.ts.map +1 -0
- package/dist/umd/image-editor.umd.js +2 -0
- package/dist/umd/image-editor.umd.js.map +1 -0
- package/package.json +72 -66
- package/dist/image-editor.cjs +0 -4407
- package/dist/image-editor.cjs.map +0 -7
- package/dist/image-editor.esm.js +0 -4376
- package/dist/image-editor.esm.js.map +0 -7
- package/dist/image-editor.esm.min.js +0 -9
- package/dist/image-editor.esm.min.js.map +0 -7
- package/dist/image-editor.esm.min.mjs +0 -9
- package/dist/image-editor.esm.min.mjs.map +0 -7
- package/dist/image-editor.esm.mjs +0 -4376
- package/dist/image-editor.esm.mjs.map +0 -7
- package/dist/image-editor.js +0 -4373
- package/dist/image-editor.js.map +0 -7
- package/dist/image-editor.min.js +0 -9
- package/dist/image-editor.min.js.map +0 -7
- package/image-editor.d.ts +0 -271
- package/src/browser.js +0 -11
- package/src/esm.js +0 -9
- package/src/image-editor.js +0 -5013
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hover, selection, and "original style restore" helpers for
|
|
3
|
+
* mask visual state. Owns the legacy `_getMaskNormalStyle`,
|
|
4
|
+
* `_withNormalizedMaskStyles`, `_rebindMaskEvents`, and the
|
|
5
|
+
* selected/unselected stroke logic from `_handleSelectionChanged`
|
|
6
|
+
* that were inlined on the editor in legacy and are now extracted
|
|
7
|
+
* into pure(ish) helpers that take a {@link MaskStyleContext}.
|
|
8
|
+
*
|
|
9
|
+
* Two callers consume the same backup shape:
|
|
10
|
+
*
|
|
11
|
+
* - Export bake-in (`export/export-service.ts`) — temporarily forces every
|
|
12
|
+
* mask to `opacity: 1, fill: '#000', strokeWidth: 0, stroke: null,
|
|
13
|
+
* selectable: false` so the rendered raster has solid black masks, and
|
|
14
|
+
* restores the live values inside a `finally` block whether the export
|
|
15
|
+
* succeeded or threw.
|
|
16
|
+
*
|
|
17
|
+
* - Crop session (`crop/crop-controller.ts`) — backs up the same fields plus
|
|
18
|
+
* `lockRotation` when entering crop mode and restores them on
|
|
19
|
+
* `cancelCrop`.
|
|
20
|
+
*
|
|
21
|
+
* Centralizing the backup shape, the hover style literals (`#ff5500`,
|
|
22
|
+
* `strokeWidth: 2`, `opacity = originalAlpha + 0.2`), and the
|
|
23
|
+
* selected/unselected stroke literals (`#ff0000`, `mask.originalStroke ||
|
|
24
|
+
* '#ccc'`) here means the legacy visuals stay pixel-identical and any future
|
|
25
|
+
* tweak happens in one place.
|
|
26
|
+
*
|
|
27
|
+
* ## Owned contracts
|
|
28
|
+
*
|
|
29
|
+
* - {@link captureMaskStyleBackup} captures the prior
|
|
30
|
+
* live values for `opacity`, `fill`, `stroke`, `strokeWidth`, `selectable`,
|
|
31
|
+
* `evented`, and `lockRotation` BEFORE any export-only mutation runs. The backup
|
|
32
|
+
* shape matches {@link MaskBackup} in `core/public-types.ts`.
|
|
33
|
+
*
|
|
34
|
+
* - {@link withMaskStyleBackup} runs the supplied
|
|
35
|
+
* mutator → callback inside a `try/finally` so {@link restoreMaskStyleBackup}
|
|
36
|
+
* is called regardless of whether the callback resolved or threw.
|
|
37
|
+
*
|
|
38
|
+
* - Each restored field is the exact value captured
|
|
39
|
+
* at the start of the operation; the restore performs no defaulting and
|
|
40
|
+
* no clamping, so an export-only style is never observable on any mask
|
|
41
|
+
* after the operation returns.
|
|
42
|
+
*
|
|
43
|
+
* - {@link applyCropHideMaskStyle} sets `opacity: 0`
|
|
44
|
+
* and `evented: false` on a mask so the user cannot interact with it
|
|
45
|
+
* while the crop rectangle is the only interactive object. The caller is
|
|
46
|
+
* expected to have captured a backup via {@link captureMaskStyleBackup}
|
|
47
|
+
* first.
|
|
48
|
+
*
|
|
49
|
+
* - {@link restoreMaskStyleBackup} restores
|
|
50
|
+
* `opacity`, `fill`, `strokeWidth`, `stroke`, `selectable`, `evented`,
|
|
51
|
+
* and `lockRotation` from the captured {@link MaskBackup}, matching the current
|
|
52
|
+
* documented `MaskBackup` interface.
|
|
53
|
+
*
|
|
54
|
+
* - **Mirrors legacy hover behavior** — {@link attachMaskHoverHandlers} and
|
|
55
|
+
* {@link reattachMaskHoverHandlers} bind the same `mouseover`/`mouseout`
|
|
56
|
+
* handlers legacy's `_rebindMaskEvents` used. The handlers read
|
|
57
|
+
* `mask.originalAlpha` / `mask.originalStroke` / `mask.originalStrokeWidth`
|
|
58
|
+
* on each invocation so they always reflect the current "live" state
|
|
59
|
+
* (e.g. after a stroke change from a selection event).
|
|
60
|
+
*
|
|
61
|
+
* - **Mirrors legacy selection styling** — {@link applyMaskSelectedStyle} sets
|
|
62
|
+
* the selection-highlight stroke (`#ff0000`, `strokeWidth: 1`) and
|
|
63
|
+
* {@link applyMaskUnselectedStyle} restores the normal stroke from the
|
|
64
|
+
* per-mask `originalStroke` / `originalStrokeWidth`. Both literals match
|
|
65
|
+
* legacy's `_handleSelectionChanged`.
|
|
66
|
+
*
|
|
67
|
+
* ## Out of scope (handled by sibling modules)
|
|
68
|
+
*
|
|
69
|
+
* - Mask creation, falsy-style preservation, polygon placement — see
|
|
70
|
+
* `mask/mask-factory.ts`.
|
|
71
|
+
* - Mask label overlay — see `mask/mask-label-manager.ts`.
|
|
72
|
+
* - Mask list DOM — see `mask/mask-list.ts`.
|
|
73
|
+
*
|
|
74
|
+
* ## Implementation notes
|
|
75
|
+
*
|
|
76
|
+
* - The orchestrator (`src/image-editor.ts`) owns the canvas reference and
|
|
77
|
+
* the resolved options. The helpers in this module receive those slots
|
|
78
|
+
* through a {@link MaskStyleContext} so the module is independent of the
|
|
79
|
+
* `ImageEditor` class shape and can be unit tested in isolation against
|
|
80
|
+
* a stub Fabric environment.
|
|
81
|
+
* - Hover handlers do NOT cache the normal/hover style at attach time. They
|
|
82
|
+
* read `mask.originalAlpha` / `mask.originalStroke` / `mask.originalStrokeWidth`
|
|
83
|
+
* on every event so the visual matches the live "original" values even
|
|
84
|
+
* after a stroke or opacity change (matching legacy).
|
|
85
|
+
* - The handlers are tagged on `mask.imageEditorMaskHandlers` exactly as
|
|
86
|
+
* legacy did so {@link reattachMaskHoverHandlers} can drop the old pair before
|
|
87
|
+
* binding fresh ones, avoiding duplicate listeners after `loadFromJSON`.
|
|
88
|
+
*
|
|
89
|
+
* @module
|
|
90
|
+
*/
|
|
91
|
+
import type * as FabricNS from 'fabric';
|
|
92
|
+
import type { MaskBackup, MaskObject, ResolvedOptions } from '../core/public-types.js';
|
|
93
|
+
/**
|
|
94
|
+
* State the mask-style helpers read from the `ImageEditor` orchestrator.
|
|
95
|
+
*
|
|
96
|
+
* The module does NOT own any of these slots — it only reads them so
|
|
97
|
+
* ownership of the canvas and resolved options stays on the orchestrator
|
|
98
|
+
* (where legacy left them).
|
|
99
|
+
*/
|
|
100
|
+
export interface MaskStyleContext {
|
|
101
|
+
/**
|
|
102
|
+
* The live Fabric canvas. May be `null` after `dispose` or before
|
|
103
|
+
* `init` has run; the helpers no-op in that case.
|
|
104
|
+
*/
|
|
105
|
+
canvas: FabricNS.Canvas | null;
|
|
106
|
+
/**
|
|
107
|
+
* Fully resolved editor options. Only consulted by helpers that need
|
|
108
|
+
* the export-bake-in fill (`#000` matches legacy) or the crop visibility
|
|
109
|
+
* defaults; most helpers operate on the per-mask `original*` fields
|
|
110
|
+
* and do not need this slot.
|
|
111
|
+
*/
|
|
112
|
+
options?: ResolvedOptions;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The "normal" (non-hover, non-selected) style of a mask, computed from
|
|
116
|
+
* its persisted `original*` fields. Matches the shape returned by legacy's
|
|
117
|
+
* `_getMaskNormalStyle`.
|
|
118
|
+
*/
|
|
119
|
+
export interface MaskNormalStyle {
|
|
120
|
+
stroke: FabricNS.TFiller | string | null;
|
|
121
|
+
strokeWidth: number;
|
|
122
|
+
opacity: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Compute the "normal" (non-hover, non-selected) style of `mask` from its
|
|
126
|
+
* persisted `original*` fields, with legacy-identical fallbacks.
|
|
127
|
+
*
|
|
128
|
+
* - `stroke` → `mask.originalStroke`, falling back to `'#ccc'` (legacy).
|
|
129
|
+
* - `strokeWidth` → `Number(mask.originalStrokeWidth)` if finite, else `1`.
|
|
130
|
+
* - `opacity` → `Number(mask.originalAlpha)` if finite, else `0.5`.
|
|
131
|
+
*
|
|
132
|
+
* The result is used by:
|
|
133
|
+
* - {@link applyMaskNormalStyle} to restore on `mouseout`,
|
|
134
|
+
* - {@link applyMaskUnselectedStyle} to restore the un-highlighted stroke,
|
|
135
|
+
* - export bake-in callers that want a pre-mutation snapshot of the live
|
|
136
|
+
* visual when no `MaskBackup` is being captured.
|
|
137
|
+
*
|
|
138
|
+
* @param mask - The mask to inspect.
|
|
139
|
+
* @returns A {@link MaskNormalStyle} ready to pass to `mask.set(...)`.
|
|
140
|
+
*/
|
|
141
|
+
export declare function getMaskNormalStyle(mask: MaskObject): MaskNormalStyle;
|
|
142
|
+
/**
|
|
143
|
+
* Compute the "hover" style for `mask`, derived from its normal style.
|
|
144
|
+
*
|
|
145
|
+
* - `stroke` → `'#ff5500'` (legacy).
|
|
146
|
+
* - `strokeWidth` → `2` (legacy).
|
|
147
|
+
* - `opacity` → `min(originalAlpha + 0.2, 1)` (legacy).
|
|
148
|
+
*
|
|
149
|
+
* @param mask - The mask to inspect.
|
|
150
|
+
* @returns A style patch ready to pass to `mask.set(...)`.
|
|
151
|
+
*/
|
|
152
|
+
export declare function getMaskHoverStyle(mask: MaskObject): MaskNormalStyle;
|
|
153
|
+
/**
|
|
154
|
+
* Apply the selected-mask highlight stroke. Matches legacy's literal
|
|
155
|
+
* (`stroke: '#ff0000'`, `strokeWidth: 1`).
|
|
156
|
+
*
|
|
157
|
+
* Does NOT change opacity — the selection highlight only modifies the
|
|
158
|
+
* outline so the user can still see the mask's tinted fill.
|
|
159
|
+
*
|
|
160
|
+
* @param mask - The mask becoming selected.
|
|
161
|
+
*/
|
|
162
|
+
export declare function applyMaskSelectedStyle(mask: MaskObject): void;
|
|
163
|
+
/**
|
|
164
|
+
* Restore the un-highlighted stroke on `mask` after selection moves to a
|
|
165
|
+
* different object. Reads the per-mask `originalStroke`/`originalStrokeWidth`
|
|
166
|
+
* (matching legacy's `_handleSelectionChanged`) so the value is the one the
|
|
167
|
+
* mask carried before any selection-time mutation.
|
|
168
|
+
*
|
|
169
|
+
* Does NOT touch `opacity` — the un-highlighted state retains the live
|
|
170
|
+
* opacity (which may differ from `originalAlpha` while a hover is in
|
|
171
|
+
* progress, etc.).
|
|
172
|
+
*
|
|
173
|
+
* @param mask - The mask becoming un-selected.
|
|
174
|
+
*/
|
|
175
|
+
export declare function applyMaskUnselectedStyle(mask: MaskObject): void;
|
|
176
|
+
/**
|
|
177
|
+
* Bind `mouseover`/`mouseout` handlers on `mask` that toggle the legacy hover
|
|
178
|
+
* highlight. The handlers re-read `mask.originalAlpha` /
|
|
179
|
+
* `mask.originalStroke` / `mask.originalStrokeWidth` on each event so they
|
|
180
|
+
* track any post-attach mutation (matching legacy's `_rebindMaskEvents`).
|
|
181
|
+
*
|
|
182
|
+
* Handlers are tagged on `mask.imageEditorMaskHandlers` so
|
|
183
|
+
* {@link reattachMaskHoverHandlers} can drop them before binding a new
|
|
184
|
+
* pair, avoiding duplicates after a `loadFromJSON` restore.
|
|
185
|
+
*
|
|
186
|
+
* Idempotent — calling twice on the same mask without an intervening
|
|
187
|
+
* detach simply produces two pairs of listeners. Use
|
|
188
|
+
* {@link reattachMaskHoverHandlers} to refresh listeners safely.
|
|
189
|
+
*
|
|
190
|
+
* @param mask - The mask to bind handlers on.
|
|
191
|
+
*/
|
|
192
|
+
export declare function attachMaskHoverHandlers(mask: MaskObject): void;
|
|
193
|
+
/**
|
|
194
|
+
* Drop any previously-attached hover handler pair (best-effort) and bind a
|
|
195
|
+
* fresh pair via {@link attachMaskHoverHandlers}.
|
|
196
|
+
*
|
|
197
|
+
* Used after `canvas.loadFromJSON` in `core/state-serializer.ts`'s
|
|
198
|
+
* `loadFromState` flow, because Fabric never serializes event listeners,
|
|
199
|
+
* so masks restored from history have lost their hover styling. The
|
|
200
|
+
* orchestrator re-runs this helper for every restored mask.
|
|
201
|
+
*
|
|
202
|
+
* Also re-asserts the persisted `original*` metadata when missing — legacy's
|
|
203
|
+
* `_rebindMaskEvents` did the same so a snapshot from an older format that
|
|
204
|
+
* happens to lack `originalStroke`/`originalStrokeWidth` still hovers
|
|
205
|
+
* correctly. The current Pretty_Printer always serializes
|
|
206
|
+
* `originalAlpha`, but we defend against partial payloads here too.
|
|
207
|
+
*
|
|
208
|
+
* @param mask - The mask to refresh handlers on.
|
|
209
|
+
*/
|
|
210
|
+
export declare function reattachMaskHoverHandlers(mask: MaskObject): void;
|
|
211
|
+
/**
|
|
212
|
+
* Detach the hover handler pair previously bound by
|
|
213
|
+
* {@link attachMaskHoverHandlers} (or {@link reattachMaskHoverHandlers}).
|
|
214
|
+
*
|
|
215
|
+
* Best-effort — wraps each `off(...)` in `try/catch` so a stale Fabric
|
|
216
|
+
* reference does not break callers that iterate every mask (e.g. the
|
|
217
|
+
* `dispose` path or `removeAllMasks`).
|
|
218
|
+
*
|
|
219
|
+
* @param mask - The mask to detach handlers from.
|
|
220
|
+
*/
|
|
221
|
+
export declare function detachMaskHoverHandlers(mask: MaskObject): void;
|
|
222
|
+
/**
|
|
223
|
+
* Snapshot the current live values of the fields that both the export
|
|
224
|
+
* bake-in path and the crop session need to restore later.
|
|
225
|
+
*
|
|
226
|
+
* Captured fields:
|
|
227
|
+
*
|
|
228
|
+
* - `opacity` — restored when the export ends or the crop is canceled.
|
|
229
|
+
* - `fill` — export bake-in temporarily forces `'#000'`; crop never
|
|
230
|
+
* changes fill but captures it so a single restore call works for both.
|
|
231
|
+
* - `strokeWidth` — export bake-in forces `0`.
|
|
232
|
+
* - `stroke` — export bake-in forces `null`.
|
|
233
|
+
* - `selectable` — both paths force `false` so the mask is not draggable
|
|
234
|
+
* while the operation is in progress.
|
|
235
|
+
* - `evented` — the crop session forces `false` while the crop rectangle is
|
|
236
|
+
* the only interactive object.
|
|
237
|
+
* - `lockRotation` — the crop session captures this because some integrators
|
|
238
|
+
* set `maskRotatable: true` and the rotation lock is part of the
|
|
239
|
+
* per-mask state.
|
|
240
|
+
*
|
|
241
|
+
* Defaults match legacy: missing `opacity` → `1`, missing `selectable` →
|
|
242
|
+
* `true`, missing `lockRotation` → `false`. They never override a
|
|
243
|
+
* caller-supplied value because the snapshot reads from the live mask.
|
|
244
|
+
*
|
|
245
|
+
* @param mask - The mask whose live style should be captured.
|
|
246
|
+
* @returns A {@link MaskBackup} suitable for passing to
|
|
247
|
+
* {@link restoreMaskStyleBackup}.
|
|
248
|
+
*/
|
|
249
|
+
export declare function captureMaskStyleBackup(mask: MaskObject): MaskBackup;
|
|
250
|
+
/**
|
|
251
|
+
* Restore every backed-up field from a {@link MaskBackup} onto the mask
|
|
252
|
+
* referenced by `backup.object`.
|
|
253
|
+
*
|
|
254
|
+
* Wraps the `set(...)` call in `try/catch` so a stale Fabric reference (a
|
|
255
|
+
* mask removed after the backup was captured but before the restore
|
|
256
|
+
* finally block ran) does not break callers iterating multiple backups.
|
|
257
|
+
* After a successful restore, `setCoords` is called to keep Fabric's
|
|
258
|
+
* cached bounding rect in sync (matching legacy's mergeMasks restore).
|
|
259
|
+
*
|
|
260
|
+
* @param backup - The backup produced by {@link captureMaskStyleBackup}.
|
|
261
|
+
*
|
|
262
|
+
*/
|
|
263
|
+
export declare function restoreMaskStyleBackup(backup: MaskBackup): void;
|
|
264
|
+
/**
|
|
265
|
+
* Run `callback` with every mask's stroke/strokeWidth/opacity reset to the
|
|
266
|
+
* persisted "normal" style ({@link getMaskNormalStyle}), then restore each
|
|
267
|
+
* mutated field inside a `finally` block.
|
|
268
|
+
*
|
|
269
|
+
* Mirrors legacy's `_withNormalizedMaskStyles`. The two callers are:
|
|
270
|
+
*
|
|
271
|
+
* - The pre-snapshot pass in some history paths that wants the snapshot
|
|
272
|
+
* to capture a "clean" un-hovered, un-selected canvas regardless of the
|
|
273
|
+
* live UI state.
|
|
274
|
+
* - The crop-cancel restore path that wants to clear any selection
|
|
275
|
+
* highlight before re-rendering.
|
|
276
|
+
*
|
|
277
|
+
* Only fields that ACTUALLY changed are captured and restored — if a mask
|
|
278
|
+
* is already at its normal style, no patch is recorded for it.
|
|
279
|
+
*
|
|
280
|
+
* The `finally` block runs whether `callback` returned, threw, or
|
|
281
|
+
* rejected. The function returns whatever `callback` returns (sync or
|
|
282
|
+
* Promise), preserving the caller's control flow.
|
|
283
|
+
*
|
|
284
|
+
* @param context - Orchestration context — see {@link MaskStyleContext}.
|
|
285
|
+
* @param callback - Body to execute with normalized mask styles.
|
|
286
|
+
* @returns The value returned by `callback` (or the promise it returned).
|
|
287
|
+
*/
|
|
288
|
+
export declare function withNormalizedMaskStyles<T>(context: MaskStyleContext, callback: () => T): T;
|
|
289
|
+
/**
|
|
290
|
+
* Captures every mask's live style via {@link captureMaskStyleBackup},
|
|
291
|
+
* runs the supplied async `callback` (which is allowed to mutate masks
|
|
292
|
+
* freely — typically by forcing the export bake-in style of
|
|
293
|
+
* `opacity: 1, fill: '#000', strokeWidth: 0, stroke: null,
|
|
294
|
+
* selectable: false`), then restores every mask's pre-callback state in a
|
|
295
|
+
* `finally` block — even if `callback` rejected.
|
|
296
|
+
*
|
|
297
|
+
* This is the canonical owner of the "export-only style restoration"
|
|
298
|
+
* contract. Callers in
|
|
299
|
+
* `export/export-service.ts` use this so they never need to write their
|
|
300
|
+
* own `try/finally` block — and so a future refactor cannot accidentally
|
|
301
|
+
* forget the restore step on an early return path.
|
|
302
|
+
*
|
|
303
|
+
* The function returns whatever `callback` resolves to.
|
|
304
|
+
*
|
|
305
|
+
* @typeParam T - The return type of `callback`.
|
|
306
|
+
* @param context - Orchestration context — see {@link MaskStyleContext}.
|
|
307
|
+
* @param mutator - Synchronous function applied to each captured mask
|
|
308
|
+
* BEFORE `callback` runs. Typically applies the export
|
|
309
|
+
* bake-in style. Called once per mask in canvas object
|
|
310
|
+
* order with `(mask, index)`. Backups are captured BEFORE
|
|
311
|
+
* the mutator runs so an exception in the mutator still
|
|
312
|
+
* triggers the `finally` restore for already-mutated
|
|
313
|
+
* masks.
|
|
314
|
+
* @param callback - The export body to run after every mutator pass
|
|
315
|
+
* completed. Typically `canvas.toDataURL` plus any
|
|
316
|
+
* post-processing.
|
|
317
|
+
* @returns The value `callback` resolved to.
|
|
318
|
+
*
|
|
319
|
+
*/
|
|
320
|
+
export declare function withMaskStyleBackup<T>(context: MaskStyleContext, mutator: (mask: MaskObject, index: number) => void, callback: () => Promise<T> | T): Promise<T>;
|
|
321
|
+
/**
|
|
322
|
+
* Apply the crop-mode hide style on `mask`: opacity 0 + non-interactive.
|
|
323
|
+
*
|
|
324
|
+
* Used by `crop/crop-controller.ts` when entering crop mode with
|
|
325
|
+
* `options.crop.hideMasksDuringCrop === true`. Callers MUST capture a
|
|
326
|
+
* {@link MaskBackup} via {@link captureMaskStyleBackup} BEFORE calling
|
|
327
|
+
* this helper so {@link restoreMaskStyleBackup} can revert the change on
|
|
328
|
+
* `cancelCrop`.
|
|
329
|
+
*
|
|
330
|
+
* Sets `evented: false` and `selectable: false` so the user cannot
|
|
331
|
+
* interact with the mask while only the crop rectangle should respond to
|
|
332
|
+
* pointer events. Wraps the `set(...)` in `try/catch` so a removed mask
|
|
333
|
+
* does not break the loop in the controller.
|
|
334
|
+
*
|
|
335
|
+
* @param mask - The mask to hide.
|
|
336
|
+
*/
|
|
337
|
+
export declare function applyCropHideMaskStyle(mask: MaskObject): void;
|
|
338
|
+
//# sourceMappingURL=mask-style.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mask-style.d.ts","sourceRoot":"","sources":["../../../src/mask/mask-style.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAwBvF;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC7B;;;OAGG;IACH,MAAM,EAAE,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE,QAAQ,CAAC,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACnB;AAoBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,eAAe,CAQpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,eAAe,CAQnE;AAID;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAE7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAM/D;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAe9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAwChE;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAU9D;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAWnE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAiB/D;AAeD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAiC3F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EACvC,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,EAClD,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC,CAiBZ;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAM7D"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed registry of DOM event listeners owned by the
|
|
3
|
+
* {@link ImageEditor} facade. Records every listener it adds so
|
|
4
|
+
* `dispose` can detach them all idempotently.
|
|
5
|
+
*
|
|
6
|
+
* ## Owned contracts
|
|
7
|
+
*
|
|
8
|
+
* - `bindIfExists(key, event, handler)` records the
|
|
9
|
+
* `{ elementKey, eventType, handler}` triple in an internal registry as
|
|
10
|
+
* the listener is attached.
|
|
11
|
+
* - `removeAll` iterates the registry, calls
|
|
12
|
+
* `removeEventListener` for every recorded entry, and clears the registry
|
|
13
|
+
* afterwards.
|
|
14
|
+
* - Every `removeEventListener` call is wrapped in
|
|
15
|
+
* `try/catch` so a second `dispose` (or a listener that has already been
|
|
16
|
+
* detached by other means) never throws. `removeAll` is idempotent.
|
|
17
|
+
* - Every bound handler is wrapped so it consults the
|
|
18
|
+
* editor's `isDisposed` flag (via the `isDisposed` callback supplied to the
|
|
19
|
+
* constructor) and exits early without touching the canvas while disposed.
|
|
20
|
+
*
|
|
21
|
+
* ## Why this lives in its own module
|
|
22
|
+
*
|
|
23
|
+
* The orchestrator's `dispose` path needs to detach DOM listeners without
|
|
24
|
+
* caring about which logical key originally owned each one. Co-locating the
|
|
25
|
+
* registry here keeps the orchestrator free of bookkeeping and lets unit
|
|
26
|
+
* tests exercise the bindings registry without instantiating a full editor.
|
|
27
|
+
* This module is imported by `image-editor.ts` only and is intentionally not
|
|
28
|
+
* re-exported from `src/index.ts`.
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
import type { ElementIdMap } from '../core/public-types.js';
|
|
33
|
+
/**
|
|
34
|
+
* Logical element-name keys understood by the editor's `idMap`. Mirrors the
|
|
35
|
+
* `ElementKey` alias used internally by `image-editor.ts` so callers can
|
|
36
|
+
* speak the same vocabulary without crossing the public-types boundary.
|
|
37
|
+
*/
|
|
38
|
+
export type ElementKey = keyof Required<ElementIdMap>;
|
|
39
|
+
/**
|
|
40
|
+
* Lightweight registry of DOM event listeners owned by an editor instance.
|
|
41
|
+
*
|
|
42
|
+
* The class is intentionally small: it does not know about Fabric, the
|
|
43
|
+
* animation queue, or the operation guard — it only knows how to look up an
|
|
44
|
+
* element ID for a key and how to add/remove a listener. Disposed-state
|
|
45
|
+
* awareness comes in via the `isDisposed` callback so the guard can stay the
|
|
46
|
+
* single source of truth for the `isDisposed` flag (see
|
|
47
|
+
* `core/operation-guard.ts`).
|
|
48
|
+
*
|
|
49
|
+
* Usage:
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* const bindings = new DomBindings(
|
|
53
|
+
* (key) => this.elements[key],
|
|
54
|
+
* () => this.guard.isDisposed(),
|
|
55
|
+
* );
|
|
56
|
+
* bindings.bindIfExists('zoomInButton', 'click', () =>
|
|
57
|
+
* this.scaleImage(s + step),
|
|
58
|
+
* );
|
|
59
|
+
* // ...
|
|
60
|
+
* bindings.removeAll(); // called from dispose
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare class DomBindings {
|
|
64
|
+
private registry;
|
|
65
|
+
private readonly resolveElementId;
|
|
66
|
+
private readonly isDisposed;
|
|
67
|
+
/**
|
|
68
|
+
* @param resolveElementId - Returns the resolved DOM element ID for a given logical key, or a
|
|
69
|
+
* falsy value when the integrator omitted that key from the `idMap`.
|
|
70
|
+
* The orchestrator's `elements` table fills this role.
|
|
71
|
+
* @param isDisposed - Returns the editor's current `isDisposed` flag. Bound handlers
|
|
72
|
+
* consult this on every dispatch and exit early when it returns
|
|
73
|
+
* `true`.
|
|
74
|
+
*/
|
|
75
|
+
constructor(resolveElementId: (key: ElementKey) => string | null | undefined, isDisposed: () => boolean);
|
|
76
|
+
/**
|
|
77
|
+
* Look up the element registered under `key`. If it exists, attach
|
|
78
|
+
* `handler` for `eventType` and record the binding so `removeAll` can
|
|
79
|
+
* detach it later. The handler is wrapped to short-circuit when the
|
|
80
|
+
* editor has been disposed.
|
|
81
|
+
*
|
|
82
|
+
* Missing keys and missing elements are silently ignored — the editor
|
|
83
|
+
* tolerates partial DOM as documented under {@link ElementIdMap}.
|
|
84
|
+
*
|
|
85
|
+
* @returns `true` if the listener was attached, `false` if the element
|
|
86
|
+
* could not be resolved.
|
|
87
|
+
*/
|
|
88
|
+
bindIfExists(key: ElementKey, eventType: string, handler: EventListener): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Detach every recorded listener and clear the registry. Each
|
|
91
|
+
* `removeEventListener` call is wrapped in `try/catch` so an
|
|
92
|
+
* already-detached listener (for example because the host page swapped
|
|
93
|
+
* out the DOM node) does not abort the cleanup loop. Calling `removeAll`
|
|
94
|
+
* a second time is a no-op.
|
|
95
|
+
*/
|
|
96
|
+
removeAll(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Number of currently-registered listeners. Exposed for diagnostics and
|
|
99
|
+
* for the unit tests under `tests/units/dom-bindings.test.mjs`.
|
|
100
|
+
*/
|
|
101
|
+
size(): number;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=dom-bindings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-bindings.d.ts","sourceRoot":"","sources":["../../../src/ui/dom-bindings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;AActD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiD;IAClF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAE3C;;;;;;;OAOG;gBAEC,gBAAgB,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,EAChE,UAAU,EAAE,MAAM,OAAO;IAM7B;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO;IAmBjF;;;;;;OAMG;IACH,SAAS,IAAI,IAAI;IAgBjB;;;OAGG;IACH,IAAI,IAAI,MAAM;CAGjB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disabled-state, aria-state, and toolbar-state helpers used by
|
|
3
|
+
* {@link ImageEditor}'s `init` and operation handlers. These
|
|
4
|
+
* helpers share the same `idMap`-driven element-resolution
|
|
5
|
+
* vocabulary as `dom-bindings.ts` so the orchestrator can speak
|
|
6
|
+
* one language when wiring or refreshing UI state.
|
|
7
|
+
*
|
|
8
|
+
* ## Owned contracts
|
|
9
|
+
*
|
|
10
|
+
* - Bound DOM controls live in the orchestrator's
|
|
11
|
+
* bindings registry and are addressed by logical {@link ElementKey}.
|
|
12
|
+
* These helpers consume the same key vocabulary so toolbar-state updates
|
|
13
|
+
* stay aligned with what `dom-bindings.ts` originally bound.
|
|
14
|
+
* - Toolbar-state mutation must remain a no-op when
|
|
15
|
+
* the editor is disposed or when a logical key is unmapped. Each helper
|
|
16
|
+
* short-circuits on a missing element ID or missing DOM node so
|
|
17
|
+
* post-`dispose` `updateUi`-style calls cannot throw or surprise the
|
|
18
|
+
* host page.
|
|
19
|
+
*
|
|
20
|
+
* ## Why this lives in its own module
|
|
21
|
+
*
|
|
22
|
+
* Splitting low-level DOM state out keeps `image-editor.ts` focused on
|
|
23
|
+
* toolbar policy while helpers here own native DOM writes such as setting
|
|
24
|
+
* `disabled` by logical key.
|
|
25
|
+
*
|
|
26
|
+
* Like `dom-bindings.ts` and `visibility-state.ts`, this module is imported
|
|
27
|
+
* by `image-editor.ts` only and is intentionally NOT re-exported from
|
|
28
|
+
* `src/index.ts`.
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
import type { ElementIdMap } from '../core/public-types.js';
|
|
33
|
+
/**
|
|
34
|
+
* Logical element-name keys understood by the editor's `idMap`. Matches the
|
|
35
|
+
* `ElementKey` alias exported from `dom-bindings.ts` so the orchestrator's
|
|
36
|
+
* registry and the toolbar-state helpers can be driven from the same
|
|
37
|
+
* lookup function without crossing the public-types boundary.
|
|
38
|
+
*/
|
|
39
|
+
export type ElementKey = keyof Required<ElementIdMap>;
|
|
40
|
+
/**
|
|
41
|
+
* Callback used by every helper in this module to translate a logical
|
|
42
|
+
* {@link ElementKey} to the resolved DOM element ID supplied by the host
|
|
43
|
+
* page through `idMap`. Returning a falsy value (`null`, `undefined`, or
|
|
44
|
+
* empty string) means the host omitted that key — helpers MUST treat that
|
|
45
|
+
* as a no-op rather than a bug.
|
|
46
|
+
*/
|
|
47
|
+
export type ElementIdResolver = (key: ElementKey) => string | null | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Set the native `disabled` IDL property on a button-like control resolved
|
|
50
|
+
* from `key`. Used by the orchestrator's `updateUi` policy: each toolbar
|
|
51
|
+
* button maps to one logical key, and the policy decides whether the
|
|
52
|
+
* button is currently usable.
|
|
53
|
+
*
|
|
54
|
+
* Behaviour:
|
|
55
|
+
*
|
|
56
|
+
* - If `resolveElementId(key)` returns a falsy value, the helper returns
|
|
57
|
+
* without touching the DOM (the integrator chose not to wire that
|
|
58
|
+
* control).
|
|
59
|
+
* - If `document.getElementById(id)` returns `null`, the helper returns
|
|
60
|
+
* without throwing. A missing node is a partial-DOM scenario, not a
|
|
61
|
+
* fatal error.
|
|
62
|
+
* - Otherwise the resolved element's `disabled` property is set to the
|
|
63
|
+
* requested boolean. Using the IDL property (not `setAttribute`)
|
|
64
|
+
* keeps the keyboard/click behaviour the
|
|
65
|
+
* browser provides "for free" on real `<button>` elements.
|
|
66
|
+
*
|
|
67
|
+
* The element is typed as `HTMLButtonElement` because every key in the
|
|
68
|
+
* documented toolbar set (`zoomInButton`, `applyCropButton`, …) resolves to a
|
|
69
|
+
* `<button>`. A non-button host element will still receive the `disabled`
|
|
70
|
+
* assignment via the IDL slot but will not visually reflect it; that is
|
|
71
|
+
* the integrator's responsibility per the public `idMap` contract.
|
|
72
|
+
*
|
|
73
|
+
* @param resolveElementId - Resolver from logical key to DOM element ID.
|
|
74
|
+
* @param key - Logical toolbar element key.
|
|
75
|
+
* @param disabled - Target `disabled` value.
|
|
76
|
+
*/
|
|
77
|
+
export declare function setDisabled(resolveElementId: ElementIdResolver, key: ElementKey, disabled: boolean): void;
|
|
78
|
+
/**
|
|
79
|
+
* Set the `aria-disabled` attribute on the element resolved from `key`.
|
|
80
|
+
* Useful for non-button toolbar controls (links, custom widgets) that do
|
|
81
|
+
* not honour the native `disabled` IDL property but still need to expose
|
|
82
|
+
* disabled state to assistive technology.
|
|
83
|
+
*
|
|
84
|
+
* Behaviour mirrors {@link setDisabled}: missing key or missing element
|
|
85
|
+
* results in a silent no-op. The attribute value is
|
|
86
|
+
* always the canonical string `'true'` or `'false'` as required by the
|
|
87
|
+
* ARIA spec — never the empty string and never removed entirely, so a
|
|
88
|
+
* subsequent toggle is a single `setAttribute` away.
|
|
89
|
+
*
|
|
90
|
+
* @param resolveElementId - Resolver from logical key to DOM element ID.
|
|
91
|
+
* @param key - Logical toolbar element key.
|
|
92
|
+
* @param disabled - Target `aria-disabled` value.
|
|
93
|
+
*/
|
|
94
|
+
export declare function setAriaDisabled(resolveElementId: ElementIdResolver, key: ElementKey, disabled: boolean): void;
|
|
95
|
+
/**
|
|
96
|
+
* Toggle a CSS class on the element resolved from `key`. Used for toolbar
|
|
97
|
+
* state that does not correspond to `disabled` / `aria-disabled` — for
|
|
98
|
+
* example, marking the active mask in the mask list or flipping a button
|
|
99
|
+
* into a "pressed" visual style during crop mode.
|
|
100
|
+
*
|
|
101
|
+
* The helper delegates to `Element.classList.toggle(className, force)`, so
|
|
102
|
+
* the caller's `enabled` flag deterministically adds or removes the class
|
|
103
|
+
* regardless of its current presence. Missing key or missing element is a
|
|
104
|
+
* silent no-op.
|
|
105
|
+
*
|
|
106
|
+
* @param resolveElementId - Resolver from logical key to DOM element ID.
|
|
107
|
+
* @param key - Logical toolbar element key.
|
|
108
|
+
* @param className - CSS class name to toggle.
|
|
109
|
+
* @param enabled - `true` to add the class, `false` to remove it.
|
|
110
|
+
*/
|
|
111
|
+
export declare function setClass(resolveElementId: ElementIdResolver, key: ElementKey, className: string, enabled: boolean): void;
|
|
112
|
+
//# sourceMappingURL=ui-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-state.d.ts","sourceRoot":"","sources":["../../../src/ui/ui-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,WAAW,CACvB,gBAAgB,EAAE,iBAAiB,EACnC,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,OAAO,GAClB,IAAI,CAKN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC3B,gBAAgB,EAAE,iBAAiB,EACnC,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,OAAO,GAClB,IAAI,CAKN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CACpB,gBAAgB,EAAE,iBAAiB,EACnC,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACjB,IAAI,CAKN"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Placeholder/canvas-container visibility helper. Owns the
|
|
3
|
+
* standard-DOM-state transition that the orchestrator's
|
|
4
|
+
* private `_setPlaceholderVisible` method delegates to.
|
|
5
|
+
*
|
|
6
|
+
* ## Owned contracts
|
|
7
|
+
*
|
|
8
|
+
* - `setPlaceholderVisible(..., true)` SHALL set the
|
|
9
|
+
* placeholder's `hidden` to `false` and `aria-hidden` to `'false'`, and
|
|
10
|
+
* SHALL set the canvas container's `hidden` to `true` and `aria-hidden`
|
|
11
|
+
* to `'true'`.
|
|
12
|
+
* - `setPlaceholderVisible(..., false)` SHALL set the
|
|
13
|
+
* placeholder's `hidden` to `true` and `aria-hidden` to `'true'`, and
|
|
14
|
+
* SHALL set the canvas container's `hidden` to `false` and `aria-hidden`
|
|
15
|
+
* to `'false'`.
|
|
16
|
+
* - This module SHALL NOT add or remove the
|
|
17
|
+
* Bootstrap `d-none` class on either element. The host page is free to
|
|
18
|
+
* style `[hidden]` however it likes; the editor stays out of utility-class
|
|
19
|
+
* territory so it works with or without Bootstrap.
|
|
20
|
+
* - When `containerElement` is `null`, the
|
|
21
|
+
* placeholder's `hidden` and `aria-hidden` SHALL still be updated
|
|
22
|
+
* correctly. A missing container is a partial-DOM scenario, not a fatal
|
|
23
|
+
* error.
|
|
24
|
+
*
|
|
25
|
+
* ## Why this lives in its own module
|
|
26
|
+
*
|
|
27
|
+
* The helper uses standard DOM state instead of Bootstrap utility classes so
|
|
28
|
+
* the editor works with or without a host stylesheet. Keeping the transition
|
|
29
|
+
* here makes the orchestrator's private method a one-line delegate and keeps
|
|
30
|
+
* the behavior unit-testable in isolation. This module is imported by
|
|
31
|
+
* `image-editor.ts` only and is intentionally not re-exported from
|
|
32
|
+
* `src/index.ts`.
|
|
33
|
+
*
|
|
34
|
+
* @module
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Toggle placeholder/canvas-container visibility using only standard DOM
|
|
38
|
+
* state. The function is total: it never throws on null inputs and never
|
|
39
|
+
* touches utility classes.
|
|
40
|
+
*
|
|
41
|
+
* Visibility semantics:
|
|
42
|
+
*
|
|
43
|
+
* - `show === true` means **show the placeholder** (and therefore hide the
|
|
44
|
+
* canvas container). The placeholder is the "no image yet" affordance, so
|
|
45
|
+
* showing it implies the live canvas is not the right thing to render.
|
|
46
|
+
* - `show === false` means **hide the placeholder** (and therefore show the
|
|
47
|
+
* canvas container). This is the post-`loadImage` steady state.
|
|
48
|
+
*
|
|
49
|
+
* In both branches the function:
|
|
50
|
+
*
|
|
51
|
+
* 1. Sets the DOM `hidden` property. Using the
|
|
52
|
+
* property — not the attribute — keeps the IDL flag and the reflected
|
|
53
|
+
* attribute in sync without an extra `setAttribute` call.
|
|
54
|
+
* 2. Sets `aria-hidden` to the matching string so assistive technology
|
|
55
|
+
* tracks the visual state.
|
|
56
|
+
* 3. Leaves every other class and inline style untouched. In particular,
|
|
57
|
+
* Bootstrap's `d-none` is never added or removed,
|
|
58
|
+
* which lets the editor coexist with host pages that use `d-none` for
|
|
59
|
+
* their own purposes.
|
|
60
|
+
*
|
|
61
|
+
* When `containerElement` is `null` (partial DOM, or a host page that does
|
|
62
|
+
* not wrap the canvas in a dedicated container), the placeholder side of
|
|
63
|
+
* the transition still runs to completion. When
|
|
64
|
+
* `placeholderElement` is `null` the function is a no-op for that side; the
|
|
65
|
+
* orchestrator's `updatePlaceholderStatus` already early-returns in that
|
|
66
|
+
* case, but defending here keeps the helper safe to call from any future
|
|
67
|
+
* code path.
|
|
68
|
+
*
|
|
69
|
+
* @param placeholderElement - The placeholder DOM element shown when no image is loaded, or `null`
|
|
70
|
+
* when the host page omitted the placeholder slot from the `idMap`.
|
|
71
|
+
* @param containerElement - The canvas container DOM element wrapping the live `<canvas>`, or
|
|
72
|
+
* `null` when no container is available.
|
|
73
|
+
* @param show - `true` to make the placeholder visible (and hide the canvas container);
|
|
74
|
+
* `false` to hide the placeholder (and show the canvas container).
|
|
75
|
+
*/
|
|
76
|
+
export declare function setPlaceholderVisible(placeholderElement: HTMLElement | null, containerElement: HTMLElement | null, show: boolean): void;
|
|
77
|
+
//# sourceMappingURL=visibility-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility-state.d.ts","sourceRoot":"","sources":["../../../src/ui/visibility-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,qBAAqB,CACjC,kBAAkB,EAAE,WAAW,GAAG,IAAI,EACtC,gBAAgB,EAAE,WAAW,GAAG,IAAI,EACpC,IAAI,EAAE,OAAO,GACd,IAAI,CAgBN"}
|