@ulu/frontend-vue 0.1.1-beta.17 → 0.1.1-beta.19
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.
- package/dist/{breakpoints-DGRU8UaH.js → breakpoints-3ShTarRs.js} +1 -1
- package/dist/frontend-vue.js +1 -1
- package/dist/{index-XmLnxPpm.js → index-DD8opHUp.js} +1925 -1893
- package/lib/components/elements/UluCard.vue +171 -157
- package/lib/components/elements/UluDefinitionList.vue +55 -3
- package/lib/components/navigation/UluMenuStack.vue +2 -2
- package/package.json +3 -3
- package/types/components/elements/UluCard.vue.d.ts +58 -230
- package/types/components/elements/UluCard.vue.d.ts.map +1 -1
- package/types/components/elements/UluDefinitionList.vue.d.ts +18 -2
- package/types/components/elements/UluDefinitionList.vue.d.ts.map +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
:is="resolvedElement"
|
|
4
|
+
ref="cardRoot"
|
|
5
|
+
class="card"
|
|
5
6
|
@mousedown="onMousedown"
|
|
6
7
|
@mouseup="onMouseup"
|
|
7
8
|
:class="[
|
|
@@ -76,166 +77,179 @@
|
|
|
76
77
|
</component>
|
|
77
78
|
</template>
|
|
78
79
|
|
|
79
|
-
<script>
|
|
80
|
+
<script setup>
|
|
81
|
+
import { ref, computed, useSlots } from 'vue';
|
|
80
82
|
import { RouterLink } from "vue-router";
|
|
81
83
|
import { useModifiers } from "../../composables/useModifiers.js";
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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]
|
|
84
|
+
|
|
85
|
+
const props = defineProps({
|
|
86
|
+
/**
|
|
87
|
+
* Specify card element, unless to or href are used which will use 'a' or 'router-link'
|
|
88
|
+
* - Other than changing to more appropriate element (ie 'li' if in list for example), this can
|
|
89
|
+
* be used to set the card to a button to attach your own click handlers to
|
|
90
|
+
*/
|
|
91
|
+
cardElement: {
|
|
92
|
+
type: String,
|
|
93
|
+
default: "article"
|
|
194
94
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
proxyStart: null,
|
|
206
|
-
shouldProxy: false
|
|
207
|
-
}
|
|
95
|
+
/**
|
|
96
|
+
* Text for title if not using slot
|
|
97
|
+
*/
|
|
98
|
+
title: String,
|
|
99
|
+
/**
|
|
100
|
+
* Element to use for title
|
|
101
|
+
*/
|
|
102
|
+
titleElement: {
|
|
103
|
+
type: String,
|
|
104
|
+
default: "h3"
|
|
208
105
|
},
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Title will be router link
|
|
108
|
+
*/
|
|
109
|
+
titleTo: [String, Object],
|
|
110
|
+
/**
|
|
111
|
+
* Will make title a link to href
|
|
112
|
+
*/
|
|
113
|
+
titleHref: String,
|
|
114
|
+
/**
|
|
115
|
+
* When using href this will set title link's target attribute
|
|
116
|
+
*/
|
|
117
|
+
titleTarget: String,
|
|
118
|
+
/**
|
|
119
|
+
* If set the entire card will be router link
|
|
120
|
+
* - Do not us in combination with titleTo or titleHref
|
|
121
|
+
*/
|
|
122
|
+
to: [String, Object],
|
|
123
|
+
/**
|
|
124
|
+
* If set the entire card will be a link to href
|
|
125
|
+
* - Do not us in combination with titleTo or titleHref
|
|
126
|
+
*/
|
|
127
|
+
href: String,
|
|
128
|
+
/**
|
|
129
|
+
* When using href this will set link's target attribute
|
|
130
|
+
*/
|
|
131
|
+
target: String,
|
|
132
|
+
/**
|
|
133
|
+
* Classes with class bindings for different elements including ({ title, image })
|
|
134
|
+
*/
|
|
135
|
+
classes: {
|
|
136
|
+
type: Object,
|
|
137
|
+
default: () => ({})
|
|
212
138
|
},
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Whether to proxy clicks of non-interactive elements (making whole card clickable).
|
|
141
|
+
* This is for accessibility, allowing a non-link card to have a primary action.
|
|
142
|
+
* The proxy action is determined in the following order:
|
|
143
|
+
* 1. If the title has a link (`titleTo` or `titleHref`), it will proxy the click to the title's link.
|
|
144
|
+
* 2. If not, it will look for an element with the `data-ulu-card-proxy-target` attribute within the card's slots and click it.
|
|
145
|
+
* 3. If no proxy target is found, it will emit a `proxy-click` event.
|
|
146
|
+
* Note: This should not be used with the `to` or `href` props.
|
|
147
|
+
*/
|
|
148
|
+
proxyClick: Boolean,
|
|
149
|
+
/**
|
|
150
|
+
* Options to be merged for proxy click settings ({ preventSelector, preventSelectionDuration })
|
|
151
|
+
*/
|
|
152
|
+
proxyClickOptions: {
|
|
153
|
+
type: Object,
|
|
154
|
+
default: () => ({})
|
|
218
155
|
},
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Source of image
|
|
158
|
+
*/
|
|
159
|
+
imageSrc: String,
|
|
160
|
+
/**
|
|
161
|
+
* Alt text for image
|
|
162
|
+
*/
|
|
163
|
+
imageAlt: String,
|
|
164
|
+
/**
|
|
165
|
+
* If true image will use icon modifier (displays for image adjusts for icon vs full image)
|
|
166
|
+
*/
|
|
167
|
+
imageIcon: Boolean,
|
|
168
|
+
/**
|
|
169
|
+
* Horizontal card layout
|
|
170
|
+
*/
|
|
171
|
+
horizontal: Boolean,
|
|
172
|
+
/**
|
|
173
|
+
* Horizontal centered card layout
|
|
174
|
+
*/
|
|
175
|
+
horizontalCenter: Boolean,
|
|
176
|
+
/**
|
|
177
|
+
* Overlay card layout
|
|
178
|
+
*/
|
|
179
|
+
overlay: Boolean,
|
|
180
|
+
/**
|
|
181
|
+
* Class modifiers (ie. 'transparent', 'secondary', etc)
|
|
182
|
+
* - Can be String or Array of Strings
|
|
183
|
+
*/
|
|
184
|
+
modifiers: [Array, String]
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const emit = defineEmits(['proxy-click']);
|
|
188
|
+
const $slots = useSlots();
|
|
189
|
+
|
|
190
|
+
// --- Validation warnings
|
|
191
|
+
if (props.proxyClick && (props.to || props.href)) {
|
|
192
|
+
console.warn("UluCard: 'proxyClick' is ignored when 'to' or 'href' are present.");
|
|
193
|
+
}
|
|
194
|
+
if ((props.titleTo || props.titleHref) && (props.to || props.href)) {
|
|
195
|
+
console.warn("UluCard: 'titleTo'/'titleHref' should not be used with 'to'/'href'.");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// --- Template refs
|
|
199
|
+
const cardRoot = ref(null);
|
|
200
|
+
const link = ref(null);
|
|
201
|
+
|
|
202
|
+
// --- Composables
|
|
203
|
+
const { resolvedModifiers } = useModifiers({ props, baseClass: "card" });
|
|
204
|
+
|
|
205
|
+
// --- State
|
|
206
|
+
const proxyStart = ref(null);
|
|
207
|
+
const shouldProxy = ref(false);
|
|
208
|
+
|
|
209
|
+
// --- Computed properties
|
|
210
|
+
const isClickable = computed(() => props.proxyClick && !props.to && !props.href);
|
|
211
|
+
const isTitleProxy = computed(() => isClickable.value && (props.titleTo || props.titleHref));
|
|
212
|
+
const isEventProxy = computed(() => isClickable.value && !isTitleProxy.value);
|
|
213
|
+
const proxyClickEnabled = computed(() => isClickable.value || null);
|
|
214
|
+
|
|
215
|
+
const resolvedProxyOptions = computed(() => ({
|
|
216
|
+
selectorPrevent: "input, select, textarea, button, a, [tabindex='-1']",
|
|
217
|
+
mousedownDurationPrevent: 250,
|
|
218
|
+
...props.proxyClickOptions
|
|
219
|
+
}));
|
|
220
|
+
|
|
221
|
+
const cursorStyle = computed(() => isClickable.value ? 'pointer' : null);
|
|
222
|
+
|
|
223
|
+
const resolvedElement = computed(() => {
|
|
224
|
+
return props.to ? RouterLink : props.href ? 'a' : props.cardElement;
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// --- Methods
|
|
228
|
+
function onMousedown({ target, timeStamp }) {
|
|
229
|
+
if (!proxyClickEnabled.value) return;
|
|
230
|
+
const { selectorPrevent } = resolvedProxyOptions.value;
|
|
231
|
+
shouldProxy.value = false;
|
|
232
|
+
if (!target.closest(selectorPrevent)) {
|
|
233
|
+
shouldProxy.value = true;
|
|
234
|
+
proxyStart.value = timeStamp;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function onMouseup({ timeStamp }) {
|
|
239
|
+
if (!proxyClickEnabled.value || !shouldProxy.value) return;
|
|
240
|
+
const { mousedownDurationPrevent } = resolvedProxyOptions.value;
|
|
241
|
+
if (timeStamp - proxyStart.value < mousedownDurationPrevent) {
|
|
242
|
+
if (isTitleProxy.value) {
|
|
243
|
+
link.value?.click();
|
|
244
|
+
} else if (isEventProxy.value) {
|
|
245
|
+
const proxyTarget = cardRoot.value?.querySelector('[data-ulu-card-proxy-target]');
|
|
246
|
+
if (proxyTarget) {
|
|
247
|
+
proxyTarget.click();
|
|
248
|
+
} else {
|
|
249
|
+
emit('proxy-click');
|
|
237
250
|
}
|
|
238
|
-
}
|
|
251
|
+
}
|
|
239
252
|
}
|
|
240
|
-
|
|
241
|
-
|
|
253
|
+
shouldProxy.value = false;
|
|
254
|
+
}
|
|
255
|
+
</script>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<dl :class="classes.list">
|
|
2
|
+
<dl class="definition-list" :class="[resolvedModifiers, classes.list]">
|
|
3
3
|
<div
|
|
4
4
|
v-for="(item, index) in items"
|
|
5
5
|
:key="index"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
{{ item.term }}
|
|
11
11
|
</slot>
|
|
12
12
|
</dt>
|
|
13
|
+
|
|
13
14
|
<dd :class="classes.description">
|
|
14
15
|
<slot name="description" :item="item" :index="index">
|
|
15
16
|
{{ item.description }}
|
|
@@ -20,7 +21,10 @@
|
|
|
20
21
|
</template>
|
|
21
22
|
|
|
22
23
|
<script setup>
|
|
23
|
-
|
|
24
|
+
import { computed } from 'vue';
|
|
25
|
+
import { useModifiers } from "../../composables/useModifiers.js";
|
|
26
|
+
|
|
27
|
+
const props = defineProps({
|
|
24
28
|
/**
|
|
25
29
|
* Array of term, and description (props in object)
|
|
26
30
|
* - Can use slots also
|
|
@@ -32,6 +36,54 @@
|
|
|
32
36
|
classes: {
|
|
33
37
|
type: Object,
|
|
34
38
|
default: () => ({})
|
|
35
|
-
}
|
|
39
|
+
},
|
|
40
|
+
/**
|
|
41
|
+
* Class modifiers (ie. 'transparent', 'secondary', etc)
|
|
42
|
+
*/
|
|
43
|
+
modifiers: [String, Array],
|
|
44
|
+
/**
|
|
45
|
+
* Displays only the definition descriptions on the same line.
|
|
46
|
+
*/
|
|
47
|
+
inline: Boolean,
|
|
48
|
+
/**
|
|
49
|
+
* Displays both the definition term and its descriptions on the same line.
|
|
50
|
+
*/
|
|
51
|
+
inlineAll: Boolean,
|
|
52
|
+
/**
|
|
53
|
+
* Displays the list in a two-column grid on larger screens.
|
|
54
|
+
*/
|
|
55
|
+
table: Boolean,
|
|
56
|
+
/**
|
|
57
|
+
* Adds a rule between each item.
|
|
58
|
+
*/
|
|
59
|
+
separated: Boolean,
|
|
60
|
+
/**
|
|
61
|
+
* Adds a rule to the top of the first item.
|
|
62
|
+
*/
|
|
63
|
+
separatedFirst: Boolean,
|
|
64
|
+
/**
|
|
65
|
+
* Adds a rule to the bottom of the last item.
|
|
66
|
+
*/
|
|
67
|
+
separatedLast: Boolean,
|
|
68
|
+
/**
|
|
69
|
+
* Reduces the margin between items.
|
|
70
|
+
*/
|
|
71
|
+
compact: Boolean,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const internalModifiers = computed(() => ({
|
|
75
|
+
"inline" : props.inline,
|
|
76
|
+
"inline-all" : props.inlineAll,
|
|
77
|
+
"table" : props.table,
|
|
78
|
+
"separated" : props.separated,
|
|
79
|
+
"separated-first" : props.separatedFirst,
|
|
80
|
+
"separated-last" : props.separatedLast,
|
|
81
|
+
"compact" : props.compact,
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
const { resolvedModifiers } = useModifiers({
|
|
85
|
+
props,
|
|
86
|
+
internal: internalModifiers,
|
|
87
|
+
baseClass: "definition-list"
|
|
36
88
|
});
|
|
37
89
|
</script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ulu/frontend-vue",
|
|
3
|
-
"version": "0.1.1-beta.
|
|
3
|
+
"version": "0.1.1-beta.19",
|
|
4
4
|
"description": "A modular and tree-shakeable Vue 3 component library for the Ulu frontend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@formkit/auto-animate": "^0.9.0",
|
|
65
65
|
"@headlessui/vue": "^1.7.23",
|
|
66
|
-
"@ulu/frontend": "^0.1.0-beta.
|
|
66
|
+
"@ulu/frontend": "^0.1.0-beta.118",
|
|
67
67
|
"@unhead/vue": "^2.0.11",
|
|
68
68
|
"vue": "^3.5.17",
|
|
69
69
|
"vue-router": "^4.5.1"
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"@storybook/addon-essentials": "^9.0.0-alpha.12",
|
|
88
88
|
"@storybook/addon-links": "^9.1.1",
|
|
89
89
|
"@storybook/vue3-vite": "^9.1.1",
|
|
90
|
-
"@ulu/frontend": "^0.1.0-beta.
|
|
90
|
+
"@ulu/frontend": "^0.1.0-beta.118",
|
|
91
91
|
"@unhead/vue": "^2.0.11",
|
|
92
92
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
93
93
|
"ollama": "^0.5.16",
|