@servicetitan/dte-pdf-editor 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/README.md +35 -7
  2. package/dist/components/field-config-panel/advanced-settings.d.ts +9 -0
  3. package/dist/components/field-config-panel/advanced-settings.d.ts.map +1 -0
  4. package/dist/components/field-config-panel/advanced-settings.js +17 -0
  5. package/dist/components/field-config-panel/advanced-settings.js.map +1 -0
  6. package/dist/components/field-config-panel/field-config-panel-overlay.d.ts +4 -1
  7. package/dist/components/field-config-panel/field-config-panel-overlay.d.ts.map +1 -1
  8. package/dist/components/field-config-panel/field-config-panel-overlay.js +2 -2
  9. package/dist/components/field-config-panel/field-config-panel-overlay.js.map +1 -1
  10. package/dist/components/field-config-panel/field-config-panel.d.ts +4 -1
  11. package/dist/components/field-config-panel/field-config-panel.d.ts.map +1 -1
  12. package/dist/components/field-config-panel/field-config-panel.js +11 -5
  13. package/dist/components/field-config-panel/field-config-panel.js.map +1 -1
  14. package/dist/components/field-config-panel/field-sidebar.d.ts +13 -0
  15. package/dist/components/field-config-panel/field-sidebar.d.ts.map +1 -0
  16. package/dist/components/field-config-panel/field-sidebar.js +20 -0
  17. package/dist/components/field-config-panel/field-sidebar.js.map +1 -0
  18. package/dist/components/field-config-panel/formula-generator.d.ts +11 -0
  19. package/dist/components/field-config-panel/formula-generator.d.ts.map +1 -0
  20. package/dist/components/field-config-panel/formula-generator.js +51 -0
  21. package/dist/components/field-config-panel/formula-generator.js.map +1 -0
  22. package/dist/components/field-config-panel/formula-modal.d.ts +12 -0
  23. package/dist/components/field-config-panel/formula-modal.d.ts.map +1 -0
  24. package/dist/components/field-config-panel/formula-modal.js +99 -0
  25. package/dist/components/field-config-panel/formula-modal.js.map +1 -0
  26. package/dist/components/field-config-panel/formula-workspace.d.ts +23 -0
  27. package/dist/components/field-config-panel/formula-workspace.d.ts.map +1 -0
  28. package/dist/components/field-config-panel/formula-workspace.js +28 -0
  29. package/dist/components/field-config-panel/formula-workspace.js.map +1 -0
  30. package/dist/components/field-config-panel/result-type-selector.d.ts +9 -0
  31. package/dist/components/field-config-panel/result-type-selector.d.ts.map +1 -0
  32. package/dist/components/field-config-panel/result-type-selector.js +10 -0
  33. package/dist/components/field-config-panel/result-type-selector.js.map +1 -0
  34. package/dist/components/field-sidebar/calculated-field-type-list.d.ts +9 -0
  35. package/dist/components/field-sidebar/calculated-field-type-list.d.ts.map +1 -0
  36. package/dist/components/field-sidebar/calculated-field-type-list.js +12 -0
  37. package/dist/components/field-sidebar/calculated-field-type-list.js.map +1 -0
  38. package/dist/components/field-sidebar/data-model-field-type-list.d.ts +0 -1
  39. package/dist/components/field-sidebar/data-model-field-type-list.d.ts.map +1 -1
  40. package/dist/components/field-sidebar/data-model-field-type-list.js +8 -7
  41. package/dist/components/field-sidebar/data-model-field-type-list.js.map +1 -1
  42. package/dist/components/field-sidebar/field-menu-group.d.ts +11 -0
  43. package/dist/components/field-sidebar/field-menu-group.d.ts.map +1 -0
  44. package/dist/components/field-sidebar/field-menu-group.js +6 -0
  45. package/dist/components/field-sidebar/field-menu-group.js.map +1 -0
  46. package/dist/components/field-sidebar/field-sidebar.d.ts.map +1 -1
  47. package/dist/components/field-sidebar/field-sidebar.js +6 -15
  48. package/dist/components/field-sidebar/field-sidebar.js.map +1 -1
  49. package/dist/components/field-sidebar/fillable-field-type-list.d.ts +0 -1
  50. package/dist/components/field-sidebar/fillable-field-type-list.d.ts.map +1 -1
  51. package/dist/components/field-sidebar/fillable-field-type-list.js +8 -9
  52. package/dist/components/field-sidebar/fillable-field-type-list.js.map +1 -1
  53. package/dist/components/pdf-editor/pdf-editor.d.ts.map +1 -1
  54. package/dist/components/pdf-editor/pdf-editor.js +1 -1
  55. package/dist/components/pdf-editor/pdf-editor.js.map +1 -1
  56. package/dist/components/pdf-fields-overlay/pdf-overlay-field-calculated.d.ts +8 -0
  57. package/dist/components/pdf-fields-overlay/pdf-overlay-field-calculated.d.ts.map +1 -0
  58. package/dist/components/pdf-fields-overlay/pdf-overlay-field-calculated.js +5 -0
  59. package/dist/components/pdf-fields-overlay/pdf-overlay-field-calculated.js.map +1 -0
  60. package/dist/components/pdf-fields-overlay/pdf-overlay-field.d.ts.map +1 -1
  61. package/dist/components/pdf-fields-overlay/pdf-overlay-field.js +11 -6
  62. package/dist/components/pdf-fields-overlay/pdf-overlay-field.js.map +1 -1
  63. package/dist/components/pdf-view/pdf-view-calculated.d.ts +9 -0
  64. package/dist/components/pdf-view/pdf-view-calculated.d.ts.map +1 -0
  65. package/dist/components/pdf-view/pdf-view-calculated.js +18 -0
  66. package/dist/components/pdf-view/pdf-view-calculated.js.map +1 -0
  67. package/dist/components/pdf-view/pdf-view.d.ts.map +1 -1
  68. package/dist/components/pdf-view/pdf-view.js +2 -1
  69. package/dist/components/pdf-view/pdf-view.js.map +1 -1
  70. package/dist/constants/field.constants.d.ts +3 -2
  71. package/dist/constants/field.constants.d.ts.map +1 -1
  72. package/dist/constants/field.constants.js +6 -0
  73. package/dist/constants/field.constants.js.map +1 -1
  74. package/dist/constants/menu-group.d.ts +8 -0
  75. package/dist/constants/menu-group.d.ts.map +1 -0
  76. package/dist/constants/menu-group.js +20 -0
  77. package/dist/constants/menu-group.js.map +1 -0
  78. package/dist/hooks/index.d.ts +1 -0
  79. package/dist/hooks/index.d.ts.map +1 -1
  80. package/dist/hooks/index.js +1 -0
  81. package/dist/hooks/index.js.map +1 -1
  82. package/dist/hooks/useFieldDrag.d.ts +9 -2
  83. package/dist/hooks/useFieldDrag.d.ts.map +1 -1
  84. package/dist/hooks/useFieldDrag.js +60 -8
  85. package/dist/hooks/useFieldDrag.js.map +1 -1
  86. package/dist/hooks/useFormulaEditor.d.ts +22 -0
  87. package/dist/hooks/useFormulaEditor.d.ts.map +1 -0
  88. package/dist/hooks/useFormulaEditor.js +290 -0
  89. package/dist/hooks/useFormulaEditor.js.map +1 -0
  90. package/dist/hooks/usePdfFieldDnD.d.ts.map +1 -1
  91. package/dist/hooks/usePdfFieldDnD.js +19 -3
  92. package/dist/hooks/usePdfFieldDnD.js.map +1 -1
  93. package/dist/interface/types.d.ts +45 -3
  94. package/dist/interface/types.d.ts.map +1 -1
  95. package/dist/interface/types.js +3 -0
  96. package/dist/interface/types.js.map +1 -1
  97. package/dist/utils/data-model/extract-fields.utils.d.ts +5 -5
  98. package/dist/utils/data-model/extract-fields.utils.d.ts.map +1 -1
  99. package/dist/utils/data-model/extract-fields.utils.js +42 -8
  100. package/dist/utils/data-model/extract-fields.utils.js.map +1 -1
  101. package/dist/utils/formula/caret.utils.d.ts +3 -0
  102. package/dist/utils/formula/caret.utils.d.ts.map +1 -0
  103. package/dist/utils/formula/caret.utils.js +123 -0
  104. package/dist/utils/formula/caret.utils.js.map +1 -0
  105. package/dist/utils/formula/dom.utils.d.ts +4 -0
  106. package/dist/utils/formula/dom.utils.d.ts.map +1 -0
  107. package/dist/utils/formula/dom.utils.js +34 -0
  108. package/dist/utils/formula/dom.utils.js.map +1 -0
  109. package/dist/utils/formula/evaluate-formula.utils.d.ts +13 -0
  110. package/dist/utils/formula/evaluate-formula.utils.d.ts.map +1 -0
  111. package/dist/utils/formula/evaluate-formula.utils.js +134 -0
  112. package/dist/utils/formula/evaluate-formula.utils.js.map +1 -0
  113. package/dist/utils/formula/expression.utils.d.ts +18 -0
  114. package/dist/utils/formula/expression.utils.d.ts.map +1 -0
  115. package/dist/utils/formula/expression.utils.js +84 -0
  116. package/dist/utils/formula/expression.utils.js.map +1 -0
  117. package/dist/utils/formula/format-calculated-result.utils.d.ts +7 -0
  118. package/dist/utils/formula/format-calculated-result.utils.d.ts.map +1 -0
  119. package/dist/utils/formula/format-calculated-result.utils.js +50 -0
  120. package/dist/utils/formula/format-calculated-result.utils.js.map +1 -0
  121. package/dist/utils/formula/formula-types.d.ts +3 -0
  122. package/dist/utils/formula/formula-types.d.ts.map +1 -0
  123. package/dist/utils/formula/formula-types.js +2 -0
  124. package/dist/utils/formula/formula-types.js.map +1 -0
  125. package/dist/utils/formula/index.d.ts +11 -0
  126. package/dist/utils/formula/index.d.ts.map +1 -0
  127. package/dist/utils/formula/index.js +11 -0
  128. package/dist/utils/formula/index.js.map +1 -0
  129. package/dist/utils/formula/referenced-paths.utils.d.ts +7 -0
  130. package/dist/utils/formula/referenced-paths.utils.d.ts.map +1 -0
  131. package/dist/utils/formula/referenced-paths.utils.js +18 -0
  132. package/dist/utils/formula/referenced-paths.utils.js.map +1 -0
  133. package/dist/utils/formula/render-formula.utils.d.ts +8 -0
  134. package/dist/utils/formula/render-formula.utils.d.ts.map +1 -0
  135. package/dist/utils/formula/render-formula.utils.js +39 -0
  136. package/dist/utils/formula/render-formula.utils.js.map +1 -0
  137. package/dist/utils/formula/serialize-formula.utils.d.ts +14 -0
  138. package/dist/utils/formula/serialize-formula.utils.d.ts.map +1 -0
  139. package/dist/utils/formula/serialize-formula.utils.js +33 -0
  140. package/dist/utils/formula/serialize-formula.utils.js.map +1 -0
  141. package/dist/utils/formula/validate-formula.utils.d.ts +11 -0
  142. package/dist/utils/formula/validate-formula.utils.d.ts.map +1 -0
  143. package/dist/utils/formula/validate-formula.utils.js +79 -0
  144. package/dist/utils/formula/validate-formula.utils.js.map +1 -0
  145. package/dist/utils/index.d.ts +1 -0
  146. package/dist/utils/index.d.ts.map +1 -1
  147. package/dist/utils/index.js +1 -0
  148. package/dist/utils/index.js.map +1 -1
  149. package/package.json +2 -2
  150. package/src/components/field-config-panel/advanced-settings.tsx +113 -0
  151. package/src/components/field-config-panel/field-config-panel-overlay.tsx +8 -1
  152. package/src/components/field-config-panel/field-config-panel.tsx +43 -15
  153. package/src/components/field-config-panel/field-sidebar.tsx +91 -0
  154. package/src/components/field-config-panel/formula-generator.tsx +122 -0
  155. package/src/components/field-config-panel/formula-modal.tsx +229 -0
  156. package/src/components/field-config-panel/formula-workspace.tsx +116 -0
  157. package/src/components/field-config-panel/result-type-selector.tsx +34 -0
  158. package/src/components/field-sidebar/calculated-field-type-list.tsx +29 -0
  159. package/src/components/field-sidebar/data-model-field-type-list.tsx +10 -4
  160. package/src/components/field-sidebar/field-menu-group.tsx +36 -0
  161. package/src/components/field-sidebar/field-sidebar.tsx +14 -55
  162. package/src/components/field-sidebar/fillable-field-type-list.tsx +11 -9
  163. package/src/components/pdf-editor/pdf-editor.tsx +2 -0
  164. package/src/components/pdf-fields-overlay/pdf-overlay-field-calculated.tsx +15 -0
  165. package/src/components/pdf-fields-overlay/pdf-overlay-field.tsx +10 -5
  166. package/src/components/pdf-view/pdf-view-calculated.tsx +23 -0
  167. package/src/components/pdf-view/pdf-view.tsx +4 -0
  168. package/src/constants/field.constants.ts +9 -2
  169. package/src/constants/menu-group.ts +26 -0
  170. package/src/hooks/index.ts +1 -0
  171. package/src/hooks/useFieldDrag.ts +84 -8
  172. package/src/hooks/useFormulaEditor.ts +336 -0
  173. package/src/hooks/usePdfFieldDnD.ts +36 -14
  174. package/src/interface/types.ts +38 -2
  175. package/src/styles/formula-modal.css +307 -0
  176. package/src/styles/index.css +1 -0
  177. package/src/styles/pdf-field-overlay.css +1 -0
  178. package/src/utils/data-model/extract-fields.utils.ts +65 -7
  179. package/src/utils/formula/caret.utils.ts +125 -0
  180. package/src/utils/formula/dom.utils.ts +35 -0
  181. package/src/utils/formula/evaluate-formula.utils.ts +159 -0
  182. package/src/utils/formula/expression.utils.ts +99 -0
  183. package/src/utils/formula/format-calculated-result.utils.ts +79 -0
  184. package/src/utils/formula/formula-types.ts +2 -0
  185. package/src/utils/formula/index.ts +10 -0
  186. package/src/utils/formula/referenced-paths.utils.ts +18 -0
  187. package/src/utils/formula/render-formula.utils.ts +40 -0
  188. package/src/utils/formula/serialize-formula.utils.ts +40 -0
  189. package/src/utils/formula/validate-formula.utils.ts +94 -0
  190. package/src/utils/index.ts +1 -0
@@ -0,0 +1,307 @@
1
+ /* Formula modal overlay */
2
+ .dte-formula-modal-overlay {
3
+ position: fixed;
4
+ inset: 0;
5
+ z-index: var(--z-index-drawer);
6
+ background-color: rgba(0, 0, 0, 0.4);
7
+ padding: var(--spacing-2);
8
+ }
9
+
10
+ .dte-formula-modal {
11
+ background: var(--white);
12
+ border-radius: 8px;
13
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
14
+ width: 800px;
15
+ max-height: 85vh;
16
+ }
17
+
18
+ .dte-formula-modal-body {
19
+ padding: var(--spacing-2);
20
+ overflow: auto;
21
+ }
22
+
23
+ .dte-formula-modal-columns {
24
+ min-height: 280px;
25
+ max-height: 60vh;
26
+ }
27
+
28
+ /* Field sidebar (left) */
29
+ .dte-formula-sidebar {
30
+ flex: 0 0 220px;
31
+ border-right: 1px solid var(--border-color);
32
+ padding-right: var(--spacing-2);
33
+ gap: var(--spacing-2);
34
+ display: flex;
35
+ flex-direction: column;
36
+ min-height: 0;
37
+ overflow-y: auto;
38
+ }
39
+
40
+ .dte-formula-field-list {
41
+ margin: var(--spacing-0);
42
+ padding: var(--spacing-0);
43
+ list-style: none;
44
+ }
45
+
46
+ .dte-formula-field-list-item {
47
+ padding: var(--spacing-1) var(--spacing-2);
48
+ cursor: pointer;
49
+ border-left: 3px solid transparent;
50
+ border-bottom: 1px solid var(--border-color);
51
+ }
52
+
53
+ .dte-formula-field-list-item:hover,
54
+ .dte-formula-field-list-item.--highlight {
55
+ color: var(--color-neutral-100, #e8e8e8);
56
+ }
57
+
58
+ .dte-formula-field-list-item.--selected {
59
+ border-left-color: var(--border-color-active, #0265dc);
60
+ }
61
+
62
+ .dte-formula-editor {
63
+ min-height: 100px;
64
+ max-height: 180px;
65
+ overflow-y: auto;
66
+ padding: var(--spacing-2);
67
+ border: 1px solid var(--border-color);
68
+ border-radius: 4px;
69
+ outline: none;
70
+ font-size: var(--typescale-2);
71
+ line-height: var(--base-line-height);
72
+ white-space: pre-wrap;
73
+ }
74
+
75
+ .dte-formula-editor:focus {
76
+ border-color: var(--border-color-active);
77
+ box-shadow: 0 0 0 1px var(--border-color-active);
78
+ }
79
+
80
+ .dte-formula-editor-invalid {
81
+ border-color: var(--danger, #dc3545);
82
+ }
83
+
84
+ .dte-formula-editor:empty::before {
85
+ content: attr(data-placeholder);
86
+ color: var(--color-neutral-200);
87
+ }
88
+
89
+ .dte-formula-chip {
90
+ display: inline-flex;
91
+ align-items: center;
92
+ padding: 2px 6px;
93
+ margin: var(--spacing-0) 2px;
94
+ background: var(--menu-active-color, #0265dc);
95
+ border-radius: var(--spacing-half, 4px);
96
+ color: var(--white);
97
+ gap: var(--spacing-half);
98
+ margin-bottom: var(--spacing-half);
99
+ cursor: grab;
100
+ font-weight: 500;
101
+ }
102
+
103
+ .dte-formula-chip-label {
104
+ pointer-events: none;
105
+ }
106
+
107
+ .dte-formula-chip-remove {
108
+ cursor: pointer;
109
+ opacity: 0.9;
110
+ padding: var(--spacing-0) 2px;
111
+ line-height: 1;
112
+ }
113
+
114
+ .dte-formula-chip-remove:hover {
115
+ opacity: 1;
116
+ }
117
+
118
+ .dte-formula-advanced-toggle {
119
+ background: none;
120
+ border: none;
121
+ padding: var(--spacing-0);
122
+ font-size: var(--typescale-2);
123
+ color: var(--menu-active-color, #0265dc);
124
+ cursor: pointer;
125
+ text-decoration: none;
126
+ }
127
+
128
+ .dte-formula-advanced-toggle:hover {
129
+ text-decoration: underline;
130
+ }
131
+
132
+ .dte-formula-advanced {
133
+ margin-top: var(--spacing-2);
134
+ padding-top: var(--spacing-2);
135
+ border-top: 1px solid var(--border-color);
136
+ display: flex;
137
+ flex-direction: column;
138
+ gap: var(--spacing-2);
139
+ }
140
+
141
+ .dte-formula-advanced-row {
142
+ margin-bottom: var(--spacing-0);
143
+ }
144
+
145
+ .dte-formula-advanced-value {
146
+ color: var(--color-neutral-300);
147
+ }
148
+
149
+ .dte-formula-advanced-range {
150
+ width: 100%;
151
+ margin: var(--spacing-0);
152
+ }
153
+
154
+ .dte-formula-advanced-checkbox {
155
+ display: flex;
156
+ align-items: center;
157
+ gap: var(--spacing-1);
158
+ cursor: pointer;
159
+ }
160
+
161
+ .dte-formula-advanced-checkbox input {
162
+ margin: var(--spacing-0);
163
+ }
164
+
165
+ .dte-formula-advanced-input {
166
+ flex: 1;
167
+ min-width: 0;
168
+ max-width: 160px;
169
+ padding: var(--spacing-1) var(--spacing-2);
170
+ border: 1px solid var(--border-color);
171
+ border-radius: 4px;
172
+ font-size: var(--typescale-2);
173
+ }
174
+
175
+ .dte-formula-modal-header {
176
+ padding: var(--spacing-2);
177
+ border-bottom: 1px solid var(--border-color);
178
+ }
179
+
180
+ .dte-formula-modal-footer {
181
+ padding: var(--spacing-2);
182
+ border-top: 1px solid var(--border-color);
183
+ }
184
+
185
+ /* Token input */
186
+ .dte-formula-token-input-wrapper {
187
+ display: flex;
188
+ flex-direction: row;
189
+ align-items: stretch;
190
+ gap: var(--spacing-2);
191
+ }
192
+
193
+ .dte-formula-token-input {
194
+ flex: 1;
195
+ padding: var(--spacing-1) var(--spacing-2);
196
+ border: 1px solid var(--border-color);
197
+ border-radius: 4px;
198
+ outline: none;
199
+ flex-wrap: wrap;
200
+ gap: 2px;
201
+ cursor: text;
202
+ }
203
+
204
+ .dte-formula-token-input:focus {
205
+ border-color: var(--border-color-active);
206
+ box-shadow: 0 0 0 1px var(--border-color-active);
207
+ }
208
+
209
+ .dte-formula-placeholder {
210
+ color: var(--color-neutral-200);
211
+ }
212
+
213
+ .dte-formula-token {
214
+ margin: var(--spacing-half);
215
+ user-select: none;
216
+ font-size: var(--typescale-2);
217
+ }
218
+
219
+ .dte-formula-token-field {
220
+ padding: 2px var(--spacing-half);
221
+ background: var(--menu-active-color, #0265dc);
222
+ border-radius: var(--spacing-half, 4px);
223
+ color: var(--white);
224
+ flex-shrink: 0;
225
+ }
226
+
227
+ .dte-formula-token-delete {
228
+ display: inline-flex;
229
+ align-items: center;
230
+ justify-content: center;
231
+ padding: var(--spacing-0);
232
+ margin: var(--spacing-0);
233
+ margin-left: 2px;
234
+ border: none;
235
+ background: transparent;
236
+ color: var(--color-neutral-200);
237
+ cursor: pointer;
238
+ border-radius: 2px;
239
+ }
240
+
241
+ .dte-formula-token-delete:hover {
242
+ color: var(--danger, #dc3545);
243
+ }
244
+
245
+ .dte-formula-token-number {
246
+ font-variant-numeric: tabular-nums;
247
+ }
248
+
249
+ .dte-formula-caret {
250
+ width: 0;
251
+ height: 1em;
252
+ border-left: 2px solid var(--color-neutral-300);
253
+ margin: var(--spacing-0) 1px;
254
+ animation: dte-formula-caret-blink 1s step-end infinite;
255
+ }
256
+
257
+ @keyframes dte-formula-caret-blink {
258
+ 50% {
259
+ opacity: 0;
260
+ }
261
+ }
262
+
263
+ /* Autosuggest - left side, always visible */
264
+ .dte-formula-autosuggest {
265
+ margin: var(--spacing-0);
266
+ padding: var(--spacing-0);
267
+ list-style: none;
268
+ width: 200px;
269
+ min-width: 200px;
270
+ max-height: 200px;
271
+ overflow-y: auto;
272
+ background: var(--white);
273
+ border: 1px solid var(--border-color);
274
+ border-radius: 4px;
275
+ flex-shrink: 0;
276
+ }
277
+
278
+ .dte-formula-autosuggest-item {
279
+ padding: var(--spacing-1) var(--spacing-2);
280
+ cursor: pointer;
281
+ }
282
+
283
+ .dte-formula-autosuggest-item:hover,
284
+ .dte-formula-autosuggest-item.--highlight {
285
+ color: var(--menu-active-color);
286
+ }
287
+
288
+ .dte-formula-autosuggest-item.empty {
289
+ cursor: default;
290
+ color: var(--color-neutral-200);
291
+ }
292
+
293
+ .dte-formula-box {
294
+ padding: var(--spacing-1) var(--spacing-2);
295
+ border: 1px solid var(--border-color);
296
+ border-radius: 4px;
297
+ background: var(--color-neutral-0);
298
+ cursor: pointer;
299
+ display: flex;
300
+ overflow-x: auto;
301
+ align-items: center;
302
+ gap: 2px;
303
+ }
304
+
305
+ .dte-formula-box:hover {
306
+ border-color: var(--border-color-hover);
307
+ }
@@ -6,5 +6,6 @@
6
6
  @import './pdf-editor.css';
7
7
  @import './field-type-list.css';
8
8
  @import './field-config-panel-overlay.css';
9
+ @import './formula-modal.css';
9
10
  @import './field-type.css';
10
11
  @import './pdf-document-renderer.css';
@@ -33,6 +33,7 @@
33
33
 
34
34
  .dte-pdf-field.--dragging {
35
35
  opacity: 0.5;
36
+ will-change: left, top;
36
37
  }
37
38
 
38
39
  .dte-pdf-field.--colored:not(.--selected) {
@@ -2,17 +2,37 @@ import {
2
2
  DataModelFieldGroup,
3
3
  FieldTypeEnum,
4
4
  FieldTypeOption,
5
+ SchemaNode,
5
6
  SchemaObject,
7
+ SchemaSimpleNumber,
6
8
  } from '../../interface/types';
7
9
 
10
+ function isSchemaSimpleNumber(node: SchemaNode): node is SchemaSimpleNumber {
11
+ return node.type === 'number';
12
+ }
13
+
14
+ function useInCalculatedFields(node: SchemaNode): boolean {
15
+ return node.options?.useInCalculatedFields === true;
16
+ }
17
+
18
+ export interface ExtractGroupedFieldsOptions {
19
+ /** When true, only include fields with SchemaFieldBaseOptions.useInCalculatedFields === true */
20
+ onlyUseInCalculatedFields?: boolean;
21
+ }
22
+
8
23
  /**
9
24
  * Utility function to extract grouped fields from DataModel structure
10
25
  * Filters out array types and only processes object properties, generating correct paths for data replacement
11
26
  */
27
+ const DEFAULT_GROUP_NAME = 'Fields';
28
+
12
29
  export const extractGroupedFieldsFromDataModel = (
13
30
  dataModel: SchemaObject,
31
+ options?: ExtractGroupedFieldsOptions,
14
32
  ): DataModelFieldGroup[] => {
33
+ const onlyUseInCalculatedFields = options?.onlyUseInCalculatedFields === true;
15
34
  const groups: DataModelFieldGroup[] = [];
35
+ const topLevelFields: FieldTypeOption[] = [];
16
36
 
17
37
  if (!dataModel?.properties) {
18
38
  return groups;
@@ -23,7 +43,13 @@ export const extractGroupedFieldsFromDataModel = (
23
43
 
24
44
  if (property.type === 'object' && property.properties) {
25
45
  const fields: FieldTypeOption[] = [];
26
- extractFieldsRecursive(property.properties, key, fields, key);
46
+ extractFieldsRecursive(
47
+ property.properties,
48
+ key,
49
+ fields,
50
+ key,
51
+ onlyUseInCalculatedFields,
52
+ );
27
53
 
28
54
  if (fields.length > 0) {
29
55
  groups.push({
@@ -33,18 +59,42 @@ export const extractGroupedFieldsFromDataModel = (
33
59
  }
34
60
  } else if (property.type === 'array' && property.items) {
35
61
  // Skip array types - filter them out from the data model
62
+ } else {
63
+ // First-level simple field (string, number, boolean) – add under default group
64
+ const rawType = (property as { type?: string }).type;
65
+ const isLeaf =
66
+ property.type === 'string' ||
67
+ isSchemaSimpleNumber(property as SchemaNode) ||
68
+ rawType === 'boolean';
69
+ const includeField =
70
+ !onlyUseInCalculatedFields || useInCalculatedFields(property as SchemaNode);
71
+ if (isLeaf && includeField) {
72
+ topLevelFields.push({
73
+ label: (property as SchemaNode).title ?? key,
74
+ type: FieldTypeEnum.dataModel,
75
+ path: key,
76
+ });
77
+ }
36
78
  }
37
79
  });
38
80
 
81
+ if (topLevelFields.length > 0) {
82
+ groups.unshift({
83
+ groupName: DEFAULT_GROUP_NAME,
84
+ fields: topLevelFields,
85
+ });
86
+ }
87
+
39
88
  return groups;
40
89
  };
41
90
 
42
91
  // Recursive function to extract fields from nested structures
43
92
  const extractFieldsRecursive = (
44
- properties: any,
93
+ properties: Record<string, SchemaNode>,
45
94
  basePath: string,
46
95
  fields: FieldTypeOption[],
47
96
  groupName: string,
97
+ onlyUseInCalculatedFields: boolean,
48
98
  ): void => {
49
99
  Object.keys(properties).forEach(fieldKey => {
50
100
  const fieldProperty = properties[fieldKey];
@@ -52,11 +102,13 @@ const extractFieldsRecursive = (
52
102
  ? `${basePath}.${fieldKey}`
53
103
  : `${basePath}.${fieldKey}`;
54
104
 
55
- if (
105
+ const rawType = (fieldProperty as { type?: string }).type;
106
+ const isLeaf =
56
107
  fieldProperty.type === 'string' ||
57
- fieldProperty.type === 'number' ||
58
- fieldProperty.type === 'boolean'
59
- ) {
108
+ isSchemaSimpleNumber(fieldProperty) ||
109
+ rawType === 'boolean';
110
+ const includeField = !onlyUseInCalculatedFields || useInCalculatedFields(fieldProperty);
111
+ if (isLeaf && includeField) {
60
112
  // Leaf property - add as a field
61
113
  const label = fieldProperty.title ?? fieldKey;
62
114
  fields.push({
@@ -65,7 +117,13 @@ const extractFieldsRecursive = (
65
117
  path: currentPath,
66
118
  });
67
119
  } else if (fieldProperty.type === 'object' && fieldProperty.properties) {
68
- extractFieldsRecursive(fieldProperty.properties, currentPath, fields, groupName);
120
+ extractFieldsRecursive(
121
+ fieldProperty.properties,
122
+ currentPath,
123
+ fields,
124
+ groupName,
125
+ onlyUseInCalculatedFields,
126
+ );
69
127
  } else if (fieldProperty.type === 'array' && fieldProperty.items) {
70
128
  // Skip array types - filter them out from the data model
71
129
  }
@@ -0,0 +1,125 @@
1
+ import { placeCaretAtEnd, readExpressionFromEditor } from './dom.utils';
2
+
3
+ function getExpressionBeforeCaret(element: HTMLElement): string {
4
+ const selection = window.getSelection();
5
+ if (!selection || selection.rangeCount === 0) {
6
+ return readExpressionFromEditor(element);
7
+ }
8
+ const range = selection.getRangeAt(0);
9
+ const endContainer = range.endContainer;
10
+ const endOffset = range.endOffset;
11
+ const parts: string[] = [];
12
+
13
+ const appendNode = (node: ChildNode) => {
14
+ if (node.nodeType === Node.TEXT_NODE) {
15
+ parts.push(node.textContent ?? '');
16
+ return;
17
+ }
18
+ if (node instanceof HTMLElement && node.dataset.field) {
19
+ parts.push(node.dataset.field);
20
+ return;
21
+ }
22
+ parts.push(node.textContent ?? '');
23
+ };
24
+
25
+ const getTopLevelChild = (node: Node): ChildNode | null => {
26
+ let current: Node | null = node;
27
+ while (current && current.parentNode !== element) {
28
+ current = current.parentNode;
29
+ }
30
+ return current && current.parentNode === element ? (current as ChildNode) : null;
31
+ };
32
+
33
+ if (endContainer === element) {
34
+ element.childNodes.forEach((node, index) => {
35
+ if (index < endOffset) {
36
+ appendNode(node);
37
+ }
38
+ });
39
+ return parts.join('').replace(/\u00a0/g, ' ');
40
+ }
41
+
42
+ const topChild = getTopLevelChild(endContainer);
43
+ if (!topChild) {
44
+ return readExpressionFromEditor(element);
45
+ }
46
+
47
+ for (const node of Array.from(element.childNodes)) {
48
+ if (node === topChild) {
49
+ if (node.nodeType === Node.TEXT_NODE) {
50
+ parts.push((node.textContent ?? '').slice(0, endOffset));
51
+ } else if (node instanceof HTMLElement && node.dataset.field) {
52
+ if (endOffset > 0) {
53
+ parts.push(node.dataset.field);
54
+ }
55
+ } else {
56
+ parts.push((node.textContent ?? '').slice(0, endOffset));
57
+ }
58
+ break;
59
+ }
60
+ appendNode(node);
61
+ }
62
+ return parts.join('').replace(/\u00a0/g, ' ');
63
+ }
64
+
65
+ export function getCaretExpressionIndex(element: HTMLElement): number {
66
+ return getExpressionBeforeCaret(element).length;
67
+ }
68
+
69
+ export function setCaretByExpressionIndex(element: HTMLElement, index: number): void {
70
+ const selection = window.getSelection();
71
+ if (!selection) {
72
+ return;
73
+ }
74
+ let remaining = index;
75
+ let targetNode: Node | null = null;
76
+ let targetOffset = 0;
77
+
78
+ const getNodeLength = (node: ChildNode): number => {
79
+ if (node.nodeType === Node.TEXT_NODE) {
80
+ return node.textContent?.length ?? 0;
81
+ }
82
+ if (node instanceof HTMLElement && node.dataset.field) {
83
+ return node.dataset.field?.length ?? 0;
84
+ }
85
+ return node.textContent?.length ?? 0;
86
+ };
87
+
88
+ for (const node of Array.from(element.childNodes)) {
89
+ const len = getNodeLength(node);
90
+ if (remaining <= len) {
91
+ targetNode = node;
92
+ targetOffset = remaining;
93
+ break;
94
+ }
95
+ remaining -= len;
96
+ }
97
+
98
+ if (!targetNode) {
99
+ placeCaretAtEnd(element);
100
+ return;
101
+ }
102
+
103
+ const range = document.createRange();
104
+ if (targetNode.nodeType === Node.TEXT_NODE) {
105
+ range.setStart(targetNode, targetOffset);
106
+ } else if (targetNode instanceof HTMLElement && targetNode.dataset.field) {
107
+ range.setStartAfter(targetNode);
108
+ } else if (targetNode instanceof HTMLElement) {
109
+ const textNode = Array.from(targetNode.childNodes).find(
110
+ n => n.nodeType === Node.TEXT_NODE,
111
+ ) as Text | undefined;
112
+ if (textNode) {
113
+ range.setStart(textNode, Math.min(targetOffset, textNode.textContent?.length ?? 0));
114
+ } else if (targetOffset > 0) {
115
+ range.setStartAfter(targetNode);
116
+ } else {
117
+ range.setStartBefore(targetNode);
118
+ }
119
+ } else {
120
+ range.setStart(targetNode, targetOffset);
121
+ }
122
+ range.collapse(true);
123
+ selection.removeAllRanges();
124
+ selection.addRange(range);
125
+ }
@@ -0,0 +1,35 @@
1
+ export const escapeHtml = (value: string): string =>
2
+ value
3
+ .replace(/&/g, '&amp;')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&#039;');
8
+
9
+ export function readExpressionFromEditor(node: HTMLElement): string {
10
+ const parts: string[] = [];
11
+ node.childNodes.forEach(child => {
12
+ if (child.nodeType === Node.TEXT_NODE) {
13
+ parts.push(child.textContent ?? '');
14
+ return;
15
+ }
16
+ if (child instanceof HTMLElement && child.dataset.field) {
17
+ parts.push(child.dataset.field);
18
+ return;
19
+ }
20
+ parts.push(child.textContent ?? '');
21
+ });
22
+ return parts.join('').replace(/\u00a0/g, ' ');
23
+ }
24
+
25
+ export function placeCaretAtEnd(element: HTMLElement): void {
26
+ const selection = window.getSelection();
27
+ if (!selection) {
28
+ return;
29
+ }
30
+ const range = document.createRange();
31
+ range.selectNodeContents(element);
32
+ range.collapse(false);
33
+ selection.removeAllRanges();
34
+ selection.addRange(range);
35
+ }