@ulu/frontend-vue 0.1.0-beta.9 → 0.1.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/{breakpoints-BbkGNxxt.js → breakpoints-DfGETUy5.js} +1 -1
  2. package/dist/frontend-vue.css +1 -1
  3. package/dist/frontend-vue.js +79 -68
  4. package/dist/index-94HkwBnP.js +7595 -0
  5. package/lib/components/collapsible/UluAccordion.vue +71 -53
  6. package/lib/components/collapsible/UluAccordionGroup.vue +54 -0
  7. package/lib/components/collapsible/UluCollapsible.vue +144 -0
  8. package/lib/components/collapsible/UluDropdown.vue +29 -29
  9. package/lib/components/collapsible/UluOverflowPopover.vue +1 -1
  10. package/lib/components/elements/UluBadge.vue +51 -28
  11. package/lib/components/elements/UluBadgeStack.vue +8 -13
  12. package/lib/components/elements/UluButtonVerbose.vue +119 -0
  13. package/lib/components/elements/UluCard.vue +1 -1
  14. package/lib/components/elements/UluDefinitionList.vue +14 -17
  15. package/lib/components/elements/UluExternalLink.vue +21 -27
  16. package/lib/components/elements/UluIcon.vue +11 -1
  17. package/lib/components/elements/UluList.vue +53 -55
  18. package/lib/components/elements/UluSpokeSpinner.vue +12 -18
  19. package/lib/components/elements/UluTag.vue +35 -35
  20. package/lib/components/forms/UluFileDisplay.vue +49 -31
  21. package/lib/components/forms/UluFormFile.vue +37 -24
  22. package/lib/components/forms/UluFormMessage.vue +13 -10
  23. package/lib/components/forms/UluFormSelect.vue +28 -16
  24. package/lib/components/forms/UluFormText.vue +24 -15
  25. package/lib/components/forms/UluSearchForm.vue +11 -10
  26. package/lib/components/forms/UluSelectableMenu.vue +99 -0
  27. package/lib/components/index.js +4 -3
  28. package/lib/components/layout/UluTitleRail.vue +18 -0
  29. package/lib/components/layout/UluWhenBreakpoint.vue +9 -0
  30. package/lib/components/navigation/UluBreadcrumb.vue +9 -2
  31. package/lib/components/navigation/UluMenu.vue +8 -3
  32. package/lib/components/navigation/UluMenuStack.vue +3 -1
  33. package/lib/components/navigation/UluPager.vue +102 -0
  34. package/lib/components/systems/facets/ExampleFacetsWithPagination.vue +119 -0
  35. package/lib/components/systems/facets/UluFacetsFilterLists.vue +91 -0
  36. package/lib/components/systems/facets/UluFacetsFilterPopovers.vue +125 -0
  37. package/lib/components/systems/facets/UluFacetsFilterSelects.vue +71 -0
  38. package/lib/components/systems/facets/UluFacetsHeaderLayout.vue +24 -0
  39. package/lib/components/systems/facets/UluFacetsList.vue +62 -34
  40. package/lib/components/systems/facets/UluFacetsResults.vue +63 -0
  41. package/lib/components/systems/facets/UluFacetsSearch.vue +27 -50
  42. package/lib/components/systems/facets/UluFacetsSidebarLayout.vue +70 -0
  43. package/lib/components/systems/facets/UluFacetsSort.vue +45 -0
  44. package/lib/components/systems/facets/_facets.scss +2 -3
  45. package/lib/components/systems/facets/_mock-data.js +40 -0
  46. package/lib/components/systems/facets/useFacets.js +268 -0
  47. package/lib/components/systems/index.js +13 -2
  48. package/lib/components/systems/scroll-anchors/UluScrollAnchors.vue +2 -1
  49. package/lib/components/systems/skeleton/UluShowSkeleton.vue +9 -8
  50. package/lib/components/systems/skeleton/UluSkeletonContent.vue +39 -43
  51. package/lib/components/systems/skeleton/UluSkeletonMedia.vue +4 -6
  52. package/lib/components/systems/skeleton/UluSkeletonText.vue +27 -0
  53. package/lib/components/systems/slider/UluImageSlideShow.vue +1 -1
  54. package/lib/components/systems/slider/UluSlideShow.vue +8 -3
  55. package/lib/components/systems/table-sticky/UluTableSticky.vue +7 -7
  56. package/lib/components/systems/table-sticky/UluTableStickyTable.vue +3 -3
  57. package/lib/components/visualizations/UluAnimateNumber.vue +7 -1
  58. package/lib/components/visualizations/UluProgressBar.vue +148 -74
  59. package/lib/components/visualizations/UluProgressCircle.vue +159 -0
  60. package/lib/composables/index.js +3 -1
  61. package/lib/composables/useDocumentTitle.js +61 -0
  62. package/lib/composables/usePagination.js +122 -0
  63. package/lib/index.js +1 -0
  64. package/lib/plugins/core/index.js +6 -1
  65. package/lib/plugins/popovers/UluPopover.vue +8 -3
  66. package/lib/plugins/toast/UluToast.vue +1 -1
  67. package/lib/plugins/toast/UluToastDisplay.vue +19 -2
  68. package/lib/utils/dom.js +12 -0
  69. package/lib/utils/index.js +2 -0
  70. package/lib/utils/{vue-router.js → router.js} +114 -30
  71. package/package.json +17 -11
  72. package/types/components/systems/facets/_mock-data.d.ts +18 -0
  73. package/types/components/systems/facets/_mock-data.d.ts.map +1 -0
  74. package/types/components/systems/facets/useFacets.d.ts +39 -0
  75. package/types/components/systems/facets/useFacets.d.ts.map +1 -0
  76. package/types/components/systems/index.d.ts +1 -1
  77. package/types/composables/index.d.ts +2 -0
  78. package/types/composables/useDocumentTitle.d.ts +22 -0
  79. package/types/composables/useDocumentTitle.d.ts.map +1 -0
  80. package/types/composables/usePageTitle.d.ts +19 -0
  81. package/types/composables/usePageTitle.d.ts.map +1 -0
  82. package/types/composables/usePagination.d.ts +25 -0
  83. package/types/composables/usePagination.d.ts.map +1 -0
  84. package/types/index.d.ts +1 -0
  85. package/types/plugins/core/index.d.ts.map +1 -1
  86. package/types/utils/dom.d.ts +1 -0
  87. package/types/utils/dom.d.ts.map +1 -1
  88. package/types/utils/index.d.ts +3 -0
  89. package/types/utils/index.d.ts.map +1 -0
  90. package/types/utils/router.d.ts +144 -0
  91. package/types/utils/router.d.ts.map +1 -0
  92. package/dist/index-D3Uc6T5M.js +0 -6469
  93. package/lib/components/collapsible/UluCollapsibleRegion.vue +0 -278
  94. package/lib/components/forms/UluCheckboxMenu.vue +0 -36
  95. package/lib/components/systems/facets/UluFacets.vue +0 -380
  96. package/lib/components/systems/skeleton/UluSkeletonTextInline.vue +0 -9
  97. package/lib/components/visualizations/UluProgressDonut.vue +0 -97
  98. package/lib/utils/placeholder.js +0 -6
@@ -19,22 +19,19 @@
19
19
  </dl>
20
20
  </template>
21
21
 
22
- <script>
23
- export default {
24
- name: "UluDefinitionList",
25
- props: {
26
- /**
27
- * Array of term, and description (props in object)
28
- * - Can use slots also
29
- */
30
- items: Array,
31
- /**
32
- * Classes object for different elements { list, item, term, description }
33
- */
34
- classes: {
35
- type: Object,
36
- default: () => ({})
37
- }
22
+ <script setup>
23
+ defineProps({
24
+ /**
25
+ * Array of term, and description (props in object)
26
+ * - Can use slots also
27
+ */
28
+ items: Array,
29
+ /**
30
+ * Classes object for different elements { list, item, term, description }
31
+ */
32
+ classes: {
33
+ type: Object,
34
+ default: () => ({})
38
35
  }
39
- };
36
+ });
40
37
  </script>
@@ -10,37 +10,31 @@
10
10
  </a>
11
11
  </template>
12
12
 
13
- <script>
13
+ <script setup>
14
14
  import UluIcon from "./UluIcon.vue";
15
15
 
16
16
  /**
17
17
  * Component for external links (adds icon after link text)
18
18
  */
19
- export default {
20
- name: "UluExternalLink",
21
- components: {
22
- UluIcon
19
+ defineProps({
20
+ /**
21
+ * Text for link or use slot
22
+ */
23
+ text: String,
24
+ /**
25
+ * Link href
26
+ */
27
+ href: String,
28
+ /**
29
+ * Link target
30
+ */
31
+ target: {
32
+ type: String,
33
+ default: "_blank"
23
34
  },
24
- props: {
25
- /**
26
- * Text for link or use slot
27
- */
28
- text: String,
29
- /**
30
- * Link href
31
- */
32
- href: String,
33
- /**
34
- * Link target
35
- */
36
- target: {
37
- type: String,
38
- default: "_blank"
39
- },
40
- /**
41
- * Override default icon
42
- */
43
- icon: String
44
- }
45
- };
35
+ /**
36
+ * Override default icon
37
+ */
38
+ icon: String
39
+ });
46
40
  </script>
@@ -3,15 +3,17 @@
3
3
  v-if="customIconComponent"
4
4
  :is="customIconComponent"
5
5
  v-bind="customIconProps"
6
+ :class="commonClasses"
6
7
  />
7
8
  <component
8
9
  v-else-if="!useStaticFa && faIconComponent && resolvedDefinition"
9
10
  :is="faIconComponent"
10
11
  v-bind="iconProps"
12
+ :class="commonClasses"
11
13
  />
12
14
  <span
13
15
  v-else-if="useStaticFa && resolvedDefinition"
14
- :class="staticIconClasses"
16
+ :class="[staticIconClasses, commonClasses]"
15
17
  aria-hidden="true"
16
18
  ></span>
17
19
  </template>
@@ -32,6 +34,10 @@
32
34
  * - This will override the 'type' prop if both are provided
33
35
  */
34
36
  icon: [String, Array, Object, Boolean],
37
+ /**
38
+ * Whether the icon should use flow inline
39
+ */
40
+ spaced: Boolean
35
41
  });
36
42
 
37
43
  const useStaticFa = computed(() => {
@@ -76,6 +82,10 @@
76
82
  return getClassesFromDefinition(resolvedDefinition.value);
77
83
  });
78
84
 
85
+ const commonClasses = computed(() => ({
86
+ 'flow-inline': props.spaced
87
+ }));
88
+
79
89
  // Watch for changes to prop
80
90
  // - Use watchEffect because we are watching reactive object property access (props)
81
91
  // - Load FA if needed (so it's not included if it's unneeded)
@@ -28,60 +28,58 @@
28
28
  </component>
29
29
  </template>
30
30
 
31
- <script>
32
- export default {
33
- name: "UluList",
34
- props: {
35
- /**
36
- * Array of list items, output as is or use slot to template the item
37
- */
38
- items: Array,
39
- /**
40
- * Classes object (keys are list and listItem to be applied to <ul> and <li>)
41
- * - Any valid class binding for each
42
- */
43
- classes: {
44
- type: Object,
45
- default: () => ({})
46
- },
47
- /**
48
- * Use list-ordered class, and sets element to <ol>
49
- */
50
- ordered: Boolean,
51
- /**
52
- * Use list-unordered class
53
- */
54
- unordered: Boolean,
55
- /**
56
- * Use list-lines class
57
- */
58
- lines: Boolean,
59
- /**
60
- * Use list-compact class
61
- */
62
- compact: Boolean,
63
- /**
64
- * If setting up custom ordered list this will ensure the correct element type
65
- * - Note: 'ordered' prop sets the ordered list class, this does not
66
- */
67
- forceOrdered: Boolean,
68
- /**
69
- * Define the start value for <ol>
70
- */
71
- start: String,
72
- /**
73
- * Reverse ordered list
74
- */
75
- reversed: Boolean,
76
- /**
77
- * Define list style type (ie. disc, decimal, etc)
78
- */
79
- listStyleType: String,
31
+ <script setup>
32
+ import { computed } from "vue";
33
+
34
+ const props = defineProps({
35
+ /**
36
+ * Array of list items, output as is or use slot to template the item
37
+ */
38
+ items: Array,
39
+ /**
40
+ * Classes object (keys are list and listItem to be applied to <ul> and <li>)
41
+ * - Any valid class binding for each
42
+ */
43
+ classes: {
44
+ type: Object,
45
+ default: () => ({})
80
46
  },
81
- computed: {
82
- listElement() {
83
- return this.ordered || this.forceOrdered ? "ol" : "ul";
84
- }
85
- }
86
- };
47
+ /**
48
+ * Use list-ordered class, and sets element to <ol>
49
+ */
50
+ ordered: Boolean,
51
+ /**
52
+ * Use list-unordered class
53
+ */
54
+ unordered: Boolean,
55
+ /**
56
+ * Use list-lines class
57
+ */
58
+ lines: Boolean,
59
+ /**
60
+ * Use list-compact class
61
+ */
62
+ compact: Boolean,
63
+ /**
64
+ * If setting up custom ordered list this will ensure the correct element type
65
+ * - Note: 'ordered' prop sets the ordered list class, this does not
66
+ */
67
+ forceOrdered: Boolean,
68
+ /**
69
+ * Define the start value for <ol>
70
+ */
71
+ start: String,
72
+ /**
73
+ * Reverse ordered list
74
+ */
75
+ reversed: Boolean,
76
+ /**
77
+ * Define list style type (ie. disc, decimal, etc)
78
+ */
79
+ listStyleType: String,
80
+ });
81
+
82
+ const listElement = computed(() => {
83
+ return props.ordered || props.forceOrdered ? "ol" : "ul";
84
+ });
87
85
  </script>
@@ -1,25 +1,19 @@
1
1
  <template>
2
- <div class="spoke-spinner" :class="modifierClass">
2
+ <div
3
+ class="spoke-spinner"
4
+ :class="{ [`spoke-spinner--${ type }`] : type }"
5
+ >
3
6
  <div class="spoke-spinner__spinner">
4
- <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
7
+ <div v-for="n in 12" :key="n"></div>
5
8
  </div>
6
9
  </div>
7
10
  </template>
8
11
 
9
- <script>
10
- export default {
11
- name: "UluSpokeSpinner",
12
- props: {
13
- /**
14
- * Type modifier for spinner (ie match scss style name)
15
- */
16
- type: String
17
- },
18
- computed: {
19
- modifierClass() {
20
- const { type } = this;
21
- return type ? `spoke-spinner--${ type }` : null;
22
- }
23
- }
24
- };
12
+ <script setup>
13
+ const props = defineProps({
14
+ /**
15
+ * Type modifier for spinner (ie match scss style name)
16
+ */
17
+ type: String
18
+ });
25
19
  </script>
@@ -3,51 +3,51 @@
3
3
  class="tag"
4
4
  :class="[
5
5
  {
6
- 'tag--small' : small,
7
- 'type-small' : small,
6
+ 'tag--counter' : counter,
7
+ [`tag--${ size }`] : size,
8
8
  [`tag--${ type }`] : type
9
9
  },
10
10
  resolvedModifiers
11
11
  ]"
12
12
  >
13
- <UluIcon v-if="icon" :icon="icon" />
13
+ <UluIcon v-if="icon" :icon="icon" spaced />
14
14
  <slot>
15
- {{ text }}
15
+ <span>{{ text }}</span>
16
16
  </slot>
17
17
  </span>
18
18
  </template>
19
19
 
20
- <script>
20
+ <script setup>
21
21
  import UluIcon from "./UluIcon.vue";
22
22
  import { useModifiers } from "../../composables/useModifiers.js";
23
- export default {
24
- name: "UluTag",
25
- components: {
26
- UluIcon
27
- },
28
- props: {
29
- type: [String],
30
- /**
31
- * Preset to set small modifier and small type size
32
- */
33
- small: Boolean,
34
- /**
35
- * Text for tag, or use slot
36
- */
37
- text: [String, Number],
38
- /**
39
- * Icon prop, if used will set the icon for the button, will use UluIcon (which uses font-awesome icons conditionally)
40
- * - If using custom icons use slot instead
41
- */
42
- icon: [String, Array],
43
- /**
44
- * Modifiers for tag class
45
- */
46
- modifiers: [String, Array]
47
- },
48
- setup(props) {
49
- const { resolvedModifiers } = useModifiers({ props, baseClass: "tag" });
50
- return { resolvedModifiers };
51
- }
52
- };
23
+
24
+ const props = defineProps({
25
+ /**
26
+ * Type (corresponds with styles setup for tag in scss module)
27
+ */
28
+ type: [String],
29
+ /**
30
+ * Size (corresponds with sizes setup for tag in scss module)
31
+ */
32
+ size: String,
33
+ /**
34
+ * Use counter style (for numbers, etc)
35
+ */
36
+ counter: Boolean,
37
+ /**
38
+ * Text for tag, or use slot
39
+ */
40
+ text: [String, Number],
41
+ /**
42
+ * Icon prop, if used will set the icon for the button, will use UluIcon (which uses font-awesome icons conditionally)
43
+ * - If using custom icons use slot instead
44
+ */
45
+ icon: [String, Array],
46
+ /**
47
+ * Modifiers for tag class
48
+ */
49
+ modifiers: [String, Array]
50
+ });
51
+
52
+ const { resolvedModifiers } = useModifiers({ props, baseClass: "tag" });
53
53
  </script>
@@ -1,39 +1,57 @@
1
1
  <template>
2
2
  <a class="layout-flex-baseline" :href="fileUrl" :download="file.name">
3
- <FaIcon class="ui-icon" :icon="['far', $site.getIcon('file')]"/>
4
- <span class="margin-left-small-x">
5
- {{ file.name }}
6
- <span class="tag tag--small tag--outline type-small-x">{{ fileSize }}</span>
7
- </span>
3
+ <slot :fileName="file.name" :fileSize="fileSize">
4
+ <UluIcon class="ui-icon" :icon="icon"/>
5
+ <span class="margin-left-small-x">
6
+ {{ file.name }}
7
+ <UluTag v-if="!noFileSize" :text="fileSize" small outline />
8
+ </span>
9
+ </slot>
8
10
  </a>
9
11
  </template>
10
12
 
11
- <script>
12
- export default {
13
- name: "FileDisplay",
14
- props: {
15
- file: {
16
- required: true,
17
- type: Object
18
- }
13
+ <script setup>
14
+ import { computed } from "vue";
15
+ import UluIcon from "../elements/UluIcon.vue";
16
+ import UluTag from "../elements/UluTag.vue";
17
+
18
+ const props = defineProps({
19
+ /**
20
+ * The File object to be displayed.
21
+ */
22
+ file: {
23
+ required: true,
24
+ type: Object,
19
25
  },
20
- computed: {
21
- fileUrl() {
22
- return window.URL.createObjectURL(this.file);
23
- },
24
- fileSize() {
25
- const { size } = this.file;
26
- const Mbs = size / 1000000;
27
- const Kbs = size / 1000;
28
- const format = n => parseFloat(n.toFixed(2));
29
- // Either display Mbs or Kbs if less than 1 Mb
30
- /* eslint-disable */
31
- return Mbs > 1 ?
32
- `${ format(Mbs) }Mb` : Kbs > 1 ?
33
- `${ format(Kbs) }Kb` :
34
- `${ format(size) }B`;
35
- /* eslint-enable */
36
- }
26
+ /**
27
+ * The icon to display next to the file name.
28
+ */
29
+ icon: {
30
+ type: String,
31
+ default: "type:file"
37
32
  },
38
- };
33
+ /**
34
+ * If true, the file size will not be displayed.
35
+ */
36
+ noFileSize: Boolean
37
+ });
38
+
39
+ const fileUrl = computed(() => {
40
+ if (typeof window === 'undefined') return '';
41
+ return window.URL.createObjectURL(props.file);
42
+ });
43
+
44
+ const fileSize = computed(() => {
45
+ const { size } = props.file;
46
+ const Mbs = size / 1000000;
47
+ const Kbs = size / 1000;
48
+ const format = n => parseFloat(n.toFixed(2));
49
+ // Either display Mbs or Kbs if less than 1 Mb
50
+ /* eslint-disable */
51
+ return Mbs > 1 ?
52
+ `${ format(Mbs) }Mb` : Kbs > 1 ?
53
+ `${ format(Kbs) }Kb` :
54
+ `${ format(size) }B`;
55
+ /* eslint-enable */
56
+ });
39
57
  </script>
@@ -18,30 +18,43 @@
18
18
  </div>
19
19
  </template>
20
20
 
21
- <script>
22
- let count = 0;
23
- export default {
24
- name: "FormFile",
25
- props: {
26
- label: {
27
- type: String,
28
- default: "Select File"
29
- },
30
- labelHidden: Boolean,
31
- noClasses: Boolean,
32
- multiple: Boolean,
33
- inputAttrs: Object
34
- },
35
- emits: ["filesChange"],
36
- data() {
37
- return {
38
- id: `file-input-id-${ ++count }`
39
- };
21
+ <script setup>
22
+ const getNextId = (() => {
23
+ let count = 0;
24
+ return () => `file-input-id-${++count}`;
25
+ })();
26
+
27
+ defineProps({
28
+ /**
29
+ * The label for the file input.
30
+ */
31
+ label: {
32
+ type: String,
33
+ default: "Select File"
40
34
  },
41
- methods: {
42
- onChangeFile(event) {
43
- this.$emit("filesChange", event.target.files);
44
- }
45
- }
35
+ /**
36
+ * If true, the label will be visually hidden.
37
+ */
38
+ labelHidden: Boolean,
39
+ /**
40
+ * If true, default classes will not be applied.
41
+ */
42
+ noClasses: Boolean,
43
+ /**
44
+ * If true, allows multiple file selection.
45
+ */
46
+ multiple: Boolean,
47
+ /**
48
+ * Additional attributes to bind to the input element.
49
+ */
50
+ inputAttrs: Object
51
+ });
52
+
53
+ const emit = defineEmits(["file-change"]);
54
+
55
+ const id = getNextId();
56
+
57
+ const onChangeFile = (event) => {
58
+ emit("file-change", event.target.files);
46
59
  };
47
60
  </script>
@@ -3,18 +3,21 @@
3
3
  'site-form__error' : error,
4
4
  'site-form__warning' : warning
5
5
  }">
6
- <FaIcon v-if="error" :icon="$site.getIcon('error')"/>
7
- <FaIcon v-if="warning" :icon="$site.getIcon('warning')"/>
6
+ <UluIcon v-if="error || warning" :icon="`type:${ error ? 'error' : 'warning' }`" />
8
7
  <slot/>
9
8
  </p>
10
9
  </template>
11
10
 
12
- <script>
13
- export default {
14
- name: "FormMessage",
15
- props: {
16
- warning: Boolean,
17
- error: Boolean,
18
- }
19
- };
11
+ <script setup>
12
+ import UluIcon from "../elements/UluIcon.vue";
13
+ defineProps({
14
+ /**
15
+ * If true, the message will be styled as a warning.
16
+ */
17
+ warning: Boolean,
18
+ /**
19
+ * If true, the message will be styled as an error.
20
+ */
21
+ error: Boolean,
22
+ });
20
23
  </script>
@@ -18,20 +18,32 @@
18
18
  </div>
19
19
  </template>
20
20
 
21
- <script>
22
- let count = 0;
23
- export default {
24
- name: "FormSelect",
25
- props: {
26
- label: String,
27
- modelValue: String,
28
- options: Array,
29
- labelHidden: Boolean
30
- },
31
- data() {
32
- return {
33
- id: `select-id-${ ++count }`
34
- };
35
- }
36
- };
21
+ <script setup>
22
+ const getNextId = (() => {
23
+ let count = 0;
24
+ return () => `select-id-${++count}`;
25
+ })();
26
+
27
+ defineProps({
28
+ /**
29
+ * The label for the select input.
30
+ */
31
+ label: String,
32
+ /**
33
+ * The value of the select input (for v-model).
34
+ */
35
+ modelValue: String,
36
+ /**
37
+ * An array of options for the select input. Each option should be an object with `value` and `text` properties.
38
+ */
39
+ options: Array,
40
+ /**
41
+ * If true, the label will be visually hidden.
42
+ */
43
+ labelHidden: Boolean
44
+ });
45
+
46
+ defineEmits(['update:modelValue']);
47
+
48
+ const id = getNextId();
37
49
  </script>
@@ -14,19 +14,28 @@
14
14
  </div>
15
15
  </template>
16
16
 
17
- <script>
18
- let count = 0;
19
- export default {
20
- name: "FormText",
21
- props: {
22
- label: String,
23
- modelValue: String,
24
- labelHidden: Boolean
25
- },
26
- data() {
27
- return {
28
- id: `text-input-id-${ ++count }`
29
- };
30
- }
31
- };
17
+ <script setup>
18
+ const getNextId = (() => {
19
+ let count = 0;
20
+ return () => `text-input-id-${++count}`;
21
+ })();
22
+
23
+ defineProps({
24
+ /**
25
+ * The label for the text input.
26
+ */
27
+ label: String,
28
+ /**
29
+ * The value of the text input (for v-model).
30
+ */
31
+ modelValue: String,
32
+ /**
33
+ * If true, the label will be visually hidden.
34
+ */
35
+ labelHidden: Boolean
36
+ });
37
+
38
+ defineEmits(['update:modelValue']);
39
+
40
+ const id = getNextId();
32
41
  </script>