@elyndra/svelte-bgs 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 +53 -0
- package/src/Dots/Dots.svelte +59 -0
- package/src/Dots/Dots.test.ts +16 -0
- package/src/Dots/index.ts +2 -0
- package/src/Dots/types.ts +13 -0
- package/src/GridLines/GridLines.svelte +59 -0
- package/src/GridLines/GridLines.test.ts +16 -0
- package/src/GridLines/index.ts +2 -0
- package/src/GridLines/types.ts +13 -0
- package/src/MovingLines/MovingLines.svelte +59 -0
- package/src/MovingLines/MovingLines.test.ts +16 -0
- package/src/MovingLines/index.ts +2 -0
- package/src/MovingLines/types.ts +13 -0
- package/src/Puffs/Puffs.svelte +59 -0
- package/src/Puffs/Puffs.test.ts +16 -0
- package/src/Puffs/index.ts +2 -0
- package/src/Puffs/types.ts +13 -0
- package/src/index.ts +4 -0
- package/src/internal/styles.ts +54 -0
- package/src/svelte.d.ts +7 -0
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elyndra/svelte-bgs",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"sideEffects": false,
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"description": "Elyndra backgrounds components for Svelte",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"elyndra",
|
|
11
|
+
"ui",
|
|
12
|
+
"front-end",
|
|
13
|
+
"framework",
|
|
14
|
+
"scifi",
|
|
15
|
+
"sci-fi",
|
|
16
|
+
"science-fiction",
|
|
17
|
+
"svelte"
|
|
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
|
+
"svelte": "5.57.0"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@elyndra/animated": "^1.2.0",
|
|
43
|
+
"@elyndra/animator": "^1.2.0",
|
|
44
|
+
"@elyndra/bgs": "^1.2.0",
|
|
45
|
+
"@elyndra/svelte-animator": "^1.2.0",
|
|
46
|
+
"@elyndra/svelte-tools": "^1.2.0",
|
|
47
|
+
"@elyndra/tools": "^1.2.0",
|
|
48
|
+
"tslib": "2.8.1"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc --noEmit -p tsconfig.json && svelte-check --tsconfig tsconfig.json --output machine"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createBackgroundDots } from '@elyndra/bgs';
|
|
3
|
+
import { useAnimator } from '@elyndra/svelte-animator';
|
|
4
|
+
import { cx } from '@elyndra/tools';
|
|
5
|
+
import { positionedStyleText, toStyleText } from '../internal/styles.js';
|
|
6
|
+
import type { DotsProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
// No destructured rest: only direct `props.*` reads stay reactive.
|
|
9
|
+
const props: DotsProps = $props();
|
|
10
|
+
|
|
11
|
+
const getAnimator = useAnimator();
|
|
12
|
+
let canvas: HTMLCanvasElement | null = $state(null);
|
|
13
|
+
|
|
14
|
+
// The props object stays live, so the vanilla background always reads the
|
|
15
|
+
// latest settings, same as the per-render ref update in React/Preact.
|
|
16
|
+
// Intentionally captures the props proxy (Solid does the same).
|
|
17
|
+
// svelte-ignore state_referenced_locally
|
|
18
|
+
const settingsRef: { current: DotsProps } = { current: props };
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
const animator = getAnimator?.();
|
|
22
|
+
const target = canvas;
|
|
23
|
+
|
|
24
|
+
if (!target) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const background = createBackgroundDots({
|
|
29
|
+
canvas: target,
|
|
30
|
+
animator: animator?.node,
|
|
31
|
+
settingsRef,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return () => background.cancel();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
const target = canvas;
|
|
39
|
+
const ref = props.elementRef;
|
|
40
|
+
|
|
41
|
+
if (typeof ref === 'function') {
|
|
42
|
+
ref(target);
|
|
43
|
+
} else if (ref) {
|
|
44
|
+
ref.current = target;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const styleText = $derived(toStyleText((props.positioned ?? true) ? positionedStyleText : undefined, props.style));
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<!-- `role="presentation"` mirrors the React/Solid adapters: decorative background canvas. -->
|
|
52
|
+
<!-- svelte-ignore a11y_no_interactive_element_to_noninteractive_role -->
|
|
53
|
+
<canvas
|
|
54
|
+
role="presentation"
|
|
55
|
+
bind:this={canvas}
|
|
56
|
+
id={props.id}
|
|
57
|
+
class={cx('elyndra-bgs-dots', props.className)}
|
|
58
|
+
style={styleText}
|
|
59
|
+
></canvas>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte';
|
|
2
|
+
import type { Component } from 'svelte';
|
|
3
|
+
import { expect, test, vi } from 'vitest';
|
|
4
|
+
import Dots from './Dots.svelte';
|
|
5
|
+
|
|
6
|
+
HTMLCanvasElement.prototype.getContext = vi.fn<() => void>() as unknown as typeof HTMLCanvasElement.prototype.getContext;
|
|
7
|
+
|
|
8
|
+
// `.svelte` components are `unknown` in-repo (ambient decl, tests only).
|
|
9
|
+
const dots = Dots as Component;
|
|
10
|
+
|
|
11
|
+
test('Should render canvas element with elyndra class', () => {
|
|
12
|
+
const { container } = render(dots, { color: 'cyan' });
|
|
13
|
+
const element = container.querySelector('canvas') as HTMLElement;
|
|
14
|
+
expect(element.tagName).toBe('CANVAS');
|
|
15
|
+
expect(element.classList.contains('elyndra-bgs-dots')).toBe(true);
|
|
16
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CreateBackgroundDotsSettings } from '@elyndra/bgs';
|
|
2
|
+
|
|
3
|
+
type ElementRef<E> = ((element: E | null) => void) | { current: E | null };
|
|
4
|
+
|
|
5
|
+
interface DotsProps extends CreateBackgroundDotsSettings {
|
|
6
|
+
elementRef?: ElementRef<HTMLCanvasElement>;
|
|
7
|
+
id?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: string | Record<string, string | number | undefined>;
|
|
10
|
+
positioned?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type { DotsProps };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createBackgroundGridLines } from '@elyndra/bgs';
|
|
3
|
+
import { useAnimator } from '@elyndra/svelte-animator';
|
|
4
|
+
import { cx } from '@elyndra/tools';
|
|
5
|
+
import { positionedStyleText, toStyleText } from '../internal/styles.js';
|
|
6
|
+
import type { GridLinesProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
// No destructured rest: only direct `props.*` reads stay reactive.
|
|
9
|
+
const props: GridLinesProps = $props();
|
|
10
|
+
|
|
11
|
+
const getAnimator = useAnimator();
|
|
12
|
+
let canvas: HTMLCanvasElement | null = $state(null);
|
|
13
|
+
|
|
14
|
+
// The props object stays live, so the vanilla background always reads the
|
|
15
|
+
// latest settings, same as the per-render ref update in React/Preact.
|
|
16
|
+
// Intentionally captures the props proxy (Solid does the same).
|
|
17
|
+
// svelte-ignore state_referenced_locally
|
|
18
|
+
const settingsRef: { current: GridLinesProps } = { current: props };
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
const animator = getAnimator?.();
|
|
22
|
+
const target = canvas;
|
|
23
|
+
|
|
24
|
+
if (!target) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const background = createBackgroundGridLines({
|
|
29
|
+
canvas: target,
|
|
30
|
+
animator: animator?.node,
|
|
31
|
+
settingsRef,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return () => background.cancel();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
const target = canvas;
|
|
39
|
+
const ref = props.elementRef;
|
|
40
|
+
|
|
41
|
+
if (typeof ref === 'function') {
|
|
42
|
+
ref(target);
|
|
43
|
+
} else if (ref) {
|
|
44
|
+
ref.current = target;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const styleText = $derived(toStyleText((props.positioned ?? true) ? positionedStyleText : undefined, props.style));
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<!-- `role="presentation"` mirrors the React/Solid adapters: decorative background canvas. -->
|
|
52
|
+
<!-- svelte-ignore a11y_no_interactive_element_to_noninteractive_role -->
|
|
53
|
+
<canvas
|
|
54
|
+
role="presentation"
|
|
55
|
+
bind:this={canvas}
|
|
56
|
+
id={props.id}
|
|
57
|
+
class={cx('elyndra-bgs-gridlines', props.className)}
|
|
58
|
+
style={styleText}
|
|
59
|
+
></canvas>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte';
|
|
2
|
+
import type { Component } from 'svelte';
|
|
3
|
+
import { expect, test, vi } from 'vitest';
|
|
4
|
+
import GridLines from './GridLines.svelte';
|
|
5
|
+
|
|
6
|
+
HTMLCanvasElement.prototype.getContext = vi.fn<() => void>() as unknown as typeof HTMLCanvasElement.prototype.getContext;
|
|
7
|
+
|
|
8
|
+
// `.svelte` components are `unknown` in-repo (ambient decl, tests only).
|
|
9
|
+
const gridLines = GridLines as Component;
|
|
10
|
+
|
|
11
|
+
test('Should render canvas element with elyndra class', () => {
|
|
12
|
+
const { container } = render(gridLines, { color: 'cyan' });
|
|
13
|
+
const element = container.querySelector('canvas') as HTMLElement;
|
|
14
|
+
expect(element.tagName).toBe('CANVAS');
|
|
15
|
+
expect(element.classList.contains('elyndra-bgs-gridlines')).toBe(true);
|
|
16
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CreateBackgroundGridLinesSettings } from '@elyndra/bgs';
|
|
2
|
+
|
|
3
|
+
type ElementRef<E> = ((element: E | null) => void) | { current: E | null };
|
|
4
|
+
|
|
5
|
+
interface GridLinesProps extends CreateBackgroundGridLinesSettings {
|
|
6
|
+
elementRef?: ElementRef<HTMLCanvasElement>;
|
|
7
|
+
id?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: string | Record<string, string | number | undefined>;
|
|
10
|
+
positioned?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type { GridLinesProps };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createBackgroundMovingLines } from '@elyndra/bgs';
|
|
3
|
+
import { useAnimator } from '@elyndra/svelte-animator';
|
|
4
|
+
import { cx } from '@elyndra/tools';
|
|
5
|
+
import { positionedStyleText, toStyleText } from '../internal/styles.js';
|
|
6
|
+
import type { MovingLinesProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
// No destructured rest: only direct `props.*` reads stay reactive.
|
|
9
|
+
const props: MovingLinesProps = $props();
|
|
10
|
+
|
|
11
|
+
const getAnimator = useAnimator();
|
|
12
|
+
let canvas: HTMLCanvasElement | null = $state(null);
|
|
13
|
+
|
|
14
|
+
// The props object stays live, so the vanilla background always reads the
|
|
15
|
+
// latest settings, same as the per-render ref update in React/Preact.
|
|
16
|
+
// Intentionally captures the props proxy (Solid does the same).
|
|
17
|
+
// svelte-ignore state_referenced_locally
|
|
18
|
+
const settingsRef: { current: MovingLinesProps } = { current: props };
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
const animator = getAnimator?.();
|
|
22
|
+
const target = canvas;
|
|
23
|
+
|
|
24
|
+
if (!target) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const background = createBackgroundMovingLines({
|
|
29
|
+
canvas: target,
|
|
30
|
+
animator: animator?.node,
|
|
31
|
+
settingsRef,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return () => background.cancel();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
const target = canvas;
|
|
39
|
+
const ref = props.elementRef;
|
|
40
|
+
|
|
41
|
+
if (typeof ref === 'function') {
|
|
42
|
+
ref(target);
|
|
43
|
+
} else if (ref) {
|
|
44
|
+
ref.current = target;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const styleText = $derived(toStyleText((props.positioned ?? true) ? positionedStyleText : undefined, props.style));
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<!-- `role="presentation"` mirrors the React/Solid adapters: decorative background canvas. -->
|
|
52
|
+
<!-- svelte-ignore a11y_no_interactive_element_to_noninteractive_role -->
|
|
53
|
+
<canvas
|
|
54
|
+
role="presentation"
|
|
55
|
+
bind:this={canvas}
|
|
56
|
+
id={props.id}
|
|
57
|
+
class={cx('elyndra-bgs-movinglines', props.className)}
|
|
58
|
+
style={styleText}
|
|
59
|
+
></canvas>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte';
|
|
2
|
+
import type { Component } from 'svelte';
|
|
3
|
+
import { expect, test, vi } from 'vitest';
|
|
4
|
+
import MovingLines from './MovingLines.svelte';
|
|
5
|
+
|
|
6
|
+
HTMLCanvasElement.prototype.getContext = vi.fn<() => void>() as unknown as typeof HTMLCanvasElement.prototype.getContext;
|
|
7
|
+
|
|
8
|
+
// `.svelte` components are `unknown` in-repo (ambient decl, tests only).
|
|
9
|
+
const movingLines = MovingLines as Component;
|
|
10
|
+
|
|
11
|
+
test('Should render canvas element with elyndra class', () => {
|
|
12
|
+
const { container } = render(movingLines, { color: 'cyan' });
|
|
13
|
+
const element = container.querySelector('canvas') as HTMLElement;
|
|
14
|
+
expect(element.tagName).toBe('CANVAS');
|
|
15
|
+
expect(element.classList.contains('elyndra-bgs-movinglines')).toBe(true);
|
|
16
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CreateBackgroundMovingLinesSettings } from '@elyndra/bgs';
|
|
2
|
+
|
|
3
|
+
type ElementRef<E> = ((element: E | null) => void) | { current: E | null };
|
|
4
|
+
|
|
5
|
+
interface MovingLinesProps extends CreateBackgroundMovingLinesSettings {
|
|
6
|
+
elementRef?: ElementRef<HTMLCanvasElement>;
|
|
7
|
+
id?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: string | Record<string, string | number | undefined>;
|
|
10
|
+
positioned?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type { MovingLinesProps };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createBackgroundPuffs } from '@elyndra/bgs';
|
|
3
|
+
import { useAnimator } from '@elyndra/svelte-animator';
|
|
4
|
+
import { cx } from '@elyndra/tools';
|
|
5
|
+
import { positionedStyleText, toStyleText } from '../internal/styles.js';
|
|
6
|
+
import type { PuffsProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
// No destructured rest: only direct `props.*` reads stay reactive.
|
|
9
|
+
const props: PuffsProps = $props();
|
|
10
|
+
|
|
11
|
+
const getAnimator = useAnimator();
|
|
12
|
+
let canvas: HTMLCanvasElement | null = $state(null);
|
|
13
|
+
|
|
14
|
+
// The props object stays live, so the vanilla background always reads the
|
|
15
|
+
// latest settings, same as the per-render ref update in React/Preact.
|
|
16
|
+
// Intentionally captures the props proxy (Solid does the same).
|
|
17
|
+
// svelte-ignore state_referenced_locally
|
|
18
|
+
const settingsRef: { current: PuffsProps } = { current: props };
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
const animator = getAnimator?.();
|
|
22
|
+
const target = canvas;
|
|
23
|
+
|
|
24
|
+
if (!target) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const background = createBackgroundPuffs({
|
|
29
|
+
canvas: target,
|
|
30
|
+
animator: animator?.node,
|
|
31
|
+
settingsRef,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return () => background.cancel();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
const target = canvas;
|
|
39
|
+
const ref = props.elementRef;
|
|
40
|
+
|
|
41
|
+
if (typeof ref === 'function') {
|
|
42
|
+
ref(target);
|
|
43
|
+
} else if (ref) {
|
|
44
|
+
ref.current = target;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const styleText = $derived(toStyleText((props.positioned ?? true) ? positionedStyleText : undefined, props.style));
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<!-- `role="presentation"` mirrors the React/Solid adapters: decorative background canvas. -->
|
|
52
|
+
<!-- svelte-ignore a11y_no_interactive_element_to_noninteractive_role -->
|
|
53
|
+
<canvas
|
|
54
|
+
role="presentation"
|
|
55
|
+
bind:this={canvas}
|
|
56
|
+
id={props.id}
|
|
57
|
+
class={cx('elyndra-bgs-puffs', props.className)}
|
|
58
|
+
style={styleText}
|
|
59
|
+
></canvas>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte';
|
|
2
|
+
import type { Component } from 'svelte';
|
|
3
|
+
import { expect, test, vi } from 'vitest';
|
|
4
|
+
import Puffs from './Puffs.svelte';
|
|
5
|
+
|
|
6
|
+
HTMLCanvasElement.prototype.getContext = vi.fn<() => void>() as unknown as typeof HTMLCanvasElement.prototype.getContext;
|
|
7
|
+
|
|
8
|
+
// `.svelte` components are `unknown` in-repo (ambient decl, tests only).
|
|
9
|
+
const puffs = Puffs as Component;
|
|
10
|
+
|
|
11
|
+
test('Should render canvas element with elyndra class', () => {
|
|
12
|
+
const { container } = render(puffs, { color: 'cyan' });
|
|
13
|
+
const element = container.querySelector('canvas') as HTMLElement;
|
|
14
|
+
expect(element.tagName).toBe('CANVAS');
|
|
15
|
+
expect(element.classList.contains('elyndra-bgs-puffs')).toBe(true);
|
|
16
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CreateBackgroundPuffsSettings } from '@elyndra/bgs';
|
|
2
|
+
|
|
3
|
+
type ElementRef<E> = ((element: E | null) => void) | { current: E | null };
|
|
4
|
+
|
|
5
|
+
interface PuffsProps extends CreateBackgroundPuffsSettings {
|
|
6
|
+
elementRef?: ElementRef<HTMLCanvasElement>;
|
|
7
|
+
id?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: string | Record<string, string | number | undefined>;
|
|
10
|
+
positioned?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type { PuffsProps };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
type StyleValue = string | number | undefined;
|
|
2
|
+
type StyleInput = string | Record<string, StyleValue> | undefined;
|
|
3
|
+
|
|
4
|
+
const toKebabCase = (key: string): string => key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
5
|
+
|
|
6
|
+
const stringifyStyleObject = (style: Record<string, StyleValue>): string => {
|
|
7
|
+
const parts: string[] = [];
|
|
8
|
+
|
|
9
|
+
for (const [key, value] of Object.entries(style)) {
|
|
10
|
+
if (value === undefined || value === null || value === '') {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
parts.push(`${toKebabCase(key)}: ${value}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return parts.join('; ');
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Serializes Svelte `style` props to CSS text. Accepts the React-style
|
|
22
|
+
* object (camelCase keys) for API parity plus plain CSS strings.
|
|
23
|
+
*/
|
|
24
|
+
const toStyleText = (...styles: StyleInput[]): string | undefined => {
|
|
25
|
+
const parts: string[] = [];
|
|
26
|
+
|
|
27
|
+
for (const style of styles) {
|
|
28
|
+
if (!style) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (typeof style === 'string') {
|
|
33
|
+
const trimmed = style.trim().replace(/;$/, '');
|
|
34
|
+
|
|
35
|
+
if (trimmed) {
|
|
36
|
+
parts.push(trimmed);
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
const text = stringifyStyleObject(style);
|
|
40
|
+
|
|
41
|
+
if (text) {
|
|
42
|
+
parts.push(text);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return parts.length ? parts.join('; ') : undefined;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const positionedStyleText =
|
|
51
|
+
'position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%';
|
|
52
|
+
|
|
53
|
+
export { positionedStyleText, toStyleText };
|
|
54
|
+
export type { StyleInput };
|
package/src/svelte.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// In-repo ambient types for `.svelte` imports (tests only). The published
|
|
2
|
+
// package ships the `.svelte` sources and consumers get full prop inference
|
|
3
|
+
// from the `$props()` interfaces via their own Svelte setup.
|
|
4
|
+
declare module '*.svelte' {
|
|
5
|
+
const Component: unknown;
|
|
6
|
+
export default Component;
|
|
7
|
+
}
|