@mux/mux-player-astro 0.0.1
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 +238 -0
- package/package.json +33 -0
- package/src/MuxPlayer.astro +13 -0
- package/src/ads/MuxPlayer.astro +13 -0
- package/src/ads/index.ts +3 -0
- package/src/index.ts +3 -0
- package/src/themes/classic/classic.astro +3 -0
- package/src/themes/classic/index.ts +6 -0
- package/src/themes/gerwig/gerwig.astro +3 -0
- package/src/themes/gerwig/index.ts +6 -0
- package/src/themes/microvideo/index.ts +6 -0
- package/src/themes/microvideo/microvideo.astro +3 -0
- package/src/themes/minimal/index.ts +6 -0
- package/src/themes/minimal/minimal.astro +3 -0
- package/src/themes/news/index.ts +6 -0
- package/src/themes/news/news.astro +3 -0
- package/src/types.ts +95 -0
- package/src/utils.ts +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center"><MuxPlayer/></h1>
|
|
3
|
+
<a href="https://npmcharts.com/compare/@mux/mux-player-astro?interval=30"><img src="https://img.shields.io/npm/dm/@mux/mux-player-astro.svg?sanitize=true" alt="Downloads"></a>
|
|
4
|
+
<a href="https://www.npmjs.com/package/@mux/mux-player-astro"><img src="https://img.shields.io/npm/v/@mux/mux-player-astro.svg?sanitize=true" alt="Version"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/@mux/mux-player-astro"><img src="https://img.shields.io/npm/l/@mux/mux-player-astro.svg?sanitize=true" alt="License"></a>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
# Introduction
|
|
9
|
+
|
|
10
|
+
`<MuxPlayer />` is a Mux-flavored Astro video player component, built on top of our [mux-player web component](../mux-player) and [Media Chrome](https://media-chrome.org).
|
|
11
|
+
|
|
12
|
+
# Installation
|
|
13
|
+
|
|
14
|
+
```shell
|
|
15
|
+
npm install @mux/mux-player-astro
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
or
|
|
19
|
+
|
|
20
|
+
```shell
|
|
21
|
+
yarn add @mux/mux-player-astro
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
# Usage
|
|
25
|
+
|
|
26
|
+
## Basic Usage
|
|
27
|
+
|
|
28
|
+
```astro
|
|
29
|
+
---
|
|
30
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
<MuxPlayer
|
|
34
|
+
playbackId="DS00Spx1CV902MCtPj5WknGlR102V5HFkDe"
|
|
35
|
+
metadata={{
|
|
36
|
+
video_title: 'Big Buck Bunny',
|
|
37
|
+
viewer_user_id: 'user-id-1234',
|
|
38
|
+
}}
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## With Styling
|
|
43
|
+
|
|
44
|
+
```astro
|
|
45
|
+
---
|
|
46
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
<MuxPlayer
|
|
50
|
+
playbackId="DS00Spx1CV902MCtPj5WknGlR102V5HFkDe"
|
|
51
|
+
style={{
|
|
52
|
+
display: 'block',
|
|
53
|
+
aspectRatio: '16/9',
|
|
54
|
+
backgroundColor: '#000',
|
|
55
|
+
}}
|
|
56
|
+
autoplay
|
|
57
|
+
muted
|
|
58
|
+
streamType="on-demand"
|
|
59
|
+
proudlyDisplayMuxBadge
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## With Themes
|
|
64
|
+
|
|
65
|
+
You can use one of the built-in themes by passing the theme name as a string to the `theme` prop:
|
|
66
|
+
|
|
67
|
+
```astro
|
|
68
|
+
---
|
|
69
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
<MuxPlayer
|
|
73
|
+
playbackId="DS00Spx1CV902MCtPj5WknGlR102V5HFkDe"
|
|
74
|
+
theme="classic"
|
|
75
|
+
style={{
|
|
76
|
+
display: 'block',
|
|
77
|
+
aspectRatio: '16/9',
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Available themes:
|
|
83
|
+
- `classic` - Classic player theme
|
|
84
|
+
- `minimal` - Minimal player theme
|
|
85
|
+
- `microvideo` - Microvideo theme for short-form content
|
|
86
|
+
- `gerwig` - P, pretty, I, intelligent, N, never sad, K, cool
|
|
87
|
+
- `news` - News theme
|
|
88
|
+
|
|
89
|
+
Alternatively you can use a [Media Chrome theme](https://www.mux.com/docs/guides/player-themes#media-chrome-themes) by passing the theme name as a string and including the theme `<template>` element with that ID in your page:
|
|
90
|
+
|
|
91
|
+
```astro
|
|
92
|
+
---
|
|
93
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
94
|
+
---
|
|
95
|
+
<template id="tiny-theme">
|
|
96
|
+
<media-controller>
|
|
97
|
+
<slot name="media" slot="media"></slot>
|
|
98
|
+
<media-control-bar>
|
|
99
|
+
<media-play-button></media-play-button>
|
|
100
|
+
</media-control-bar>
|
|
101
|
+
</media-controller>
|
|
102
|
+
</template>
|
|
103
|
+
<MuxPlayer
|
|
104
|
+
playbackId="DS00Spx1CV902MCtPj5WknGlR102V5HFkDe"
|
|
105
|
+
theme="tiny-theme"
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## With Event Handling
|
|
110
|
+
|
|
111
|
+
To add event listeners to the component you can use [a client-side script](https://docs.astro.build/en/guides/client-side-scripts/). You can get the correct types for the player element by importing `MuxPlayerElement` from `@mux/mux-player-astro` and casting the element to that type.
|
|
112
|
+
|
|
113
|
+
```astro
|
|
114
|
+
---
|
|
115
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
<MuxPlayer
|
|
119
|
+
id="my-player"
|
|
120
|
+
playbackId="DS00Spx1CV902MCtPj5WknGlR102V5HFkDe"
|
|
121
|
+
/>
|
|
122
|
+
|
|
123
|
+
<script>
|
|
124
|
+
import type { MuxPlayerElement } from '@mux/mux-player-astro';
|
|
125
|
+
|
|
126
|
+
const player = document.getElementById('my-player') as MuxPlayerElement;
|
|
127
|
+
|
|
128
|
+
player.addEventListener('play', (event) => {
|
|
129
|
+
console.log('Player started playing!');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
player.addEventListener('pause', (event) => {
|
|
133
|
+
console.log('Player paused!');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
player.addEventListener('timeupdate', (event) => {
|
|
137
|
+
console.log('Current time: ', player.currentTime);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
player.addEventListener('ended', (event) => {
|
|
141
|
+
console.log('Video ended!');
|
|
142
|
+
});
|
|
143
|
+
</script>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Audio Content
|
|
147
|
+
|
|
148
|
+
```astro
|
|
149
|
+
---
|
|
150
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
<MuxPlayer
|
|
154
|
+
playbackId="your-audio-playback-id"
|
|
155
|
+
audio
|
|
156
|
+
metadata={{
|
|
157
|
+
video_title: 'My Podcast Episode',
|
|
158
|
+
}}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Live Streams
|
|
163
|
+
|
|
164
|
+
```astro
|
|
165
|
+
---
|
|
166
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
<MuxPlayer
|
|
170
|
+
playbackId="your-live-playback-id"
|
|
171
|
+
streamType="live"
|
|
172
|
+
targetLiveWindow={Infinity}
|
|
173
|
+
title="Live Stream"
|
|
174
|
+
/>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Custom Colors
|
|
178
|
+
|
|
179
|
+
```astro
|
|
180
|
+
---
|
|
181
|
+
import { MuxPlayer } from '@mux/mux-player-astro';
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
<MuxPlayer
|
|
185
|
+
playbackId="DS00Spx1CV902MCtPj5WknGlR102V5HFkDe"
|
|
186
|
+
primaryColor="#ff6b35"
|
|
187
|
+
secondaryColor="#ffffff"
|
|
188
|
+
accentColor="#0066cc"
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
# Props
|
|
193
|
+
|
|
194
|
+
All props from the underlying `mux-player` web component are supported, including:
|
|
195
|
+
|
|
196
|
+
## Core Props
|
|
197
|
+
- `playbackId` - Mux playback ID for the video
|
|
198
|
+
- `src` - Direct video URL (alternative to playbackId)
|
|
199
|
+
- `poster` - Poster image URL
|
|
200
|
+
- `audio` - Enable audio-only mode
|
|
201
|
+
|
|
202
|
+
## Playback Props
|
|
203
|
+
- `autoplay` - Auto-start playback
|
|
204
|
+
- `muted` - Start muted
|
|
205
|
+
- `loop` - Loop the video
|
|
206
|
+
- `playsInline` - Play inline on mobile
|
|
207
|
+
- `currentTime` - Set initial playback position
|
|
208
|
+
- `playbackRate` - Playback speed (1.0 = normal)
|
|
209
|
+
|
|
210
|
+
## Stream Props
|
|
211
|
+
- `streamType` - Type of stream ('on-demand', 'live', 'll-live')
|
|
212
|
+
- `targetLiveWindow` - Live stream window duration
|
|
213
|
+
|
|
214
|
+
## Metadata Props
|
|
215
|
+
- `metadata` - Object with video_id, video_title, viewer_user_id
|
|
216
|
+
- `envKey` - Environment key for Mux Data
|
|
217
|
+
- `customDomain` - Custom domain for video delivery
|
|
218
|
+
|
|
219
|
+
## UI Props
|
|
220
|
+
- `theme` - Player theme component
|
|
221
|
+
- `primaryColor` - Primary UI color
|
|
222
|
+
- `secondaryColor` - Secondary UI color
|
|
223
|
+
- `accentColor` - Accent UI color
|
|
224
|
+
- `proudlyDisplayMuxBadge` - Show Mux badge
|
|
225
|
+
|
|
226
|
+
## Advanced Props
|
|
227
|
+
- `tokens` - Signed tokens for private videos
|
|
228
|
+
- `storyboardSrc` - Custom storyboard/thumbnail track
|
|
229
|
+
- `chapters` - Chapter markers
|
|
230
|
+
- `renditionOrder` - Quality selection ordering
|
|
231
|
+
- `maxResolution` - Maximum playback resolution
|
|
232
|
+
- `minResolution` - Minimum playback resolution
|
|
233
|
+
|
|
234
|
+
# Docs
|
|
235
|
+
|
|
236
|
+
Docs and guides live on [docs.mux.com](https://docs.mux.com/guides/video/mux-player?utm_source=github-mux-player).
|
|
237
|
+
|
|
238
|
+
API reference lives [on Github](../mux-player/REFERENCE.md).
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mux/mux-player-astro",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "An open source Mux player for Astro that Just Works™",
|
|
5
|
+
"homepage": "https://mux.com/player",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"video",
|
|
8
|
+
"mux",
|
|
9
|
+
"player",
|
|
10
|
+
"hls",
|
|
11
|
+
"astro",
|
|
12
|
+
"astro-component"
|
|
13
|
+
],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"files": [
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./src/index.ts",
|
|
20
|
+
"./ads": "./src/ads/index.ts"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"astro": "^4.0.0 || ^5.0.0"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@mux/mux-player": "3.5.1",
|
|
27
|
+
"@mux/playback-core": "0.30.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"astro": "^5.11.0",
|
|
31
|
+
"vite": "^6.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { MuxPlayerProps } from './types';
|
|
3
|
+
import { getThemeObject, toNativeAttributes } from './utils';
|
|
4
|
+
type Props = MuxPlayerProps;
|
|
5
|
+
const { theme, ...props } = Astro.props;
|
|
6
|
+
const { component: Theme, name: themeName } = await getThemeObject(theme);
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<mux-player {...toNativeAttributes(props)} theme={themeName}><slot /></mux-player>
|
|
10
|
+
{Theme && <Theme />}
|
|
11
|
+
<script>
|
|
12
|
+
import '@mux/mux-player';
|
|
13
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { MuxPlayerAdsProps } from '../types';
|
|
3
|
+
import { getThemeObject, toNativeAttributes } from '../utils';
|
|
4
|
+
type Props = MuxPlayerAdsProps;
|
|
5
|
+
const { theme, ...props } = Astro.props;
|
|
6
|
+
const { component: Theme, name: themeName } = await getThemeObject(theme);
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<mux-player {...toNativeAttributes(props)} theme={themeName}><slot /></mux-player>
|
|
10
|
+
{Theme && <Theme />}
|
|
11
|
+
<script>
|
|
12
|
+
import '@mux/mux-player/ads';
|
|
13
|
+
</script>
|
package/src/ads/index.ts
ADDED
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CmcdTypes,
|
|
3
|
+
MaxResolutionValue,
|
|
4
|
+
MinResolutionValue,
|
|
5
|
+
PlaybackTypes,
|
|
6
|
+
RenditionOrderValue,
|
|
7
|
+
StreamTypes,
|
|
8
|
+
} from '@mux/playback-core';
|
|
9
|
+
import type { Tokens } from '@mux/mux-player';
|
|
10
|
+
import type { AstroComponentFactory } from 'astro/runtime/server/index.js';
|
|
11
|
+
|
|
12
|
+
type ValueOf<T> = T[keyof T];
|
|
13
|
+
|
|
14
|
+
export type MuxVideoTheme = {
|
|
15
|
+
component?: AstroComponentFactory;
|
|
16
|
+
name?: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type BuiltinTheme = 'classic' | 'gerwig' | 'microvideo' | 'minimal' | 'news';
|
|
20
|
+
|
|
21
|
+
export type MuxPlayerProps = {
|
|
22
|
+
theme?: MuxVideoTheme | BuiltinTheme | (string & {});
|
|
23
|
+
hotkeys?: string;
|
|
24
|
+
nohotkeys?: boolean;
|
|
25
|
+
castReceiver?: string | undefined;
|
|
26
|
+
castCustomData?: Record<string, any> | undefined;
|
|
27
|
+
defaultHiddenCaptions?: boolean;
|
|
28
|
+
playerSoftwareVersion?: string;
|
|
29
|
+
playerSoftwareName?: string;
|
|
30
|
+
playerInitTime?: number;
|
|
31
|
+
forwardSeekOffset?: number;
|
|
32
|
+
backwardSeekOffset?: number;
|
|
33
|
+
maxResolution?: MaxResolutionValue;
|
|
34
|
+
minResolution?: MinResolutionValue;
|
|
35
|
+
renditionOrder?: RenditionOrderValue;
|
|
36
|
+
programStartTime?: number;
|
|
37
|
+
programEndTime?: number;
|
|
38
|
+
proudlyDisplayMuxBadge?: boolean;
|
|
39
|
+
assetStartTime?: number;
|
|
40
|
+
assetEndTime?: number;
|
|
41
|
+
metadataVideoId?: string;
|
|
42
|
+
metadataVideoTitle?: string;
|
|
43
|
+
metadataViewerUserId?: string;
|
|
44
|
+
metadata?: {
|
|
45
|
+
video_id?: string;
|
|
46
|
+
video_title?: string;
|
|
47
|
+
viewer_user_id?: string;
|
|
48
|
+
};
|
|
49
|
+
primaryColor?: string;
|
|
50
|
+
secondaryColor?: string;
|
|
51
|
+
accentColor?: string;
|
|
52
|
+
placeholder?: string;
|
|
53
|
+
playbackRates?: number[];
|
|
54
|
+
defaultShowRemainingTime?: boolean;
|
|
55
|
+
defaultDuration?: number;
|
|
56
|
+
noVolumePref?: boolean;
|
|
57
|
+
thumbnailTime?: number;
|
|
58
|
+
title?: string;
|
|
59
|
+
videoTitle?: string;
|
|
60
|
+
tokens?: Tokens;
|
|
61
|
+
currentTime?: number;
|
|
62
|
+
volume?: number;
|
|
63
|
+
paused?: boolean;
|
|
64
|
+
src?: string | null;
|
|
65
|
+
poster?: string;
|
|
66
|
+
playbackRate?: number;
|
|
67
|
+
playsInline?: boolean;
|
|
68
|
+
preload?: string;
|
|
69
|
+
crossorigin?: string;
|
|
70
|
+
autoplay?: boolean | string;
|
|
71
|
+
loop?: boolean;
|
|
72
|
+
muted?: boolean;
|
|
73
|
+
audio?: boolean;
|
|
74
|
+
envKey?: string;
|
|
75
|
+
debug?: boolean;
|
|
76
|
+
disableTracking?: boolean;
|
|
77
|
+
disableCookies?: boolean;
|
|
78
|
+
disablePictureInPicture?: boolean;
|
|
79
|
+
extraSourceParams?: Record<string, any>;
|
|
80
|
+
beaconCollectionDomain?: string;
|
|
81
|
+
customDomain?: string;
|
|
82
|
+
playbackId?: string;
|
|
83
|
+
preferPlayback?: ValueOf<PlaybackTypes> | undefined;
|
|
84
|
+
streamType?: ValueOf<StreamTypes>;
|
|
85
|
+
defaultStreamType?: ValueOf<StreamTypes>;
|
|
86
|
+
targetLiveWindow?: number;
|
|
87
|
+
startTime?: number;
|
|
88
|
+
storyboardSrc?: string;
|
|
89
|
+
preferCmcd?: ValueOf<CmcdTypes> | undefined;
|
|
90
|
+
} & astroHTML.JSX.HTMLAttributes;
|
|
91
|
+
|
|
92
|
+
export type MuxPlayerAdsProps = MuxPlayerProps & {
|
|
93
|
+
allowAdBlocker?: boolean;
|
|
94
|
+
adTagUrl?: string;
|
|
95
|
+
};
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
import type { MuxVideoTheme } from './types';
|
|
3
|
+
|
|
4
|
+
const toKebabCase = (string: string) =>
|
|
5
|
+
string.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`).replaceAll('_', '-');
|
|
6
|
+
|
|
7
|
+
const FLATTEN_PROPS = new Set(['metadata', 'tokens', 'castCustomData']);
|
|
8
|
+
|
|
9
|
+
export const themes = import.meta.glob<{ default: MuxVideoTheme }>('./themes/*/index.ts');
|
|
10
|
+
|
|
11
|
+
function stringifyValue(value: any): string {
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
return value.join(' ');
|
|
14
|
+
}
|
|
15
|
+
if (typeof value === 'object' && value !== null) {
|
|
16
|
+
return JSON.stringify(value);
|
|
17
|
+
}
|
|
18
|
+
if (value === true) {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
return String(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function getThemeObject(theme: string | MuxVideoTheme | undefined): Promise<MuxVideoTheme> {
|
|
25
|
+
if (!theme) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
if (typeof theme !== 'string') {
|
|
29
|
+
return theme;
|
|
30
|
+
}
|
|
31
|
+
const themeModule = themes[`./themes/${theme}/index.ts`];
|
|
32
|
+
if (!themeModule) {
|
|
33
|
+
return {
|
|
34
|
+
name: theme,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return (await themeModule()).default;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const toNativeAttributes = (props: { [key: string]: any } = {}): Record<string, string> => {
|
|
41
|
+
return Object.entries(props).reduce<Record<string, string>>((transformedProps, [propName, propValue]) => {
|
|
42
|
+
if (typeof propValue === 'undefined' || propValue === null || propValue === false) {
|
|
43
|
+
return transformedProps;
|
|
44
|
+
}
|
|
45
|
+
if (propName === 'style') {
|
|
46
|
+
transformedProps.style = propValue;
|
|
47
|
+
return transformedProps;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const attrName = toKebabCase(propName);
|
|
51
|
+
|
|
52
|
+
if (FLATTEN_PROPS.has(propName)) {
|
|
53
|
+
if (typeof propValue === 'object' && !Array.isArray(propValue)) {
|
|
54
|
+
Object.entries(propValue).forEach(([key, value]) => {
|
|
55
|
+
const kebabKey = toKebabCase(`${attrName}-${key}`);
|
|
56
|
+
if (typeof propValue !== 'undefined' && propValue !== null && !props.hasOwnProperty(kebabKey)) {
|
|
57
|
+
transformedProps[kebabKey] = stringifyValue(value);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
const attrValue = stringifyValue(propValue);
|
|
63
|
+
transformedProps[attrName] = attrValue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return transformedProps;
|
|
67
|
+
}, {});
|
|
68
|
+
};
|