Skip to content

Commit

Permalink
feat: add v-model for open sections
Browse files Browse the repository at this point in the history
  • Loading branch information
davidnixon committed Jan 28, 2024
1 parent 5ef7621 commit d32bc62
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,74 +1,54 @@
import { Canvas, Meta, Story } from '@storybook/addon-docs';
import { action } from '@storybook/addon-actions';
import { CvAccordion, CvAccordionItem } from '.';
import { alignConsts, sizeConsts } from './consts';
import { ref } from 'vue';

import {
sbCompPrefix,
storyParametersObject,
} from '../../global/storybook-utils';
import { ref } from 'vue';
const open = ref({
accItem1: false,
accItem2: false,
accItem3: false,
accItem4: false,
});

export default {
title: `${sbCompPrefix}/CvAccordion`,
component: CvAccordion,
argTypes: {
align: {
control: { type: 'select', options: Object.keys(alignConsts.$labels) },
},
size: {
control: { type: 'select', options: Object.keys(sizeConsts.$labels) },
},
},
};
<Meta title={`${sbCompPrefix}/CvAccordion`} component={CvAccordion} />

// <cv-button @click="onClick" v-bind="newArgs">{{defaultSlot}}</cv-button>
const template = `<cv-accordion @change="onChange" v-bind="args">
export const Template = args => ({
components: { CvAccordion, CvAccordionItem },
setup() {
return {
...args,
align: alignConsts[alignConsts.$labels[args.align]],
size: sizeConsts[sizeConsts.$labels[args.size]],
onChange: action('change'),
open,
};
},
template: args.template,
});
const template = `<cv-accordion @change="onChange" :align="align" :size="size">
<cv-accordion-item v-for="n in 4" :key="\`acc-item-\${n}\`" :id="n % 2 ? \`acc-item-\${n}\` : ''">
<template v-slot:title>Section {{n}} title </template>
<template v-slot:title>Episode {{n}} </template>
<template v-slot:content>
<p>Did you hear that? They've shut down the main reactor. We'll be destroyed for sure. This is madness! We're doomed! There'll be no escape for the Princess this time. What's that? R2! R2-D2, where are you? At last! Where have you been? They're heading in this direction.</p>
</template>
</cv-accordion-item>
</cv-accordion>`;
const Template = (args, { argTypes }) => {
// eslint-disable-next-line no-param-reassign
args = {
...args,
align: alignConsts[alignConsts.$labels[args.align]],
size: sizeConsts[sizeConsts.$labels[args.size]],
};
return {
props: Object.keys(argTypes),
components: { CvAccordion, CvAccordionItem },
setup() {
return { args, onChange: action('change') };
},
template,
};
};

export const Default = Template.bind({});
const Default = Template.bind({});
Default.args = {};
Default.parameters = storyParametersObject(
Default.parameters,
template,
Default.args
);

/* V-MODEL STORY */

const open = ref({
accItem1: false,
accItem2: false,
accItem3: false,
accItem4: false,
});

const templateVModel = `
<div>
<cv-accordion @change="onChange" v-bind="args">
<cv-accordion @change="onChange" :align="align" :size="size">
<cv-accordion-item v-for="n in 4" :key="\`acc-item-\${n}\`" :id="\`accItem\${n}\`" v-model:open="open[\`accItem\${n}\`]">
<template #title>Section {{n}} title </template>
<template #title>Episode {{n}} </template>
<template #content>
<p>Give us a few minutes to lock it down. Large leak...very dangerous. Who is this? What's your operating number? Boring conversation anyway. Luke! We're going to have company! Aren't you a little short to be a stormtrooper? What? Oh...the uniform.</p>
</template>
Expand All @@ -91,21 +71,83 @@ const templateVModel = `
</div>
`;

const TemplateVModel = args => {
return {
components: { CvAccordion, CvAccordionItem },
setup: () => ({
args,
onChange: action('change'),
open,
}),
template: templateVModel,
};
};
# CvAccordion

export const VModel = TemplateVModel.bind({});
VModel.parameters = storyParametersObject(
VModel.parameters,
templateVModel,
VModel.args
);
<Canvas>
<Story
name="Default"
parameters={{
docs: { source: { code: template } },
controls: {
include: ['align', 'size'],
},
}}
args={{
template: template,
}}
argTypes={{
align: {
control: 'select',
options: Object.keys(alignConsts.$labels),
},
size: {
control: 'select',
options: Object.keys(sizeConsts.$labels),
},
}}
>
{Template.bind({})}
</Story>
</Canvas>

# Control open state with v-model

- Notes: The Vue 2 component does not support v-model. One interesting implementation using this would be to create an
"auto close" component such that opening one section closes other sections.

```javascript
// example auto close
// <cv-accordion @change="onAutoClose">
const open = ref({
accItem1: false,
accItem2: false,
accItem3: false,
accItem4: false,
});
function autoClose(ev) {
if (ev.change.open) {
for (let state in open.value) {
if (state !== ev.change.id) open.value[state] = false;
}
}
}
```

<Canvas>
<Story
name="v-model"
parameters={{
docs: { source: { code: templateVModel } },
controls: {
include: ['align', 'size'],
},
}}
args={{
template: templateVModel,
}}
argTypes={{
align: {
control: 'select',
default: 'end',
options: Object.keys(alignConsts.$labels),
},
size: {
control: 'select',
default: 'md',
options: Object.keys(sizeConsts.$labels),
},
}}
>
{Template.bind({})}
</Story>
</Canvas>
4 changes: 2 additions & 2 deletions src/components/CvAccordion/CvAccordion.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ import { alignConsts, sizeConsts } from './consts';
defineProps({
/**
* optional align, defaults to 'end'
* Specify the alignment of the accordion heading title and chevron.
*/
align: {
type: String,
default: null,
validator: val => alignConsts.includes(val),
},
/**
* optional size setting
* Specify the size of the Accordion
*/
size: {
type: String,
Expand Down
12 changes: 6 additions & 6 deletions src/components/CvAccordion/consts.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
export const alignConsts = [null, 'start', 'end', ''];
alignConsts.$labels = {
'Not supplied': 0,
Start: 1,
End: 2,
'Empty string': 3,
'Not supplied (end)': 0,
'Start (start)': 1,
'End (end)': 2,
'Empty string (end)': 3,
};
export const sizeConsts = [null, 'sm', 'xl', ''];
sizeConsts.$labels = {
'Not supplied': 0,
'Not supplied (md)': 0,
'Small (sm)': 1,
'Large (xl)': 2,
'Empty string': 3,
'Empty string (md)': 3,
};

const CvAccordionConsts = { alignConsts, sizeConsts };
Expand Down

0 comments on commit d32bc62

Please sign in to comment.