@resee-movies/nuxt-ux 0.16.0 → 0.17.0
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/module.json +1 -1
- package/dist/runtime/components/GlobalHeaderAnnouncement.vue +1 -1
- package/dist/runtime/components/ImageTiler.vue +193 -0
- package/dist/runtime/components/ImageTiler.vue.d.ts +31 -0
- package/dist/runtime/components/InlineStatsList.vue +33 -0
- package/dist/runtime/components/InlineStatsList.vue.d.ts +15 -0
- package/dist/runtime/components/InlineStatsListItem.vue +39 -0
- package/dist/runtime/components/InlineStatsListItem.vue.d.ts +19 -0
- package/dist/runtime/components/TableOfContents.vue +19 -0
- package/dist/runtime/components/TableOfContents.vue.d.ts +7 -0
- package/dist/runtime/components/form/Form.vue +4 -2
- package/dist/runtime/components/form/FormField.vue +7 -7
- package/dist/runtime/components/form/FormFieldTurnstile.vue +2 -1
- package/dist/runtime/components/form/element/FormElementTurnstile.vue +2 -1
- package/dist/runtime/components/form/element/FormElementTurnstile.vue.d.ts +1 -0
- package/dist/runtime/composables/use-settings-for-breakpoint.d.ts +11 -0
- package/dist/runtime/composables/use-settings-for-breakpoint.js +25 -0
- package/dist/runtime/theme/css/brand/image.css +1 -0
- package/dist/runtime/theme/css/styles.css +1 -1
- package/dist/runtime/types/form.d.ts +1 -0
- package/dist/runtime/utils/form.d.ts +3 -3
- package/dist/runtime/utils/form.js +6 -5
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -45,5 +45,5 @@ function dismissAnnouncement() {
|
|
|
45
45
|
</script>
|
|
46
46
|
|
|
47
47
|
<style scoped>
|
|
48
|
-
@reference "tailwindcss";.announcement{--announcement-bg-color:#fff;@variant dark{--announcement-bg-color:#000}background-image:linear-gradient(to bottom,var(--announcement-bg-color) 0 calc(100% - 10px),transparent),linear-gradient(to right,var(--colorscale-resee-linear));padding-bottom:6px}.announcement.dismissable>div{padding-right
|
|
48
|
+
@reference "tailwindcss";.announcement{--announcement-bg-color:#fff;@variant dark{--announcement-bg-color:#000}background-image:linear-gradient(to bottom,var(--announcement-bg-color) 0 calc(100% - 10px),transparent),linear-gradient(to right,var(--colorscale-resee-linear));padding-bottom:6px}.announcement.dismissable>div{padding-right:--spacing(12)}
|
|
49
49
|
</style>
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="['tiler', props.maskPreset]">
|
|
3
|
+
<div v-for="(entry, idx) of displayArray" :key="idx">
|
|
4
|
+
<ImageBase
|
|
5
|
+
:src = "entry.source"
|
|
6
|
+
aspect = "poster"
|
|
7
|
+
:class = "[props.imageClass, { 'opacity-0': entry.switching || entry.loading }]"
|
|
8
|
+
:style = "{ '--duration': `${entry.switchTime}ms`, '--delay': `${entry.switchDelay}ms` }"
|
|
9
|
+
@loading = "entry.loading = true"
|
|
10
|
+
@load = "entry.loading = false"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<style scoped>
|
|
17
|
+
@reference "tailwindcss";@layer components{.tiler{-moz-column-gap:--spacing(v-bind(grid.gapY));column-gap:--spacing(v-bind(grid.gapY));display:grid;grid-template-columns:repeat(v-bind(grid.cols),1fr);row-gap:--spacing(v-bind(grid.gapX))}.tiler>div{justify-self:center}img{--duration:200ms;--delay:0ms;transition:opacity;transition-delay:var(--delay);transition-duration:var(--duration);transition-timing-function:ease-out}}
|
|
18
|
+
</style>
|
|
19
|
+
|
|
20
|
+
<script>
|
|
21
|
+
export const DefaultImageTilerGridSizeFallback = {
|
|
22
|
+
cols: 5,
|
|
23
|
+
rows: 8,
|
|
24
|
+
gap: 3
|
|
25
|
+
};
|
|
26
|
+
export const DefaultImageTilerGridSizeDefinition = {
|
|
27
|
+
md: {
|
|
28
|
+
cols: 7,
|
|
29
|
+
rows: 5
|
|
30
|
+
},
|
|
31
|
+
lg: {
|
|
32
|
+
cols: 10,
|
|
33
|
+
rows: 5
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<script setup>
|
|
39
|
+
import { useState } from "#imports";
|
|
40
|
+
import { getRandomEntry } from "@resee-movies/utilities/arrays/get-random-entry";
|
|
41
|
+
import { normalizeImageFileDescriptor } from "@resee-movies/utilities/images/normalize-image-file-descriptor";
|
|
42
|
+
import { getRandomInteger } from "@resee-movies/utilities/numbers/get-random-integer";
|
|
43
|
+
import { toInteger } from "@resee-movies/utilities/numbers/to-integer";
|
|
44
|
+
import { sleep } from "@resee-movies/utilities/timers/sleep";
|
|
45
|
+
import { computed, onMounted, shallowReactive, useId, watch } from "vue";
|
|
46
|
+
import { useSettingsForBreakpoint } from "../composables/use-settings-for-breakpoint";
|
|
47
|
+
import ImageBase from "./ImageBase.vue";
|
|
48
|
+
const props = defineProps({
|
|
49
|
+
images: { type: Array, required: true },
|
|
50
|
+
play: { type: Boolean, required: false, default: true },
|
|
51
|
+
gridSettings: { type: Object, required: false, default: () => DefaultImageTilerGridSizeDefinition },
|
|
52
|
+
turnoverRate: { type: [String, Number, Array], required: false, default: () => [2e3, 6e3] },
|
|
53
|
+
switchTime: { type: [String, Number, Array], required: false, default: () => [1200, 1800] },
|
|
54
|
+
switchDelay: { type: [String, Number, Array], required: false, default: () => [0, 500] },
|
|
55
|
+
imageClass: { type: null, required: false, default: void 0 },
|
|
56
|
+
maskPreset: { type: [String, Array], required: false }
|
|
57
|
+
});
|
|
58
|
+
const gridSettingsForBreakpoint = useSettingsForBreakpoint(() => props.gridSettings);
|
|
59
|
+
const grid = computed(() => {
|
|
60
|
+
const settings = gridSettingsForBreakpoint.value;
|
|
61
|
+
const rows = settings?.rows ?? DefaultImageTilerGridSizeFallback.rows;
|
|
62
|
+
const cols = settings?.cols ?? DefaultImageTilerGridSizeFallback.cols;
|
|
63
|
+
const cells = rows * cols;
|
|
64
|
+
const gapX = settings?.gapX ?? settings?.gap ?? DefaultImageTilerGridSizeFallback.gap;
|
|
65
|
+
const gapY = settings?.gapY ?? settings?.gap ?? DefaultImageTilerGridSizeFallback.gap;
|
|
66
|
+
return { rows, cols, cells, gapX, gapY };
|
|
67
|
+
});
|
|
68
|
+
const componentId = useId();
|
|
69
|
+
const displayArray = useState(componentId, () => {
|
|
70
|
+
const arr = [];
|
|
71
|
+
for (let i = 0; i < grid.value.cells; i += 1) {
|
|
72
|
+
arr.push(generateImageDisplayInfo(i, arr));
|
|
73
|
+
}
|
|
74
|
+
return arr;
|
|
75
|
+
});
|
|
76
|
+
onMounted(() => {
|
|
77
|
+
showAll();
|
|
78
|
+
queueNextChange();
|
|
79
|
+
});
|
|
80
|
+
watch(() => grid.value.cells, (newCount, oldCount) => {
|
|
81
|
+
if (newCount < oldCount) {
|
|
82
|
+
displayArray.value.splice(newCount, Number.POSITIVE_INFINITY);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (newCount > oldCount) {
|
|
86
|
+
while (displayArray.value.length < newCount) {
|
|
87
|
+
const info = generateImageDisplayInfo(displayArray.value.length, displayArray.value);
|
|
88
|
+
displayArray.value.push(info);
|
|
89
|
+
showImageCellContent(info);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
function queueNextChange() {
|
|
94
|
+
setTimeout(async () => {
|
|
95
|
+
if (props.play) {
|
|
96
|
+
const idx = getValueFromRange([0, displayArray.value.length - 1]);
|
|
97
|
+
const info = displayArray.value[idx];
|
|
98
|
+
if (info) {
|
|
99
|
+
await switchImageCellContent(info, idx);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
queueNextChange();
|
|
103
|
+
}, getValueFromRange(props.turnoverRate));
|
|
104
|
+
}
|
|
105
|
+
function getValueFromRange(value) {
|
|
106
|
+
return Array.isArray(value) ? getRandomInteger(value[0], value[1]) : toInteger(value);
|
|
107
|
+
}
|
|
108
|
+
function pickImage(forIdx, forArray) {
|
|
109
|
+
let candidate = normalizeImageFileDescriptor(getRandomEntry(props.images));
|
|
110
|
+
if (props.images.length > 5) {
|
|
111
|
+
const neighbors = getNeighborIndexes(
|
|
112
|
+
forIdx,
|
|
113
|
+
grid.value.cols,
|
|
114
|
+
grid.value.rows,
|
|
115
|
+
props.images.length > 9 ? "8-edge" : "4-edge"
|
|
116
|
+
);
|
|
117
|
+
neighbors.push(forIdx);
|
|
118
|
+
for (let maxAttempts = 0; maxAttempts < 3; maxAttempts += 1) {
|
|
119
|
+
if (isImageInUse(candidate, forArray, neighbors)) {
|
|
120
|
+
candidate = normalizeImageFileDescriptor(getRandomEntry(props.images));
|
|
121
|
+
} else {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return candidate;
|
|
127
|
+
}
|
|
128
|
+
function getNeighborIndexes(centerIdx, columnCount, rowCount, distance = "8-edge") {
|
|
129
|
+
const rowOffset = Math.floor(centerIdx / columnCount);
|
|
130
|
+
const colOffset = centerIdx % columnCount;
|
|
131
|
+
const top = rowOffset > 0 ? centerIdx - columnCount : -1;
|
|
132
|
+
const right = colOffset < columnCount ? centerIdx + 1 : -1;
|
|
133
|
+
const bottom = rowOffset < rowCount ? centerIdx + columnCount : -1;
|
|
134
|
+
const left = colOffset > 0 ? centerIdx - 1 : -1;
|
|
135
|
+
if (distance === "4-edge") {
|
|
136
|
+
return [top, right, bottom, left];
|
|
137
|
+
}
|
|
138
|
+
const topRight = top > -1 && right > -1 ? top + 1 : -1;
|
|
139
|
+
const bottomRight = bottom > -1 && right > -1 ? bottom + 1 : -1;
|
|
140
|
+
const bottomLeft = bottom > -1 && left > -1 ? bottom - 1 : -1;
|
|
141
|
+
const topLeft = top > -1 && left > -1 ? top - 1 : -1;
|
|
142
|
+
return [top, topRight, right, bottomRight, bottom, bottomLeft, left, topLeft];
|
|
143
|
+
}
|
|
144
|
+
function isImageInUse(candidate, sourceArray, indicesToCheck) {
|
|
145
|
+
for (const idx of indicesToCheck) {
|
|
146
|
+
if (idx < 0 || idx > sourceArray.length) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (sourceArray.at(idx)?.source.identifier === candidate.identifier) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
function generateImageDisplayInfo(forIdx, forArray) {
|
|
156
|
+
return shallowReactive({
|
|
157
|
+
source: pickImage(forIdx, forArray),
|
|
158
|
+
loading: true,
|
|
159
|
+
switching: true,
|
|
160
|
+
switchTime: getValueFromRange(props.switchTime),
|
|
161
|
+
switchDelay: getValueFromRange(props.switchDelay)
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async function hideImageCellContent(info) {
|
|
165
|
+
if (info.switching) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
info.switching = true;
|
|
169
|
+
await sleep(info.switchTime + info.switchDelay);
|
|
170
|
+
}
|
|
171
|
+
async function showImageCellContent(info) {
|
|
172
|
+
if (!info.switching) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
info.switching = false;
|
|
176
|
+
await sleep(info.switchTime + info.switchDelay);
|
|
177
|
+
}
|
|
178
|
+
async function switchImageCellContent(info, idx) {
|
|
179
|
+
await hideImageCellContent(info);
|
|
180
|
+
info.source = pickImage(idx, displayArray.value);
|
|
181
|
+
await showImageCellContent(info);
|
|
182
|
+
}
|
|
183
|
+
async function showAll() {
|
|
184
|
+
return Promise.allSettled(
|
|
185
|
+
displayArray.value.map((entry) => showImageCellContent(entry))
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
async function hideAll() {
|
|
189
|
+
return Promise.allSettled(
|
|
190
|
+
displayArray.value.map((entry) => hideImageCellContent(entry))
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ImageFileDescriptor } from '@resee-movies/utilities/images/normalize-image-file-descriptor';
|
|
2
|
+
import type { BreakpointSettings } from '../composables/use-settings-for-breakpoint.js';
|
|
3
|
+
import type { HTMLElementClassNames } from '../types/index.js';
|
|
4
|
+
export type ValueOrRange = string | number | [min: number, max: number];
|
|
5
|
+
export type ImageTilerGridSizeDefinition = {
|
|
6
|
+
cols: number;
|
|
7
|
+
rows: number;
|
|
8
|
+
gap?: number;
|
|
9
|
+
gapX?: number;
|
|
10
|
+
gapY?: number;
|
|
11
|
+
};
|
|
12
|
+
export type ImageMaskPreset = 'image-mask-washout' | 'image-mask-gradient-washout' | 'image-mask-gradient-washout-lite' | 'image-mask-gradient-opacity' | 'image-mask-hero';
|
|
13
|
+
export declare const DefaultImageTilerGridSizeFallback: {
|
|
14
|
+
cols: number;
|
|
15
|
+
rows: number;
|
|
16
|
+
gap: number;
|
|
17
|
+
};
|
|
18
|
+
export declare const DefaultImageTilerGridSizeDefinition: BreakpointSettings<ImageTilerGridSizeDefinition>;
|
|
19
|
+
export interface ImageTilerProps {
|
|
20
|
+
images: ImageFileDescriptor[];
|
|
21
|
+
play?: boolean;
|
|
22
|
+
gridSettings?: BreakpointSettings<ImageTilerGridSizeDefinition>;
|
|
23
|
+
turnoverRate?: ValueOrRange;
|
|
24
|
+
switchTime?: ValueOrRange;
|
|
25
|
+
switchDelay?: ValueOrRange;
|
|
26
|
+
imageClass?: HTMLElementClassNames;
|
|
27
|
+
maskPreset?: ImageMaskPreset | ImageMaskPreset[];
|
|
28
|
+
}
|
|
29
|
+
declare const __VLS_export: import("vue").DefineComponent<ImageTilerProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ImageTilerProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="['stats', { responsive: props.responsive }]">
|
|
3
|
+
<dl>
|
|
4
|
+
<slot name="default">
|
|
5
|
+
<template v-if="props.items?.length">
|
|
6
|
+
<InlineStatsListItem
|
|
7
|
+
v-for = "item of props.items"
|
|
8
|
+
:key = "item.label"
|
|
9
|
+
:label = "item.label"
|
|
10
|
+
:description = "item.description"
|
|
11
|
+
:icon = "item.icon"
|
|
12
|
+
/>
|
|
13
|
+
</template>
|
|
14
|
+
</slot>
|
|
15
|
+
</dl>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
import InlineStatsListItem from "./InlineStatsListItem.vue";
|
|
25
|
+
const props = defineProps({
|
|
26
|
+
responsive: { type: Boolean, required: false, default: false },
|
|
27
|
+
items: { type: Array, required: false, default: void 0 }
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<style scoped>
|
|
32
|
+
@reference "tailwindcss";.stats{--stats-list-spacer-width:1.2rem;overflow:clip}.stats dl{display:flex;flex-wrap:wrap;margin-inline-start:calc(var(--stats-list-spacer-width)*-1)}.stats.responsive dl{@variant max-sm{flex-direction:column}}
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { InlineStatsListItemProps } from './InlineStatsListItem.vue.js';
|
|
2
|
+
export interface InlineStatsListProps {
|
|
3
|
+
responsive?: boolean;
|
|
4
|
+
items?: InlineStatsListItemProps[];
|
|
5
|
+
}
|
|
6
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<InlineStatsListProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<InlineStatsListProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
7
|
+
default?: (props: {}) => any;
|
|
8
|
+
}>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
11
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
12
|
+
new (): {
|
|
13
|
+
$slots: S;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<dt class="sr-only">
|
|
3
|
+
<slot name="label">
|
|
4
|
+
{{ props.label }}
|
|
5
|
+
</slot>
|
|
6
|
+
</dt>
|
|
7
|
+
|
|
8
|
+
<dd>
|
|
9
|
+
<slot name="default">
|
|
10
|
+
<IconTextPair :icon="props.icon" :text="props.description">
|
|
11
|
+
<template #default v-if="slots.description">
|
|
12
|
+
<slot name="description" />
|
|
13
|
+
</template>
|
|
14
|
+
</IconTextPair>
|
|
15
|
+
</slot>
|
|
16
|
+
</dd>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
import IconTextPair from "./IconTextPair.vue";
|
|
25
|
+
import { useSlots } from "vue";
|
|
26
|
+
defineOptions({
|
|
27
|
+
inheritAttrs: false
|
|
28
|
+
});
|
|
29
|
+
const props = defineProps({
|
|
30
|
+
label: { type: String, required: true },
|
|
31
|
+
description: { type: String, required: true },
|
|
32
|
+
icon: { type: String, required: false, default: void 0 }
|
|
33
|
+
});
|
|
34
|
+
const slots = useSlots();
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<style scoped>
|
|
38
|
+
@reference "tailwindcss";dd{padding-inline-start:var(--stats-list-spacer-width);position:relative}dd:before{color:var(--color-global-foreground-accent);content:"|";inset-inline-start:0;margin-inline:--spacing(2);position:absolute}
|
|
39
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface InlineStatsListItemProps {
|
|
2
|
+
label: string;
|
|
3
|
+
description: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<InlineStatsListItemProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<InlineStatsListItemProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
7
|
+
label?: (props: {}) => any;
|
|
8
|
+
} & {
|
|
9
|
+
default?: (props: {}) => any;
|
|
10
|
+
} & {
|
|
11
|
+
description?: (props: {}) => any;
|
|
12
|
+
}>;
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|
|
15
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
16
|
+
new (): {
|
|
17
|
+
$slots: S;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ol v-if="props.toc?.length">
|
|
3
|
+
<li v-for="entry of props.toc" :key="entry.slug">
|
|
4
|
+
<a :href="`#${entry.slug}`" v-html="entry.text" />
|
|
5
|
+
<TableOfContents v-if="entry.children.length" :toc="entry.children" />
|
|
6
|
+
</li>
|
|
7
|
+
</ol>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import TableOfContents from "./TableOfContents.vue";
|
|
16
|
+
const props = defineProps({
|
|
17
|
+
toc: { type: null, required: true }
|
|
18
|
+
});
|
|
19
|
+
</script>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TableOfContents as TableOfContentsOptions } from '@resee-movies/utilities/dom/generate-table-of-contents';
|
|
2
|
+
export type UiTableOfContentsProps = {
|
|
3
|
+
toc: TableOfContentsOptions[] | null | undefined;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<UiTableOfContentsProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<UiTableOfContentsProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
+
declare const _default: typeof __VLS_export;
|
|
7
|
+
export default _default;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
<PrimeForm
|
|
24
24
|
v-slot = "$form"
|
|
25
25
|
v-bind = "$attrs"
|
|
26
|
+
:id = "formUid"
|
|
26
27
|
ref = "form"
|
|
27
28
|
novalidate = "true"
|
|
28
29
|
:validate-on-mount = "true"
|
|
@@ -54,7 +55,7 @@ import PrimeForm, {} from "@primevue/forms/form";
|
|
|
54
55
|
import { toNonNullableArray } from "@resee-movies/utilities/arrays/to-non-nullable-array";
|
|
55
56
|
import { isPromiseLike } from "@resee-movies/utilities/objects/is-promise-like";
|
|
56
57
|
import { syncRefs } from "@vueuse/core";
|
|
57
|
-
import { ref, useTemplateRef } from "vue";
|
|
58
|
+
import { ref, useId, useTemplateRef } from "vue";
|
|
58
59
|
import FormFieldBuilder from "./FormFieldBuilder.vue";
|
|
59
60
|
import LazySuccessSplash from "../SuccessSplash.vue";
|
|
60
61
|
import LazyMessage from "../Message.vue";
|
|
@@ -76,8 +77,9 @@ const form = useTemplateRef("form");
|
|
|
76
77
|
const values = defineModel("values", { type: null, ...{ default: void 0 } });
|
|
77
78
|
const success = ref(false);
|
|
78
79
|
const errors = ref();
|
|
80
|
+
const formUid = useId();
|
|
79
81
|
defineEmits(["submit", "change"]);
|
|
80
|
-
const formInstance = provideFormInstance();
|
|
82
|
+
const formInstance = provideFormInstance(formUid);
|
|
81
83
|
syncRefs(() => props.disabled, formInstance.isDisabled);
|
|
82
84
|
useReactiveObjectsSync({
|
|
83
85
|
left: () => form.value?.states,
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
:readonly = "isReadonly"
|
|
43
43
|
:value = "$field.value"
|
|
44
44
|
:invalid = "$field.invalid"
|
|
45
|
-
:on-blur = "$field.props
|
|
46
|
-
:on-change = "$field.props
|
|
47
|
-
:on-input = "$field.props
|
|
48
|
-
:on-invalid = "$field.props
|
|
45
|
+
:on-blur = "$field.props?.onBlur"
|
|
46
|
+
:on-change = "$field.props?.onChange"
|
|
47
|
+
:on-input = "$field.props?.onInput"
|
|
48
|
+
:on-invalid = "$field.props?.onInvalid"
|
|
49
49
|
/>
|
|
50
50
|
</template>
|
|
51
51
|
</FormLabelInputPair>
|
|
@@ -87,9 +87,9 @@ const props = defineProps({
|
|
|
87
87
|
class: { type: null, required: false }
|
|
88
88
|
});
|
|
89
89
|
const formState = injectFormInstance();
|
|
90
|
-
const inputId =
|
|
91
|
-
const labelId = `${
|
|
92
|
-
const messageId = `${
|
|
90
|
+
const inputId = computed(() => `${formState.formUid}_${props.name}_field`);
|
|
91
|
+
const labelId = computed(() => `${formState.formUid}_${props.name}_label`);
|
|
92
|
+
const messageId = computed(() => `${formState.formUid}_${props.name}_message`);
|
|
93
93
|
const labelText = computed(() => props.label ?? humanize(props.name));
|
|
94
94
|
const isDisabled = computed(() => props.disabled || formState.isDisabled.value);
|
|
95
95
|
const isReadonly = computed(() => props.readonly || formState.isSubmitting.value);
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
<slot name="label" />
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
|
-
<template #default="{ inputName, onChange }">
|
|
7
|
+
<template #default="{ inputId, inputName, onChange }">
|
|
8
8
|
<FormElementTurnstile
|
|
9
|
+
:id = "inputId"
|
|
9
10
|
:sitekey = "props.sitekey"
|
|
10
11
|
:response-field-name = "inputName"
|
|
11
12
|
:callback = "(token) => onChange({ value: token })"
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { onUnmounted, useId } from "#imports";
|
|
17
17
|
import { useCloudflareTurnstile } from "../../../composables/use-cloudflare-turnstile";
|
|
18
18
|
const props = defineProps({
|
|
19
|
+
id: { type: String, required: false },
|
|
19
20
|
sitekey: { type: String, required: true },
|
|
20
21
|
action: { type: String, required: false },
|
|
21
22
|
cData: { type: String, required: false },
|
|
@@ -40,7 +41,7 @@ const props = defineProps({
|
|
|
40
41
|
appearance: { type: String, required: false, default: "always" },
|
|
41
42
|
"feedback-enabled": { type: Boolean, required: false }
|
|
42
43
|
});
|
|
43
|
-
const widgetId = useId();
|
|
44
|
+
const widgetId = props.id ?? useId();
|
|
44
45
|
const { onReady } = useCloudflareTurnstile();
|
|
45
46
|
let turnstile = void 0;
|
|
46
47
|
onReady((ts) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TurnstileRenderOptions } from '../../../composables/use-cloudflare-turnstile.js';
|
|
2
2
|
export interface FormElementTurnstileProps extends TurnstileRenderOptions {
|
|
3
|
+
id?: string;
|
|
3
4
|
}
|
|
4
5
|
declare const __VLS_export: import("vue").DefineComponent<FormElementTurnstileProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FormElementTurnstileProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
5
6
|
declare const _default: typeof __VLS_export;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { breakpointsTailwind } from '@vueuse/core';
|
|
2
|
+
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
3
|
+
export type BreakpointSettingName = (keyof typeof breakpointsTailwind) | 'default';
|
|
4
|
+
export type BreakpointSettings<T> = Partial<Record<BreakpointSettingName, T>>;
|
|
5
|
+
/**
|
|
6
|
+
* Given an object whose properties are Tailwind breakpoint names, this will return
|
|
7
|
+
* the value of the property that matches the active breakpoint. If an exact match
|
|
8
|
+
* is not available, a mobile-first approach is taken - the first value of a smaller
|
|
9
|
+
* breakpoint, or finally the `default`, will be returned.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useSettingsForBreakpoint<T>(settings: MaybeRefOrGetter<BreakpointSettings<T> | null | undefined>): ComputedRef<T | undefined>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { computed, toValue } from "vue";
|
|
2
|
+
import { useReseeBreakpoints } from "./use-resee-breakpoints.js";
|
|
3
|
+
export function useSettingsForBreakpoint(settings) {
|
|
4
|
+
const ordering = ["default", "sm", "md", "lg", "xl", "2xl"];
|
|
5
|
+
const activeBreak = useReseeBreakpoints().active();
|
|
6
|
+
return computed(() => {
|
|
7
|
+
const breakpoint = activeBreak.value || "default";
|
|
8
|
+
const rawSettings = toValue(settings);
|
|
9
|
+
if (!rawSettings) {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
if (breakpoint in rawSettings) {
|
|
13
|
+
return rawSettings[breakpoint];
|
|
14
|
+
}
|
|
15
|
+
let idx = ordering.indexOf(breakpoint);
|
|
16
|
+
while (idx > 0) {
|
|
17
|
+
idx -= 1;
|
|
18
|
+
const name = ordering[idx];
|
|
19
|
+
if (name && name in rawSettings) {
|
|
20
|
+
return rawSettings[name];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return rawSettings["default"];
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer base{:root{--image-mask-gradient-opacity-dir:to bottom;--image-mask-gradient-opacity-stop:85%;--image-mask-gradient-dir:to bottom;--image-mask-gradient-stop:80%;--image-mask-color:var(--color-global-background);--image-mask-alpha-percent:85%}}@utility image-mask-washout{@apply relative before:z-1 before:absolute before:inset-0;&:before{background:--alpha(var(--image-mask-color)/var(--image-mask-alpha-percent))}}@utility image-mask-gradient-washout{@apply relative before:z-1 before:absolute before:inset-0;&:before{background:linear-gradient(var(--image-mask-gradient-dir),--alpha(var(--image-mask-color)/var(--image-mask-alpha-percent)) var(--image-mask-gradient-stop),var(--image-mask-color))}}@utility image-mask-gradient-washout-lite{@apply relative before:z-1 before:absolute before:inset-0;--image-mask-alpha-percent:10%;--image-mask-gradient-stop:30%;&:before{background:linear-gradient(var(--image-mask-gradient-dir),--alpha(var(--image-mask-color)/var(--image-mask-alpha-percent)) var(--image-mask-gradient-stop),var(--image-mask-color))}}@utility image-mask-gradient-opacity{-webkit-mask-image:linear-gradient(var(--image-mask-gradient-opacity-dir),#000 var(--image-mask-gradient-opacity-stop),transparent);mask-image:linear-gradient(var(--image-mask-gradient-opacity-dir),#000 var(--image-mask-gradient-opacity-stop),transparent)}@utility image-mask-hero{@apply relative before:z-1 before:absolute before:inset-0;--image-mask-color:#fff;@variant dark{--image-mask-color:#000}&:before{background:--alpha(var(--image-mask-color)/75%);@variant sm{background:linear-gradient(to right,--alpha(var(--image-mask-color)/90%) 35%,--alpha(var(--image-mask-color)/15%))}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import "./brand/anchor.css";@import "./brand/application.css";@import "./brand/button.css";@import "./brand/form.css";@import "./brand/gradient.css";@import "./brand/menu.css";@import "./brand/mobile.css";@import "./brand/status.css";@import "./brand/theme.css";@import "./brand/tooltip.css";@import "./brand/transition.css";@import "./brand/typography.css";@import "./brand/utilities.css";
|
|
1
|
+
@import "./brand/anchor.css";@import "./brand/application.css";@import "./brand/button.css";@import "./brand/form.css";@import "./brand/gradient.css";@import "./brand/image.css";@import "./brand/menu.css";@import "./brand/mobile.css";@import "./brand/status.css";@import "./brand/theme.css";@import "./brand/tooltip.css";@import "./brand/transition.css";@import "./brand/typography.css";@import "./brand/utilities.css";
|
|
@@ -13,21 +13,21 @@ export declare const FormSymbol: InjectionKey<FormInstance>;
|
|
|
13
13
|
*
|
|
14
14
|
* @private
|
|
15
15
|
*/
|
|
16
|
-
export declare function createFormInstance(): FormInstance;
|
|
16
|
+
export declare function createFormInstance(uid?: string): FormInstance;
|
|
17
17
|
/**
|
|
18
18
|
* Provides the object that a Form uses to convey stateful information to the
|
|
19
19
|
* DI registry. You shouldn't ever need to use this directly.
|
|
20
20
|
*
|
|
21
21
|
* @private
|
|
22
22
|
*/
|
|
23
|
-
export declare function provideFormInstance(): FormInstance;
|
|
23
|
+
export declare function provideFormInstance(uid?: string): FormInstance;
|
|
24
24
|
/**
|
|
25
25
|
* Injects the stateful object provided by an ancestor Form instance. If not
|
|
26
26
|
* available, a dummy state object is generated.
|
|
27
27
|
*
|
|
28
28
|
* @private
|
|
29
29
|
*/
|
|
30
|
-
export declare function injectFormInstance(): FormInstance;
|
|
30
|
+
export declare function injectFormInstance(uid?: string): FormInstance;
|
|
31
31
|
/**
|
|
32
32
|
* Takes a Primevue Form's `states` object, and extracts the current values
|
|
33
33
|
* of each named property. In doing so, it will deref proxies, and create
|
|
@@ -4,20 +4,21 @@ import { isObjectLike } from "@resee-movies/utilities/objects/is-object-like";
|
|
|
4
4
|
import { isString } from "@resee-movies/utilities/strings/is-string";
|
|
5
5
|
import { computed, inject, provide, ref, toRaw, toValue } from "vue";
|
|
6
6
|
export const FormSymbol = Symbol("form");
|
|
7
|
-
export function createFormInstance() {
|
|
7
|
+
export function createFormInstance(uid) {
|
|
8
8
|
return {
|
|
9
|
+
formUid: uid,
|
|
9
10
|
hasSubmitted: ref(false),
|
|
10
11
|
isSubmitting: ref(false),
|
|
11
12
|
isDisabled: ref(false)
|
|
12
13
|
};
|
|
13
14
|
}
|
|
14
|
-
export function provideFormInstance() {
|
|
15
|
-
const instance = createFormInstance();
|
|
15
|
+
export function provideFormInstance(uid) {
|
|
16
|
+
const instance = createFormInstance(uid);
|
|
16
17
|
provide(FormSymbol, instance);
|
|
17
18
|
return instance;
|
|
18
19
|
}
|
|
19
|
-
export function injectFormInstance() {
|
|
20
|
-
return inject(FormSymbol, () => createFormInstance(), true);
|
|
20
|
+
export function injectFormInstance(uid) {
|
|
21
|
+
return inject(FormSymbol, () => createFormInstance(uid), true);
|
|
21
22
|
}
|
|
22
23
|
export function getValuesFromFormState(state) {
|
|
23
24
|
const result = {};
|
package/package.json
CHANGED