@dvrd/dvr-controls 1.0.14 → 1.0.16

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 (180) hide show
  1. package/index.ts +8 -1
  2. package/package.json +29 -23
  3. package/src/js/button/button.tsx +102 -0
  4. package/src/js/button/buttonController.tsx +179 -0
  5. package/src/js/button/closeButton.tsx +29 -0
  6. package/src/js/button/dvrdButton.tsx +128 -0
  7. package/src/js/button/outlinedButton.tsx +105 -0
  8. package/src/js/button/simpleButton.tsx +163 -0
  9. package/src/js/button/style/button.scss +95 -0
  10. package/src/js/button/style/closeButton.scss +15 -0
  11. package/src/js/button/style/dvrdButton.scss +30 -0
  12. package/src/js/button/style/outlinedButton.scss +84 -0
  13. package/src/js/button/style/simpleButton.scss +80 -0
  14. package/src/js/carousel/DVRCarousel.tsx +163 -0
  15. package/src/js/carousel/DVRCarouselController.tsx +95 -0
  16. package/src/js/carousel/style/DVRCarousel.scss +38 -0
  17. package/src/js/checkbox/checkbox.tsx +148 -0
  18. package/src/js/checkbox/checkboxController.tsx +131 -0
  19. package/src/js/checkbox/style/checkbox.scss +109 -0
  20. package/src/js/colorPicker/colorPicker.tsx +118 -0
  21. package/src/js/colorPicker/style/colorPicker.scss +20 -0
  22. package/src/js/date/dvrdDatePicker.tsx +357 -0
  23. package/src/js/date/style/dvrdDatePicker.scss +307 -0
  24. package/src/js/dialog/dialog.tsx +207 -0
  25. package/src/js/dialog/dialogController.tsx +70 -0
  26. package/src/js/dialog/inlineDialog.tsx +127 -0
  27. package/src/js/dialog/style/dialog.scss +61 -0
  28. package/src/js/events/withEvents.tsx +40 -0
  29. package/src/js/head/DVRHead.tsx +49 -0
  30. package/src/js/header/DVRHeader.tsx +417 -0
  31. package/src/js/header/style/header.scss +206 -0
  32. package/src/js/icon/awesomeIcon.tsx +20 -0
  33. package/src/js/image/imageUpload.tsx +69 -0
  34. package/src/js/image/style/imageUpload.scss +11 -0
  35. package/src/js/info/info.tsx +136 -0
  36. package/src/js/info/style/info.scss +39 -0
  37. package/src/js/input/animated/animatedTextField.tsx +159 -0
  38. package/src/js/input/date/dateField.tsx +360 -0
  39. package/src/js/input/date/dateFieldController.tsx +245 -0
  40. package/src/js/input/date/datePicker/datePicker.tsx +186 -0
  41. package/src/js/input/date/datePicker/style/datePicker.scss +102 -0
  42. package/src/js/input/date/input/dateInput.tsx +214 -0
  43. package/src/js/input/date/style/dateField.scss +40 -0
  44. package/src/js/input/date/timePicker/style/timePicker.scss +95 -0
  45. package/src/js/input/date/timePicker/timePicker.tsx +143 -0
  46. package/src/js/input/editor/DVREditor.tsx +21 -0
  47. package/src/js/input/number/numberInput.tsx +157 -0
  48. package/src/js/input/password/passwordInput.tsx +140 -0
  49. package/src/js/input/password/passwordRules.tsx +48 -0
  50. package/src/js/input/password/style/passwordInput.scss +39 -0
  51. package/src/js/input/password/style/passwordRules.scss +41 -0
  52. package/src/js/input/simple/style/simpleInput.scss +98 -0
  53. package/src/js/input/simple/v2/simpleInputV2.tsx +178 -0
  54. package/src/js/input/style/input.scss +138 -0
  55. package/src/js/input/v2/inputController_v2.tsx +250 -0
  56. package/src/js/input/v2/input_v2.tsx +7 -0
  57. package/src/js/label/label.tsx +196 -0
  58. package/src/js/label/style/label.scss +4 -0
  59. package/src/js/link/link.tsx +38 -0
  60. package/src/js/link/style/link.scss +30 -0
  61. package/src/js/loader/loader.tsx +79 -0
  62. package/src/js/loader/loaderController.tsx +61 -0
  63. package/src/js/loader/style/loader.scss +53 -0
  64. package/src/js/media/media.tsx +72 -0
  65. package/src/js/navigator/navigator.tsx +51 -0
  66. package/src/js/optionsList/dvrdOptionsList.tsx +112 -0
  67. package/src/js/optionsList/style/dvrdOptionsList.scss +84 -0
  68. package/src/js/optionsMenu/optionsMenu.tsx +187 -0
  69. package/src/js/optionsMenu/style/optionsMenu.scss +70 -0
  70. package/src/js/pdf/element/pdfElement.tsx +315 -0
  71. package/src/js/pdf/element/style/pdfElement.scss +111 -0
  72. package/src/js/pdf/history/pdfHistory.ts +57 -0
  73. package/src/js/pdf/image/pdfImage.tsx +175 -0
  74. package/src/js/pdf/image/style/pdfImage.scss +34 -0
  75. package/src/js/pdf/invoiceTable/pdfInvoiceTable.tsx +176 -0
  76. package/src/js/pdf/invoiceTable/style/pdfInvoiceTable.scss +32 -0
  77. package/src/js/pdf/pdfTemplateCreator.tsx +279 -0
  78. package/src/js/pdf/settings/buttons/iconButton.tsx +49 -0
  79. package/src/js/pdf/settings/buttons/style/iconButton.scss +50 -0
  80. package/src/js/pdf/settings/image/pdfImageSettings.tsx +82 -0
  81. package/src/js/pdf/settings/image/style/pdfImageSettings.scss +9 -0
  82. package/src/js/pdf/settings/invoiceTable/pdfInvoiceTableSettings.tsx +141 -0
  83. package/src/js/pdf/settings/invoiceTable/style/pdfInvoiceTableSettings.scss +38 -0
  84. package/src/js/pdf/settings/pdfElementSettings.tsx +86 -0
  85. package/src/js/pdf/settings/style/pdfElementSettings.scss +56 -0
  86. package/src/js/pdf/settings/text/pdfTextSettings.tsx +202 -0
  87. package/src/js/pdf/settings/text/style/pdfTextSettings.scss +94 -0
  88. package/src/js/pdf/style/pdfTemplateCreator.scss +118 -0
  89. package/src/js/pdf/text/pdfText.tsx +267 -0
  90. package/src/js/pdf/text/style/pdfText.scss +22 -0
  91. package/src/js/pdf/v2/pdfElement/pdfDraggableElement.tsx +193 -0
  92. package/src/js/pdf/v2/types/pdfTemplateTypes.ts +27 -0
  93. package/src/js/popup/style/withBackground.scss +29 -0
  94. package/src/js/popup/withBackground.tsx +92 -0
  95. package/src/js/select/async/asyncSelect.tsx +46 -0
  96. package/src/js/select/async/style/asyncSelect.scss +23 -0
  97. package/src/js/select/dvrdSelect.tsx +214 -0
  98. package/src/js/select/dvrdSelectController.tsx +81 -0
  99. package/src/js/select/select.tsx +310 -0
  100. package/src/js/select/selectController.tsx +341 -0
  101. package/src/js/select/style/dvrdSelect.scss +140 -0
  102. package/src/js/select/style/select.scss +199 -0
  103. package/src/js/sidebarMenu/sidebarMenu.tsx +167 -0
  104. package/src/js/sidebarMenu/style/sidebarMenu.scss +167 -0
  105. package/src/js/slider/DVRSlider.tsx +107 -0
  106. package/src/js/slider/style/DVRSlider.scss +88 -0
  107. package/src/js/snackbar/snackbar.tsx +72 -0
  108. package/src/js/snackbar/snackbarController.tsx +104 -0
  109. package/src/js/snackbar/style/snackbar.scss +46 -0
  110. package/src/js/switch/dvrdSwitch.tsx +53 -0
  111. package/src/js/switch/style/dvrdSwitch.scss +47 -0
  112. package/src/js/switch/style/switch.scss +84 -0
  113. package/src/js/switch/switch.tsx +115 -0
  114. package/src/js/switch/switchController.tsx +97 -0
  115. package/src/js/textField/dvrdInput.tsx +219 -0
  116. package/src/js/textField/dvrdInputController.tsx +97 -0
  117. package/src/js/textField/dvrdNumberInput.tsx +141 -0
  118. package/src/js/textField/dvrdPasswordInput.tsx +40 -0
  119. package/src/js/textField/style/dvrdInput.scss +114 -0
  120. package/src/js/textField/style/dvrdPassword.scss +15 -0
  121. package/src/js/topButton/style/topButton.scss +54 -0
  122. package/src/js/topButton/topButton.tsx +136 -0
  123. package/src/js/util/analyticsUtil.ts +41 -0
  124. package/src/js/util/colorUtil.ts +230 -0
  125. package/src/js/util/componentUtil.tsx +59 -0
  126. package/src/js/util/constants.ts +12 -0
  127. package/src/js/util/controlContext.tsx +46 -0
  128. package/src/js/util/controlUtil.ts +107 -0
  129. package/src/js/util/cookieUtil.ts +17 -0
  130. package/src/js/util/eventUtil.ts +65 -0
  131. package/src/js/util/googleUtil.ts +88 -0
  132. package/src/js/util/interfaces.ts +180 -0
  133. package/src/js/util/jwtUtil.ts +72 -0
  134. package/src/js/util/miscUtil.ts +170 -0
  135. package/src/js/util/momentUtil.ts +45 -0
  136. package/src/js/util/pdfUtil.ts +124 -0
  137. package/src/js/util/requestUtil.ts +145 -0
  138. package/src/js/util/responsiveUtil.ts +37 -0
  139. package/src/js/util/validationUtil.ts +13 -0
  140. package/src/res/img/lock-handle.png +0 -0
  141. package/src/res/img/lock-handle.webp +0 -0
  142. package/src/res/img/lock.png +0 -0
  143. package/src/res/img/lock.webp +0 -0
  144. package/src/style/common-icons-variables.scss +140 -0
  145. package/src/style/common-icons.scss +714 -0
  146. package/src/style/common-variables.scss +243 -0
  147. package/src/style/display-breakpoints.scss +141 -0
  148. package/src/style/fonts/common-icons.eot +0 -0
  149. package/src/style/fonts/common-icons.svg +150 -0
  150. package/src/style/fonts/common-icons.ttf +0 -0
  151. package/src/style/fonts/common-icons.woff +0 -0
  152. package/src/style/fonts/common-icons.woff2 +0 -0
  153. package/src/style/fonts/fontAwesome/css/all.css +7003 -0
  154. package/src/style/fonts/fontAwesome/css/all.min.css +6 -0
  155. package/src/style/fonts/fontAwesome/css/brands.css +1423 -0
  156. package/src/style/fonts/fontAwesome/css/brands.min.css +6 -0
  157. package/src/style/fonts/fontAwesome/css/fontawesome.css +5519 -0
  158. package/src/style/fonts/fontAwesome/css/fontawesome.min.css +6 -0
  159. package/src/style/fonts/fontAwesome/css/regular.css +19 -0
  160. package/src/style/fonts/fontAwesome/css/regular.min.css +6 -0
  161. package/src/style/fonts/fontAwesome/css/solid.css +19 -0
  162. package/src/style/fonts/fontAwesome/css/solid.min.css +6 -0
  163. package/src/style/fonts/fontAwesome/css/svg-with-js.css +634 -0
  164. package/src/style/fonts/fontAwesome/css/svg-with-js.min.css +6 -0
  165. package/src/style/fonts/fontAwesome/css/v4-font-face.css +26 -0
  166. package/src/style/fonts/fontAwesome/css/v4-font-face.min.css +6 -0
  167. package/src/style/fonts/fontAwesome/css/v4-shims.css +2146 -0
  168. package/src/style/fonts/fontAwesome/css/v4-shims.min.css +6 -0
  169. package/src/style/fonts/fontAwesome/css/v5-font-face.css +22 -0
  170. package/src/style/fonts/fontAwesome/css/v5-font-face.min.css +6 -0
  171. package/src/style/fonts/fontAwesome/webfonts/fa-brands-400.ttf +0 -0
  172. package/src/style/fonts/fontAwesome/webfonts/fa-brands-400.woff2 +0 -0
  173. package/src/style/fonts/fontAwesome/webfonts/fa-regular-400.ttf +0 -0
  174. package/src/style/fonts/fontAwesome/webfonts/fa-regular-400.woff2 +0 -0
  175. package/src/style/fonts/fontAwesome/webfonts/fa-solid-900.ttf +0 -0
  176. package/src/style/fonts/fontAwesome/webfonts/fa-solid-900.woff2 +0 -0
  177. package/src/style/fonts/fontAwesome/webfonts/fa-v4compatibility.ttf +0 -0
  178. package/src/style/fonts/fontAwesome/webfonts/fa-v4compatibility.woff2 +0 -0
  179. package/src/style/variables.scss +11 -0
  180. package/.gitignore +0 -31
@@ -0,0 +1,315 @@
1
+ /*
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+ import './style/pdfElement.scss';
5
+
6
+ import React, {MouseEventHandler, PropsWithChildren, PureComponent} from 'react';
7
+ import {DraggableData, HandleClasses, HandleStyles, ResizeEnable, Rnd} from 'react-rnd';
8
+ import {
9
+ CustomAppEvent, ElementPosition, IndexedObject, PDFElementDimensions, PDFElementParams, PDFElementPersist, PdfFont,
10
+ RNDDimensions
11
+ } from "../../util/interfaces";
12
+ import {generateComponentId} from "../../util/componentUtil";
13
+ import {PAGE_WIDTH, pxToPt} from "../../util/pdfUtil";
14
+ import classNames from 'classnames';
15
+ import {AwesomeIcon, debug} from "../../../../index";
16
+
17
+ interface State {
18
+ dragging: boolean;
19
+ settings: IndexedObject<any>;
20
+ }
21
+
22
+ interface SharedProps {
23
+ onFocusElement: (element: PdfElement) => void;
24
+ onDelete: MouseEventHandler;
25
+ onSaveHistory: VoidFunction;
26
+ persistent?: PDFElementPersist;
27
+ }
28
+
29
+ interface Props {
30
+ id?: string;
31
+ }
32
+
33
+ export abstract class PdfElement<P extends SharedProps = any, S extends State = any> extends PureComponent<P & Props, S> {
34
+ protected readonly id = generateComponentId(this.props.id);
35
+ protected element: HTMLDivElement;
36
+ protected readonly event: CustomAppEvent;
37
+ protected draggable: PDFDraggable;
38
+ abstract getParams: (convertPixels?: boolean) => PDFElementParams<any, any>;
39
+ abstract onClick: (evt: React.MouseEvent) => void;
40
+ abstract onClickDelete: (evt: React.MouseEvent) => void;
41
+
42
+ protected constructor(props: Props & P) {
43
+ super(props);
44
+ this.event = {eventName: 'pdfFontChanged', handler: this.setFont};
45
+ }
46
+
47
+ onDragStart = () => {
48
+ this.setState({dragging: true});
49
+ };
50
+
51
+ onDragEnd = () => {
52
+ this.setState({dragging: false});
53
+ };
54
+
55
+ setFont = (data: { previousFont: PdfFont, font: PdfFont }) => {
56
+ const {previousFont, font} = data, {settings} = this.state;
57
+ if (settings.hasOwnProperty('font')) {
58
+ if (settings['font'] === previousFont)
59
+ this.setState({settings: Object.assign({}, settings, {font})});
60
+ }
61
+ };
62
+
63
+ getDimensions = (convertPixels: boolean): PDFElementDimensions => {
64
+ if (this.element) {
65
+ const parent = this.element.parentElement?.parentElement, rect = this.element.getBoundingClientRect();
66
+ const width = convertPixels ? pxToPt(rect.width) : rect.width,
67
+ height = convertPixels ? pxToPt(rect.height) : rect.height;
68
+ if (parent) return {
69
+ left: this.getLeft(parent, convertPixels),
70
+ top: this.getTop(parent, convertPixels),
71
+ width,
72
+ height,
73
+ };
74
+ }
75
+ return {left: 0, top: 0, width: 0, height: 0};
76
+ };
77
+
78
+ public getSettings = () => this.state.settings;
79
+
80
+ public setSetting = (key: string, value: any, callback?: VoidFunction, save: boolean = true) => {
81
+ this.setState({settings: Object.assign({}, this.state.settings, {[key]: value})}, () => {
82
+ if (save)
83
+ this.props.onSaveHistory();
84
+ if (callback) callback();
85
+ });
86
+ };
87
+
88
+ public changeSetting = (key: string) => (value: any) => {
89
+ this.setSetting(key, value);
90
+ };
91
+
92
+ public isPersistent = (): PDFElementPersist => {
93
+ return this.props.persistent ?? PDFElementPersist.NOT_PERSISTENT;
94
+ }
95
+
96
+ private getLeft = (parent: HTMLElement, convertPixels: boolean) => {
97
+ const rect = this.element.getBoundingClientRect(), parentRect = parent.getBoundingClientRect(),
98
+ left = Math.abs(rect.left - parentRect.left);
99
+ if (convertPixels)
100
+ return pxToPt(left);
101
+ return left;
102
+ };
103
+
104
+ private getTop = (parent: HTMLElement, convertPixels: boolean) => {
105
+ const rect = this.element.getBoundingClientRect(), parentRect = parent.getBoundingClientRect(),
106
+ top = Math.abs(rect.top - parentRect.top);
107
+ if (convertPixels)
108
+ return pxToPt(top);
109
+ return top;
110
+ };
111
+ }
112
+
113
+ interface DraggableProps {
114
+ onDrag?: (position: { x: number; y: number; }) => void;
115
+ onDragStart: VoidFunction;
116
+ onDragEnd: (position: { x: number; y: number; }) => void;
117
+ onDragged: VoidFunction;
118
+ onResized: VoidFunction;
119
+ onDelete?: MouseEventHandler;
120
+ onEdit?: MouseEventHandler;
121
+ onClickBar: MouseEventHandler;
122
+ id?: string;
123
+ dragging: boolean;
124
+ forwardRef?: any;
125
+ elementLabel: string;
126
+ dimensions?: RNDDimensions;
127
+ draggable: boolean;
128
+ resizeable: boolean;
129
+ resizeHoriz: boolean;
130
+ resizeVert: boolean;
131
+ position?: { x: number; y: number };
132
+ lockAspect?: boolean;
133
+ maxWidth: number;
134
+ maxHeight: number;
135
+ width: number;
136
+ height: number;
137
+ matchParentSize: boolean;
138
+ alignment?: ElementPosition;
139
+ persistent?: PDFElementPersist;
140
+ }
141
+
142
+ interface DraggableState {
143
+ position: { x: number; y: number };
144
+ width: number | string;
145
+ height: number | string;
146
+ }
147
+
148
+ export class PDFDraggable extends PureComponent<PropsWithChildren<DraggableProps>, DraggableState> {
149
+ static defaultProps = {
150
+ resizeable: true,
151
+ resizeHoriz: true,
152
+ resizeVert: true,
153
+ maxWidth: Number.MAX_SAFE_INTEGER,
154
+ maxHeight: Number.MAX_SAFE_INTEGER,
155
+ lockAspect: false,
156
+ width: 'auto',
157
+ height: 'auto',
158
+ matchParentSize: false,
159
+ };
160
+ private readonly id = generateComponentId(this.props.id);
161
+ private draggable: Rnd;
162
+
163
+ constructor(props: DraggableProps) {
164
+ super(props);
165
+ this.state = {
166
+ position: this.props.position || {x: 0, y: 0},
167
+ width: props.width || 'auto',
168
+ height: props.height || 'auto',
169
+ };
170
+ }
171
+
172
+ public setSize = (width: number, height: number, callListener: boolean = true) => {
173
+ this.setState({width, height}, () => {
174
+ if (callListener)
175
+ this.props.onResized();
176
+ });
177
+ };
178
+
179
+ public setFocus = () => {
180
+ if (this.draggable) {
181
+ const div = this.draggable.resizableElement.current;
182
+ if (div) div.classList.add('focused');
183
+ }
184
+ };
185
+
186
+ public setPosition = (position: { x?: number; y?: number }, callback?: VoidFunction) => {
187
+ this.setState({position: Object.assign({}, this.state.position, position)}, callback);
188
+ };
189
+
190
+ public getPosition = (): { x: number; y: number } => this.state.position;
191
+
192
+ onDrag = (evt: any, data: DraggableData) => {
193
+ const {onDrag, alignment} = this.props, {position} = this.state,
194
+ nextPosition = {x: alignment ? position.x : data.x, y: data.y};
195
+ if (onDrag) {
196
+ onDrag(nextPosition);
197
+ }
198
+ };
199
+
200
+ onDragStop = (evt: any, data: any) => {
201
+ const {onDragEnd, alignment, onDragged} = this.props, {position} = this.state,
202
+ nextPosition = {x: alignment ? position.x : data.lastX, y: data.lastY};
203
+ debug('Stop drag at', {nextPosition});
204
+ this.setState({position: nextPosition});
205
+ onDragEnd(nextPosition);
206
+ onDragged();
207
+ };
208
+
209
+ onResizeStop = (evt: any, direction: any, ref: HTMLElement, delta: any, position: any) => {
210
+ this.setState({
211
+ width: ref.style.width,
212
+ height: ref.style.height,
213
+ position
214
+ }, this.props.onResized);
215
+ };
216
+
217
+ setInitialPosition = () => {
218
+ const {alignment} = this.props, {position} = this.state;
219
+ if (!alignment) return;
220
+ const div = document.getElementById(this.id);
221
+ if (div) {
222
+ const width = div.getBoundingClientRect().width;
223
+ if (alignment === ElementPosition.CENTER)
224
+ this.setState({position: {x: PAGE_WIDTH / 2 - width / 2, y: position.y}});
225
+ else if (alignment === ElementPosition.LEFT)
226
+ this.setState({position: {x: 75, y: position.y}});
227
+ else if (alignment === ElementPosition.RIGHT)
228
+ this.setState({position: {x: PAGE_WIDTH - 75 - width, y: position.y}});
229
+ }
230
+ }
231
+
232
+ getHandleClasses = (): HandleClasses => {
233
+ const cls = 'resize-handle';
234
+ return {
235
+ bottomLeft: `${cls} bottom left`,
236
+ bottomRight: `${cls} bottom right`,
237
+ topLeft: `${cls} top left`,
238
+ topRight: `${cls} top right`,
239
+ };
240
+ };
241
+
242
+ getHandleStyles = (): HandleStyles => {
243
+ const style: React.CSSProperties = {width: '10px', height: '10px'};
244
+ return {
245
+ topRight: {...style, top: '-5px', right: '-5px'},
246
+ topLeft: {...style, top: '-5px', left: '-5px'},
247
+ bottomRight: {...style, bottom: '-5px', right: '-5px'},
248
+ bottomLeft: {...style, bottom: '-5px', left: '-5px'},
249
+ }
250
+ };
251
+
252
+ getEnabledResize = (): ResizeEnable => {
253
+ const {resizeable, resizeHoriz, resizeVert} = this.props;
254
+ if (!resizeable) return false;
255
+ if (resizeHoriz && resizeVert) return true;
256
+ return {
257
+ bottom: resizeVert,
258
+ bottomLeft: resizeVert && resizeHoriz,
259
+ bottomRight: resizeHoriz && resizeVert,
260
+ left: resizeHoriz,
261
+ right: resizeHoriz,
262
+ top: resizeVert,
263
+ topLeft: resizeHoriz && resizeVert,
264
+ topRight: resizeHoriz && resizeVert,
265
+ };
266
+ };
267
+
268
+ componentDidMount = () => {
269
+ window.setTimeout(this.setInitialPosition, 20);
270
+ };
271
+
272
+ componentDidUpdate = (prevProps: DraggableProps) => {
273
+ if (prevProps.alignment !== this.props.alignment)
274
+ window.setTimeout(this.setInitialPosition, 20);
275
+ };
276
+
277
+ render = () => {
278
+ const {
279
+ children, forwardRef, onDragStart, dragging, draggable, persistent,
280
+ maxHeight, maxWidth, lockAspect, matchParentSize, onEdit, alignment
281
+ } = this.props, {width, height, position} = this.state,
282
+ axis = alignment ? 'y' : 'both',
283
+ onDelete = persistent === PDFElementPersist.PERSISTENT ? undefined : this.props.onDelete;
284
+ return (
285
+ <Rnd position={position} dragAxis={axis} onDragStart={onDragStart} onDragStop={this.onDragStop}
286
+ bounds='parent' className={classNames('pdf-draggable', dragging && 'dragging')}
287
+ disableDragging={!draggable} enableResizing={this.getEnabledResize()} lockAspectRatio={lockAspect}
288
+ maxWidth={maxWidth} maxHeight={maxHeight} size={{width, height}} onDrag={this.onDrag}
289
+ resizeHandleClasses={this.getHandleClasses()} resizeHandleStyles={this.getHandleStyles()}
290
+ onResizeStop={this.onResizeStop} dragHandleClassName='drag-handle' dragGrid={[10, 10]}
291
+ ref={(ref: Rnd) => {
292
+ this.draggable = ref
293
+ }}>
294
+ <div className='action-bar'>
295
+ {draggable ? <AwesomeIcon name='arrows-alt' className='action drag-handle'/> : <div/>}
296
+ <div className='options'>
297
+ {onEdit !== undefined && <AwesomeIcon name='pen' onClick={onEdit} className='action'/>}
298
+ {onDelete !== undefined &&
299
+ <AwesomeIcon name='trash-alt' onClick={onDelete} className='action delete'/>}
300
+ </div>
301
+ </div>
302
+ <div className={classNames('pdf-element', 'rnd', matchParentSize && 'match-size')} ref={forwardRef}
303
+ id={this.id}>
304
+ {dragging && <>
305
+ <div className='guide vert'/>
306
+ <div className='guide vert reverse'/>
307
+ <div className='guide horiz'/>
308
+ <div className='guide horiz reverse'/>
309
+ </>}
310
+ {children}
311
+ </div>
312
+ </Rnd>
313
+ )
314
+ }
315
+ }
@@ -0,0 +1,111 @@
1
+ /*!
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+
5
+ @import '../../../../style/variables';
6
+
7
+ .pdf-draggable {
8
+ outline: 2px solid transparent;
9
+ transition: outline-color .2s ease-in-out;
10
+
11
+ .action-bar {
12
+ position: absolute;
13
+ top: 0;
14
+ left: -2px;
15
+ width: calc(100% + 4px);
16
+ transform: translateY(-100%);
17
+ background-color: $color-gray-5;
18
+ display: flex;
19
+ justify-content: space-between;
20
+ align-items: center;
21
+ visibility: hidden;
22
+ opacity: 0;
23
+ transition: visibility .2s ease-in-out, opacity .2s ease-in-out;
24
+
25
+ .action {
26
+ color: white;
27
+ padding: .5rem;
28
+ cursor: pointer;
29
+ font-size: .9rem;
30
+ transition: color .2s ease-in-out;
31
+
32
+ &.drag-handle {
33
+ cursor: move;
34
+ }
35
+
36
+ &:hover {
37
+ color: $color-gray-4;
38
+
39
+ &.delete {
40
+ color: red;
41
+ }
42
+ }
43
+ }
44
+
45
+ .options {
46
+ display: flex;
47
+ align-items: center;
48
+
49
+ .action {
50
+ border-right: 1px solid $color-gray-5;
51
+
52
+ &:last-child {
53
+ border-right: none;
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ .pdf-element {
60
+ position: relative;
61
+ cursor: pointer;
62
+
63
+ .guide {
64
+ position: absolute;
65
+ background-color: $color-gray-4;
66
+ top: 0;
67
+ left: 0;
68
+
69
+ &.horiz {
70
+ height: 1px;
71
+ width: 100vw;
72
+
73
+ &.reverse {
74
+ transform: translateX(-100%);
75
+ }
76
+ }
77
+
78
+ &.vert {
79
+ width: 1px;
80
+ height: 100vh;
81
+
82
+ &.reverse {
83
+ transform: translateY(-100%);
84
+ }
85
+ }
86
+ }
87
+
88
+ &.match-size {
89
+ width: 100%;
90
+ height: 100%;
91
+ }
92
+ }
93
+
94
+ &:hover, &.focused {
95
+ outline-color: $color-gray-5;
96
+ z-index: $z-index-high;
97
+ background-color: white;
98
+
99
+ .action-bar {
100
+ visibility: visible;
101
+ opacity: 1;
102
+ }
103
+ }
104
+
105
+ &.dragging {
106
+ .action-bar {
107
+ opacity: .3;
108
+ }
109
+ background-color: unset;
110
+ }
111
+ }
@@ -0,0 +1,57 @@
1
+ /*
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+
5
+ import {PDFElementParams, PdfFont} from "../../util/interfaces";
6
+
7
+ let HISTORY: string[] = [];
8
+ let currentIdx: number = -1;
9
+
10
+ export const addToHistory = (items: PDFElementParams<any, any>[], mainFont: PdfFont) => {
11
+ clearFrom(currentIdx);
12
+ const history: string = JSON.stringify({items, mainFont});
13
+ if (history !== HISTORY[currentIdx]) {
14
+ HISTORY.push(history);
15
+ currentIdx++;
16
+ console.debug('Current history', HISTORY.map((hist: string) => JSON.parse(hist)));
17
+ }
18
+ };
19
+
20
+ export const replaceHistory = (items: PDFElementParams<any, any>[], mainFont: PdfFont) => {
21
+ if(currentIdx > -1) {
22
+ HISTORY[currentIdx] = JSON.stringify({items, mainFont});
23
+ }
24
+ }
25
+
26
+ export const undo = (): { items: PDFElementParams<any, any>[], mainFont: PdfFont } => {
27
+ if (currentIdx <= 0) throw new Error('Current index is already at first position.');
28
+ const prevHistory = HISTORY[--currentIdx]
29
+ if (prevHistory)
30
+ return JSON.parse(prevHistory);
31
+ return {items: [], mainFont: PdfFont.LATO};
32
+ };
33
+
34
+ export const redo = (): { items: PDFElementParams<any, any>[], mainFont: PdfFont } => {
35
+ if (currentIdx >= HISTORY.length - 1) throw new Error('Current index is already at the end of HISTORY.');
36
+ const nextHistory = HISTORY[++currentIdx]
37
+ if (nextHistory)
38
+ return JSON.parse(nextHistory);
39
+ return {items: [], mainFont: PdfFont.LATO};
40
+ };
41
+
42
+ export const clearHistory = () => {
43
+ HISTORY = [];
44
+ currentIdx = -1;
45
+ }
46
+
47
+ export const canUndo = (): boolean => currentIdx > 0;
48
+ export const canRedo = (): boolean => currentIdx < HISTORY.length - 1;
49
+
50
+ const clearFrom = (index: number) => {
51
+ const newHistory: string[] = [];
52
+ for (let i = 0; i < HISTORY.length; i++) {
53
+ newHistory.push(HISTORY[i]);
54
+ if (i === index) break;
55
+ }
56
+ HISTORY = newHistory;
57
+ };
@@ -0,0 +1,175 @@
1
+ /*
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+ import './style/pdfImage.scss';
5
+
6
+ import React, {MouseEventHandler} from 'react';
7
+ import {
8
+ ElementPosition, IndexedObject, PDFDisplay, PDFElementParams, PDFElementPersist, PDFElementType, PDFImageParams
9
+ } from "../../util/interfaces";
10
+ import {PDFDraggable, PdfElement} from "../element/pdfElement";
11
+ import {nullify} from "../../util/miscUtil";
12
+ import {merge} from 'lodash';
13
+ import {AwesomeIcon, directTimeout, PAGE_HEIGHT, PAGE_WIDTH} from "../../../../index";
14
+
15
+ interface Props {
16
+ onDelete: MouseEventHandler;
17
+ onSaveHistory: VoidFunction;
18
+ values: IndexedObject<string>;
19
+ defaultSettings?: Partial<PDFImageParams>;
20
+ id?: string;
21
+ defaultPosition: { x: number; y: number };
22
+ draggable: boolean;
23
+ onFocusElement: (element: PdfElement) => void;
24
+ width?: number;
25
+ height?: number;
26
+ persistent?: PDFElementPersist;
27
+ }
28
+
29
+ interface State {
30
+ dragging: boolean;
31
+ settings: { img: string; persistent: PDFElementPersist; alignment?: ElementPosition; display?: PDFDisplay };
32
+ }
33
+
34
+ export default class PdfImage extends PdfElement<Props, State> {
35
+ static defaultProps = {
36
+ defaultPosition: {x: 0, y: 0},
37
+ };
38
+
39
+ private input: HTMLInputElement;
40
+ private image: File | null = null;
41
+
42
+ constructor(props: Props) {
43
+ super(props);
44
+ this.state = {
45
+ settings: merge({}, {
46
+ img: props.values?.default_image || '',
47
+ persistent: PDFElementPersist.NOT_PERSISTENT,
48
+ alignment: undefined,
49
+ display: PDFDisplay.ALL_PAGES,
50
+ }, props.defaultSettings),
51
+ dragging: false,
52
+ };
53
+ };
54
+
55
+ public onChooseFile = () => {
56
+ if (this.input)
57
+ this.input.click();
58
+ };
59
+
60
+ onChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
61
+ const {files} = evt.target;
62
+ if (files?.length) this.setWidth(files[0]);
63
+ };
64
+
65
+ onClick = (evt: React.MouseEvent): void => {
66
+ evt.stopPropagation();
67
+ this.props.onFocusElement(this);
68
+ if (this.draggable)
69
+ this.draggable.setFocus();
70
+ }
71
+
72
+ onClickDelete = (evt: React.MouseEvent): void => {
73
+ evt.stopPropagation();
74
+ const {onDelete} = this.props;
75
+ onDelete(evt);
76
+ };
77
+
78
+ onClickBar = (evt: React.MouseEvent) => {
79
+ this.onClick(evt);
80
+ };
81
+
82
+ setWidth = (file: File | string, setDirect: boolean = false) => {
83
+ const img: HTMLImageElement = new Image;
84
+ img.onload = () => {
85
+ const MAX_WIDTH = PAGE_WIDTH, MAX_HEIGHT = PAGE_HEIGHT, {width, height} = img;
86
+ let calcWidth = this.props.width ?? width, calcHeight = this.props.height ?? height;
87
+ const widthDiff = calcWidth - MAX_WIDTH, heightDiff = calcHeight - MAX_HEIGHT,
88
+ imgRatio = height / width, calcRatio = calcHeight / calcWidth;
89
+ if (calcRatio != imgRatio) calcHeight = calcHeight / calcRatio * imgRatio;
90
+ let finalWidth: number = calcWidth, finalHeight: number = calcHeight;
91
+ if (widthDiff > 0 || heightDiff > 0) {
92
+ if (widthDiff > heightDiff) {
93
+ finalWidth = MAX_WIDTH;
94
+ finalHeight = Math.round(finalWidth * imgRatio);
95
+ } else {
96
+ finalHeight = MAX_HEIGHT;
97
+ finalWidth = Math.round(finalHeight / imgRatio);
98
+ }
99
+ }
100
+ if (this.draggable)
101
+ this.draggable.setSize(finalWidth, finalHeight, !setDirect);
102
+ };
103
+ let imageSource: string;
104
+ if (typeof file === 'string') {
105
+ imageSource = file;
106
+ img.src = file;
107
+ } else {
108
+ imageSource = URL.createObjectURL(file);
109
+ if (!setDirect)
110
+ img.src = imageSource
111
+ this.image = file;
112
+ }
113
+ if (setDirect) {
114
+ this.setState({settings: Object.assign({}, this.state.settings, {img: imageSource})});
115
+ } else this.setSetting('img', img.src);
116
+ };
117
+
118
+ getParams = (convertPixels: boolean = true): PDFElementParams<PDFElementType.IMAGE, PDFImageParams> => {
119
+ const {settings} = this.state;
120
+ return {
121
+ key: this.id,
122
+ dimensions: this.getDimensions(convertPixels),
123
+ type: PDFElementType.IMAGE,
124
+ options: {
125
+ img: this.image ?? nullify(settings.img),
126
+ persistent: settings.persistent,
127
+ alignment: settings.alignment,
128
+ display: settings.display,
129
+ },
130
+ };
131
+ };
132
+
133
+ isDraggable = (): boolean => this.state.settings.alignment === undefined && this.props.draggable;
134
+
135
+ renderImg = () => {
136
+ const {img} = this.state.settings;
137
+ if (img) return <img src={img} alt='Afbeelding niet gevonden' className='image'/>;
138
+ return (
139
+ <div className='img-selector'>
140
+ <AwesomeIcon name='image' className='img-icon'/>
141
+ <span className='img-selector-label'>Kies afbeelding</span>
142
+ </div>
143
+ )
144
+ };
145
+
146
+ componentDidMount = () => {
147
+ const {settings} = this.state;
148
+ directTimeout(() => {
149
+ this.setWidth(settings.img, true);
150
+ });
151
+ };
152
+
153
+ render = () => {
154
+ const {settings, dragging} = this.state, {defaultPosition, width, height, onSaveHistory, onDelete, persistent} = this.props;
155
+ return (
156
+ <PDFDraggable onDragEnd={this.onDragEnd} elementLabel='Afbeelding' onDragStart={this.onDragStart}
157
+ draggable={this.isDraggable()} dragging={dragging} position={defaultPosition}
158
+ maxWidth={PAGE_WIDTH} maxHeight={PAGE_HEIGHT} width={width} height={height} lockAspect
159
+ onDelete={onDelete} onEdit={this.onClick} onClickBar={this.onClickBar} persistent={persistent}
160
+ ref={(ref: PDFDraggable) => {
161
+ this.draggable = ref
162
+ }} matchParentSize forwardRef={(ref: HTMLDivElement) => {
163
+ this.element = ref
164
+ }} onDragged={onSaveHistory} onResized={onSaveHistory} alignment={settings.alignment}>
165
+ <div className='pdf-image' onClick={this.onClick}>
166
+ {this.renderImg()}
167
+ <input type='file' accept='image/png, image/jpeg' onChange={this.onChange}
168
+ style={{display: 'none'}} ref={(ref: HTMLInputElement) => {
169
+ this.input = ref
170
+ }}/>
171
+ </div>
172
+ </PDFDraggable>
173
+ )
174
+ };
175
+ }
@@ -0,0 +1,34 @@
1
+ /*!
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+
5
+ @import '../../../../style/variables';
6
+
7
+ .pdf-image {
8
+ width: 100%;
9
+ height: 100%;
10
+ .image {
11
+ width: 100%;
12
+ height: 100%;
13
+ pointer-events: none;
14
+ }
15
+
16
+ .img-selector {
17
+ padding: 2rem;
18
+ border: 2px dashed $color-gray-3;
19
+ color: $color-gray-3;
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-items: center;
23
+
24
+ .img-icon {
25
+ font-size: 3rem;
26
+ }
27
+
28
+ .img-selector-label {
29
+ font-weight: 500;
30
+ font-size: .9rem;
31
+ white-space: nowrap;
32
+ }
33
+ }
34
+ }