@elyndra/vue-effects 1.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/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@elyndra/vue-effects",
3
+ "version": "1.2.0",
4
+ "sideEffects": false,
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "description": "Elyndra effects components for Vue",
9
+ "keywords": [
10
+ "elyndra",
11
+ "ui",
12
+ "front-end",
13
+ "framework",
14
+ "scifi",
15
+ "sci-fi",
16
+ "science-fiction",
17
+ "vue"
18
+ ],
19
+ "homepage": "https://elyndra.dev",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Gabox301/elyndra.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Gabox301/elyndra/issues"
26
+ },
27
+ "funding": "https://github.com/sponsors/romelperez",
28
+ "license": "MIT",
29
+ "files": [
30
+ "src"
31
+ ],
32
+ "exports": {
33
+ ".": "./src/index.ts"
34
+ },
35
+ "types": "./src/index.ts",
36
+ "module": "./src/index.ts",
37
+ "main": "./src/index.ts",
38
+ "peerDependencies": {
39
+ "vue": "3"
40
+ },
41
+ "dependencies": {
42
+ "@elyndra/effects": "^1.2.0",
43
+ "@elyndra/frames": "^1.2.0",
44
+ "@elyndra/tools": "^1.2.0",
45
+ "@elyndra/vue-tools": "^1.2.0",
46
+ "tslib": "2.8.1"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc --noEmit -p tsconfig.json && vue-tsc --noEmit -p tsconfig.json"
50
+ }
51
+ }
@@ -0,0 +1,15 @@
1
+ import { flushPromises, mount } from '@vue/test-utils';
2
+ import { expect, test } from 'vitest';
3
+ import { Illuminator } from './index.js';
4
+
5
+ test('Should render div element with elyndra class', async () => {
6
+ const wrapper = mount(Illuminator, {
7
+ props: { color: 'cyan', size: 300 },
8
+ });
9
+ await flushPromises();
10
+
11
+ const element = wrapper.element as HTMLElement;
12
+ expect(element.tagName).toBe('DIV');
13
+ expect(element.classList.contains('elyndra-frames-illuminator')).toBe(true);
14
+ wrapper.unmount();
15
+ });
@@ -0,0 +1,52 @@
1
+ <script setup lang="ts">
2
+ import { createEffectIlluminator } from '@elyndra/effects';
3
+ import { cx } from '@elyndra/tools';
4
+ import { mergeRefs } from '@elyndra/vue-tools';
5
+ import { ref, watch } from 'vue';
6
+ import type { IlluminatorProps } from '../types.js';
7
+
8
+ const props = defineProps<IlluminatorProps>();
9
+
10
+ const container = ref<HTMLDivElement | null>(null);
11
+
12
+ // Vue types element ref callbacks with the full
13
+ // `Element | ComponentPublicInstance | null` union; `unknown` keeps the
14
+ // callback assignable and the cast narrows to this component's element.
15
+ const setContainerRef = (value: unknown): void => {
16
+ const element = value as HTMLDivElement | null;
17
+ container.value = element;
18
+ mergeRefs(props.elementRef)(element);
19
+ };
20
+
21
+ watch(
22
+ () => [container.value, props.color, props.size] as const,
23
+ ([currentContainer, color, size], _previous, onCleanup) => {
24
+ if (!currentContainer) {
25
+ return;
26
+ }
27
+
28
+ const illuminator = createEffectIlluminator({ container: currentContainer, color, size });
29
+
30
+ onCleanup(() => illuminator.cancel());
31
+ },
32
+ { immediate: true, flush: 'post' },
33
+ );
34
+ </script>
35
+
36
+ <template>
37
+ <div
38
+ :ref="setContainerRef"
39
+ role="presentation"
40
+ :class="cx('elyndra-frames-illuminator', props.className)"
41
+ :style="{
42
+ position: 'absolute',
43
+ inset: 0,
44
+ overflow: 'hidden',
45
+ width: '100%',
46
+ height: '100%',
47
+ ...props.style,
48
+ }"
49
+ >
50
+ <slot />
51
+ </div>
52
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Illuminator } from './Illuminator.vue';
@@ -0,0 +1,30 @@
1
+ import { flushPromises, mount } from '@vue/test-utils';
2
+ import { defineComponent, h, ref } from 'vue';
3
+ import { expect, test } from 'vitest';
4
+ import { IlluminatorSVG } from './index.js';
5
+
6
+ test('Should render g element with elyndra class inside svg', async () => {
7
+ const svgRef = { current: null as SVGSVGElement | null };
8
+
9
+ const Harness = defineComponent({
10
+ setup() {
11
+ const svg = ref<SVGSVGElement | null>(null);
12
+ return () =>
13
+ h('svg', {
14
+ ref: (value: unknown) => {
15
+ const element = value as SVGSVGElement | null;
16
+ svg.value = element;
17
+ svgRef.current = element;
18
+ },
19
+ }, [h(IlluminatorSVG, { svgRef })]);
20
+ },
21
+ });
22
+
23
+ const wrapper = mount(Harness);
24
+ await flushPromises();
25
+
26
+ const element = wrapper.find('g');
27
+ expect(element.exists()).toBe(true);
28
+ expect((element.element as SVGElement).classList.contains('elyndra-frames-illuminatorsvg')).toBe(true);
29
+ wrapper.unmount();
30
+ });
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ import { createEffectIlluminatorSVG } from '@elyndra/effects';
3
+ import { cx } from '@elyndra/tools';
4
+ import { mergeRefs } from '@elyndra/vue-tools';
5
+ import { ref, watch } from 'vue';
6
+ import type { IlluminatorSVGProps } from '../types.js';
7
+
8
+ const props = defineProps<IlluminatorSVGProps>();
9
+
10
+ const container = ref<SVGGElement | null>(null);
11
+
12
+ // Vue types element ref callbacks with the full
13
+ // `Element | ComponentPublicInstance | null` union; `unknown` keeps the
14
+ // callback assignable and the cast narrows to this component's element.
15
+ const setContainerRef = (value: unknown): void => {
16
+ const element = value as SVGGElement | null;
17
+ container.value = element;
18
+ mergeRefs(props.elementRef)(element);
19
+ };
20
+
21
+ watch(
22
+ () => [container.value, props.svgRef.current, props.color, props.size] as const,
23
+ ([currentContainer, svg, color, size], _previous, onCleanup) => {
24
+ if (!svg || !currentContainer) {
25
+ return;
26
+ }
27
+
28
+ const effect = createEffectIlluminatorSVG({ svg, container: currentContainer, size, color });
29
+
30
+ onCleanup(() => effect.cancel());
31
+ },
32
+ { immediate: true, flush: 'post' },
33
+ );
34
+ </script>
35
+
36
+ <template>
37
+ <g
38
+ :ref="setContainerRef"
39
+ :class="cx('elyndra-frames-illuminatorsvg', props.className)"
40
+ :style="{
41
+ 'pointer-events': 'none',
42
+ ...props.style,
43
+ }"
44
+ >
45
+ <slot />
46
+ </g>
47
+ </template>
@@ -0,0 +1 @@
1
+ export { default as IlluminatorSVG } from './IlluminatorSVG.vue';
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './Illuminator/index.js';
2
+ export * from './IlluminatorSVG/index.js';
3
+ export type * from './types.js';
package/src/types.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { CSSProperties } from 'vue';
2
+ import type { CreateEffectIlluminatorProps, CreateEffectIlluminatorSVGProps } from '@elyndra/effects';
3
+ import type { ElementRef } from '@elyndra/vue-tools';
4
+
5
+ interface IlluminatorProps extends Omit<CreateEffectIlluminatorProps, 'container' | 'className' | 'style'> {
6
+ elementRef?: ElementRef<HTMLDivElement>;
7
+ className?: string;
8
+ style?: CSSProperties;
9
+ }
10
+
11
+ interface IlluminatorSVGProps extends Omit<
12
+ CreateEffectIlluminatorSVGProps,
13
+ 'svg' | 'container' | 'className' | 'style'
14
+ > {
15
+ elementRef?: ElementRef<SVGGElement>;
16
+ svgRef: { current: SVGSVGElement | null };
17
+ className?: string;
18
+ style?: CSSProperties;
19
+ color?: string;
20
+ size?: number;
21
+ }
22
+
23
+ export type { ElementRef, IlluminatorProps, IlluminatorSVGProps };
package/src/vue.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ // In-repo ambient types for `.vue` imports (tests only). The published
2
+ // package ships the `.vue` sources and consumers get full prop inference
3
+ // from their own Vue setup.
4
+ declare module '*.vue' {
5
+ import type { DefineComponent } from 'vue';
6
+ const Component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
7
+ export default Component;
8
+ }