@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,118 @@
1
+ /*!
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+
5
+ @import '../../../style/variables';
6
+
7
+ .pdf-creator {
8
+ margin: 2rem auto;
9
+ display: grid;
10
+ grid-template-columns: repeat(2, auto) minmax(min-content, 30rem);
11
+ align-items: start;
12
+ grid-row-gap: 1rem;
13
+ position: relative;
14
+ justify-content: center;
15
+
16
+ .right-col {
17
+ position: sticky;
18
+ top: 4rem;
19
+ }
20
+
21
+ .elements-container {
22
+ display: grid;
23
+ grid-template-columns: auto;
24
+ background-color: white;
25
+ grid-row-gap: 1rem;
26
+ padding: 1rem;
27
+ position: sticky;
28
+ top: 4rem;
29
+ border: 1px solid $color-gray-7;
30
+ border-radius: .5rem;
31
+
32
+ .element-button {
33
+ @include backgroundShadow;
34
+ border-radius: .5rem;
35
+ cursor: pointer;
36
+ transition: background-color .2s ease-in-out;
37
+ display: grid;
38
+ grid-template-columns: 2rem 1fr;
39
+ grid-column-gap: 1rem;
40
+ align-items: center;
41
+ color: $color-gray-5;
42
+ padding: .5rem;
43
+
44
+ .element-label {
45
+ white-space: nowrap;
46
+ }
47
+
48
+ .element-icon {
49
+ font-size: 2rem;
50
+ }
51
+
52
+ &:hover {
53
+ background-color: $color-gray-6;
54
+ }
55
+ }
56
+
57
+ .history {
58
+ display: grid;
59
+ grid-template-columns: 1fr 1fr;
60
+ grid-column-gap: 1rem;
61
+
62
+ .history-button {
63
+ @include backgroundShadow;
64
+ border-radius: .5rem;
65
+ cursor: pointer;
66
+ transition: background-color .2s ease-in-out;
67
+ padding: .5rem 1rem;
68
+ text-align: center;
69
+
70
+ &:hover {
71
+ background-color: $color-gray-7;
72
+ }
73
+
74
+ &.disabled {
75
+ cursor: not-allowed;
76
+ background-color: white !important;
77
+ box-shadow: none;
78
+ border: 1px solid $color-gray-4;
79
+
80
+ .history-icon {
81
+ color: $color-gray-4;
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ .history-reset {
88
+ display: flex;
89
+ justify-content: center;
90
+ }
91
+ }
92
+
93
+ .pdf-paper {
94
+ @include backgroundShadow;
95
+ border-radius: .5rem;
96
+ width: 595pt;
97
+ height: 842pt;
98
+ background-color: white;
99
+ position: relative;
100
+ overflow: hidden;
101
+ z-index: 1;
102
+ }
103
+
104
+ .footer-container {
105
+ @include backgroundShadow;
106
+ border-radius: .5rem;
107
+ grid-column: 2;
108
+ padding: 1rem;
109
+ background-color: white;
110
+ display: flex;
111
+ justify-content: space-between;
112
+ align-items: center;
113
+
114
+ .proceed-btn {
115
+ margin-left: 1rem;
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,267 @@
1
+ /*
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+ import './style/pdfText.scss';
5
+
6
+ import React, {CSSProperties, MouseEventHandler} from 'react';
7
+ import {
8
+ CustomAppEvent,
9
+ IndexedObject,
10
+ PDFDisplay,
11
+ PDFElementParams,
12
+ PDFElementPersist,
13
+ PDFElementType,
14
+ PdfFont,
15
+ PDFTextParams,
16
+ PDFTextVariables
17
+ } from "../../util/interfaces";
18
+ import {PDFDraggable, PdfElement} from "../element/pdfElement";
19
+ import {debug, sanitizeHtml} from "../../util/miscUtil";
20
+ import {merge} from 'lodash';
21
+ import {PAGE_WIDTH, pxToPt, setPdfVariables, waitForFonts} from "../../util/pdfUtil";
22
+ import {directTimeout} from "../../util/componentUtil";
23
+ import {dispatchCustomEvent, showDialog} from "../../util/eventUtil";
24
+ import {remToPx, WithEvents} from "../../../../";
25
+
26
+ interface Props {
27
+ onDelete: MouseEventHandler;
28
+ onSaveHistory: VoidFunction;
29
+ values: IndexedObject<string>;
30
+ defaultSettings?: Partial<PDFTextParams>;
31
+ id?: string;
32
+ customVariables?: PDFTextVariables;
33
+ defaultPosition: { x: number; y: number };
34
+ draggable: boolean;
35
+ onFocusElement: (element: PdfElement) => void;
36
+ persistent?: PDFElementPersist;
37
+ mainFont: PdfFont;
38
+ linkedID?: string;
39
+ }
40
+
41
+ interface State {
42
+ settings: PDFTextParams;
43
+ dragging: boolean;
44
+ focused: boolean;
45
+ }
46
+
47
+ export default class PdfText extends PdfElement<Props, State> {
48
+ static defaultProps = {
49
+ defaultPosition: {x: 0, y: 0},
50
+ };
51
+ private lastKnownCursor: number = 0;
52
+ private field: HTMLTextAreaElement;
53
+ private initialWidth: number | null = null;
54
+ private currentText: string = '';
55
+ private readonly events: CustomAppEvent[];
56
+
57
+ constructor(props: Props) {
58
+ super(props);
59
+ this.state = {
60
+ settings: merge({}, {
61
+ text: 'Klik hier om deze tekst aan te passen.',
62
+ bold: false,
63
+ underline: false,
64
+ italic: false,
65
+ fontSize: remToPx(1),
66
+ alignment: undefined,
67
+ font: props.mainFont,
68
+ color: '#000',
69
+ persistent: PDFElementPersist.NOT_PERSISTENT,
70
+ display: PDFDisplay.ALL_PAGES,
71
+ }, props.defaultSettings),
72
+ dragging: false,
73
+ focused: false,
74
+ }
75
+ this.currentText = this.state.settings.text;
76
+ this.events = [this.event, {eventName: 'onLinkedElementMoved', handler: this.onLinkedElementMoved}]
77
+ }
78
+
79
+ private onBlur = (evt: React.FocusEvent<HTMLTextAreaElement>) => {
80
+ this.lastKnownCursor = evt.target.selectionEnd || 0;
81
+ this.setState({focused: false}, this.setWidth);
82
+ if (this.state.settings.text !== this.currentText) this.props.onSaveHistory();
83
+ };
84
+
85
+ private onFocus = (evt: React.FocusEvent) => {
86
+ evt.stopPropagation();
87
+ this.setState({focused: true}, this.setWidth);
88
+ this.currentText = this.state.settings.text;
89
+ this.onClick();
90
+ };
91
+
92
+ getTextValue = (): string => {
93
+ const {settings, focused} = this.state, {values} = this.props;
94
+ if (focused) return settings.text;
95
+ return setPdfVariables(settings.text, values);
96
+ }
97
+
98
+ public setSetting = (key: string, value: any, callback?: VoidFunction, save: boolean = true) => {
99
+ this.setState({settings: Object.assign({}, this.state.settings, {[key]: value})}, () => {
100
+ this.setWidth();
101
+ if (key !== 'text' && save)
102
+ this.props.onSaveHistory();
103
+ if (callback) callback();
104
+ });
105
+ };
106
+
107
+ public onClickDelete = (evt: React.MouseEvent) => {
108
+ const {persistent, onDelete} = this.props;
109
+ if (persistent === 'confirm')
110
+ showDialog('We raden aan om dit element wel te tonen op de factuur. Weet je zeker dat je dit ' +
111
+ 'element wilt verwijderen?', 'Element verwijderen',
112
+ ['Nee', {label: 'Ja', onClick: onDelete}]);
113
+ else onDelete(evt);
114
+ };
115
+
116
+ onClickEdit = (evt: React.MouseEvent) => {
117
+ if (this.field) {
118
+ this.field.focus();
119
+ const {value} = this.field;
120
+ this.field.selectionStart = value.length;
121
+ this.field.selectionEnd = this.field.selectionStart;
122
+ }
123
+ this.onClick(evt);
124
+ };
125
+
126
+ onClick = (evt?: React.MouseEvent) => {
127
+ if (evt)
128
+ evt.stopPropagation();
129
+ this.props.onFocusElement(this);
130
+ if (this.draggable)
131
+ this.draggable.setFocus();
132
+ };
133
+
134
+ onChange = (evt: React.ChangeEvent<HTMLTextAreaElement>) => {
135
+ const {target} = evt;
136
+ this.setSetting('text', target.value, this.setWidth);
137
+ }
138
+
139
+ onClickBar = (evt: React.MouseEvent) => {
140
+ this.onClick(evt);
141
+ };
142
+
143
+ onDrag = (position: { x: number; y: number }) => {
144
+ const {linkedID} = this.props;
145
+ if (linkedID)
146
+ dispatchCustomEvent('onLinkedElementMoved', {position, id: linkedID, elementId: this.id});
147
+ }
148
+
149
+ onLinkedElementMoved = (data: { position: { x: number; y: number }, id: string; elementId: string }) => {
150
+ const {linkedID} = this.props;
151
+ if (this.draggable && linkedID && data.id === linkedID && data.elementId !== this.id)
152
+ this.draggable.setPosition({x: data.position.x});
153
+ };
154
+
155
+ /**
156
+ * Externally insert text add last know cursor position
157
+ * @param newText
158
+ */
159
+ public insertText = (newText: string) => {
160
+ const {settings} = this.state;
161
+ let {text} = settings;
162
+ text = text.substr(0, this.lastKnownCursor) + newText + text.substr(this.lastKnownCursor, text.length);
163
+ this.setState({settings: Object.assign({}, settings, {text})}, () => {
164
+ this.setWidth();
165
+ if (this.field) {
166
+ this.field.selectionStart = this.field.selectionStart + newText.length;
167
+ this.field.selectionEnd = this.field.selectionStart;
168
+ this.field.focus();
169
+ }
170
+ this.props.onSaveHistory();
171
+ });
172
+ };
173
+
174
+ private setWidth = () => {
175
+ const position = this.draggable?.getPosition() || {x: 0},
176
+ maxWidth = PAGE_WIDTH - position.x, {linkedID} = this.props
177
+ if (this.field) {
178
+ this.field.style.width = '0px';
179
+ this.field.style.width = this.field.scrollWidth + 'px';
180
+ this.initialWidth = this.initialWidth ?? this.field.scrollWidth;
181
+ if (this.field.scrollWidth > maxWidth && this.draggable) {
182
+ this.draggable.setPosition({x: PAGE_WIDTH - this.field.scrollWidth}, () => {
183
+ dispatchCustomEvent('onLinkedElementMoved',
184
+ {position: this.draggable.getPosition(), id: linkedID, elementId: this.id});
185
+ });
186
+ }
187
+ }
188
+ };
189
+
190
+ getParams = (convertPixels: boolean = true): PDFElementParams<PDFElementType.TEXT, PDFTextParams> => {
191
+ const {settings} = this.state,
192
+ {bold, italic, text, underline, alignment, font, color, persistent, display} = settings,
193
+ fontSize = convertPixels ? pxToPt(settings.fontSize) : settings.fontSize, {linkedID} = this.props;
194
+ return {
195
+ dimensions: this.getDimensions(convertPixels),
196
+ key: this.id,
197
+ type: PDFElementType.TEXT,
198
+ options: {fontSize: fontSize, bold, italic, text, underline, alignment, font, color, persistent, display},
199
+ linkedID: linkedID,
200
+ };
201
+ }
202
+
203
+ private getTextStyle = (): CSSProperties => {
204
+ const {italic, underline, bold, fontSize, font, color} = this.state.settings,
205
+ styles: CSSProperties = {fontSize, fontFamily: font, color};
206
+ if (italic) styles.fontStyle = 'italic';
207
+ if (underline) styles.textDecoration = 'underline';
208
+ if (bold) styles.fontWeight = font === PdfFont.HELVETICA ? 600 : 500;
209
+ return styles;
210
+ };
211
+
212
+ private getRows = () => {
213
+ const {text} = this.state.settings;
214
+ return text.split('\n').length;
215
+ };
216
+
217
+ componentDidMount = () => {
218
+ directTimeout(this.setWidth);
219
+ if (this.props.linkedID) {
220
+ directTimeout(() => {
221
+ if (this.draggable) {
222
+ debug('Dispatch event');
223
+ dispatchCustomEvent('onLinkedElementMoved',
224
+ {position: this.draggable.getPosition(), id: this.props.linkedID, elementId: this.id});
225
+ }
226
+ })
227
+ }
228
+ waitForFonts(this.setWidth);
229
+ };
230
+
231
+ componentDidUpdate = (prevProps: Props, prevState: State) => {
232
+ const {settings} = this.state, prevSettings = prevState.settings;
233
+ if (settings.font !== prevSettings.font) waitForFonts(this.setWidth);
234
+ }
235
+
236
+ render = () => {
237
+ const {settings, dragging} = this.state, {
238
+ draggable,
239
+ defaultPosition,
240
+ onSaveHistory,
241
+ persistent
242
+ } = this.props;
243
+ return (
244
+ <WithEvents events={this.events}>
245
+ <PDFDraggable onDrag={this.onDrag} onDragEnd={this.onDragEnd} position={defaultPosition}
246
+ elementLabel='Tekst' alignment={settings.alignment} onDragStart={this.onDragStart}
247
+ draggable={draggable} dragging={dragging} resizeable={false} onDragged={onSaveHistory}
248
+ onResized={onSaveHistory} persistent={persistent} onDelete={this.onClickDelete}
249
+ onEdit={this.onClickEdit} ref={(ref: PDFDraggable) => {
250
+ this.draggable = ref
251
+ }} forwardRef={(ref: HTMLDivElement) => {
252
+ this.element = ref
253
+ }} onClickBar={this.onClickBar}>
254
+ <div className='pdf-text-container'>
255
+ <textarea className='pdf-text-input' style={this.getTextStyle()}
256
+ readOnly={settings.disabled === true}
257
+ value={sanitizeHtml(this.getTextValue())} onChange={this.onChange}
258
+ rows={this.getRows()} onFocus={this.onFocus} onBlur={this.onBlur} onClick={this.onClick}
259
+ ref={(ref: HTMLTextAreaElement) => {
260
+ this.field = ref
261
+ }}/>
262
+ </div>
263
+ </PDFDraggable>
264
+ </WithEvents>
265
+ )
266
+ }
267
+ }
@@ -0,0 +1,22 @@
1
+ /*!
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+
5
+ @import '../../../../style/variables';
6
+
7
+ .pdf-text-container {
8
+ .pdf-text-input {
9
+ border: none !important;
10
+ outline: none !important;
11
+ resize: none;
12
+ background-color: transparent;
13
+ padding: 0;
14
+ overflow: hidden;
15
+ line-height: 1.5;
16
+ white-space: pre;
17
+
18
+ &:disabled {
19
+ color: black;
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,193 @@
1
+ /*
2
+ * Copyright (c) Dave van Rijn Development 2022.
3
+ */
4
+
5
+ import React, {
6
+ ForwardedRef,
7
+ forwardRef,
8
+ MouseEventHandler,
9
+ PropsWithChildren,
10
+ useEffect,
11
+ useImperativeHandle,
12
+ useMemo,
13
+ useRef,
14
+ useState
15
+ } from 'react';
16
+ import {ElementPosition, PDFElementPersist, RNDDimensions} from "../../../util/interfaces";
17
+ import {generateComponentId} from "../../../util/componentUtil";
18
+ import {DraggableData, HandleStyles, Position, ResizableDelta, ResizeEnable, Rnd, RndDragCallback} from 'react-rnd';
19
+ import {defer, delay} from 'lodash';
20
+ import {PDFDraggableType, ResizeDirection} from "../types/pdfTemplateTypes";
21
+ import {PAGE_WIDTH} from "../../../util/pdfUtil";
22
+ import classNames from 'classnames';
23
+ import {AwesomeIcon} from "../../../../../index";
24
+
25
+ type ElementDimensions = { width: number | string; height: number | string };
26
+
27
+ interface Props {
28
+ onDragStart: RndDragCallback;
29
+ onDragEnd: (position: Position) => void
30
+ onDragged: VoidFunction;
31
+ onResized: VoidFunction;
32
+ onDrag?: (position: Position) => void;
33
+ onClickDelete?: MouseEventHandler;
34
+ onClickEdit?: MouseEventHandler;
35
+ onClickOptions?: MouseEventHandler;
36
+ onClickBar: MouseEventHandler;
37
+ id?: string;
38
+ dragging: boolean;
39
+ elementLabel: string;
40
+ dimensions?: RNDDimensions;
41
+ draggable: boolean;
42
+ resizeable?: boolean;
43
+ resizableHorizontal?: boolean;
44
+ resizableVertical?: boolean;
45
+ position?: Position;
46
+ lockAspect?: boolean;
47
+ maxWidth?: number;
48
+ maxHeight?: number;
49
+ width?: number;
50
+ height?: number;
51
+ matchParentSize?: boolean;
52
+ alignment?: ElementPosition;
53
+ persistent?: PDFElementPersist;
54
+ }
55
+
56
+ const resizeHandleClass = 'resize-handle';
57
+ const resizeHandleClasses = {
58
+ bottomLeft: `${resizeHandleClass} bottom left`,
59
+ bottomRight: `${resizeHandleClass} bottom right`,
60
+ topLeft: `${resizeHandleClass} top left`,
61
+ topRight: `${resizeHandleClass} top right`,
62
+ };
63
+ const resizeHandleStyles: HandleStyles = {
64
+ topRight: {width: '10px', height: '10px', top: '-5px', right: '-5px'},
65
+ topLeft: {width: '10px', height: '10px', top: '-5px', left: '-5px'},
66
+ bottomRight: {width: '10px', height: '10px', bottom: '-5px', right: '-5px'},
67
+ bottomLeft: {width: '10px', height: '10px', bottom: '-5px', left: '-5px'},
68
+ }
69
+
70
+ function PDFDraggableElement(props: PropsWithChildren<Props>, ref: ForwardedRef<PDFDraggableType>) {
71
+ const [position, _setPosition] = useState<Position>(props.position ?? {x: 0, y: 0});
72
+ const id = useRef<string>(generateComponentId(props.id));
73
+ const [dimensions, setDimensions] = useState<ElementDimensions>({
74
+ width: props.width ?? 'auto',
75
+ height: props.height ?? 'auto'
76
+ });
77
+ const draggableRef = useRef<Rnd>(null);
78
+ const resizeEnable: ResizeEnable = useMemo(() => {
79
+ const {resizeable, resizableVertical, resizableHorizontal} = props;
80
+ if (!resizeable) return false;
81
+ if (resizableHorizontal && resizableVertical) return true;
82
+ return {
83
+ bottom: resizableVertical,
84
+ bottomLeft: resizableVertical && resizableHorizontal,
85
+ bottomRight: resizableVertical && resizableHorizontal,
86
+ left: resizableHorizontal,
87
+ right: resizableHorizontal,
88
+ top: resizableVertical,
89
+ topLeft: resizableVertical && resizableHorizontal,
90
+ topRight: resizableVertical && resizableHorizontal,
91
+ }
92
+ }, [props.resizableHorizontal, props.resizableVertical, props.resizeable])
93
+
94
+ function setSize(width: number, height: number, notifyResized: boolean = true) {
95
+ setDimensions({width, height});
96
+ if (notifyResized)
97
+ defer(props.onResized);
98
+ }
99
+
100
+ function setFocus() {
101
+ draggableRef.current?.resizableElement.current?.classList.add('focused');
102
+ }
103
+
104
+ function setPosition(_position: Position, callback?: VoidFunction) {
105
+ _setPosition(Object.assign({}, position, _position));
106
+ if (callback) defer(callback);
107
+ }
108
+
109
+ function getPosition(): Position {
110
+ return position;
111
+ }
112
+
113
+ function onDrag(evt: any, data: DraggableData) {
114
+ const {onDrag, alignment} = props;
115
+ if (!onDrag) return;
116
+ const nextPosition = {x: alignment ? position.x : data.x, y: data.y};
117
+ onDrag(nextPosition);
118
+ }
119
+
120
+ function onDragStop(evt: any, data: DraggableData) {
121
+ const {onDragEnd, alignment, onDragged} = props;
122
+ const nextPosition = {x: alignment ? position.x : data.lastX, y: data.lastY};
123
+ _setPosition(nextPosition);
124
+ onDragEnd(nextPosition);
125
+ onDragged();
126
+ }
127
+
128
+ function onResizeStop(evt: any, direction: ResizeDirection, ref: HTMLElement, delta: ResizableDelta, position: Position) {
129
+ setDimensions({width: ref.style.width, height: ref.style.height});
130
+ _setPosition(position);
131
+ defer(props.onResized);
132
+ }
133
+
134
+ function setInitialPosition() {
135
+ const {alignment} = props;
136
+ if (!alignment) return;
137
+ const div = document.getElementById(id.current);
138
+ if (!div) return;
139
+ const width = div.getBoundingClientRect().width;
140
+ let nextPosition: Position | null = null;
141
+ if (alignment === ElementPosition.CENTER)
142
+ nextPosition = {x: PAGE_WIDTH / 2 - width / 2, y: position.y}
143
+ else if (alignment === ElementPosition.LEFT)
144
+ nextPosition = {x: 75, y: position.y}
145
+ else if (alignment === ElementPosition.RIGHT)
146
+ nextPosition = {x: PAGE_WIDTH - 75 - width, y: position.y}
147
+ if (nextPosition) _setPosition(nextPosition);
148
+ }
149
+
150
+ useImperativeHandle(ref, () => ({
151
+ setPosition, getPosition, setFocus, setSize
152
+ }));
153
+
154
+ useEffect(() => {
155
+ delay(setInitialPosition, 20);
156
+ }, [props.alignment]);
157
+
158
+ const axis = props.alignment ? 'y' : 'both';
159
+ const {
160
+ onDragStart, dragging, draggable, lockAspect, maxWidth, maxHeight, onClickEdit, onClickDelete,
161
+ onClickOptions, matchParentSize, children
162
+ } = props;
163
+ return (
164
+ <Rnd position={position} dragAxis={axis} onDragStart={onDragStart} onDragStop={onDragStop} bounds='parent'
165
+ className={classNames('pdf-draggable', dragging && 'dragging')} disableDragging={!draggable}
166
+ enableResizing={resizeEnable} lockAspectRatio={lockAspect} maxWidth={maxWidth ?? Number.MAX_SAFE_INTEGER}
167
+ maxHeight={maxHeight ?? Number.MAX_SAFE_INTEGER} size={dimensions} onDrag={onDrag}
168
+ resizeHandleClasses={resizeHandleClasses} resizeHandleStyles={resizeHandleStyles}
169
+ onResizeStop={onResizeStop} dragHandleClassName='drag-handle' dragGrid={[10, 10]} ref={draggableRef}>
170
+ <div className='action-bar'>
171
+ {draggable ? <AwesomeIcon name='arrows-alt' className='action drag-handle'/> : <div/>}
172
+ <div className='options'>
173
+ {!!onClickEdit && <AwesomeIcon name='pen' onClick={onClickEdit} className='action'/>}
174
+ {!!onClickDelete &&
175
+ <AwesomeIcon name='trash-alt' onClick={onClickDelete} className='action delete'/>}
176
+ {!!onClickOptions && <AwesomeIcon name='ellipsis' className='action'/>}
177
+ </div>
178
+ </div>
179
+ <div className={classNames('pdf-element', 'rnd', matchParentSize && 'match-size')} id={id.current}>
180
+ {dragging && <>
181
+ <div className='guide vert'/>
182
+ <div className='guide vert reverse'/>
183
+ <div className='guide horiz'/>
184
+ <div className='guide horiz reverse'/>
185
+ </>}
186
+ {children}
187
+ </div>
188
+ </Rnd>
189
+
190
+ )
191
+ }
192
+
193
+ export default forwardRef<PDFDraggableType, Props>(PDFDraggableElement);
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Copyright (c) Dave van Rijn Development 2022.
3
+ */
4
+
5
+ import {Position} from "react-rnd";
6
+
7
+ export type ResizeDirection =
8
+ 'top'
9
+ | 'right'
10
+ | 'bottom'
11
+ | 'left'
12
+ | 'topRight'
13
+ | 'bottomRight'
14
+ | 'bottomLeft'
15
+ | 'topLeft';
16
+
17
+ export interface PDFDraggableType {
18
+ setSize: (width: number, height: number, notifyResized?: boolean) => void;
19
+ setFocus: VoidFunction;
20
+ setPosition: (position: Position, callback?: VoidFunction) => void;
21
+ getPosition: () => Position;
22
+ }
23
+
24
+ export interface PDFElementType {
25
+ id: string;
26
+
27
+ }
@@ -0,0 +1,29 @@
1
+ /*!
2
+ * Copyright (c) 2021. Dave van Rijn Development
3
+ */
4
+
5
+ @import '../../../style/variables';
6
+
7
+ .with-background {
8
+ @include popupContainer;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ z-index: $z-index-dialog;
13
+
14
+ .content-container {
15
+ width: fit-content;
16
+ height: fit-content;
17
+
18
+ .header-container {
19
+ display: flex;
20
+ justify-content: space-between;
21
+ align-items: center;
22
+
23
+ .header-title {
24
+ font-size: 1.2rem;
25
+ font-weight: 500;
26
+ }
27
+ }
28
+ }
29
+ }