@elicecontents/content-ui 1.0.8 β†’ 1.0.9

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.
@@ -1,5 +1,7 @@
1
1
  export interface EliceAudioPlayerProps {
2
2
  src: string;
3
+ mimeType?: string;
4
+ onFileLoaded?: (file: File) => void;
3
5
  }
4
- declare const EliceAudioPlayer: ({ src }: EliceAudioPlayerProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const EliceAudioPlayer: ({ src, mimeType, onFileLoaded, }: EliceAudioPlayerProps) => import("react/jsx-runtime").JSX.Element;
5
7
  export default EliceAudioPlayer;
@@ -25,8 +25,47 @@ var PlayerButton = /*#__PURE__*/_styled__default.default("button", {
25
25
  styles: "display:flex;background-color:transparent!important;border:none",
26
26
  toString: _EMOTION_STRINGIFIED_CSS_ERROR__
27
27
  });
28
- var EliceAudioPlayer = function EliceAudioPlayer(_ref) {
29
- var src = _ref.src;
28
+ var getAccurateDuration = /*#__PURE__*/function () {
29
+ var _ref = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regeneratorRuntime().mark(function _callee(src) {
30
+ var response, arrayBuffer, audioCtx, audioBuffer;
31
+ return _rollupPluginBabelHelpers.regeneratorRuntime().wrap(function _callee$(_context) {
32
+ while (1) switch (_context.prev = _context.next) {
33
+ case 0:
34
+ _context.prev = 0;
35
+ _context.next = 3;
36
+ return fetch(src);
37
+ case 3:
38
+ response = _context.sent;
39
+ _context.next = 6;
40
+ return response.arrayBuffer();
41
+ case 6:
42
+ arrayBuffer = _context.sent;
43
+ audioCtx = new AudioContext();
44
+ _context.next = 10;
45
+ return audioCtx.decodeAudioData(arrayBuffer);
46
+ case 10:
47
+ audioBuffer = _context.sent;
48
+ return _context.abrupt("return", audioBuffer.duration);
49
+ case 14:
50
+ _context.prev = 14;
51
+ _context.t0 = _context["catch"](0);
52
+ console.error('🎧 decodeAudioData μ‹€νŒ¨:', _context.t0);
53
+ return _context.abrupt("return", null);
54
+ case 18:
55
+ case "end":
56
+ return _context.stop();
57
+ }
58
+ }, _callee, null, [[0, 14]]);
59
+ }));
60
+ return function getAccurateDuration(_x) {
61
+ return _ref.apply(this, arguments);
62
+ };
63
+ }();
64
+ var EliceAudioPlayer = function EliceAudioPlayer(_ref2) {
65
+ var src = _ref2.src,
66
+ _ref2$mimeType = _ref2.mimeType,
67
+ mimeType = _ref2$mimeType === void 0 ? 'audio/mp3' : _ref2$mimeType,
68
+ onFileLoaded = _ref2.onFileLoaded;
30
69
  var audioRef = React.useRef(null);
31
70
  var _useState = React.useState(false),
32
71
  _useState2 = _rollupPluginBabelHelpers.slicedToArray(_useState, 2),
@@ -36,37 +75,99 @@ var EliceAudioPlayer = function EliceAudioPlayer(_ref) {
36
75
  _useState4 = _rollupPluginBabelHelpers.slicedToArray(_useState3, 2),
37
76
  progress = _useState4[0],
38
77
  setProgress = _useState4[1];
78
+ var _useState5 = React.useState(false),
79
+ _useState6 = _rollupPluginBabelHelpers.slicedToArray(_useState5, 2),
80
+ isReady = _useState6[0],
81
+ setIsReady = _useState6[1];
82
+ var _useState7 = React.useState(0),
83
+ _useState8 = _rollupPluginBabelHelpers.slicedToArray(_useState7, 2),
84
+ duration = _useState8[0],
85
+ setDuration = _useState8[1];
86
+ React.useEffect(function () {
87
+ var fetchAndDecode = /*#__PURE__*/function () {
88
+ var _ref3 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regeneratorRuntime().mark(function _callee2() {
89
+ var response, blob, filename, file, _duration;
90
+ return _rollupPluginBabelHelpers.regeneratorRuntime().wrap(function _callee2$(_context2) {
91
+ while (1) switch (_context2.prev = _context2.next) {
92
+ case 0:
93
+ _context2.prev = 0;
94
+ _context2.next = 3;
95
+ return fetch(src);
96
+ case 3:
97
+ response = _context2.sent;
98
+ _context2.next = 6;
99
+ return response.blob();
100
+ case 6:
101
+ blob = _context2.sent;
102
+ filename = src.split('/').pop() || 'audio.mp3';
103
+ file = new File([blob], filename, {
104
+ type: blob.type || mimeType
105
+ });
106
+ onFileLoaded === null || onFileLoaded === void 0 ? void 0 : onFileLoaded(file);
107
+ _context2.next = 12;
108
+ return getAccurateDuration(src);
109
+ case 12:
110
+ _duration = _context2.sent;
111
+ if (_duration && isFinite(_duration)) {
112
+ setDuration(_duration);
113
+ setIsReady(true);
114
+ }
115
+ _context2.next = 19;
116
+ break;
117
+ case 16:
118
+ _context2.prev = 16;
119
+ _context2.t0 = _context2["catch"](0);
120
+ console.error('❌ Fetch or decode μ‹€νŒ¨:', _context2.t0);
121
+ case 19:
122
+ case "end":
123
+ return _context2.stop();
124
+ }
125
+ }, _callee2, null, [[0, 16]]);
126
+ }));
127
+ return function fetchAndDecode() {
128
+ return _ref3.apply(this, arguments);
129
+ };
130
+ }();
131
+ if (src) fetchAndDecode();
132
+ }, [src, mimeType, onFileLoaded]);
39
133
  var togglePlay = function togglePlay() {
40
134
  var audio = audioRef.current;
41
135
  if (!audio) return;
42
- if (isPlaying) {
43
- audio.pause();
44
- } else {
45
- audio.play();
46
- }
136
+ isPlaying ? audio.pause() : audio.play();
47
137
  };
48
138
  React.useEffect(function () {
49
139
  var audio = audioRef.current;
50
140
  if (!audio) return;
141
+ var updateProgress = function updateProgress() {
142
+ if (duration > 0) {
143
+ var percent = audio.currentTime / duration * 100;
144
+ setProgress(percent);
145
+ }
146
+ };
51
147
  var handlePlay = function handlePlay() {
52
148
  return setIsPlaying(true);
53
149
  };
54
150
  var handlePause = function handlePause() {
55
151
  return setIsPlaying(false);
56
152
  };
57
- var handleTimeUpdate = function handleTimeUpdate() {
58
- var percent = audio.currentTime / audio.duration * 100;
59
- setProgress(percent);
153
+ var handleEnded = function handleEnded() {
154
+ setProgress(100);
155
+ setTimeout(function () {
156
+ setProgress(0);
157
+ setIsPlaying(false);
158
+ }, 300);
60
159
  };
160
+ audio.addEventListener('timeupdate', updateProgress);
61
161
  audio.addEventListener('play', handlePlay);
62
162
  audio.addEventListener('pause', handlePause);
63
- audio.addEventListener('timeupdate', handleTimeUpdate);
163
+ audio.addEventListener('ended', handleEnded);
64
164
  return function () {
165
+ audio.removeEventListener('timeupdate', updateProgress);
65
166
  audio.removeEventListener('play', handlePlay);
66
167
  audio.removeEventListener('pause', handlePause);
67
- audio.removeEventListener('timeupdate', handleTimeUpdate);
168
+ audio.removeEventListener('ended', handleEnded);
68
169
  };
69
- }, []);
170
+ }, [duration]);
70
171
  return jsxRuntime.jsxs(material.Stack, {
71
172
  spacing: 1,
72
173
  alignItems: "center",
@@ -74,12 +175,12 @@ var EliceAudioPlayer = function EliceAudioPlayer(_ref) {
74
175
  children: [jsxRuntime.jsx("audio", {
75
176
  ref: audioRef,
76
177
  src: src,
77
- preload: "auto"
178
+ preload: "metadata"
78
179
  }), jsxRuntime.jsx(PlayerButton, {
79
180
  onClick: togglePlay,
80
181
  children: isPlaying ? jsxRuntime.jsx(Pause.default, {}) : jsxRuntime.jsx(Play.default, {})
81
182
  }), jsxRuntime.jsx(material.LinearProgress, {
82
- variant: "determinate",
183
+ variant: isReady ? 'determinate' : 'indeterminate',
83
184
  value: progress,
84
185
  sx: {
85
186
  width: '200px'
@@ -17,10 +17,11 @@ export interface EliceChatProps {
17
17
  onTranscribingChange?: (value: boolean) => void;
18
18
  isLoadingMessage?: boolean;
19
19
  isDisabled?: boolean;
20
+ backgroundImage?: string;
20
21
  CustomAssistantAvatar?: React.ReactNode;
21
22
  }
22
23
  declare const EliceChat: {
23
- ({ placeholder, messages, content, onReset, onSend, onChange, onRecord, onTranscribingChange, setAudioFile, onTransform, isLoadingMessage, CustomAssistantAvatar, isDisabled, height, }: EliceChatProps): import("react/jsx-runtime").JSX.Element;
24
+ ({ placeholder, messages, content, onReset, onSend, onChange, onRecord, onTranscribingChange, setAudioFile, onTransform, isLoadingMessage, CustomAssistantAvatar, isDisabled, backgroundImage, height, }: EliceChatProps): import("react/jsx-runtime").JSX.Element;
24
25
  MessageList({ messages, isLoadingMessage, scrollRef, height, isRecord, setIsRecord, CustomAssistantAvatar, }: {
25
26
  messages: {
26
27
  role: "system" | "user" | "assistant";
@@ -24,55 +24,58 @@ var _styled__default = /*#__PURE__*/_interopDefaultCompat(_styled);
24
24
  function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
25
25
  var StyledChatContainer = /*#__PURE__*/_styled__default.default(material.Stack, {
26
26
  target: "e1i7zt4"
27
- })("position:relative;height:fit-content;max-height:100%;height:", function (_ref) {
27
+ })("position:relative;max-height:100%;height:", function (_ref) {
28
28
  var height = _ref.height;
29
- return height;
29
+ return height !== null && height !== void 0 ? height : 'fit-content';
30
30
  }, ";min-width:30rem;max-width:100%;border:2px solid ", function (_ref2) {
31
31
  var theme = _ref2.theme;
32
32
  return theme.palette.grey[300];
33
- }, ";border-radius:1.5rem;padding:1.5rem;gap:1.75rem;");
33
+ }, ";border-radius:1.5rem;padding:1.5rem;gap:1.75rem;", function (_ref3) {
34
+ var backgroundImage = _ref3.backgroundImage;
35
+ return backgroundImage && "\n background-image: url(".concat(backgroundImage, ");\n background-size: cover;\n background-position: center;\n ");
36
+ }, ";");
34
37
  var StyledScrollBarStack = /*#__PURE__*/_styled__default.default(material.Stack, {
35
38
  target: "e1i7zt3"
36
- })("flex:1;overflow-y:auto;border-radius:1.125rem;padding-right:1rem;::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref3) {
37
- var theme = _ref3.theme;
38
- return theme.palette.grey[200];
39
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref4) {
39
+ })("flex:1;overflow-y:auto;border-radius:1.125rem;padding-right:1rem;::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref4) {
40
40
  var theme = _ref4.theme;
41
- return theme.palette.primary.main;
42
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref5) {
41
+ return theme.palette.grey[200];
42
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref5) {
43
43
  var theme = _ref5.theme;
44
+ return theme.palette.primary.main;
45
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref6) {
46
+ var theme = _ref6.theme;
44
47
  return theme.palette.secondary.main;
45
48
  }, ";}");
46
49
  var StyledInput = /*#__PURE__*/_styled__default.default(material.Input, {
47
50
  target: "e1i7zt2"
48
- })("width:100%;height:100%;border:none!important;background-color:transparent;font-size:1.375rem;font-weight:700;outline:none;resize:none;color:", function (_ref6) {
49
- var theme = _ref6.theme;
50
- return theme.palette.secondary.main;
51
- }, ";::placeholder{color:", function (_ref7) {
51
+ })("width:100%;height:100%;border:none!important;background-color:transparent;font-size:1.375rem;font-weight:700;outline:none;resize:none;color:", function (_ref7) {
52
52
  var theme = _ref7.theme;
53
- return theme.palette.grey[300];
54
- }, ";}::before{border:none;}:hover{::before{border:none;}}::after{border-bottom:none!important;}::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref8) {
53
+ return theme.palette.secondary.main;
54
+ }, ";::placeholder{color:", function (_ref8) {
55
55
  var theme = _ref8.theme;
56
- return theme.palette.grey[200];
57
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref9) {
56
+ return theme.palette.grey[300];
57
+ }, ";}::before{border:none;}:hover{::before{border:none;}}::after{border-bottom:none!important;}::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref9) {
58
58
  var theme = _ref9.theme;
59
- return theme.palette.primary.main;
60
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref10) {
59
+ return theme.palette.grey[200];
60
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref10) {
61
61
  var theme = _ref10.theme;
62
+ return theme.palette.primary.main;
63
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref11) {
64
+ var theme = _ref11.theme;
62
65
  return theme.palette.secondary.main;
63
66
  }, ";}");
64
67
  var StyledMessage = /*#__PURE__*/_styled__default.default(material.Typography, {
65
68
  target: "e1i7zt1"
66
- })("color:", function (_ref11) {
67
- var isAssistant = _ref11.isAssistant,
68
- theme = _ref11.theme;
69
+ })("color:", function (_ref12) {
70
+ var isAssistant = _ref12.isAssistant,
71
+ theme = _ref12.theme;
69
72
  return isAssistant ? theme.palette.text.secondary : theme.palette.secondary.main;
70
- }, ";font-size:1rem;font-weight:", function (_ref12) {
71
- var isAssistant = _ref12.isAssistant;
73
+ }, ";font-size:1rem;font-weight:", function (_ref13) {
74
+ var isAssistant = _ref13.isAssistant;
72
75
  return isAssistant ? 500 : 700;
73
- }, ";background-color:", function (_ref13) {
74
- var isAssistant = _ref13.isAssistant,
75
- theme = _ref13.theme;
76
+ }, ";background-color:", function (_ref14) {
77
+ var isAssistant = _ref14.isAssistant,
78
+ theme = _ref14.theme;
76
79
  return isAssistant ? theme.palette.grey[50] : theme.palette.primary.light;
77
80
  }, ";border-radius:1rem;white-space:pre-wrap;padding:0.75rem;margin-bottom:16px;");
78
81
  var RecordingOverlay = /*#__PURE__*/_styled__default.default("div", {
@@ -85,26 +88,27 @@ var RecordingOverlay = /*#__PURE__*/_styled__default.default("div", {
85
88
  styles: "position:absolute;top:0;left:24px;width:calc(100% - 48px);height:calc(100% - 24px);background-color:rgba(0, 0, 0, 0.4);z-index:999;backdrop-filter:blur(1px);border-radius:0 0 1.125rem 1.125rem",
86
89
  toString: _EMOTION_STRINGIFIED_CSS_ERROR__
87
90
  });
88
- var _EliceChat = function EliceChat(_ref14) {
89
- var _ref14$placeholder = _ref14.placeholder,
90
- placeholder = _ref14$placeholder === void 0 ? "AI와 λŒ€ν™”λ₯Ό μ‹œμž‘ν•΄ λ³΄μ„Έμš”" : _ref14$placeholder,
91
- _ref14$messages = _ref14.messages,
92
- messages = _ref14$messages === void 0 ? [] : _ref14$messages,
93
- _ref14$content = _ref14.content,
94
- content = _ref14$content === void 0 ? "" : _ref14$content,
95
- onReset = _ref14.onReset,
96
- onSend = _ref14.onSend,
97
- _onChange = _ref14.onChange,
98
- onRecord = _ref14.onRecord,
99
- onTranscribingChange = _ref14.onTranscribingChange,
100
- setAudioFile = _ref14.setAudioFile,
101
- onTransform = _ref14.onTransform,
102
- isLoadingMessage = _ref14.isLoadingMessage,
103
- CustomAssistantAvatar = _ref14.CustomAssistantAvatar,
104
- _ref14$isDisabled = _ref14.isDisabled,
105
- isDisabled = _ref14$isDisabled === void 0 ? false : _ref14$isDisabled,
106
- _ref14$height = _ref14.height,
107
- height = _ref14$height === void 0 ? "100%" : _ref14$height;
91
+ var _EliceChat = function EliceChat(_ref15) {
92
+ var _ref15$placeholder = _ref15.placeholder,
93
+ placeholder = _ref15$placeholder === void 0 ? "AI와 λŒ€ν™”λ₯Ό μ‹œμž‘ν•΄ λ³΄μ„Έμš”" : _ref15$placeholder,
94
+ _ref15$messages = _ref15.messages,
95
+ messages = _ref15$messages === void 0 ? [] : _ref15$messages,
96
+ _ref15$content = _ref15.content,
97
+ content = _ref15$content === void 0 ? "" : _ref15$content,
98
+ onReset = _ref15.onReset,
99
+ onSend = _ref15.onSend,
100
+ _onChange = _ref15.onChange,
101
+ onRecord = _ref15.onRecord,
102
+ onTranscribingChange = _ref15.onTranscribingChange,
103
+ setAudioFile = _ref15.setAudioFile,
104
+ onTransform = _ref15.onTransform,
105
+ isLoadingMessage = _ref15.isLoadingMessage,
106
+ CustomAssistantAvatar = _ref15.CustomAssistantAvatar,
107
+ _ref15$isDisabled = _ref15.isDisabled,
108
+ isDisabled = _ref15$isDisabled === void 0 ? false : _ref15$isDisabled,
109
+ backgroundImage = _ref15.backgroundImage,
110
+ _ref15$height = _ref15.height,
111
+ height = _ref15$height === void 0 ? "100%" : _ref15$height;
108
112
  var theme = material.useTheme();
109
113
  var _useState = React.useState(content),
110
114
  _useState2 = _rollupPluginBabelHelpers.slicedToArray(_useState, 2),
@@ -141,6 +145,7 @@ var _EliceChat = function EliceChat(_ref14) {
141
145
  return jsxRuntime.jsxs(StyledChatContainer, {
142
146
  theme: theme,
143
147
  height: height,
148
+ backgroundImage: backgroundImage,
144
149
  children: [jsxRuntime.jsx(_EliceChat.MessageList, {
145
150
  messages: messages,
146
151
  isLoadingMessage: isLoadingMessage,
@@ -168,15 +173,15 @@ var _EliceChat = function EliceChat(_ref14) {
168
173
  });
169
174
  };
170
175
  // βœ… λ©”μ‹œμ§€ 리슀트 μ»΄ν¬λ„ŒνŠΈ
171
- _EliceChat.MessageList = function (_ref15) {
172
- var messages = _ref15.messages,
173
- isLoadingMessage = _ref15.isLoadingMessage,
174
- scrollRef = _ref15.scrollRef,
175
- _ref15$height = _ref15.height,
176
- height = _ref15$height === void 0 ? "100%" : _ref15$height,
177
- isRecord = _ref15.isRecord,
178
- setIsRecord = _ref15.setIsRecord,
179
- CustomAssistantAvatar = _ref15.CustomAssistantAvatar;
176
+ _EliceChat.MessageList = function (_ref16) {
177
+ var messages = _ref16.messages,
178
+ isLoadingMessage = _ref16.isLoadingMessage,
179
+ scrollRef = _ref16.scrollRef,
180
+ _ref16$height = _ref16.height,
181
+ height = _ref16$height === void 0 ? "100%" : _ref16$height,
182
+ isRecord = _ref16.isRecord,
183
+ setIsRecord = _ref16.setIsRecord,
184
+ CustomAssistantAvatar = _ref16.CustomAssistantAvatar;
180
185
  var theme = material.useTheme();
181
186
  return jsxRuntime.jsxs(StyledScrollBarStack, {
182
187
  theme: theme,
@@ -211,19 +216,19 @@ _EliceChat.MessageList = function (_ref15) {
211
216
  })]
212
217
  });
213
218
  };
214
- _EliceChat.InputArea = function (_ref16) {
215
- var placeHolder = _ref16.placeHolder,
216
- value = _ref16.value,
217
- isDisabled = _ref16.isDisabled,
218
- onChange = _ref16.onChange,
219
- onSend = _ref16.onSend,
220
- onReset = _ref16.onReset,
221
- onRecord = _ref16.onRecord,
222
- onTranscribingChange = _ref16.onTranscribingChange,
223
- setAudioFile = _ref16.setAudioFile,
224
- onTransform = _ref16.onTransform,
225
- setIsRecord = _ref16.setIsRecord,
226
- isRecord = _ref16.isRecord;
219
+ _EliceChat.InputArea = function (_ref17) {
220
+ var placeHolder = _ref17.placeHolder,
221
+ value = _ref17.value,
222
+ isDisabled = _ref17.isDisabled,
223
+ onChange = _ref17.onChange,
224
+ onSend = _ref17.onSend,
225
+ onReset = _ref17.onReset,
226
+ onRecord = _ref17.onRecord,
227
+ onTranscribingChange = _ref17.onTranscribingChange,
228
+ setAudioFile = _ref17.setAudioFile,
229
+ onTransform = _ref17.onTransform,
230
+ setIsRecord = _ref17.setIsRecord,
231
+ isRecord = _ref17.isRecord;
227
232
  var _a;
228
233
  var theme = material.useTheme();
229
234
  return jsxRuntime.jsx(material.Stack, {
@@ -1,5 +1,7 @@
1
1
  export interface EliceAudioPlayerProps {
2
2
  src: string;
3
+ mimeType?: string;
4
+ onFileLoaded?: (file: File) => void;
3
5
  }
4
- declare const EliceAudioPlayer: ({ src }: EliceAudioPlayerProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const EliceAudioPlayer: ({ src, mimeType, onFileLoaded, }: EliceAudioPlayerProps) => import("react/jsx-runtime").JSX.Element;
5
7
  export default EliceAudioPlayer;
@@ -1,4 +1,4 @@
1
- import { slicedToArray as _slicedToArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { slicedToArray as _slicedToArray, asyncToGenerator as _asyncToGenerator, regeneratorRuntime as _regeneratorRuntime } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import _styled from '@emotion/styled/base';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
  import { useRef, useState, useEffect } from 'react';
@@ -17,8 +17,47 @@ var PlayerButton = /*#__PURE__*/_styled("button", {
17
17
  styles: "display:flex;background-color:transparent!important;border:none",
18
18
  toString: _EMOTION_STRINGIFIED_CSS_ERROR__
19
19
  });
20
- var EliceAudioPlayer = function EliceAudioPlayer(_ref) {
21
- var src = _ref.src;
20
+ var getAccurateDuration = /*#__PURE__*/function () {
21
+ var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(src) {
22
+ var response, arrayBuffer, audioCtx, audioBuffer;
23
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
24
+ while (1) switch (_context.prev = _context.next) {
25
+ case 0:
26
+ _context.prev = 0;
27
+ _context.next = 3;
28
+ return fetch(src);
29
+ case 3:
30
+ response = _context.sent;
31
+ _context.next = 6;
32
+ return response.arrayBuffer();
33
+ case 6:
34
+ arrayBuffer = _context.sent;
35
+ audioCtx = new AudioContext();
36
+ _context.next = 10;
37
+ return audioCtx.decodeAudioData(arrayBuffer);
38
+ case 10:
39
+ audioBuffer = _context.sent;
40
+ return _context.abrupt("return", audioBuffer.duration);
41
+ case 14:
42
+ _context.prev = 14;
43
+ _context.t0 = _context["catch"](0);
44
+ console.error('🎧 decodeAudioData μ‹€νŒ¨:', _context.t0);
45
+ return _context.abrupt("return", null);
46
+ case 18:
47
+ case "end":
48
+ return _context.stop();
49
+ }
50
+ }, _callee, null, [[0, 14]]);
51
+ }));
52
+ return function getAccurateDuration(_x) {
53
+ return _ref.apply(this, arguments);
54
+ };
55
+ }();
56
+ var EliceAudioPlayer = function EliceAudioPlayer(_ref2) {
57
+ var src = _ref2.src,
58
+ _ref2$mimeType = _ref2.mimeType,
59
+ mimeType = _ref2$mimeType === void 0 ? 'audio/mp3' : _ref2$mimeType,
60
+ onFileLoaded = _ref2.onFileLoaded;
22
61
  var audioRef = useRef(null);
23
62
  var _useState = useState(false),
24
63
  _useState2 = _slicedToArray(_useState, 2),
@@ -28,37 +67,99 @@ var EliceAudioPlayer = function EliceAudioPlayer(_ref) {
28
67
  _useState4 = _slicedToArray(_useState3, 2),
29
68
  progress = _useState4[0],
30
69
  setProgress = _useState4[1];
70
+ var _useState5 = useState(false),
71
+ _useState6 = _slicedToArray(_useState5, 2),
72
+ isReady = _useState6[0],
73
+ setIsReady = _useState6[1];
74
+ var _useState7 = useState(0),
75
+ _useState8 = _slicedToArray(_useState7, 2),
76
+ duration = _useState8[0],
77
+ setDuration = _useState8[1];
78
+ useEffect(function () {
79
+ var fetchAndDecode = /*#__PURE__*/function () {
80
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
81
+ var response, blob, filename, file, _duration;
82
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
83
+ while (1) switch (_context2.prev = _context2.next) {
84
+ case 0:
85
+ _context2.prev = 0;
86
+ _context2.next = 3;
87
+ return fetch(src);
88
+ case 3:
89
+ response = _context2.sent;
90
+ _context2.next = 6;
91
+ return response.blob();
92
+ case 6:
93
+ blob = _context2.sent;
94
+ filename = src.split('/').pop() || 'audio.mp3';
95
+ file = new File([blob], filename, {
96
+ type: blob.type || mimeType
97
+ });
98
+ onFileLoaded === null || onFileLoaded === void 0 ? void 0 : onFileLoaded(file);
99
+ _context2.next = 12;
100
+ return getAccurateDuration(src);
101
+ case 12:
102
+ _duration = _context2.sent;
103
+ if (_duration && isFinite(_duration)) {
104
+ setDuration(_duration);
105
+ setIsReady(true);
106
+ }
107
+ _context2.next = 19;
108
+ break;
109
+ case 16:
110
+ _context2.prev = 16;
111
+ _context2.t0 = _context2["catch"](0);
112
+ console.error('❌ Fetch or decode μ‹€νŒ¨:', _context2.t0);
113
+ case 19:
114
+ case "end":
115
+ return _context2.stop();
116
+ }
117
+ }, _callee2, null, [[0, 16]]);
118
+ }));
119
+ return function fetchAndDecode() {
120
+ return _ref3.apply(this, arguments);
121
+ };
122
+ }();
123
+ if (src) fetchAndDecode();
124
+ }, [src, mimeType, onFileLoaded]);
31
125
  var togglePlay = function togglePlay() {
32
126
  var audio = audioRef.current;
33
127
  if (!audio) return;
34
- if (isPlaying) {
35
- audio.pause();
36
- } else {
37
- audio.play();
38
- }
128
+ isPlaying ? audio.pause() : audio.play();
39
129
  };
40
130
  useEffect(function () {
41
131
  var audio = audioRef.current;
42
132
  if (!audio) return;
133
+ var updateProgress = function updateProgress() {
134
+ if (duration > 0) {
135
+ var percent = audio.currentTime / duration * 100;
136
+ setProgress(percent);
137
+ }
138
+ };
43
139
  var handlePlay = function handlePlay() {
44
140
  return setIsPlaying(true);
45
141
  };
46
142
  var handlePause = function handlePause() {
47
143
  return setIsPlaying(false);
48
144
  };
49
- var handleTimeUpdate = function handleTimeUpdate() {
50
- var percent = audio.currentTime / audio.duration * 100;
51
- setProgress(percent);
145
+ var handleEnded = function handleEnded() {
146
+ setProgress(100);
147
+ setTimeout(function () {
148
+ setProgress(0);
149
+ setIsPlaying(false);
150
+ }, 300);
52
151
  };
152
+ audio.addEventListener('timeupdate', updateProgress);
53
153
  audio.addEventListener('play', handlePlay);
54
154
  audio.addEventListener('pause', handlePause);
55
- audio.addEventListener('timeupdate', handleTimeUpdate);
155
+ audio.addEventListener('ended', handleEnded);
56
156
  return function () {
157
+ audio.removeEventListener('timeupdate', updateProgress);
57
158
  audio.removeEventListener('play', handlePlay);
58
159
  audio.removeEventListener('pause', handlePause);
59
- audio.removeEventListener('timeupdate', handleTimeUpdate);
160
+ audio.removeEventListener('ended', handleEnded);
60
161
  };
61
- }, []);
162
+ }, [duration]);
62
163
  return jsxs(Stack, {
63
164
  spacing: 1,
64
165
  alignItems: "center",
@@ -66,12 +167,12 @@ var EliceAudioPlayer = function EliceAudioPlayer(_ref) {
66
167
  children: [jsx("audio", {
67
168
  ref: audioRef,
68
169
  src: src,
69
- preload: "auto"
170
+ preload: "metadata"
70
171
  }), jsx(PlayerButton, {
71
172
  onClick: togglePlay,
72
173
  children: isPlaying ? jsx(PauseIcon, {}) : jsx(PlayIcon, {})
73
174
  }), jsx(LinearProgress, {
74
- variant: "determinate",
175
+ variant: isReady ? 'determinate' : 'indeterminate',
75
176
  value: progress,
76
177
  sx: {
77
178
  width: '200px'
@@ -17,10 +17,11 @@ export interface EliceChatProps {
17
17
  onTranscribingChange?: (value: boolean) => void;
18
18
  isLoadingMessage?: boolean;
19
19
  isDisabled?: boolean;
20
+ backgroundImage?: string;
20
21
  CustomAssistantAvatar?: React.ReactNode;
21
22
  }
22
23
  declare const EliceChat: {
23
- ({ placeholder, messages, content, onReset, onSend, onChange, onRecord, onTranscribingChange, setAudioFile, onTransform, isLoadingMessage, CustomAssistantAvatar, isDisabled, height, }: EliceChatProps): import("react/jsx-runtime").JSX.Element;
24
+ ({ placeholder, messages, content, onReset, onSend, onChange, onRecord, onTranscribingChange, setAudioFile, onTransform, isLoadingMessage, CustomAssistantAvatar, isDisabled, backgroundImage, height, }: EliceChatProps): import("react/jsx-runtime").JSX.Element;
24
25
  MessageList({ messages, isLoadingMessage, scrollRef, height, isRecord, setIsRecord, CustomAssistantAvatar, }: {
25
26
  messages: {
26
27
  role: "system" | "user" | "assistant";
@@ -15,55 +15,58 @@ import Send from '../../icons/Send.js';
15
15
  function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
16
16
  var StyledChatContainer = /*#__PURE__*/_styled(Stack, {
17
17
  target: "e1i7zt4"
18
- })("position:relative;height:fit-content;max-height:100%;height:", function (_ref) {
18
+ })("position:relative;max-height:100%;height:", function (_ref) {
19
19
  var height = _ref.height;
20
- return height;
20
+ return height !== null && height !== void 0 ? height : 'fit-content';
21
21
  }, ";min-width:30rem;max-width:100%;border:2px solid ", function (_ref2) {
22
22
  var theme = _ref2.theme;
23
23
  return theme.palette.grey[300];
24
- }, ";border-radius:1.5rem;padding:1.5rem;gap:1.75rem;");
24
+ }, ";border-radius:1.5rem;padding:1.5rem;gap:1.75rem;", function (_ref3) {
25
+ var backgroundImage = _ref3.backgroundImage;
26
+ return backgroundImage && "\n background-image: url(".concat(backgroundImage, ");\n background-size: cover;\n background-position: center;\n ");
27
+ }, ";");
25
28
  var StyledScrollBarStack = /*#__PURE__*/_styled(Stack, {
26
29
  target: "e1i7zt3"
27
- })("flex:1;overflow-y:auto;border-radius:1.125rem;padding-right:1rem;::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref3) {
28
- var theme = _ref3.theme;
29
- return theme.palette.grey[200];
30
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref4) {
30
+ })("flex:1;overflow-y:auto;border-radius:1.125rem;padding-right:1rem;::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref4) {
31
31
  var theme = _ref4.theme;
32
- return theme.palette.primary.main;
33
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref5) {
32
+ return theme.palette.grey[200];
33
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref5) {
34
34
  var theme = _ref5.theme;
35
+ return theme.palette.primary.main;
36
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref6) {
37
+ var theme = _ref6.theme;
35
38
  return theme.palette.secondary.main;
36
39
  }, ";}");
37
40
  var StyledInput = /*#__PURE__*/_styled(Input, {
38
41
  target: "e1i7zt2"
39
- })("width:100%;height:100%;border:none!important;background-color:transparent;font-size:1.375rem;font-weight:700;outline:none;resize:none;color:", function (_ref6) {
40
- var theme = _ref6.theme;
41
- return theme.palette.secondary.main;
42
- }, ";::placeholder{color:", function (_ref7) {
42
+ })("width:100%;height:100%;border:none!important;background-color:transparent;font-size:1.375rem;font-weight:700;outline:none;resize:none;color:", function (_ref7) {
43
43
  var theme = _ref7.theme;
44
- return theme.palette.grey[300];
45
- }, ";}::before{border:none;}:hover{::before{border:none;}}::after{border-bottom:none!important;}::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref8) {
44
+ return theme.palette.secondary.main;
45
+ }, ";::placeholder{color:", function (_ref8) {
46
46
  var theme = _ref8.theme;
47
- return theme.palette.grey[200];
48
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref9) {
47
+ return theme.palette.grey[300];
48
+ }, ";}::before{border:none;}:hover{::before{border:none;}}::after{border-bottom:none!important;}::-webkit-scrollbar{width:0.25rem;}::-webkit-scrollbar-track{background:", function (_ref9) {
49
49
  var theme = _ref9.theme;
50
- return theme.palette.primary.main;
51
- }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref10) {
50
+ return theme.palette.grey[200];
51
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb{background:", function (_ref10) {
52
52
  var theme = _ref10.theme;
53
+ return theme.palette.primary.main;
54
+ }, ";border-radius:0.5rem;}::-webkit-scrollbar-thumb:hover{background:", function (_ref11) {
55
+ var theme = _ref11.theme;
53
56
  return theme.palette.secondary.main;
54
57
  }, ";}");
55
58
  var StyledMessage = /*#__PURE__*/_styled(Typography, {
56
59
  target: "e1i7zt1"
57
- })("color:", function (_ref11) {
58
- var isAssistant = _ref11.isAssistant,
59
- theme = _ref11.theme;
60
+ })("color:", function (_ref12) {
61
+ var isAssistant = _ref12.isAssistant,
62
+ theme = _ref12.theme;
60
63
  return isAssistant ? theme.palette.text.secondary : theme.palette.secondary.main;
61
- }, ";font-size:1rem;font-weight:", function (_ref12) {
62
- var isAssistant = _ref12.isAssistant;
64
+ }, ";font-size:1rem;font-weight:", function (_ref13) {
65
+ var isAssistant = _ref13.isAssistant;
63
66
  return isAssistant ? 500 : 700;
64
- }, ";background-color:", function (_ref13) {
65
- var isAssistant = _ref13.isAssistant,
66
- theme = _ref13.theme;
67
+ }, ";background-color:", function (_ref14) {
68
+ var isAssistant = _ref14.isAssistant,
69
+ theme = _ref14.theme;
67
70
  return isAssistant ? theme.palette.grey[50] : theme.palette.primary.light;
68
71
  }, ";border-radius:1rem;white-space:pre-wrap;padding:0.75rem;margin-bottom:16px;");
69
72
  var RecordingOverlay = /*#__PURE__*/_styled("div", {
@@ -76,26 +79,27 @@ var RecordingOverlay = /*#__PURE__*/_styled("div", {
76
79
  styles: "position:absolute;top:0;left:24px;width:calc(100% - 48px);height:calc(100% - 24px);background-color:rgba(0, 0, 0, 0.4);z-index:999;backdrop-filter:blur(1px);border-radius:0 0 1.125rem 1.125rem",
77
80
  toString: _EMOTION_STRINGIFIED_CSS_ERROR__
78
81
  });
79
- var _EliceChat = function EliceChat(_ref14) {
80
- var _ref14$placeholder = _ref14.placeholder,
81
- placeholder = _ref14$placeholder === void 0 ? "AI와 λŒ€ν™”λ₯Ό μ‹œμž‘ν•΄ λ³΄μ„Έμš”" : _ref14$placeholder,
82
- _ref14$messages = _ref14.messages,
83
- messages = _ref14$messages === void 0 ? [] : _ref14$messages,
84
- _ref14$content = _ref14.content,
85
- content = _ref14$content === void 0 ? "" : _ref14$content,
86
- onReset = _ref14.onReset,
87
- onSend = _ref14.onSend,
88
- _onChange = _ref14.onChange,
89
- onRecord = _ref14.onRecord,
90
- onTranscribingChange = _ref14.onTranscribingChange,
91
- setAudioFile = _ref14.setAudioFile,
92
- onTransform = _ref14.onTransform,
93
- isLoadingMessage = _ref14.isLoadingMessage,
94
- CustomAssistantAvatar = _ref14.CustomAssistantAvatar,
95
- _ref14$isDisabled = _ref14.isDisabled,
96
- isDisabled = _ref14$isDisabled === void 0 ? false : _ref14$isDisabled,
97
- _ref14$height = _ref14.height,
98
- height = _ref14$height === void 0 ? "100%" : _ref14$height;
82
+ var _EliceChat = function EliceChat(_ref15) {
83
+ var _ref15$placeholder = _ref15.placeholder,
84
+ placeholder = _ref15$placeholder === void 0 ? "AI와 λŒ€ν™”λ₯Ό μ‹œμž‘ν•΄ λ³΄μ„Έμš”" : _ref15$placeholder,
85
+ _ref15$messages = _ref15.messages,
86
+ messages = _ref15$messages === void 0 ? [] : _ref15$messages,
87
+ _ref15$content = _ref15.content,
88
+ content = _ref15$content === void 0 ? "" : _ref15$content,
89
+ onReset = _ref15.onReset,
90
+ onSend = _ref15.onSend,
91
+ _onChange = _ref15.onChange,
92
+ onRecord = _ref15.onRecord,
93
+ onTranscribingChange = _ref15.onTranscribingChange,
94
+ setAudioFile = _ref15.setAudioFile,
95
+ onTransform = _ref15.onTransform,
96
+ isLoadingMessage = _ref15.isLoadingMessage,
97
+ CustomAssistantAvatar = _ref15.CustomAssistantAvatar,
98
+ _ref15$isDisabled = _ref15.isDisabled,
99
+ isDisabled = _ref15$isDisabled === void 0 ? false : _ref15$isDisabled,
100
+ backgroundImage = _ref15.backgroundImage,
101
+ _ref15$height = _ref15.height,
102
+ height = _ref15$height === void 0 ? "100%" : _ref15$height;
99
103
  var theme = useTheme();
100
104
  var _useState = useState(content),
101
105
  _useState2 = _slicedToArray(_useState, 2),
@@ -132,6 +136,7 @@ var _EliceChat = function EliceChat(_ref14) {
132
136
  return jsxs(StyledChatContainer, {
133
137
  theme: theme,
134
138
  height: height,
139
+ backgroundImage: backgroundImage,
135
140
  children: [jsx(_EliceChat.MessageList, {
136
141
  messages: messages,
137
142
  isLoadingMessage: isLoadingMessage,
@@ -159,15 +164,15 @@ var _EliceChat = function EliceChat(_ref14) {
159
164
  });
160
165
  };
161
166
  // βœ… λ©”μ‹œμ§€ 리슀트 μ»΄ν¬λ„ŒνŠΈ
162
- _EliceChat.MessageList = function (_ref15) {
163
- var messages = _ref15.messages,
164
- isLoadingMessage = _ref15.isLoadingMessage,
165
- scrollRef = _ref15.scrollRef,
166
- _ref15$height = _ref15.height,
167
- height = _ref15$height === void 0 ? "100%" : _ref15$height,
168
- isRecord = _ref15.isRecord,
169
- setIsRecord = _ref15.setIsRecord,
170
- CustomAssistantAvatar = _ref15.CustomAssistantAvatar;
167
+ _EliceChat.MessageList = function (_ref16) {
168
+ var messages = _ref16.messages,
169
+ isLoadingMessage = _ref16.isLoadingMessage,
170
+ scrollRef = _ref16.scrollRef,
171
+ _ref16$height = _ref16.height,
172
+ height = _ref16$height === void 0 ? "100%" : _ref16$height,
173
+ isRecord = _ref16.isRecord,
174
+ setIsRecord = _ref16.setIsRecord,
175
+ CustomAssistantAvatar = _ref16.CustomAssistantAvatar;
171
176
  var theme = useTheme();
172
177
  return jsxs(StyledScrollBarStack, {
173
178
  theme: theme,
@@ -202,19 +207,19 @@ _EliceChat.MessageList = function (_ref15) {
202
207
  })]
203
208
  });
204
209
  };
205
- _EliceChat.InputArea = function (_ref16) {
206
- var placeHolder = _ref16.placeHolder,
207
- value = _ref16.value,
208
- isDisabled = _ref16.isDisabled,
209
- onChange = _ref16.onChange,
210
- onSend = _ref16.onSend,
211
- onReset = _ref16.onReset,
212
- onRecord = _ref16.onRecord,
213
- onTranscribingChange = _ref16.onTranscribingChange,
214
- setAudioFile = _ref16.setAudioFile,
215
- onTransform = _ref16.onTransform,
216
- setIsRecord = _ref16.setIsRecord,
217
- isRecord = _ref16.isRecord;
210
+ _EliceChat.InputArea = function (_ref17) {
211
+ var placeHolder = _ref17.placeHolder,
212
+ value = _ref17.value,
213
+ isDisabled = _ref17.isDisabled,
214
+ onChange = _ref17.onChange,
215
+ onSend = _ref17.onSend,
216
+ onReset = _ref17.onReset,
217
+ onRecord = _ref17.onRecord,
218
+ onTranscribingChange = _ref17.onTranscribingChange,
219
+ setAudioFile = _ref17.setAudioFile,
220
+ onTransform = _ref17.onTransform,
221
+ setIsRecord = _ref17.setIsRecord,
222
+ isRecord = _ref17.isRecord;
218
223
  var _a;
219
224
  var theme = useTheme();
220
225
  return jsx(Stack, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elicecontents/content-ui",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "A set of UI components for creating content of Elice",
5
5
  "author": "Elice <contact@elice.io>",
6
6
  "license": "UNLICENSED",