Skip to content

Commit d4510f1

Browse files
committed
Merge branch 'accordian'
2 parents 621c1e8 + a71f5c5 commit d4510f1

File tree

10 files changed

+557
-148
lines changed

10 files changed

+557
-148
lines changed

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"@storybook/addon-vitest": "^9.1.1",
6161
"@storybook/sveltekit": "^9.1.1",
6262
"@sveltejs/adapter-static": "^3.0.8",
63-
"@sveltejs/kit": "^2.27.0",
63+
"@sveltejs/kit": "^2.27.1",
6464
"@sveltejs/package": "^2.4.0",
6565
"@sveltejs/vite-plugin-svelte": "^6.1.0",
6666
"@types/file-saver": "^2.0.7",
@@ -77,14 +77,14 @@
7777
"prettier": "^3.6.2",
7878
"prettier-plugin-svelte": "^3.4.0",
7979
"publint": "^0.3.12",
80-
"sass": "^1.89.2",
80+
"sass": "^1.90.0",
8181
"storybook": "^9.1.1",
82-
"svelte": "^5.37.3",
82+
"svelte": "^5.38.0",
8383
"svelte-check": "^4.3.1",
8484
"svelte-preprocess": "^6.0.3",
8585
"typescript": "^5.9.2",
8686
"typescript-eslint": "^8.39.0",
87-
"vite": "^7.0.6",
87+
"vite": "^7.1.0",
8888
"vitest": "^3.2.4"
8989
},
9090
"keywords": [

pnpm-lock.yaml

Lines changed: 136 additions & 136 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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>

0 commit comments

Comments
 (0)