@easy-editor/materials-dashboard-audio 0.0.2

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.
Files changed (44) hide show
  1. package/.vite/plugins/vite-plugin-external-deps.ts +224 -0
  2. package/.vite/plugins/vite-plugin-material-dev.ts +218 -0
  3. package/CHANGELOG.md +7 -0
  4. package/LICENSE +9 -0
  5. package/dist/component.esm.js +165 -0
  6. package/dist/component.esm.js.map +1 -0
  7. package/dist/component.js +173 -0
  8. package/dist/component.js.map +1 -0
  9. package/dist/component.min.js +2 -0
  10. package/dist/component.min.js.map +1 -0
  11. package/dist/index.cjs +456 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.esm.js +453 -0
  14. package/dist/index.esm.js.map +1 -0
  15. package/dist/index.js +460 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/index.min.js +2 -0
  18. package/dist/index.min.js.map +1 -0
  19. package/dist/meta.esm.js +292 -0
  20. package/dist/meta.esm.js.map +1 -0
  21. package/dist/meta.js +303 -0
  22. package/dist/meta.js.map +1 -0
  23. package/dist/meta.min.js +2 -0
  24. package/dist/meta.min.js.map +1 -0
  25. package/dist/src/component.d.ts +23 -0
  26. package/dist/src/configure.d.ts +7 -0
  27. package/dist/src/constants.d.ts +16 -0
  28. package/dist/src/index.d.ts +6 -0
  29. package/dist/src/meta.d.ts +7 -0
  30. package/dist/src/snippets.d.ts +7 -0
  31. package/package.json +68 -0
  32. package/rollup.config.js +222 -0
  33. package/src/component.module.css +104 -0
  34. package/src/component.tsx +140 -0
  35. package/src/configure.ts +247 -0
  36. package/src/constants.ts +18 -0
  37. package/src/index.tsx +7 -0
  38. package/src/meta.ts +28 -0
  39. package/src/snippets.ts +50 -0
  40. package/src/type.d.ts +8 -0
  41. package/tsconfig.build.json +12 -0
  42. package/tsconfig.json +9 -0
  43. package/tsconfig.test.json +7 -0
  44. package/vite.config.ts +54 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.min.js","sources":["../../../../shared/src/index.ts","../src/constants.ts","../src/meta.ts","../src/snippets.ts","../src/configure.ts"],"sourcesContent":["/**\n * Shared types, components and utilities for EasyEditor materials\n * @package @easy-editor/materials-shared\n */\n\n// 物料分组常量\nexport const MaterialGroup = {\n /** 内置 */\n INNER: 'inner',\n /** 基础 */\n BASIC: 'basic',\n /** 图表 */\n CHART: 'chart',\n /** 数据展示 */\n DISPLAY: 'display',\n /** 媒体 */\n MEDIA: 'media',\n /** 交互 */\n INTERACTION: 'interaction',\n /** 地图 */\n MAP: 'map',\n} as const\n\nexport type MaterialGroup = (typeof MaterialGroup)[keyof typeof MaterialGroup]\n\n// 工具函数\nexport { cn } from './lib/utils'\n\nexport * from './types'\n","/**\n * 物料常量配置\n * 统一管理全局变量名等配置,确保 meta.ts 和 rollup.config.js 使用相同的值\n */\n\n/**\n * UMD 全局变量基础名称\n * 用于构建:\n * - 元数据:${GLOBAL_NAME}Meta (例如: EasyEditorMaterialsAudioMeta)\n * - 组件:${GLOBAL_NAME}Component (例如: EasyEditorMaterialsAudioComponent)\n * - 完整构建:${GLOBAL_NAME} (例如: EasyEditorMaterialsAudio)\n */\nexport const COMPONENT_NAME = 'EasyEditorMaterialsAudio'\n\n/**\n * 包名\n */\nexport const PACKAGE_NAME = '@easy-editor/materials-dashboard-audio'\n","/**\n * Audio Meta\n * 音频组件元数据\n */\n\nimport type { ComponentMetadata } from '@easy-editor/core'\nimport { MaterialGroup } from '@easy-editor/materials-shared'\nimport { COMPONENT_NAME, PACKAGE_NAME } from './constants'\nimport configure from './configure'\nimport snippets from './snippets'\nimport pkg from '../package.json'\n\nexport const meta: ComponentMetadata = {\n componentName: COMPONENT_NAME,\n title: '音频',\n group: MaterialGroup.MEDIA,\n devMode: 'proCode',\n npm: {\n package: PACKAGE_NAME,\n version: pkg.version,\n globalName: COMPONENT_NAME,\n componentName: COMPONENT_NAME,\n },\n snippets,\n configure,\n}\n\nexport default meta\n","/**\n * Audio Snippets\n * 音频组件代码片段\n */\n\nimport type { Snippet } from '@easy-editor/core'\nimport { COMPONENT_NAME } from './constants'\n\nexport const snippets: Snippet[] = [\n {\n title: '音频播放器',\n screenshot: '',\n schema: {\n componentName: COMPONENT_NAME,\n props: {\n src: '',\n title: '音频文件',\n autoPlay: false,\n loop: false,\n audioStyle: 'custom',\n },\n $dashboard: {\n rect: {\n width: 300,\n height: 60,\n },\n },\n },\n },\n {\n title: '原生音频',\n screenshot: '',\n schema: {\n componentName: COMPONENT_NAME,\n props: {\n src: '',\n title: '音频文件',\n audioStyle: 'native',\n },\n $dashboard: {\n rect: {\n width: 300,\n height: 60,\n },\n },\n },\n },\n]\n\nexport default snippets\n","/**\n * Audio Configure\n * 音频组件配置\n */\n\nimport type { Configure } from '@easy-editor/core'\nimport type { UploadValue } from '@easy-editor/materials-shared'\n\nexport const configure: Configure = {\n props: [\n {\n type: 'group',\n title: '属性',\n setter: 'TabSetter',\n items: [\n {\n type: 'group',\n key: 'config',\n title: '配置',\n setter: {\n componentName: 'CollapseSetter',\n props: {\n icon: false,\n },\n },\n items: [\n // 基础配置\n {\n name: 'id',\n title: 'ID',\n setter: 'NodeIdSetter',\n extraProps: {\n // @ts-expect-error label is not a valid extra prop\n label: false,\n },\n },\n {\n name: 'title',\n title: '标题',\n setter: 'StringSetter',\n extraProps: {\n getValue(target) {\n return target.getExtraPropValue('title')\n },\n setValue(target, value) {\n target.setExtraPropValue('title', value)\n },\n },\n },\n {\n type: 'group',\n title: '基础属性',\n setter: {\n componentName: 'CollapseSetter',\n props: {\n icon: false,\n },\n },\n items: [\n {\n name: 'rect',\n title: '位置尺寸',\n setter: 'RectSetter',\n extraProps: {\n getValue(target) {\n return target.getExtraPropValue('$dashboard.rect')\n },\n setValue(target, value) {\n target.setExtraPropValue('$dashboard.rect', value)\n },\n },\n },\n ],\n },\n // 组件配置\n {\n type: 'group',\n title: '内容',\n setter: {\n componentName: 'CollapseSetter',\n props: {\n icon: false,\n },\n },\n items: [\n {\n name: '__upload',\n title: '上传',\n setter: {\n componentName: 'UploadSetter',\n props: {\n accept: '.mp3,.wav,.ogg',\n },\n },\n extraProps: {\n setValue(target, value: UploadValue) {\n if (value) {\n const { base64, raw } = value\n if (base64) {\n target.parent.setPropValue('src', base64)\n }\n if (raw?.width) {\n target.parent.setExtraPropValue('$dashboard.rect.width', raw.width)\n }\n if (raw?.height) {\n target.parent.setExtraPropValue('$dashboard.rect.height', raw.height)\n }\n } else {\n target.parent.clearPropValue('src')\n }\n },\n },\n },\n {\n name: 'src',\n title: '音频地址',\n setter: 'StringSetter',\n },\n {\n name: 'title',\n title: '标题',\n setter: 'StringSetter',\n extraProps: {\n defaultValue: '音频文件',\n },\n },\n ],\n },\n {\n type: 'group',\n title: '播放',\n setter: {\n componentName: 'CollapseSetter',\n props: {\n icon: false,\n },\n },\n items: [\n {\n name: 'autoPlay',\n title: '自动播放',\n setter: 'SwitchSetter',\n extraProps: {\n defaultValue: false,\n },\n },\n {\n name: 'loop',\n title: '循环播放',\n setter: 'SwitchSetter',\n extraProps: {\n defaultValue: false,\n },\n },\n {\n name: 'audioStyle',\n title: '样式类型',\n setter: {\n componentName: 'SelectSetter',\n props: {\n options: [\n { label: '自定义', value: 'custom' },\n { label: '原生', value: 'native' },\n ],\n },\n },\n extraProps: {\n defaultValue: 'custom',\n },\n },\n {\n name: 'playbackRate',\n title: '播放速度',\n setter: {\n componentName: 'SelectSetter',\n props: {\n options: [\n { label: '0.5x', value: 0.5 },\n { label: '0.75x', value: 0.75 },\n { label: '1x (正常)', value: 1 },\n { label: '1.25x', value: 1.25 },\n { label: '1.5x', value: 1.5 },\n { label: '2x', value: 2 },\n ],\n },\n },\n extraProps: {\n defaultValue: 1,\n },\n },\n {\n name: 'volume',\n title: '音量',\n setter: {\n componentName: 'SliderSetter',\n props: {\n min: 0,\n max: 100,\n step: 1,\n suffix: '%',\n },\n },\n extraProps: {\n defaultValue: 100,\n },\n },\n ],\n },\n ],\n },\n {\n type: 'group',\n key: 'data',\n title: '数据',\n items: [\n {\n name: 'dataBinding',\n title: '数据绑定',\n setter: 'DataBindingSetter',\n },\n ],\n },\n {\n type: 'group',\n key: 'advanced',\n title: '高级',\n items: [\n {\n name: 'condition',\n title: '显隐控制',\n setter: 'SwitchSetter',\n extraProps: {\n defaultValue: true,\n supportVariable: true,\n },\n },\n ],\n },\n ],\n },\n ],\n component: {},\n supports: {},\n advanced: {},\n}\n\nexport default configure\n"],"names":["COMPONENT_NAME","meta","componentName","title","group","devMode","npm","package","version","globalName","snippets","screenshot","schema","props","src","autoPlay","loop","audioStyle","$dashboard","rect","width","height","configure","type","setter","items","key","icon","name","extraProps","label","getValue","target","getExtraPropValue","setValue","value","setExtraPropValue","accept","base64","raw","parent","setPropValue","clearPropValue","defaultValue","options","min","max","step","suffix","supportVariable","component","supports","advanced"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Audio Component
3
+ * 音频播放组件
4
+ */
5
+ import { type CSSProperties, type Ref } from 'react';
6
+ export type AudioStyle = 'custom' | 'native';
7
+ export interface AudioProps {
8
+ ref?: Ref<HTMLDivElement>;
9
+ /** 音频地址 */
10
+ src?: string;
11
+ /** 标题 */
12
+ title?: string;
13
+ /** 自动播放 */
14
+ autoPlay?: boolean;
15
+ /** 循环播放 */
16
+ loop?: boolean;
17
+ /** 样式类型 */
18
+ audioStyle?: AudioStyle;
19
+ /** 外部样式 */
20
+ style?: CSSProperties;
21
+ }
22
+ export declare const Audio: React.FC<AudioProps>;
23
+ export default Audio;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Audio Configure
3
+ * 音频组件配置
4
+ */
5
+ import type { Configure } from '@easy-editor/core';
6
+ export declare const configure: Configure;
7
+ export default configure;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 物料常量配置
3
+ * 统一管理全局变量名等配置,确保 meta.ts 和 rollup.config.js 使用相同的值
4
+ */
5
+ /**
6
+ * UMD 全局变量基础名称
7
+ * 用于构建:
8
+ * - 元数据:${GLOBAL_NAME}Meta (例如: EasyEditorMaterialsAudioMeta)
9
+ * - 组件:${GLOBAL_NAME}Component (例如: EasyEditorMaterialsAudioComponent)
10
+ * - 完整构建:${GLOBAL_NAME} (例如: EasyEditorMaterialsAudio)
11
+ */
12
+ export declare const COMPONENT_NAME = "EasyEditorMaterialsAudio";
13
+ /**
14
+ * 包名
15
+ */
16
+ export declare const PACKAGE_NAME = "@easy-editor/materials-dashboard-audio";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Audio Entry
3
+ * 音频组件入口
4
+ */
5
+ export { Audio as component } from './component';
6
+ export { default as meta } from './meta';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Audio Meta
3
+ * 音频组件元数据
4
+ */
5
+ import type { ComponentMetadata } from '@easy-editor/core';
6
+ export declare const meta: ComponentMetadata;
7
+ export default meta;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Audio Snippets
3
+ * 音频组件代码片段
4
+ */
5
+ import type { Snippet } from '@easy-editor/core';
6
+ export declare const snippets: Snippet[];
7
+ export default snippets;
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@easy-editor/materials-dashboard-audio",
3
+ "version": "0.0.2",
4
+ "description": "Audio component for EasyEditor dashboard",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.esm.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "jsdelivr": "dist/index.min.js",
18
+ "registry": "https://registry.npmjs.org/"
19
+ },
20
+ "homepage": "https://github.com/Easy-Editor/EasyMaterials",
21
+ "license": "MIT",
22
+ "author": "JinSo <kimjinso@qq.com>",
23
+ "keywords": [
24
+ "@easy-editor",
25
+ "easyeditor",
26
+ "low-code",
27
+ "dashboard",
28
+ "audio",
29
+ "player",
30
+ "component",
31
+ "react"
32
+ ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/Easy-Editor/EasyMaterials",
36
+ "directory": "packages/dashboard/media/audio"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/Easy-Editor/EasyMaterials/issues"
40
+ },
41
+ "peerDependencies": {
42
+ "@easy-editor/core": "*",
43
+ "@types/react": "^18 || ^19",
44
+ "@types/react-dom": "^18 || ^19",
45
+ "react": "^18 || ^19",
46
+ "react-dom": "^18 || ^19"
47
+ },
48
+ "dependencies": {
49
+ "@easy-editor/materials-shared": "0.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@originjs/vite-plugin-federation": "^1.4.1"
53
+ },
54
+ "scripts": {
55
+ "dev": "vite",
56
+ "format": "biome format --write .",
57
+ "lint": "biome check .",
58
+ "build": "npm-run-all -nl build:*",
59
+ "build:clean": "rimraf dist/",
60
+ "build:js": "rollup -c",
61
+ "build:types": "pnpm types",
62
+ "types": "npm-run-all -nl types:*",
63
+ "types:src": "tsc --project tsconfig.build.json",
64
+ "test-types": "tsc --project tsconfig.test.json"
65
+ },
66
+ "module": "dist/index.esm.js",
67
+ "unpkg": "dist/index.min.js"
68
+ }
@@ -0,0 +1,222 @@
1
+ import babel from '@rollup/plugin-babel'
2
+ import commonjs from '@rollup/plugin-commonjs'
3
+ import nodeResolve from '@rollup/plugin-node-resolve'
4
+ import json from '@rollup/plugin-json'
5
+ import { terser } from 'rollup-plugin-terser'
6
+ import cleanup from 'rollup-plugin-cleanup'
7
+ import postcss from 'rollup-plugin-postcss'
8
+ import pkg from './package.json' with { type: 'json' }
9
+
10
+ const GLOBAL_NAME = 'EasyEditorMaterialsAudio'
11
+
12
+ // 外部依赖(不打包进组件)
13
+ const external = ['react', 'react-dom', 'react/jsx-runtime', '@easy-editor/core']
14
+
15
+ const globals = {
16
+ react: 'React',
17
+ 'react-dom': 'ReactDOM',
18
+ 'react/jsx-runtime': 'jsxRuntime',
19
+ '@easy-editor/core': 'EasyEditorCore',
20
+ }
21
+
22
+ const plugins = [
23
+ nodeResolve({
24
+ extensions: ['.js', '.ts', '.jsx', '.tsx'],
25
+ }),
26
+ commonjs(),
27
+ json(),
28
+ postcss({
29
+ modules: {
30
+ generateScopedName: '[name]__[local]___[hash:base64:5]',
31
+ },
32
+ autoModules: true,
33
+ minimize: true,
34
+ inject: true,
35
+ }),
36
+ babel({
37
+ extensions: ['.js', '.ts', '.jsx', '.tsx'],
38
+ exclude: 'node_modules/**',
39
+ babelrc: false,
40
+ babelHelpers: 'bundled',
41
+ presets: [
42
+ ['@babel/preset-react', { runtime: 'automatic' }],
43
+ [
44
+ '@babel/preset-typescript',
45
+ {
46
+ allowDeclareFields: true,
47
+ },
48
+ ],
49
+ ],
50
+ }),
51
+ cleanup({
52
+ comments: ['some', /PURE/],
53
+ extensions: ['.js', '.ts'],
54
+ }),
55
+ ]
56
+
57
+ export default [
58
+ /* ---------------------------------- 元数据构建 --------------------------------- */
59
+ // 元数据 ESM 构建(用于动态 import)
60
+ {
61
+ input: 'src/meta.ts',
62
+ output: [
63
+ {
64
+ file: 'dist/meta.esm.js',
65
+ format: 'esm',
66
+ sourcemap: true,
67
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} (meta, esm) */`,
68
+ exports: 'named',
69
+ },
70
+ ],
71
+ plugins,
72
+ external,
73
+ },
74
+ // 元数据 UMD 构建(备用方案)
75
+ {
76
+ input: 'src/meta.ts',
77
+ output: [
78
+ {
79
+ file: 'dist/meta.js',
80
+ format: 'umd',
81
+ name: `${GLOBAL_NAME}Meta`,
82
+ globals,
83
+ sourcemap: true,
84
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} (meta) */`,
85
+ exports: 'named',
86
+ },
87
+ ],
88
+ plugins,
89
+ external,
90
+ },
91
+ // 元数据压缩版本(UMD,备用方案)
92
+ {
93
+ input: 'src/meta.ts',
94
+ output: [
95
+ {
96
+ file: 'dist/meta.min.js',
97
+ format: 'umd',
98
+ name: `${GLOBAL_NAME}Meta`,
99
+ globals,
100
+ sourcemap: true,
101
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} (meta, minified) */`,
102
+ exports: 'named',
103
+ },
104
+ ],
105
+ plugins: [...plugins, terser()],
106
+ external,
107
+ },
108
+
109
+ /* ---------------------------------- 组件构建 ---------------------------------- */
110
+ // 组件 ESM 构建(用于动态 import)
111
+ {
112
+ input: 'src/component.tsx',
113
+ output: [
114
+ {
115
+ file: 'dist/component.esm.js',
116
+ format: 'esm',
117
+ sourcemap: true,
118
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} (component, esm) */`,
119
+ exports: 'named',
120
+ },
121
+ ],
122
+ plugins,
123
+ external,
124
+ },
125
+ // 组件 UMD 构建(备用方案)
126
+ {
127
+ input: 'src/component.tsx',
128
+ output: [
129
+ {
130
+ file: 'dist/component.js',
131
+ format: 'umd',
132
+ name: `${GLOBAL_NAME}Component`,
133
+ globals,
134
+ sourcemap: true,
135
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} (component) */`,
136
+ exports: 'named',
137
+ },
138
+ ],
139
+ plugins,
140
+ external,
141
+ },
142
+ // 组件压缩版本(UMD,备用方案)
143
+ {
144
+ input: 'src/component.tsx',
145
+ output: [
146
+ {
147
+ file: 'dist/component.min.js',
148
+ format: 'umd',
149
+ name: `${GLOBAL_NAME}Component`,
150
+ globals,
151
+ sourcemap: true,
152
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} (component, minified) */`,
153
+ exports: 'named',
154
+ },
155
+ ],
156
+ plugins: [...plugins, terser()],
157
+ external,
158
+ },
159
+
160
+ /* ---------------------------------- 完整构建 ---------------------------------- */
161
+ // UMD 构建(用于 CDN 和浏览器)
162
+ {
163
+ input: 'src/index.tsx',
164
+ output: [
165
+ {
166
+ file: 'dist/index.js',
167
+ format: 'umd',
168
+ name: GLOBAL_NAME,
169
+ globals,
170
+ sourcemap: true,
171
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} */`,
172
+ exports: 'named',
173
+ },
174
+ ],
175
+ plugins,
176
+ external,
177
+ },
178
+ // ESM 构建(用于现代打包工具)
179
+ {
180
+ input: 'src/index.tsx',
181
+ output: [
182
+ {
183
+ file: 'dist/index.esm.js',
184
+ format: 'esm',
185
+ sourcemap: true,
186
+ },
187
+ ],
188
+ plugins,
189
+ external,
190
+ },
191
+ // CJS 构建(用于 Node.js)
192
+ {
193
+ input: 'src/index.tsx',
194
+ output: [
195
+ {
196
+ file: 'dist/index.cjs',
197
+ format: 'cjs',
198
+ sourcemap: true,
199
+ exports: 'named',
200
+ },
201
+ ],
202
+ plugins,
203
+ external,
204
+ },
205
+ // 压缩版本(用于生产环境)
206
+ {
207
+ input: 'src/index.tsx',
208
+ output: [
209
+ {
210
+ file: 'dist/index.min.js',
211
+ format: 'umd',
212
+ name: GLOBAL_NAME,
213
+ globals,
214
+ sourcemap: true,
215
+ banner: `/* @easy-editor/materials-dashboard-image v${pkg.version} (minified) */`,
216
+ exports: 'named',
217
+ },
218
+ ],
219
+ plugins: [...plugins, terser()],
220
+ external,
221
+ },
222
+ ]
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Audio Component Styles
3
+ * 音频组件样式
4
+ */
5
+
6
+ .container {
7
+ display: flex;
8
+ align-items: center;
9
+ gap: 12px;
10
+ padding: 12px 16px;
11
+ width: 100%;
12
+ height: 100%;
13
+ background: rgba(10, 10, 26, 0.95);
14
+ border: 1px solid rgba(26, 26, 62, 0.8);
15
+ border-radius: 8px;
16
+ }
17
+
18
+ .playButton {
19
+ width: 40px;
20
+ height: 40px;
21
+ border: none;
22
+ border-radius: 50%;
23
+ background: linear-gradient(135deg, #00d4ff, #9b59b6);
24
+ cursor: pointer;
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ flex-shrink: 0;
29
+ transition: transform 0.2s ease;
30
+ }
31
+
32
+ .playButton:hover {
33
+ transform: scale(1.05);
34
+ }
35
+
36
+ .playIcon {
37
+ width: 0;
38
+ height: 0;
39
+ border-top: 8px solid transparent;
40
+ border-bottom: 8px solid transparent;
41
+ border-left: 12px solid #fff;
42
+ margin-left: 3px;
43
+ }
44
+
45
+ .pauseIcon {
46
+ display: flex;
47
+ gap: 3px;
48
+ }
49
+
50
+ .pauseBar {
51
+ width: 4px;
52
+ height: 14px;
53
+ background: #fff;
54
+ border-radius: 2px;
55
+ }
56
+
57
+ .info {
58
+ flex: 1;
59
+ min-width: 0;
60
+ }
61
+
62
+ .title {
63
+ font-size: 14px;
64
+ font-weight: 500;
65
+ color: #e6e6e6;
66
+ overflow: hidden;
67
+ text-overflow: ellipsis;
68
+ white-space: nowrap;
69
+ }
70
+
71
+ .progressContainer {
72
+ display: flex;
73
+ align-items: center;
74
+ gap: 8px;
75
+ margin-top: 4px;
76
+ }
77
+
78
+ .progressBar {
79
+ flex: 1;
80
+ height: 4px;
81
+ background: rgba(26, 26, 62, 0.8);
82
+ border-radius: 2px;
83
+ overflow: hidden;
84
+ cursor: pointer;
85
+ }
86
+
87
+ .progressFill {
88
+ height: 100%;
89
+ background: linear-gradient(90deg, #00d4ff, #9b59b6);
90
+ border-radius: 2px;
91
+ transition: width 0.1s linear;
92
+ }
93
+
94
+ .time {
95
+ font-size: 12px;
96
+ color: rgba(255, 255, 255, 0.6);
97
+ font-family: "Courier New", Courier, monospace;
98
+ min-width: 80px;
99
+ text-align: right;
100
+ }
101
+
102
+ .nativeAudio {
103
+ width: 100%;
104
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Audio Component
3
+ * 音频播放组件
4
+ */
5
+
6
+ import { useState, useRef, useEffect, type CSSProperties, type Ref } from 'react'
7
+ import styles from './component.module.css'
8
+
9
+ export type AudioStyle = 'custom' | 'native'
10
+
11
+ export interface AudioProps {
12
+ ref?: Ref<HTMLDivElement>
13
+ /** 音频地址 */
14
+ src?: string
15
+ /** 标题 */
16
+ title?: string
17
+ /** 自动播放 */
18
+ autoPlay?: boolean
19
+ /** 循环播放 */
20
+ loop?: boolean
21
+ /** 样式类型 */
22
+ audioStyle?: AudioStyle
23
+ /** 外部样式 */
24
+ style?: CSSProperties
25
+ }
26
+
27
+ const formatTime = (seconds: number): string => {
28
+ const mins = Math.floor(seconds / 60)
29
+ const secs = Math.floor(seconds % 60)
30
+ return `${mins}:${secs.toString().padStart(2, '0')}`
31
+ }
32
+
33
+ export const Audio: React.FC<AudioProps> = ({
34
+ ref,
35
+ src = '',
36
+ title = '音频文件',
37
+ autoPlay = false,
38
+ loop = false,
39
+ audioStyle = 'custom',
40
+ style: externalStyle,
41
+ }) => {
42
+ const audioRef = useRef<HTMLAudioElement>(null)
43
+ const [isPlaying, setIsPlaying] = useState(false)
44
+ const [currentTime, setCurrentTime] = useState(0)
45
+ const [duration, setDuration] = useState(0)
46
+
47
+ useEffect(() => {
48
+ const audio = audioRef.current
49
+ if (!audio) {
50
+ return
51
+ }
52
+
53
+ const handleTimeUpdate = () => setCurrentTime(audio.currentTime)
54
+ const handleLoadedMetadata = () => setDuration(audio.duration)
55
+ const handleEnded = () => setIsPlaying(false)
56
+
57
+ audio.addEventListener('timeupdate', handleTimeUpdate)
58
+ audio.addEventListener('loadedmetadata', handleLoadedMetadata)
59
+ audio.addEventListener('ended', handleEnded)
60
+
61
+ return () => {
62
+ audio.removeEventListener('timeupdate', handleTimeUpdate)
63
+ audio.removeEventListener('loadedmetadata', handleLoadedMetadata)
64
+ audio.removeEventListener('ended', handleEnded)
65
+ }
66
+ }, [])
67
+
68
+ const togglePlay = () => {
69
+ if (audioRef.current) {
70
+ if (isPlaying) {
71
+ audioRef.current.pause()
72
+ } else {
73
+ audioRef.current.play()
74
+ }
75
+ setIsPlaying(!isPlaying)
76
+ }
77
+ }
78
+
79
+ const handleProgressClick = (e: React.MouseEvent<HTMLDivElement>) => {
80
+ if (audioRef.current && duration) {
81
+ const rect = e.currentTarget.getBoundingClientRect()
82
+ const percent = (e.clientX - rect.left) / rect.width
83
+ audioRef.current.currentTime = percent * duration
84
+ }
85
+ }
86
+
87
+ const progress = duration ? (currentTime / duration) * 100 : 0
88
+
89
+ // 原生样式
90
+ if (audioStyle === 'native') {
91
+ return (
92
+ <div className={styles.container} ref={ref} style={externalStyle}>
93
+ <audio autoPlay={autoPlay} className={styles.nativeAudio} controls loop={loop} ref={audioRef} src={src} />
94
+ </div>
95
+ )
96
+ }
97
+
98
+ // 自定义样式
99
+ return (
100
+ <div className={styles.container} ref={ref} style={externalStyle}>
101
+ <audio autoPlay={autoPlay} loop={loop} ref={audioRef} src={src} />
102
+
103
+ <button
104
+ aria-label={isPlaying ? 'Pause' : 'Play'}
105
+ className={styles.playButton}
106
+ onClick={togglePlay}
107
+ type='button'
108
+ >
109
+ {isPlaying ? (
110
+ <div className={styles.pauseIcon}>
111
+ <div className={styles.pauseBar} />
112
+ <div className={styles.pauseBar} />
113
+ </div>
114
+ ) : (
115
+ <div className={styles.playIcon} />
116
+ )}
117
+ </button>
118
+
119
+ <div className={styles.info}>
120
+ <div className={styles.title}>{title}</div>
121
+ <div className={styles.progressContainer}>
122
+ <button
123
+ aria-label='Seek to position'
124
+ className={styles.progressBar}
125
+ // @ts-expect-error
126
+ onClick={handleProgressClick}
127
+ type='button'
128
+ >
129
+ <div className={styles.progressFill} style={{ width: `${progress}%` }} />
130
+ </button>
131
+ <span className={styles.time}>
132
+ {formatTime(currentTime)} / {formatTime(duration || 0)}
133
+ </span>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ )
138
+ }
139
+
140
+ export default Audio