webcoreui 1.3.0 → 1.4.0
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 +6 -3
- package/astro.d.ts +6 -0
- package/astro.js +4 -0
- package/components/Accordion/Accordion.astro +1 -0
- package/components/Accordion/Accordion.svelte +1 -1
- package/components/Accordion/Accordion.tsx +1 -1
- package/components/Accordion/accordion.ts +1 -0
- package/components/Avatar/Avatar.astro +4 -2
- package/components/Avatar/Avatar.svelte +6 -4
- package/components/Avatar/Avatar.tsx +4 -2
- package/components/Checkbox/Checkbox.svelte +2 -0
- package/components/Checkbox/Checkbox.tsx +0 -2
- package/components/Checkbox/checkbox.ts +3 -1
- package/components/Collapsible/collapsible.ts +1 -1
- package/components/DataTable/DataTable.astro +4 -4
- package/components/DataTable/DataTable.svelte +1 -1
- package/components/DataTable/DataTable.tsx +1 -1
- package/components/Image/Image.astro +45 -0
- package/components/Image/Image.svelte +51 -0
- package/components/Image/Image.tsx +52 -0
- package/components/Image/image.module.scss +47 -0
- package/components/Image/image.ts +13 -0
- package/components/ImageLoader/ImageLoader.astro +82 -0
- package/components/ImageLoader/ImageLoader.svelte +72 -0
- package/components/ImageLoader/ImageLoader.tsx +82 -0
- package/components/ImageLoader/imageloader.module.scss +13 -0
- package/components/ImageLoader/imageloader.ts +6 -0
- package/components/Input/input.ts +2 -2
- package/components/Popover/popover.module.scss +4 -2
- package/components/RangeSlider/RangeSlider.svelte +3 -3
- package/components/RangeSlider/RangeSlider.tsx +1 -1
- package/components/Switch/Switch.svelte +2 -0
- package/components/Switch/Switch.tsx +0 -2
- package/components/Switch/switch.module.scss +1 -0
- package/components/Switch/switch.ts +3 -1
- package/components/Textarea/Textarea.svelte +2 -0
- package/components/Textarea/textarea.ts +7 -6
- package/components/ThemeSwitcher/themeswitcher.module.scss +1 -0
- package/components/ThemeSwitcher/themeswitcher.ts +1 -0
- package/index.d.ts +12 -5
- package/package.json +22 -22
- package/react.d.ts +6 -0
- package/react.js +4 -0
- package/scss/resets.scss +2 -0
- package/svelte.d.ts +6 -0
- package/svelte.js +4 -0
- package/utils/DOMUtils.ts +3 -3
- package/utils/modal.ts +2 -2
- package/utils/popover.ts +87 -46
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
|
|
53
53
|
- Full documentation available on [webcoreui.dev](https://webcoreui.dev).
|
|
54
54
|
- For installation steps, visit our [setup docs](https://webcoreui.dev/docs/setup).
|
|
55
|
+
- To build and test components visually, visit our [builder](https://webcoreui.dev/build).
|
|
55
56
|
|
|
56
57
|
## Getting Started
|
|
57
58
|
|
|
@@ -64,15 +65,15 @@ Webcore can be used as a standalone project, or it can be integrated into your e
|
|
|
64
65
|
|
|
65
66
|
Webcore components use Sass for styling. To use the component library, you must have the following packages installed:
|
|
66
67
|
|
|
67
|
-
- [Sass](https://www.npmjs.com/package/sass) - `v1.
|
|
68
|
+
- [Sass](https://www.npmjs.com/package/sass) - `v1.97`
|
|
68
69
|
- [TypeScript](https://www.npmjs.com/package/typescript) - `v5.9`
|
|
69
70
|
|
|
70
71
|
Depending on your project setup, you'll also need the following packages:
|
|
71
72
|
|
|
72
73
|
- **For Astro projects**
|
|
73
|
-
- [Astro](https://www.npmjs.com/package/astro) - `v5.
|
|
74
|
+
- [Astro](https://www.npmjs.com/package/astro) - `v5.17`
|
|
74
75
|
- **For Svelte projects**
|
|
75
|
-
- [Svelte](https://www.npmjs.com/package/svelte) - `v5.
|
|
76
|
+
- [Svelte](https://www.npmjs.com/package/svelte) - `v5.53`
|
|
76
77
|
- **For React projects**
|
|
77
78
|
- [React](https://www.npmjs.com/package/react) - `v19.2`
|
|
78
79
|
- [React DOM](https://www.npmjs.com/package/react-dom) -`v19.2`
|
|
@@ -297,6 +298,8 @@ import { Accordion } from 'webcoreui/react'
|
|
|
297
298
|
- [Grid](https://github.com/Frontendland/webcoreui/tree/main/src/components/Grid)
|
|
298
299
|
- [Group](https://github.com/Frontendland/webcoreui/tree/main/src/components/Group)
|
|
299
300
|
- [Icon](https://github.com/Frontendland/webcoreui/tree/main/src/components/Icon)
|
|
301
|
+
- [Image](https://github.com/Frontendland/webcoreui/tree/main/src/components/Image)
|
|
302
|
+
- [ImageLoader](https://github.com/Frontendland/webcoreui/tree/main/src/components/ImageLoader)
|
|
300
303
|
- [Input](https://github.com/Frontendland/webcoreui/tree/main/src/components/Input)
|
|
301
304
|
- [Kbd](https://github.com/Frontendland/webcoreui/tree/main/src/components/Kbd)
|
|
302
305
|
- [List](https://github.com/Frontendland/webcoreui/tree/main/src/components/List)
|
package/astro.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ import type { FooterProps as WFooterProps } from './components/Footer/footer'
|
|
|
21
21
|
import type { GridProps as WGridProps } from './components/Grid/grid'
|
|
22
22
|
import type { GroupProps as WGroupProps } from './components/Group/group'
|
|
23
23
|
import type { IconProps as WIconProps } from './components/Icon/icon'
|
|
24
|
+
import type { ImageProps as WImageProps } from './components/Image/image'
|
|
25
|
+
import type { ImageLoaderProps as WImageLoaderProps } from './components/ImageLoader/imageloader'
|
|
24
26
|
import type { InputProps as WInputProps } from './components/Input/input'
|
|
25
27
|
import type { KbdProps as WKbdProps } from './components/Kbd/kbd'
|
|
26
28
|
import type { ListProps as WListProps } from './components/List/list'
|
|
@@ -83,6 +85,8 @@ declare module 'webcoreui/astro' {
|
|
|
83
85
|
export function Grid(_props: WGridProps): any
|
|
84
86
|
export function Group(_props: WGroupProps): any
|
|
85
87
|
export function Icon(_props: WIconProps): any
|
|
88
|
+
export function Image(_props: WImageProps): any
|
|
89
|
+
export function ImageLoader(_props: WImageLoaderProps): any
|
|
86
90
|
export function Input(_props: WInputProps): any
|
|
87
91
|
export function Kbd(_props: WKbdProps): any
|
|
88
92
|
export function List(_props: WListProps): any
|
|
@@ -138,6 +142,8 @@ declare module 'webcoreui/astro' {
|
|
|
138
142
|
export type GridProps = WGridProps
|
|
139
143
|
export type GroupProps = WGroupProps
|
|
140
144
|
export type IconProps = WIconProps
|
|
145
|
+
export type ImageProps = WImageProps
|
|
146
|
+
export type ImageLoaderProps = WImageLoaderProps
|
|
141
147
|
export type InputProps = WInputProps
|
|
142
148
|
export type KbdProps = WKbdProps
|
|
143
149
|
export type ListProps = WListProps
|
package/astro.js
CHANGED
|
@@ -21,6 +21,8 @@ import FooterComponent from './components/Footer/Footer.astro'
|
|
|
21
21
|
import GridComponent from './components/Grid/Grid.astro'
|
|
22
22
|
import GroupComponent from './components/Group/Group.astro'
|
|
23
23
|
import IconComponent from './components/Icon/Icon.astro'
|
|
24
|
+
import ImageComponent from './components/Image/Image.astro'
|
|
25
|
+
import ImageLoaderComponent from './components/ImageLoader/ImageLoader.astro'
|
|
24
26
|
import InputComponent from './components/Input/Input.astro'
|
|
25
27
|
import KbdComponent from './components/Kbd/Kbd.astro'
|
|
26
28
|
import ListComponent from './components/List/List.astro'
|
|
@@ -76,6 +78,8 @@ export const Footer = FooterComponent
|
|
|
76
78
|
export const Grid = GridComponent
|
|
77
79
|
export const Group = GroupComponent
|
|
78
80
|
export const Icon = IconComponent
|
|
81
|
+
export const Image = ImageComponent
|
|
82
|
+
export const ImageLoader = ImageLoaderComponent
|
|
79
83
|
export const Input = InputComponent
|
|
80
84
|
export const Kbd = KbdComponent
|
|
81
85
|
export const List = ListComponent
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
className
|
|
16
16
|
}: AccordionProps = $props()
|
|
17
17
|
|
|
18
|
-
let toggleState = $state(
|
|
18
|
+
let toggleState = $state(items.map(item => item.expanded ?? false))
|
|
19
19
|
|
|
20
20
|
const toggle = (index: number) => {
|
|
21
21
|
toggleState = toggleState.map((_, i) => index === i
|
|
@@ -14,7 +14,7 @@ const Accordion = ({
|
|
|
14
14
|
reverse,
|
|
15
15
|
className
|
|
16
16
|
}: AccordionProps) => {
|
|
17
|
-
const [state, setState] = useState(
|
|
17
|
+
const [state, setState] = useState(items.map(item => item.expanded ?? false))
|
|
18
18
|
|
|
19
19
|
const toggle = (index: number) => {
|
|
20
20
|
setState(state.map((_, i) => index === i
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { AvatarProps } from './avatar'
|
|
3
3
|
|
|
4
|
+
import Image from '../Image/Image.astro'
|
|
5
|
+
|
|
4
6
|
import styles from './avatar.module.scss'
|
|
5
7
|
|
|
6
8
|
interface Props extends AvatarProps {}
|
|
@@ -35,7 +37,7 @@ const groupClasses = [
|
|
|
35
37
|
style={borderColor ? `--w-avatar-border: ${borderColor};` : null}
|
|
36
38
|
>
|
|
37
39
|
{img.map((img, index) => (
|
|
38
|
-
<
|
|
40
|
+
<Image
|
|
39
41
|
src={img}
|
|
40
42
|
alt={Array.isArray(alt) ? alt[index] : alt}
|
|
41
43
|
width={Array.isArray(size) ? size[index] : size}
|
|
@@ -47,7 +49,7 @@ const groupClasses = [
|
|
|
47
49
|
))}
|
|
48
50
|
</div>
|
|
49
51
|
) : (
|
|
50
|
-
<
|
|
52
|
+
<Image
|
|
51
53
|
src={img}
|
|
52
54
|
alt={Array.isArray(alt) ? alt[0] : alt}
|
|
53
55
|
width={Array.isArray(size) ? size[0] : size}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { AvatarProps } from './avatar'
|
|
3
3
|
|
|
4
|
+
import Image from '../Image/Image.svelte'
|
|
5
|
+
|
|
4
6
|
import { classNames } from '../../utils/classNames'
|
|
5
7
|
|
|
6
8
|
import styles from './avatar.module.scss'
|
|
@@ -35,24 +37,24 @@
|
|
|
35
37
|
style={borderColor ? `--w-avatar-border: ${borderColor};` : null}
|
|
36
38
|
>
|
|
37
39
|
{#each img as img, index}
|
|
38
|
-
<
|
|
40
|
+
<Image
|
|
39
41
|
src={img}
|
|
40
42
|
alt={Array.isArray(alt) ? alt[index] : alt}
|
|
41
43
|
width={Array.isArray(size) ? size[index] : size}
|
|
42
44
|
height={Array.isArray(size) ? size[index] : size}
|
|
43
45
|
loading={lazy ? 'lazy' : null}
|
|
44
|
-
|
|
46
|
+
className={classes}
|
|
45
47
|
style={Array.isArray(size) ? `--w-avatar-index: ${size[index]}` : null}
|
|
46
48
|
/>
|
|
47
49
|
{/each}
|
|
48
50
|
</div>
|
|
49
51
|
{:else}
|
|
50
|
-
<
|
|
52
|
+
<Image
|
|
51
53
|
src={img}
|
|
52
54
|
alt={Array.isArray(alt) ? alt[0] : alt}
|
|
53
55
|
width={Array.isArray(size) ? size[0] : size}
|
|
54
56
|
height={Array.isArray(size) ? size[0] : size}
|
|
55
|
-
|
|
57
|
+
className={classes}
|
|
56
58
|
loading={lazy ? 'lazy' : null}
|
|
57
59
|
style={borderColor ? `--w-avatar-border: ${borderColor};` : null}
|
|
58
60
|
/>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import type { AvatarProps } from './avatar'
|
|
3
3
|
|
|
4
|
+
import Image from '../Image/Image.tsx'
|
|
5
|
+
|
|
4
6
|
import { classNames } from '../../utils/classNames'
|
|
5
7
|
|
|
6
8
|
import styles from './avatar.module.scss'
|
|
@@ -37,7 +39,7 @@ const Avatar = ({
|
|
|
37
39
|
style={borderColorStyle}
|
|
38
40
|
>
|
|
39
41
|
{img.map((img, index) => (
|
|
40
|
-
<
|
|
42
|
+
<Image
|
|
41
43
|
key={index}
|
|
42
44
|
src={img}
|
|
43
45
|
alt={Array.isArray(alt) ? alt[index] : alt}
|
|
@@ -53,7 +55,7 @@ const Avatar = ({
|
|
|
53
55
|
))}
|
|
54
56
|
</div>
|
|
55
57
|
) : (
|
|
56
|
-
<
|
|
58
|
+
<Image
|
|
57
59
|
src={img}
|
|
58
60
|
alt={Array.isArray(alt) ? alt[0] : alt}
|
|
59
61
|
width={Array.isArray(size) ? size[0] : size}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
color,
|
|
18
18
|
className,
|
|
19
19
|
onClick,
|
|
20
|
+
onChange,
|
|
20
21
|
...rest
|
|
21
22
|
}: SvelteCheckboxProps = $props()
|
|
22
23
|
|
|
@@ -42,6 +43,7 @@
|
|
|
42
43
|
checked={checked}
|
|
43
44
|
disabled={disabled}
|
|
44
45
|
onclick={onClick}
|
|
46
|
+
onchange={onChange}
|
|
45
47
|
{...rest}
|
|
46
48
|
/>
|
|
47
49
|
<span class={styles.check}>
|
|
@@ -16,7 +16,6 @@ const Checkbox = ({
|
|
|
16
16
|
disabled,
|
|
17
17
|
color,
|
|
18
18
|
className,
|
|
19
|
-
onClick,
|
|
20
19
|
...rest
|
|
21
20
|
}: ReactCheckboxProps) => {
|
|
22
21
|
const classes = classNames([
|
|
@@ -43,7 +42,6 @@ const Checkbox = ({
|
|
|
43
42
|
type="checkbox"
|
|
44
43
|
defaultChecked={checked}
|
|
45
44
|
disabled={disabled}
|
|
46
|
-
onClick={onClick}
|
|
47
45
|
{...rest}
|
|
48
46
|
/>
|
|
49
47
|
<span
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MouseEventHandler } from 'svelte/elements'
|
|
1
|
+
import type { ChangeEventHandler, MouseEventHandler } from 'svelte/elements'
|
|
2
2
|
|
|
3
3
|
export type CheckboxProps = {
|
|
4
4
|
checked?: boolean
|
|
@@ -11,9 +11,11 @@ export type CheckboxProps = {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export type SvelteCheckboxProps = {
|
|
14
|
+
onChange?: ChangeEventHandler<HTMLInputElement>
|
|
14
15
|
onClick?: MouseEventHandler<HTMLInputElement>
|
|
15
16
|
} & CheckboxProps
|
|
16
17
|
|
|
17
18
|
export type ReactCheckboxProps = {
|
|
19
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement>
|
|
18
20
|
onClick?: React.MouseEventHandler<HTMLInputElement>
|
|
19
21
|
} & CheckboxProps
|
|
@@ -149,7 +149,7 @@ const hasPagination = data?.length && itemsPerPage
|
|
|
149
149
|
{!!columnFilterItems?.length && (
|
|
150
150
|
<tfoot data-hidden="true">
|
|
151
151
|
<tr>
|
|
152
|
-
<td colspan={
|
|
152
|
+
<td colspan={headings?.length} class={styles['no-results']}>{noResultsLabel}</td>
|
|
153
153
|
</tr>
|
|
154
154
|
</tfoot>
|
|
155
155
|
)}
|
|
@@ -251,9 +251,9 @@ const hasPagination = data?.length && itemsPerPage
|
|
|
251
251
|
const sortedTableRows = Array.from(
|
|
252
252
|
table?.querySelectorAll('tbody tr') as NodeListOf<HTMLTableRowElement>
|
|
253
253
|
).sort((a, b) => {
|
|
254
|
-
let aValue: string | number = (a.querySelector(`[data-name
|
|
254
|
+
let aValue: string | number = (a.querySelector(`[data-name="${sortBy}"]`) as HTMLElement)
|
|
255
255
|
?.innerText.replace(/\s/g, '')
|
|
256
|
-
let bValue: string | number = (b.querySelector(`[data-name
|
|
256
|
+
let bValue: string | number = (b.querySelector(`[data-name="${sortBy}"]`) as HTMLElement)
|
|
257
257
|
?.innerText.replace(/\s/g, '')
|
|
258
258
|
|
|
259
259
|
if (!isNaN(aValue as any)) {
|
|
@@ -298,7 +298,7 @@ const hasPagination = data?.length && itemsPerPage
|
|
|
298
298
|
return
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
const affectedTableCells = Array.from(table.querySelectorAll(`[data-name
|
|
301
|
+
const affectedTableCells = Array.from(table.querySelectorAll(`[data-name="${eventName}"]`)) as HTMLElement[]
|
|
302
302
|
|
|
303
303
|
const columnToggleListElement = Array.from(event.list.children)
|
|
304
304
|
.find(child => (child as HTMLLIElement).dataset.name === event.name) as HTMLLIElement
|
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
{#if columnFilterIndexes?.length && !filteredData.length}
|
|
251
251
|
<tfoot>
|
|
252
252
|
<tr>
|
|
253
|
-
<td colspan={
|
|
253
|
+
<td colspan={headings?.length} class={styles['no-results']}>
|
|
254
254
|
{noResultsLabel}
|
|
255
255
|
</td>
|
|
256
256
|
</tr>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ImageProps } from './image'
|
|
3
|
+
|
|
4
|
+
import AspectRatio from '../AspectRatio/AspectRatio.astro'
|
|
5
|
+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.astro'
|
|
6
|
+
|
|
7
|
+
import styles from './image.module.scss'
|
|
8
|
+
|
|
9
|
+
interface Props extends ImageProps {}
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
src,
|
|
13
|
+
alt,
|
|
14
|
+
width,
|
|
15
|
+
height,
|
|
16
|
+
lazy,
|
|
17
|
+
ratio,
|
|
18
|
+
center,
|
|
19
|
+
full,
|
|
20
|
+
rounded,
|
|
21
|
+
className,
|
|
22
|
+
...rest
|
|
23
|
+
} = Astro.props
|
|
24
|
+
|
|
25
|
+
const classes = [
|
|
26
|
+
styles.img,
|
|
27
|
+
center && styles.center,
|
|
28
|
+
full && styles[full],
|
|
29
|
+
rounded && styles[rounded],
|
|
30
|
+
className
|
|
31
|
+
]
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
<ConditionalWrapper condition={!!ratio}>
|
|
35
|
+
<AspectRatio slot="wrapper" ratio={ratio || ''}>children</AspectRatio>
|
|
36
|
+
<img
|
|
37
|
+
{...rest}
|
|
38
|
+
src={src}
|
|
39
|
+
alt={alt || ''}
|
|
40
|
+
width={width}
|
|
41
|
+
height={height}
|
|
42
|
+
loading={lazy ? 'lazy' : null}
|
|
43
|
+
class:list={classes}
|
|
44
|
+
/>
|
|
45
|
+
</ConditionalWrapper>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ImageProps } from './image'
|
|
3
|
+
|
|
4
|
+
import AspectRatio from '../AspectRatio/AspectRatio.svelte'
|
|
5
|
+
|
|
6
|
+
import { classNames } from '../../utils/classNames'
|
|
7
|
+
|
|
8
|
+
import styles from './image.module.scss'
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
src,
|
|
12
|
+
alt,
|
|
13
|
+
width,
|
|
14
|
+
height,
|
|
15
|
+
lazy,
|
|
16
|
+
ratio,
|
|
17
|
+
center,
|
|
18
|
+
full,
|
|
19
|
+
rounded,
|
|
20
|
+
className,
|
|
21
|
+
...rest
|
|
22
|
+
}: ImageProps = $props()
|
|
23
|
+
|
|
24
|
+
const classes = classNames([
|
|
25
|
+
styles.img,
|
|
26
|
+
center && styles.center,
|
|
27
|
+
full && styles[full],
|
|
28
|
+
rounded && styles[rounded],
|
|
29
|
+
className
|
|
30
|
+
])
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
{#snippet img()}
|
|
34
|
+
<img
|
|
35
|
+
{...rest}
|
|
36
|
+
src={src}
|
|
37
|
+
alt={alt || ''}
|
|
38
|
+
width={width}
|
|
39
|
+
height={height}
|
|
40
|
+
loading={lazy ? 'lazy' : null}
|
|
41
|
+
class={classes}
|
|
42
|
+
/>
|
|
43
|
+
{/snippet}
|
|
44
|
+
|
|
45
|
+
{#if ratio}
|
|
46
|
+
<AspectRatio ratio={ratio}>
|
|
47
|
+
{@render img()}
|
|
48
|
+
</AspectRatio>
|
|
49
|
+
{:else}
|
|
50
|
+
{@render img()}
|
|
51
|
+
{/if}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import type { ImageProps } from './image'
|
|
3
|
+
|
|
4
|
+
import AspectRatio from '../AspectRatio/AspectRatio.tsx'
|
|
5
|
+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.tsx'
|
|
6
|
+
|
|
7
|
+
import { classNames } from '../../utils/classNames'
|
|
8
|
+
|
|
9
|
+
import styles from './image.module.scss'
|
|
10
|
+
|
|
11
|
+
const Image = ({
|
|
12
|
+
src,
|
|
13
|
+
alt,
|
|
14
|
+
width,
|
|
15
|
+
height,
|
|
16
|
+
lazy,
|
|
17
|
+
ratio,
|
|
18
|
+
center,
|
|
19
|
+
full,
|
|
20
|
+
rounded,
|
|
21
|
+
className,
|
|
22
|
+
...rest
|
|
23
|
+
}: ImageProps) => {
|
|
24
|
+
const classes = classNames([
|
|
25
|
+
styles.img,
|
|
26
|
+
center && styles.center,
|
|
27
|
+
full && styles[full],
|
|
28
|
+
rounded && styles[rounded],
|
|
29
|
+
className
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<ConditionalWrapper
|
|
34
|
+
condition={!!ratio}
|
|
35
|
+
wrapper={children => (
|
|
36
|
+
<AspectRatio ratio={ratio || ''}>{children}</AspectRatio>
|
|
37
|
+
)}
|
|
38
|
+
>
|
|
39
|
+
<img
|
|
40
|
+
{...rest}
|
|
41
|
+
src={src}
|
|
42
|
+
alt={alt || ''}
|
|
43
|
+
width={width}
|
|
44
|
+
height={height}
|
|
45
|
+
loading={lazy ? 'lazy' : undefined}
|
|
46
|
+
className={classes}
|
|
47
|
+
/>
|
|
48
|
+
</ConditionalWrapper>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default Image
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
@use '../../scss/config.scss' as *;
|
|
2
|
+
|
|
3
|
+
.img {
|
|
4
|
+
&.center {
|
|
5
|
+
@include spacing(auto-none);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
&.width {
|
|
9
|
+
@include size('w100%');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&.height {
|
|
13
|
+
@include size('h100%');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&.both {
|
|
17
|
+
@include size(100%);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&.top {
|
|
21
|
+
@include border-radius(top);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&.bottom {
|
|
25
|
+
@include border-radius(bottom);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&.left {
|
|
29
|
+
@include border-radius(left);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&.right {
|
|
33
|
+
@include border-radius(right);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&.diagonal {
|
|
37
|
+
@include border-radius(diagonal);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&.reverse-diagonal {
|
|
41
|
+
@include border-radius(reverse-diagonal);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&.none {
|
|
45
|
+
@include border-radius(none);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type ImageProps = {
|
|
2
|
+
src: string
|
|
3
|
+
alt: string
|
|
4
|
+
width: number | string
|
|
5
|
+
height: number | string
|
|
6
|
+
lazy?: boolean
|
|
7
|
+
ratio?: string
|
|
8
|
+
center?: boolean
|
|
9
|
+
full?: 'width' | 'height' | 'both'
|
|
10
|
+
rounded?: 'top' | 'bottom' | 'left' | 'right' | 'diagonal' | 'reverse-diagonal' | 'none'
|
|
11
|
+
className?: string
|
|
12
|
+
[key: string]: any
|
|
13
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ImageLoaderProps } from './imageloader'
|
|
3
|
+
|
|
4
|
+
import Image from '../Image/Image.astro'
|
|
5
|
+
import Skeleton from '../Skeleton/Skeleton.astro'
|
|
6
|
+
|
|
7
|
+
import { classNames } from '../../utils/classNames'
|
|
8
|
+
|
|
9
|
+
import styles from './imageloader.module.scss'
|
|
10
|
+
|
|
11
|
+
interface Props extends ImageLoaderProps {}
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
fallback,
|
|
15
|
+
animate,
|
|
16
|
+
type,
|
|
17
|
+
width,
|
|
18
|
+
height,
|
|
19
|
+
color,
|
|
20
|
+
waveColor,
|
|
21
|
+
className,
|
|
22
|
+
...rest
|
|
23
|
+
} = Astro.props
|
|
24
|
+
|
|
25
|
+
const styleVariables = classNames([
|
|
26
|
+
`width: ${width}px;`,
|
|
27
|
+
`height: ${height}px;`
|
|
28
|
+
])
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<div data-id="w-image-loader" class={styles.loader} style={styleVariables}>
|
|
32
|
+
<Skeleton
|
|
33
|
+
animate={animate}
|
|
34
|
+
type={type}
|
|
35
|
+
width={Number(width)}
|
|
36
|
+
height={Number(height)}
|
|
37
|
+
color={color}
|
|
38
|
+
waveColor={waveColor}
|
|
39
|
+
className={className}
|
|
40
|
+
/>
|
|
41
|
+
<Image
|
|
42
|
+
width={width}
|
|
43
|
+
height={height}
|
|
44
|
+
className={className}
|
|
45
|
+
data-fallback={fallback}
|
|
46
|
+
{...rest}
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
import { get, on } from '../../utils/DOMUtils'
|
|
52
|
+
|
|
53
|
+
const addEventListeners = () => {
|
|
54
|
+
const images = get<HTMLImageElement>('[data-id="w-image-loader"] img', true)
|
|
55
|
+
|
|
56
|
+
if (!images || !(images instanceof NodeList)) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
images.forEach(img => {
|
|
61
|
+
const container = img.parentElement as HTMLDivElement
|
|
62
|
+
const skeleton = container.firstElementChild as HTMLDivElement
|
|
63
|
+
|
|
64
|
+
const handleError = () => {
|
|
65
|
+
img.src = img.dataset.fallback || img.src
|
|
66
|
+
skeleton?.remove()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (img.complete) {
|
|
70
|
+
img.naturalWidth === 0 ? handleError() : skeleton?.remove()
|
|
71
|
+
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
img.addEventListener('load', () => skeleton?.remove(), { once: true })
|
|
76
|
+
img.addEventListener('error', () => handleError(), { once: true })
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
on(document, 'astro:after-swap', addEventListeners)
|
|
81
|
+
addEventListeners()
|
|
82
|
+
</script>
|