@ulu/frontend-vue 0.1.0-beta.1

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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/dist/breakpoints-ClT9bfZm.js +211 -0
  4. package/dist/frontend-vue.css +1 -0
  5. package/dist/frontend-vue.js +82 -0
  6. package/dist/frontend-vue.umd.cjs +561 -0
  7. package/dist/index-P5Rwl_Dl.js +7263 -0
  8. package/dist/index.es-HlG3u0J5.js +3134 -0
  9. package/lib/_index.scss +14 -0
  10. package/lib/components/_index.scss +6 -0
  11. package/lib/components/collapsible/UluAccordion.vue +82 -0
  12. package/lib/components/collapsible/UluCollapsibleRegion.vue +278 -0
  13. package/lib/components/collapsible/UluDropdown.vue +42 -0
  14. package/lib/components/collapsible/UluModal.vue +384 -0
  15. package/lib/components/collapsible/UluOverflowPopover.vue +52 -0
  16. package/lib/components/collapsible/UluTab.vue +9 -0
  17. package/lib/components/collapsible/UluTabGroup.vue +31 -0
  18. package/lib/components/collapsible/UluTabList.vue +9 -0
  19. package/lib/components/collapsible/UluTabPanel.vue +9 -0
  20. package/lib/components/collapsible/UluTabPanels.vue +9 -0
  21. package/lib/components/elements/UluAlert.vue +81 -0
  22. package/lib/components/elements/UluBadge.vue +58 -0
  23. package/lib/components/elements/UluBadgeStack.vue +27 -0
  24. package/lib/components/elements/UluButton.vue +161 -0
  25. package/lib/components/elements/UluCallout.vue +30 -0
  26. package/lib/components/elements/UluCard.vue +241 -0
  27. package/lib/components/elements/UluDefinitionList.vue +40 -0
  28. package/lib/components/elements/UluExternalLink.vue +47 -0
  29. package/lib/components/elements/UluIcon.vue +108 -0
  30. package/lib/components/elements/UluList.vue +87 -0
  31. package/lib/components/elements/UluMain.vue +5 -0
  32. package/lib/components/elements/UluSpokeSpinner.vue +25 -0
  33. package/lib/components/elements/UluTag.vue +53 -0
  34. package/lib/components/forms/UluCheckboxMenu.vue +36 -0
  35. package/lib/components/forms/UluFileDisplay.vue +39 -0
  36. package/lib/components/forms/UluFormDropzone.vue +62 -0
  37. package/lib/components/forms/UluFormFile.vue +47 -0
  38. package/lib/components/forms/UluFormMessage.vue +20 -0
  39. package/lib/components/forms/UluFormSelect.vue +37 -0
  40. package/lib/components/forms/UluFormText.vue +32 -0
  41. package/lib/components/forms/UluSearchForm.vue +31 -0
  42. package/lib/components/index.js +54 -0
  43. package/lib/components/layout/UluAdaptiveLayout.vue +11 -0
  44. package/lib/components/layout/UluDataGrid.vue +41 -0
  45. package/lib/components/layout/UluTitleRail.vue +56 -0
  46. package/lib/components/layout/UluWhenBreakpoint.vue +86 -0
  47. package/lib/components/navigation/UluBreadcrumb.vue +72 -0
  48. package/lib/components/navigation/UluMenu.vue +105 -0
  49. package/lib/components/navigation/UluMenuStack.vue +49 -0
  50. package/lib/components/navigation/UluNavStrip.vue +48 -0
  51. package/lib/components/navigation/UluSkipLink.vue +5 -0
  52. package/lib/components/systems/facets/UluFacets.vue +380 -0
  53. package/lib/components/systems/facets/UluFacetsList.vue +39 -0
  54. package/lib/components/systems/facets/UluFacetsSearch.vue +67 -0
  55. package/lib/components/systems/facets/_facets.scss +64 -0
  56. package/lib/components/systems/index.js +17 -0
  57. package/lib/components/systems/scroll-anchors/UluScrollAnchors.vue +152 -0
  58. package/lib/components/systems/scroll-anchors/UluScrollAnchorsNav.vue +37 -0
  59. package/lib/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue +124 -0
  60. package/lib/components/systems/scroll-anchors/UluScrollAnchorsSection.vue +63 -0
  61. package/lib/components/systems/scroll-anchors/symbols.js +6 -0
  62. package/lib/components/systems/skeleton/UluShowSkeleton.vue +13 -0
  63. package/lib/components/systems/skeleton/UluSkeletonContent.vue +60 -0
  64. package/lib/components/systems/skeleton/UluSkeletonMedia.vue +11 -0
  65. package/lib/components/systems/skeleton/UluSkeletonTextInline.vue +9 -0
  66. package/lib/components/systems/slider/UluImageSlideShow.vue +75 -0
  67. package/lib/components/systems/slider/UluSlideShow.vue +331 -0
  68. package/lib/components/systems/slider/UluSlideShowSlide.vue +25 -0
  69. package/lib/components/systems/table-sticky/UluTableSticky.vue +793 -0
  70. package/lib/components/systems/table-sticky/UluTableStickyRows.vue +73 -0
  71. package/lib/components/systems/table-sticky/UluTableStickyTable.vue +237 -0
  72. package/lib/components/systems/table-sticky/_table-sticky.scss +185 -0
  73. package/lib/components/utils/UluCondText.vue +28 -0
  74. package/lib/components/utils/UluEmpty.vue +3 -0
  75. package/lib/components/utils/UluEmptyView.vue +3 -0
  76. package/lib/components/utils/UluPlaceholderImage.vue +53 -0
  77. package/lib/components/utils/UluPlaceholderText.vue +25 -0
  78. package/lib/components/utils/UluRouteAnnouncer.vue +83 -0
  79. package/lib/components/visualizations/UluAnimateNumber.vue +32 -0
  80. package/lib/components/visualizations/UluProgressBar.vue +94 -0
  81. package/lib/components/visualizations/UluProgressDonut.vue +97 -0
  82. package/lib/composables/index.js +10 -0
  83. package/lib/composables/useBreakpointManager.js +68 -0
  84. package/lib/composables/useIcon.js +62 -0
  85. package/lib/composables/useModifiers.js +93 -0
  86. package/lib/composables/useWindowResize.js +64 -0
  87. package/lib/index.js +10 -0
  88. package/lib/plugins/_index.scss +7 -0
  89. package/lib/plugins/breakpoints/index.js +47 -0
  90. package/lib/plugins/index.js +11 -0
  91. package/lib/plugins/modals/UluModalsDisplay.vue +59 -0
  92. package/lib/plugins/modals/api.js +76 -0
  93. package/lib/plugins/modals/index.js +60 -0
  94. package/lib/plugins/modals/useModals.js +9 -0
  95. package/lib/plugins/popovers/UluPopover.vue +189 -0
  96. package/lib/plugins/popovers/UluTooltipDisplay.vue +15 -0
  97. package/lib/plugins/popovers/UluTooltipPopover.vue +83 -0
  98. package/lib/plugins/popovers/defaults.js +108 -0
  99. package/lib/plugins/popovers/directive.js +95 -0
  100. package/lib/plugins/popovers/index.js +18 -0
  101. package/lib/plugins/popovers/manager.js +54 -0
  102. package/lib/plugins/popovers/useFollow.js +80 -0
  103. package/lib/plugins/popovers/utils.js +5 -0
  104. package/lib/plugins/toast/UluToast.vue +87 -0
  105. package/lib/plugins/toast/UluToastDisplay.vue +35 -0
  106. package/lib/plugins/toast/_toast.scss +198 -0
  107. package/lib/plugins/toast/defaults.js +30 -0
  108. package/lib/plugins/toast/index.js +17 -0
  109. package/lib/plugins/toast/store.js +71 -0
  110. package/lib/plugins/toast/useToast.js +18 -0
  111. package/lib/settings.js +119 -0
  112. package/lib/utils/dom.js +14 -0
  113. package/lib/utils/placeholder.js +6 -0
  114. package/lib/utils/vue-router.js +219 -0
  115. package/package.json +75 -0
@@ -0,0 +1,161 @@
1
+ <template>
2
+ <component
3
+ :is="element"
4
+ class="button"
5
+ :class="[
6
+ {
7
+ 'button--transparent' : transparent,
8
+ 'button--primary' : primary,
9
+ 'button--secondary' : secondary,
10
+ 'button--outline' : outline,
11
+ 'button--small' : small,
12
+ 'button--large' : large,
13
+ 'button--icon' : iconOnly,
14
+ 'no-margin' : noMargin,
15
+ },
16
+ classes,
17
+ resolvedModifiers
18
+ ]"
19
+ v-bind="attrs"
20
+ :aria-label="resolvedAriaLabel"
21
+ >
22
+ <slot name="before"/>
23
+ <UluIcon
24
+ v-if="icon && (iconBefore || iconOnly)"
25
+ :definition="icon"
26
+ class="button__icon"
27
+ />
28
+ <span v-if="($slots.default || text) && !iconOnly">
29
+ <slot>
30
+ {{ text }}
31
+ </slot>
32
+ </span>
33
+ <UluIcon
34
+ v-if="icon && (!iconBefore && !iconOnly)"
35
+ :definition="icon"
36
+ class="button__icon"
37
+ />
38
+ <slot name="after"/>
39
+ </component>
40
+ </template>
41
+
42
+ <script>
43
+ import { RouterLink } from "vue-router";
44
+ import UluIcon from "./UluIcon.vue";
45
+ import { useModifiers } from "../../composables/useModifiers.js";
46
+ export default {
47
+ name: "UluButton",
48
+ components: {
49
+ UluIcon
50
+ },
51
+ props: {
52
+ /**
53
+ * Icon prop, if used will set the icon for the button, will use UluIcon (which uses font-awesome icons conditionally)
54
+ * - If using custom icons don't use this prop, use before or after slots with correct classes (ie .button__icon)
55
+ */
56
+ icon: [String, Array],
57
+ /**
58
+ * If passing an icon (and not using iconOnly) this determines if the icon is before or after (default) the text
59
+ */
60
+ iconBefore: Boolean,
61
+ /**
62
+ * Button style for only icon
63
+ */
64
+ iconOnly: Boolean,
65
+ /**
66
+ * If set will use router-link for button component and pass to prop
67
+ */
68
+ to: [String, Object],
69
+ /**
70
+ * Sets the button to a link with this href
71
+ */
72
+ href: String,
73
+ /**
74
+ * Set a value for target attribute when button is a link
75
+ */
76
+ target: String,
77
+ /**
78
+ * Sets the download attribute on the link (passing string [filename] will populate the download attribute, true will just include it as boolean attribute)
79
+ */
80
+ download: [Boolean, String],
81
+ /**
82
+ * For icon only buttons or buttons that need an explicit label
83
+ */
84
+ alt: String,
85
+ /**
86
+ * If not using slot this sets the buttons text via prop
87
+ */
88
+ text: String,
89
+ /**
90
+ * Pass any sizes setup for button (ie. small, large, etc)
91
+ */
92
+ size: String,
93
+ /**
94
+ * Preset to set primary style (needs to be a button style in ulu scss)
95
+ */
96
+ primary: Boolean,
97
+ /**
98
+ * Preset to set secondary style (needs to be a button style in ulu scss)
99
+ */
100
+ secondary: Boolean,
101
+ /**
102
+ * Preset to set small size (use "size" for any sizes)
103
+ */
104
+ small: Boolean,
105
+ /**
106
+ * Preset to set large size (use "size" for any sizes)
107
+ */
108
+ large: Boolean,
109
+ /**
110
+ * Preset to set outline style button (needs to be a button style in ulu scss)
111
+ */
112
+ outline: Boolean,
113
+ /**
114
+ * Preset to set transparent style button (needs to be a button style in ulu scss)
115
+ */
116
+ transparent: Boolean,
117
+ /**
118
+ * Add no-margin utility
119
+ */
120
+ noMargin: Boolean,
121
+ /**
122
+ * Modifiers (to add any modifier classes based on base class [ie. 'tertiary'])
123
+ */
124
+ modifiers: [String, Array]
125
+ },
126
+ setup(props) {
127
+ const { resolvedModifiers } = useModifiers({ props, baseClass: "button" });
128
+ return { resolvedModifiers };
129
+ },
130
+ computed: {
131
+ resolvedAriaLabel() {
132
+ const label = this.alt || this.iconOnly && this.text;
133
+ return label ? label : null;
134
+ },
135
+ classes() {
136
+ const classes = [];
137
+ const { size } = this;
138
+ if (size) {
139
+ classes.push(`button--${ size }`);
140
+ }
141
+ return classes;
142
+ },
143
+ element() {
144
+ return this.to ? RouterLink : this.href ? "a" : "button";
145
+ },
146
+ attrs() {
147
+ const { to, href, download, target } = this;
148
+ const attrs = to ? { to } : href ? { href } : {};
149
+ if (href) {
150
+ if (target) {
151
+ attrs.target = target;
152
+ }
153
+ if (download) {
154
+ attrs.download = typeof download === "string" ? download : true;
155
+ }
156
+ }
157
+ return attrs;
158
+ }
159
+ }
160
+ };
161
+ </script>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <div
3
+ class="callout"
4
+ :class="[resolvedModifiers, { 'full-height' : fullHeight }]"
5
+ >
6
+ <slot/>
7
+ </div>
8
+ </template>
9
+
10
+ <script>
11
+ import { useModifiers } from "../../composables/useModifiers.js";
12
+ export default {
13
+ name: "UluCallout",
14
+ props: {
15
+ /**
16
+ * Add full height utility class
17
+ */
18
+ fullHeight: Boolean,
19
+ /**
20
+ * Class modifiers (ie. 'transparent', 'secondary', etc)
21
+ * - Can be String or Array of Strings
22
+ */
23
+ modifiers: [String, Array]
24
+ },
25
+ setup(props) {
26
+ const { resolvedModifiers } = useModifiers({ props, baseClass: "callout" });
27
+ return { resolvedModifiers };
28
+ }
29
+ };
30
+ </script>
@@ -0,0 +1,241 @@
1
+ <template>
2
+ <component
3
+ class="card"
4
+ :is="resolvedElement"
5
+ @mousedown="onMousedown"
6
+ @mouseup="onMouseup"
7
+ :class="[
8
+ {
9
+ 'card--horizontal' : horizontal || horizontalCenter,
10
+ 'card--horizontal-center' : horizontalCenter,
11
+ 'card--overlay' : overlay,
12
+ },
13
+ resolvedModifiers
14
+ ]"
15
+ :style="{ cursor: cursorStyle }"
16
+ :target="target"
17
+ :to="to"
18
+ :href="href"
19
+ :data-ulu-proxy-click-init="proxyClickEnabled"
20
+ >
21
+ <div class="card__body">
22
+ <div class="card__main">
23
+ <component
24
+ :is="titleElement"
25
+ class="card__title"
26
+ :class="classes.title"
27
+ >
28
+ <router-link
29
+ v-if="titleTo"
30
+ class="card__title-link"
31
+ :to="titleTo"
32
+ ref="link"
33
+ >
34
+ <slot name="title">
35
+ {{ title }}
36
+ </slot>
37
+ </router-link>
38
+ <a
39
+ v-else-if="titleHref"
40
+ class="card__title-link"
41
+ :href="titleHref"
42
+ :target="titleTarget"
43
+ ref="link"
44
+ >
45
+ <slot name="title">
46
+ {{ title }}
47
+ </slot>
48
+ </a>
49
+ <template v-else>
50
+ <slot name="title">
51
+ {{ title }}
52
+ </slot>
53
+ </template>
54
+ </component>
55
+ <slot name="body"/>
56
+ </div>
57
+ <div class="card__aside" v-if="$slots.body">
58
+ <slot name="aside"/>
59
+ </div>
60
+ </div>
61
+ <div
62
+ v-if="$slots.image || imageSrc"
63
+ class="card__image"
64
+ :class="[
65
+ { 'card__image--icon' : imageIcon },
66
+ classes.image
67
+ ]"
68
+ >
69
+ <slot name="image">
70
+ <img :src="imageSrc" :alt="imageAlt">
71
+ </slot>
72
+ </div>
73
+ <div class="card__footer" v-if="$slots.footer">
74
+ <slot name="footer"/>
75
+ </div>
76
+ </component>
77
+ </template>
78
+
79
+ <script>
80
+ import { RouterLink } from "vue-router";
81
+ import { useModifiers } from "../../composables/useModifiers.js";
82
+ const titleLinkValidator = (_, props) => {
83
+ const valid = !(props.to || props.href);
84
+ if (!valid) {
85
+ console.warn("'titleHref' and 'titleTo' can't be used with to or href (nesting links)");
86
+ }
87
+ return valid;
88
+ };
89
+ export default {
90
+ name: "UluCard",
91
+ props: {
92
+ /**
93
+ * Specify card element, unless to or href are used which will use 'a' or 'router-link'
94
+ * - Other than changing to more appropriate element (ie 'li' if in list for example), this can
95
+ * be used to set the card to a button to attach your own click handlers to
96
+ */
97
+ cardElement: {
98
+ type: String,
99
+ default: "article"
100
+ },
101
+ /**
102
+ * Text for title if not using slot
103
+ */
104
+ title: String,
105
+ /**
106
+ * Element to use for title
107
+ */
108
+ titleElement: {
109
+ type: String,
110
+ default: "h3"
111
+ },
112
+ /**
113
+ * Title will be router link
114
+ */
115
+ titleTo: {
116
+ type: [String, Object],
117
+ validator: titleLinkValidator
118
+ },
119
+ /**
120
+ * Will make title a link to href
121
+ */
122
+ titleHref: {
123
+ type: String,
124
+ validator: titleLinkValidator
125
+ },
126
+ /**
127
+ * When using href this will set title link's target attribute
128
+ */
129
+ titleTarget: String,
130
+ /**
131
+ * If set the entire card will be router link
132
+ * - Do not us in combination with titleTo or titleHref
133
+ */
134
+ to: [String, Object],
135
+ /**
136
+ * If set the entire card will be a link to href
137
+ * - Do not us in combination with titleTo or titleHref
138
+ */
139
+ href: {
140
+ type: String,
141
+
142
+ },
143
+ /**
144
+ * When using href this will set link's target attribute
145
+ */
146
+ target: String,
147
+ /**
148
+ * Classes with class bindings for different elements including ({ title, image })
149
+ */
150
+ classes: {
151
+ type: Object,
152
+ default: () => ({})
153
+ },
154
+ /**
155
+ * Whether to proxy clicks of non-interactive elements (making whole card clickable)
156
+ */
157
+ proxyClick: Boolean,
158
+ /**
159
+ * Options to be merged for proxy click settings ({ preventSelector, preventSelectionDuration })
160
+ */
161
+ proxyClickOptions: {
162
+ type: Object,
163
+ default: () => ({})
164
+ },
165
+ /**
166
+ * Source of image
167
+ */
168
+ imageSrc: String,
169
+ /**
170
+ * Alt text for image
171
+ */
172
+ imageAlt: String,
173
+ /**
174
+ * If true image will use icon modifier (displays for image adjusts for icon vs full image)
175
+ */
176
+ imageIcon: Boolean,
177
+ /**
178
+ * Horizontal card layout
179
+ */
180
+ horizontal: Boolean,
181
+ /**
182
+ * Horizontal centered card layout
183
+ */
184
+ horizontalCenter: Boolean,
185
+ /**
186
+ * Overlay card layout
187
+ */
188
+ overlay: Boolean,
189
+ /**
190
+ * Class modifiers (ie. 'transparent', 'secondary', etc)
191
+ * - Can be String or Array of Strings
192
+ */
193
+ modifiers: [Array, String]
194
+ },
195
+ data() {
196
+ const { proxyClickOptions, proxyClick, titleHref, titleTo } = this;
197
+ return {
198
+ proxyClickEnabled: (proxyClick && (titleHref || titleTo)) || null,
199
+ resolvedProxyOptions: {
200
+ selectorPrevent: "input, select, textarea, button, a, [tabindex='-1']",
201
+ mousedownDurationPrevent: 250,
202
+ ...proxyClickOptions
203
+ },
204
+ cursorStyle: null,
205
+ proxyStart: null,
206
+ shouldProxy: false
207
+ }
208
+ },
209
+ setup(props) {
210
+ const { resolvedModifiers } = useModifiers({ props, baseClass: "card" });
211
+ return { resolvedModifiers };
212
+ },
213
+ computed: {
214
+ resolvedElement() {
215
+ const { cardElement, to, href } = this;
216
+ return to ? RouterLink : href ? 'a' : cardElement;
217
+ }
218
+ },
219
+ methods: {
220
+ onMousedown({ target, timeStamp }) {
221
+ if (!this.proxyClickEnabled) return;
222
+ const { resolvedProxyOptions } = this;
223
+ const { selectorPrevent } = resolvedProxyOptions;
224
+ this.shouldProxy = false;
225
+ if (!target.matches(selectorPrevent)) {
226
+ this.shouldProxy = true;
227
+ this.proxyStart = timeStamp;
228
+ }
229
+ },
230
+ onMouseup({ timeStamp }) {
231
+ if (!this.proxyClickEnabled) return;
232
+ const { link } = this.$refs;
233
+ const { resolvedProxyOptions } = this;
234
+ const { mousedownDurationPrevent } = resolvedProxyOptions;
235
+ if (this.shouldProxy && timeStamp - this.proxyStart < mousedownDurationPrevent) {
236
+ link.click();
237
+ }
238
+ },
239
+ }
240
+ };
241
+ </script>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <dl :class="classes.list">
3
+ <div
4
+ v-for="(item, index) in items"
5
+ :key="index"
6
+ :class="classes.item"
7
+ >
8
+ <dt :class="classes.term">
9
+ <slot name="term" :item="item" :index="index">
10
+ {{ item.term }}
11
+ </slot>
12
+ </dt>
13
+ <dd :class="classes.description">
14
+ <slot name="description" :item="item" :index="index">
15
+ {{ item.description }}
16
+ </slot>
17
+ </dd>
18
+ </div>
19
+ </dl>
20
+ </template>
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
+ }
38
+ }
39
+ };
40
+ </script>
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <a class="external-link" :href="href" :target="target">
3
+ <span class="external-link__text">
4
+ <slot>{{ text }}</slot>
5
+ </span>
6
+ <UluIcon
7
+ class="external-link__icon margin-left-small-x display-inline"
8
+ type="externalLink"
9
+ :definition="icon"
10
+ />
11
+ </a>
12
+ </template>
13
+
14
+ <script>
15
+ import UluIcon from "./UluIcon.vue";
16
+
17
+ /**
18
+ * Component for external links (adds icon after link text)
19
+ */
20
+ export default {
21
+ name: "UluExternalLink",
22
+ components: {
23
+ UluIcon
24
+ },
25
+ props: {
26
+ /**
27
+ * Text for link or use slot
28
+ */
29
+ text: String,
30
+ /**
31
+ * Link href
32
+ */
33
+ href: String,
34
+ /**
35
+ * Link target
36
+ */
37
+ target: {
38
+ type: String,
39
+ default: "_blank"
40
+ },
41
+ /**
42
+ * Override default icon
43
+ */
44
+ icon: String
45
+ }
46
+ };
47
+ </script>
@@ -0,0 +1,108 @@
1
+ <template>
2
+ <component
3
+ v-if="customIconComponent"
4
+ :is="customIconComponent"
5
+ v-bind="customIconProps"
6
+ />
7
+ <component
8
+ v-else-if="!useStaticFa && faIconComponent && resolvedDefinition"
9
+ :is="faIconComponent"
10
+ v-bind="iconProps"
11
+ />
12
+ <span
13
+ v-else-if="useStaticFa && resolvedDefinition"
14
+ :class="staticIconClasses"
15
+ aria-hidden="true"
16
+ ></span>
17
+ </template>
18
+
19
+ <script setup>
20
+ import { ref, defineAsyncComponent, markRaw, watchEffect, computed } from "vue";
21
+ import { useIcon } from "../../composables/useIcon.js";
22
+ import { getSetting, getIconByType } from "../../settings.js";
23
+
24
+ const faIconComponent = ref(null);
25
+ const { getIconProps, getClassesFromDefinition } = useIcon();
26
+
27
+ let FaModule;
28
+
29
+ const props = defineProps({
30
+ /**
31
+ * Semantic type of icon to use, will be resolved from settings
32
+ */
33
+ type: String,
34
+ /**
35
+ * Icon definition can be string (fa classes), or array or object (any prop format FaIcon accepts)
36
+ * - This will override the 'type' prop if both are provided
37
+ */
38
+ definition: [String, Array, Object, Boolean],
39
+ });
40
+
41
+ const useStaticFa = computed(() => {
42
+ return getSetting("fontAwesomeStatic");
43
+ });
44
+
45
+ const customIconComponent = computed(() => {
46
+ return getSetting("iconComponent");
47
+ });
48
+
49
+ const iconPropResolver = computed(() => {
50
+ return getSetting("iconPropResolver");
51
+ });
52
+
53
+ // Resolve the final icon definition, giving precedence to the `definition` prop
54
+ const resolvedDefinition = computed(() => {
55
+ if (props.definition) {
56
+ return props.definition;
57
+ }
58
+ if (props.type) {
59
+ try {
60
+ return getIconByType(props.type);
61
+ } catch (e) {
62
+ console.warn(e);
63
+ return null;
64
+ }
65
+ }
66
+ return null;
67
+ });
68
+
69
+ const customIconProps = computed(() => {
70
+ if (!customIconComponent.value || !resolvedDefinition.value) return null;
71
+ return iconPropResolver.value(resolvedDefinition.value);
72
+ });
73
+
74
+ // This is now a computed property for component props
75
+ const iconProps = computed(() => {
76
+ return getIconProps(resolvedDefinition.value);
77
+ });
78
+
79
+ // Computed property for static icon classes, using the utility method
80
+ const staticIconClasses = computed(() => {
81
+ return getClassesFromDefinition(resolvedDefinition.value);
82
+ });
83
+
84
+ // Watch for changes to prop
85
+ // - Use watchEffect because we are watching reactive object property access (props)
86
+ // - Load FA if needed (so it's not included if it's unneeded)
87
+ // - Replace the empty component after load or if value changes
88
+ watchEffect(async () => {
89
+ // Only attempt to load the component if we are NOT using the static version
90
+ if (!useStaticFa.value && resolvedDefinition.value) {
91
+ if (faIconComponent.value === null) {
92
+ if (FaModule) {
93
+ faIconComponent.value = markRaw(FaModule.FontAwesomeIcon);
94
+ } else {
95
+ const componentPromise = defineAsyncComponent(async () => {
96
+ const module = await import("@fortawesome/vue-fontawesome");
97
+ FaModule = module;
98
+ return module.FontAwesomeIcon;
99
+ });
100
+ faIconComponent.value = markRaw(componentPromise);
101
+ }
102
+ }
103
+ } else {
104
+ // If using static FA or no definition, ensure component is null
105
+ faIconComponent.value = null;
106
+ }
107
+ });
108
+ </script>