srcdev-nuxt-components 0.0.24 → 0.0.26
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/assets/styles/utils/_page.css +1 -0
- package/components/functional/accordian/AccordianCore.vue +110 -0
- package/components/functional/display-dialog/DisplayDialogCore.vue +6 -4
- package/components/functional/pop-over/PopOver.vue +55 -31
- package/components/presentation/layout-row/stories/LayoutRow.mdx +8 -0
- package/components/presentation/layout-row/stories/LayoutRow.stories.ts +68 -0
- package/nuxt.config.ts +5 -0
- package/package.json +21 -10
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="display-accordian" :class="[elementClasses]">
|
|
3
|
+
<template v-for="(item, key) in data" :key="key">
|
|
4
|
+
<div class="accordion-panel">
|
|
5
|
+
<button class="accordion-trigger" :id="`accordian-${key}-trigger`" aria-expanded="false" :aria-controls="`accordian-${key}-content`" ref="triggerRefs" @click.stop.prevent="handleSummary(key)">
|
|
6
|
+
<slot :name="`accordian-${key}-trigger`"></slot>
|
|
7
|
+
</button>
|
|
8
|
+
|
|
9
|
+
<div class="accordion-content" :aria-labelledby="`accordian-${key}-trigger`" :id="`accordian-${key}-content`" role="region" aria-hidden="true" ref="contentRefs">
|
|
10
|
+
<div>
|
|
11
|
+
<slot :name="`accordian-${key}-content`"></slot>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
interface IAccordianData {
|
|
21
|
+
title: string;
|
|
22
|
+
content: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const props = defineProps({
|
|
26
|
+
data: {
|
|
27
|
+
type: Array as PropType<IAccordianData[]>,
|
|
28
|
+
default: () => [],
|
|
29
|
+
},
|
|
30
|
+
styleClassPassthrough: {
|
|
31
|
+
type: Array as PropType<string[]>,
|
|
32
|
+
default: () => [],
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
37
|
+
|
|
38
|
+
const triggerRefs = ref<HTMLElement[]>([]);
|
|
39
|
+
const contentRefs = ref<HTMLElement[]>([]);
|
|
40
|
+
|
|
41
|
+
onMounted(() => {
|
|
42
|
+
triggerRefs.value = Array.from(document.querySelectorAll('.accordion-trigger'));
|
|
43
|
+
contentRefs.value = Array.from(document.querySelectorAll('.accordion-content'));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const handleSummary = (clickedIndex: number) => {
|
|
47
|
+
triggerRefs.value.forEach((element, index) => {
|
|
48
|
+
if (clickedIndex === index) {
|
|
49
|
+
const currentState = element.getAttribute('aria-expanded');
|
|
50
|
+
const newState = currentState !== 'true';
|
|
51
|
+
triggerRefs.value[index].setAttribute('aria-expanded', String(newState));
|
|
52
|
+
contentRefs.value[index].setAttribute('aria-hidden', String(currentState));
|
|
53
|
+
} else {
|
|
54
|
+
triggerRefs.value[index].setAttribute('aria-expanded', 'false');
|
|
55
|
+
contentRefs.value[index].setAttribute('aria-hidden', 'true');
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<style lang="css">
|
|
62
|
+
.display-accordian {
|
|
63
|
+
max-width: 600px;
|
|
64
|
+
margin: 0 auto;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.accordion-panel {
|
|
68
|
+
border: var(--accordian-panel-border);
|
|
69
|
+
border-radius: var(--accordian-panel-border-radius);
|
|
70
|
+
margin-block-end: var(--accordian-panel-mbe);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.accordion-trigger {
|
|
74
|
+
display: block;
|
|
75
|
+
width: 100%;
|
|
76
|
+
padding: 1rem;
|
|
77
|
+
background: var(--accordion-trigger-bg);
|
|
78
|
+
border: none;
|
|
79
|
+
text-align: left;
|
|
80
|
+
cursor: pointer;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.accordion-content {
|
|
84
|
+
display: grid;
|
|
85
|
+
grid-template-rows: 0fr;
|
|
86
|
+
transition: grid-template-rows ease-in-out 500ms;
|
|
87
|
+
|
|
88
|
+
> div {
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
/* transform: translateY(-1rem);
|
|
91
|
+
transition: all ease-in-out 500ms;
|
|
92
|
+
|
|
93
|
+
> p {
|
|
94
|
+
padding-block: 0;
|
|
95
|
+
transition: all ease-in-out 500ms;
|
|
96
|
+
} */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.accordion-content[aria-hidden='false'] {
|
|
101
|
+
grid-template-rows: 1fr;
|
|
102
|
+
|
|
103
|
+
/* > div {
|
|
104
|
+
transform: translateY(0);
|
|
105
|
+
> p {
|
|
106
|
+
padding-block: 32px;
|
|
107
|
+
}
|
|
108
|
+
} */
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<dialog class="display-dialog wrapper" :class="[elementClasses]" :align-dialog
|
|
3
|
-
<focus-trap v-model:active="
|
|
2
|
+
<dialog class="display-dialog wrapper" :class="[elementClasses]" :align-dialog :open ref="dialogRef">
|
|
3
|
+
<focus-trap v-model:active="open" :clickOutsideDeactivates="true" @deactivate="closeDialog()">
|
|
4
4
|
<div class="inner">
|
|
5
5
|
<div class="top-bar">
|
|
6
6
|
<template v-if="hasDialogTitle">
|
|
@@ -57,12 +57,12 @@ const props = defineProps({
|
|
|
57
57
|
|
|
58
58
|
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
59
59
|
|
|
60
|
-
const
|
|
60
|
+
const open = defineModel<boolean>();
|
|
61
61
|
const bodyTag = ref<HTMLBodyElement | null>(null);
|
|
62
62
|
const lockViewport = toRef<boolean>(props.lockViewport);
|
|
63
63
|
|
|
64
64
|
const closeDialog = () => {
|
|
65
|
-
|
|
65
|
+
open.value = false;
|
|
66
66
|
|
|
67
67
|
if (lockViewport.value && bodyTag.value !== null) {
|
|
68
68
|
bodyTag.value.classList.remove('lock');
|
|
@@ -74,6 +74,8 @@ const hasDialogTitle = computed(() => slots.dialogTitle !== undefined);
|
|
|
74
74
|
const hasDialogContent = computed(() => slots.dialogContent !== undefined);
|
|
75
75
|
const hasActionButtons = computed(() => slots.actionButtons !== undefined);
|
|
76
76
|
|
|
77
|
+
const alignDialog = computed(() => `${props.positionY}-${props.positionX}`);
|
|
78
|
+
|
|
77
79
|
onMounted(() => {
|
|
78
80
|
bodyTag.value = document.querySelector('body');
|
|
79
81
|
if (lockViewport.value && bodyTag.value !== null) {
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<ClientOnly>
|
|
3
|
-
<button :popovertarget class="popover-trigger" :class="[elementClasses]">
|
|
3
|
+
<button @click.prevent="showPopover()" :popovertarget class="popover-trigger" :class="[elementClasses]">
|
|
4
4
|
<slot name="trigger"></slot>
|
|
5
5
|
</button>
|
|
6
6
|
|
|
7
|
-
<dialog class="dialog-popover" popover :id="popovertarget" :class="[elementClasses]">
|
|
8
|
-
<
|
|
7
|
+
<dialog :open class="dialog-popover" popover :id="popovertarget" :class="[elementClasses]">
|
|
8
|
+
<focus-trap v-model:active="open" :clickOutsideDeactivates="true" @deactivate="closePopover()">
|
|
9
|
+
<div>
|
|
10
|
+
<button @click.prevent="closePopover()">x</button>
|
|
11
|
+
<slot name="popoverCotent"></slot>
|
|
12
|
+
</div>
|
|
13
|
+
</focus-trap>
|
|
9
14
|
</dialog>
|
|
10
15
|
</ClientOnly>
|
|
11
16
|
</template>
|
|
12
17
|
|
|
13
18
|
<script setup lang="ts">
|
|
14
|
-
|
|
19
|
+
import { FocusTrap } from 'focus-trap-vue';
|
|
20
|
+
|
|
21
|
+
const { popovertarget, styleClassPassthrough } = defineProps({
|
|
15
22
|
popovertarget: {
|
|
16
23
|
type: String,
|
|
17
24
|
required: true,
|
|
@@ -24,7 +31,19 @@ const props = defineProps({
|
|
|
24
31
|
|
|
25
32
|
const anchorName = `--anchor-${useId()}`;
|
|
26
33
|
|
|
27
|
-
const { elementClasses } = useStyleClassPassthrough(
|
|
34
|
+
const { elementClasses } = useStyleClassPassthrough(styleClassPassthrough);
|
|
35
|
+
|
|
36
|
+
const open = ref<boolean>(false);
|
|
37
|
+
|
|
38
|
+
const showPopover = () => {
|
|
39
|
+
console.log('showPopover()');
|
|
40
|
+
open.value = true;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const closePopover = () => {
|
|
44
|
+
console.log('closePopover()');
|
|
45
|
+
open.value = false;
|
|
46
|
+
};
|
|
28
47
|
</script>
|
|
29
48
|
|
|
30
49
|
<style lang="css">
|
|
@@ -40,41 +59,46 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
|
40
59
|
right: anchor(right);
|
|
41
60
|
}
|
|
42
61
|
|
|
43
|
-
@layer popover-setup {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
62
|
+
/* @layer popover-setup { */
|
|
63
|
+
.popover-trigger {
|
|
64
|
+
anchor-name: v-bind(anchorName);
|
|
65
|
+
}
|
|
47
66
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
inset: auto;
|
|
54
|
-
bottom: anchor(bottom);
|
|
55
|
-
left: anchor(right);
|
|
56
|
-
opacity: 0;
|
|
57
|
-
transition: opacity 200ms, display 200ms, overlay 200ms;
|
|
58
|
-
transition-behavior: allow-discrete;
|
|
67
|
+
.dialog-popover {
|
|
68
|
+
/* backdrop-filter: blur(5px);
|
|
69
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
70
|
+
border: 0;
|
|
71
|
+
padding: 0; */
|
|
59
72
|
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
display: none;
|
|
74
|
+
position: absolute;
|
|
75
|
+
position-anchor: v-bind(anchorName);
|
|
76
|
+
margin: 0;
|
|
77
|
+
inset: auto;
|
|
78
|
+
bottom: anchor(bottom);
|
|
79
|
+
left: anchor(right);
|
|
80
|
+
opacity: 0;
|
|
81
|
+
transition: opacity 200ms, display 200ms, overlay 200ms;
|
|
82
|
+
transition-behavior: allow-discrete;
|
|
62
83
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
84
|
+
position-try-fallbacks: --left;
|
|
85
|
+
position-try-fallbacks: --top;
|
|
86
|
+
|
|
87
|
+
&:popover-open {
|
|
88
|
+
display: block;
|
|
89
|
+
opacity: 1;
|
|
66
90
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
91
|
+
@starting-style {
|
|
92
|
+
display: block;
|
|
93
|
+
opacity: 0;
|
|
71
94
|
}
|
|
72
95
|
}
|
|
96
|
+
}
|
|
73
97
|
|
|
74
|
-
|
|
98
|
+
/* @position-try --left {
|
|
75
99
|
inset: auto;
|
|
76
100
|
top: anchor(bottom);
|
|
77
101
|
right: anchor(right);
|
|
78
102
|
} */
|
|
79
|
-
}
|
|
103
|
+
/* } */
|
|
80
104
|
</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Meta, StoryFn } from '@nuxtjs/storybook';
|
|
2
|
+
|
|
3
|
+
import LayoutRow from '../LayoutRow.vue';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/UI/LayoutRow',
|
|
7
|
+
component: LayoutRow,
|
|
8
|
+
argTypes: {
|
|
9
|
+
tag: {
|
|
10
|
+
options: ['div', 'header', 'footer', 'section'],
|
|
11
|
+
control: { type: 'select' },
|
|
12
|
+
},
|
|
13
|
+
variant: {
|
|
14
|
+
options: [
|
|
15
|
+
'full',
|
|
16
|
+
'full-start',
|
|
17
|
+
'full-end',
|
|
18
|
+
'popout',
|
|
19
|
+
'popout-start',
|
|
20
|
+
'popout-end',
|
|
21
|
+
'content',
|
|
22
|
+
'content-start',
|
|
23
|
+
'content-end',
|
|
24
|
+
'inset-content',
|
|
25
|
+
'inset-content-start',
|
|
26
|
+
'inset-content-end',
|
|
27
|
+
'full-width',
|
|
28
|
+
'full-content',
|
|
29
|
+
'full-content-nopad',
|
|
30
|
+
'full-content',
|
|
31
|
+
],
|
|
32
|
+
control: { type: 'select' },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
} as Meta<typeof LayoutRow>;
|
|
36
|
+
|
|
37
|
+
const Template: StoryFn<typeof LayoutRow> = (args: any) => ({
|
|
38
|
+
components: { LayoutRow },
|
|
39
|
+
setup() {
|
|
40
|
+
return { args };
|
|
41
|
+
},
|
|
42
|
+
template: `
|
|
43
|
+
<LayoutRow v-bind="args">
|
|
44
|
+
<template #default>${args.content}</template>
|
|
45
|
+
</LayoutRow>
|
|
46
|
+
`,
|
|
47
|
+
// template: '<LayoutRow v-bind="args" />',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const Primary = Template.bind({});
|
|
51
|
+
Primary.args = {
|
|
52
|
+
tag: 'div',
|
|
53
|
+
variant: 'full',
|
|
54
|
+
styleClassPassthrough: ['mbe-20'],
|
|
55
|
+
content: `
|
|
56
|
+
<h2 class="heading-2">Full Track (1fr)</h2>
|
|
57
|
+
<p>
|
|
58
|
+
Lorem ipsum odor amet, consectetuer adipiscing elit. Nec elementum maecenas placerat laoreet curae elit convallis himenaeos. Tellus varius cursus convallis commodo suspendisse litora.
|
|
59
|
+
Platea accumsan interdum ultrices adipiscing molestie cras dui. Vehicula egestas nisi sagittis fames metus velit. Sodales blandit nisi eu dis sit, ridiculus aliquam. Morbi tellus eu in
|
|
60
|
+
penatibus torquent tortor. Platea gravida nam; egestas enim nostra ultricies.
|
|
61
|
+
</p>
|
|
62
|
+
<p>
|
|
63
|
+
Mi nibh quisque taciti porta curabitur nostra volutpat. Habitant sodales arcu habitasse mi duis conubia leo lacinia. Montes torquent sodales adipiscing; proin semper feugiat morbi
|
|
64
|
+
ullamcorper praesent. Arcu luctus tempor quam ligula vestibulum sapien faucibus ridiculus. Cursus consequat ultricies consectetur class suscipit quisque convallis eget? Dignissim mattis
|
|
65
|
+
luctus enim habitant porta pretium litora. Parturient montes imperdiet massa; sollicitudin varius hac aptent. Eleifend parturient mattis tellus nisi a montes.
|
|
66
|
+
</p>
|
|
67
|
+
`,
|
|
68
|
+
};
|
package/nuxt.config.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export default defineNuxtConfig({
|
|
3
3
|
devtools: { enabled: true },
|
|
4
4
|
css: ['modern-normalize', './assets/styles/main.css'],
|
|
5
|
+
modules: ['@nuxt/icon', '@nuxtjs/storybook'],
|
|
6
|
+
|
|
5
7
|
app: {
|
|
6
8
|
head: {
|
|
7
9
|
htmlAttrs: {
|
|
@@ -25,6 +27,9 @@ export default defineNuxtConfig({
|
|
|
25
27
|
pathPrefix: false,
|
|
26
28
|
},
|
|
27
29
|
],
|
|
30
|
+
vue: {
|
|
31
|
+
runtimeCompiler: true,
|
|
32
|
+
},
|
|
28
33
|
// plugins: ['css-anchor-positioning'],
|
|
29
34
|
compatibilityDate: '2024-07-13',
|
|
30
35
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srcdev-nuxt-components",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.26",
|
|
5
5
|
"main": "nuxt.config.ts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"clean": "rm -rf .nuxt && rm -rf .output && rm -rf .playground/.nuxt && rm -rf .playground/.output",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"preview": "nuxt preview .playground",
|
|
14
14
|
"lint": "eslint .",
|
|
15
15
|
"postinstall": "nuxt prepare .playground",
|
|
16
|
-
"release": "release-it"
|
|
16
|
+
"release": "release-it",
|
|
17
|
+
"storybook": "storybook dev --port 6006 --config-dir .storybook",
|
|
18
|
+
"test": "vitest"
|
|
17
19
|
},
|
|
18
20
|
"files": [
|
|
19
21
|
"assets/",
|
|
@@ -23,12 +25,26 @@
|
|
|
23
25
|
"types/"
|
|
24
26
|
],
|
|
25
27
|
"devDependencies": {
|
|
26
|
-
"@nuxt/eslint-config": "0.7.
|
|
28
|
+
"@nuxt/eslint-config": "0.7.3",
|
|
29
|
+
"@nuxt/icon": "1.10.2",
|
|
27
30
|
"@oddbird/css-anchor-positioning": "0.4.0",
|
|
28
|
-
"eslint": "9.
|
|
31
|
+
"eslint": "9.17.0",
|
|
32
|
+
"happy-dom": "15.11.7",
|
|
29
33
|
"nuxt": "3.14.1592",
|
|
30
34
|
"release-it": "17.10.0",
|
|
31
|
-
"typescript": "5.7.2"
|
|
35
|
+
"typescript": "5.7.2",
|
|
36
|
+
"vue": "3.5.13"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@nuxtjs/storybook": "8.3.1",
|
|
40
|
+
"@storybook/addon-essentials": "8.4.7",
|
|
41
|
+
"@storybook/addon-interactions": "8.4.7",
|
|
42
|
+
"@storybook/addon-links": "8.4.7",
|
|
43
|
+
"@storybook/vue3": "8.4.7",
|
|
44
|
+
"@vueuse/core": "12.0.0",
|
|
45
|
+
"focus-trap-vue": "4.0.3",
|
|
46
|
+
"http-proxy-middleware": "3.0.3",
|
|
47
|
+
"modern-normalize": "3.0.1"
|
|
32
48
|
},
|
|
33
49
|
"release-it": {
|
|
34
50
|
"$schema": "https://unpkg.com/release-it/schema/release-it.json",
|
|
@@ -39,10 +55,5 @@
|
|
|
39
55
|
"release": true,
|
|
40
56
|
"releaseName": "v${version}"
|
|
41
57
|
}
|
|
42
|
-
},
|
|
43
|
-
"dependencies": {
|
|
44
|
-
"@vueuse/core": "12.0.0",
|
|
45
|
-
"focus-trap-vue": "4.0.3",
|
|
46
|
-
"modern-normalize": "3.0.1"
|
|
47
58
|
}
|
|
48
59
|
}
|