@uibit/text-rotator 0.1.1 → 0.2.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/dist/frameworks/angular/index.ts +39 -35
- package/dist/frameworks/astro/index.d.ts +7 -1
- package/dist/frameworks/preact/index.d.ts +2 -0
- package/dist/frameworks/react/index.ts +105 -0
- package/dist/frameworks/solid/index.d.ts +1 -1
- package/dist/frameworks/stencil/index.d.ts +2 -0
- package/dist/frameworks/svelte/index.svelte +51 -19
- package/dist/frameworks/vue/index.ts +93 -23
- package/package.json +3 -3
- package/dist/frameworks/react/index.d.ts +0 -21
|
@@ -1,44 +1,48 @@
|
|
|
1
1
|
import { Component, ChangeDetectionStrategy, ElementRef, input, effect, output, booleanAttribute, numberAttribute } from '@angular/core';
|
|
2
2
|
import '@uibit/text-rotator';
|
|
3
3
|
import type { TextRotator as HTMLElementClass } from '@uibit/text-rotator';
|
|
4
|
-
|
|
5
4
|
@Component({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
selector: 'uibit-text-rotator',
|
|
6
|
+
template: '<ng-content></ng-content>',
|
|
7
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
8
|
+
standalone: true,
|
|
9
|
+
host: {
|
|
10
|
+
'(word-change)': 'wordChange.emit($event)'
|
|
11
|
+
}
|
|
13
12
|
})
|
|
14
13
|
export class NgxTextRotator {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
constructor(private el: ElementRef<HTMLElementClass>){
|
|
15
|
+
effect(()=>{
|
|
16
|
+
if (this.el.nativeElement) {
|
|
17
|
+
this.el.nativeElement.interval = this.interval();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
effect(()=>{
|
|
21
|
+
if (this.el.nativeElement) {
|
|
22
|
+
this.el.nativeElement.transition = this.transition();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
effect(()=>{
|
|
26
|
+
if (this.el.nativeElement) {
|
|
27
|
+
this.el.nativeElement.loop = this.loop();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
effect(()=>{
|
|
31
|
+
if (this.el.nativeElement) {
|
|
32
|
+
this.el.nativeElement.locale = this.locale();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
readonly interval = input<number, any>(2500, {
|
|
37
|
+
transform: numberAttribute
|
|
20
38
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
39
|
+
readonly transition = input<'slide' | 'flip'>('slide');
|
|
40
|
+
readonly loop = input<boolean, any>(true, {
|
|
41
|
+
transform: booleanAttribute
|
|
25
42
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
31
|
-
effect(() => {
|
|
32
|
-
if (this.el.nativeElement) {
|
|
33
|
-
this.el.nativeElement.locale = this.locale();
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
readonly interval = input<number, any>(2500, { transform: numberAttribute });
|
|
39
|
-
readonly transition = input<'slide' | 'flip', any>('slide');
|
|
40
|
-
readonly loop = input<boolean, any>(true, { transform: booleanAttribute });
|
|
41
|
-
readonly locale = input<string, any>('');
|
|
42
|
-
|
|
43
|
-
readonly wordChange = output<CustomEvent<{ word: string, index: number }>>();
|
|
43
|
+
readonly locale = input<string>('');
|
|
44
|
+
readonly wordChange = output<CustomEvent<{
|
|
45
|
+
word: string;
|
|
46
|
+
index: number;
|
|
47
|
+
}>>();
|
|
44
48
|
}
|
|
@@ -4,7 +4,13 @@ import '@uibit/text-rotator';
|
|
|
4
4
|
declare global {
|
|
5
5
|
namespace astroHTML.JSX {
|
|
6
6
|
interface IntrinsicElements {
|
|
7
|
-
'uibit-text-rotator': Partial<HTMLElementClass> & astroHTML.JSX.HTMLAttributes
|
|
7
|
+
'uibit-text-rotator': Partial<HTMLElementClass> & astroHTML.JSX.HTMLAttributes & {
|
|
8
|
+
interval?: number;
|
|
9
|
+
transition?: 'slide' | 'flip';
|
|
10
|
+
loop?: boolean;
|
|
11
|
+
locale?: string;
|
|
12
|
+
"on:word-change"?: (event: CustomEvent<{ word: string, index: number }>) => void;
|
|
13
|
+
};
|
|
8
14
|
}
|
|
9
15
|
}
|
|
10
16
|
}
|
|
@@ -10,6 +10,8 @@ declare module 'preact' {
|
|
|
10
10
|
transition?: 'slide' | 'flip';
|
|
11
11
|
loop?: boolean;
|
|
12
12
|
locale?: string;
|
|
13
|
+
onWordChange?: (event: CustomEvent<{ word: string, index: number }>) => void;
|
|
14
|
+
"on:word-change"?: (event: CustomEvent<{ word: string, index: number }>) => void;
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
17
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import React, { useRef, useEffect, useLayoutEffect, useImperativeHandle } from 'react';
|
|
2
|
+
import type { TextRotator as HTMLElementClass } from '@uibit/text-rotator';
|
|
3
|
+
import '@uibit/text-rotator';
|
|
4
|
+
const useTypeOfLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
5
|
+
export interface TextRotatorProps extends Omit<React.HTMLAttributes<HTMLElementClass>, 'interval' | 'transition' | 'loop' | 'locale' | 'onWordChange'> {
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
interval?: number;
|
|
8
|
+
transition?: 'slide' | 'flip';
|
|
9
|
+
loop?: boolean;
|
|
10
|
+
locale?: string;
|
|
11
|
+
onWordChange?: (event: CustomEvent<{
|
|
12
|
+
word: string;
|
|
13
|
+
index: number;
|
|
14
|
+
}>) => void;
|
|
15
|
+
}
|
|
16
|
+
export const TextRotator = ({ ref, children, ...props }: TextRotatorProps & {
|
|
17
|
+
ref?: React.Ref<HTMLElementClass>;
|
|
18
|
+
})=>{
|
|
19
|
+
const innerRef = useRef<HTMLElementClass>(null);
|
|
20
|
+
const propsRef = useRef(props);
|
|
21
|
+
propsRef.current = props;
|
|
22
|
+
useImperativeHandle(ref, ()=>innerRef.current!);
|
|
23
|
+
useTypeOfLayoutEffect(()=>{
|
|
24
|
+
const element = innerRef.current;
|
|
25
|
+
if (element && props.interval !== undefined) {
|
|
26
|
+
(element as any).interval = props.interval;
|
|
27
|
+
}
|
|
28
|
+
}, [
|
|
29
|
+
props.interval
|
|
30
|
+
]);
|
|
31
|
+
useTypeOfLayoutEffect(()=>{
|
|
32
|
+
const element = innerRef.current;
|
|
33
|
+
if (element && props.transition !== undefined) {
|
|
34
|
+
(element as any).transition = props.transition;
|
|
35
|
+
}
|
|
36
|
+
}, [
|
|
37
|
+
props.transition
|
|
38
|
+
]);
|
|
39
|
+
useTypeOfLayoutEffect(()=>{
|
|
40
|
+
const element = innerRef.current;
|
|
41
|
+
if (element && props.loop !== undefined) {
|
|
42
|
+
(element as any).loop = props.loop;
|
|
43
|
+
}
|
|
44
|
+
}, [
|
|
45
|
+
props.loop
|
|
46
|
+
]);
|
|
47
|
+
useTypeOfLayoutEffect(()=>{
|
|
48
|
+
const element = innerRef.current;
|
|
49
|
+
if (element && props.locale !== undefined) {
|
|
50
|
+
(element as any).locale = props.locale;
|
|
51
|
+
}
|
|
52
|
+
}, [
|
|
53
|
+
props.locale
|
|
54
|
+
]);
|
|
55
|
+
useTypeOfLayoutEffect(()=>{
|
|
56
|
+
const element = innerRef.current;
|
|
57
|
+
if (!element) return;
|
|
58
|
+
const handleEvent = (event: Event)=>{
|
|
59
|
+
if (propsRef.current.onWordChange) {
|
|
60
|
+
propsRef.current.onWordChange(event as any);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
element.addEventListener('word-change', handleEvent);
|
|
64
|
+
return ()=>{
|
|
65
|
+
element.removeEventListener('word-change', handleEvent);
|
|
66
|
+
};
|
|
67
|
+
}, []);
|
|
68
|
+
const domProps = {
|
|
69
|
+
...props
|
|
70
|
+
};
|
|
71
|
+
const customPropNames = [
|
|
72
|
+
'interval',
|
|
73
|
+
'transition',
|
|
74
|
+
'loop',
|
|
75
|
+
'locale',
|
|
76
|
+
'onWordChange'
|
|
77
|
+
];
|
|
78
|
+
for (const key of customPropNames){
|
|
79
|
+
delete (domProps as any)[key];
|
|
80
|
+
}
|
|
81
|
+
return React.createElement('uibit-text-rotator', {
|
|
82
|
+
ref: innerRef,
|
|
83
|
+
...domProps
|
|
84
|
+
}, children);
|
|
85
|
+
};
|
|
86
|
+
declare global {
|
|
87
|
+
namespace React {
|
|
88
|
+
namespace JSX {
|
|
89
|
+
interface IntrinsicElements {
|
|
90
|
+
'uibit-text-rotator': React.ClassAttributes<HTMLElementClass> & React.HTMLAttributes<HTMLElementClass> & {
|
|
91
|
+
children?: React.ReactNode;
|
|
92
|
+
class?: string;
|
|
93
|
+
interval?: number;
|
|
94
|
+
transition?: 'slide' | 'flip';
|
|
95
|
+
loop?: boolean;
|
|
96
|
+
locale?: string;
|
|
97
|
+
onWordChange?: (event: CustomEvent<{
|
|
98
|
+
word: string;
|
|
99
|
+
index: number;
|
|
100
|
+
}>) => void;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -9,6 +9,8 @@ declare module '@stencil/core' {
|
|
|
9
9
|
transition?: 'slide' | 'flip';
|
|
10
10
|
loop?: boolean;
|
|
11
11
|
locale?: string;
|
|
12
|
+
onWordChange?: (event: CustomEvent<{ word: string, index: number }>) => void;
|
|
13
|
+
"on:word-change"?: (event: CustomEvent<{ word: string, index: number }>) => void;
|
|
12
14
|
};
|
|
13
15
|
}
|
|
14
16
|
}
|
|
@@ -1,42 +1,74 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import '@uibit/text-rotator';
|
|
3
3
|
import type { TextRotator as HTMLElementClass } from '@uibit/text-rotator';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
interval =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
interval = $bindable(),
|
|
7
|
+
transition = $bindable(),
|
|
8
|
+
loop = $bindable(),
|
|
9
|
+
locale = $bindable(),
|
|
10
|
+
children,
|
|
11
|
+
...restProps
|
|
11
12
|
} = $props<{
|
|
12
|
-
children?:
|
|
13
|
+
children?: import('svelte').Snippet;
|
|
13
14
|
interval?: number;
|
|
14
15
|
transition?: 'slide' | 'flip';
|
|
15
16
|
loop?: boolean;
|
|
16
17
|
locale?: string;
|
|
17
|
-
|
|
18
|
+
|
|
19
|
+
[key: string]: any;
|
|
18
20
|
}>();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (elementRef && interval !== undefined) {
|
|
21
|
+
|
|
22
|
+
let elementRef: HTMLElementClass | null = $state(null);
|
|
23
|
+
|
|
24
|
+
$effect(() => {
|
|
25
|
+
if (elementRef && interval !== undefined && elementRef.interval !== interval) {
|
|
24
26
|
elementRef.interval = interval;
|
|
25
27
|
}
|
|
26
|
-
if (elementRef && transition !== undefined) {
|
|
28
|
+
if (elementRef && transition !== undefined && elementRef.transition !== transition) {
|
|
27
29
|
elementRef.transition = transition;
|
|
28
30
|
}
|
|
29
|
-
if (elementRef && loop !== undefined) {
|
|
31
|
+
if (elementRef && loop !== undefined && elementRef.loop !== loop) {
|
|
30
32
|
elementRef.loop = loop;
|
|
31
33
|
}
|
|
32
|
-
if (elementRef && locale !== undefined) {
|
|
34
|
+
if (elementRef && locale !== undefined && elementRef.locale !== locale) {
|
|
33
35
|
elementRef.locale = locale;
|
|
34
36
|
}
|
|
35
37
|
});
|
|
36
|
-
|
|
38
|
+
|
|
39
|
+
$effect(() => {
|
|
40
|
+
const element = elementRef;
|
|
41
|
+
if (!element) return;
|
|
42
|
+
|
|
43
|
+
const handleEvent = () => {
|
|
44
|
+
if (interval !== element.interval) {
|
|
45
|
+
interval = element.interval as any;
|
|
46
|
+
}
|
|
47
|
+
if (transition !== element.transition) {
|
|
48
|
+
transition = element.transition as any;
|
|
49
|
+
}
|
|
50
|
+
if (loop !== element.loop) {
|
|
51
|
+
loop = element.loop as any;
|
|
52
|
+
}
|
|
53
|
+
if (locale !== element.locale) {
|
|
54
|
+
locale = element.locale as any;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const events = ['change', 'input', 'word-change'];
|
|
59
|
+
for (const event of events) {
|
|
60
|
+
element.addEventListener(event, handleEvent);
|
|
61
|
+
}
|
|
62
|
+
return () => {
|
|
63
|
+
for (const event of events) {
|
|
64
|
+
element.removeEventListener(event, handleEvent);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
|
|
37
69
|
</script>
|
|
38
70
|
|
|
39
|
-
<uibit-text-rotator bind:this={elementRef} {
|
|
71
|
+
<uibit-text-rotator bind:this={elementRef} {...restProps}>
|
|
40
72
|
|
|
41
73
|
{#if children}
|
|
42
74
|
{@render children()}
|
|
@@ -1,27 +1,97 @@
|
|
|
1
|
-
import { defineComponent, h } from 'vue';
|
|
1
|
+
import { defineComponent, h, ref, watch } from 'vue';
|
|
2
2
|
import type { TextRotator as HTMLElementClass } from '@uibit/text-rotator';
|
|
3
3
|
import '@uibit/text-rotator';
|
|
4
|
-
|
|
5
4
|
export const TextRotator = defineComponent({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
name: 'TextRotator',
|
|
6
|
+
props: {
|
|
7
|
+
interval: {
|
|
8
|
+
type: [
|
|
9
|
+
String,
|
|
10
|
+
Number,
|
|
11
|
+
Boolean,
|
|
12
|
+
Array,
|
|
13
|
+
Object
|
|
14
|
+
] as any
|
|
15
|
+
},
|
|
16
|
+
transition: {
|
|
17
|
+
type: [
|
|
18
|
+
String,
|
|
19
|
+
Number,
|
|
20
|
+
Boolean,
|
|
21
|
+
Array,
|
|
22
|
+
Object
|
|
23
|
+
] as any
|
|
24
|
+
},
|
|
25
|
+
loop: {
|
|
26
|
+
type: [
|
|
27
|
+
String,
|
|
28
|
+
Number,
|
|
29
|
+
Boolean,
|
|
30
|
+
Array,
|
|
31
|
+
Object
|
|
32
|
+
] as any
|
|
33
|
+
},
|
|
34
|
+
locale: {
|
|
35
|
+
type: [
|
|
36
|
+
String,
|
|
37
|
+
Number,
|
|
38
|
+
Boolean,
|
|
39
|
+
Array,
|
|
40
|
+
Object
|
|
41
|
+
] as any
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
emits: [
|
|
45
|
+
'word-change'
|
|
46
|
+
],
|
|
47
|
+
setup (props, { slots, emit }) {
|
|
48
|
+
const elementRef = ref<HTMLElementClass | null>(null);
|
|
49
|
+
if (false) {
|
|
50
|
+
watch(()=>props.modelValue, (newVal)=>{
|
|
51
|
+
if (elementRef.value && newVal !== undefined && elementRef.value.value !== newVal) {
|
|
52
|
+
elementRef.value.value = newVal;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
watch(()=>props.value, (newVal)=>{
|
|
56
|
+
if (elementRef.value && newVal !== undefined && elementRef.value.value !== newVal) {
|
|
57
|
+
elementRef.value.value = newVal;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
watch(()=>props.interval, (newVal)=>{
|
|
62
|
+
if (elementRef.value && newVal !== undefined) {
|
|
63
|
+
(elementRef.value as any).interval = newVal;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
watch(()=>props.transition, (newVal)=>{
|
|
67
|
+
if (elementRef.value && newVal !== undefined) {
|
|
68
|
+
(elementRef.value as any).transition = newVal;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
watch(()=>props.loop, (newVal)=>{
|
|
72
|
+
if (elementRef.value && newVal !== undefined) {
|
|
73
|
+
(elementRef.value as any).loop = newVal;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
watch(()=>props.locale, (newVal)=>{
|
|
77
|
+
if (elementRef.value && newVal !== undefined) {
|
|
78
|
+
(elementRef.value as any).locale = newVal;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return ()=>{
|
|
82
|
+
const eventListeners: Record<string, any> = {};
|
|
83
|
+
eventListeners['onWord-change'] = (event: Event)=>{
|
|
84
|
+
emit('word-change', event);
|
|
85
|
+
};
|
|
86
|
+
const mergedProps = {
|
|
87
|
+
...props,
|
|
88
|
+
...eventListeners,
|
|
89
|
+
ref: elementRef
|
|
90
|
+
};
|
|
91
|
+
if (false && props.modelValue !== undefined) {
|
|
92
|
+
(mergedProps as any).value = props.modelValue;
|
|
93
|
+
}
|
|
94
|
+
return h('uibit-text-rotator', mergedProps, slots.default?.());
|
|
95
|
+
};
|
|
96
|
+
}
|
|
27
97
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uibit/text-rotator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Rotates a single word inside a static sentence block with smooth vertical slide or 3D flip transitions. Designed to pull attention to changing value propositions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
},
|
|
13
13
|
"./custom-elements.json": "./custom-elements.json",
|
|
14
|
-
"./react": "./dist/frameworks/react/index.
|
|
14
|
+
"./react": "./dist/frameworks/react/index.ts",
|
|
15
15
|
"./vue": "./dist/frameworks/vue/index.ts",
|
|
16
16
|
"./svelte": "./dist/frameworks/svelte/index.svelte",
|
|
17
17
|
"./angular": "./dist/frameworks/angular/index.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@types/node": "^20.19.43",
|
|
51
51
|
"lit": "^3.3.3",
|
|
52
52
|
"typescript": "7.0.2",
|
|
53
|
-
"@uibit/codegen": "0.
|
|
53
|
+
"@uibit/codegen": "0.2.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"lit": "^3.0.0",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { HTMLAttributes, ClassAttributes } from 'react';
|
|
2
|
-
import type { TextRotator as HTMLElementClass } from '@uibit/text-rotator';
|
|
3
|
-
import '@uibit/text-rotator';
|
|
4
|
-
|
|
5
|
-
declare global {
|
|
6
|
-
namespace React {
|
|
7
|
-
namespace JSX {
|
|
8
|
-
interface IntrinsicElements {
|
|
9
|
-
'uibit-text-rotator': ClassAttributes<HTMLElementClass> & HTMLAttributes<HTMLElementClass> & {
|
|
10
|
-
children?: React.ReactNode;
|
|
11
|
-
class?: string;
|
|
12
|
-
interval?: number;
|
|
13
|
-
transition?: 'slide' | 'flip';
|
|
14
|
-
loop?: boolean;
|
|
15
|
-
locale?: string;
|
|
16
|
-
onWordChange?: (event: any) => void;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|