@elyndra/vue-core 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,54 @@
1
+ {
2
+ "name": "@elyndra/vue-core",
3
+ "version": "1.2.0",
4
+ "sideEffects": false,
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "description": "Elyndra core 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/animated": "^1.2.0",
43
+ "@elyndra/animator": "^1.2.0",
44
+ "@elyndra/bleeps": "^1.2.0",
45
+ "@elyndra/vue-animated": "^1.2.0",
46
+ "@elyndra/vue-animator": "^1.2.0",
47
+ "@elyndra/vue-bleeps": "^1.2.0",
48
+ "@elyndra/vue-tools": "^1.2.0",
49
+ "tslib": "2.8.1"
50
+ },
51
+ "scripts": {
52
+ "build": "tsc --noEmit -p tsconfig.json && vue-tsc --noEmit -p tsconfig.json"
53
+ }
54
+ }
@@ -0,0 +1,15 @@
1
+ import { flushPromises, mount } from '@vue/test-utils';
2
+ import { expect, test } from 'vitest';
3
+ import { BleepsOnAnimator } from './index.js';
4
+
5
+ test('Should render nothing without animator and bleeps providers', async () => {
6
+ const wrapper = mount(BleepsOnAnimator, {
7
+ props: { transitions: {} },
8
+ });
9
+ await flushPromises();
10
+
11
+ // A renderless bridge leaves a comment placeholder behind, no elements.
12
+ expect(wrapper.element.nodeType).toBe(8);
13
+ expect(wrapper.find('*').exists()).toBe(false);
14
+ wrapper.unmount();
15
+ });
@@ -0,0 +1,73 @@
1
+ import { type Bleep } from '@elyndra/bleeps';
2
+ import { useAnimator } from '@elyndra/vue-animator';
3
+ import { useBleeps } from '@elyndra/vue-bleeps';
4
+ import { defineComponent, type PropType, watch } from 'vue';
5
+ import type { Transitions } from '../types.js';
6
+
7
+ let bleepsOnAnimatorIdCounter = 0;
8
+
9
+ /**
10
+ * Renderless bridge: plays bleeps on animator state transitions. It is a
11
+ * `.ts` `defineComponent` (not an SFC) on purpose — there is no DOM output
12
+ * at all (`() => null`, same as the Solid adapter's `return null`), so an
13
+ * SFC template would only add a comment node and compiler overhead.
14
+ *
15
+ * Mechanical Vue port of the React/Preact/Solid `BleepsOnAnimator` bridge.
16
+ * Differences are Vue idiom only: a module counter replaces `useId` /
17
+ * `createUniqueId`, `watch` + `watch` cleanup replace `useEffect` /
18
+ * `createEffect` + `onCleanup`, and the animator is read through the
19
+ * `useAnimator` accessor.
20
+ */
21
+ const BleepsOnAnimator = defineComponent({
22
+ name: 'BleepsOnAnimator',
23
+ props: {
24
+ id: { type: String, required: false, default: undefined },
25
+ transitions: { type: Object as PropType<Transitions<string>>, required: true },
26
+ continuous: { type: Boolean, required: false, default: undefined },
27
+ },
28
+ setup(props) {
29
+ const internalId = `bleeps-on-animator-${bleepsOnAnimatorIdCounter++}`;
30
+ const getAnimator = useAnimator();
31
+ const bleeps = useBleeps<string>();
32
+
33
+ watch(
34
+ // Tracked so the subscription follows prop updates.
35
+ () => [props.id ?? internalId, getAnimator?.()] as const,
36
+ ([id, animator], _previous, onCleanup) => {
37
+ if (!animator) {
38
+ return;
39
+ }
40
+
41
+ let currentBleep: Bleep | null = null;
42
+
43
+ const cancelSubscription = animator.node.subscribe((node) => {
44
+ const bleepName = props.transitions[node.state];
45
+
46
+ if (!props.continuous) {
47
+ currentBleep?.stop(id);
48
+ }
49
+
50
+ if (bleepName) {
51
+ const newBleep = (bleeps as Record<string, Bleep>)[bleepName];
52
+
53
+ if (newBleep) {
54
+ currentBleep?.stop(id);
55
+ currentBleep = newBleep;
56
+ currentBleep.play(id);
57
+ }
58
+ }
59
+ });
60
+
61
+ onCleanup(() => {
62
+ cancelSubscription();
63
+ currentBleep?.stop(id);
64
+ });
65
+ },
66
+ { immediate: true, flush: 'post' },
67
+ );
68
+
69
+ return () => null;
70
+ },
71
+ });
72
+
73
+ export { BleepsOnAnimator };
@@ -0,0 +1 @@
1
+ export * from './BleepsOnAnimator.js';
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './BleepsOnAnimator/index.js';
2
+ export type * from './types.js';
package/src/types.ts ADDED
@@ -0,0 +1,13 @@
1
+ import type { AnimatorState } from '@elyndra/animator';
2
+
3
+ type Transitions<BleepsNames extends string> = {
4
+ [p in AnimatorState]?: BleepsNames;
5
+ };
6
+
7
+ interface BleepsOnAnimatorProps<BleepsNames extends string = string> {
8
+ id?: string;
9
+ transitions: Transitions<BleepsNames>;
10
+ continuous?: boolean;
11
+ }
12
+
13
+ export type { BleepsOnAnimatorProps, Transitions };
package/src/vue.d.ts ADDED
@@ -0,0 +1,10 @@
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. This package holds no `.vue` files itself, but
4
+ // its type program reaches other packages' `.vue` sources through their
5
+ // indexes, so the ambient is needed for plain `tsc` as well.
6
+ declare module '*.vue' {
7
+ import type { DefineComponent } from 'vue';
8
+ const Component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
9
+ export default Component;
10
+ }