@duffcloudservices/site-forms 0.1.1 → 0.1.3

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 (41) hide show
  1. package/README.md +274 -260
  2. package/dist/composables/useFormSubmission.d.ts +1 -1
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.js +554 -398
  5. package/dist/index.js.map +1 -1
  6. package/dist/presets.d.ts +13 -0
  7. package/dist/site-forms.css +1 -0
  8. package/dist/types.d.ts +12 -2
  9. package/package.json +72 -73
  10. package/src/DcsForm.vue +295 -303
  11. package/src/__tests__/fields.test.ts +81 -82
  12. package/src/__tests__/multi-step.test.ts +45 -46
  13. package/src/__tests__/presets.test.ts +64 -0
  14. package/src/__tests__/schema.test.ts +41 -42
  15. package/src/__tests__/style-import.test.ts +9 -0
  16. package/src/__tests__/submission.test.ts +115 -77
  17. package/src/__tests__/validation.test.ts +29 -0
  18. package/src/__tests__/visible-if.test.ts +110 -111
  19. package/src/composables/useDcsForm.ts +201 -201
  20. package/src/composables/useFormSubmission.ts +113 -113
  21. package/src/composables/useFormValidation.ts +128 -127
  22. package/src/fields/DcsFormCheckbox.vue +35 -35
  23. package/src/fields/DcsFormCheckboxGroup.vue +52 -52
  24. package/src/fields/DcsFormDate.vue +34 -34
  25. package/src/fields/DcsFormFieldWrapper.vue +39 -39
  26. package/src/fields/DcsFormFile.vue +38 -38
  27. package/src/fields/DcsFormHidden.vue +17 -17
  28. package/src/fields/DcsFormHtmlBlock.vue +19 -19
  29. package/src/fields/DcsFormRadio.vue +45 -45
  30. package/src/fields/DcsFormSection.vue +19 -19
  31. package/src/fields/DcsFormSelect.vue +62 -62
  32. package/src/fields/DcsFormText.vue +54 -54
  33. package/src/fields/DcsFormTextarea.vue +43 -43
  34. package/src/index.ts +64 -51
  35. package/src/loaders/yaml.ts +51 -51
  36. package/src/presets.ts +192 -0
  37. package/src/schema/form-definition.schema.json +410 -45
  38. package/src/schema/validate.ts +58 -58
  39. package/src/shims.d.ts +10 -10
  40. package/src/style.css +256 -0
  41. package/src/types.ts +164 -140
@@ -6,7 +6,6 @@
6
6
  "description": "Portable form definition. This schema is the source of truth for\nboth the portal CRUD APIs and the `.dcs/forms/<formId>.yaml`\nfiles consumed by customer-site builds via `<DcsForm/>`.\n",
7
7
  "required": [
8
8
  "formId",
9
- "title",
10
9
  "submission",
11
10
  "fields"
12
11
  ],
@@ -19,17 +18,8 @@
19
18
  "maxLength": 80,
20
19
  "example": "contact"
21
20
  },
22
- "title": {
23
- "type": "string",
24
- "description": "Human-readable form title shown in the portal and rendered as the form heading.",
25
- "minLength": 1,
26
- "maxLength": 200,
27
- "example": "Contact Us"
28
- },
29
- "description": {
30
- "type": "string",
31
- "description": "Optional descriptive text rendered above the fields.",
32
- "maxLength": 2000
21
+ "formKind": {
22
+ "$ref": "#/definitions/PortalFormKind"
33
23
  },
34
24
  "submitLabel": {
35
25
  "type": "string",
@@ -46,6 +36,9 @@
46
36
  "submission": {
47
37
  "$ref": "#/definitions/PortalFormSubmissionConfig"
48
38
  },
39
+ "attachmentPolicy": {
40
+ "$ref": "#/definitions/PortalFormAttachmentPolicy"
41
+ },
49
42
  "steps": {
50
43
  "type": "array",
51
44
  "description": "Optional multi-step grouping. When omitted, fields render as a single page.",
@@ -77,6 +70,278 @@
77
70
  }
78
71
  },
79
72
  "definitions": {
73
+ "PortalFormKind": {
74
+ "type": "string",
75
+ "description": "High-level form kind used by the visual page editor and submission\npipeline. `freeform` preserves fully editable questionnaires; the\nstandard values provide predictable field roles and routing for common\nsite forms.\n",
76
+ "enum": [
77
+ "freeform",
78
+ "contact",
79
+ "revenue-contractor",
80
+ "resume-submission"
81
+ ],
82
+ "default": "freeform"
83
+ },
84
+ "PortalFormFieldRole": {
85
+ "type": "string",
86
+ "description": "Semantic role for a field inside a standard form. Free-form forms may\nomit roles or use `custom`; standard forms use roles so submissions can\nbe surfaced consistently as contact messages, notifications, revenue\ncontractor inquiries, or resume submissions without locking the editor\nout of label/help-text changes.\n",
87
+ "enum": [
88
+ "contact-name",
89
+ "contact-email",
90
+ "contact-phone",
91
+ "contact-company",
92
+ "subject",
93
+ "message",
94
+ "summary",
95
+ "image-attachments",
96
+ "resume",
97
+ "consent",
98
+ "custom"
99
+ ]
100
+ },
101
+ "PortalFormAttachmentPolicy": {
102
+ "type": "object",
103
+ "description": "Attachment expectations for standard forms. For\n`revenue-contractor`, image attachments are expected so contractors can\ninclude project photos. For `resume-submission`, the resume field\nshould accept document uploads. Free-form questionnaires can omit this.\n",
104
+ "properties": {
105
+ "expected": {
106
+ "type": "boolean",
107
+ "default": false,
108
+ "description": "Whether the standard flow should prompt for attachments."
109
+ },
110
+ "required": {
111
+ "type": "boolean",
112
+ "default": false,
113
+ "description": "Whether at least one attachment is required."
114
+ },
115
+ "maxFiles": {
116
+ "type": "integer",
117
+ "minimum": 1,
118
+ "maximum": 20,
119
+ "description": "Maximum number of files accepted.",
120
+ "example": 5
121
+ },
122
+ "maxFileSizeBytes": {
123
+ "type": "integer",
124
+ "minimum": 1,
125
+ "description": "Maximum size per file in bytes.",
126
+ "example": 10485760
127
+ },
128
+ "accept": {
129
+ "type": "array",
130
+ "description": "Accepted MIME types or extensions (for example `image/*`).",
131
+ "items": {
132
+ "type": "string"
133
+ }
134
+ }
135
+ }
136
+ },
137
+ "PublicSiteFormContact": {
138
+ "type": "object",
139
+ "description": "Normalized contact identity supplied with a public form submission.",
140
+ "properties": {
141
+ "name": {
142
+ "type": "string",
143
+ "maxLength": 160
144
+ },
145
+ "email": {
146
+ "type": "string",
147
+ "format": "email",
148
+ "maxLength": 255
149
+ },
150
+ "phone": {
151
+ "type": "string",
152
+ "maxLength": 32
153
+ },
154
+ "company": {
155
+ "type": "string",
156
+ "maxLength": 160
157
+ }
158
+ }
159
+ },
160
+ "PublicSiteFormAttachment": {
161
+ "type": "object",
162
+ "description": "Metadata for an attachment associated with a public form submission.",
163
+ "required": [
164
+ "fileName"
165
+ ],
166
+ "properties": {
167
+ "fileName": {
168
+ "type": "string",
169
+ "maxLength": 255
170
+ },
171
+ "contentType": {
172
+ "type": "string",
173
+ "maxLength": 120
174
+ },
175
+ "sizeBytes": {
176
+ "type": "integer",
177
+ "minimum": 0
178
+ },
179
+ "storageUrl": {
180
+ "type": "string",
181
+ "format": "uri",
182
+ "description": "Internal or pre-uploaded storage URL when the binary was uploaded separately."
183
+ }
184
+ }
185
+ },
186
+ "PublicSiteFormSubmissionRequest": {
187
+ "type": "object",
188
+ "description": "JSON request for public managed-form submissions.",
189
+ "required": [
190
+ "values"
191
+ ],
192
+ "properties": {
193
+ "formKind": {
194
+ "$ref": "#/definitions/PortalFormKind"
195
+ },
196
+ "pageSlug": {
197
+ "type": "string",
198
+ "description": "Optional visual-editor page slug where the form was rendered."
199
+ },
200
+ "contact": {
201
+ "$ref": "#/definitions/PublicSiteFormContact"
202
+ },
203
+ "subject": {
204
+ "type": "string",
205
+ "maxLength": 200,
206
+ "description": "Contact subject or inquiry title."
207
+ },
208
+ "summary": {
209
+ "type": "string",
210
+ "maxLength": 4000,
211
+ "description": "Project, request, or applicant summary for standard flows."
212
+ },
213
+ "message": {
214
+ "type": "string",
215
+ "maxLength": 4000,
216
+ "description": "Free-text message supplied by the submitter."
217
+ },
218
+ "values": {
219
+ "type": "object",
220
+ "additionalProperties": true,
221
+ "description": "Field id to submitted value map for the attached PortalFormDefinition."
222
+ },
223
+ "attachments": {
224
+ "type": "array",
225
+ "description": "Attachment metadata for JSON submissions.",
226
+ "items": {
227
+ "$ref": "#/definitions/PublicSiteFormAttachment"
228
+ }
229
+ },
230
+ "source": {
231
+ "type": "string",
232
+ "maxLength": 120,
233
+ "description": "Capture source such as `site-contact-page` or `visual-page-editor`."
234
+ },
235
+ "consent": {
236
+ "type": "boolean",
237
+ "description": "Whether the submitter consented to follow-up."
238
+ }
239
+ }
240
+ },
241
+ "PublicSiteFormMultipartSubmissionRequest": {
242
+ "type": "object",
243
+ "description": "Multipart request for public managed-form submissions with binary uploads.",
244
+ "properties": {
245
+ "formKind": {
246
+ "$ref": "#/definitions/PortalFormKind"
247
+ },
248
+ "pageSlug": {
249
+ "type": "string"
250
+ },
251
+ "values": {
252
+ "type": "string",
253
+ "description": "JSON-encoded field id to submitted value map."
254
+ },
255
+ "name": {
256
+ "type": "string",
257
+ "maxLength": 160
258
+ },
259
+ "email": {
260
+ "type": "string",
261
+ "format": "email",
262
+ "maxLength": 255
263
+ },
264
+ "phone": {
265
+ "type": "string",
266
+ "maxLength": 32
267
+ },
268
+ "company": {
269
+ "type": "string",
270
+ "maxLength": 160
271
+ },
272
+ "subject": {
273
+ "type": "string",
274
+ "maxLength": 200
275
+ },
276
+ "summary": {
277
+ "type": "string",
278
+ "maxLength": 4000
279
+ },
280
+ "message": {
281
+ "type": "string",
282
+ "maxLength": 4000
283
+ },
284
+ "attachments": {
285
+ "type": "array",
286
+ "description": "Image or supporting files for standard form submissions.",
287
+ "items": {
288
+ "type": "string",
289
+ "format": "binary"
290
+ }
291
+ },
292
+ "resume": {
293
+ "type": "string",
294
+ "format": "binary",
295
+ "description": "Resume document for `resume-submission` standard forms."
296
+ },
297
+ "source": {
298
+ "type": "string",
299
+ "maxLength": 120
300
+ },
301
+ "consent": {
302
+ "type": "boolean"
303
+ }
304
+ }
305
+ },
306
+ "PublicSiteFormSubmissionResponse": {
307
+ "type": "object",
308
+ "required": [
309
+ "id",
310
+ "status",
311
+ "submittedAt"
312
+ ],
313
+ "properties": {
314
+ "id": {
315
+ "type": "string",
316
+ "description": "Unique submission identifier."
317
+ },
318
+ "status": {
319
+ "type": "string",
320
+ "enum": [
321
+ "submitted",
322
+ "accepted",
323
+ "queued"
324
+ ]
325
+ },
326
+ "submittedAt": {
327
+ "type": "string",
328
+ "format": "date-time"
329
+ },
330
+ "message": {
331
+ "type": "string",
332
+ "description": "Friendly acknowledgement shown to the submitter."
333
+ },
334
+ "contactMessageId": {
335
+ "type": "string",
336
+ "nullable": true,
337
+ "description": "Future portal contact-message identifier when surfaced in the portal."
338
+ },
339
+ "notificationQueued": {
340
+ "type": "boolean",
341
+ "description": "Whether a portal notification/contact-message handoff was queued."
342
+ }
343
+ }
344
+ },
80
345
  "PortalFormFieldType": {
81
346
  "type": "string",
82
347
  "description": "Field type controlling input rendering and validation. Includes\nlayout-only types (`section-heading`, `html-block`) that render\ndecorative content rather than capturing values, and `hidden`\nfor prefilled values not displayed to the user.\n",
@@ -206,6 +471,9 @@
206
471
  "type": {
207
472
  "$ref": "#/definitions/PortalFormFieldType"
208
473
  },
474
+ "role": {
475
+ "$ref": "#/definitions/PortalFormFieldRole"
476
+ },
209
477
  "label": {
210
478
  "type": "string",
211
479
  "description": "Human-readable label rendered above the input.",
@@ -361,7 +629,7 @@
361
629
  },
362
630
  "subjectTemplate": {
363
631
  "type": "string",
364
- "description": "Optional subject-line template. Use `{title}` to interpolate\nthe form's title; values are intentionally not interpolated\ninto the subject line for compliance reasons.\n",
632
+ "description": "Optional subject-line template. Submitted values are intentionally\nnot interpolated into the subject line for compliance reasons.\n",
365
633
  "maxLength": 200
366
634
  }
367
635
  }
@@ -418,7 +686,6 @@
418
686
  "description": "List-row projection of a form definition.",
419
687
  "required": [
420
688
  "formId",
421
- "title",
422
689
  "fieldCount"
423
690
  ],
424
691
  "properties": {
@@ -428,14 +695,8 @@
428
695
  "pattern": "^[a-z0-9][a-z0-9-]*$",
429
696
  "example": "contact"
430
697
  },
431
- "title": {
432
- "type": "string",
433
- "description": "Human-readable title.",
434
- "example": "Contact Us"
435
- },
436
- "description": {
437
- "type": "string",
438
- "description": "Optional descriptive text."
698
+ "formKind": {
699
+ "$ref": "#/definitions/PortalFormKind"
439
700
  },
440
701
  "fieldCount": {
441
702
  "type": "integer",
@@ -471,7 +732,6 @@
471
732
  "description": "Payload for creating a new form definition.",
472
733
  "required": [
473
734
  "formId",
474
- "title",
475
735
  "submission",
476
736
  "fields"
477
737
  ],
@@ -483,14 +743,8 @@
483
743
  "minLength": 1,
484
744
  "maxLength": 80
485
745
  },
486
- "title": {
487
- "type": "string",
488
- "minLength": 1,
489
- "maxLength": 200
490
- },
491
- "description": {
492
- "type": "string",
493
- "maxLength": 2000
746
+ "formKind": {
747
+ "$ref": "#/definitions/PortalFormKind"
494
748
  },
495
749
  "submitLabel": {
496
750
  "type": "string",
@@ -503,6 +757,9 @@
503
757
  "submission": {
504
758
  "$ref": "#/definitions/PortalFormSubmissionConfig"
505
759
  },
760
+ "attachmentPolicy": {
761
+ "$ref": "#/definitions/PortalFormAttachmentPolicy"
762
+ },
506
763
  "steps": {
507
764
  "type": "array",
508
765
  "items": {
@@ -528,14 +785,8 @@
528
785
  "maxLength": 80,
529
786
  "description": "Optional echo of the path formId; must match if provided."
530
787
  },
531
- "title": {
532
- "type": "string",
533
- "minLength": 1,
534
- "maxLength": 200
535
- },
536
- "description": {
537
- "type": "string",
538
- "maxLength": 2000
788
+ "formKind": {
789
+ "$ref": "#/definitions/PortalFormKind"
539
790
  },
540
791
  "submitLabel": {
541
792
  "type": "string",
@@ -548,6 +799,9 @@
548
799
  "submission": {
549
800
  "$ref": "#/definitions/PortalFormSubmissionConfig"
550
801
  },
802
+ "attachmentPolicy": {
803
+ "$ref": "#/definitions/PortalFormAttachmentPolicy"
804
+ },
551
805
  "steps": {
552
806
  "type": "array",
553
807
  "items": {
@@ -580,12 +834,6 @@
580
834
  "pattern": "^[a-z0-9][a-z0-9-]*$",
581
835
  "minLength": 1,
582
836
  "maxLength": 80
583
- },
584
- "title": {
585
- "type": "string",
586
- "description": "Optional title override; defaults to `<source title> (copy)`.",
587
- "minLength": 1,
588
- "maxLength": 200
589
837
  }
590
838
  }
591
839
  },
@@ -628,6 +876,123 @@
628
876
  "example": 3
629
877
  }
630
878
  }
879
+ },
880
+ "PortalFormSubmission": {
881
+ "type": "object",
882
+ "description": "A single recorded submission against a managed form. PHI fields are\nreplaced with `[REDACTED]` for Medical-category sites, in which case\n`redactedForPhi` is true.\n",
883
+ "required": [
884
+ "id",
885
+ "formId",
886
+ "siteSlug",
887
+ "submittedAt",
888
+ "source",
889
+ "values",
890
+ "redactedForPhi"
891
+ ],
892
+ "properties": {
893
+ "id": {
894
+ "type": "string",
895
+ "description": "Unique submission row key (reverse-chronological)."
896
+ },
897
+ "formId": {
898
+ "type": "string"
899
+ },
900
+ "siteSlug": {
901
+ "type": "string"
902
+ },
903
+ "formKind": {
904
+ "$ref": "#/definitions/PortalFormKind"
905
+ },
906
+ "submittedAt": {
907
+ "type": "string",
908
+ "format": "date-time"
909
+ },
910
+ "source": {
911
+ "type": "string",
912
+ "description": "Capture channel (e.g. `web`, `import`)."
913
+ },
914
+ "values": {
915
+ "type": "object",
916
+ "additionalProperties": true,
917
+ "description": "Field id → submitted value map. PHI values are redacted."
918
+ },
919
+ "attachments": {
920
+ "type": "array",
921
+ "description": "Attachment metadata captured with the submission.",
922
+ "items": {
923
+ "$ref": "#/definitions/PublicSiteFormAttachment"
924
+ }
925
+ },
926
+ "leadId": {
927
+ "type": "string",
928
+ "nullable": true,
929
+ "description": "Cross-reference to the lead row created by the legacy capture flow."
930
+ },
931
+ "contactMessageId": {
932
+ "type": "string",
933
+ "nullable": true,
934
+ "description": "Future portal contact-message identifier when surfaced in the portal."
935
+ },
936
+ "redactedForPhi": {
937
+ "type": "boolean",
938
+ "description": "True when one or more values were replaced with the PHI placeholder."
939
+ },
940
+ "remoteIp": {
941
+ "type": "string",
942
+ "nullable": true
943
+ },
944
+ "userAgent": {
945
+ "type": "string",
946
+ "nullable": true
947
+ }
948
+ }
949
+ },
950
+ "PortalFormSubmissionSummary": {
951
+ "type": "object",
952
+ "description": "List-view representation of a submission.",
953
+ "required": [
954
+ "id",
955
+ "formId",
956
+ "submittedAt",
957
+ "redactedForPhi",
958
+ "summary"
959
+ ],
960
+ "properties": {
961
+ "id": {
962
+ "type": "string"
963
+ },
964
+ "formId": {
965
+ "type": "string"
966
+ },
967
+ "formKind": {
968
+ "$ref": "#/definitions/PortalFormKind"
969
+ },
970
+ "submittedAt": {
971
+ "type": "string",
972
+ "format": "date-time"
973
+ },
974
+ "redactedForPhi": {
975
+ "type": "boolean"
976
+ },
977
+ "summary": {
978
+ "type": "string",
979
+ "description": "Short single-line preview suitable for the portal list view."
980
+ }
981
+ }
982
+ },
983
+ "PortalFormSubmissionListResponse": {
984
+ "type": "object",
985
+ "required": [
986
+ "submissions"
987
+ ],
988
+ "properties": {
989
+ "submissions": {
990
+ "type": "array",
991
+ "items": {
992
+ "$ref": "#/definitions/PortalFormSubmissionSummary"
993
+ }
994
+ }
995
+ }
631
996
  }
632
997
  }
633
998
  }
@@ -1,58 +1,58 @@
1
- /**
2
- * Validates a loaded form definition against the form-definition JSON
3
- * Schema emitted by `@dcs/contracts`. Dev-only — failures are logged
4
- * via `console.warn` rather than thrown so a malformed YAML never
5
- * takes down a customer site in production.
6
- *
7
- * Schema is bundled as a snapshot of
8
- * `contracts/dist/form-definition.schema.json` to avoid a runtime
9
- * dependency on the contracts build output.
10
- */
11
- import Ajv, { type ErrorObject, type ValidateFunction } from 'ajv'
12
- import addFormats from 'ajv-formats'
13
- import schema from './form-definition.schema.json'
14
- import type { PortalFormDefinition } from '../types'
15
-
16
- let validator: ValidateFunction | null = null
17
-
18
- function getValidator(): ValidateFunction {
19
- if (validator) return validator
20
- const ajv = new Ajv({
21
- allErrors: true,
22
- strict: false,
23
- discriminator: false,
24
- })
25
- addFormats(ajv)
26
- validator = ajv.compile(schema as object)
27
- return validator
28
- }
29
-
30
- export interface SchemaValidationResult {
31
- valid: boolean
32
- errors: ErrorObject[]
33
- }
34
-
35
- export function validateFormDefinition(
36
- def: PortalFormDefinition | unknown,
37
- ): SchemaValidationResult {
38
- const v = getValidator()
39
- const valid = v(def) as boolean
40
- return { valid, errors: valid ? [] : (v.errors ?? []) }
41
- }
42
-
43
- /** Logs a `console.warn` when invalid, but only when `import.meta.env.DEV`. */
44
- export function warnIfInvalid(
45
- formId: string,
46
- def: PortalFormDefinition | unknown,
47
- isDev: boolean,
48
- ): SchemaValidationResult {
49
- const result = validateFormDefinition(def)
50
- if (!result.valid && isDev) {
51
- // eslint-disable-next-line no-console
52
- console.warn(
53
- `[@duffcloudservices/site-forms] Form "${formId}" failed schema validation:`,
54
- result.errors,
55
- )
56
- }
57
- return result
58
- }
1
+ /**
2
+ * Validates a loaded form definition against the form-definition JSON
3
+ * Schema emitted by `@dcs/contracts`. Dev-only — failures are logged
4
+ * via `console.warn` rather than thrown so a malformed YAML never
5
+ * takes down a customer site in production.
6
+ *
7
+ * Schema is bundled as a snapshot of
8
+ * `contracts/dist/form-definition.schema.json` to avoid a runtime
9
+ * dependency on the contracts build output.
10
+ */
11
+ import Ajv, { type ErrorObject, type ValidateFunction } from 'ajv'
12
+ import addFormats from 'ajv-formats'
13
+ import schema from './form-definition.schema.json'
14
+ import type { PortalFormDefinition } from '../types'
15
+
16
+ let validator: ValidateFunction | null = null
17
+
18
+ function getValidator(): ValidateFunction {
19
+ if (validator) return validator
20
+ const ajv = new Ajv({
21
+ allErrors: true,
22
+ strict: false,
23
+ discriminator: false,
24
+ })
25
+ addFormats(ajv)
26
+ validator = ajv.compile(schema as object)
27
+ return validator
28
+ }
29
+
30
+ export interface SchemaValidationResult {
31
+ valid: boolean
32
+ errors: ErrorObject[]
33
+ }
34
+
35
+ export function validateFormDefinition(
36
+ def: PortalFormDefinition | unknown,
37
+ ): SchemaValidationResult {
38
+ const v = getValidator()
39
+ const valid = v(def) as boolean
40
+ return { valid, errors: valid ? [] : (v.errors ?? []) }
41
+ }
42
+
43
+ /** Logs a `console.warn` when invalid, but only when `import.meta.env.DEV`. */
44
+ export function warnIfInvalid(
45
+ formId: string,
46
+ def: PortalFormDefinition | unknown,
47
+ isDev: boolean,
48
+ ): SchemaValidationResult {
49
+ const result = validateFormDefinition(def)
50
+ if (!result.valid && isDev) {
51
+ // eslint-disable-next-line no-console
52
+ console.warn(
53
+ `[@duffcloudservices/site-forms] Form "${formId}" failed schema validation:`,
54
+ result.errors,
55
+ )
56
+ }
57
+ return result
58
+ }
package/src/shims.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- declare module '*.vue' {
2
- import type { DefineComponent } from 'vue'
3
- const component: DefineComponent<{}, {}, unknown>
4
- export default component
5
- }
6
-
7
- declare module '*.json' {
8
- const value: unknown
9
- export default value
10
- }
1
+ declare module '*.vue' {
2
+ import type { DefineComponent } from 'vue'
3
+ const component: DefineComponent<{}, {}, unknown>
4
+ export default component
5
+ }
6
+
7
+ declare module '*.json' {
8
+ const value: unknown
9
+ export default value
10
+ }