srcdev-nuxt-components 0.0.25 → 0.0.27

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.
@@ -1,5 +1,6 @@
1
1
  :root {
2
2
  color-scheme: light dark;
3
+ interpolate-size: allow-keywords; /* can also be set within html {} */
3
4
  }
4
5
 
5
6
  html {
@@ -0,0 +1,113 @@
1
+ <template>
2
+ <div class="display-accordian" :class="[elementClasses]" ref="accordianRef">
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 accordianRef = ref<HTMLElement>();
39
+ const triggerRefs = ref<HTMLElement[]>([]);
40
+ const contentRefs = ref<HTMLElement[]>([]);
41
+
42
+ onMounted(() => {
43
+ if (accordianRef.value) {
44
+ triggerRefs.value = Array.from(accordianRef.value.querySelectorAll('.accordion-trigger'));
45
+ contentRefs.value = Array.from(accordianRef.value.querySelectorAll('.accordion-content'));
46
+ }
47
+ });
48
+
49
+ const handleSummary = (clickedIndex: number) => {
50
+ triggerRefs.value.forEach((element, index) => {
51
+ if (clickedIndex === index) {
52
+ const currentState = element.getAttribute('aria-expanded');
53
+ const newState = currentState !== 'true';
54
+ triggerRefs.value[index].setAttribute('aria-expanded', String(newState));
55
+ contentRefs.value[index].setAttribute('aria-hidden', String(currentState));
56
+ } else {
57
+ triggerRefs.value[index].setAttribute('aria-expanded', 'false');
58
+ contentRefs.value[index].setAttribute('aria-hidden', 'true');
59
+ }
60
+ });
61
+ };
62
+ </script>
63
+
64
+ <style lang="css">
65
+ .display-accordian {
66
+ max-width: 600px;
67
+ margin: 0 auto;
68
+ }
69
+
70
+ .accordion-panel {
71
+ border: var(--accordian-panel-border);
72
+ border-radius: var(--accordian-panel-border-radius);
73
+ margin-block-end: var(--accordian-panel-mbe);
74
+ }
75
+
76
+ .accordion-trigger {
77
+ display: block;
78
+ width: 100%;
79
+ padding: 1rem;
80
+ background: var(--accordion-trigger-bg);
81
+ border: none;
82
+ text-align: left;
83
+ cursor: pointer;
84
+ }
85
+
86
+ .accordion-content {
87
+ display: grid;
88
+ grid-template-rows: 0fr;
89
+ transition: grid-template-rows ease-in-out 500ms;
90
+
91
+ > div {
92
+ overflow: hidden;
93
+ /* transform: translateY(-1rem);
94
+ transition: all ease-in-out 500ms;
95
+
96
+ > p {
97
+ padding-block: 0;
98
+ transition: all ease-in-out 500ms;
99
+ } */
100
+ }
101
+ }
102
+
103
+ .accordion-content[aria-hidden='false'] {
104
+ grid-template-rows: 1fr;
105
+
106
+ /* > div {
107
+ transform: translateY(0);
108
+ > p {
109
+ padding-block: 32px;
110
+ }
111
+ } */
112
+ }
113
+ </style>
@@ -1,6 +1,6 @@
1
1
  <template>
2
- <dialog class="display-dialog wrapper" :class="[elementClasses]" :align-dialog="`${positionY}-${positionX}`" :open="displayDialog" ref="dialogRef">
3
- <focus-trap v-model:active="displayDialog" :clickOutsideDeactivates="true" @deactivate="closeDialog()">
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 displayDialog = defineModel<boolean>();
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
- displayDialog.value = false;
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
- <slot name="popoverCotent"></slot>
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
- const props = defineProps({
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(props.styleClassPassthrough);
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">
@@ -46,6 +65,11 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
46
65
  }
47
66
 
48
67
  .dialog-popover {
68
+ /* backdrop-filter: blur(5px);
69
+ background-color: rgba(0, 0, 0, 0.5);
70
+ border: 0;
71
+ padding: 0; */
72
+
49
73
  display: none;
50
74
  position: absolute;
51
75
  position-anchor: v-bind(anchorName);
@@ -0,0 +1,8 @@
1
+ import { Meta, Canvas, Controls } from '@storybook/blocks';
2
+ import * as LayoutRowStories from './LayoutRow.stories'
3
+
4
+ <Meta of={LayoutRowStories} />
5
+
6
+ <Canvas of={LayoutRowStories.Primary} />
7
+
8
+ <Controls of={LayoutRowStories.Primary} />
@@ -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.25",
4
+ "version": "0.0.27",
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.2",
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.16.0",
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
  }