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.
- package/README.md +12 -8
- package/astro.d.ts +6 -0
- package/astro.js +4 -0
- package/components/OTPInput/OTPInput.astro +96 -0
- package/components/OTPInput/OTPInput.svelte +73 -0
- package/components/OTPInput/OTPInput.tsx +93 -0
- package/components/OTPInput/otpinput.module.scss +85 -0
- package/components/OTPInput/otpinput.ts +11 -0
- package/components/Rating/Rating.svelte +1 -1
- package/components/SpeedDial/SpeedDial.astro +106 -0
- package/components/SpeedDial/SpeedDial.svelte +102 -0
- package/components/SpeedDial/SpeedDial.tsx +106 -0
- package/components/SpeedDial/speeddial.module.scss +94 -0
- package/components/SpeedDial/speeddial.ts +18 -0
- package/components/Timeline/timeline.module.scss +11 -0
- package/components/Timeline/timeline.ts +1 -1
- package/components/TimelineItem/TimelineItem.astro +12 -0
- package/components/TimelineItem/TimelineItem.svelte +7 -0
- package/components/TimelineItem/TimelineItem.tsx +8 -0
- package/components/TimelineItem/timelineitem.module.scss +16 -1
- package/components/TimelineItem/timelineitem.ts +3 -0
- package/package.json +16 -16
- package/react.d.ts +6 -0
- package/react.js +4 -0
- package/scss/global/theme.scss +77 -49
- package/svelte.d.ts +6 -0
- package/svelte.js +4 -0
package/README.md
CHANGED
|
@@ -34,10 +34,6 @@
|
|
|
34
34
|
</a>
|
|
35
35
|
</p>
|
|
36
36
|
|
|
37
|
-
> [!IMPORTANT]
|
|
38
|
-
> This library is still in early development. New changes can break existing functionality, and no functionality should be considered final at this stage. The library will be considered stable once it reaches v1.0.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
37
|
## Table of Contents
|
|
42
38
|
|
|
43
39
|
- [Table of Contents](#table-of-contents)
|
|
@@ -64,15 +60,15 @@ Webcore can be used as a standalone project, or it can be integrated into your e
|
|
|
64
60
|
|
|
65
61
|
Webcore components use Sass for styling. To use the component library, you must have the following packages installed:
|
|
66
62
|
|
|
67
|
-
- [Sass](https://www.npmjs.com/package/sass) - `v1.
|
|
68
|
-
- [TypeScript](https://www.npmjs.com/package/typescript) - `v5.
|
|
63
|
+
- [Sass](https://www.npmjs.com/package/sass) - `v1.86`
|
|
64
|
+
- [TypeScript](https://www.npmjs.com/package/typescript) - `v5.8`
|
|
69
65
|
|
|
70
66
|
Depending on your project setup, you'll also need the following packages:
|
|
71
67
|
|
|
72
68
|
- **For Astro projects**
|
|
73
|
-
- [Astro](https://www.npmjs.com/package/astro) - `v5.
|
|
69
|
+
- [Astro](https://www.npmjs.com/package/astro) - `v5.5`
|
|
74
70
|
- **For Svelte projects**
|
|
75
|
-
- [Svelte](https://www.npmjs.com/package/svelte) - `v5.
|
|
71
|
+
- [Svelte](https://www.npmjs.com/package/svelte) - `v5.25`
|
|
76
72
|
- **For React projects**
|
|
77
73
|
- [React](https://www.npmjs.com/package/react) - `v19.0`
|
|
78
74
|
- [React DOM](https://www.npmjs.com/package/react-dom) -`v19.0`
|
|
@@ -170,6 +166,9 @@ html body {
|
|
|
170
166
|
--w-slider-color: var(--w-color-primary);
|
|
171
167
|
--w-slider-thumb: var(--w-color-primary-50);
|
|
172
168
|
|
|
169
|
+
// SpeedDial component
|
|
170
|
+
--w-speed-dial-size: 50px;
|
|
171
|
+
|
|
173
172
|
// Spinner component
|
|
174
173
|
--w-spinner-color: var(--w-color-primary);
|
|
175
174
|
--w-spinner-width: 2px;
|
|
@@ -258,6 +257,7 @@ import { Accordion } from 'webcoreui/react'
|
|
|
258
257
|
- [Masonry](https://github.com/Frontendland/webcoreui/tree/main/src/components/Masonry)
|
|
259
258
|
- [Menu](https://github.com/Frontendland/webcoreui/tree/main/src/components/Menu)
|
|
260
259
|
- [Modal](https://github.com/Frontendland/webcoreui/tree/main/src/components/Modal)
|
|
260
|
+
- [OTPInput](https://github.com/Frontendland/webcoreui/tree/main/src/components/OTPInput)
|
|
261
261
|
- [Pagination](https://github.com/Frontendland/webcoreui/tree/main/src/components/Pagination)
|
|
262
262
|
- [Popover](https://github.com/Frontendland/webcoreui/tree/main/src/components/Popover)
|
|
263
263
|
- [Progress](https://github.com/Frontendland/webcoreui/tree/main/src/components/Progress)
|
|
@@ -269,6 +269,7 @@ import { Accordion } from 'webcoreui/react'
|
|
|
269
269
|
- [Sidebar](https://github.com/Frontendland/webcoreui/tree/main/src/components/Sidebar)
|
|
270
270
|
- [Skeleton](https://github.com/Frontendland/webcoreui/tree/main/src/components/Skeleton)
|
|
271
271
|
- [Slider](https://github.com/Frontendland/webcoreui/tree/main/src/components/Slider)
|
|
272
|
+
- [SpeedDial](https://github.com/Frontendland/webcoreui/tree/main/src/components/SpeedDial)
|
|
272
273
|
- [Spinner](https://github.com/Frontendland/webcoreui/tree/main/src/components/Spinner)
|
|
273
274
|
- [Spoiler](https://github.com/Frontendland/webcoreui/tree/main/src/components/Spoiler)
|
|
274
275
|
- [Stepper](https://github.com/Frontendland/webcoreui/tree/main/src/components/Stepper)
|
|
@@ -294,15 +295,18 @@ import { Accordion } from 'webcoreui/react'
|
|
|
294
295
|
- [Icon](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Icon)
|
|
295
296
|
- [IconList](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/IconList)
|
|
296
297
|
- [Layout](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Layout)
|
|
298
|
+
- [Maintenance](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Maintenance)
|
|
297
299
|
- [SEO](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/SEO)
|
|
298
300
|
- [SettingCard](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/SettingCard)
|
|
299
301
|
- [SignUp](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/SignUp)
|
|
300
302
|
- [SocialProof](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/SocialProof)
|
|
301
303
|
- [Socials](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Socials)
|
|
304
|
+
- [Team](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Team)
|
|
302
305
|
- [Tiles](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Tiles)
|
|
303
306
|
- [User](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/User)
|
|
304
307
|
|
|
305
308
|
## Templates
|
|
306
309
|
|
|
310
|
+
- [Blog](https://github.com/Frontendland/webcoreui/tree/main/src/templates/Blog)
|
|
307
311
|
- [Portfolio](https://github.com/Frontendland/webcoreui/tree/main/src/templates/Portfolio)
|
|
308
312
|
- [ProductPage](https://github.com/Frontendland/webcoreui/tree/main/src/templates/ProductPage)
|
package/astro.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ import type { ListProps as WListProps } from './components/List/list'
|
|
|
25
25
|
import type { MasonryProps as WMasonryProps } from './components/Masonry/masonry'
|
|
26
26
|
import type { MenuProps as WMenuProps } from './components/Menu/menu'
|
|
27
27
|
import type { ModalProps as WModalProps } from './components/Modal/modal'
|
|
28
|
+
import type { OTPInputProps as WOTPInputProps } from './components/OTPInput/otpinput'
|
|
28
29
|
import type { PaginationProps as WPaginationProps } from './components/Pagination/pagination'
|
|
29
30
|
import type { PopoverProps as WPopoverProps } from './components/Popover/popover'
|
|
30
31
|
import type { ProgressProps as WProgressProps } from './components/Progress/progress'
|
|
@@ -36,6 +37,7 @@ import type { SheetProps as WSheetProps } from './components/Sheet/sheet'
|
|
|
36
37
|
import type { SidebarProps as WSidebarProps } from './components/Sidebar/sidebar'
|
|
37
38
|
import type { SkeletonProps as WSkeletonProps } from './components/Skeleton/skeleton'
|
|
38
39
|
import type { SliderProps as WSliderProps } from './components/Slider/slider'
|
|
40
|
+
import type { SpeedDialProps as WSpeedDialProps } from './components/SpeedDial/speeddial'
|
|
39
41
|
import type { SpinnerProps as WSpinnerProps } from './components/Spinner/spinner'
|
|
40
42
|
import type { SpoilerProps as WSpoilerProps } from './components/Spoiler/spoiler'
|
|
41
43
|
import type { StepperProps as WStepperProps } from './components/Stepper/stepper'
|
|
@@ -81,6 +83,7 @@ declare module 'webcoreui/astro' {
|
|
|
81
83
|
export function Masonry(_props: WMasonryProps): any
|
|
82
84
|
export function Menu(_props: WMenuProps): any
|
|
83
85
|
export function Modal(_props: WModalProps): any
|
|
86
|
+
export function OTPInput(_props: WOTPInputProps): any
|
|
84
87
|
export function Pagination(_props: WPaginationProps): any
|
|
85
88
|
export function Popover(_props: WPopoverProps): any
|
|
86
89
|
export function Progress(_props: WProgressProps): any
|
|
@@ -92,6 +95,7 @@ declare module 'webcoreui/astro' {
|
|
|
92
95
|
export function Sidebar(_props: WSidebarProps): any
|
|
93
96
|
export function Skeleton(_props: WSkeletonProps): any
|
|
94
97
|
export function Slider(_props: WSliderProps): any
|
|
98
|
+
export function SpeedDial(_props: WSpeedDialProps): any
|
|
95
99
|
export function Spinner(_props: WSpinnerProps): any
|
|
96
100
|
export function Spoiler(_props: WSpoilerProps): any
|
|
97
101
|
export function Stepper(_props: WStepperProps): any
|
|
@@ -131,6 +135,7 @@ declare module 'webcoreui/astro' {
|
|
|
131
135
|
export type MasonryProps = WMasonryProps
|
|
132
136
|
export type MenuProps = WMenuProps
|
|
133
137
|
export type ModalProps = WModalProps
|
|
138
|
+
export type OTPInputProps = WOTPInputProps
|
|
134
139
|
export type PaginationProps = WPaginationProps
|
|
135
140
|
export type PopoverProps = WPopoverProps
|
|
136
141
|
export type ProgressProps = WProgressProps
|
|
@@ -142,6 +147,7 @@ declare module 'webcoreui/astro' {
|
|
|
142
147
|
export type SidebarProps = WSidebarProps
|
|
143
148
|
export type SkeletonProps = WSkeletonProps
|
|
144
149
|
export type SliderProps = WSliderProps
|
|
150
|
+
export type SpeedDialProps = WSpeedDialProps
|
|
145
151
|
export type SpinnerProps = WSpinnerProps
|
|
146
152
|
export type SpoilerProps = WSpoilerProps
|
|
147
153
|
export type StepperProps = WStepperProps
|
package/astro.js
CHANGED
|
@@ -25,6 +25,7 @@ import ListComponent from './components/List/List.astro'
|
|
|
25
25
|
import MasonryComponent from './components/Masonry/Masonry.astro'
|
|
26
26
|
import MenuComponent from './components/Menu/Menu.astro'
|
|
27
27
|
import ModalComponent from './components/Modal/Modal.astro'
|
|
28
|
+
import OTPInputComponent from './components/OTPInput/OTPInput.astro'
|
|
28
29
|
import PaginationComponent from './components/Pagination/Pagination.astro'
|
|
29
30
|
import PopoverComponent from './components/Popover/Popover.astro'
|
|
30
31
|
import ProgressComponent from './components/Progress/Progress.astro'
|
|
@@ -36,6 +37,7 @@ import SheetComponent from './components/Sheet/Sheet.astro'
|
|
|
36
37
|
import SidebarComponent from './components/Sidebar/Sidebar.astro'
|
|
37
38
|
import SkeletonComponent from './components/Skeleton/Skeleton.astro'
|
|
38
39
|
import SliderComponent from './components/Slider/Slider.astro'
|
|
40
|
+
import SpeedDialComponent from './components/SpeedDial/SpeedDial.astro'
|
|
39
41
|
import SpinnerComponent from './components/Spinner/Spinner.astro'
|
|
40
42
|
import SpoilerComponent from './components/Spoiler/Spoiler.astro'
|
|
41
43
|
import StepperComponent from './components/Stepper/Stepper.astro'
|
|
@@ -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
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { OTPInputProps } from './otpinput'
|
|
3
|
+
|
|
4
|
+
import Input from '../Input/Input.astro'
|
|
5
|
+
|
|
6
|
+
import styles from './otpinput.module.scss'
|
|
7
|
+
|
|
8
|
+
interface Props extends OTPInputProps {}
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
name,
|
|
12
|
+
disabled,
|
|
13
|
+
length = 6,
|
|
14
|
+
groupLength = 0,
|
|
15
|
+
separator = '•',
|
|
16
|
+
label,
|
|
17
|
+
subText,
|
|
18
|
+
className,
|
|
19
|
+
...rest
|
|
20
|
+
} = Astro.props
|
|
21
|
+
|
|
22
|
+
const classes = [
|
|
23
|
+
styles.wrapper,
|
|
24
|
+
className
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
const inputPlaceholders = Array.from({ length }, (_, i) => i + 1)
|
|
28
|
+
.reduce<(number | string)[]>((acc, num, i) =>
|
|
29
|
+
groupLength > 0 && i % groupLength === 0 && i !== 0
|
|
30
|
+
? [...acc, separator, num]
|
|
31
|
+
: [...acc, num]
|
|
32
|
+
, [])
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
<div class:list={classes}>
|
|
36
|
+
{label && (
|
|
37
|
+
<label
|
|
38
|
+
for={name}
|
|
39
|
+
class={styles.label}
|
|
40
|
+
set:html={label}
|
|
41
|
+
/>
|
|
42
|
+
)}
|
|
43
|
+
|
|
44
|
+
<div class={styles['input-wrapper']}>
|
|
45
|
+
<Input
|
|
46
|
+
name={name || 'otp'}
|
|
47
|
+
data-id="w-input-otp"
|
|
48
|
+
disabled={disabled}
|
|
49
|
+
maxlength={length}
|
|
50
|
+
required={true}
|
|
51
|
+
{...rest}
|
|
52
|
+
/>
|
|
53
|
+
|
|
54
|
+
<div class={styles.placeholders}>
|
|
55
|
+
{inputPlaceholders.map((placeholder, index) => (
|
|
56
|
+
<div
|
|
57
|
+
class={typeof placeholder === 'string' ? styles.separator : styles.placeholder}
|
|
58
|
+
data-active={index === 0 ? true : undefined}
|
|
59
|
+
data-separator={typeof placeholder === 'string' ? true : undefined}
|
|
60
|
+
>
|
|
61
|
+
{typeof placeholder === 'string' ? placeholder : ''}
|
|
62
|
+
</div>
|
|
63
|
+
))}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
{subText && (
|
|
68
|
+
<div class={styles.subtext} set:html={subText} />
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<script>
|
|
73
|
+
import { on } from '../../utils/DOMUtils'
|
|
74
|
+
|
|
75
|
+
const addEventListeners = () => {
|
|
76
|
+
on('[data-id="w-input-otp"]', 'input', (event: Event) => {
|
|
77
|
+
const target = event.target as HTMLInputElement
|
|
78
|
+
const value = target.value
|
|
79
|
+
const placeholders = Array.from(target.nextElementSibling!.children)
|
|
80
|
+
.filter(child => !(child as HTMLDivElement).dataset.separator)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
placeholders.forEach((placeholder, index) => {
|
|
84
|
+
const placeholderElement = placeholder as HTMLDivElement
|
|
85
|
+
|
|
86
|
+
placeholderElement.innerText = value[index] || ''
|
|
87
|
+
placeholderElement.dataset.active = value.length === index
|
|
88
|
+
? 'true'
|
|
89
|
+
: 'false'
|
|
90
|
+
})
|
|
91
|
+
}, true)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
on(document, 'astro:after-swap', addEventListeners)
|
|
95
|
+
addEventListeners()
|
|
96
|
+
</script>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { OTPInputProps } from './otpinput'
|
|
3
|
+
|
|
4
|
+
import Input from '../Input/Input.svelte'
|
|
5
|
+
|
|
6
|
+
import { classNames } from '../../utils/classNames'
|
|
7
|
+
|
|
8
|
+
import styles from './otpinput.module.scss'
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
name,
|
|
12
|
+
disabled,
|
|
13
|
+
length = 6,
|
|
14
|
+
groupLength = 0,
|
|
15
|
+
separator = '•',
|
|
16
|
+
label,
|
|
17
|
+
subText,
|
|
18
|
+
className,
|
|
19
|
+
value = $bindable(''),
|
|
20
|
+
...rest
|
|
21
|
+
}: OTPInputProps = $props()
|
|
22
|
+
|
|
23
|
+
const classes = classNames([
|
|
24
|
+
styles.wrapper,
|
|
25
|
+
className
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
const inputPlaceholders = Array.from({ length }, (_, i) => i + 1)
|
|
29
|
+
.reduce<(number | string)[]>((acc, num, i) =>
|
|
30
|
+
groupLength > 0 && i % groupLength === 0 && i !== 0
|
|
31
|
+
? [...acc, separator, num]
|
|
32
|
+
: [...acc, num]
|
|
33
|
+
, [])
|
|
34
|
+
|
|
35
|
+
const getAdjustedIndex = (index: number) => inputPlaceholders
|
|
36
|
+
.slice(0, index)
|
|
37
|
+
.filter(placeholder => typeof placeholder !== 'string')
|
|
38
|
+
.length
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<div class={classes}>
|
|
42
|
+
{#if label}
|
|
43
|
+
<label for={name} class={styles.label}>{@html label}</label>
|
|
44
|
+
{/if}
|
|
45
|
+
|
|
46
|
+
<div class={styles['input-wrapper']}>
|
|
47
|
+
<Input
|
|
48
|
+
name={name || 'otp'}
|
|
49
|
+
disabled={disabled}
|
|
50
|
+
maxlength={length}
|
|
51
|
+
required={true}
|
|
52
|
+
bind:value
|
|
53
|
+
{...rest}
|
|
54
|
+
/>
|
|
55
|
+
|
|
56
|
+
<div class={styles.placeholders}>
|
|
57
|
+
{#each inputPlaceholders as placeholder, index}
|
|
58
|
+
<div
|
|
59
|
+
class={typeof placeholder === 'string' ? styles.separator : styles.placeholder}
|
|
60
|
+
data-active={getAdjustedIndex(index) === value.length ? true : undefined}
|
|
61
|
+
>
|
|
62
|
+
{typeof placeholder === 'string' ? placeholder : value[getAdjustedIndex(index)]}
|
|
63
|
+
</div>
|
|
64
|
+
{/each}
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
{#if subText}
|
|
69
|
+
<div class={styles.subtext}>
|
|
70
|
+
{@html subText}
|
|
71
|
+
</div>
|
|
72
|
+
{/if}
|
|
73
|
+
</div>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import type { OTPInputProps } from './otpinput'
|
|
3
|
+
|
|
4
|
+
import Input from '../Input/Input.tsx'
|
|
5
|
+
|
|
6
|
+
import { classNames } from '../../utils/classNames'
|
|
7
|
+
|
|
8
|
+
import styles from './otpinput.module.scss'
|
|
9
|
+
|
|
10
|
+
const OTPInput = ({
|
|
11
|
+
name,
|
|
12
|
+
disabled,
|
|
13
|
+
length = 6,
|
|
14
|
+
groupLength = 0,
|
|
15
|
+
separator = '•',
|
|
16
|
+
label,
|
|
17
|
+
subText,
|
|
18
|
+
className,
|
|
19
|
+
value,
|
|
20
|
+
onChange,
|
|
21
|
+
...rest
|
|
22
|
+
}: OTPInputProps) => {
|
|
23
|
+
const [inputValue, setValue] = useState(value || '')
|
|
24
|
+
|
|
25
|
+
const classes = classNames([
|
|
26
|
+
styles.wrapper,
|
|
27
|
+
className
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
const inputPlaceholders = Array.from({ length }, (_, i) => i + 1)
|
|
31
|
+
.reduce<(number | string)[]>((acc, num, i) =>
|
|
32
|
+
groupLength > 0 && i % groupLength === 0 && i !== 0
|
|
33
|
+
? [...acc, separator, num]
|
|
34
|
+
: [...acc, num]
|
|
35
|
+
, [])
|
|
36
|
+
|
|
37
|
+
const getAdjustedIndex = (index: number) => inputPlaceholders
|
|
38
|
+
.slice(0, index)
|
|
39
|
+
.filter(placeholder => typeof placeholder !== 'string')
|
|
40
|
+
.length
|
|
41
|
+
|
|
42
|
+
const updateInput = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
43
|
+
setValue(event.target.value)
|
|
44
|
+
onChange?.(inputValue)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className={classes}>
|
|
49
|
+
{label && (
|
|
50
|
+
<label
|
|
51
|
+
htmlFor={name}
|
|
52
|
+
className={styles.label}
|
|
53
|
+
dangerouslySetInnerHTML={{ __html: label }}
|
|
54
|
+
/>
|
|
55
|
+
)}
|
|
56
|
+
|
|
57
|
+
<div className={styles['input-wrapper']}>
|
|
58
|
+
<Input
|
|
59
|
+
name={name || 'otp'}
|
|
60
|
+
disabled={disabled}
|
|
61
|
+
maxLength={length}
|
|
62
|
+
required={true}
|
|
63
|
+
value={inputValue}
|
|
64
|
+
onChange={updateInput}
|
|
65
|
+
{...rest}
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
<div className={styles.placeholders}>
|
|
69
|
+
{inputPlaceholders.map((placeholder, index) => (
|
|
70
|
+
<div
|
|
71
|
+
key={index}
|
|
72
|
+
className={typeof placeholder === 'string' ? styles.separator : styles.placeholder}
|
|
73
|
+
data-active={getAdjustedIndex(index) === inputValue.length ? true : undefined}
|
|
74
|
+
>
|
|
75
|
+
{typeof placeholder === 'string'
|
|
76
|
+
? placeholder
|
|
77
|
+
: inputValue[getAdjustedIndex(index)]}
|
|
78
|
+
</div>
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{subText && (
|
|
84
|
+
<div
|
|
85
|
+
className={styles.subtext}
|
|
86
|
+
dangerouslySetInnerHTML={{ __html: subText }}
|
|
87
|
+
/>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default OTPInput
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
@use '../../scss/config.scss' as *;
|
|
2
|
+
|
|
3
|
+
.wrapper {
|
|
4
|
+
@include layout(flex, column, xs);
|
|
5
|
+
|
|
6
|
+
.label {
|
|
7
|
+
@include typography(primary-20);
|
|
8
|
+
@include spacing(mb-xs);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.input-wrapper {
|
|
12
|
+
@include position(relative);
|
|
13
|
+
|
|
14
|
+
input {
|
|
15
|
+
@include visibility(0);
|
|
16
|
+
@include position(absolute, t0, l0);
|
|
17
|
+
@include size(h40px);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.placeholders {
|
|
22
|
+
@include layout(flex);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.placeholder {
|
|
26
|
+
@include layout(flex, center);
|
|
27
|
+
@include border(top, primary-50);
|
|
28
|
+
@include border(bottom, primary-50);
|
|
29
|
+
@include border(right, primary-50);
|
|
30
|
+
@include size(40px);
|
|
31
|
+
|
|
32
|
+
&:first-child {
|
|
33
|
+
@include border(primary-50);
|
|
34
|
+
@include border-radius(left);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&:last-child {
|
|
38
|
+
@include border(primary-50);
|
|
39
|
+
@include border(left, 0);
|
|
40
|
+
@include border-radius(right);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&[data-active="true"] {
|
|
44
|
+
@include border(primary);
|
|
45
|
+
|
|
46
|
+
&::before {
|
|
47
|
+
@include size(w1px, h15px);
|
|
48
|
+
@include background(primary);
|
|
49
|
+
|
|
50
|
+
content: '';
|
|
51
|
+
animation: flash 1s infinite forwards;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.separator {
|
|
57
|
+
@include size(40px);
|
|
58
|
+
@include layout(flex, center);
|
|
59
|
+
|
|
60
|
+
+ .placeholder {
|
|
61
|
+
@include border(left, primary-50);
|
|
62
|
+
|
|
63
|
+
&[data-active="true"] {
|
|
64
|
+
@include border(left, primary);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.subtext {
|
|
70
|
+
@include typography(md, primary-30);
|
|
71
|
+
@include spacing(mt-xs);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@keyframes flash {
|
|
76
|
+
0% {
|
|
77
|
+
@include visibility(0);
|
|
78
|
+
}
|
|
79
|
+
50% {
|
|
80
|
+
@include visibility(1);
|
|
81
|
+
}
|
|
82
|
+
100% {
|
|
83
|
+
@include visibility(0);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { SpeedDialProps } from './speeddial'
|
|
3
|
+
|
|
4
|
+
import Button from '../Button/Button.astro'
|
|
5
|
+
import Icon from '../Icon/Icon.astro'
|
|
6
|
+
|
|
7
|
+
import styles from './speeddial.module.scss'
|
|
8
|
+
|
|
9
|
+
interface Props extends SpeedDialProps {}
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
items,
|
|
13
|
+
position,
|
|
14
|
+
horizontal,
|
|
15
|
+
circular,
|
|
16
|
+
theme,
|
|
17
|
+
icon,
|
|
18
|
+
triggerOnClick,
|
|
19
|
+
className
|
|
20
|
+
} = Astro.props
|
|
21
|
+
|
|
22
|
+
const classes = [
|
|
23
|
+
styles.dial,
|
|
24
|
+
position && styles[position],
|
|
25
|
+
horizontal && styles.horizontal,
|
|
26
|
+
circular && styles.circular,
|
|
27
|
+
className
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
const getTooltipPosition = () => {
|
|
31
|
+
const positionMap = {
|
|
32
|
+
'top-left': 'right',
|
|
33
|
+
'bottom-left': 'right',
|
|
34
|
+
'horizontal': {
|
|
35
|
+
'top-left': 'bottom',
|
|
36
|
+
'top-right': 'bottom'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return horizontal
|
|
41
|
+
? positionMap.horizontal[position as keyof typeof positionMap.horizontal]
|
|
42
|
+
: positionMap[position as keyof typeof positionMap] || 'left'
|
|
43
|
+
}
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
{!!items?.length && (
|
|
47
|
+
<div class:list={classes} data-id={triggerOnClick ? 'w-speed-dial' : null}>
|
|
48
|
+
<Button className={styles.trigger} {...(theme && { theme })}>
|
|
49
|
+
{icon && (
|
|
50
|
+
<Fragment>
|
|
51
|
+
{icon.startsWith('<svg')
|
|
52
|
+
? <Fragment set:html={icon} />
|
|
53
|
+
: <Icon type={icon} size={18} />
|
|
54
|
+
}
|
|
55
|
+
</Fragment>
|
|
56
|
+
)}
|
|
57
|
+
{!icon && <span>+</span>}
|
|
58
|
+
</Button>
|
|
59
|
+
|
|
60
|
+
<ul class={styles.list}>
|
|
61
|
+
{items.map(item => (
|
|
62
|
+
<li>
|
|
63
|
+
<Button
|
|
64
|
+
data-tooltip={item.tooltip}
|
|
65
|
+
data-position={getTooltipPosition()}
|
|
66
|
+
href={item.href}
|
|
67
|
+
target={item.target}
|
|
68
|
+
className={styles.button}
|
|
69
|
+
{...(theme && { theme })}
|
|
70
|
+
>
|
|
71
|
+
{item.icon.startsWith('<svg')
|
|
72
|
+
? <Fragment set:html={item.icon} />
|
|
73
|
+
: <Icon type={item.icon} size={16} />
|
|
74
|
+
}
|
|
75
|
+
</Button>
|
|
76
|
+
</li>
|
|
77
|
+
))}
|
|
78
|
+
</ul>
|
|
79
|
+
</div>
|
|
80
|
+
)}
|
|
81
|
+
|
|
82
|
+
<script>
|
|
83
|
+
import { get, on } from '../../utils/DOMUtils'
|
|
84
|
+
|
|
85
|
+
const addEventListeners = () => {
|
|
86
|
+
const speedDial = get('[data-id="w-speed-dial"] button') as HTMLButtonElement
|
|
87
|
+
const speedDialContainer = speedDial?.parentElement as HTMLDivElement
|
|
88
|
+
|
|
89
|
+
if (speedDial) {
|
|
90
|
+
on(speedDial, 'click', () => {
|
|
91
|
+
speedDialContainer.dataset.show = speedDialContainer.dataset.show === 'true'
|
|
92
|
+
? 'false'
|
|
93
|
+
: 'true'
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
on(document, 'click', (event: Event) => {
|
|
97
|
+
if (!speedDial.contains((event.target || event.currentTarget) as HTMLElement)) {
|
|
98
|
+
speedDialContainer.dataset.show = 'false'
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
on(document, 'astro:after-swap', addEventListeners)
|
|
105
|
+
addEventListeners()
|
|
106
|
+
</script>
|