free-astro-components 1.0.13 → 1.1.1
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.
- package/README.md +3 -0
- package/package.json +1 -1
- package/src/components/Accordion.astro +111 -0
- package/src/components/AccordionItem.astro +92 -0
- package/src/components/Modal.astro +5 -1
- package/src/index.js +3 -1
- package/src/types/index.d.ts +8 -0
- package/src/utils/accordion.ts +40 -0
- package/src/utils/utils.ts +35 -0
package/README.md
CHANGED
|
@@ -32,6 +32,9 @@ Explore and utilize a variety of components that can help you build your web pro
|
|
|
32
32
|
- **ModalHeader**: The header section of the modal, usually containing a title.
|
|
33
33
|
- **ModalBody**: The main content area of the modal.
|
|
34
34
|
- **ModalFooter**: The footer section of the modal, typically containing action buttons.
|
|
35
|
+
- **Accordion**
|
|
36
|
+
- A component for creating collapsible content sections.
|
|
37
|
+
- **AccordionItem**: A subcomponent for individual accordion items.
|
|
35
38
|
|
|
36
39
|
## Getting Started
|
|
37
40
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
import '../css/main.css'
|
|
3
|
+
import type { AccordionItem } from '../../.'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
variant?: 'light' | 'shadow' | 'bordered' | 'splitted'
|
|
7
|
+
class?: string
|
|
8
|
+
children: AccordionItem | AccordionItem[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { variant = 'light', class: className } = Astro.props
|
|
12
|
+
const variantClasses = {
|
|
13
|
+
light: 'ac-accordion--light',
|
|
14
|
+
shadow: 'ac-accordion--shadow',
|
|
15
|
+
bordered: 'ac-accordion--bordered',
|
|
16
|
+
splitted: 'ac-accordion--splitted',
|
|
17
|
+
}[variant]
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<div class:list={['ac-accordion', variantClasses, className]}>
|
|
21
|
+
<slot />
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<style>
|
|
25
|
+
:root {
|
|
26
|
+
--ac-accordion-background-color: rgb(var(--ac-color-100));
|
|
27
|
+
--ac-accordion-border-color: var(--ac-color-200);
|
|
28
|
+
--ac-accordion-border-width: var(--ac-border);
|
|
29
|
+
--ac-accordion-rounded: var(--ac-rounded-2xl);
|
|
30
|
+
--ac-accordion-spacing: var(--ac-spacing-4);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.ac-accordion {
|
|
34
|
+
background: transparent;
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
|
|
38
|
+
&.ac-accordion--light {
|
|
39
|
+
> * + * {
|
|
40
|
+
border-color: rgb(var(--ac-accordion-border-color));
|
|
41
|
+
border-top-width: var(--ac-accordion-border-width);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&.ac-accordion--shadow {
|
|
46
|
+
background-color: var(--ac-accordion-background-color);
|
|
47
|
+
border-radius: var(--ac-accordion-rounded);
|
|
48
|
+
border-width: var(--ac-accordion-border-width);
|
|
49
|
+
border-color: rgba(var(--ac-accordion-border-color), 0.5);
|
|
50
|
+
box-shadow:
|
|
51
|
+
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
52
|
+
0 -5px 15px -4px rgb(0 0 0 / 0.05);
|
|
53
|
+
padding: 0 var(--ac-accordion-spacing);
|
|
54
|
+
|
|
55
|
+
> * + * {
|
|
56
|
+
border-color: rgb(var(--ac-accordion-border-color));
|
|
57
|
+
border-top-width: var(--ac-accordion-border-width);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&.ac-accordion--bordered {
|
|
62
|
+
border-color: rgb(var(--ac-accordion-border-color));
|
|
63
|
+
border-radius: var(--ac-accordion-rounded);
|
|
64
|
+
border-width: calc(var(--ac-accordion-border-width) * 2);
|
|
65
|
+
padding: 0 var(--ac-accordion-spacing);
|
|
66
|
+
|
|
67
|
+
> * + * {
|
|
68
|
+
border-color: rgb(var(--ac-accordion-border-color));
|
|
69
|
+
border-top-width: var(--ac-accordion-border-width);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&.ac-accordion--splitted {
|
|
74
|
+
gap: var(--ac-spacing-2);
|
|
75
|
+
|
|
76
|
+
> * {
|
|
77
|
+
background-color: var(--ac-accordion-background-color);
|
|
78
|
+
border-radius: var(--ac-accordion-rounded);
|
|
79
|
+
border-width: var(--ac-accordion-border-width);
|
|
80
|
+
border-color: rgba(var(--ac-accordion-border-color), 0.5);
|
|
81
|
+
padding: 0 var(--ac-accordion-spacing);
|
|
82
|
+
box-shadow:
|
|
83
|
+
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
84
|
+
0 -5px 15px -4px rgb(0 0 0 / 0.05);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
</style>
|
|
89
|
+
|
|
90
|
+
<script>
|
|
91
|
+
import {
|
|
92
|
+
DOMLoaded,
|
|
93
|
+
handleResize,
|
|
94
|
+
hasViewportWidthChanged,
|
|
95
|
+
} from '../utils/utils'
|
|
96
|
+
import { setAccordionHeight } from '../utils/accordion'
|
|
97
|
+
|
|
98
|
+
DOMLoaded(() => {
|
|
99
|
+
const accordions = document.querySelectorAll<HTMLDetailsElement>(
|
|
100
|
+
'[data-accordion-item]'
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
setAccordionHeight(accordions)
|
|
104
|
+
|
|
105
|
+
handleResize(() => {
|
|
106
|
+
if (hasViewportWidthChanged()) {
|
|
107
|
+
setAccordionHeight(accordions)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
</script>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Icon from './Icon.astro'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
open?: boolean
|
|
6
|
+
title: string
|
|
7
|
+
name?: string
|
|
8
|
+
class?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { open, title, name, class: className } = Astro.props
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<details
|
|
15
|
+
data-accordion-item
|
|
16
|
+
class:list={['ac-accordion-item', className]}
|
|
17
|
+
name={name}
|
|
18
|
+
open={open}
|
|
19
|
+
>
|
|
20
|
+
<summary class="ac-accordion-item-title">
|
|
21
|
+
<span>{title}</span>
|
|
22
|
+
<Icon icon="add" />
|
|
23
|
+
</summary>
|
|
24
|
+
<div class="ac-accordion-item-content">
|
|
25
|
+
<slot />
|
|
26
|
+
</div>
|
|
27
|
+
</details>
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.ac-accordion-item {
|
|
31
|
+
margin: 0;
|
|
32
|
+
font-family: var(--ac-font-sans);
|
|
33
|
+
height: var(--ac-accordion-item-collapsed);
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
|
|
36
|
+
&[open] {
|
|
37
|
+
height: var(--ac-accordion-item-expanded);
|
|
38
|
+
|
|
39
|
+
.ac-accordion-item-title {
|
|
40
|
+
color: rgb(var(--ac-color-700));
|
|
41
|
+
|
|
42
|
+
& > svg {
|
|
43
|
+
transform: rotate(-45deg);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.accordion-item--animated {
|
|
49
|
+
transition: height 0.3s linear;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.ac-accordion-item-title {
|
|
54
|
+
align-items: center;
|
|
55
|
+
color: rgb(var(--ac-color-500));
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
display: flex;
|
|
58
|
+
font-size: var(--ac-text-lg);
|
|
59
|
+
font-weight: var(--ac-font-medium);
|
|
60
|
+
gap: var(--ac-spacing-3);
|
|
61
|
+
justify-content: space-between;
|
|
62
|
+
line-height: var(--ac-leading-normal);
|
|
63
|
+
list-style-type: none;
|
|
64
|
+
padding: var(--ac-accordion-spacing) 0;
|
|
65
|
+
transition: color 0.3s ease-in-out;
|
|
66
|
+
|
|
67
|
+
&:hover,
|
|
68
|
+
&:focus {
|
|
69
|
+
color: rgb(var(--ac-color-700));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&::marker,
|
|
73
|
+
&::-webkit-details-marker {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
& > span {
|
|
78
|
+
flex: 1 1 auto;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
& > svg {
|
|
82
|
+
width: var(--ac-spacing-6);
|
|
83
|
+
height: var(--ac-spacing-6);
|
|
84
|
+
transition: transform 0.3s ease-in-out;
|
|
85
|
+
color: rgb(var(--ac-color-400));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ac-accordion-item-content {
|
|
90
|
+
padding: 0 0 var(--ac-accordion-spacing);
|
|
91
|
+
}
|
|
92
|
+
</style>
|
|
@@ -7,7 +7,11 @@ interface Props {
|
|
|
7
7
|
id: string
|
|
8
8
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | 'full'
|
|
9
9
|
class?: string
|
|
10
|
-
children:
|
|
10
|
+
children:
|
|
11
|
+
| ModalHeader
|
|
12
|
+
| ModalBody
|
|
13
|
+
| ModalFooter
|
|
14
|
+
| [ModalHeader, ModalBody, ModalFooter]
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
const { id, size = 'md', class: className } = Astro.props
|
package/src/index.js
CHANGED
|
@@ -14,4 +14,6 @@ export { default as ModalHeader } from './components/ModalHeader.astro'
|
|
|
14
14
|
export { default as ModalBody } from './components/ModalBody.astro'
|
|
15
15
|
export { default as ModalFooter } from './components/ModalFooter.astro'
|
|
16
16
|
export { openModal } from './utils/modal.ts'
|
|
17
|
-
export { closeModal } from './utils/modal.ts'
|
|
17
|
+
export { closeModal } from './utils/modal.ts'
|
|
18
|
+
export { default as Accordion } from './components/Accordion.astro'
|
|
19
|
+
export { default as AccordionItem } from './components/AccordionItem.astro'
|
package/src/types/index.d.ts
CHANGED
|
@@ -65,3 +65,11 @@ export const openModal: openModal
|
|
|
65
65
|
// closeModal function
|
|
66
66
|
export type closeModal = typeof import('../index.js').closeModal
|
|
67
67
|
export const closeModal: closeModal
|
|
68
|
+
|
|
69
|
+
// Accordion component
|
|
70
|
+
export type Accordion = typeof import('../index.js').Accordion
|
|
71
|
+
export const Accordion: Accordion
|
|
72
|
+
|
|
73
|
+
// AccordionItem component
|
|
74
|
+
export type AccordionItem = typeof import('../index.js').AccordionItem
|
|
75
|
+
export const AccordionItem: AccordionItem
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const setAccordionHeight = (
|
|
2
|
+
accordions: NodeListOf<HTMLDetailsElement>,
|
|
3
|
+
) => {
|
|
4
|
+
const originalStates = Array.from(accordions).map(
|
|
5
|
+
(accordion) => accordion.open,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
accordions.forEach((accordion) => {
|
|
9
|
+
accordion.classList.remove('accordion-item--animated')
|
|
10
|
+
resetAccordionHeight(accordion)
|
|
11
|
+
assignHeight(accordion)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
accordions.forEach((accordion, index) => {
|
|
15
|
+
accordion.open = originalStates[index]
|
|
16
|
+
accordion.classList.add('accordion-item--animated')
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const resetAccordionHeight = (accordion: HTMLDetailsElement) => {
|
|
21
|
+
accordion.style.removeProperty('--ac-accordion-item-expanded')
|
|
22
|
+
accordion.style.removeProperty('--ac-accordion-item-collapsed')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const assignHeight = (accordion: HTMLDetailsElement) => {
|
|
26
|
+
accordion.open = false
|
|
27
|
+
const collapsedHeight = accordion.offsetHeight
|
|
28
|
+
|
|
29
|
+
accordion.open = true
|
|
30
|
+
const expandedHeight = accordion.scrollHeight
|
|
31
|
+
|
|
32
|
+
accordion.style.setProperty(
|
|
33
|
+
'--ac-accordion-item-expanded',
|
|
34
|
+
`${expandedHeight}px`,
|
|
35
|
+
)
|
|
36
|
+
accordion.style.setProperty(
|
|
37
|
+
'--ac-accordion-item-collapsed',
|
|
38
|
+
`${collapsedHeight}px`,
|
|
39
|
+
)
|
|
40
|
+
}
|
package/src/utils/utils.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
let lastWidth: number;
|
|
2
|
+
|
|
1
3
|
export const DOMLoaded = (callback: () => void) => {
|
|
2
4
|
if (document.readyState === 'loading') {
|
|
3
5
|
document.addEventListener('DOMContentLoaded', callback)
|
|
@@ -6,6 +8,39 @@ export const DOMLoaded = (callback: () => void) => {
|
|
|
6
8
|
}
|
|
7
9
|
}
|
|
8
10
|
|
|
11
|
+
export const debounce = (callback: (...args: any[]) => void, delay: number) => {
|
|
12
|
+
let timeout: number
|
|
13
|
+
|
|
14
|
+
return (...args: any[]) => {
|
|
15
|
+
clearTimeout(timeout)
|
|
16
|
+
timeout = window.setTimeout(() => callback(...args), delay)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const handleResize = (callback: () => void) => {
|
|
21
|
+
const debouncedCallback = debounce(callback, 300)
|
|
22
|
+
window.addEventListener('resize', debouncedCallback)
|
|
23
|
+
|
|
24
|
+
return () => {
|
|
25
|
+
window.removeEventListener('resize', debouncedCallback)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
9
29
|
export const isTouchDevice = () => {
|
|
10
30
|
return window.matchMedia('(pointer: coarse)').matches
|
|
11
31
|
}
|
|
32
|
+
|
|
33
|
+
export const hasViewportWidthChanged = (): boolean => {
|
|
34
|
+
if (typeof window !== 'undefined') {
|
|
35
|
+
const currentWidth = window.innerWidth;
|
|
36
|
+
const widthChanged = currentWidth !== lastWidth;
|
|
37
|
+
|
|
38
|
+
if (widthChanged) {
|
|
39
|
+
lastWidth = currentWidth;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return widthChanged;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return false;
|
|
46
|
+
};
|