diff --git a/examples/nextjs-with-typescript/pages/index.tsx b/examples/nextjs-with-typescript/pages/index.tsx index f518588bc..00e4ec209 100644 --- a/examples/nextjs-with-typescript/pages/index.tsx +++ b/examples/nextjs-with-typescript/pages/index.tsx @@ -23,6 +23,7 @@ function HomePage() {
  • <><mux-video>
    (Web Component)
  • <><mux-audio>
    (Web Component)
  • <><mux-player>
    (Web Component)
  • +
  • <><MuxVideo>
    (React Web Component)
  • <>App Router
  • diff --git a/examples/nextjs-with-typescript/pages/mux-video-react.tsx b/examples/nextjs-with-typescript/pages/mux-video-react.tsx new file mode 100644 index 000000000..fd20dd3b9 --- /dev/null +++ b/examples/nextjs-with-typescript/pages/mux-video-react.tsx @@ -0,0 +1,82 @@ +import Head from 'next/head'; +import { useRef, useState } from "react"; +import MuxVideo from "@mux/mux-video/react"; + +const INITIAL_AUTOPLAY = false; +const INITIAL_MUTED = false; + +function MuxVideoPage() { + const mediaElRef = useRef(null); + const [autoplay, setAutoplay] = useState<"muted" | boolean>(INITIAL_AUTOPLAY); + const [muted, setMuted] = useState(INITIAL_MUTED); + const [paused, setPaused] = useState(true); + + return ( + <> + + <MuxVideo/> Demo + + + { + setPaused(false); + }} + onPause={() => { + setPaused(true); + }} + /> + +
    +
    + + paused ? mediaElRef.current.play() : mediaElRef.current.pause()} + checked={paused} + /> +
    +
    + + setAutoplay(!autoplay ? "muted" : false)} + checked={!!autoplay} + /> +
    +
    + + setMuted(!muted)} + checked={muted} + /> +
    +
    + + ); +} + +export default MuxVideoPage; diff --git a/packages/mux-video/package.json b/packages/mux-video/package.json index 22d8df510..b293fcf93 100644 --- a/packages/mux-video/package.json +++ b/packages/mux-video/package.json @@ -18,11 +18,17 @@ "<4.3.5": { ".": [ "./dist/types-ts3.4/index.d.ts" + ], + "react": [ + "./dist/types-ts3.4/react.d.ts" ] }, "*": { ".": [ "./dist/types/index.d.ts" + ], + "react": [ + "./dist/types/react.d.ts" ] } }, @@ -33,6 +39,12 @@ "types@<4.3.5": "./dist/types-ts3.4/index.d.ts", "types": "./dist/types/index.d.ts", "default": "./dist/index.cjs.js" + }, + "./react": { + "import": "./dist/react.mjs", + "require": "./dist/react.cjs.js", + "types": "./dist/types/react.d.ts", + "default": "./dist/react.cjs.js" } }, "types": "./dist/types/index.d.ts", @@ -52,16 +64,20 @@ "dev:cjs": "yarn build:cjs --watch=forever", "dev:esm": "yarn build:esm --watch=forever", "dev:esm-module": "yarn build:esm-module --watch=forever", + "dev:react:cjs": "yarn build:react:cjs --watch=forever", + "dev:react:esm": "yarn build:react:esm --watch=forever", "dev:types": "yarn build:types -w", - "dev": "npm-run-all --parallel dev:types dev:esm dev:cjs dev:iife", + "dev": "npm-run-all --parallel dev:types dev:esm dev:cjs dev:iife dev:react:*", "build:esm": "esbuild src/index.ts --target=es2019 --external:@mux/* --bundle --sourcemap --metafile=./dist/esm.json --format=esm --outdir=dist --out-extension:.js=.mjs --define:PLAYER_VERSION=\"'$npm_package_version'\"", "build:esm-module": "esbuild src/index.ts --target=es2019 --bundle --sourcemap --metafile=./dist/module.json --format=esm --outfile=./dist/mux-video.mjs --define:PLAYER_VERSION=\"'$npm_package_version'\"", "build:cjs": "esbuild src/index.ts --target=es2019 --external:@mux/* --bundle --sourcemap --metafile=./dist/cjs.json --format=cjs --outdir=dist --out-extension:.js=.cjs.js --define:PLAYER_VERSION=\"'$npm_package_version'\"", - "build:iife": "esbuild src/index.ts --target=es2019 --bundle --sourcemap --metafile=./dist/iife.json --format=iife --outfile=./dist/mux-video.js --define:PLAYER_VERSION=\"'$npm_package_version'\"", + "build:iife": "esbuild src/index.ts --target=es2019 --bundle --sourcemap --metafile=./dist/iife.json --format=iife --outfile=./dist/mux-video.js --define:PLAYER_VERSION=\"'$npm_package_version'\"", + "build:react:cjs": "esbuild src/react.ts --target=es2019 --bundle --format=cjs --outdir=dist --out-extension:.js=.cjs.js --external:react --external:.", + "build:react:esm": "esbuild src/react.ts --target=es2019 --bundle --format=esm --outdir=dist --out-extension:.js=.mjs --external:react --external:.", "copypolyfills": "shx mkdir -p src/polyfills && shx cp ../../shared/polyfills/index.ts ./src/polyfills/index.ts", "build:types": "tsc", "postbuild:types": "downlevel-dts ./dist/types ./dist/types-ts3.4", - "build": "npm-run-all --parallel 'build:esm --minify' 'build:iife --minify' 'build:cjs --minify' 'build:esm-module --minify'" + "build": "npm-run-all --parallel 'build:esm --minify' 'build:iife --minify' 'build:cjs --minify' 'build:esm-module --minify' 'build:react:cjs --minify' 'build:react:esm --minify'" }, "dependencies": { "@mux/playback-core": "0.28.1", @@ -76,11 +92,13 @@ "@web/dev-server-esbuild": "^1.0.2", "@web/dev-server-import-maps": "^0.2.1", "@web/test-runner": "^0.19.0", + "ce-la-react": "^0.1.3", "downlevel-dts": "^0.11.0", "esbuild": "^0.19.8", "eslint": "^9.9.1", "hls.js": "~1.5.11", "npm-run-all": "^4.1.5", + "react": "^18.2.0", "replace": "^1.2.1", "shx": "^0.3.4", "typescript": "^5.5.4" diff --git a/packages/mux-video/src/react.ts b/packages/mux-video/src/react.ts new file mode 100644 index 000000000..459fb94da --- /dev/null +++ b/packages/mux-video/src/react.ts @@ -0,0 +1,29 @@ +'use client'; + +import MuxVideoElement from '.'; +import React from 'react'; +// keep as last import, ce-la-react is bundled. +import { createComponent } from 'ce-la-react'; + +export default createComponent({ + react: React, + tagName: 'mux-video', + elementClass: MuxVideoElement, + toAttributeName, +}); + +const ReactPropToAttrNameMap: Record = { + autoPlay: 'autoplay', + controlsList: 'controlslist', + crossOrigin: 'crossorigin', + playsInline: 'playsinline', + disablePictureInPicture: 'disablepictureinpicture', + disableRemotePlayback: 'disableremoteplayback', +}; + +function toAttributeName(propName: string) { + if (ReactPropToAttrNameMap[propName]) { + return ReactPropToAttrNameMap[propName]; + } + return propName.replace(/([A-Z])/g, '-$1').toLowerCase(); +} diff --git a/yarn.lock b/yarn.lock index b34379302..e06ece57a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6090,6 +6090,11 @@ ccount@^2.0.0: resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== +ce-la-react@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ce-la-react/-/ce-la-react-0.1.3.tgz#ccb34ec24091bd8be3da40ddcedb4a99ae1db72f" + integrity sha512-zZwEEJv9XukeEGbswQXObaDJjYAufOIilSnDg4BWCpKNEYN84H9fpaB+wl+rYKWOIH4wBBPbLnOxKvDIwsL/JQ== + chai-a11y-axe@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/chai-a11y-axe/-/chai-a11y-axe-1.5.0.tgz#aafa37f91f53baeafe98219768e5dee8776cf655" @@ -15162,7 +15167,16 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -15297,7 +15311,14 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -17033,7 +17054,7 @@ workbox-window@6.6.1: "@types/trusted-types" "^2.0.2" workbox-core "6.6.1" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -17051,6 +17072,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"