@gentomiyano/optimized-web-audio-player 0.2.2 → 0.2.3
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 +14 -0
- package/dist/react/index.js +212 -159
- package/dist/react/index.js.map +1 -1
- package/dist/ui/index.js +151 -109
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/player-views.css +37 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,20 @@ The public npm registry, scoped package name, and release workflow are fixed.
|
|
|
39
39
|
Initial npm publication still requires the scope owner's authentication.
|
|
40
40
|
Release and consumer pinning rules are documented in `docs/RELEASING.md`.
|
|
41
41
|
|
|
42
|
+
## PLAYER-UI-CONTRACT-01 Bound Compact
|
|
43
|
+
|
|
44
|
+
Version 0.2.3 makes the occurrence-bound inline Player use the standard
|
|
45
|
+
Compact visual implementation. `CompactPlayer` and `BoundCompactPlayerView`
|
|
46
|
+
now share one surface, metadata grid, waveform signal, seek overlay, tokens,
|
|
47
|
+
and container-query behavior; the former `player-bound-compact` surface and
|
|
48
|
+
its separate active panel are removed.
|
|
49
|
+
|
|
50
|
+
The React API and playback semantics are unchanged. An inactive occurrence
|
|
51
|
+
shows its own metadata at zero and activates its context only on Play. The
|
|
52
|
+
active occurrence exposes global Play / Pause, time, and seek while the
|
|
53
|
+
existing Global Mini continues to use the same Store and audio element. See
|
|
54
|
+
`docs/PLAYER-UI-CONTRACT-01-BOUND-COMPACT.md`.
|
|
55
|
+
|
|
42
56
|
## WP-04.4 SSR-transparent Provider
|
|
43
57
|
|
|
44
58
|
Version 0.2.2 renders consumer children inside the same Player Context from
|
package/dist/react/index.js
CHANGED
|
@@ -2951,100 +2951,6 @@ function IconButton({
|
|
|
2951
2951
|
}
|
|
2952
2952
|
);
|
|
2953
2953
|
}
|
|
2954
|
-
function SeekBar({
|
|
2955
|
-
canSeek,
|
|
2956
|
-
className,
|
|
2957
|
-
commitMode,
|
|
2958
|
-
currentTimeSec,
|
|
2959
|
-
durationSec,
|
|
2960
|
-
label = "Seek",
|
|
2961
|
-
onSeek,
|
|
2962
|
-
status
|
|
2963
|
-
}) {
|
|
2964
|
-
const duration = durationSec !== null && Number.isFinite(durationSec) && durationSec > 0 ? durationSec : 0;
|
|
2965
|
-
const disabled = !canSeek || duration === 0 || status === "loading";
|
|
2966
|
-
const safeCurrentTime = clamp(currentTimeSec, 0, duration);
|
|
2967
|
-
const [previewTime, setPreviewTime] = useState(safeCurrentTime);
|
|
2968
|
-
const previewProgress = duration === 0 ? 0 : clamp(previewTime / duration, 0, 1) * 100;
|
|
2969
|
-
const isAdjusting = useRef(false);
|
|
2970
|
-
const lastCommitted = useRef(null);
|
|
2971
|
-
useEffect(() => {
|
|
2972
|
-
if (!isAdjusting.current) {
|
|
2973
|
-
setPreviewTime(safeCurrentTime);
|
|
2974
|
-
}
|
|
2975
|
-
}, [safeCurrentTime]);
|
|
2976
|
-
function updatePreview(value) {
|
|
2977
|
-
const nextValue = clamp(value, 0, duration);
|
|
2978
|
-
isAdjusting.current = true;
|
|
2979
|
-
setPreviewTime(nextValue);
|
|
2980
|
-
if (commitMode === "live") {
|
|
2981
|
-
onSeek(nextValue);
|
|
2982
|
-
lastCommitted.current = nextValue;
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
function commitPreview(value = previewTime) {
|
|
2986
|
-
const nextValue = clamp(value, 0, duration);
|
|
2987
|
-
if (disabled || !isAdjusting.current || commitMode === "live" && lastCommitted.current === nextValue) {
|
|
2988
|
-
isAdjusting.current = false;
|
|
2989
|
-
return;
|
|
2990
|
-
}
|
|
2991
|
-
onSeek(nextValue);
|
|
2992
|
-
lastCommitted.current = nextValue;
|
|
2993
|
-
isAdjusting.current = false;
|
|
2994
|
-
}
|
|
2995
|
-
function cancelPreview() {
|
|
2996
|
-
isAdjusting.current = false;
|
|
2997
|
-
lastCommitted.current = null;
|
|
2998
|
-
setPreviewTime(safeCurrentTime);
|
|
2999
|
-
}
|
|
3000
|
-
return /* @__PURE__ */ jsxs(
|
|
3001
|
-
"label",
|
|
3002
|
-
{
|
|
3003
|
-
className: ["player-seek", className].filter(Boolean).join(" "),
|
|
3004
|
-
"data-disabled": disabled ? "true" : "false",
|
|
3005
|
-
children: [
|
|
3006
|
-
/* @__PURE__ */ jsx("span", { className: "player-visually-hidden", children: label }),
|
|
3007
|
-
/* @__PURE__ */ jsx(
|
|
3008
|
-
"span",
|
|
3009
|
-
{
|
|
3010
|
-
"aria-hidden": "true",
|
|
3011
|
-
className: "player-seek__progress",
|
|
3012
|
-
style: { width: `${String(disabled ? 0 : previewProgress)}%` }
|
|
3013
|
-
}
|
|
3014
|
-
),
|
|
3015
|
-
/* @__PURE__ */ jsx(
|
|
3016
|
-
"input",
|
|
3017
|
-
{
|
|
3018
|
-
"aria-label": label,
|
|
3019
|
-
"aria-valuetext": formatTimeAria(previewTime),
|
|
3020
|
-
disabled,
|
|
3021
|
-
max: duration || 1,
|
|
3022
|
-
min: 0,
|
|
3023
|
-
onBlur: (event) => {
|
|
3024
|
-
commitPreview(Number(event.currentTarget.value));
|
|
3025
|
-
},
|
|
3026
|
-
onChange: (event) => {
|
|
3027
|
-
updatePreview(Number(event.currentTarget.value));
|
|
3028
|
-
},
|
|
3029
|
-
onKeyUp: (event) => {
|
|
3030
|
-
commitPreview(Number(event.currentTarget.value));
|
|
3031
|
-
},
|
|
3032
|
-
onPointerDown: () => {
|
|
3033
|
-
isAdjusting.current = true;
|
|
3034
|
-
},
|
|
3035
|
-
onPointerCancel: cancelPreview,
|
|
3036
|
-
onPointerUp: (event) => {
|
|
3037
|
-
commitPreview(Number(event.currentTarget.value));
|
|
3038
|
-
},
|
|
3039
|
-
step: 0.1,
|
|
3040
|
-
type: "range",
|
|
3041
|
-
value: disabled ? 0 : previewTime
|
|
3042
|
-
}
|
|
3043
|
-
)
|
|
3044
|
-
]
|
|
3045
|
-
}
|
|
3046
|
-
);
|
|
3047
|
-
}
|
|
3048
2954
|
var FALLBACK_PEAKS = [
|
|
3049
2955
|
0.16,
|
|
3050
2956
|
0.24,
|
|
@@ -3141,6 +3047,182 @@ function Waveform({
|
|
|
3141
3047
|
}
|
|
3142
3048
|
);
|
|
3143
3049
|
}
|
|
3050
|
+
function CompactPlayerLayout({
|
|
3051
|
+
appearance,
|
|
3052
|
+
className,
|
|
3053
|
+
contextId,
|
|
3054
|
+
contextMode,
|
|
3055
|
+
currentTimeSec,
|
|
3056
|
+
durationSec,
|
|
3057
|
+
errorNotice,
|
|
3058
|
+
isActive,
|
|
3059
|
+
isPlaying,
|
|
3060
|
+
item,
|
|
3061
|
+
label,
|
|
3062
|
+
primaryControl,
|
|
3063
|
+
queueItemId,
|
|
3064
|
+
runtimeStatus,
|
|
3065
|
+
seekControl,
|
|
3066
|
+
status,
|
|
3067
|
+
trailingControl,
|
|
3068
|
+
waveformOpacity,
|
|
3069
|
+
waveformPlayedStateEnabled
|
|
3070
|
+
}) {
|
|
3071
|
+
const progress = durationSec === null || durationSec <= 0 ? 0 : currentTimeSec / durationSec;
|
|
3072
|
+
return /* @__PURE__ */ jsxs(
|
|
3073
|
+
PlayerSurface,
|
|
3074
|
+
{
|
|
3075
|
+
appearance,
|
|
3076
|
+
className: ["player-compact", className].filter(Boolean).join(" "),
|
|
3077
|
+
label,
|
|
3078
|
+
children: [
|
|
3079
|
+
/* @__PURE__ */ jsxs(
|
|
3080
|
+
"div",
|
|
3081
|
+
{
|
|
3082
|
+
className: "player-compact__main",
|
|
3083
|
+
...isActive === void 0 ? {} : { "data-active": isActive ? "true" : "false" },
|
|
3084
|
+
"data-has-status": status === void 0 ? "false" : "true",
|
|
3085
|
+
"data-has-trailing-control": trailingControl === void 0 ? "false" : "true",
|
|
3086
|
+
"data-playback-context-id": contextId,
|
|
3087
|
+
"data-playback-context-mode": contextMode,
|
|
3088
|
+
"data-player-runtime-status": runtimeStatus,
|
|
3089
|
+
"data-queue-item-id": queueItemId,
|
|
3090
|
+
children: [
|
|
3091
|
+
primaryControl,
|
|
3092
|
+
/* @__PURE__ */ jsx(Artwork, { className: "player-compact__artwork", item }),
|
|
3093
|
+
/* @__PURE__ */ jsx(TrackMetadata, { item, scrollTitle: isPlaying }),
|
|
3094
|
+
/* @__PURE__ */ jsxs("div", { className: "player-compact__signal", children: [
|
|
3095
|
+
status,
|
|
3096
|
+
/* @__PURE__ */ jsxs(
|
|
3097
|
+
"div",
|
|
3098
|
+
{
|
|
3099
|
+
className: "player-compact__scrubber",
|
|
3100
|
+
"data-seek-enabled": seekControl === void 0 ? "false" : "true",
|
|
3101
|
+
children: [
|
|
3102
|
+
/* @__PURE__ */ jsx(
|
|
3103
|
+
Waveform,
|
|
3104
|
+
{
|
|
3105
|
+
opacity: waveformOpacity,
|
|
3106
|
+
playedStateEnabled: waveformPlayedStateEnabled,
|
|
3107
|
+
progress,
|
|
3108
|
+
waveform: item?.waveform
|
|
3109
|
+
}
|
|
3110
|
+
),
|
|
3111
|
+
seekControl
|
|
3112
|
+
]
|
|
3113
|
+
}
|
|
3114
|
+
),
|
|
3115
|
+
/* @__PURE__ */ jsx(
|
|
3116
|
+
TimeReadout,
|
|
3117
|
+
{
|
|
3118
|
+
currentTimeSec,
|
|
3119
|
+
durationSec
|
|
3120
|
+
}
|
|
3121
|
+
)
|
|
3122
|
+
] }),
|
|
3123
|
+
trailingControl
|
|
3124
|
+
]
|
|
3125
|
+
}
|
|
3126
|
+
),
|
|
3127
|
+
errorNotice
|
|
3128
|
+
]
|
|
3129
|
+
}
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
3132
|
+
function SeekBar({
|
|
3133
|
+
canSeek,
|
|
3134
|
+
className,
|
|
3135
|
+
commitMode,
|
|
3136
|
+
currentTimeSec,
|
|
3137
|
+
durationSec,
|
|
3138
|
+
label = "Seek",
|
|
3139
|
+
onSeek,
|
|
3140
|
+
status
|
|
3141
|
+
}) {
|
|
3142
|
+
const duration = durationSec !== null && Number.isFinite(durationSec) && durationSec > 0 ? durationSec : 0;
|
|
3143
|
+
const disabled = !canSeek || duration === 0 || status === "loading";
|
|
3144
|
+
const safeCurrentTime = clamp(currentTimeSec, 0, duration);
|
|
3145
|
+
const [previewTime, setPreviewTime] = useState(safeCurrentTime);
|
|
3146
|
+
const previewProgress = duration === 0 ? 0 : clamp(previewTime / duration, 0, 1) * 100;
|
|
3147
|
+
const isAdjusting = useRef(false);
|
|
3148
|
+
const lastCommitted = useRef(null);
|
|
3149
|
+
useEffect(() => {
|
|
3150
|
+
if (!isAdjusting.current) {
|
|
3151
|
+
setPreviewTime(safeCurrentTime);
|
|
3152
|
+
}
|
|
3153
|
+
}, [safeCurrentTime]);
|
|
3154
|
+
function updatePreview(value) {
|
|
3155
|
+
const nextValue = clamp(value, 0, duration);
|
|
3156
|
+
isAdjusting.current = true;
|
|
3157
|
+
setPreviewTime(nextValue);
|
|
3158
|
+
if (commitMode === "live") {
|
|
3159
|
+
onSeek(nextValue);
|
|
3160
|
+
lastCommitted.current = nextValue;
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
function commitPreview(value = previewTime) {
|
|
3164
|
+
const nextValue = clamp(value, 0, duration);
|
|
3165
|
+
if (disabled || !isAdjusting.current || commitMode === "live" && lastCommitted.current === nextValue) {
|
|
3166
|
+
isAdjusting.current = false;
|
|
3167
|
+
return;
|
|
3168
|
+
}
|
|
3169
|
+
onSeek(nextValue);
|
|
3170
|
+
lastCommitted.current = nextValue;
|
|
3171
|
+
isAdjusting.current = false;
|
|
3172
|
+
}
|
|
3173
|
+
function cancelPreview() {
|
|
3174
|
+
isAdjusting.current = false;
|
|
3175
|
+
lastCommitted.current = null;
|
|
3176
|
+
setPreviewTime(safeCurrentTime);
|
|
3177
|
+
}
|
|
3178
|
+
return /* @__PURE__ */ jsxs(
|
|
3179
|
+
"label",
|
|
3180
|
+
{
|
|
3181
|
+
className: ["player-seek", className].filter(Boolean).join(" "),
|
|
3182
|
+
"data-disabled": disabled ? "true" : "false",
|
|
3183
|
+
children: [
|
|
3184
|
+
/* @__PURE__ */ jsx("span", { className: "player-visually-hidden", children: label }),
|
|
3185
|
+
/* @__PURE__ */ jsx(
|
|
3186
|
+
"span",
|
|
3187
|
+
{
|
|
3188
|
+
"aria-hidden": "true",
|
|
3189
|
+
className: "player-seek__progress",
|
|
3190
|
+
style: { width: `${String(disabled ? 0 : previewProgress)}%` }
|
|
3191
|
+
}
|
|
3192
|
+
),
|
|
3193
|
+
/* @__PURE__ */ jsx(
|
|
3194
|
+
"input",
|
|
3195
|
+
{
|
|
3196
|
+
"aria-label": label,
|
|
3197
|
+
"aria-valuetext": formatTimeAria(previewTime),
|
|
3198
|
+
disabled,
|
|
3199
|
+
max: duration || 1,
|
|
3200
|
+
min: 0,
|
|
3201
|
+
onBlur: (event) => {
|
|
3202
|
+
commitPreview(Number(event.currentTarget.value));
|
|
3203
|
+
},
|
|
3204
|
+
onChange: (event) => {
|
|
3205
|
+
updatePreview(Number(event.currentTarget.value));
|
|
3206
|
+
},
|
|
3207
|
+
onKeyUp: (event) => {
|
|
3208
|
+
commitPreview(Number(event.currentTarget.value));
|
|
3209
|
+
},
|
|
3210
|
+
onPointerDown: () => {
|
|
3211
|
+
isAdjusting.current = true;
|
|
3212
|
+
},
|
|
3213
|
+
onPointerCancel: cancelPreview,
|
|
3214
|
+
onPointerUp: (event) => {
|
|
3215
|
+
commitPreview(Number(event.currentTarget.value));
|
|
3216
|
+
},
|
|
3217
|
+
step: 0.1,
|
|
3218
|
+
type: "range",
|
|
3219
|
+
value: disabled ? 0 : previewTime
|
|
3220
|
+
}
|
|
3221
|
+
)
|
|
3222
|
+
]
|
|
3223
|
+
}
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
3144
3226
|
function BoundCompactPlayerView({
|
|
3145
3227
|
appearance,
|
|
3146
3228
|
className,
|
|
@@ -3151,77 +3233,48 @@ function BoundCompactPlayerView({
|
|
|
3151
3233
|
runtimeStatus,
|
|
3152
3234
|
state
|
|
3153
3235
|
}) {
|
|
3154
|
-
const progress = state.durationSec === null || state.durationSec <= 0 ? 0 : state.currentTimeSec / state.durationSec;
|
|
3155
3236
|
return /* @__PURE__ */ jsx(
|
|
3156
|
-
|
|
3237
|
+
CompactPlayerLayout,
|
|
3157
3238
|
{
|
|
3158
3239
|
appearance,
|
|
3159
|
-
className:
|
|
3240
|
+
...className === void 0 ? {} : { className },
|
|
3241
|
+
...contextId === void 0 ? {} : { contextId },
|
|
3242
|
+
...contextMode === void 0 ? {} : { contextMode },
|
|
3243
|
+
currentTimeSec: state.currentTimeSec,
|
|
3244
|
+
durationSec: state.durationSec,
|
|
3245
|
+
isActive: state.isActive,
|
|
3246
|
+
isPlaying: state.isPlaying,
|
|
3247
|
+
item: state.item,
|
|
3160
3248
|
label: `Inline player: ${state.item.title}`,
|
|
3161
|
-
|
|
3162
|
-
|
|
3249
|
+
primaryControl: /* @__PURE__ */ jsx(
|
|
3250
|
+
IconButton,
|
|
3163
3251
|
{
|
|
3164
|
-
className: "player-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
item: state.item
|
|
3187
|
-
}
|
|
3188
|
-
),
|
|
3189
|
-
/* @__PURE__ */ jsx(TrackMetadata, { item: state.item, scrollTitle: state.isPlaying }),
|
|
3190
|
-
/* @__PURE__ */ jsxs("div", { className: "player-bound-compact__signal", children: [
|
|
3191
|
-
/* @__PURE__ */ jsx(
|
|
3192
|
-
Waveform,
|
|
3193
|
-
{
|
|
3194
|
-
opacity: options.waveformOpacity,
|
|
3195
|
-
playedStateEnabled: options.waveformPlayedStateEnabled,
|
|
3196
|
-
progress,
|
|
3197
|
-
waveform: state.item.waveform
|
|
3198
|
-
}
|
|
3199
|
-
),
|
|
3200
|
-
/* @__PURE__ */ jsx(
|
|
3201
|
-
TimeReadout,
|
|
3202
|
-
{
|
|
3203
|
-
currentTimeSec: state.currentTimeSec,
|
|
3204
|
-
durationSec: state.durationSec
|
|
3205
|
-
}
|
|
3206
|
-
)
|
|
3207
|
-
] }),
|
|
3208
|
-
/* @__PURE__ */ jsx(
|
|
3209
|
-
SeekBar,
|
|
3210
|
-
{
|
|
3211
|
-
canSeek: state.canSeek,
|
|
3212
|
-
commitMode: options.seekCommitMode,
|
|
3213
|
-
currentTimeSec: state.currentTimeSec,
|
|
3214
|
-
durationSec: state.durationSec,
|
|
3215
|
-
label: `Seek in ${state.item.title}`,
|
|
3216
|
-
onSeek: (seconds) => {
|
|
3217
|
-
commands.seekTo(seconds);
|
|
3218
|
-
},
|
|
3219
|
-
status: state.status
|
|
3220
|
-
}
|
|
3221
|
-
)
|
|
3222
|
-
]
|
|
3252
|
+
className: "player-play-button",
|
|
3253
|
+
label: state.isPlaying ? "Pause" : "Play",
|
|
3254
|
+
onClick: () => {
|
|
3255
|
+
void commands.togglePlayback();
|
|
3256
|
+
},
|
|
3257
|
+
children: state.isPlaying ? /* @__PURE__ */ jsx(PauseIcon, { size: 22 }) : /* @__PURE__ */ jsx(PlayIcon, { size: 22 })
|
|
3258
|
+
}
|
|
3259
|
+
),
|
|
3260
|
+
queueItemId: state.queueItemId,
|
|
3261
|
+
...runtimeStatus === void 0 ? {} : { runtimeStatus },
|
|
3262
|
+
seekControl: /* @__PURE__ */ jsx(
|
|
3263
|
+
SeekBar,
|
|
3264
|
+
{
|
|
3265
|
+
canSeek: state.canSeek,
|
|
3266
|
+
commitMode: options.seekCommitMode,
|
|
3267
|
+
currentTimeSec: state.currentTimeSec,
|
|
3268
|
+
durationSec: state.durationSec,
|
|
3269
|
+
label: `Seek in ${state.item.title}`,
|
|
3270
|
+
onSeek: (seconds) => {
|
|
3271
|
+
commands.seekTo(seconds);
|
|
3272
|
+
},
|
|
3273
|
+
status: state.status
|
|
3223
3274
|
}
|
|
3224
|
-
)
|
|
3275
|
+
),
|
|
3276
|
+
waveformOpacity: options.waveformOpacity,
|
|
3277
|
+
waveformPlayedStateEnabled: options.waveformPlayedStateEnabled
|
|
3225
3278
|
}
|
|
3226
3279
|
);
|
|
3227
3280
|
}
|