js-draw 1.0.1 → 1.0.2

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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bundle.js +1 -1
  3. package/dist/cjs/version.js +1 -1
  4. package/dist/mjs/version.mjs +1 -1
  5. package/docs/img/readme-images/js-draw.jpg +0 -0
  6. package/docs/img/readme-images/unsupported-elements--in-editor.png +0 -0
  7. package/package.json +5 -4
  8. package/dist-test/test_imports/package-lock.json +0 -13
  9. package/dist-test/test_imports/package.json +0 -12
  10. package/dist-test/test_imports/test-imports.js +0 -11
  11. package/dist-test/test_imports/test-require.cjs +0 -14
  12. package/src/Editor.loadFrom.test.ts +0 -24
  13. package/src/Editor.test.ts +0 -107
  14. package/src/Editor.toSVG.test.ts +0 -294
  15. package/src/Editor.ts +0 -1443
  16. package/src/EditorImage.test.ts +0 -117
  17. package/src/EditorImage.ts +0 -609
  18. package/src/EventDispatcher.test.ts +0 -123
  19. package/src/EventDispatcher.ts +0 -72
  20. package/src/Pointer.ts +0 -183
  21. package/src/SVGLoader.test.ts +0 -114
  22. package/src/SVGLoader.ts +0 -672
  23. package/src/UndoRedoHistory.test.ts +0 -34
  24. package/src/UndoRedoHistory.ts +0 -102
  25. package/src/Viewport.ts +0 -322
  26. package/src/bundle/bundled.ts +0 -7
  27. package/src/commands/Command.ts +0 -45
  28. package/src/commands/Duplicate.ts +0 -75
  29. package/src/commands/Erase.ts +0 -95
  30. package/src/commands/SerializableCommand.ts +0 -49
  31. package/src/commands/UnresolvedCommand.ts +0 -37
  32. package/src/commands/invertCommand.ts +0 -58
  33. package/src/commands/lib.ts +0 -16
  34. package/src/commands/localization.ts +0 -47
  35. package/src/commands/uniteCommands.test.ts +0 -23
  36. package/src/commands/uniteCommands.ts +0 -140
  37. package/src/components/AbstractComponent.transformBy.test.ts +0 -23
  38. package/src/components/AbstractComponent.ts +0 -383
  39. package/src/components/BackgroundComponent.test.ts +0 -44
  40. package/src/components/BackgroundComponent.ts +0 -348
  41. package/src/components/ImageComponent.ts +0 -176
  42. package/src/components/RestylableComponent.ts +0 -161
  43. package/src/components/SVGGlobalAttributesObject.ts +0 -79
  44. package/src/components/Stroke.test.ts +0 -137
  45. package/src/components/Stroke.ts +0 -294
  46. package/src/components/TextComponent.test.ts +0 -202
  47. package/src/components/TextComponent.ts +0 -429
  48. package/src/components/UnknownSVGObject.test.ts +0 -10
  49. package/src/components/UnknownSVGObject.ts +0 -60
  50. package/src/components/builders/ArrowBuilder.ts +0 -106
  51. package/src/components/builders/CircleBuilder.ts +0 -100
  52. package/src/components/builders/FreehandLineBuilder.test.ts +0 -24
  53. package/src/components/builders/FreehandLineBuilder.ts +0 -210
  54. package/src/components/builders/LineBuilder.ts +0 -77
  55. package/src/components/builders/PressureSensitiveFreehandLineBuilder.ts +0 -453
  56. package/src/components/builders/RectangleBuilder.ts +0 -73
  57. package/src/components/builders/types.ts +0 -15
  58. package/src/components/lib.ts +0 -31
  59. package/src/components/localization.ts +0 -24
  60. package/src/components/util/StrokeSmoother.ts +0 -302
  61. package/src/components/util/describeComponentList.ts +0 -18
  62. package/src/dialogs/makeAboutDialog.ts +0 -82
  63. package/src/inputEvents.ts +0 -143
  64. package/src/lib.ts +0 -91
  65. package/src/localization.ts +0 -34
  66. package/src/localizations/de.ts +0 -146
  67. package/src/localizations/en.ts +0 -8
  68. package/src/localizations/es.ts +0 -74
  69. package/src/localizations/getLocalizationTable.test.ts +0 -27
  70. package/src/localizations/getLocalizationTable.ts +0 -74
  71. package/src/rendering/Display.ts +0 -247
  72. package/src/rendering/RenderablePathSpec.ts +0 -88
  73. package/src/rendering/RenderingStyle.test.ts +0 -68
  74. package/src/rendering/RenderingStyle.ts +0 -55
  75. package/src/rendering/TextRenderingStyle.ts +0 -55
  76. package/src/rendering/caching/CacheRecord.test.ts +0 -48
  77. package/src/rendering/caching/CacheRecord.ts +0 -76
  78. package/src/rendering/caching/CacheRecordManager.ts +0 -71
  79. package/src/rendering/caching/RenderingCache.test.ts +0 -43
  80. package/src/rendering/caching/RenderingCache.ts +0 -66
  81. package/src/rendering/caching/RenderingCacheNode.ts +0 -404
  82. package/src/rendering/caching/testUtils.ts +0 -35
  83. package/src/rendering/caching/types.ts +0 -34
  84. package/src/rendering/lib.ts +0 -8
  85. package/src/rendering/localization.ts +0 -20
  86. package/src/rendering/renderers/AbstractRenderer.ts +0 -232
  87. package/src/rendering/renderers/CanvasRenderer.ts +0 -312
  88. package/src/rendering/renderers/DummyRenderer.test.ts +0 -41
  89. package/src/rendering/renderers/DummyRenderer.ts +0 -142
  90. package/src/rendering/renderers/SVGRenderer.ts +0 -434
  91. package/src/rendering/renderers/TextOnlyRenderer.test.ts +0 -34
  92. package/src/rendering/renderers/TextOnlyRenderer.ts +0 -68
  93. package/src/shortcuts/KeyBinding.test.ts +0 -61
  94. package/src/shortcuts/KeyBinding.ts +0 -257
  95. package/src/shortcuts/KeyboardShortcutManager.test.ts +0 -95
  96. package/src/shortcuts/KeyboardShortcutManager.ts +0 -163
  97. package/src/shortcuts/lib.ts +0 -3
  98. package/src/testing/createEditor.ts +0 -11
  99. package/src/testing/getUniquePointerId.ts +0 -18
  100. package/src/testing/lib.ts +0 -3
  101. package/src/testing/sendPenEvent.ts +0 -36
  102. package/src/testing/sendTouchEvent.ts +0 -71
  103. package/src/toolbar/AbstractToolbar.ts +0 -542
  104. package/src/toolbar/DropdownToolbar.ts +0 -220
  105. package/src/toolbar/EdgeToolbar.test.ts +0 -54
  106. package/src/toolbar/EdgeToolbar.ts +0 -543
  107. package/src/toolbar/IconProvider.ts +0 -861
  108. package/src/toolbar/constants.ts +0 -1
  109. package/src/toolbar/lib.ts +0 -6
  110. package/src/toolbar/localization.ts +0 -136
  111. package/src/toolbar/types.ts +0 -13
  112. package/src/toolbar/widgets/ActionButtonWidget.ts +0 -39
  113. package/src/toolbar/widgets/BaseToolWidget.ts +0 -81
  114. package/src/toolbar/widgets/BaseWidget.ts +0 -495
  115. package/src/toolbar/widgets/DocumentPropertiesWidget.ts +0 -250
  116. package/src/toolbar/widgets/EraserToolWidget.ts +0 -84
  117. package/src/toolbar/widgets/HandToolWidget.ts +0 -239
  118. package/src/toolbar/widgets/InsertImageWidget.ts +0 -248
  119. package/src/toolbar/widgets/OverflowWidget.ts +0 -92
  120. package/src/toolbar/widgets/PenToolWidget.ts +0 -369
  121. package/src/toolbar/widgets/SelectionToolWidget.ts +0 -195
  122. package/src/toolbar/widgets/TextToolWidget.ts +0 -149
  123. package/src/toolbar/widgets/components/makeColorInput.ts +0 -184
  124. package/src/toolbar/widgets/components/makeFileInput.ts +0 -128
  125. package/src/toolbar/widgets/components/makeGridSelector.ts +0 -179
  126. package/src/toolbar/widgets/components/makeSeparator.ts +0 -17
  127. package/src/toolbar/widgets/components/makeThicknessSlider.ts +0 -62
  128. package/src/toolbar/widgets/keybindings.ts +0 -19
  129. package/src/toolbar/widgets/layout/DropdownLayoutManager.ts +0 -262
  130. package/src/toolbar/widgets/layout/EdgeToolbarLayoutManager.ts +0 -71
  131. package/src/toolbar/widgets/layout/types.ts +0 -74
  132. package/src/toolbar/widgets/lib.ts +0 -13
  133. package/src/tools/BaseTool.ts +0 -169
  134. package/src/tools/Eraser.test.ts +0 -103
  135. package/src/tools/Eraser.ts +0 -173
  136. package/src/tools/FindTool.test.ts +0 -67
  137. package/src/tools/FindTool.ts +0 -153
  138. package/src/tools/InputFilter/FunctionMapper.ts +0 -17
  139. package/src/tools/InputFilter/InputMapper.ts +0 -41
  140. package/src/tools/InputFilter/InputPipeline.test.ts +0 -41
  141. package/src/tools/InputFilter/InputPipeline.ts +0 -34
  142. package/src/tools/InputFilter/InputStabilizer.ts +0 -254
  143. package/src/tools/InputFilter/StrokeKeyboardControl.ts +0 -104
  144. package/src/tools/PanZoom.test.ts +0 -339
  145. package/src/tools/PanZoom.ts +0 -525
  146. package/src/tools/PasteHandler.ts +0 -94
  147. package/src/tools/Pen.test.ts +0 -260
  148. package/src/tools/Pen.ts +0 -284
  149. package/src/tools/PipetteTool.ts +0 -84
  150. package/src/tools/SelectionTool/SelectAllShortcutHandler.ts +0 -29
  151. package/src/tools/SelectionTool/Selection.ts +0 -647
  152. package/src/tools/SelectionTool/SelectionHandle.ts +0 -142
  153. package/src/tools/SelectionTool/SelectionTool.test.ts +0 -370
  154. package/src/tools/SelectionTool/SelectionTool.ts +0 -510
  155. package/src/tools/SelectionTool/TransformMode.ts +0 -112
  156. package/src/tools/SelectionTool/types.ts +0 -11
  157. package/src/tools/SoundUITool.ts +0 -221
  158. package/src/tools/TextTool.ts +0 -339
  159. package/src/tools/ToolController.ts +0 -224
  160. package/src/tools/ToolEnabledGroup.ts +0 -14
  161. package/src/tools/ToolSwitcherShortcut.ts +0 -39
  162. package/src/tools/ToolbarShortcutHandler.ts +0 -39
  163. package/src/tools/UndoRedoShortcut.test.ts +0 -62
  164. package/src/tools/UndoRedoShortcut.ts +0 -24
  165. package/src/tools/keybindings.ts +0 -85
  166. package/src/tools/lib.ts +0 -22
  167. package/src/tools/localization.ts +0 -76
  168. package/src/types.ts +0 -151
  169. package/src/util/ReactiveValue.test.ts +0 -168
  170. package/src/util/ReactiveValue.ts +0 -241
  171. package/src/util/assertions.ts +0 -55
  172. package/src/util/fileToBase64.ts +0 -18
  173. package/src/util/guessKeyCodeFromKey.ts +0 -36
  174. package/src/util/listPrefixMatch.ts +0 -19
  175. package/src/util/stopPropagationOfScrollingWheelEvents.ts +0 -20
  176. package/src/util/untilNextAnimationFrame.ts +0 -9
  177. package/src/util/waitForAll.ts +0 -18
  178. package/src/util/waitForTimeout.ts +0 -9
  179. package/src/version.test.ts +0 -12
  180. package/src/version.ts +0 -3
  181. package/tools/allLocales.js +0 -4
  182. package/tools/copyREADME.ts +0 -62
package/src/types.ts DELETED
@@ -1,151 +0,0 @@
1
- // Types related to the image editor
2
-
3
- import type EventDispatcher from './EventDispatcher';
4
- import type { Mat33, Point2, Vec2, Rect2, Color4 } from '@js-draw/math';
5
- import type BaseTool from './tools/BaseTool';
6
- import type AbstractComponent from './components/AbstractComponent';
7
- import type Command from './commands/Command';
8
- import type { WidgetContentLayoutManager } from './toolbar/widgets/layout/types';
9
-
10
- export type EditorNotifier = EventDispatcher<EditorEventType, EditorEventDataType>;
11
-
12
- export enum EditorEventType {
13
- ToolEnabled,
14
- ToolDisabled,
15
- ToolUpdated,
16
-
17
- UndoRedoStackUpdated,
18
- CommandDone,
19
- CommandUndone,
20
- ObjectAdded,
21
-
22
- ViewportChanged,
23
- DisplayResized,
24
-
25
- SelectionUpdated,
26
-
27
- /** @internal */
28
- ColorPickerToggled,
29
-
30
- /** @internal */
31
- ColorPickerColorSelected,
32
-
33
- /** @deprecated @internal */
34
- ToolbarDropdownShown,
35
- }
36
-
37
- // Types of `EditorUndoStackUpdated` events.
38
- export enum UndoEventType {
39
- CommandDone,
40
- CommandUndone,
41
- CommandRedone,
42
- }
43
-
44
- type EditorToolEventType = EditorEventType.ToolEnabled
45
- | EditorEventType.ToolDisabled
46
- | EditorEventType.ToolUpdated;
47
-
48
- export interface EditorToolEvent {
49
- readonly kind: EditorToolEventType;
50
- readonly tool: BaseTool;
51
- }
52
-
53
- export interface EditorObjectEvent {
54
- readonly kind: EditorEventType.ObjectAdded;
55
- readonly object: AbstractComponent;
56
- }
57
-
58
- export interface EditorViewportChangedEvent {
59
- readonly kind: EditorEventType.ViewportChanged;
60
-
61
- // Canvas -> screen transform
62
- readonly newTransform: Mat33;
63
- readonly oldTransform: Mat33;
64
- }
65
-
66
- export interface DisplayResizedEvent {
67
- readonly kind: EditorEventType.DisplayResized;
68
- readonly newSize: Vec2;
69
- }
70
-
71
- export interface EditorUndoStackUpdated {
72
- readonly kind: EditorEventType.UndoRedoStackUpdated;
73
-
74
- readonly undoStackSize: number;
75
- readonly redoStackSize: number;
76
-
77
- readonly command?: Command;
78
- readonly stackUpdateType: UndoEventType;
79
- }
80
-
81
- export interface CommandDoneEvent {
82
- readonly kind: EditorEventType.CommandDone;
83
- readonly command: Command;
84
- }
85
-
86
- export interface CommandUndoneEvent {
87
- readonly kind: EditorEventType.CommandUndone;
88
- readonly command: Command;
89
- }
90
-
91
- export interface SelectionUpdated {
92
- readonly kind: EditorEventType.SelectionUpdated;
93
- readonly selectedComponents: AbstractComponent[];
94
- readonly tool: BaseTool;
95
- }
96
-
97
- export interface ColorPickerToggled {
98
- readonly kind: EditorEventType.ColorPickerToggled;
99
- readonly open: boolean;
100
- }
101
-
102
- export interface ColorPickerColorSelected {
103
- readonly kind: EditorEventType.ColorPickerColorSelected;
104
- readonly color: Color4;
105
- }
106
-
107
- export interface ToolbarDropdownShownEvent {
108
- readonly kind: EditorEventType.ToolbarDropdownShown;
109
-
110
- // True iff the source dropdown is toplevel.
111
- readonly fromToplevelDropdown: boolean;
112
- readonly layoutManager: WidgetContentLayoutManager;
113
- }
114
-
115
- export type EditorEventDataType = EditorToolEvent | EditorObjectEvent
116
- | EditorViewportChangedEvent | DisplayResizedEvent
117
- | EditorUndoStackUpdated | CommandDoneEvent | CommandUndoneEvent
118
- | SelectionUpdated
119
- | ColorPickerToggled | ColorPickerColorSelected
120
- | ToolbarDropdownShownEvent;
121
-
122
-
123
- // Returns a Promise to indicate that the event source should pause until the Promise resolves.
124
- // Returns null to continue loading without pause.
125
- // [totalToProcess] can be an estimate and may change if a better estimate becomes available.
126
- export type OnProgressListener =
127
- (amountProcessed: number, totalToProcess: number)=> Promise<void>|null|void;
128
-
129
- export type ComponentAddedListener = (component: AbstractComponent)=> Promise<void>|void;
130
-
131
- // Called when a new estimate for the import/export rect has been generated. This can be called multiple times.
132
- // Only the last call to this listener must be accurate.
133
- // The import/export rect is also returned by [start].
134
- export type OnDetermineExportRectListener = (exportRect: Rect2)=> void;
135
-
136
- export interface ImageLoader {
137
- start(
138
- onAddComponent: ComponentAddedListener,
139
- onProgressListener: OnProgressListener,
140
- onDetermineExportRect?: OnDetermineExportRectListener,
141
- ): Promise<void>;
142
- }
143
-
144
- export interface StrokeDataPoint {
145
- pos: Point2;
146
- width: number;
147
-
148
- /** Time in milliseconds (e.g. as returned by `performance.now()`). */
149
- time: number;
150
- color: Color4;
151
- }
@@ -1,168 +0,0 @@
1
- import { ReactiveValue, MutableReactiveValue } from './ReactiveValue';
2
-
3
- describe('ReactiveValue', () => {
4
- it('should fire update listeners on update', () => {
5
- const value = ReactiveValue.fromInitialValue(3);
6
- const listener = jest.fn();
7
- const { remove: removeListener } = value.onUpdateAndNow(listener);
8
-
9
- expect(listener).toHaveBeenCalledWith(3);
10
- expect(listener).toHaveBeenCalledTimes(1);
11
-
12
- value.set(2);
13
-
14
- expect(listener).toHaveBeenLastCalledWith(2);
15
- expect(listener).toHaveBeenCalledTimes(2);
16
-
17
- removeListener();
18
-
19
- value.set(4);
20
- expect(listener).toHaveBeenCalledTimes(2);
21
-
22
- // Should be able to call remove multiple times without error.
23
- removeListener();
24
- value.set(6);
25
- });
26
-
27
- it('values from callbacks should derive values from the callback', () => {
28
- const sourceValue1 = ReactiveValue.fromInitialValue('test');
29
- const sourceValue2 = ReactiveValue.fromInitialValue('test2');
30
- const sourceValue3 = ReactiveValue.fromImmutable(3);
31
-
32
- // Create a value that is computed from the three above values.
33
- const derivedValue1 = ReactiveValue.fromCallback(() => {
34
- return [
35
- sourceValue1.get(),
36
- sourceValue2.get(),
37
- sourceValue3.get(),
38
- ].join(',');
39
- }, [ sourceValue1, sourceValue2, sourceValue3 ]);
40
-
41
- const derivedValue1Listener = jest.fn();
42
- derivedValue1.onUpdate(derivedValue1Listener);
43
-
44
- expect(derivedValue1.get()).toBe('test,test2,3');
45
- expect(derivedValue1Listener).toHaveBeenCalledTimes(0);
46
-
47
- // Create a value that is computed just from derivedValue1
48
- const derivedValue2 = ReactiveValue.fromCallback(() => {
49
- return derivedValue1.get() + '!';
50
- }, [ derivedValue1 ]);
51
-
52
- const derivedValue2Listener = jest.fn();
53
- derivedValue2.onUpdate(derivedValue2Listener);
54
-
55
- expect(derivedValue2.get()).toBe('test,test2,3!');
56
- expect(derivedValue1Listener).toHaveBeenCalledTimes(0);
57
- expect(derivedValue2Listener).toHaveBeenCalledTimes(0);
58
-
59
- // Changing the source values should update the derived values
60
- sourceValue1.set('...');
61
-
62
- // The change should trigger the listeners
63
- expect(derivedValue1Listener).toHaveBeenCalledTimes(1);
64
- expect(derivedValue1Listener).toHaveBeenCalledWith(derivedValue1.get());
65
- expect(derivedValue2Listener).toHaveBeenCalledTimes(1);
66
- expect(derivedValue2Listener).toHaveBeenCalledWith(derivedValue2.get());
67
-
68
- // The values should be updated to the expected values.
69
- expect(derivedValue1.get()).toBe('...,test2,3');
70
- expect(derivedValue2.get()).toBe('...,test2,3!');
71
-
72
- // Something similar should happen when other values are changed
73
- sourceValue1.set('1');
74
- sourceValue2.set('2');
75
-
76
- expect(derivedValue1.get()).toBe('1,2,3');
77
- expect(derivedValue2.get()).toBe('1,2,3!');
78
- });
79
-
80
- it('should be able to create values from properties', () => {
81
- const sourceValue = ReactiveValue.fromInitialValue({
82
- a: 1,
83
- b: 2,
84
- c: { d: 3 },
85
- });
86
-
87
- const destValue1 = MutableReactiveValue.fromProperty(sourceValue, 'c');
88
- const destValue2 = MutableReactiveValue.fromProperty(sourceValue, 'b');
89
- expect(destValue1.get()).toBe(sourceValue.get().c);
90
- expect(destValue2.get()).toBe(2);
91
-
92
- // Updating the source value should update the destination values.
93
- sourceValue.set({
94
- ...sourceValue.get(),
95
- c: { d: 4 },
96
- });
97
-
98
- expect(destValue1.get()).toBe(sourceValue.get().c);
99
- expect(destValue1.get().d).toBe(4);
100
- expect(destValue2.get()).toBe(2);
101
-
102
- sourceValue.set({
103
- a: 3,
104
- b: 4,
105
- c: { d: 5 },
106
- });
107
- expect(destValue1.get().d).toBe(5);
108
- expect(destValue2.get()).toBe(4);
109
-
110
- // Updating the destination values should update the source values
111
- destValue1.set({ d: 8 });
112
- expect(sourceValue.get().c.d).toBe(8);
113
-
114
- destValue2.set(5);
115
- expect(sourceValue.get().b).toBe(5);
116
- });
117
-
118
- it('mutable map should be bidirectional', () => {
119
- const sourceValue = ReactiveValue.fromInitialValue(5);
120
- const mappedValue = MutableReactiveValue.map(
121
- sourceValue, a => a ** 2, b => Math.sqrt(b),
122
- );
123
-
124
- expect(mappedValue.get()).toBeCloseTo(25);
125
-
126
- // Changing the destination should change the source
127
- mappedValue.set(26);
128
- expect(sourceValue.get()).toBeCloseTo(Math.sqrt(26));
129
-
130
- // Changing the source should change the destination
131
- sourceValue.set(10);
132
- expect(mappedValue.get()).toBeCloseTo(100);
133
- });
134
-
135
- it('single-directional map should apply the given mapping function', () => {
136
- const sourceValue = ReactiveValue.fromInitialValue(1);
137
- const midValue = ReactiveValue.map(sourceValue, a => a * 2);
138
- const destValue = ReactiveValue.map(midValue, _ => 0);
139
-
140
- const sourceUpdateFn = jest.fn();
141
- const midUpdateFn = jest.fn();
142
- const destUpdateFn = jest.fn();
143
-
144
- sourceValue.onUpdate(sourceUpdateFn);
145
- midValue.onUpdate(midUpdateFn);
146
- destValue.onUpdate(destUpdateFn);
147
-
148
- // Initial value checking
149
- expect(destValue.get()).toBe(0);
150
- expect(sourceUpdateFn).toHaveBeenCalledTimes(0);
151
- expect(midUpdateFn).toHaveBeenCalledTimes(0);
152
- expect(destUpdateFn).toHaveBeenCalledTimes(0);
153
-
154
- // Setting to the same value should trigger no listeners
155
- sourceValue.set(1);
156
- expect(sourceUpdateFn).toHaveBeenCalledTimes(0);
157
- expect(midUpdateFn).toHaveBeenCalledTimes(0);
158
- expect(destUpdateFn).toHaveBeenCalledTimes(0);
159
-
160
- // Changing the initial value should only fire listeners that
161
- // result in a different value
162
- sourceValue.set(2);
163
- expect(sourceUpdateFn).toHaveBeenCalledTimes(1);
164
- expect(midUpdateFn).toHaveBeenCalledTimes(1);
165
- expect(destUpdateFn).toHaveBeenCalledTimes(0);
166
- expect(midValue.get()).toBe(4);
167
- });
168
- });
@@ -1,241 +0,0 @@
1
-
2
- type ListenerResult = { remove(): void; };
3
- type UpdateCallback<T> = (value: T)=>void;
4
-
5
- const noOpUpdateListenerResult = {
6
- remove() { }
7
- };
8
-
9
- /**
10
- * An update listener that does nothing. Useful for reactive values
11
- * that will never change.
12
- */
13
- const noOpSetUpdateListener = () => {
14
- return noOpUpdateListenerResult;
15
- };
16
-
17
- /**
18
- * A `ReactiveValue` is a value that
19
- * - updates periodically,
20
- * - can fire listeners when it updates,
21
- * - and can be chanined together with other `ReactiveValue`s.
22
- *
23
- * A `ReactiveValue` is a read-only view. See {@link MutableReactiveValue} for a
24
- * read-write view.
25
- *
26
- * Static methods in the `ReactiveValue` and `MutableReactiveValue` classes are
27
- * constructors (e.g. `fromImmutable`).
28
- */
29
- export abstract class ReactiveValue<T> {
30
- /**
31
- * Returns a reference to the current value of this `ReactiveValue`.
32
- *
33
- * The result of this **should not be modified** (use `setValue` instead).
34
- */
35
- public abstract get(): T;
36
-
37
- /**
38
- * Registers a listener that is notified when the value of this changes.
39
- */
40
- public abstract onUpdate(listener: UpdateCallback<T>): ListenerResult;
41
-
42
- /**
43
- * Calls `callback` immediately, then registers `callback` as an onUpdateListener.
44
- *
45
- * @see {@link onUpdate}.
46
- */
47
- public abstract onUpdateAndNow(callback: UpdateCallback<T>): ListenerResult;
48
-
49
- /** Creates a `ReactiveValue` with an initial value, `initialValue`. */
50
- public static fromInitialValue<T> (
51
- initialValue: T
52
- ): MutableReactiveValue<T>{
53
- return new ReactiveValueImpl(initialValue);
54
- }
55
-
56
- /** Returns a `ReactiveValue` that is **known** will never change. */
57
- public static fromImmutable<T> (
58
- value: T
59
- ): ReactiveValue<T>{
60
- return {
61
- get: () => value,
62
- onUpdate: noOpSetUpdateListener,
63
- onUpdateAndNow: callback => {
64
- callback(value);
65
- return noOpUpdateListenerResult;
66
- },
67
- };
68
- }
69
-
70
- /**
71
- * Creates a `ReactiveValue` whose values come from `callback`.
72
- *
73
- * `callback` is called whenever any of `sourceValues` are updated and initially to
74
- * set the initial value of the result.
75
- */
76
- public static fromCallback<T> (
77
- callback: ()=>T, sourceValues: ReactiveValue<any>[]
78
- ): ReactiveValue<T>{
79
- const result = new ReactiveValueImpl(callback());
80
- const resultRef = window.WeakRef ? new WeakRef(result) : { deref: () => result };
81
-
82
- for (const value of sourceValues) {
83
- const listener = value.onUpdate(() => {
84
- // Use resultRef to allow `result` to be garbage collected
85
- // despite this listener.
86
- const value = resultRef.deref();
87
- if (value) {
88
- value.set(callback());
89
- } else {
90
- listener.remove();
91
- }
92
- });
93
- }
94
-
95
- return result;
96
- }
97
-
98
- /**
99
- * Returns a reactive value derived from a single `source`.
100
- *
101
- * If `inverseMap` is `undefined`, the result is a read-only view.
102
- */
103
- public static map<A, B> (
104
- source: ReactiveValue<A>,
105
- map: (a: A)=>B,
106
- inverseMap?: undefined,
107
- ): ReactiveValue<B>;
108
-
109
-
110
- /**
111
- * Returns a reactive value derived from a single `source`.
112
- */
113
- public static map<A, B> (
114
- source: ReactiveValue<A>,
115
- map: (a: A)=>B,
116
- inverseMap: (b: B)=>A,
117
- ): MutableReactiveValue<B>;
118
-
119
-
120
- public static map<A, B> (
121
- source: MutableReactiveValue<A>,
122
- map: (a: A)=>B,
123
- inverseMap: ((b: B)=>A)|undefined,
124
- ): ReactiveValue<B>|MutableReactiveValue<B>{
125
- const result = ReactiveValue.fromInitialValue(map(source.get()));
126
-
127
- let expectedResultValue = result.get();
128
- source.onUpdate(newValue => {
129
- expectedResultValue = map(newValue);
130
- result.set(expectedResultValue);
131
- });
132
-
133
- if (inverseMap) {
134
- result.onUpdate(newValue => {
135
- // Prevent infinite loops if inverseMap is not a true
136
- // inverse.
137
- if (newValue !== expectedResultValue) {
138
- source.set(inverseMap(newValue));
139
- }
140
- });
141
- }
142
-
143
- return result;
144
- }
145
- }
146
-
147
- export abstract class MutableReactiveValue<T> extends ReactiveValue<T> {
148
- /**
149
- * Changes the value of this and fires all update listeners.
150
- *
151
- * @see {@link onUpdate}
152
- */
153
- public abstract set(newValue: T): void;
154
-
155
- public static fromProperty<SourceType extends object, Name extends keyof SourceType> (
156
- sourceValue: MutableReactiveValue<SourceType>,
157
- propertyName: Name,
158
- ): MutableReactiveValue<SourceType[Name]>{
159
- const child = ReactiveValue.fromInitialValue(
160
- sourceValue.get()[propertyName]
161
- );
162
- const childRef = new WeakRef(child);
163
-
164
- // When the source is updated...
165
- const sourceListener = sourceValue.onUpdate(newValue => {
166
- const childValue = childRef.deref();
167
-
168
- if (childValue) {
169
- childValue.set(newValue[propertyName]);
170
- } else {
171
- // TODO: What if `sourceValue` would be dropped before
172
- // the child value?
173
- sourceListener.remove();
174
- }
175
- });
176
-
177
- // When the child is updated, also apply the update to the
178
- // parent.
179
- child.onUpdate(newValue => {
180
- sourceValue.set({
181
- ...sourceValue.get(),
182
- [propertyName]: newValue,
183
- });
184
- });
185
-
186
- return child;
187
- }
188
- }
189
-
190
- // @internal
191
- class ReactiveValueImpl<T> extends MutableReactiveValue<T> {
192
- #value: T;
193
- #onUpdateListeners: Array<(value: T)=>void>;
194
-
195
- public constructor(initialValue: T) {
196
- super();
197
-
198
- this.#value = initialValue;
199
- this.#onUpdateListeners = [];
200
- }
201
-
202
- public set(newValue: T) {
203
- if (this.#value === newValue) {
204
- return;
205
- }
206
-
207
- this.#value = newValue;
208
-
209
- for (const listener of this.#onUpdateListeners) {
210
- listener(newValue);
211
- }
212
- }
213
-
214
- public get() {
215
- return this.#value;
216
- }
217
-
218
- public onUpdate(listener: (value: T)=>void) {
219
- // **Note**: If memory is a concern, listeners should avoid referencing this
220
- // reactive value directly. Doing so allows the value to be garbage collected when
221
- // no longer referenced.
222
-
223
- this.#onUpdateListeners.push(listener);
224
-
225
- return {
226
- remove: () => {
227
- this.#onUpdateListeners = this.#onUpdateListeners.filter(otherListener => {
228
- return otherListener !== listener;
229
- });
230
- },
231
- };
232
- }
233
-
234
- public onUpdateAndNow(callback: (value: T)=>void) {
235
- callback(this.get());
236
- return this.onUpdate(callback);
237
- }
238
- }
239
-
240
-
241
- export default ReactiveValue;
@@ -1,55 +0,0 @@
1
-
2
- /**
3
- * Compile-time assertion that a branch of code is unreachable.
4
- * @internal
5
- */
6
- export const assertUnreachable = (key: never): never => {
7
- // See https://stackoverflow.com/a/39419171/17055750
8
- throw new Error(`Should be unreachable. Key: ${key}.`);
9
- };
10
-
11
-
12
- /**
13
- * Throws an exception if the typeof given value is not a number or `value` is NaN.
14
- *
15
- * @example
16
- * ```ts
17
- * const foo: unknown = 3;
18
- * assertIsNumber(foo);
19
- *
20
- * assertIsNumber('hello, world'); // throws an Error.
21
- * ```
22
- *
23
- *
24
- */
25
- export const assertIsNumber = (value: any, allowNaN: boolean = false): value is number => {
26
- if (typeof value !== 'number' || (!allowNaN && isNaN(value))) {
27
- throw new Error('Given value is not a number');
28
- // return false;
29
- }
30
-
31
- return true;
32
- };
33
-
34
- /**
35
- * Throws if any of `values` is not of type number.
36
- */
37
- export const assertIsNumberArray = (
38
- values: any[], allowNaN: boolean = false
39
- ): values is number[] => {
40
- if (typeof values !== 'object') {
41
- throw new Error('Asserting isNumberArray: Given entity is not an array');
42
- }
43
-
44
- if (!assertIsNumber(values['length'])) {
45
- return false;
46
- }
47
-
48
- for (const value of values) {
49
- if (!assertIsNumber(value, allowNaN)) {
50
- return false;
51
- }
52
- }
53
-
54
- return true;
55
- };
@@ -1,18 +0,0 @@
1
-
2
- type ProgressListener = (evt: ProgressEvent<FileReader>)=> void;
3
- const fileToBase64 = (file: File, onprogress?: ProgressListener): Promise<string|null> => {
4
- const reader = new FileReader();
5
-
6
- return new Promise((resolve: (result: string|null)=>void, reject) => {
7
- reader.onload = () => resolve(reader.result as string|null);
8
- reader.onerror = reject;
9
- reader.onabort = reject;
10
- reader.onprogress = (evt) => {
11
- onprogress?.(evt);
12
- };
13
-
14
- reader.readAsDataURL(file);
15
- });
16
- };
17
-
18
- export default fileToBase64;
@@ -1,36 +0,0 @@
1
-
2
- // See https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values for
3
- // more
4
- const keyToKeyCode: Record<string, string> = {
5
- 'Control': 'ControlLeft',
6
- '=': 'Equal',
7
- '-': 'Minus',
8
- ';': 'Semicolon',
9
- ' ': 'Space',
10
- };
11
-
12
- /**
13
- * Attempts to guess the .code value corresponding to the given key.
14
- *
15
- * Use this to facilitate testing.
16
- *
17
- * If no matching keycode is found, returns `key`.
18
- */
19
- const guessKeyCodeFromKey = (key: string) => {
20
- const upperKey = key.toUpperCase();
21
- if ('A' <= upperKey && upperKey <= 'Z') {
22
- return `Key${upperKey}`;
23
- }
24
-
25
- if ('0' <= key && key <= '9') {
26
- return `Digit${key}`;
27
- }
28
-
29
- if (key in keyToKeyCode) {
30
- return keyToKeyCode[key];
31
- }
32
-
33
- return key;
34
- };
35
-
36
- export default guessKeyCodeFromKey;
@@ -1,19 +0,0 @@
1
-
2
- /**
3
- * Returns true iff all elements in the shorter list equal (===) the elements
4
- * in the longer list.
5
- */
6
- const listPrefixMatch = <T> (a: T[], b: T[]) => {
7
- const shorter = a.length < b.length ? a : b;
8
- const longer = shorter === a ? b : a;
9
-
10
- for (let i = 0; i < shorter.length; i++) {
11
- if (shorter[i] !== longer[i]) {
12
- return false;
13
- }
14
- }
15
-
16
- return true;
17
- };
18
-
19
- export default listPrefixMatch;
@@ -1,20 +0,0 @@
1
-
2
- const stopPropagationOfScrollingWheelEvents = (scrollingContainer: HTMLElement) => {
3
- scrollingContainer.onwheel = (event) => {
4
- const hasScroll = scrollingContainer.clientWidth !== scrollingContainer.scrollWidth
5
- && event.deltaX !== 0;
6
- const eventScrollsPastLeft =
7
- scrollingContainer.scrollLeft + event.deltaX <= 0;
8
- const scrollRight = scrollingContainer.scrollLeft + scrollingContainer.clientWidth;
9
- const eventScrollsPastRight =
10
- scrollRight + event.deltaX > scrollingContainer.scrollWidth;
11
-
12
- // Stop the editor from receiving the event if it will scroll the pen type selector
13
- // instead.
14
- if (hasScroll && !eventScrollsPastLeft && !eventScrollsPastRight) {
15
- event.stopPropagation();
16
- }
17
- };
18
- };
19
-
20
- export default stopPropagationOfScrollingWheelEvents;