webcoreui 0.4.1 → 0.5.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.
Files changed (47) hide show
  1. package/README.md +230 -227
  2. package/astro.d.ts +6 -0
  3. package/astro.js +6 -0
  4. package/components/Avatar/Avatar.astro +9 -2
  5. package/components/Avatar/Avatar.svelte +3 -1
  6. package/components/Avatar/Avatar.tsx +4 -2
  7. package/components/Avatar/avatar.ts +1 -0
  8. package/components/Button/button.module.scss +6 -1
  9. package/components/Button/button.ts +2 -2
  10. package/components/Carousel/Carousel.astro +198 -0
  11. package/components/Carousel/Carousel.svelte +161 -0
  12. package/components/Carousel/Carousel.tsx +172 -0
  13. package/components/Carousel/carousel.module.scss +58 -0
  14. package/components/Carousel/carousel.ts +26 -0
  15. package/components/DataTable/DataTable.astro +332 -0
  16. package/components/DataTable/DataTable.svelte +272 -0
  17. package/components/DataTable/DataTable.tsx +287 -0
  18. package/components/DataTable/datatable.module.scss +102 -0
  19. package/components/DataTable/datatable.ts +41 -0
  20. package/components/Icon/map.ts +6 -0
  21. package/components/Input/input.module.scss +6 -0
  22. package/components/List/List.astro +1 -1
  23. package/components/List/List.svelte +1 -1
  24. package/components/List/List.tsx +1 -2
  25. package/components/Pagination/Pagination.astro +189 -0
  26. package/components/Pagination/Pagination.svelte +144 -0
  27. package/components/Pagination/Pagination.tsx +162 -0
  28. package/components/Pagination/pagination.module.scss +49 -0
  29. package/components/Pagination/pagination.ts +35 -0
  30. package/components/Select/Select.astro +8 -4
  31. package/components/Select/Select.svelte +15 -6
  32. package/components/Select/Select.tsx +15 -8
  33. package/components/Select/select.ts +7 -2
  34. package/components/Table/Table.svelte +1 -1
  35. package/components/Table/table.ts +1 -1
  36. package/icons/arrow-left.svg +3 -0
  37. package/icons/arrow-right.svg +3 -0
  38. package/icons/order.svg +3 -0
  39. package/icons.d.ts +3 -0
  40. package/icons.js +3 -0
  41. package/index.d.ts +6 -6
  42. package/package.json +1 -1
  43. package/react.d.ts +6 -0
  44. package/react.js +6 -0
  45. package/scss/resets.scss +27 -1
  46. package/svelte.d.ts +6 -0
  47. package/svelte.js +6 -0
@@ -0,0 +1,198 @@
1
+ ---
2
+ import type { CarouselProps } from './carousel'
3
+
4
+ import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.astro'
5
+ import Pagination from '../Pagination/Pagination.astro'
6
+ import Progress from '../Progress/Progress.astro'
7
+
8
+ import { classNames } from '../../utils/classNames'
9
+
10
+ import styles from './carousel.module.scss'
11
+
12
+ interface Props extends CarouselProps {}
13
+
14
+ const {
15
+ items,
16
+ visibleItems = 1,
17
+ subText,
18
+ scrollSnap = true,
19
+ progress,
20
+ pagination,
21
+ effect,
22
+ debounce = 20,
23
+ className,
24
+ wrapperClassName,
25
+ paginationClassName
26
+ } = Astro.props
27
+
28
+ const classes = [
29
+ styles.carousel,
30
+ className
31
+ ]
32
+
33
+ const containerClasses = [
34
+ styles.container,
35
+ scrollSnap && styles.snap
36
+ ]
37
+
38
+ const wrapperClasses = [
39
+ styles.wrapper,
40
+ effect && styles[effect],
41
+ wrapperClassName
42
+ ]
43
+
44
+ const paginationWrapperClasses = [
45
+ styles['pagination-wrapper'],
46
+ paginationClassName
47
+ ]
48
+
49
+ const paginationClasses = classNames([
50
+ styles.pagination,
51
+ !subText && paginationClassName
52
+ ])
53
+
54
+ const totalPages = Math.ceil(items / visibleItems)
55
+ const subTextValue = subText?.match(/\{0\}|\{1\}/g) ? subText : undefined
56
+ const style = visibleItems > 1
57
+ ? `--w-slide-width: ${100 / visibleItems}%;`
58
+ : null
59
+ ---
60
+
61
+ <section class:list={classes}>
62
+ <div
63
+ class:list={containerClasses}
64
+ data-id="w-carousel"
65
+ data-debounce={debounce !== 20 && debounce}
66
+ >
67
+ <ul
68
+ class:list={wrapperClasses}
69
+ style={style}
70
+ data-visible-items={visibleItems > 1 ? visibleItems : null}
71
+ >
72
+ <slot />
73
+ </ul>
74
+ </div>
75
+ <ConditionalWrapper condition={!!(subText || progress)}>
76
+ <div slot="wrapper" class:list={paginationWrapperClasses}>children</div>
77
+ {progress && (
78
+ <Progress
79
+ className="w-carousel-progress"
80
+ value={0}
81
+ />
82
+ )}
83
+ <Pagination
84
+ type="arrows"
85
+ {...pagination}
86
+ totalPages={totalPages}
87
+ className={paginationClasses}
88
+ />
89
+ {subText && (
90
+ <span class={styles.subtext} data-text={subTextValue}>
91
+ {subText
92
+ .replace('{0}', '1')
93
+ .replace('{1}', String(totalPages))
94
+ }
95
+ </span>
96
+ )}
97
+ </ConditionalWrapper>
98
+ </section>
99
+
100
+ <script>
101
+ import { debounce } from '../../utils/debounce'
102
+ import { listen } from '../../utils/event'
103
+
104
+ const carousels = Array.from(document.querySelectorAll('[data-id="w-carousel"]'))
105
+
106
+ const scroll = (event: Event) => {
107
+ const target = event.target as HTMLDivElement
108
+
109
+ if (!target.dataset.paginated) {
110
+ const scrollLeft = target.scrollLeft
111
+ const itemWidth = target.children[0].clientWidth
112
+ const page = Math.round(scrollLeft / itemWidth) + 1
113
+ const carouselElement = target.children[0]
114
+ const paginationElement = target.parentElement
115
+ ?.querySelector('[data-id="w-pagination"]') as HTMLUListElement
116
+ const currentPage = Number(paginationElement.dataset.currentPage)
117
+ const diff = Math.abs(currentPage - page)
118
+
119
+ let triggerButton = currentPage > page
120
+ ? paginationElement.querySelector('[data-page="prev"]') as HTMLButtonElement
121
+ : paginationElement.querySelector('[data-page="next"]') as HTMLButtonElement
122
+
123
+ if (!triggerButton) {
124
+ triggerButton = paginationElement.querySelector(`[data-page="${page}"]`) as HTMLButtonElement
125
+ }
126
+
127
+ for (let i = 0; i < diff; i++) {
128
+ triggerButton.click()
129
+ }
130
+
131
+ Array.from(carouselElement.children).forEach(li => {
132
+ (li as HTMLLIElement).removeAttribute('data-active')
133
+ })
134
+
135
+ const activeElement = carouselElement.children[page - 1] as HTMLLIElement
136
+
137
+ activeElement.dataset.active = 'true'
138
+ }
139
+ }
140
+
141
+ carousels.forEach(carousel => {
142
+ const carouselElement = carousel as HTMLDivElement
143
+ const debounceAmount = carouselElement.dataset.debounce
144
+ ? Number(carouselElement.dataset.debounce)
145
+ : 20
146
+
147
+ carousel.addEventListener('scroll', debounce((event: Event) => {
148
+ scroll(event)
149
+ }, debounceAmount))
150
+ })
151
+
152
+ listen('paginate', event => {
153
+ const target = event.target
154
+ const carousel = target.closest('section').querySelector('[data-id="w-carousel"] ul')
155
+
156
+ if (!carousel) {
157
+ return
158
+ }
159
+
160
+ const progress = target.closest('section').querySelector('.w-carousel-progress')
161
+ const progressValue = (100 / (Number(target.dataset.totalPages) - 1))
162
+ const visibleItems = Number(carousel.dataset.visibleItems) || 0
163
+ const pageIndex = (event.page + visibleItems) - 1
164
+
165
+ const liElement = carousel.children[pageIndex]
166
+ const subText = event.target.nextElementSibling
167
+
168
+ Array.from(carousel.children).forEach(li => {
169
+ (li as HTMLLIElement).removeAttribute('data-active')
170
+ })
171
+
172
+ if (subText?.dataset.text) {
173
+ subText.innerText = subText.dataset.text
174
+ .replace('{0}', event.page)
175
+ .replace('{1}', target.dataset.totalPages)
176
+ }
177
+
178
+ if (progress) {
179
+ const updatedProgress = progressValue * (Number(event.page) - 1)
180
+
181
+ progress.children[0]
182
+ .style.setProperty('--w-progress-width', `${updatedProgress}%`)
183
+ }
184
+
185
+ if (event.trusted) {
186
+ const carouselContaienr = target.closest('section').querySelector('[data-id="w-carousel"]')
187
+
188
+ liElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
189
+ liElement.dataset.active = 'true'
190
+
191
+ carouselContaienr.dataset.paginated = 'true'
192
+
193
+ setTimeout(() => {
194
+ carouselContaienr.removeAttribute('data-paginated')
195
+ }, 300)
196
+ }
197
+ })
198
+ </script>
@@ -0,0 +1,161 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte'
3
+ import type { SvelteCarouselProps } from './carousel'
4
+
5
+ import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.svelte'
6
+ import Pagination from '../Pagination/Pagination.svelte'
7
+ import Progress from '../Progress/Progress.svelte'
8
+
9
+ import { classNames } from '../../utils/classNames'
10
+ import { debounce as debounceScroll } from '../../utils/debounce'
11
+
12
+ import styles from './carousel.module.scss'
13
+
14
+ import type { PaginationEventType } from '../Pagination/pagination'
15
+
16
+ export let items: SvelteCarouselProps['items'] = 0
17
+ export let visibleItems: SvelteCarouselProps['visibleItems'] = 1
18
+ export let subText: SvelteCarouselProps['subText'] = ''
19
+ export let scrollSnap: SvelteCarouselProps['scrollSnap'] = true
20
+ export let progress: SvelteCarouselProps['progress'] = false
21
+ export let pagination: SvelteCarouselProps['pagination'] = {}
22
+ export let effect: SvelteCarouselProps['effect'] = null
23
+ export let debounce: SvelteCarouselProps['debounce'] = 20
24
+ export let className: SvelteCarouselProps['className'] = ''
25
+ export let wrapperClassName: SvelteCarouselProps['wrapperClassName'] = ''
26
+ export let paginationClassName: SvelteCarouselProps['paginationClassName'] = ''
27
+ export let onScroll: SvelteCarouselProps['onScroll'] = () => {}
28
+
29
+ let carouselContainer: HTMLDivElement
30
+ let carousel: HTMLUListElement
31
+ let carouselItems: HTMLCollection | NodeListOf<HTMLLIElement>
32
+ let progressValue = 0
33
+ let paginated = false
34
+ let currentPage = 1
35
+
36
+ const classes = classNames([
37
+ styles.carousel,
38
+ className
39
+ ])
40
+
41
+ const containerClasses = classNames([
42
+ styles.container,
43
+ scrollSnap && styles.snap
44
+ ])
45
+
46
+ const wrapperClasses = classNames([
47
+ styles.wrapper,
48
+ effect && styles[effect],
49
+ wrapperClassName
50
+ ])
51
+
52
+ const paginationWrapperClasses = classNames([
53
+ styles['pagination-wrapper'],
54
+ paginationClassName
55
+ ])
56
+
57
+ const paginationClasses = classNames([
58
+ styles.pagination,
59
+ !subText && paginationClassName
60
+ ])
61
+
62
+ const totalPages = Math.ceil(items / visibleItems!)
63
+ const subTextValue = subText?.match(/\{0\}|\{1\}/g) ? subText : undefined
64
+ const style = visibleItems! > 1
65
+ ? `--w-slide-width: ${100 / visibleItems!}%;`
66
+ : null
67
+
68
+ const updateValues = () => {
69
+ const activeElement = carouselItems[currentPage - 1] as HTMLLIElement
70
+
71
+ Array.from(carouselItems).forEach(li => li.removeAttribute('data-active'))
72
+ activeElement.dataset.active = 'true'
73
+
74
+ if (subTextValue) {
75
+ subText = subTextValue
76
+ .replace('{0}', String(currentPage))
77
+ .replace('{1}', String(totalPages))
78
+ }
79
+
80
+ if (progress) {
81
+ const percentage = (100 / (totalPages - 1))
82
+
83
+ progressValue = percentage * (currentPage - 1)
84
+ }
85
+
86
+ onScroll?.(currentPage)
87
+ }
88
+
89
+ const scroll = debounceScroll((event: Event) => {
90
+ if (!paginated) {
91
+ const target = event.target as HTMLDivElement
92
+ const scrollLeft = target.scrollLeft
93
+ const itemWidth = target.children[0].clientWidth
94
+ const page = Math.round(scrollLeft / itemWidth) + 1
95
+
96
+ currentPage = page
97
+
98
+ updateValues()
99
+ }
100
+ }, debounce)
101
+
102
+ const paginate = (event: PaginationEventType) => {
103
+ const liElement = carouselItems[event.page - 1] as HTMLLIElement
104
+
105
+ liElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
106
+
107
+ currentPage = event.page
108
+ paginated = true
109
+
110
+ updateValues()
111
+ setTimeout(() => {
112
+ paginated = false
113
+ }, 300)
114
+ }
115
+
116
+ onMount(() => {
117
+ const usedInAstro = carousel.children[0].nodeName === 'ASTRO-SLOT'
118
+
119
+ carouselContainer.addEventListener('scroll', scroll)
120
+
121
+ carouselItems = usedInAstro
122
+ ? carousel.querySelectorAll('li')
123
+ : carousel.children
124
+
125
+ return () => {
126
+ carouselContainer.removeEventListener('scroll', scroll)
127
+ }
128
+ })
129
+ </script>
130
+
131
+ <section class={classes}>
132
+ <div class={containerClasses} bind:this={carouselContainer}>
133
+ <ul class={wrapperClasses} style={style} bind:this={carousel}>
134
+ <slot />
135
+ </ul>
136
+ </div>
137
+ <ConditionalWrapper
138
+ condition={!!(subText || progress)}
139
+ class={paginationWrapperClasses}
140
+ >
141
+ {#if progress}
142
+ <Progress value={progressValue} />
143
+ {/if}
144
+ <Pagination
145
+ type="arrows"
146
+ {...pagination}
147
+ currentPage={currentPage}
148
+ totalPages={totalPages}
149
+ className={paginationClasses}
150
+ onChange={paginate}
151
+ />
152
+ {#if subText}
153
+ <span class={styles.subtext}>
154
+ {subText
155
+ .replace('{0}', '1')
156
+ .replace('{1}', String(totalPages))
157
+ }
158
+ </span>
159
+ {/if}
160
+ </ConditionalWrapper>
161
+ </section>
@@ -0,0 +1,172 @@
1
+ import React, { useEffect, useRef, useState } from 'react'
2
+ import type { ReactCarouselProps } from './carousel'
3
+
4
+ import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.tsx'
5
+ import Pagination from '../Pagination/Pagination.tsx'
6
+ import Progress from '../Progress/Progress.tsx'
7
+
8
+ import { classNames } from '../../utils/classNames'
9
+ import { debounce as debounceScroll } from '../../utils/debounce'
10
+
11
+ import styles from './carousel.module.scss'
12
+
13
+ import type { PaginationEventType } from '../Pagination/pagination'
14
+
15
+ const Carousel = ({
16
+ items,
17
+ visibleItems = 1,
18
+ subText,
19
+ scrollSnap = true,
20
+ progress,
21
+ pagination,
22
+ effect,
23
+ debounce = 20,
24
+ className,
25
+ wrapperClassName,
26
+ paginationClassName,
27
+ onScroll,
28
+ children
29
+ }: ReactCarouselProps) => {
30
+ const carouselContainer = useRef<HTMLDivElement>(null)
31
+ const carousel = useRef<HTMLUListElement>(null)
32
+ const carouselItems = useRef<any>(null)
33
+ const paginated = useRef(false)
34
+ const currentPage = useRef(1)
35
+
36
+ const [progressValue, setProgressValue] = useState(0)
37
+ const [updatedSubText, setUpdatedSubText] = useState(subText)
38
+
39
+ const classes = classNames([
40
+ styles.carousel,
41
+ className
42
+ ])
43
+
44
+ const containerClasses = classNames([
45
+ styles.container,
46
+ scrollSnap && styles.snap
47
+ ])
48
+
49
+ const wrapperClasses = classNames([
50
+ styles.wrapper,
51
+ effect && styles[effect],
52
+ wrapperClassName
53
+ ])
54
+
55
+ const paginationWrapperClasses = classNames([
56
+ styles['pagination-wrapper'],
57
+ paginationClassName
58
+ ])
59
+
60
+ const paginationClasses = classNames([
61
+ styles.pagination,
62
+ !subText && paginationClassName
63
+ ])
64
+
65
+ const totalPages = Math.ceil(items / visibleItems!)
66
+ const subTextValue = subText?.match(/\{0\}|\{1\}/g) ? subText : undefined
67
+ const style = visibleItems > 1
68
+ ? { '--w-slide-width': `${100 / visibleItems}%;` } as React.CSSProperties
69
+ : undefined
70
+
71
+ const updateValues = (page: number) => {
72
+ const activeElement = carouselItems.current[page - 1]
73
+
74
+ Array.from(carouselItems.current).forEach(li => (li as HTMLLIElement).removeAttribute('data-active'))
75
+ activeElement.dataset.active = 'true'
76
+
77
+ if (subTextValue) {
78
+ setUpdatedSubText(
79
+ subTextValue
80
+ .replace('{0}', String(page))
81
+ .replace('{1}', String(totalPages))
82
+ )
83
+ }
84
+
85
+ if (progress) {
86
+ const percentage = (100 / (totalPages - 1))
87
+
88
+ setProgressValue(percentage * (page - 1))
89
+ }
90
+
91
+ onScroll?.(page)
92
+ }
93
+
94
+ const scroll = debounceScroll((event: Event) => {
95
+ if (!paginated.current) {
96
+ const target = event.target as HTMLDivElement
97
+ const scrollLeft = target.scrollLeft
98
+ const itemWidth = target.children[0].clientWidth
99
+ const page = Math.round(scrollLeft / itemWidth) + 1
100
+
101
+ currentPage.current = page
102
+
103
+ updateValues(page)
104
+ }
105
+ }, debounce)
106
+
107
+ const paginate = (event: PaginationEventType) => {
108
+ const liElement = carouselItems.current[event.page - 1]
109
+
110
+ liElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
111
+
112
+ currentPage.current = event.page
113
+ paginated.current = true
114
+
115
+ updateValues(event.page)
116
+ setTimeout(() => {
117
+ paginated.current = false
118
+ }, 300)
119
+ }
120
+
121
+ useEffect(() => {
122
+ const usedInAstro = carousel.current?.children[0].nodeName === 'ASTRO-SLOT'
123
+
124
+ carouselItems.current = usedInAstro
125
+ ? carousel.current.querySelectorAll('li')
126
+ : carousel.current?.children
127
+
128
+ carouselContainer.current?.addEventListener('scroll', scroll)
129
+
130
+ return () => {
131
+ carouselContainer.current?.removeEventListener('scroll', scroll)
132
+ }
133
+ }, [])
134
+
135
+ return (
136
+ <section className={classes}>
137
+ <div className={containerClasses} ref={carouselContainer}>
138
+ <ul className={wrapperClasses} style={style} ref={carousel}>
139
+ {children}
140
+ </ul>
141
+ </div>
142
+ <ConditionalWrapper
143
+ condition={!!(subText || progress)}
144
+ wrapper={children => (
145
+ <div className={paginationWrapperClasses}>{children}</div>
146
+ )}
147
+ >
148
+ {progress && (
149
+ <Progress value={progressValue} />
150
+ )}
151
+ <Pagination
152
+ type="arrows"
153
+ {...pagination}
154
+ currentPage={currentPage.current}
155
+ totalPages={totalPages}
156
+ className={paginationClasses}
157
+ onChange={paginate}
158
+ />
159
+ {updatedSubText && (
160
+ <span className={styles.subtext}>
161
+ {updatedSubText
162
+ .replace('{0}', '1')
163
+ .replace('{1}', String(totalPages))
164
+ }
165
+ </span>
166
+ )}
167
+ </ConditionalWrapper>
168
+ </section>
169
+ )
170
+ }
171
+
172
+ export default Carousel
@@ -0,0 +1,58 @@
1
+ @import '../../scss/config.scss';
2
+
3
+ body {
4
+ --w-slide-width: 100%;
5
+ }
6
+
7
+ .carousel {
8
+ @include layout(flex, sm, column);
9
+ }
10
+
11
+ .container {
12
+ @include layout(flex, sm);
13
+ @include visibility(auto);
14
+
15
+ scrollbar-width: none;
16
+
17
+ &.snap {
18
+ scroll-snap-type: x mandatory;
19
+ }
20
+ }
21
+
22
+ .wrapper {
23
+ @include layout(flex, sm);
24
+ @include spacing(0);
25
+ @include size('w100%');
26
+
27
+ list-style-type: none;
28
+
29
+ &.opacity li:not([data-active]) {
30
+ opacity: .5;
31
+ }
32
+
33
+ &.saturate li:not([data-active]) {
34
+ filter: saturate(0);
35
+ }
36
+
37
+ li {
38
+ @include transition();
39
+ @include spacing(m0);
40
+ @include layout(flex, h-center);
41
+
42
+ scroll-snap-align: center;
43
+ min-width: var(--w-slide-width);
44
+ }
45
+ }
46
+
47
+ .pagination-wrapper {
48
+ @include layout(flex, sm, column);
49
+ }
50
+
51
+ .pagination {
52
+ @include layout(h-center);
53
+ }
54
+
55
+ .subtext {
56
+ @include layout(flex, h-center);
57
+ @include typography(md, primary-20);
58
+ }
@@ -0,0 +1,26 @@
1
+ import type { PaginationProps } from '../Pagination/pagination'
2
+
3
+ export type CarouselProps = {
4
+ items: number
5
+ visibleItems?: number
6
+ subText?: string
7
+ autoplay?: boolean
8
+ vertical?: boolean
9
+ scrollSnap?: boolean
10
+ progress?: boolean
11
+ pagination?: PaginationProps
12
+ effect?: 'opacity' | 'saturate' | null
13
+ debounce?: number
14
+ className?: string
15
+ wrapperClassName?: string
16
+ paginationClassName?: string
17
+ }
18
+
19
+ export type SvelteCarouselProps = {
20
+ onScroll?: (event: number) => void
21
+ } & CarouselProps
22
+
23
+ export type ReactCarouselProps = {
24
+ onScroll?: (event: number) => void
25
+ children?: React.ReactNode
26
+ } & CarouselProps