Skip to content

Commit a327bb3

Browse files
committed
Accordian added
1 parent 621c1e8 commit a327bb3

File tree

8 files changed

+417
-8
lines changed

8 files changed

+417
-8
lines changed

src/lib/index.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export type { ComponentWeight } from './types/weight.js';
1212

1313
export type { PositionY, PositionX } from './types/position.js';
1414

15+
export type { DropdownArrowPosition } from './types/special.js';
16+
1517
/** developer tools: helpers: logger */
1618
export { default as createLogger } from '$lib/stories/developer tools/helpers/logger/logger.js';
1719
export type {
@@ -103,11 +105,7 @@ export type { MessageProps } from '$lib/stories/components/Form/Message/Message.
103105

104106
/** Form: Select */
105107
export { default as Select } from '$lib/stories/components/Form/Select/Select.svelte';
106-
export type {
107-
SelectOption,
108-
SelectDropdownArrowPosition,
109-
SelectProps,
110-
} from '$lib/stories/components/Form/Select/Select.svelte';
108+
export type { SelectOption, SelectProps } from '$lib/stories/components/Form/Select/Select.svelte';
111109

112110
/** Form: NumericInput */
113111
export { default as NumericInput } from '$lib/stories/components/Form/NumericInput/NumericInput.svelte';
@@ -172,6 +170,13 @@ export type {
172170
GridColumnProps,
173171
} from '$lib/stories/components/Layout/Grid/Column/Column.svelte';
174172

173+
/** Layout: Accordian */
174+
export { default as Accordian } from '$lib/stories/components/Layout/Accordian/Accordian.svelte';
175+
export type {
176+
AccordianProps,
177+
AccordianToggleEvent,
178+
} from '$lib/stories/components/Layout/Accordian/Accordian.svelte';
179+
175180
/** Info: Calendar */
176181
export { default as Calendar } from '$lib/stories/components/Info/Calendar/Calendar.svelte';
177182
export type {

src/lib/stories/components/Form/Select/Select.svelte

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
disabled?: boolean;
1818
};
1919
20-
export type SelectDropdownArrowPosition = false | 'before' | 'after';
21-
2220
export interface SelectProps {
2321
/** How large should the button be? */
2422
size?: ComponentSize;
@@ -105,7 +103,7 @@
105103
/** Dropdown Arrow Icon */
106104
customDropdownArrowIcon?: (open: boolean) => Snippet;
107105
/** Select Dropdown Arrow Position */
108-
dropdownArrowPosition?: SelectDropdownArrowPosition;
106+
dropdownArrowPosition?: DropdownArrowPosition;
109107
/** Popup stick horizontally */
110108
popupPositionX?: PositionX;
111109
/** Popup stick vertically */
@@ -138,6 +136,7 @@
138136
} from '$lib/index.js';
139137
import type { TextInputInputEvent } from '../TextInput/TextInput.svelte';
140138
import type { ButtonClickEvent } from '../Button/Button.svelte';
139+
import type { DropdownArrowPosition } from '$lib/types/special.js';
141140
142141
let {
143142
size = 'normal',
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<script module lang="ts">
2+
import { defineMeta } from '@storybook/addon-svelte-csf';
3+
import Accordian from './Accordian.svelte';
4+
import type { StoryBookArgTypes } from '$lib/storybook-types.js';
5+
import { componentSizeArray } from '$lib/types/size.js';
6+
7+
export const storyAccordianArgTypes: StoryBookArgTypes = {
8+
size: {
9+
control: { type: 'select' },
10+
options: componentSizeArray,
11+
},
12+
};
13+
14+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
15+
const { Story } = defineMeta({
16+
component: Accordian,
17+
tags: ['autodocs'],
18+
argTypes: storyAccordianArgTypes,
19+
});
20+
</script>
21+
22+
<Story name="Default" asChild>
23+
<Accordian>
24+
{#snippet summary()}
25+
Click me!
26+
{/snippet}
27+
28+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur nisi hic accusamus,
29+
mollitia velit corporis, sit culpa nam ducimus quisquam aliquam eos atque doloribus architecto
30+
at harum, explicabo et doloremque.
31+
</Accordian>
32+
</Story>
33+
34+
<Story name="Open by Default" asChild>
35+
<Accordian defaultOpen={true}>
36+
{#snippet summary()}
37+
Click me!
38+
{/snippet}
39+
40+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur nisi hic accusamus,
41+
mollitia velit corporis, sit culpa nam ducimus quisquam aliquam eos atque doloribus architecto
42+
at harum, explicabo et doloremque.
43+
</Accordian>
44+
</Story>
45+
46+
<Story name="Full Width Summary" asChild>
47+
<Accordian fullWidthSummary>
48+
{#snippet summary()}
49+
Click me!
50+
{/snippet}
51+
52+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur nisi hic accusamus,
53+
mollitia velit corporis, sit culpa nam ducimus quisquam aliquam eos atque doloribus architecto
54+
at harum, explicabo et doloremque.
55+
</Accordian>
56+
</Story>
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
<script lang="ts" module>
2+
import type { ComponentSize } from '$lib/types/size.js';
3+
import type { DropdownArrowPosition } from '$lib/types/special.js';
4+
import Icon from '@iconify/svelte';
5+
import { onMount, type Snippet } from 'svelte';
6+
import type { EventHandler } from 'svelte/elements';
7+
8+
export type AccordianToggleEvent = Event & {
9+
currentTarget: EventTarget & HTMLDetailsElement;
10+
};
11+
12+
export interface AccordianProps {
13+
/** Contents goes here */
14+
children?: Snippet;
15+
/** Accordian summary */
16+
summary?: Snippet;
17+
/** summary full width */
18+
fullWidthSummary?: boolean;
19+
/** Accordian ref */
20+
ref?: HTMLDetailsElement;
21+
/** Custom css class */
22+
class?: string;
23+
/** The toggle event handler */
24+
ontoggle?: EventHandler<Event, HTMLDetailsElement>;
25+
/** Open state, for dynmaic Accordians */
26+
open?: boolean;
27+
/** default Open, for static Accordians */
28+
defaultOpen?: boolean;
29+
/** How large should the button be? */
30+
size?: ComponentSize;
31+
/** Select Dropdown Arrow Position */
32+
dropdownArrowPosition?: DropdownArrowPosition;
33+
/** Dropdown Arrow Icon */
34+
customDropdownArrowIcon?: (open: boolean) => Snippet;
35+
}
36+
</script>
37+
38+
<script lang="ts">
39+
let {
40+
class: className = '',
41+
ref = $bindable<HTMLDetailsElement>(),
42+
ontoggle,
43+
open = $bindable<boolean>(),
44+
defaultOpen,
45+
summary,
46+
children,
47+
size = 'normal',
48+
fullWidthSummary = false,
49+
customDropdownArrowIcon: customDropdownArrowIconInternal,
50+
dropdownArrowPosition = 'before',
51+
}: AccordianProps = $props();
52+
53+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
54+
let customDropdownArrowIconTyped = customDropdownArrowIconInternal as any;
55+
56+
let isUserInteraction = $state(false);
57+
58+
function ontoggleMod(e: AccordianToggleEvent) {
59+
if (isUserInteraction) {
60+
if (ontoggle) {
61+
ontoggle(e);
62+
}
63+
}
64+
65+
isUserInteraction = false;
66+
}
67+
68+
function onsummaryclick() {
69+
isUserInteraction = true;
70+
}
71+
72+
onMount(() => {
73+
if (open === true) {
74+
ref.open = true;
75+
} else if (open === false) {
76+
ref.open = false;
77+
} else if (defaultOpen === true) {
78+
ref.open = true;
79+
} else if (defaultOpen === false) {
80+
ref.open = false;
81+
}
82+
});
83+
</script>
84+
85+
{#snippet dropdownArrowIcon()}
86+
{#if customDropdownArrowIconTyped}
87+
{@render customDropdownArrowIconTyped(open)}
88+
{:else}
89+
<div class="IconOpen">
90+
<Icon icon="material-symbols:arrow-drop-up-rounded" width="32" height="32" />
91+
</div>
92+
<div class="IconClose">
93+
<Icon icon="material-symbols:arrow-drop-down-rounded" width="32" height="32" />
94+
</div>
95+
{/if}
96+
{/snippet}
97+
98+
<details
99+
class:fullWidthSummary
100+
class={['dodo-ui-Accordian', `size--${size}`, className].join(' ')}
101+
bind:this={ref}
102+
{open}
103+
ontoggle={ontoggleMod}
104+
>
105+
{#if summary}
106+
<summary onclick={onsummaryclick}>
107+
{#if dropdownArrowPosition === 'before'}
108+
<div class:open class="DropdownArrow before">
109+
{@render dropdownArrowIcon()}
110+
</div>
111+
{/if}
112+
{@render summary()}
113+
{#if dropdownArrowPosition === 'after'}
114+
<div class:open class="DropdownArrow after">
115+
{@render dropdownArrowIcon()}
116+
</div>
117+
{/if}
118+
</summary>
119+
{/if}
120+
121+
{#if children}
122+
<div class="AccordianContent">
123+
{@render children()}
124+
</div>
125+
{/if}
126+
</details>
127+
128+
<style lang="scss">
129+
.dodo-ui-Accordian {
130+
color: var(--dodo-color-neutral-900);
131+
width: 100%;
132+
133+
summary {
134+
display: inline-flex;
135+
align-items: center;
136+
cursor: pointer;
137+
user-select: none;
138+
font-weight: 500;
139+
}
140+
141+
&.fullWidthSummary {
142+
summary {
143+
display: flex;
144+
width: 100%;
145+
}
146+
}
147+
148+
&[open] {
149+
.IconOpen {
150+
display: flex;
151+
}
152+
153+
.IconClose {
154+
display: none;
155+
}
156+
}
157+
158+
&:not([open]) {
159+
.IconOpen {
160+
display: none;
161+
}
162+
163+
.IconClose {
164+
display: flex;
165+
}
166+
}
167+
168+
&.size {
169+
&--normal {
170+
summary {
171+
font-size: 1rem;
172+
min-height: var(--dodo-ui-element-height-normal);
173+
}
174+
}
175+
176+
&--small {
177+
summary {
178+
font-size: 0.9rem;
179+
min-height: var(--dodo-ui-element-height-small);
180+
}
181+
}
182+
183+
&--large {
184+
summary {
185+
font-size: 1.1rem;
186+
min-height: var(--dodo-ui-element-height-large);
187+
}
188+
}
189+
}
190+
191+
.AccordianContent {
192+
margin-top: var(--dodo-ui-space);
193+
}
194+
}
195+
</style>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<script module lang="ts">
2+
import { defineMeta } from '@storybook/addon-svelte-csf';
3+
import Accordian from '../Accordian.svelte';
4+
import { storyAccordianArgTypes } from '../Accordian.stories.svelte';
5+
import Icon from '@iconify/svelte';
6+
7+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
8+
const { Story } = defineMeta({
9+
component: Accordian,
10+
tags: ['autodocs'],
11+
argTypes: storyAccordianArgTypes,
12+
});
13+
14+
let open = $state<boolean>(true);
15+
</script>
16+
17+
<Story name="DropdownArrowPositionBefore" asChild>
18+
<Accordian>
19+
{#snippet summary()}
20+
Click me!
21+
{/snippet}
22+
23+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur nisi hic accusamus,
24+
mollitia velit corporis, sit culpa nam ducimus quisquam aliquam eos atque doloribus architecto
25+
at harum, explicabo et doloremque.
26+
</Accordian>
27+
</Story>
28+
29+
<Story name="DropdownArrowPositionAfter" asChild>
30+
<Accordian dropdownArrowPosition="after">
31+
{#snippet summary()}
32+
Click me!
33+
{/snippet}
34+
35+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur nisi hic accusamus,
36+
mollitia velit corporis, sit culpa nam ducimus quisquam aliquam eos atque doloribus architecto
37+
at harum, explicabo et doloremque.
38+
</Accordian>
39+
</Story>
40+
41+
<Story name="HideDropdownArrow" asChild>
42+
<Accordian dropdownArrowPosition={false}>
43+
{#snippet summary()}
44+
Click me!
45+
{/snippet}
46+
47+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur nisi hic accusamus,
48+
mollitia velit corporis, sit culpa nam ducimus quisquam aliquam eos atque doloribus architecto
49+
at harum, explicabo et doloremque.
50+
</Accordian>
51+
</Story>
52+
53+
<!-- Format look and feel Dropdown Arrow icon -->
54+
<Story name="CustomDropdownArrowIcon" asChild>
55+
<Accordian {open} ontoggle={() => (open = !open)}>
56+
{#snippet summary()}
57+
Click me!
58+
{/snippet}
59+
60+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur nisi hic accusamus,
61+
mollitia velit corporis, sit culpa nam ducimus quisquam aliquam eos atque doloribus architecto
62+
at harum, explicabo et doloremque.
63+
64+
{#snippet customDropdownArrowIcon(open)}
65+
{#if open}
66+
<Icon icon="mingcute:up-fill" width="24" height="24" />
67+
{:else}
68+
<Icon icon="mingcute:down-fill" width="24" height="24" />
69+
{/if}
70+
{/snippet}
71+
</Accordian>
72+
</Story>

0 commit comments

Comments
 (0)