@m11g/library 0.0.2 → 0.0.3
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/dist-C8cpIyO1.js +3039 -0
- package/dist/library.css +2 -0
- package/dist/library.js +4057 -0
- package/dist/library.umd.cjs +3 -0
- package/package.json +13 -1
- package/.editorconfig +0 -8
- package/.gitattributes +0 -1
- package/.oxfmtrc.json +0 -5
- package/.oxlintrc.json +0 -10
- package/.stylelintrc +0 -33
- package/.vscode/extensions.json +0 -8
- package/env.d.ts +0 -1
- package/eslint.config.ts +0 -35
- package/index.html +0 -13
- package/postcss.config.ts +0 -23
- package/src/App.vue +0 -28
- package/src/assets/css/base.css +0 -2
- package/src/assets/css/elements/_base.css +0 -5
- package/src/assets/css/elements/buttons.css +0 -23
- package/src/assets/css/elements/form.css +0 -75
- package/src/assets/css/elements/scaffolding.css +0 -62
- package/src/assets/css/elements/transition.css +0 -4
- package/src/assets/css/elements/typography.css +0 -80
- package/src/assets/css/media-queries/media-queries.css +0 -3
- package/src/assets/css/mixins/list-reset.css +0 -5
- package/src/assets/css/variables/_base.css +0 -7
- package/src/assets/css/variables/chakra.css +0 -160
- package/src/assets/css/variables/colors.css +0 -205
- package/src/assets/css/variables/grid.css +0 -6
- package/src/assets/css/variables/spacings.css +0 -10
- package/src/assets/css/variables/transitions.css +0 -10
- package/src/assets/css/variables/typography.css +0 -17
- package/src/components/AppBreadcrumb.vue +0 -63
- package/src/components/AppButton.vue +0 -105
- package/src/components/AppCarousel.vue +0 -145
- package/src/components/AppDialog.vue +0 -126
- package/src/components/AppNotification.vue +0 -68
- package/src/components/AppPagination.vue +0 -127
- package/src/components/AppPopover.vue +0 -57
- package/src/components/AppTabs.vue +0 -176
- package/src/components/CenterWrapper.vue +0 -50
- package/src/components/ClickableWrapper.vue +0 -48
- package/src/components/Forms/AppForm.vue +0 -61
- package/src/components/Forms/FormErrorMessage.vue +0 -17
- package/src/components/Forms/FormField.vue +0 -30
- package/src/components/Forms/FormFieldset.vue +0 -28
- package/src/components/Forms/RadioGroup.vue +0 -85
- package/src/components/Forms/SearchField.vue +0 -38
- package/src/components/Forms/SelectField.vue +0 -125
- package/src/components/Forms/TextField.vue +0 -41
- package/src/components/Forms/TextareaField.vue +0 -32
- package/src/components/ScrollSpy.vue +0 -111
- package/src/components/SummaryDetails.vue +0 -83
- package/src/composables/useTheme.ts +0 -20
- package/src/index.ts +0 -47
- package/src/main.ts +0 -10
- package/src/router/index.ts +0 -26
- package/src/types/Theme.ts +0 -11
- package/src/views/CarouselView.vue +0 -27
- package/src/views/FormView.vue +0 -111
- package/src/views/HomeView.vue +0 -100
- package/src/views/ScrollSpyView.vue +0 -58
- package/theme-dark +0 -117
- package/theme-light +0 -191
- package/tsconfig.app.json +0 -18
- package/tsconfig.json +0 -11
- package/tsconfig.node.json +0 -28
- package/vite.config.ts +0 -26
- /package/{public → dist}/favicon.ico +0 -0
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import useTheme from "@/composables/useTheme";
|
|
3
|
-
import { computed, ref, useId, useTemplateRef } from "vue";
|
|
4
|
-
|
|
5
|
-
const props = defineProps<{
|
|
6
|
-
tabs: {
|
|
7
|
-
id: string;
|
|
8
|
-
title: string;
|
|
9
|
-
}[];
|
|
10
|
-
}>();
|
|
11
|
-
|
|
12
|
-
const selectedTab = ref(0);
|
|
13
|
-
|
|
14
|
-
const id = useId();
|
|
15
|
-
|
|
16
|
-
const anchor = computed(() => `--${id}`);
|
|
17
|
-
|
|
18
|
-
const nextTab = () => {
|
|
19
|
-
if (selectedTab.value === props.tabs.length - 1) {
|
|
20
|
-
goToTab(0);
|
|
21
|
-
} else {
|
|
22
|
-
goToTab(selectedTab.value + 1);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const previousTab = () => {
|
|
27
|
-
if (selectedTab.value === 0) {
|
|
28
|
-
goToTab(props.tabs.length - 1);
|
|
29
|
-
} else {
|
|
30
|
-
goToTab(selectedTab.value - 1);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const firstTab = () => {
|
|
35
|
-
goToTab(0);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const lastTab = () => {
|
|
39
|
-
goToTab(props.tabs.length - 1);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const tabButtons = useTemplateRef("button");
|
|
43
|
-
|
|
44
|
-
const goToTab = (tab: number) => {
|
|
45
|
-
if (tabButtons.value?.length && tabButtons.value[tab]) {
|
|
46
|
-
tabButtons.value[tab].focus();
|
|
47
|
-
}
|
|
48
|
-
selectedTab.value = tab;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const total = computed(() => {
|
|
52
|
-
return props.tabs.length;
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const {colors} = useTheme()
|
|
56
|
-
</script>
|
|
57
|
-
|
|
58
|
-
<template>
|
|
59
|
-
<div class="tabs">
|
|
60
|
-
<ul role="tablist">
|
|
61
|
-
<li v-for="(tab, index) in tabs" :key="tab.id" role="presentation">
|
|
62
|
-
<button
|
|
63
|
-
:id="`tab-${tab.id}`"
|
|
64
|
-
ref="button"
|
|
65
|
-
type="button"
|
|
66
|
-
role="tab"
|
|
67
|
-
:aria-selected="selectedTab === index"
|
|
68
|
-
:aria-controls="`panel-${tab.id}`"
|
|
69
|
-
:tabindex="selectedTab === index ? undefined : '-1'"
|
|
70
|
-
@keydown.right="nextTab"
|
|
71
|
-
@keydown.left="previousTab"
|
|
72
|
-
@keydown.home="firstTab"
|
|
73
|
-
@keydown.end="lastTab"
|
|
74
|
-
@click="selectedTab = index"
|
|
75
|
-
>
|
|
76
|
-
{{ tab.title }}
|
|
77
|
-
</button>
|
|
78
|
-
</li>
|
|
79
|
-
</ul>
|
|
80
|
-
<div class="panel">
|
|
81
|
-
<div
|
|
82
|
-
v-for="(tab, index) in tabs"
|
|
83
|
-
:id="`panel-${tab.id}`"
|
|
84
|
-
:key="tab.id"
|
|
85
|
-
:aria-labelledby="`tab-${tab.id}`"
|
|
86
|
-
role="tabpanel"
|
|
87
|
-
tabindex="0"
|
|
88
|
-
:class="{
|
|
89
|
-
active: selectedTab === index,
|
|
90
|
-
}"
|
|
91
|
-
>
|
|
92
|
-
<slot :name="tab.id" />
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
</template>
|
|
97
|
-
|
|
98
|
-
<style lang="css">
|
|
99
|
-
@scope (.tabs) {
|
|
100
|
-
:scope {
|
|
101
|
-
margin-block-end: var(--spacing-4);
|
|
102
|
-
container-type: inline-size;
|
|
103
|
-
transition:
|
|
104
|
-
height var(--transition),
|
|
105
|
-
content-visibility var(--transition) allow-discrete;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
ul {
|
|
109
|
-
display: grid;
|
|
110
|
-
grid-template-columns: repeat(v-bind(total), 1fr);
|
|
111
|
-
padding: 0;
|
|
112
|
-
margin: 0 0 var(--spacing-4);
|
|
113
|
-
list-style: none outside;
|
|
114
|
-
border-block-end: 1px solid v-bind(colors.subtle);
|
|
115
|
-
|
|
116
|
-
&::before {
|
|
117
|
-
position: absolute;
|
|
118
|
-
inset-block-end: anchor(bottom);
|
|
119
|
-
inset-inline-start: anchor(left);
|
|
120
|
-
display: block;
|
|
121
|
-
/* stylelint-disable-next-line declaration-property-value-no-unknown */
|
|
122
|
-
inline-size: anchor-size(inline);
|
|
123
|
-
/* stylelint-disable-next-line declaration-property-value-no-unknown */
|
|
124
|
-
block-size: anchor-size(block);
|
|
125
|
-
position-anchor: v-bind(anchor);
|
|
126
|
-
content: "";
|
|
127
|
-
background: v-bind(colors.emphasized);
|
|
128
|
-
|
|
129
|
-
/* background: v-bind(colors.muted); */
|
|
130
|
-
transition:
|
|
131
|
-
left var(--transition),
|
|
132
|
-
width var(--transition);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
[role="tab"] {
|
|
137
|
-
position: relative;
|
|
138
|
-
inline-size: 100%;
|
|
139
|
-
padding: var(--spacing-3) var(--spacing-2);
|
|
140
|
-
text-align: center;
|
|
141
|
-
transition: background var(--transition);
|
|
142
|
-
|
|
143
|
-
&:hover:not([aria-selected="true"]) {
|
|
144
|
-
color: v-bind(colors.fg);
|
|
145
|
-
background-color: v-bind(colors.subtle);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
&[aria-selected="true"] {
|
|
149
|
-
anchor-name: v-bind(anchor);
|
|
150
|
-
color: v-bind(colors.fg);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
[role="tabpanel"] {
|
|
155
|
-
display: none;
|
|
156
|
-
opacity: 0;
|
|
157
|
-
transition:
|
|
158
|
-
opacity var(--transition),
|
|
159
|
-
overlay allow-discrete,
|
|
160
|
-
display allow-discrete;
|
|
161
|
-
|
|
162
|
-
&.active {
|
|
163
|
-
display: block;
|
|
164
|
-
opacity: 1;
|
|
165
|
-
transition-delay: 0.1s;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
@starting-style {
|
|
170
|
-
[role="tabpanel"].active {
|
|
171
|
-
opacity: 0;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
</style>
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
withDefaults(
|
|
3
|
-
defineProps<{
|
|
4
|
-
size?: "full" | "md" | "lg" | "sm";
|
|
5
|
-
top?: boolean;
|
|
6
|
-
}>(),
|
|
7
|
-
{
|
|
8
|
-
top: false,
|
|
9
|
-
size: "lg",
|
|
10
|
-
},
|
|
11
|
-
);
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<template>
|
|
15
|
-
<div class="notch" :class="{ top }">
|
|
16
|
-
<div class="wrapper" :class="`wrapper-${size}`">
|
|
17
|
-
<slot />
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
</template>
|
|
21
|
-
|
|
22
|
-
<style lang="css" scoped>
|
|
23
|
-
.notch {
|
|
24
|
-
padding: 0 env(safe-area-inset-right) 0 env(safe-area-inset-left);
|
|
25
|
-
|
|
26
|
-
&.top {
|
|
27
|
-
padding-block-start: env(safe-area-inset-top);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.wrapper-sm {
|
|
32
|
-
--wrapper-size: var(--container-size-sm);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.wrapper-md {
|
|
36
|
-
--wrapper-size: var(--container-size-md);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.wrapper-lg {
|
|
40
|
-
--wrapper-size: var(--container-size-lg);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.wrapper {
|
|
44
|
-
/* stylelint-disable-next-line length-zero-no-unit */
|
|
45
|
-
--zero: 0px;
|
|
46
|
-
|
|
47
|
-
padding-inline: var(--gutter);
|
|
48
|
-
margin-inline: max(var(--zero), ((100% - var(--wrapper-size)) / 2));
|
|
49
|
-
}
|
|
50
|
-
</style>
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { ref, type Ref } from "vue";
|
|
3
|
-
import { useRouter, type RouteLocationRaw } from "vue-router";
|
|
4
|
-
|
|
5
|
-
const props = withDefaults(
|
|
6
|
-
defineProps<{
|
|
7
|
-
to: RouteLocationRaw;
|
|
8
|
-
tag?: "div" | "li";
|
|
9
|
-
}>(),
|
|
10
|
-
{
|
|
11
|
-
tag: "li",
|
|
12
|
-
},
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
const down: Ref<number | null> = ref(null);
|
|
16
|
-
|
|
17
|
-
const router = useRouter();
|
|
18
|
-
|
|
19
|
-
const mouseDown = (event: MouseEvent) => {
|
|
20
|
-
const target = event.target as Element;
|
|
21
|
-
if (target.nodeName.toUpperCase() === "A" || target.parentNode?.nodeName.toUpperCase() === "A") {
|
|
22
|
-
down.value = null;
|
|
23
|
-
} else {
|
|
24
|
-
down.value = +new Date();
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
const mouseUp = async () => {
|
|
28
|
-
if (!down.value) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const up = +new Date();
|
|
32
|
-
if (up - down.value < 200) {
|
|
33
|
-
await router.push(props.to);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
</script>
|
|
37
|
-
|
|
38
|
-
<template>
|
|
39
|
-
<component :is="tag" class="item" @mousedown.left="mouseDown" @mouseup.left="mouseUp">
|
|
40
|
-
<slot />
|
|
41
|
-
</component>
|
|
42
|
-
</template>
|
|
43
|
-
|
|
44
|
-
<style lang="css" scoped>
|
|
45
|
-
.item {
|
|
46
|
-
cursor: pointer;
|
|
47
|
-
}
|
|
48
|
-
</style>
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import type { FormErrors } from "vee-validate";
|
|
3
|
-
import AppButton from "@/components/AppButton.vue";
|
|
4
|
-
import AppNotification from "@/components/AppNotification.vue";
|
|
5
|
-
import { computed, ref } from "vue";
|
|
6
|
-
|
|
7
|
-
const props = defineProps<{
|
|
8
|
-
buttonTitle: string;
|
|
9
|
-
successText: string;
|
|
10
|
-
status: "idle" | "pending" | "success" | "error";
|
|
11
|
-
errors: FormErrors<Record<string, string>>;
|
|
12
|
-
}>();
|
|
13
|
-
|
|
14
|
-
const emit = defineEmits<{
|
|
15
|
-
(event: "submit-form"): void;
|
|
16
|
-
}>();
|
|
17
|
-
|
|
18
|
-
const errorList = computed(() => {
|
|
19
|
-
return Object.values(props.errors);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const touched = ref(false);
|
|
23
|
-
|
|
24
|
-
const submit = () => {
|
|
25
|
-
touched.value = true;
|
|
26
|
-
emit("submit-form");
|
|
27
|
-
};
|
|
28
|
-
</script>
|
|
29
|
-
|
|
30
|
-
<template>
|
|
31
|
-
<app-notification v-if="status === 'success'" :title="successText" variant="success" />
|
|
32
|
-
<form v-else method="post" novalidate @submit.prevent="submit">
|
|
33
|
-
<slot />
|
|
34
|
-
<div aria-live="assertive">
|
|
35
|
-
<app-notification
|
|
36
|
-
v-if="errorList.length && touched"
|
|
37
|
-
variant="warning"
|
|
38
|
-
title="Het formulier is niet correct ingevuld"
|
|
39
|
-
>
|
|
40
|
-
<ul>
|
|
41
|
-
<li v-for="error in errors" :key="error">
|
|
42
|
-
{{ error }}
|
|
43
|
-
</li>
|
|
44
|
-
</ul>
|
|
45
|
-
</app-notification>
|
|
46
|
-
</div>
|
|
47
|
-
<app-button :title="buttonTitle" type="submit" :disabled="status === 'pending'" />
|
|
48
|
-
</form>
|
|
49
|
-
</template>
|
|
50
|
-
|
|
51
|
-
<style lang="css" scoped>
|
|
52
|
-
ul {
|
|
53
|
-
padding-inline-start: 0;
|
|
54
|
-
margin: 0;
|
|
55
|
-
list-style: none outside;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
[aria-live="assertive"]:not(:empty) {
|
|
59
|
-
margin-block-start: var(--spacing-4);
|
|
60
|
-
}
|
|
61
|
-
</style>
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
defineProps<{
|
|
3
|
-
errorMessage?: string;
|
|
4
|
-
}>();
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
|
-
<template>
|
|
8
|
-
<div aria-live="assertive">
|
|
9
|
-
{{ errorMessage }}
|
|
10
|
-
</div>
|
|
11
|
-
</template>
|
|
12
|
-
|
|
13
|
-
<style lang="css" scoped>
|
|
14
|
-
span {
|
|
15
|
-
display: block;
|
|
16
|
-
}
|
|
17
|
-
</style>
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import FormErrorMessage from "./FormErrorMessage.vue";
|
|
3
|
-
|
|
4
|
-
defineProps<{
|
|
5
|
-
id: string;
|
|
6
|
-
title: string;
|
|
7
|
-
errorMessage?: string;
|
|
8
|
-
}>();
|
|
9
|
-
</script>
|
|
10
|
-
|
|
11
|
-
<template>
|
|
12
|
-
<div>
|
|
13
|
-
<label :for="id" class="label">
|
|
14
|
-
{{ title }}
|
|
15
|
-
</label>
|
|
16
|
-
<slot />
|
|
17
|
-
<form-error-message :error-message="errorMessage" class="error-message" />
|
|
18
|
-
</div>
|
|
19
|
-
</template>
|
|
20
|
-
|
|
21
|
-
<style lang="css" scoped>
|
|
22
|
-
label {
|
|
23
|
-
margin-block-end: var(--spacing-xxs);
|
|
24
|
-
font-weight: var(--font-weight-bold);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.error-message {
|
|
28
|
-
margin-block-start: var(--spacing-xxs);
|
|
29
|
-
}
|
|
30
|
-
</style>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
withDefaults(
|
|
3
|
-
defineProps<{
|
|
4
|
-
title: string;
|
|
5
|
-
columns?: number;
|
|
6
|
-
}>(),
|
|
7
|
-
{
|
|
8
|
-
columns: 1,
|
|
9
|
-
},
|
|
10
|
-
);
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<template>
|
|
14
|
-
<fieldset>
|
|
15
|
-
<legend>
|
|
16
|
-
{{ title }}
|
|
17
|
-
</legend>
|
|
18
|
-
<slot />
|
|
19
|
-
</fieldset>
|
|
20
|
-
</template>
|
|
21
|
-
|
|
22
|
-
<style lang="css" scoped>
|
|
23
|
-
fieldset {
|
|
24
|
-
display: grid;
|
|
25
|
-
grid-template-columns: repeat(v-bind(columns), 1fr);
|
|
26
|
-
gap: var(--gutter);
|
|
27
|
-
}
|
|
28
|
-
</style>
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { useField } from "vee-validate";
|
|
3
|
-
import { toRefs, useId } from "vue";
|
|
4
|
-
import FormErrorMessage from "./FormErrorMessage.vue";
|
|
5
|
-
import useTheme from "@/composables/useTheme.ts";
|
|
6
|
-
|
|
7
|
-
const props = defineProps<{
|
|
8
|
-
// type: 'directors' | 'authors'
|
|
9
|
-
name: string;
|
|
10
|
-
title: string;
|
|
11
|
-
options: {
|
|
12
|
-
value: string | number;
|
|
13
|
-
title: string;
|
|
14
|
-
}[];
|
|
15
|
-
}>();
|
|
16
|
-
|
|
17
|
-
const id = useId();
|
|
18
|
-
|
|
19
|
-
const { name } = toRefs(props);
|
|
20
|
-
|
|
21
|
-
// we don't provide any rules here because we are using form-level validation
|
|
22
|
-
// https://vee-validate.logaretm.com/v4/guide/validation#form-level-validation
|
|
23
|
-
const { value, handleChange, errorMessage } = useField<string>(name);
|
|
24
|
-
|
|
25
|
-
const validationListeners = {
|
|
26
|
-
change: handleChange,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const { colors } = useTheme()
|
|
30
|
-
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
|
-
<template>
|
|
34
|
-
<fieldset>
|
|
35
|
-
<legend>{{ title }}</legend>
|
|
36
|
-
<div class="fields">
|
|
37
|
-
<div v-for="(option, index) in options" :key="option.value" class="field">
|
|
38
|
-
<input
|
|
39
|
-
:id="`${id}-${index}`"
|
|
40
|
-
type="radio"
|
|
41
|
-
:checked="value === option.value"
|
|
42
|
-
:name
|
|
43
|
-
:value="option.value"
|
|
44
|
-
v-on="validationListeners"
|
|
45
|
-
/>
|
|
46
|
-
<label :for="`${id}-${index}`">
|
|
47
|
-
{{ option.title }}
|
|
48
|
-
</label>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
<form-error-message :error-message="errorMessage" />
|
|
52
|
-
</fieldset>
|
|
53
|
-
</template>
|
|
54
|
-
|
|
55
|
-
<style lang="css" scoped>
|
|
56
|
-
.field {
|
|
57
|
-
display: flex;
|
|
58
|
-
gap: var(--spacing-2);
|
|
59
|
-
align-items: start;
|
|
60
|
-
|
|
61
|
-
&:not(:last-child) {
|
|
62
|
-
margin-block-end: var(--spacing-1);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
input {
|
|
67
|
-
flex: 0 0 auto;
|
|
68
|
-
inline-size: 1.25em;
|
|
69
|
-
aspect-ratio: 1;
|
|
70
|
-
padding: 0;
|
|
71
|
-
margin: 0;
|
|
72
|
-
margin-block-start: 0.1em;
|
|
73
|
-
appearance: none;
|
|
74
|
-
background: var(--color-panel-bg);
|
|
75
|
-
border: 3px solid var(--color-white);
|
|
76
|
-
border-radius: 50%;
|
|
77
|
-
transition:
|
|
78
|
-
border var(--transition),
|
|
79
|
-
background var(--transition);
|
|
80
|
-
|
|
81
|
-
&:checked {
|
|
82
|
-
background-color: v-bind(colors.solid);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
</style>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { Icon } from "@iconify/vue";
|
|
3
|
-
|
|
4
|
-
defineProps<{
|
|
5
|
-
placeholder?: string;
|
|
6
|
-
}>();
|
|
7
|
-
|
|
8
|
-
const model = defineModel<string>({
|
|
9
|
-
required: true,
|
|
10
|
-
});
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<template>
|
|
14
|
-
<div class="field">
|
|
15
|
-
<input v-model="model" :placeholder name="search" type="search" />
|
|
16
|
-
<icon icon="solar:minimalistic-magnifer-outline" />
|
|
17
|
-
</div>
|
|
18
|
-
</template>
|
|
19
|
-
|
|
20
|
-
<style lang="css" scoped>
|
|
21
|
-
.field {
|
|
22
|
-
position: relative;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
input {
|
|
26
|
-
padding-inline-end: 3rem;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
svg {
|
|
30
|
-
position: absolute;
|
|
31
|
-
inset-block-start: 50%;
|
|
32
|
-
inset-inline-end: var(--spacing-4);
|
|
33
|
-
inline-size: 1.5rem;
|
|
34
|
-
block-size: auto;
|
|
35
|
-
aspect-ratio: 1;
|
|
36
|
-
translate: 0 -0.75rem;
|
|
37
|
-
}
|
|
38
|
-
</style>
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { useField } from "vee-validate";
|
|
3
|
-
import { toRefs, useId } from "vue";
|
|
4
|
-
import FormField from "./FormField.vue";
|
|
5
|
-
import { Icon } from "@iconify/vue";
|
|
6
|
-
import useTheme from "@/composables/useTheme.ts";
|
|
7
|
-
|
|
8
|
-
const props = defineProps<{
|
|
9
|
-
// type: 'directors' | 'authors'
|
|
10
|
-
name: string;
|
|
11
|
-
title: string;
|
|
12
|
-
options: {
|
|
13
|
-
value: string | number;
|
|
14
|
-
title: string;
|
|
15
|
-
}[];
|
|
16
|
-
}>();
|
|
17
|
-
|
|
18
|
-
const id = useId();
|
|
19
|
-
|
|
20
|
-
const { name } = toRefs(props);
|
|
21
|
-
|
|
22
|
-
// we don't provide any rules here because we are using form-level validation
|
|
23
|
-
// https://vee-validate.logaretm.com/v4/guide/validation#form-level-validation
|
|
24
|
-
const { value, handleChange, errorMessage } = useField<string>(name, undefined, {
|
|
25
|
-
validateOnValueUpdate: false,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const validationListeners = {
|
|
29
|
-
change: handleChange,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const { colors } = useTheme()
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
<template>
|
|
36
|
-
<form-field :id :title :error-message>
|
|
37
|
-
<select :id :value :name v-on="validationListeners">
|
|
38
|
-
<button>
|
|
39
|
-
<selectedcontent />
|
|
40
|
-
<icon icon="solar:alt-arrow-down-outline" class="icon" />
|
|
41
|
-
</button>
|
|
42
|
-
<option v-for="option in options" :key="option.value" :value="option.value">
|
|
43
|
-
{{ option.title }}
|
|
44
|
-
</option>
|
|
45
|
-
</select>
|
|
46
|
-
</form-field>
|
|
47
|
-
</template>
|
|
48
|
-
|
|
49
|
-
<style lang="css" scoped>
|
|
50
|
-
.icon {
|
|
51
|
-
transition: rotate var(--transition);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
select {
|
|
55
|
-
appearance: base-select;
|
|
56
|
-
cursor: pointer;
|
|
57
|
-
|
|
58
|
-
&:open {
|
|
59
|
-
.icon {
|
|
60
|
-
rotate: -180deg;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
button {
|
|
66
|
-
display: flex;
|
|
67
|
-
gap: var(--spacing-2);
|
|
68
|
-
align-items: center;
|
|
69
|
-
justify-content: space-between;
|
|
70
|
-
inline-size: 100%;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
::checkmark {
|
|
74
|
-
display: none;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
::picker-icon {
|
|
78
|
-
display: none;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
::picker(select) {
|
|
82
|
-
margin-block-start: var(--spacing-1);
|
|
83
|
-
appearance: base-select;
|
|
84
|
-
border: 2px solid var(--color-white);
|
|
85
|
-
opacity: 0;
|
|
86
|
-
translate: 0 calc(-1 * var(--spacing-4));
|
|
87
|
-
transition:
|
|
88
|
-
translate var(--transition),
|
|
89
|
-
opacity var(--transition),
|
|
90
|
-
overlay var(--transition) allow-discrete,
|
|
91
|
-
display var(--transition) allow-discrete;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
:open::picker(select) {
|
|
95
|
-
opacity: 1;
|
|
96
|
-
translate: 0 0;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@starting-style {
|
|
100
|
-
:open::picker(select) {
|
|
101
|
-
opacity: 0;
|
|
102
|
-
translate: 0 calc(-1 * var(--spacing-4));
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
option {
|
|
107
|
-
display: flex;
|
|
108
|
-
gap: var(--spacing-2);
|
|
109
|
-
padding: var(--spacing-2);
|
|
110
|
-
color: var(--color-fg);
|
|
111
|
-
background-color: var(--color-body-background);
|
|
112
|
-
border-inline-start: 3px solid transparent;
|
|
113
|
-
|
|
114
|
-
&:hover {
|
|
115
|
-
color: v-bind(colors.fg);
|
|
116
|
-
background-color: var(--color-primary-hover);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
&:checked {
|
|
120
|
-
font-weight: var(--font-weight-bold);
|
|
121
|
-
color: v-bind(colors.fg);
|
|
122
|
-
background-color: var(--color-primary);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
</style>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { useField } from "vee-validate";
|
|
3
|
-
import { toRefs, useId, type InputTypeHTMLAttribute } from "vue";
|
|
4
|
-
import FormField from "./FormField.vue";
|
|
5
|
-
|
|
6
|
-
const props = withDefaults(
|
|
7
|
-
defineProps<{
|
|
8
|
-
type?: InputTypeHTMLAttribute;
|
|
9
|
-
autocomplete?: AutoFillField;
|
|
10
|
-
title: string;
|
|
11
|
-
name: string;
|
|
12
|
-
placeholder?: string;
|
|
13
|
-
}>(),
|
|
14
|
-
{
|
|
15
|
-
autocomplete: undefined,
|
|
16
|
-
type: "text",
|
|
17
|
-
placeholder: undefined,
|
|
18
|
-
},
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
const id = useId();
|
|
22
|
-
const { name } = toRefs(props);
|
|
23
|
-
|
|
24
|
-
// we don't provide any rules here because we are using form-level validation
|
|
25
|
-
// https://vee-validate.logaretm.com/v4/guide/validation#form-level-validation
|
|
26
|
-
const { value, handleBlur, handleChange, errorMessage } = useField<string>(name, undefined, {
|
|
27
|
-
validateOnValueUpdate: false,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const validationListeners = {
|
|
31
|
-
blur: (event: InputEvent) => handleBlur(event, true),
|
|
32
|
-
change: handleChange,
|
|
33
|
-
input: (event: InputEvent) => handleChange(event, !!errorMessage.value),
|
|
34
|
-
};
|
|
35
|
-
</script>
|
|
36
|
-
|
|
37
|
-
<template>
|
|
38
|
-
<form-field :id :title :error-message>
|
|
39
|
-
<input :id :name :type :autocomplete :value :placeholder v-on="validationListeners" />
|
|
40
|
-
</form-field>
|
|
41
|
-
</template>
|