Skip to content

Commit 4911a82

Browse files
committed
chore: Bump package version to 1.0.216 and enhance Accordion component
- Update package version in package.json to 1.0.216 - Add defaultExpanded prop to Accordion component for initial section expansion - Implement interactive and default expanded stories for Accordion - Refactor Accordion component to support draggable sections and improved styling - Update tests to verify default expanded behavior and section interactions
1 parent 8ea1dbd commit 4911a82

File tree

6 files changed

+145
-44
lines changed

6 files changed

+145
-44
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@programmer_network/yail",
3-
"version": "1.0.215",
3+
"version": "1.0.216",
44
"description": "Programmer Network's official UI library for React",
55
"author": "Aleksandar Grbic - (https://programmer.network)",
66
"publishConfig": {

src/Components/Accordion/Accordion.stories.tsx

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ export const Primary = () => {
6060
<div>
6161
<Accordion
6262
className='yl:w-[500px]'
63-
selectedId={2}
6463
sections={sections}
6564
onSorted={(_, data) => {
6665
setSections(data);
@@ -82,6 +81,46 @@ export const Primary = () => {
8281
);
8382
};
8483

84+
export const Interactive = () => {
85+
const [sections, setSections] = useState<ISection[]>([]);
86+
const [expandedSections, setExpandedSections] = useState<number[]>([1]);
87+
const [selectedSection, setSelectedSection] = useState<number>(2);
88+
89+
useEffect(() => {
90+
if (sections.length) {
91+
return;
92+
}
93+
94+
setSections(dummySections);
95+
}, [sections.length]);
96+
97+
if (!sections.length) {
98+
return <div>Loading...</div>;
99+
}
100+
101+
return (
102+
<div>
103+
<Accordion
104+
className='yl:w-[500px]'
105+
sections={sections}
106+
expanded={expandedSections}
107+
selectedId={selectedSection}
108+
setExpanded={(expanded: number[]) => {
109+
setExpandedSections(expanded);
110+
}}
111+
onSectionItemClick={sectionItem => {
112+
action("onSectionItemClick")(sectionItem);
113+
setSelectedSection(sectionItem.id);
114+
}}
115+
onSectionClick={section => {
116+
action("onSectionClick")(section);
117+
setSelectedSection(section.id);
118+
}}
119+
/>
120+
</div>
121+
);
122+
};
123+
85124
export const NonInteractive = () => {
86125
const [sections, setSections] = useState<ISection[]>([]);
87126
const [expandedSections, setExpandedSections] = useState<number[]>([1]);
@@ -141,6 +180,8 @@ export const WithoutDragAndDrop = () => {
141180
className='yl:w-[500px]'
142181
selectedId={2}
143182
sections={sections}
183+
hasDraggableSectionItems={true}
184+
hasDraggableSections={true}
144185
onSorted={(_, sections) => {
145186
setSections(sections);
146187
}}
@@ -280,3 +321,42 @@ export const WithAddLabels = () => {
280321
</div>
281322
);
282323
};
324+
325+
export const DefaultExpanded = () => {
326+
const [sections, setSections] = useState<ISection[]>([]);
327+
const [expandedSections, setExpandedSections] = useState<number[]>([]);
328+
329+
useEffect(() => {
330+
if (sections.length) {
331+
return;
332+
}
333+
334+
setSections(dummySections);
335+
}, [sections.length]);
336+
337+
if (!sections.length) {
338+
return <div>Loading...</div>;
339+
}
340+
341+
return (
342+
<div>
343+
<Accordion
344+
className='yl:w-[500px]'
345+
selectedId={2}
346+
sections={sections}
347+
expanded={expandedSections}
348+
defaultExpanded={true}
349+
onSorted={(_, sections) => {
350+
setSections(sections);
351+
}}
352+
setExpanded={(expanded: number[]) => {
353+
setExpandedSections(expanded);
354+
action("setExpanded")(expanded);
355+
}}
356+
onSelected={item => {
357+
action("onSelected")(item);
358+
}}
359+
/>
360+
</div>
361+
);
362+
};

src/Components/Accordion/Accordion.test.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,25 @@ describe("Accordion component", () => {
106106
);
107107
});
108108

109-
test("applies custom class names", () => {
109+
test("expands all sections by default when defaultExpanded is true", async () => {
110+
const setExpanded = vi.fn();
110111
render(
111112
<Accordion
112113
sections={mockSections}
113114
onSorted={vi.fn()}
114-
className='custom-class'
115-
sectionTitleClassName='custom-title-class'
116-
setExpanded={vi.fn()}
115+
setExpanded={setExpanded}
117116
expanded={[]}
117+
defaultExpanded={true}
118118
onSectionItemClick={vi.fn()}
119119
/>
120120
);
121121

122-
expect(screen.getByText("Section 1").parentNode).toHaveClass(
123-
"custom-title-class"
122+
expect(setExpanded).toHaveBeenCalledWith(
123+
mockSections.map(section => section.id)
124124
);
125+
126+
mockSections.forEach(section => {
127+
expect(screen.getByText(section.title)).toBeInTheDocument();
128+
});
125129
});
126130
});

src/Components/Accordion/__snapshots__/Accordion.test.tsx.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ exports[`Accordion component > renders correctly 1`] = `
1111
>
1212
<h3
1313
aria-expanded="true"
14-
class="yl:relative yl:flex yl:cursor-default yl:select-none yl:items-center yl:font-semibold yl:capitalize yl:p-4 yl:bg-text/5 yl:cursor-pointer yl:text-text"
14+
class="yl:relative yl:flex yl:cursor-default yl:select-none yl:items-center yl:font-semibold yl:capitalize yl:p-4 yl:hover:text-primary yl:transition-colors yl:duration-400 yl:ease-in-out yl:hover:cursor-pointer yl:bg-text/2 yl:cursor-pointer yl:text-text"
1515
role="button"
1616
tabindex="0"
1717
>
@@ -37,12 +37,12 @@ exports[`Accordion component > renders correctly 1`] = `
3737
class="yl:relative yl:text-text yl:gap-4 yl:flex yl:flex-col yl:py-4"
3838
>
3939
<li
40-
class="yl:relative yl:flex yl:items-center yl:cursor-default hover:text-text break-words leading-normal yl:px-4 yl:cursor-pointer yl:text-text"
40+
class="yl:relative yl:flex yl:items-center yl:cursor-default yl:break-words yl:leading-normal yl:px-4 yl:hover:cursor-pointer yl:hover:text-primary"
4141
>
4242
Item A
4343
</li>
4444
<li
45-
class="yl:relative yl:flex yl:items-center yl:cursor-default hover:text-text break-words leading-normal yl:px-4 yl:cursor-pointer yl:text-text"
45+
class="yl:relative yl:flex yl:items-center yl:cursor-default yl:break-words yl:leading-normal yl:px-4 yl:hover:cursor-pointer yl:hover:text-primary"
4646
>
4747
Item B
4848
</li>
@@ -54,7 +54,7 @@ exports[`Accordion component > renders correctly 1`] = `
5454
>
5555
<h3
5656
aria-expanded="false"
57-
class="yl:relative yl:flex yl:cursor-default yl:select-none yl:items-center yl:font-semibold yl:capitalize yl:p-4 yl:cursor-pointer yl:text-text"
57+
class="yl:relative yl:flex yl:cursor-default yl:select-none yl:items-center yl:font-semibold yl:capitalize yl:p-4 yl:hover:text-primary yl:transition-colors yl:duration-400 yl:ease-in-out yl:hover:cursor-pointer yl:cursor-pointer yl:text-text"
5858
role="button"
5959
tabindex="0"
6060
>

src/Components/Accordion/index.tsx

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import classNames from "classnames";
2-
import { FC, useEffect, useState } from "react";
2+
import { FC, useEffect, useRef, useState } from "react";
33

44
import DraggableList from "Components/DraggableList";
55
import { IDraggableListItem } from "Components/DraggableList/types";
@@ -26,8 +26,10 @@ const Accordion: FC<IAccordionProps> = ({
2626
setExpanded,
2727
selectedId,
2828
hasDraggableSections,
29-
hasDraggableSectionItems
29+
hasDraggableSectionItems,
30+
defaultExpanded
3031
}) => {
32+
const hasInitialized = useRef(false);
3133
const [selectedItemId, setSelectedItemId] = useState<
3234
number | null | undefined
3335
>(selectedId);
@@ -50,6 +52,13 @@ const Accordion: FC<IAccordionProps> = ({
5052

5153
useEffect(() => setSelectedItemId(selectedId), [selectedId]);
5254

55+
useEffect(() => {
56+
if (defaultExpanded && sections.length > 0 && !hasInitialized.current) {
57+
setExpanded(sections.map(section => section.id));
58+
hasInitialized.current = true;
59+
}
60+
}, [defaultExpanded, sections, setExpanded]);
61+
5362
const handleDrag = (
5463
_: React.DragEvent<Element>,
5564
item: IDraggableListItem
@@ -113,12 +122,14 @@ const Accordion: FC<IAccordionProps> = ({
113122
e.preventDefault();
114123
onSectionClick?.(section);
115124
setSelectedSectionId(section.id);
125+
setSelectedItemId(null);
126+
toggleExpand(section.id);
116127
}}
117128
className={classNames(
118-
"yl:relative yl:flex yl:cursor-default yl:select-none yl:items-center yl:font-semibold yl:capitalize yl:p-4",
129+
"yl:relative yl:flex yl:cursor-default yl:select-none yl:items-center yl:font-semibold yl:capitalize yl:p-4 yl:hover:text-primary yl:transition-colors yl:duration-400 yl:ease-in-out yl:hover:cursor-pointer",
119130
sectionTitleClassName,
120131
{
121-
"yl:bg-text/5": expanded.includes(section.id),
132+
"yl:bg-text/2": expanded.includes(section.id),
122133
"yl:cursor-pointer": onSectionItemClick,
123134
"yl:text-text":
124135
selectedSectionId !== section.id || !onSectionItemClick,
@@ -147,22 +158,12 @@ const Accordion: FC<IAccordionProps> = ({
147158
<Icon
148159
iconName='IconExpandLess'
149160
dataTestId='icon-expand-less'
150-
onClick={e => {
151-
e.stopPropagation();
152-
e.preventDefault();
153-
toggleExpand(section.id);
154-
}}
155161
className='yl:absolute yl:right-2 yl:w-6 yl:cursor-pointer yl:fill-primary yl:hover:fill-primary'
156162
/>
157163
) : (
158164
<Icon
159165
iconName='IconExpandMore'
160166
dataTestId='icon-expand-more'
161-
onClick={e => {
162-
e.stopPropagation();
163-
e.preventDefault();
164-
toggleExpand(section.id);
165-
}}
166167
className='yl:absolute yl:right-2 yl:w-6 yl:cursor-pointer yl:fill-primary yl:hover:fill-primary'
167168
/>
168169
)}
@@ -183,6 +184,7 @@ const Accordion: FC<IAccordionProps> = ({
183184
onSectionItemClick?.(item);
184185
onSelected?.(item);
185186
setSelectedItemId(item.id);
187+
setSelectedSectionId(null);
186188
}}
187189
onDragged={(items: IDraggableListItem[]) => {
188190
onSorted?.(
@@ -200,12 +202,12 @@ const Accordion: FC<IAccordionProps> = ({
200202
draggedOverClassName='yl:border-t-2 yl:border-border'
201203
liClassName={(item: IDraggableListItem) =>
202204
classNames(
203-
"yl:cursor-default hover:text-text break-words leading-normal yl:px-4",
205+
"yl:cursor-default yl:break-words yl:leading-normal yl:px-4",
204206
{
205-
"yl:cursor-pointer": onSectionItemClick,
206-
"yl:text-text": selectedItemId !== item.id,
207-
// "yl:text-text":
208-
// onSectionItemClick && selectedItemId === item.id,
207+
"yl:hover:cursor-pointer yl:hover:text-primary":
208+
onSectionItemClick,
209+
"yl:text-primary":
210+
onSectionItemClick && selectedItemId === item.id,
209211
"yl:pl-5": section.items.length === 1
210212
}
211213
)
@@ -215,17 +217,29 @@ const Accordion: FC<IAccordionProps> = ({
215217
<div
216218
onClick={() => onAddSectionItem(section)}
217219
className={classNames(
218-
"yl:cursor-pointer yl:hover:text-text yl:pb-4 yl:text-text yl:text-center yl:flex yl:items-center yl:justify-center yl:gap-1"
220+
"yl:group yl:border-border yl:hover:bg-text/2 yl:cursor-pointer"
219221
)}
222+
role='presentation'
220223
>
221-
<Icon
222-
iconName='IconAddCircle'
223-
dataTestId='icon-add-circle'
224-
className='yl:w-6'
225-
/>
226-
{addSectionItemLabel && (
227-
<span className='yl:text-sm'>{addSectionItemLabel}</span>
228-
)}
224+
<h3
225+
className={classNames(
226+
"yl:flex yl:flex-col yl:items-center yl:justify-center yl:select-none yl:font-semibold yl:p-4 yl:text-center"
227+
)}
228+
role='button'
229+
>
230+
<Paragraph className='yl:flex yl:items-center yl:gap-1'>
231+
<Icon
232+
iconName='IconAddCircle'
233+
dataTestId='icon-add-circle'
234+
className='yl:w-6 yl:text-primary'
235+
/>
236+
{addSectionItemLabel && (
237+
<span className='yl:text-sm yl:text-primary'>
238+
{addSectionItemLabel}
239+
</span>
240+
)}
241+
</Paragraph>
242+
</h3>
229243
</div>
230244
)}
231245
</>
@@ -236,7 +250,7 @@ const Accordion: FC<IAccordionProps> = ({
236250
<div
237251
onClick={onAddSection}
238252
className={classNames(
239-
"yl:group yl:border-2 yl:border-t-0 yl:border-border yl:hover:bg-text/5 yl:rounded-bl-md yl:rounded-br-md yl:cursor-pointer"
253+
"yl:group yl:border-2 yl:border-t-0 yl:border-border yl:hover:bg-text/2 yl:rounded-bl-md yl:rounded-br-md yl:cursor-pointer"
240254
)}
241255
role='presentation'
242256
>
@@ -246,14 +260,16 @@ const Accordion: FC<IAccordionProps> = ({
246260
)}
247261
role='button'
248262
>
249-
<Paragraph className='yl:text-text/70 yl:group-hover:text-text yl:flex yl:items-center yl:gap-1'>
263+
<Paragraph className='yl:flex yl:items-center yl:gap-1'>
250264
<Icon
251265
iconName='IconAddCircle'
252266
dataTestId='icon-add-circle'
253-
className='yl:w-6 yl:group-hover:text-text'
267+
className='yl:w-6 yl:text-primary'
254268
/>
255269
{addSectionLabel && (
256-
<span className='yl:text-sm'>{addSectionLabel}</span>
270+
<span className='yl:text-sm yl:text-primary'>
271+
{addSectionLabel}
272+
</span>
257273
)}
258274
</Paragraph>
259275
</h3>

src/Components/Accordion/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ export interface IAccordionProps {
4040
selectedId?: number;
4141
hasDraggableSections?: boolean;
4242
hasDraggableSectionItems?: boolean;
43+
defaultExpanded?: boolean;
4344
}

0 commit comments

Comments
 (0)