webcoreui 0.10.1 → 1.0.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.
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte'
3
+ import type { SpeedDialProps } from './speeddial'
4
+
5
+ import Button from '../Button/Button.svelte'
6
+
7
+ import { classNames } from '../../utils/classNames'
8
+ import { get, on } from '../../utils/DOMUtils'
9
+
10
+ import styles from './speeddial.module.scss'
11
+
12
+ const {
13
+ items,
14
+ position,
15
+ horizontal,
16
+ circular,
17
+ theme,
18
+ icon,
19
+ triggerOnClick,
20
+ className
21
+ }: SpeedDialProps = $props()
22
+
23
+ let show = $state(false)
24
+
25
+ const classes = classNames([
26
+ styles.dial,
27
+ position && styles[position],
28
+ horizontal && styles.horizontal,
29
+ circular && styles.circular,
30
+ className
31
+ ])
32
+
33
+ const getTooltipPosition = () => {
34
+ const positionMap = {
35
+ 'top-left': 'right',
36
+ 'bottom-left': 'right',
37
+ 'horizontal': {
38
+ 'top-left': 'bottom',
39
+ 'top-right': 'bottom'
40
+ }
41
+ }
42
+
43
+ return horizontal
44
+ ? positionMap.horizontal[position as keyof typeof positionMap.horizontal]
45
+ : positionMap[position as keyof typeof positionMap] || 'left'
46
+ }
47
+
48
+ const toggle = () => show = !show
49
+
50
+ onMount(() => {
51
+ const speedDial = get('[data-id="w-speed-dial"] button') as HTMLButtonElement
52
+
53
+ const eventListener = (event: Event) => {
54
+ if (!speedDial.contains((event.target || event.currentTarget) as HTMLElement)) {
55
+ show = false
56
+ }
57
+ }
58
+
59
+ on(document, 'click', eventListener)
60
+
61
+ return () => {
62
+ document.removeEventListener('click', eventListener)
63
+ }
64
+ })
65
+ </script>
66
+
67
+ {#if items?.length}
68
+ <div
69
+ class={classes}
70
+ data-id={triggerOnClick ? 'w-speed-dial' : null}
71
+ data-show={triggerOnClick ? show : null}
72
+ >
73
+ <Button
74
+ className={styles.trigger}
75
+ onClick={triggerOnClick ? toggle : undefined}
76
+ {...(theme && { theme })}
77
+ >
78
+ {#if icon}
79
+ {@html icon}
80
+ {:else}
81
+ <span>+</span>
82
+ {/if}
83
+ </Button>
84
+
85
+ <ul class={styles.list}>
86
+ {#each items as item}
87
+ <li>
88
+ <Button
89
+ data-tooltip={item.tooltip}
90
+ data-position={getTooltipPosition()}
91
+ {...(theme && { theme })}
92
+ href={item.href}
93
+ target={item.target}
94
+ className={styles.button}
95
+ >
96
+ {@html item.icon}
97
+ </Button>
98
+ </li>
99
+ {/each}
100
+ </ul>
101
+ </div>
102
+ {/if}
@@ -0,0 +1,106 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import type { SpeedDialProps } from './speeddial'
3
+
4
+ import Button from '../Button/Button.tsx'
5
+
6
+ import { classNames } from '../../utils/classNames'
7
+ import { get, on } from '../../utils/DOMUtils'
8
+
9
+ import styles from './speeddial.module.scss'
10
+
11
+ const SpeedDial = ({
12
+ items,
13
+ position,
14
+ horizontal,
15
+ circular,
16
+ theme,
17
+ icon,
18
+ triggerOnClick,
19
+ className
20
+ }: SpeedDialProps) => {
21
+ const [show, setShow] = useState(false)
22
+
23
+ const classes = classNames([
24
+ styles.dial,
25
+ position && styles[position],
26
+ horizontal && styles.horizontal,
27
+ circular && styles.circular,
28
+ className
29
+ ])
30
+
31
+ const getTooltipPosition = () => {
32
+ const positionMap = {
33
+ 'top-left': 'right',
34
+ 'bottom-left': 'right',
35
+ 'horizontal': {
36
+ 'top-left': 'bottom',
37
+ 'top-right': 'bottom'
38
+ }
39
+ }
40
+
41
+ return horizontal
42
+ ? positionMap.horizontal[position as keyof typeof positionMap.horizontal]
43
+ : positionMap[position as keyof typeof positionMap] || 'left'
44
+ }
45
+
46
+ const toggle = () => {
47
+ setShow(!show)
48
+ }
49
+
50
+ useEffect(() => {
51
+ const speedDial = get('[data-id="w-speed-dial"] button') as HTMLButtonElement
52
+
53
+ const eventListener = (event: Event) => {
54
+ if (!speedDial.contains((event.target || event.currentTarget) as HTMLElement)) {
55
+ setShow(false)
56
+ }
57
+ }
58
+
59
+ on(document, 'click', eventListener)
60
+
61
+ return () => {
62
+ document.removeEventListener('click', eventListener)
63
+ }
64
+ }, [])
65
+
66
+ if (!items?.length) {
67
+ return null
68
+ }
69
+
70
+ return (
71
+ <div
72
+ className={classes}
73
+ data-id={triggerOnClick ? 'w-speed-dial' : null}
74
+ data-show={triggerOnClick ? show : null}
75
+ >
76
+ <Button
77
+ className={styles.trigger}
78
+ onClick={triggerOnClick ? toggle : undefined}
79
+ {...(theme && { theme })}
80
+ >
81
+ {icon && (
82
+ <span dangerouslySetInnerHTML={{ __html: icon }} />
83
+ )}
84
+ {!icon && <span>+</span>}
85
+ </Button>
86
+
87
+ <ul className={styles.list}>
88
+ {items.map((item, index) => (
89
+ <li key={index}>
90
+ <Button
91
+ data-tooltip={item.tooltip}
92
+ data-position={getTooltipPosition()}
93
+ href={item.href}
94
+ target={item.target}
95
+ className={styles.button}
96
+ dangerouslySetInnerHTML={{ __html: item.icon }}
97
+ {...(theme && { theme })}
98
+ />
99
+ </li>
100
+ ))}
101
+ </ul>
102
+ </div>
103
+ )
104
+ }
105
+
106
+ export default SpeedDial
@@ -0,0 +1,94 @@
1
+ @use '../../scss/config.scss' as *;
2
+
3
+ body {
4
+ --w-speed-dial-size: 40px;
5
+ }
6
+
7
+ .dial {
8
+ @include layout(flex, column-reverse, center, xs);
9
+ @include position(fixed, b20px, r20px);
10
+
11
+ width: fit-content;
12
+
13
+ &.top-left,
14
+ &.top-right {
15
+ @include position(t20px, bauto);
16
+ @include layout(column);
17
+ }
18
+
19
+ &.top-left,
20
+ &.bottom-left {
21
+ @include position(l20px, rauto);
22
+
23
+ &.horizontal {
24
+ @include layout(row);
25
+ }
26
+ }
27
+
28
+ &.circular {
29
+ .trigger,
30
+ .button {
31
+ @include border-radius(max);
32
+ }
33
+ }
34
+
35
+ &.horizontal {
36
+ @include layout(row-reverse, v-stretch);
37
+
38
+ .list {
39
+ @include layout(row, v-stretch);
40
+ }
41
+ }
42
+
43
+ &:not([data-id]):hover .list,
44
+ &[data-show="true"] .list {
45
+ @include layout(flex);
46
+ }
47
+
48
+ &:not([data-id]):hover .trigger span,
49
+ &[data-show="true"] .trigger span {
50
+ transform: rotate(45deg) translate(1px);
51
+ }
52
+ }
53
+
54
+ .trigger {
55
+ @include layout(flex, column);
56
+ @include typography(bold);
57
+ @include size(var(--w-speed-dial-size));
58
+
59
+ user-select: none;
60
+
61
+ span {
62
+ @include transition(transform);
63
+ }
64
+
65
+ svg {
66
+ @include size(18px);
67
+ }
68
+ }
69
+
70
+ .list {
71
+ @include spacing(0);
72
+ @include layout(flex, column, center, xs);
73
+ @include visibility(none);
74
+
75
+ list-style-type: none;
76
+
77
+ &:hover {
78
+ @include layout(flex);
79
+ }
80
+
81
+ li {
82
+ @include spacing(0);
83
+ @include size('w100%');
84
+ }
85
+
86
+ .button {
87
+ @include layout(flex, column, xs);
88
+ @include size(var(--w-speed-dial-size));
89
+
90
+ svg {
91
+ @include size(16px);
92
+ }
93
+ }
94
+ }
@@ -0,0 +1,18 @@
1
+ import type { ButtonProps } from '../Button/button'
2
+ import type { IconProps } from '../Icon/icon'
3
+
4
+ export type SpeedDialProps = {
5
+ items: {
6
+ icon: IconProps['type'] | string
7
+ href: string
8
+ tooltip?: string
9
+ target?: ButtonProps['target']
10
+ }[]
11
+ position?: 'top-left' | 'top-right' | 'bottom-left'
12
+ horizontal?: boolean
13
+ circular?: boolean
14
+ theme?: ButtonProps['theme']
15
+ icon?: IconProps['type'] | string
16
+ triggerOnClick?: boolean
17
+ className?: string
18
+ }
@@ -67,6 +67,17 @@ body {
67
67
  right: $rightOffset;
68
68
  }
69
69
  }
70
+
71
+ &.icons > li {
72
+ &:nth-child(even) > span:first-child {
73
+ left: 25px;
74
+ }
75
+
76
+ &:nth-child(odd) > span:first-child {
77
+ right: -15px;
78
+ }
79
+ }
80
+
70
81
  }
71
82
 
72
83
  &.centered > li:nth-child(odd) {
@@ -1,7 +1,7 @@
1
1
  import type { Snippet } from 'svelte'
2
2
 
3
3
  export type TimelineProps = {
4
- theme?: 'fill' | 'stroke' | 'stroke fill'
4
+ theme?: 'fill' | 'stroke' | 'stroke fill' | 'icons'
5
5
  alternate?: boolean
6
6
  centered?: boolean
7
7
  color?: string
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  import type { TimelineItemProps } from './timelineitem'
3
3
 
4
+ import Icon from '../Icon/Icon.astro'
5
+
4
6
  import styles from './timelineitem.module.scss'
5
7
 
6
8
  interface Props extends TimelineItemProps {}
@@ -8,11 +10,13 @@ interface Props extends TimelineItemProps {}
8
10
  const {
9
11
  title,
10
12
  titleTag = 'span',
13
+ icon,
11
14
  className
12
15
  } = Astro.props
13
16
 
14
17
  const classes = [
15
18
  styles.item,
19
+ icon && styles['with-icon'],
16
20
  className
17
21
  ]
18
22
 
@@ -20,6 +24,14 @@ const Title = titleTag
20
24
  ---
21
25
 
22
26
  <li class:list={classes}>
27
+ {icon && (
28
+ <span class={styles.icon}>
29
+ {icon.startsWith('<svg')
30
+ ? <Fragment set:html={icon} />
31
+ : <Icon type={icon} size={18} />
32
+ }
33
+ </span>
34
+ )}
23
35
  {title && (
24
36
  <Title class:list={styles.title}>{title}</Title>
25
37
  )}
@@ -8,17 +8,24 @@
8
8
  const {
9
9
  title,
10
10
  titleTag = 'span',
11
+ icon,
11
12
  className,
12
13
  children
13
14
  }: SvelteTimelineItemProps = $props()
14
15
 
15
16
  const classes = classNames([
16
17
  styles.item,
18
+ icon && styles['with-icon'],
17
19
  className
18
20
  ])
19
21
  </script>
20
22
 
21
23
  <li class={classes}>
24
+ {#if icon}
25
+ <span class={styles.icon}>
26
+ {@html icon}
27
+ </span>
28
+ {/if}
22
29
  {#if title}
23
30
  <svelte:element this={titleTag} class={styles.title}>
24
31
  {title}
@@ -8,16 +8,24 @@ import styles from './timelineitem.module.scss'
8
8
  const TimelineItem = ({
9
9
  title,
10
10
  TitleTag = 'span',
11
+ icon,
11
12
  className,
12
13
  children
13
14
  }: ReactTimelineItemProps) => {
14
15
  const classes = classNames([
15
16
  styles.item,
17
+ icon && styles['with-icon'],
16
18
  className
17
19
  ])
18
20
 
19
21
  return (
20
22
  <li className={classes}>
23
+ {icon && (
24
+ <span
25
+ className={styles.icon}
26
+ dangerouslySetInnerHTML={{ __html: icon }}
27
+ />
28
+ )}
21
29
  {title && (
22
30
  <TitleTag className={styles.title}>{title}</TitleTag>
23
31
  )}
@@ -4,7 +4,7 @@
4
4
  @include position(relative);
5
5
  @include spacing(m0);
6
6
 
7
- &::before {
7
+ &:not(.with-icon)::before {
8
8
  @include position(absolute, t-5px);
9
9
  @include size(25px);
10
10
  @include border-radius(max);
@@ -19,6 +19,21 @@
19
19
  margin-left: -40px;
20
20
  }
21
21
 
22
+ .icon {
23
+ @include position(absolute);
24
+ @include background(primary-70);
25
+ @include border(6px, primary-70);
26
+ @include layout(flex);
27
+
28
+ color: var(--w-timeline-text-color);
29
+ margin-left: -40px;
30
+ margin-top: -4px;
31
+
32
+ svg {
33
+ @include size(18px);
34
+ }
35
+ }
36
+
22
37
  .title {
23
38
  @include typography(bold, lg);
24
39
  @include spacing(mb-sm);
@@ -1,8 +1,11 @@
1
1
  import type { Snippet } from 'svelte'
2
2
 
3
+ import type { IconProps } from '../Icon/icon'
4
+
3
5
  export type TimelineItemProps = {
4
6
  title?: string
5
7
  titleTag?: string
8
+ icon?: IconProps['type'] | string
6
9
  className?: string
7
10
  }
8
11
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "webcoreui",
3
3
  "type": "module",
4
- "version": "0.10.1",
4
+ "version": "1.0.0",
5
5
  "scripts": {
6
6
  "prepare": "husky",
7
7
  "pre-commit": "lint-staged",
@@ -19,29 +19,29 @@
19
19
  },
20
20
  "devDependencies": {
21
21
  "@astrojs/check": "0.9.4",
22
- "@astrojs/node": "9.0.2",
23
- "@astrojs/react": "4.1.6",
24
- "@astrojs/svelte": "7.0.4",
25
- "@eslint/js": "9.18.0",
26
- "@typescript-eslint/parser": "8.21.0",
27
- "astro": "5.1.10",
28
- "astro-eslint-parser": "1.1.0",
29
- "eslint": "9.18.0",
22
+ "@astrojs/node": "9.1.3",
23
+ "@astrojs/react": "4.2.1",
24
+ "@astrojs/svelte": "7.0.7",
25
+ "@eslint/js": "9.23.0",
26
+ "@typescript-eslint/parser": "8.27.0",
27
+ "astro": "5.5.4",
28
+ "astro-eslint-parser": "1.2.2",
29
+ "eslint": "9.23.0",
30
30
  "eslint-plugin-astro": "1.3.1",
31
31
  "eslint-plugin-react": "7.37.4",
32
32
  "eslint-plugin-simple-import-sort": "12.1.1",
33
- "eslint-plugin-svelte": "2.46.1",
33
+ "eslint-plugin-svelte": "3.3.3",
34
34
  "husky": "9.1.7",
35
35
  "jsdom": "26.0.0",
36
- "lint-staged": "15.4.2",
36
+ "lint-staged": "15.5.0",
37
37
  "react": "19.0.0",
38
38
  "react-dom": "19.0.0",
39
- "sass": "1.83.4",
39
+ "sass": "1.86.0",
40
40
  "sass-true": "8.1.0",
41
- "svelte": "5.19.2",
42
- "svelte-eslint-parser": "0.43.0",
43
- "typescript": "5.7.3",
44
- "typescript-eslint": "8.21.0",
41
+ "svelte": "5.25.3",
42
+ "svelte-eslint-parser": "1.1.0",
43
+ "typescript": "5.8.2",
44
+ "typescript-eslint": "8.27.0",
45
45
  "vite-tsconfig-paths": "5.1.4",
46
46
  "vitest": "3.0.4"
47
47
  },
package/react.d.ts CHANGED
@@ -26,6 +26,7 @@ import type { ReactListProps as WReactListProps } from './components/List/list'
26
26
  import type { ReactMasonryProps as WReactMasonryProps } from './components/Masonry/masonry'
27
27
  import type { ReactMenuProps as WReactMenuProps } from './components/Menu/menu'
28
28
  import type { ReactModalProps as WReactModalProps } from './components/Modal/modal'
29
+ import type { OTPInputProps as WOTPInputProps } from './components/OTPInput/otpinput'
29
30
  import type { ReactPaginationProps as WReactPaginationProps } from './components/Pagination/pagination'
30
31
  import type { ReactPopoverProps as WReactPopoverProps } from './components/Popover/popover'
31
32
  import type { ProgressProps as WProgressProps } from './components/Progress/progress'
@@ -37,6 +38,7 @@ import type { ReactSheetProps as WReactSheetProps } from './components/Sheet/she
37
38
  import type { ReactSidebarProps as WReactSidebarProps } from './components/Sidebar/sidebar'
38
39
  import type { SkeletonProps as WSkeletonProps } from './components/Skeleton/skeleton'
39
40
  import type { ReactSliderProps as WReactSliderProps } from './components/Slider/slider'
41
+ import type { SpeedDialProps as WSpeedDialProps } from './components/SpeedDial/speeddial'
40
42
  import type { SpinnerProps as WSpinnerProps } from './components/Spinner/spinner'
41
43
  import type { ReactSpoilerProps as WReactSpoilerProps } from './components/Spoiler/spoiler'
42
44
  import type { StepperProps as WStepperProps } from './components/Stepper/stepper'
@@ -82,6 +84,7 @@ declare module 'webcoreui/react' {
82
84
  export const Masonry: FC<WReactMasonryProps>
83
85
  export const Menu: FC<WReactMenuProps>
84
86
  export const Modal: FC<WReactModalProps>
87
+ export const OTPInput: FC<WOTPInputProps>
85
88
  export const Pagination: FC<WReactPaginationProps>
86
89
  export const Popover: FC<WReactPopoverProps>
87
90
  export const Progress: FC<WProgressProps>
@@ -93,6 +96,7 @@ declare module 'webcoreui/react' {
93
96
  export const Sidebar: FC<WReactSidebarProps>
94
97
  export const Skeleton: FC<WSkeletonProps>
95
98
  export const Slider: FC<WReactSliderProps>
99
+ export const SpeedDial: FC<WSpeedDialProps>
96
100
  export const Spinner: FC<WSpinnerProps>
97
101
  export const Spoiler: FC<WReactSpoilerProps>
98
102
  export const Stepper: FC<WStepperProps>
@@ -132,6 +136,7 @@ declare module 'webcoreui/react' {
132
136
  export type MasonryProps = WReactMasonryProps
133
137
  export type MenuProps = WReactMenuProps
134
138
  export type ModalProps = WReactModalProps
139
+ export type OTPInputProps = WOTPInputProps
135
140
  export type PaginationProps = WReactPaginationProps
136
141
  export type PopoverProps = WReactPopoverProps
137
142
  export type ProgressProps = WProgressProps
@@ -143,6 +148,7 @@ declare module 'webcoreui/react' {
143
148
  export type SidebarProps = WReactSidebarProps
144
149
  export type SkeletonProps = WSkeletonProps
145
150
  export type SliderProps = WReactSliderProps
151
+ export type SpeedDialProps = WSpeedDialProps
146
152
  export type SpinnerProps = WSpinnerProps
147
153
  export type SpoilerProps = WReactSpoilerProps
148
154
  export type StepperProps = WStepperProps
package/react.js CHANGED
@@ -25,6 +25,7 @@ import ListComponent from './components/List/List.tsx'
25
25
  import MasonryComponent from './components/Masonry/Masonry.tsx'
26
26
  import MenuComponent from './components/Menu/Menu.tsx'
27
27
  import ModalComponent from './components/Modal/Modal.tsx'
28
+ import OTPInputComponent from './components/OTPInput/OTPInput.tsx'
28
29
  import PaginationComponent from './components/Pagination/Pagination.tsx'
29
30
  import PopoverComponent from './components/Popover/Popover.tsx'
30
31
  import ProgressComponent from './components/Progress/Progress.tsx'
@@ -36,6 +37,7 @@ import SheetComponent from './components/Sheet/Sheet.tsx'
36
37
  import SidebarComponent from './components/Sidebar/Sidebar.tsx'
37
38
  import SkeletonComponent from './components/Skeleton/Skeleton.tsx'
38
39
  import SliderComponent from './components/Slider/Slider.tsx'
40
+ import SpeedDialComponent from './components/SpeedDial/SpeedDial.tsx'
39
41
  import SpinnerComponent from './components/Spinner/Spinner.tsx'
40
42
  import SpoilerComponent from './components/Spoiler/Spoiler.tsx'
41
43
  import StepperComponent from './components/Stepper/Stepper.tsx'
@@ -75,6 +77,7 @@ export const List = ListComponent
75
77
  export const Masonry = MasonryComponent
76
78
  export const Menu = MenuComponent
77
79
  export const Modal = ModalComponent
80
+ export const OTPInput = OTPInputComponent
78
81
  export const Pagination = PaginationComponent
79
82
  export const Popover = PopoverComponent
80
83
  export const Progress = ProgressComponent
@@ -86,6 +89,7 @@ export const Sheet = SheetComponent
86
89
  export const Sidebar = SidebarComponent
87
90
  export const Skeleton = SkeletonComponent
88
91
  export const Slider = SliderComponent
92
+ export const SpeedDial = SpeedDialComponent
89
93
  export const Spinner = SpinnerComponent
90
94
  export const Spoiler = SpoilerComponent
91
95
  export const Stepper = StepperComponent