@bensitu/image-editor 1.5.2 → 2.1.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.
Files changed (166) hide show
  1. package/README.md +460 -509
  2. package/dist/cjs/index.cjs +6892 -0
  3. package/dist/cjs/index.cjs.map +1 -0
  4. package/dist/esm/animation/animation-queue.js +74 -0
  5. package/dist/esm/animation/animation-queue.js.map +1 -0
  6. package/dist/esm/core/callback-reporter.js +23 -0
  7. package/dist/esm/core/callback-reporter.js.map +1 -0
  8. package/dist/esm/core/default-options.js +529 -0
  9. package/dist/esm/core/default-options.js.map +1 -0
  10. package/dist/esm/core/errors.js +156 -0
  11. package/dist/esm/core/errors.js.map +1 -0
  12. package/dist/esm/core/operation-guard.js +157 -0
  13. package/dist/esm/core/operation-guard.js.map +1 -0
  14. package/dist/esm/core/public-types.js +4 -0
  15. package/dist/esm/core/public-types.js.map +1 -0
  16. package/dist/esm/core/state-serializer.js +252 -0
  17. package/dist/esm/core/state-serializer.js.map +1 -0
  18. package/dist/esm/crop/crop-controller.js +405 -0
  19. package/dist/esm/crop/crop-controller.js.map +1 -0
  20. package/dist/esm/export/export-format.js +53 -0
  21. package/dist/esm/export/export-format.js.map +1 -0
  22. package/dist/esm/export/export-service.js +607 -0
  23. package/dist/esm/export/export-service.js.map +1 -0
  24. package/dist/esm/fabric/fabric-adapter.js +37 -0
  25. package/dist/esm/fabric/fabric-adapter.js.map +1 -0
  26. package/dist/esm/fabric/fabric-animation.js +89 -0
  27. package/dist/esm/fabric/fabric-animation.js.map +1 -0
  28. package/dist/esm/history/command.js +2 -0
  29. package/dist/esm/history/command.js.map +1 -0
  30. package/dist/esm/history/history-manager.js +103 -0
  31. package/dist/esm/history/history-manager.js.map +1 -0
  32. package/dist/esm/image/image-loader.js +238 -0
  33. package/dist/esm/image/image-loader.js.map +1 -0
  34. package/dist/esm/image/image-resampler.js +60 -0
  35. package/dist/esm/image/image-resampler.js.map +1 -0
  36. package/dist/esm/image/layout-manager.js +206 -0
  37. package/dist/esm/image/layout-manager.js.map +1 -0
  38. package/dist/esm/image/transform-controller.js +132 -0
  39. package/dist/esm/image/transform-controller.js.map +1 -0
  40. package/dist/esm/image-editor.js +2076 -0
  41. package/dist/esm/image-editor.js.map +1 -0
  42. package/dist/esm/index.js +5 -0
  43. package/dist/esm/index.js.map +1 -0
  44. package/dist/esm/mask/mask-factory.js +356 -0
  45. package/dist/esm/mask/mask-factory.js.map +1 -0
  46. package/dist/esm/mask/mask-label-manager.js +120 -0
  47. package/dist/esm/mask/mask-label-manager.js.map +1 -0
  48. package/dist/esm/mask/mask-list.js +53 -0
  49. package/dist/esm/mask/mask-list.js.map +1 -0
  50. package/dist/esm/mask/mask-style.js +182 -0
  51. package/dist/esm/mask/mask-style.js.map +1 -0
  52. package/dist/esm/mosaic/mosaic-controller.js +670 -0
  53. package/dist/esm/mosaic/mosaic-controller.js.map +1 -0
  54. package/dist/esm/mosaic/mosaic-geometry.js +81 -0
  55. package/dist/esm/mosaic/mosaic-geometry.js.map +1 -0
  56. package/dist/esm/mosaic/mosaic-pixelate.js +71 -0
  57. package/dist/esm/mosaic/mosaic-pixelate.js.map +1 -0
  58. package/dist/esm/ui/dom-bindings.js +67 -0
  59. package/dist/esm/ui/dom-bindings.js.map +1 -0
  60. package/dist/esm/ui/ui-state.js +25 -0
  61. package/dist/esm/ui/ui-state.js.map +1 -0
  62. package/dist/esm/ui/visibility-state.js +11 -0
  63. package/dist/esm/ui/visibility-state.js.map +1 -0
  64. package/dist/esm/utils/canvas-region.js +100 -0
  65. package/dist/esm/utils/canvas-region.js.map +1 -0
  66. package/dist/esm/utils/dom.js +6 -0
  67. package/dist/esm/utils/dom.js.map +1 -0
  68. package/dist/esm/utils/file.js +53 -0
  69. package/dist/esm/utils/file.js.map +1 -0
  70. package/dist/esm/utils/number.js +24 -0
  71. package/dist/esm/utils/number.js.map +1 -0
  72. package/dist/esm/utils/timeout.js +17 -0
  73. package/dist/esm/utils/timeout.js.map +1 -0
  74. package/dist/types/animation/animation-queue.d.ts +111 -0
  75. package/dist/types/animation/animation-queue.d.ts.map +1 -0
  76. package/dist/types/core/callback-reporter.d.ts +125 -0
  77. package/dist/types/core/callback-reporter.d.ts.map +1 -0
  78. package/dist/types/core/default-options.d.ts +84 -0
  79. package/dist/types/core/default-options.d.ts.map +1 -0
  80. package/dist/types/core/errors.d.ts +142 -0
  81. package/dist/types/core/errors.d.ts.map +1 -0
  82. package/dist/types/core/operation-guard.d.ts +194 -0
  83. package/dist/types/core/operation-guard.d.ts.map +1 -0
  84. package/dist/types/core/public-types.d.ts +788 -0
  85. package/dist/types/core/public-types.d.ts.map +1 -0
  86. package/dist/types/core/state-serializer.d.ts +303 -0
  87. package/dist/types/core/state-serializer.d.ts.map +1 -0
  88. package/dist/types/crop/crop-controller.d.ts +407 -0
  89. package/dist/types/crop/crop-controller.d.ts.map +1 -0
  90. package/dist/types/export/export-format.d.ts +136 -0
  91. package/dist/types/export/export-format.d.ts.map +1 -0
  92. package/dist/types/export/export-service.d.ts +333 -0
  93. package/dist/types/export/export-service.d.ts.map +1 -0
  94. package/dist/types/fabric/fabric-adapter.d.ts +74 -0
  95. package/dist/types/fabric/fabric-adapter.d.ts.map +1 -0
  96. package/dist/types/fabric/fabric-animation.d.ts +141 -0
  97. package/dist/types/fabric/fabric-animation.d.ts.map +1 -0
  98. package/dist/types/history/command.d.ts +16 -0
  99. package/dist/types/history/command.d.ts.map +1 -0
  100. package/dist/types/history/history-manager.d.ts +129 -0
  101. package/dist/types/history/history-manager.d.ts.map +1 -0
  102. package/dist/types/image/image-loader.d.ts +263 -0
  103. package/dist/types/image/image-loader.d.ts.map +1 -0
  104. package/dist/types/image/image-resampler.d.ts +139 -0
  105. package/dist/types/image/image-resampler.d.ts.map +1 -0
  106. package/dist/types/image/layout-manager.d.ts +211 -0
  107. package/dist/types/image/layout-manager.d.ts.map +1 -0
  108. package/dist/types/image/transform-controller.d.ts +286 -0
  109. package/dist/types/image/transform-controller.d.ts.map +1 -0
  110. package/dist/types/image-editor.d.ts +661 -0
  111. package/dist/types/image-editor.d.ts.map +1 -0
  112. package/dist/types/index.d.cts +31 -0
  113. package/dist/types/index.d.cts.map +1 -0
  114. package/dist/types/index.d.ts +31 -0
  115. package/dist/types/index.d.ts.map +1 -0
  116. package/dist/types/mask/mask-factory.d.ts +212 -0
  117. package/dist/types/mask/mask-factory.d.ts.map +1 -0
  118. package/dist/types/mask/mask-label-manager.d.ts +171 -0
  119. package/dist/types/mask/mask-label-manager.d.ts.map +1 -0
  120. package/dist/types/mask/mask-list.d.ts +144 -0
  121. package/dist/types/mask/mask-list.d.ts.map +1 -0
  122. package/dist/types/mask/mask-style.d.ts +338 -0
  123. package/dist/types/mask/mask-style.d.ts.map +1 -0
  124. package/dist/types/mosaic/mosaic-controller.d.ts +82 -0
  125. package/dist/types/mosaic/mosaic-controller.d.ts.map +1 -0
  126. package/dist/types/mosaic/mosaic-geometry.d.ts +29 -0
  127. package/dist/types/mosaic/mosaic-geometry.d.ts.map +1 -0
  128. package/dist/types/mosaic/mosaic-pixelate.d.ts +23 -0
  129. package/dist/types/mosaic/mosaic-pixelate.d.ts.map +1 -0
  130. package/dist/types/ui/dom-bindings.d.ts +105 -0
  131. package/dist/types/ui/dom-bindings.d.ts.map +1 -0
  132. package/dist/types/ui/ui-state.d.ts +112 -0
  133. package/dist/types/ui/ui-state.d.ts.map +1 -0
  134. package/dist/types/ui/visibility-state.d.ts +77 -0
  135. package/dist/types/ui/visibility-state.d.ts.map +1 -0
  136. package/dist/types/utils/canvas-region.d.ts +177 -0
  137. package/dist/types/utils/canvas-region.d.ts.map +1 -0
  138. package/dist/types/utils/dom.d.ts +26 -0
  139. package/dist/types/utils/dom.d.ts.map +1 -0
  140. package/dist/types/utils/file.d.ts +80 -0
  141. package/dist/types/utils/file.d.ts.map +1 -0
  142. package/dist/types/utils/number.d.ts +131 -0
  143. package/dist/types/utils/number.d.ts.map +1 -0
  144. package/dist/types/utils/timeout.d.ts +84 -0
  145. package/dist/types/utils/timeout.d.ts.map +1 -0
  146. package/dist/umd/image-editor.umd.js +2 -0
  147. package/dist/umd/image-editor.umd.js.map +1 -0
  148. package/package.json +72 -66
  149. package/dist/image-editor.cjs +0 -4407
  150. package/dist/image-editor.cjs.map +0 -7
  151. package/dist/image-editor.esm.js +0 -4376
  152. package/dist/image-editor.esm.js.map +0 -7
  153. package/dist/image-editor.esm.min.js +0 -9
  154. package/dist/image-editor.esm.min.js.map +0 -7
  155. package/dist/image-editor.esm.min.mjs +0 -9
  156. package/dist/image-editor.esm.min.mjs.map +0 -7
  157. package/dist/image-editor.esm.mjs +0 -4376
  158. package/dist/image-editor.esm.mjs.map +0 -7
  159. package/dist/image-editor.js +0 -4373
  160. package/dist/image-editor.js.map +0 -7
  161. package/dist/image-editor.min.js +0 -9
  162. package/dist/image-editor.min.js.map +0 -7
  163. package/image-editor.d.ts +0 -271
  164. package/src/browser.js +0 -11
  165. package/src/esm.js +0 -9
  166. package/src/image-editor.js +0 -5013
@@ -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"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Pure helpers that turn floating-point Fabric.js bounding
3
+ * rectangles into integer pixel regions and provide the
4
+ * bounding-box math that mask preservation across crop and
5
+ * export paths share.
6
+ *
7
+ * ## Owned contracts
8
+ *
9
+ * - Export regions SHALL include partially covered trailing pixels so
10
+ * sub-pixel image bounds do not lose the right or bottom edge.
11
+ * - Crop regions SHALL exclude trailing partial pixels so crop does not
12
+ * grow by a transparent row or column.
13
+ * - When `applyCrop` runs with
14
+ * `preserveMasksAfterCrop === true` and the image has been rotated,
15
+ * each mask's new `left` and `top` SHALL be expressed in the cropped
16
+ * image's coordinate frame using the rotation angle.
17
+ * - Across a crop apply, each mask's `angle`,
18
+ * `scaleX`, and `scaleY` SHALL be preserved so the visible shape does
19
+ * not change size or orientation.
20
+ *
21
+ * ## Why a dedicated module
22
+ *
23
+ * Region math is shared by export, crop, expand-to-image sizing, and crop
24
+ * rectangle initialization. Centralizing it prevents one call site from
25
+ * drifting from the others (for example, applying `Math.floor` instead of
26
+ * `Math.round`, or forgetting the `width >= 1` floor).
27
+ *
28
+ * ## Design notes
29
+ *
30
+ * - Region floors are total: any non-finite input collapses to a
31
+ * `1×1` region anchored at `(0, 0)` rather than throwing. The export
32
+ * and crop pipelines already validate the presence of an
33
+ * `originalImage` upstream, so a defensive fallback here keeps the
34
+ * `<canvas>.drawImage` call from being passed `NaN` if Fabric ever
35
+ * reports a degenerate bounding rect.
36
+ * - `getObjectBBox` calls `setCoords` before reading the bounding
37
+ * rect because Fabric.js v7's `getBoundingRect` returns the cached
38
+ * absolute rect; without the refresh a freshly-mutated mask returns
39
+ * stale coordinates. Callers that have already refreshed coords pay
40
+ * only a single redundant call, which is cheaper than double-tracking
41
+ * "is this object's cache fresh?" at every site.
42
+ * - `clampRegionToCanvas` exists for the crop pipeline, where the crop
43
+ * rectangle's bounding rect can briefly exceed the canvas after a
44
+ * user drag near the edge; clamping before the `drawImage` keeps the
45
+ * blit inside the source canvas.
46
+ *
47
+ * ## Non-goals
48
+ *
49
+ * - This module does not perform any coordinate transformation between
50
+ * pre-crop and post-crop frames; the rotation math for the
51
+ * rotated-mask coordinate frame lives in `crop/crop-controller.ts`,
52
+ * which uses
53
+ * `getObjectBBox` here only as one input to that calculation.
54
+ * - This module does not mutate the Fabric object passed to
55
+ * `getObjectBBox` beyond the `setCoords` refresh required by
56
+ * Fabric.js v7's API.
57
+ *
58
+ * @module
59
+ */
60
+ import type * as FabricNS from 'fabric';
61
+ /**
62
+ * A canvas region whose `left` / `top` / `width` / `height` are all
63
+ * integer pixels suitable for `CanvasRenderingContext2D.drawImage` and
64
+ * Fabric.js `toDataURL({ left, top, width, height})`.
65
+ *
66
+ * Produced by {@link floorRegion} and {@link clampRegionToCanvas}; the
67
+ * `width` and `height` fields are guaranteed to be at least `1` so
68
+ * region exports never collapse to a zero-pixel image.
69
+ */
70
+ export interface IntegerRegion {
71
+ left: number;
72
+ top: number;
73
+ width: number;
74
+ height: number;
75
+ }
76
+ export interface RegionRoundingOptions {
77
+ /**
78
+ * When true, `right` / `bottom` are ceiled to include partially covered
79
+ * trailing pixels. When false, they are floored to exclude them.
80
+ * @default true
81
+ */
82
+ includePartialPixels?: boolean;
83
+ }
84
+ export interface PartialExportEdges {
85
+ left: boolean;
86
+ top: boolean;
87
+ right: boolean;
88
+ bottom: boolean;
89
+ }
90
+ export declare function hasMeaningfulCanvasRegion(rect: {
91
+ left: number;
92
+ top: number;
93
+ width: number;
94
+ height: number;
95
+ }, canvasWidth?: number, canvasHeight?: number): boolean;
96
+ /**
97
+ * Convert a floating-point rectangle into an {@link IntegerRegion}.
98
+ *
99
+ * - `left` / `top` are floored and clamped to `>= 0` so the region
100
+ * never starts before the source canvas's top-left corner.
101
+ * - `right` / `bottom` are ceiled by default to include partially covered
102
+ * trailing pixels, or floored when `includePartialPixels` is false.
103
+ * - `width` / `height` are derived from those integer edges and clamped
104
+ * to `>= 1` so no sub-pixel dimensions reach Fabric's region export.
105
+ * - Non-finite inputs collapse to a `1×1` region at `(0, 0)` rather than
106
+ * propagating `NaN` into the canvas pipeline.
107
+ *
108
+ * region floor before mask remapping).
109
+ *
110
+ * @param rect - The floating-point bounding rect to discretize.
111
+ * @returns An {@link IntegerRegion} safe to pass to `drawImage`.
112
+ */
113
+ export declare function getClampedCanvasRegion(rect: {
114
+ left: number;
115
+ top: number;
116
+ width: number;
117
+ height: number;
118
+ }, canvasWidth?: number, canvasHeight?: number, options?: RegionRoundingOptions): IntegerRegion;
119
+ export declare function floorRegion(rect: {
120
+ left: number;
121
+ top: number;
122
+ width: number;
123
+ height: number;
124
+ }): IntegerRegion;
125
+ export declare function hasFractionalCanvasEdge(value: number): boolean;
126
+ export declare function getPartialExportEdges(bounds: {
127
+ left: number;
128
+ top: number;
129
+ width: number;
130
+ height: number;
131
+ } | null, angle?: number): PartialExportEdges | null;
132
+ /**
133
+ * Read a Fabric.js object's absolute bounding rectangle in canvas-pixel
134
+ * coordinates.
135
+ *
136
+ * `setCoords` is called first because Fabric.js v7's
137
+ * `getBoundingRect` returns the cached absolute rect — the per-frame
138
+ * cache the canvas already maintains. Without the refresh a freshly
139
+ * mutated mask returns stale coordinates, which can make rotated masks
140
+ * drift after crop.
141
+ *
142
+ * The returned rect uses floating-point coordinates; callers that need
143
+ * integer pixel regions should pipe the result through
144
+ * {@link floorRegion}.
145
+ *
146
+ * @param object - The Fabric.js object to measure.
147
+ * @returns The absolute bounding rect in canvas pixels.
148
+ */
149
+ export declare function getObjectBBox(object: FabricNS.FabricObject): {
150
+ left: number;
151
+ top: number;
152
+ width: number;
153
+ height: number;
154
+ };
155
+ /**
156
+ * Clamp an {@link IntegerRegion} so it fits entirely inside a canvas of
157
+ * `canvasWidth × canvasHeight` pixels.
158
+ *
159
+ * - `left` is clamped to `[0, canvasWidth - 1]`.
160
+ * - `top` is clamped to `[0, canvasHeight - 1]`.
161
+ * - `width` is clamped so `left + width <= canvasWidth`.
162
+ * - `height` is clamped so `top + height <= canvasHeight`.
163
+ *
164
+ * The function preserves the `width >= 1` / `height >= 1` invariant
165
+ * established by {@link floorRegion}, which keeps callers from having
166
+ * to special-case zero-sized regions when the supplied rect lands
167
+ * entirely outside the canvas.
168
+ *
169
+ * canvas before the mask coordinate remap).
170
+ *
171
+ * @param region - The integer region to clamp.
172
+ * @param canvasWidth - The source canvas's pixel width.
173
+ * @param canvasHeight - The source canvas's pixel height.
174
+ * @returns A clamped {@link IntegerRegion}.
175
+ */
176
+ export declare function clampRegionToCanvas(region: IntegerRegion, canvasWidth: number, canvasHeight: number): IntegerRegion;
177
+ //# sourceMappingURL=canvas-region.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-region.d.ts","sourceRoot":"","sources":["../../../src/utils/canvas-region.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAExC;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,yBAAyB,CACrC,IAAI,EAAE;IACF,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,EACD,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACtB,OAAO,CAkCT;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAClC,IAAI,EAAE;IACF,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,EACD,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,GAAE,qBAA0B,GACpC,aAAa,CA4Bf;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,GAAG,aAAa,CAEhB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAI9D;AAED,wBAAgB,qBAAqB,CACjC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC3E,KAAK,SAAI,GACV,kBAAkB,GAAG,IAAI,CAc3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,YAAY,GAAG;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,CASA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACrB,aAAa,CASf"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * DOM micro-helpers used by sizing and visibility flows.
3
+ *
4
+ * Kept intentionally small: the editor depends on a single synchronous
5
+ * reflow primitive after canvas dimension changes, and exposing it as a
6
+ * named utility lets layout, visibility, and crop flows share the same
7
+ * documented contract.
8
+ */
9
+ /**
10
+ * Force a synchronous layout reflow on `element`.
11
+ *
12
+ * Reading an offset/scroll/clientWidth-like property forces the browser
13
+ * to flush queued style and layout work on the spot, before any further
14
+ * script runs. The editor relies on this after `Canvas.setDimensions`
15
+ * so a container with `overflow: auto` shows or hides scrollbars before
16
+ * the next paint, instead of waiting for the next frame.
17
+ *
18
+ * The read is cast to `void` and isolated in this helper so optimizers
19
+ * cannot eliminate it as a dead access. The function is a no-op when
20
+ * `element` is `null` or `undefined`, which keeps callers free of guards in
21
+ * environments where the container element may not yet be attached.
22
+ *
23
+ * @param element - The element whose layout should be flushed. `null` is ignored.
24
+ */
25
+ export declare function forceReflow(element: HTMLElement | null | undefined): void;
26
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAMzE"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * File-input helpers used by the editor's file-input flow.
3
+ *
4
+ * These helpers cover three concerns:
5
+ *
6
+ * - Determining whether a `File` selected through the upload control is a
7
+ * supported image, including the extension fallback when `file.type` is
8
+ * empty (some operating systems and browsers report an empty MIME type
9
+ * for known extensions).
10
+ * - Reading the file as a base64 data URL so the result can be routed
11
+ * through the existing transactional `loadImage` pipeline (and therefore
12
+ * inherit its rollback behavior on decode/Fabric/timeout failure).
13
+ * - Resetting the file input value after every attempt so selecting the
14
+ * same file again triggers a fresh `change` event.
15
+ *
16
+ * The helpers do not call `loadImage` themselves; the orchestrator wires
17
+ * them into the file-input change handler. That keeps the public
18
+ * `loadImage` API unchanged beyond `LoadImageOptions`.
19
+ */
20
+ /**
21
+ * Supported image extensions and the MIME type each one resolves to.
22
+ *
23
+ * Supported file extensions: `png`, `jpg`/`jpeg`, `webp`, `gif`, `bmp`.
24
+ * GIF and BMP are accepted as static raster input for canvas editing. GIF
25
+ * animation and GIF/BMP source-format preservation are not retained; exports
26
+ * are emitted through the editor's JPEG, PNG, or WebP export options.
27
+ *
28
+ * Keys are lowercase extensions without the leading `.`.
29
+ */
30
+ export declare const SUPPORTED_IMAGE_EXTENSIONS: Record<string, string>;
31
+ export declare const SUPPORTED_IMAGE_MIME_TYPES: Set<string>;
32
+ /**
33
+ * Determine whether a `File` is a supported image and return its resolved
34
+ * MIME type, or `null` when it should be rejected.
35
+ *
36
+ * Resolution order:
37
+ *
38
+ * 1. If `file.type` is one of the supported image MIME types, return it
39
+ * verbatim.
40
+ * 2. If `file.type` is empty, infer the MIME type from the file
41
+ * extension via {@link SUPPORTED_IMAGE_EXTENSIONS}. This covers the
42
+ * case where a browser or OS reports `''` for files with a known
43
+ * extension.
44
+ * 3. Otherwise, return `null` so the caller can skip the load without
45
+ * mutating editor state.
46
+ *
47
+ * @param file - File selected via the upload control.
48
+ * @returns The resolved MIME type, or `null` when the file is not a
49
+ * supported image.
50
+ */
51
+ export declare function inferImageMimeType(file: File): string | null;
52
+ /**
53
+ * Read a `File` as a base64 data URL using `FileReader`.
54
+ *
55
+ * The returned data URL is suitable for the transactional `loadImage`
56
+ * pipeline: on failure the editor's existing
57
+ * rollback bundle restores placeholder visibility, scroll, overflow,
58
+ * `originalImage`, `lastSnapshot`, and the canvas JSON snapshot.
59
+ *
60
+ * @param file - File to read.
61
+ * @returns A promise that resolves to the data URL string, or rejects when
62
+ * the underlying `FileReader` errors out or returns a non-string
63
+ * result.
64
+ */
65
+ export declare function readFileAsDataUrl(file: File): Promise<string>;
66
+ /**
67
+ * Reset a file input element's value so selecting the same file again
68
+ * triggers a fresh `change` event.
69
+ *
70
+ * Some browsers reject programmatic assignment to `input.value` on
71
+ * security grounds; the assignment is wrapped in a `try`/`catch` so the
72
+ * caller never has to special-case those environments. A `null` input is
73
+ * a no-op so callers can pass the result of `document.getElementById`
74
+ * without an extra null check.
75
+ *
76
+ * @param input - File input element, or `null` when the element is not
77
+ * present in the DOM.
78
+ */
79
+ export declare function resetFileInput(input: HTMLInputElement | null): void;
80
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../../src/utils/file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO7D,CAAC;AAEF,eAAO,MAAM,0BAA0B,aAAqD,CAAC;AAE7F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAO5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAOnE"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Pure helpers used by `mask/mask-factory.ts` to turn the
3
+ * flexible `MaskNumericProp` and `PolygonPoint` inputs of
4
+ * {@link MaskConfig} into concrete numbers and `{ x, y }`
5
+ * points before a Fabric.js shape is constructed.
6
+ *
7
+ * ## Owned contracts
8
+ *
9
+ * - `MaskConfig` percentage values supplied for
10
+ * `left`, `width`, `rx`, or `radius` SHALL resolve against the canvas
11
+ * pixel **width** (axis `'x'`).
12
+ * - `MaskConfig` percentage values supplied for
13
+ * `top`, `height`, or `ry` SHALL resolve against the canvas pixel
14
+ * **height** (axis `'y'`).
15
+ * - A `MaskNumericProp` provided as a function
16
+ * SHALL be invoked with `(canvas, ResolvedOptions)` and the returned
17
+ * number used directly.
18
+ * - Polygon point items SHALL be accepted in
19
+ * either `{ x, y }` object form or `[x, y]` tuple form and coerced to
20
+ * numeric `{ x, y }` internally.
21
+ *
22
+ * ## Why a dedicated module
23
+ *
24
+ * `resolveNumeric` is axis-aware so horizontal values resolve against
25
+ * canvas width and vertical values resolve against canvas height.
26
+ * `coercePoint` lives next to it because both helpers are pure functions
27
+ * consumed by the same mask-factory pipeline.
28
+ *
29
+ * ## Design notes
30
+ *
31
+ * - `resolveNumeric` is total: any input that is not a number, a finite
32
+ * percentage string, or a function falls through to `fallback` rather
33
+ * than throwing.
34
+ * - Percentages are floored (`Math.floor`) to keep rendered placement
35
+ * deterministic across canvas resizes.
36
+ * - The helper does NOT clamp the result against canvas bounds; callers
37
+ * are responsible for any subsequent clamping (the mask factory may
38
+ * expand the canvas to accommodate larger placements in expand layout mode).
39
+ *
40
+ * ## Non-goals
41
+ *
42
+ * - This module does not validate that the supplied `axis` matches the
43
+ * field being resolved. Routing each `MaskConfig` field to the correct
44
+ * axis is the mask factory's responsibility.
45
+ * - This module does not coerce or round the output of factory functions
46
+ * (`(canvas, options) => number`); their return value is used verbatim
47
+ * so consumers retain full control over sub-pixel placement.
48
+ *
49
+ * @module
50
+ */
51
+ import type * as FabricNS from 'fabric';
52
+ import type { MaskNumericProp, PolygonPoint, ResolvedOptions } from '../core/public-types.js';
53
+ /**
54
+ * Axis selector used by {@link resolveNumeric} to decide which canvas
55
+ * dimension a percentage value resolves against.
56
+ *
57
+ * - `'x'` → `canvas.getWidth`
58
+ * - `'y'` → `canvas.getHeight`
59
+ */
60
+ export type Axis = 'x' | 'y';
61
+ /**
62
+ * Resolve a {@link MaskNumericProp} into a concrete pixel number.
63
+ *
64
+ * Resolution rules (in order):
65
+ * 1. If `val` is a `number`, return it unchanged.
66
+ * 2. If `val` is a function, invoke it as `val(canvas, options)` and
67
+ * return the result.
68
+ * 3. If `val` is a string ending in `'%'`, parse the leading number,
69
+ * multiply by `canvas.getWidth` (axis `'x'`) or
70
+ * `canvas.getHeight` (axis `'y'`), floor the product, and return
71
+ * it. Strings that do not parse to a
72
+ * finite number fall through to `fallback`.
73
+ * 4. Anything else (including `undefined`, `null`, non-percent strings,
74
+ * booleans, etc.) returns `fallback`.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * // 50% of an 800px-wide canvas:
79
+ * resolveNumeric('50%', 'x', 0, canvas, options); // → 400
80
+ *
81
+ * // Function form receives the live canvas and ResolvedOptions:
82
+ * resolveNumeric(
83
+ * (canvas) => canvas.getWidth() - 20,
84
+ * 'x',
85
+ * 0,
86
+ * canvas,
87
+ * options,
88
+ * ); // → canvas.getWidth() - 20
89
+ *
90
+ * // Unrecognized input falls back:
91
+ * resolveNumeric(undefined, 'x', 10, canvas, options); // → 10
92
+ * ```
93
+ *
94
+ * @param val - The flexible mask numeric property to resolve.
95
+ * @param axis - Which canvas dimension a percentage resolves against.
96
+ * @param fallback - Value returned when `val` cannot be resolved.
97
+ * @param canvas - Live Fabric.js canvas; only `getWidth`/`getHeight`
98
+ * are read here, but the entire canvas is forwarded to
99
+ * factory functions.
100
+ * @param options - Fully-resolved editor options forwarded to factory
101
+ * functions.
102
+ *
103
+ * @returns The resolved pixel number, or `fallback` when no rule applies.
104
+ */
105
+ export declare function resolveNumeric(val: MaskNumericProp | undefined, axis: Axis, fallback: number, canvas: FabricNS.Canvas, options: ResolvedOptions): number;
106
+ /**
107
+ * Coerce a {@link PolygonPoint} into the canonical `{ x, y }` numeric
108
+ * shape used by Fabric.js polygon construction.
109
+ *
110
+ * Both input forms are accepted so callers may write polygon points in
111
+ * whichever style is most ergonomic at the call site:
112
+ *
113
+ * ```ts
114
+ * coercePoint({ x: 10, y: 20 }); // → { x: 10, y: 20 }
115
+ * coercePoint([10, 20]); // → { x: 10, y: 20 }
116
+ * ```
117
+ *
118
+ * Values are coerced via `Number(...)` so string-encoded coordinates
119
+ * (e.g. coming straight from a JSON payload) round-trip correctly. Any
120
+ * value that fails to coerce becomes `NaN`, matching the rest of the
121
+ * mask pipeline's tolerant input handling — callers that need stricter
122
+ * validation should perform it before constructing the polygon.
123
+ *
124
+ * @param pt - A polygon vertex in object or tuple form.
125
+ * @returns An `{ x, y }` numeric point.
126
+ */
127
+ export declare function coercePoint(pt: PolygonPoint): {
128
+ x: number;
129
+ y: number;
130
+ };
131
+ //# sourceMappingURL=number.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"number.d.ts","sourceRoot":"","sources":["../../../src/utils/number.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE9F;;;;;;GAMG;AACH,MAAM,MAAM,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,cAAc,CAC1B,GAAG,EAAE,eAAe,GAAG,SAAS,EAChC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,QAAQ,CAAC,MAAM,EACvB,OAAO,EAAE,eAAe,GACzB,MAAM,CAgBR;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAKtE"}