@ulu/frontend-vue 0.5.12 → 0.5.13
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.
|
@@ -19,6 +19,8 @@ declare const __VLS_component: import('vue').DefineComponent<{}, {
|
|
|
19
19
|
bodyFills: boolean;
|
|
20
20
|
noBackdrop: boolean;
|
|
21
21
|
noMinHeight: boolean;
|
|
22
|
+
autoIframe: boolean;
|
|
23
|
+
pauseVideos: boolean;
|
|
22
24
|
labelledby?: string | undefined;
|
|
23
25
|
describedby?: string | undefined;
|
|
24
26
|
title?: string | undefined;
|
|
@@ -41,6 +43,8 @@ declare const __VLS_component: import('vue').DefineComponent<{}, {
|
|
|
41
43
|
readonly bodyFills?: boolean | undefined;
|
|
42
44
|
readonly noBackdrop?: boolean | undefined;
|
|
43
45
|
readonly noMinHeight?: boolean | undefined;
|
|
46
|
+
readonly autoIframe?: boolean | undefined;
|
|
47
|
+
readonly pauseVideos?: boolean | undefined;
|
|
44
48
|
readonly labelledby?: string | undefined;
|
|
45
49
|
readonly describedby?: string | undefined;
|
|
46
50
|
readonly title?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UluModal.vue.d.ts","sourceRoot":"","sources":["../../../lib/components/collapsible/UluModal.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UluModal.vue.d.ts","sourceRoot":"","sources":["../../../lib/components/collapsible/UluModal.vue"],"names":[],"mappings":"AAsEA;wBA07BqB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;;6BAEtE,CAAC,EAAE,CAAC;;;AAbjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4OAUG"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { useSlots as
|
|
2
|
-
import
|
|
3
|
-
import { useModifiers as
|
|
4
|
-
import { preventScroll as
|
|
5
|
-
import { Resizer as
|
|
6
|
-
import { newId as
|
|
7
|
-
const
|
|
1
|
+
import { useSlots as J, ref as n, computed as u, watch as M, nextTick as w, onMounted as K, onBeforeUnmount as Q, createBlock as H, openBlock as d, Teleport as Z, createElementVNode as f, withModifiers as x, normalizeStyle as L, normalizeClass as r, unref as T, createElementBlock as C, createCommentVNode as g, renderSlot as m, toDisplayString as ee, createVNode as P } from "vue";
|
|
2
|
+
import R from "../elements/UluIcon.vue.js";
|
|
3
|
+
import { useModifiers as le } from "../../composables/useModifiers.js";
|
|
4
|
+
import { preventScroll as oe, wasClickOutside as te } from "@ulu/utils/browser/dom.js";
|
|
5
|
+
import { getSoleIframeLayout as se, youtubePrepVideos as ie, youtubePauseVideos as ae, Resizer as ne, observeDialogToggle as re } from "@ulu/frontend";
|
|
6
|
+
import { newId as ce } from "../../utils/dom.js";
|
|
7
|
+
const ue = ["aria-labelledby", "aria-describedby"], de = ["id"], fe = { class: "modal__title-text" }, ze = {
|
|
8
8
|
__name: "UluModal",
|
|
9
9
|
props: {
|
|
10
10
|
/**
|
|
@@ -117,155 +117,180 @@ const ne = ["aria-labelledby", "aria-describedby"], ie = ["id"], re = { class: "
|
|
|
117
117
|
/**
|
|
118
118
|
* Modifiers (to add any modifier classes based on base class [ie. 'tertiary'])
|
|
119
119
|
*/
|
|
120
|
-
modifiers: [String, Array]
|
|
120
|
+
modifiers: [String, Array],
|
|
121
|
+
/**
|
|
122
|
+
* Opt-in convenience behavior. If the modal body's sole content is an iframe, it automatically applies layout fixes.
|
|
123
|
+
*/
|
|
124
|
+
autoIframe: Boolean,
|
|
125
|
+
/**
|
|
126
|
+
* Opt-in behavior to pause playing videos (YouTube and native <video>) when the modal closes.
|
|
127
|
+
*/
|
|
128
|
+
pauseVideos: Boolean
|
|
121
129
|
},
|
|
122
130
|
emits: ["update:modelValue", "close", "open"],
|
|
123
|
-
setup(t, { emit:
|
|
124
|
-
const
|
|
131
|
+
setup(t, { emit: j }) {
|
|
132
|
+
const c = j, e = t, D = J(), N = n(null), E = ce("ulu-modal-title"), B = n(!1), o = n(null), $ = n(null), k = n(null), i = n({
|
|
133
|
+
isStaticSize: !1,
|
|
134
|
+
isFill: !1,
|
|
135
|
+
bodyStyle: {}
|
|
136
|
+
}), O = u(() => e.title || D.title), v = u(() => {
|
|
125
137
|
const { allowResize: l, position: s } = e;
|
|
126
138
|
if (!l || !s) return !1;
|
|
127
|
-
const
|
|
128
|
-
return
|
|
129
|
-
}),
|
|
139
|
+
const h = ["left", "right", "center"];
|
|
140
|
+
return h.includes(s) ? !0 : (console.warn(`Passed invalid position for resize (${s}), use ${h.join(", ")}`), !1);
|
|
141
|
+
}), _ = u(() => e.position === "center" ? "type:resizeBoth" : "type:resizeHorizontal"), A = u(() => ({
|
|
130
142
|
[e.position]: e.position,
|
|
131
143
|
resize: e.allowResize,
|
|
132
144
|
"no-resize": !e.allowResize,
|
|
133
|
-
"no-header": !
|
|
145
|
+
"no-header": !O.value,
|
|
134
146
|
"body-fills": e.bodyFills,
|
|
135
147
|
"no-backdrop": e.noBackdrop,
|
|
136
148
|
"no-min-height": e.noMinHeight,
|
|
137
149
|
"non-modal": e.nonModal,
|
|
138
|
-
"resizer-active":
|
|
150
|
+
"resizer-active": v.value,
|
|
139
151
|
fullscreen: e.fullscreen,
|
|
140
|
-
"fullscreen-mobile": e.fullscreenMobile
|
|
141
|
-
|
|
152
|
+
"fullscreen-mobile": e.fullscreenMobile,
|
|
153
|
+
"frame-ratio": i.value.isStaticSize,
|
|
154
|
+
"frame-fill": i.value.isFill
|
|
155
|
+
})), { resolvedModifiers: U } = le({
|
|
142
156
|
props: e,
|
|
143
157
|
baseClass: "modal",
|
|
144
|
-
internal:
|
|
145
|
-
}),
|
|
146
|
-
|
|
147
|
-
},
|
|
148
|
-
e.modelValue && (
|
|
149
|
-
},
|
|
150
|
-
if (e.clickOutsideCloses && !
|
|
158
|
+
internal: A
|
|
159
|
+
}), X = u(() => e.labelledby ? e.labelledby : E), a = () => {
|
|
160
|
+
c("update:modelValue", !1), c("close");
|
|
161
|
+
}, q = () => {
|
|
162
|
+
e.modelValue && (c("update:modelValue", !1), c("close"));
|
|
163
|
+
}, W = (l) => {
|
|
164
|
+
if (e.clickOutsideCloses && !B.value) {
|
|
151
165
|
const { target: s } = l;
|
|
152
|
-
s === o.value &&
|
|
166
|
+
s === o.value && te(o.value, l) && a();
|
|
153
167
|
}
|
|
154
168
|
};
|
|
155
|
-
let
|
|
156
|
-
const
|
|
157
|
-
!e.nonModal && e.preventScroll && (
|
|
158
|
-
l ?
|
|
169
|
+
let y = null, b = null, S = null, p = null, z = null;
|
|
170
|
+
const Y = () => {
|
|
171
|
+
!e.nonModal && e.preventScroll && (y = re(o.value, (l) => {
|
|
172
|
+
l ? b = oe({ preventShift: e.preventScrollShift }) : F();
|
|
159
173
|
}));
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
},
|
|
165
|
-
if (
|
|
174
|
+
}, G = () => {
|
|
175
|
+
y && (y.destroy(), y = null);
|
|
176
|
+
}, F = () => {
|
|
177
|
+
b && (b(), b = null);
|
|
178
|
+
}, I = () => {
|
|
179
|
+
if (v.value) {
|
|
166
180
|
const l = e.position === "center" ? { fromX: "right", fromY: "bottom", multiplier: 2 } : { fromX: e.position === "right" ? "left" : "right" };
|
|
167
|
-
|
|
168
|
-
|
|
181
|
+
S = new ne(o.value, $.value, l), p = () => {
|
|
182
|
+
B.value = !0;
|
|
169
183
|
}, z = () => {
|
|
170
184
|
setTimeout(() => {
|
|
171
|
-
|
|
185
|
+
B.value = !1;
|
|
172
186
|
}, 0);
|
|
173
|
-
}, o.value.addEventListener("ulu:resizer:start",
|
|
187
|
+
}, o.value.addEventListener("ulu:resizer:start", p), o.value.addEventListener("ulu:resizer:end", z);
|
|
174
188
|
}
|
|
175
|
-
},
|
|
176
|
-
|
|
189
|
+
}, V = () => {
|
|
190
|
+
S && (S.destroy(), S = null), p && o.value && o.value.removeEventListener("ulu:resizer:start", p), z && o.value && o.value.removeEventListener("ulu:resizer:end", z);
|
|
177
191
|
};
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
|
|
192
|
+
return M(() => e.modelValue, (l) => {
|
|
193
|
+
w(() => {
|
|
194
|
+
if (o.value)
|
|
195
|
+
if (l) {
|
|
196
|
+
if (e.autoIframe && k.value) {
|
|
197
|
+
const s = se(k.value);
|
|
198
|
+
s && (s.iframe.classList.add("modal__frame-content"), s.isStaticSize ? (i.value.isStaticSize = !0, i.value.isFill = !1, i.value.bodyStyle = { aspectRatio: s.aspectRatio }) : (i.value.isFill = !0, i.value.isStaticSize = !1, i.value.bodyStyle = s.fillHeight ? { minHeight: s.fillHeight } : {}));
|
|
199
|
+
}
|
|
200
|
+
e.pauseVideos && ie(o.value), o.value[e.nonModal ? "show" : "showModal"](), c("open");
|
|
201
|
+
} else
|
|
202
|
+
e.pauseVideos && (ae(o.value), o.value.querySelectorAll("video").forEach((h) => h.pause())), o.value.close(), i.value = { isStaticSize: !1, isFill: !1, bodyStyle: {} };
|
|
181
203
|
});
|
|
182
|
-
}, { immediate: !0 }),
|
|
183
|
-
l ?
|
|
184
|
-
|
|
185
|
-
}) :
|
|
186
|
-
}, { immediate: !1 }),
|
|
187
|
-
l !== s && (
|
|
188
|
-
|
|
204
|
+
}, { immediate: !0 }), M(v, (l) => {
|
|
205
|
+
l ? w(() => {
|
|
206
|
+
I();
|
|
207
|
+
}) : V();
|
|
208
|
+
}, { immediate: !1 }), M(() => e.position, (l, s) => {
|
|
209
|
+
l !== s && (V(), w(() => {
|
|
210
|
+
I();
|
|
189
211
|
}));
|
|
190
|
-
}),
|
|
191
|
-
|
|
192
|
-
}),
|
|
193
|
-
o.value && o.value.open && o.value.close(),
|
|
194
|
-
}), (l, s) => (
|
|
212
|
+
}), K(() => {
|
|
213
|
+
Y(), I();
|
|
214
|
+
}), Q(() => {
|
|
215
|
+
o.value && o.value.open && o.value.close(), G(), F(), V();
|
|
216
|
+
}), (l, s) => (d(), H(Z, {
|
|
195
217
|
to: t.teleport === !1 ? null : t.teleport,
|
|
196
218
|
disabled: t.teleport === !1
|
|
197
219
|
}, [
|
|
198
|
-
|
|
199
|
-
class:
|
|
200
|
-
"aria-labelledby":
|
|
220
|
+
f("dialog", {
|
|
221
|
+
class: r(["modal", [T(U), t.classes.container]]),
|
|
222
|
+
"aria-labelledby": X.value,
|
|
201
223
|
"aria-describedby": t.describedby,
|
|
202
224
|
ref_key: "container",
|
|
203
225
|
ref: o,
|
|
204
|
-
style:
|
|
205
|
-
onCancel:
|
|
206
|
-
onClose:
|
|
207
|
-
onClick:
|
|
226
|
+
style: L({ width: N.value }),
|
|
227
|
+
onCancel: x(a, ["prevent"]),
|
|
228
|
+
onClose: q,
|
|
229
|
+
onClick: W
|
|
208
230
|
}, [
|
|
209
|
-
|
|
231
|
+
O.value ? (d(), C("header", {
|
|
210
232
|
key: 0,
|
|
211
|
-
class:
|
|
233
|
+
class: r(["modal__header", t.classes.header])
|
|
212
234
|
}, [
|
|
213
|
-
|
|
214
|
-
class:
|
|
215
|
-
id: T(
|
|
235
|
+
f("h2", {
|
|
236
|
+
class: r(["modal__title", t.classes.title]),
|
|
237
|
+
id: T(E)
|
|
216
238
|
}, [
|
|
217
|
-
|
|
218
|
-
t.titleIcon ? (
|
|
239
|
+
m(l.$slots, "title", { close: a }, () => [
|
|
240
|
+
t.titleIcon ? (d(), H(R, {
|
|
219
241
|
key: 0,
|
|
220
242
|
class: "modal__title-icon",
|
|
221
243
|
icon: t.titleIcon
|
|
222
|
-
}, null, 8, ["icon"])) :
|
|
223
|
-
|
|
244
|
+
}, null, 8, ["icon"])) : g("", !0),
|
|
245
|
+
f("span", fe, ee(t.title), 1)
|
|
224
246
|
])
|
|
225
|
-
], 10,
|
|
226
|
-
|
|
227
|
-
class:
|
|
247
|
+
], 10, de),
|
|
248
|
+
f("button", {
|
|
249
|
+
class: r(["modal__close", t.classes.close]),
|
|
228
250
|
"aria-label": "Close modal",
|
|
229
|
-
onClick:
|
|
251
|
+
onClick: a,
|
|
230
252
|
autofocus: ""
|
|
231
253
|
}, [
|
|
232
|
-
|
|
233
|
-
|
|
254
|
+
m(l.$slots, "closeIcon", {}, () => [
|
|
255
|
+
P(R, {
|
|
234
256
|
class: "modal__close-icon",
|
|
235
257
|
icon: t.closeIcon || "type:close"
|
|
236
258
|
}, null, 8, ["icon"])
|
|
237
259
|
])
|
|
238
260
|
], 2)
|
|
239
|
-
], 2)) :
|
|
240
|
-
|
|
241
|
-
class:
|
|
261
|
+
], 2)) : g("", !0),
|
|
262
|
+
f("div", {
|
|
263
|
+
class: r(["modal__body", t.classes.body]),
|
|
264
|
+
style: L(i.value.bodyStyle),
|
|
265
|
+
ref_key: "body",
|
|
266
|
+
ref: k
|
|
242
267
|
}, [
|
|
243
|
-
|
|
244
|
-
],
|
|
245
|
-
l.$slots.footer ? (
|
|
268
|
+
m(l.$slots, "default", { close: a })
|
|
269
|
+
], 6),
|
|
270
|
+
l.$slots.footer ? (d(), C("div", {
|
|
246
271
|
key: 1,
|
|
247
|
-
class:
|
|
272
|
+
class: r(["site-modal__footer", t.classes.footer])
|
|
248
273
|
}, [
|
|
249
|
-
|
|
250
|
-
], 2)) :
|
|
251
|
-
|
|
274
|
+
m(l.$slots, "footer", { close: a })
|
|
275
|
+
], 2)) : g("", !0),
|
|
276
|
+
v.value ? (d(), C("button", {
|
|
252
277
|
key: 2,
|
|
253
278
|
class: "modal__resizer",
|
|
254
279
|
ref_key: "resizer",
|
|
255
|
-
ref:
|
|
280
|
+
ref: $,
|
|
256
281
|
type: "button"
|
|
257
282
|
}, [
|
|
258
|
-
|
|
259
|
-
|
|
283
|
+
m(l.$slots, "resizerIcon", {}, () => [
|
|
284
|
+
P(R, {
|
|
260
285
|
class: "modal__resizer-icon",
|
|
261
|
-
icon: t.resizerIcon ||
|
|
286
|
+
icon: t.resizerIcon || _.value
|
|
262
287
|
}, null, 8, ["icon"])
|
|
263
288
|
])
|
|
264
|
-
], 512)) :
|
|
265
|
-
], 46,
|
|
289
|
+
], 512)) : g("", !0)
|
|
290
|
+
], 46, ue)
|
|
266
291
|
], 8, ["to", "disabled"]));
|
|
267
292
|
}
|
|
268
293
|
};
|
|
269
294
|
export {
|
|
270
|
-
|
|
295
|
+
ze as default
|
|
271
296
|
};
|
|
@@ -48,6 +48,8 @@
|
|
|
48
48
|
<div
|
|
49
49
|
class="modal__body"
|
|
50
50
|
:class="classes.body"
|
|
51
|
+
:style="iframeState.bodyStyle"
|
|
52
|
+
ref="body"
|
|
51
53
|
>
|
|
52
54
|
<slot :close="close"/>
|
|
53
55
|
</div>
|
|
@@ -72,7 +74,7 @@
|
|
|
72
74
|
import UluIcon from "../elements/UluIcon.vue";
|
|
73
75
|
import { useModifiers } from "../../composables/useModifiers.js";
|
|
74
76
|
import { wasClickOutside, preventScroll as setupPreventScroll } from "@ulu/utils/browser/dom.js";
|
|
75
|
-
import { Resizer, observeDialogToggle } from "@ulu/frontend";
|
|
77
|
+
import { Resizer, observeDialogToggle, getSoleIframeLayout, youtubePauseVideos, youtubePrepVideos } from "@ulu/frontend";
|
|
76
78
|
import { newId } from "../../utils/dom.js";
|
|
77
79
|
|
|
78
80
|
const emit = defineEmits(["update:modelValue", "close", "open"]);
|
|
@@ -188,6 +190,14 @@
|
|
|
188
190
|
* Modifiers (to add any modifier classes based on base class [ie. 'tertiary'])
|
|
189
191
|
*/
|
|
190
192
|
modifiers: [String, Array],
|
|
193
|
+
/**
|
|
194
|
+
* Opt-in convenience behavior. If the modal body's sole content is an iframe, it automatically applies layout fixes.
|
|
195
|
+
*/
|
|
196
|
+
autoIframe: Boolean,
|
|
197
|
+
/**
|
|
198
|
+
* Opt-in behavior to pause playing videos (YouTube and native <video>) when the modal closes.
|
|
199
|
+
*/
|
|
200
|
+
pauseVideos: Boolean,
|
|
191
201
|
});
|
|
192
202
|
|
|
193
203
|
const slots = useSlots();
|
|
@@ -198,6 +208,13 @@
|
|
|
198
208
|
|
|
199
209
|
const container = ref(null);
|
|
200
210
|
const resizer = ref(null);
|
|
211
|
+
const body = ref(null);
|
|
212
|
+
|
|
213
|
+
const iframeState = ref({
|
|
214
|
+
isStaticSize: false,
|
|
215
|
+
isFill: false,
|
|
216
|
+
bodyStyle: {}
|
|
217
|
+
});
|
|
201
218
|
|
|
202
219
|
const hasHeader = computed(() => props.title || slots.title);
|
|
203
220
|
|
|
@@ -230,6 +247,8 @@
|
|
|
230
247
|
"resizer-active": resizerEnabled.value,
|
|
231
248
|
"fullscreen": props.fullscreen,
|
|
232
249
|
"fullscreen-mobile": props.fullscreenMobile,
|
|
250
|
+
"frame-ratio": iframeState.value.isStaticSize,
|
|
251
|
+
"frame-fill": iframeState.value.isFill,
|
|
233
252
|
}));
|
|
234
253
|
|
|
235
254
|
const { resolvedModifiers } = useModifiers({
|
|
@@ -329,10 +348,34 @@
|
|
|
329
348
|
nextTick(() => {
|
|
330
349
|
if (container.value) {
|
|
331
350
|
if (newValue) {
|
|
351
|
+
if (props.autoIframe && body.value) {
|
|
352
|
+
const layout = getSoleIframeLayout(body.value);
|
|
353
|
+
if (layout) {
|
|
354
|
+
layout.iframe.classList.add("modal__frame-content");
|
|
355
|
+
if (layout.isStaticSize) {
|
|
356
|
+
iframeState.value.isStaticSize = true;
|
|
357
|
+
iframeState.value.isFill = false;
|
|
358
|
+
iframeState.value.bodyStyle = { aspectRatio: layout.aspectRatio };
|
|
359
|
+
} else {
|
|
360
|
+
iframeState.value.isFill = true;
|
|
361
|
+
iframeState.value.isStaticSize = false;
|
|
362
|
+
iframeState.value.bodyStyle = layout.fillHeight ? { minHeight: layout.fillHeight } : {};
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (props.pauseVideos) {
|
|
367
|
+
youtubePrepVideos(container.value);
|
|
368
|
+
}
|
|
332
369
|
container.value[props.nonModal ? "show" : "showModal"]();
|
|
333
370
|
emit("open");
|
|
334
371
|
} else {
|
|
372
|
+
if (props.pauseVideos) {
|
|
373
|
+
youtubePauseVideos(container.value);
|
|
374
|
+
const nativeVideos = container.value.querySelectorAll("video");
|
|
375
|
+
nativeVideos.forEach(video => video.pause());
|
|
376
|
+
}
|
|
335
377
|
container.value.close();
|
|
378
|
+
iframeState.value = { isStaticSize: false, isFill: false, bodyStyle: {} };
|
|
336
379
|
}
|
|
337
380
|
}
|
|
338
381
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ulu/frontend-vue",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.13",
|
|
4
4
|
"description": "A modular, tree-shakeable Vue 3 component library for the Ulu Frontend theming system, plus general utilities for Vue development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@fortawesome/vue-fontawesome": "^3.0.8",
|
|
66
66
|
"@headlessui/vue": "^1.7.23",
|
|
67
67
|
"@portabletext/vue": "^1.0.14",
|
|
68
|
-
"@ulu/frontend": "^0.4.
|
|
68
|
+
"@ulu/frontend": "^0.4.11",
|
|
69
69
|
"@ulu/utils": "^0.0.34",
|
|
70
70
|
"@unhead/vue": "^2.0.11",
|
|
71
71
|
"fuse.js": "^6.6.2",
|
|
@@ -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.4.
|
|
90
|
+
"@ulu/frontend": "^0.4.11",
|
|
91
91
|
"@ulu/utils": "^0.0.34",
|
|
92
92
|
"@unhead/vue": "^2.0.11",
|
|
93
93
|
"@vitejs/plugin-vue": "^6.0.0",
|