@arraypress/waveform-player 1.8.1 → 1.10.0

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/index.d.ts CHANGED
@@ -127,6 +127,12 @@ export interface WaveformPlayerOptions {
127
127
  // ── Layout / UI toggles ───────────────────────────────────────
128
128
  /** Play-button alignment. @default 'auto' */
129
129
  buttonAlign?: ButtonAlign;
130
+ /**
131
+ * Player layout. `'preview'` centers the title under the waveform and trims
132
+ * the meta row (time/speed/BPM) — ideal for sample-pack previews.
133
+ * @default 'default'
134
+ */
135
+ layout?: 'default' | 'preview';
130
136
  /** Show transport controls. @default true */
131
137
  showControls?: boolean;
132
138
  /** Show the info (title/subtitle) block. @default true */
@@ -329,6 +335,12 @@ export declare class WaveformPlayer {
329
335
  escapeHtml(str: unknown): string;
330
336
  /** Whether a URL uses a safe (`http`/`https`/relative) scheme. */
331
337
  isSafeHref(url: string): boolean;
338
+ /**
339
+ * Parse every recognised `data-*` attribute off an element into a
340
+ * sparse options object (the player's full declarative contract).
341
+ * Lets wrappers inherit the complete option surface without drifting.
342
+ */
343
+ parseDataAttributes(element: HTMLElement): Partial<WaveformPlayerOptions>;
332
344
  };
333
345
  }
334
346
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arraypress/waveform-player",
3
- "version": "1.8.1",
3
+ "version": "1.10.0",
4
4
  "description": "Lightweight, customizable audio player with waveform visualization",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",
@@ -3,6 +3,9 @@
3
3
  font-family: inherit;
4
4
  color: inherit;
5
5
  line-height: var(--waveform-line-height, 1.4);
6
+ /* Neutral accent for the keyboard-focus ring + active states. Monochrome
7
+ by default (shadcn-style); override this variable to re-tint it. */
8
+ --wfp-accent: #71717a;
6
9
  }
7
10
 
8
11
  .waveform-player * {
@@ -302,13 +305,13 @@
302
305
  }
303
306
 
304
307
  .speed-option.active {
305
- background: rgba(168, 85, 247, 0.2);
306
- color: #a855f7;
308
+ background: rgba(255, 255, 255, 0.16);
309
+ color: #fff;
307
310
  font-weight: 600;
308
311
  }
309
312
 
310
313
  .waveform-player.waveform-focused {
311
- outline: 2px solid rgba(168, 85, 247, 0.5);
314
+ outline: 2px solid var(--wfp-accent);
312
315
  outline-offset: 2px;
313
316
  border-radius: 4px;
314
317
  }
@@ -320,10 +323,28 @@
320
323
 
321
324
  /* Only show focus indicator when keyboard navigating (not clicking) */
322
325
  .waveform-player:focus-visible {
323
- outline: 1px solid rgba(168, 85, 247, 0.3);
326
+ outline: 1px solid var(--wfp-accent);
324
327
  outline-offset: 1px;
325
328
  }
326
329
 
330
+ /* ==========================================================================
331
+ 'preview' layout — compact, centered title under the waveform, trimmed
332
+ meta row. Ideal for sample-pack previews and dense grids.
333
+ ========================================================================== */
334
+ .waveform-layout-preview .waveform-meta {
335
+ display: none !important;
336
+ }
337
+
338
+ .waveform-layout-preview .waveform-info {
339
+ justify-content: center;
340
+ }
341
+
342
+ .waveform-layout-preview .waveform-text {
343
+ flex: 0 1 auto;
344
+ align-items: center;
345
+ text-align: center;
346
+ }
347
+
327
348
  /* Remove the class-based focus indicator since we're using :focus-visible */
328
349
  .waveform-player.waveform-focused {
329
350
  outline: none;
package/src/js/core.js CHANGED
@@ -224,6 +224,13 @@ export class WaveformPlayer {
224
224
  }
225
225
  }
226
226
 
227
+ // Compact 'preview' layout: centered title under the waveform with the
228
+ // meta row trimmed. Set via the `layout` option / data-layout="preview".
229
+ const isPreview = this.options.layout === 'preview';
230
+ if (isPreview) {
231
+ this.container.classList.add('waveform-layout-preview');
232
+ }
233
+
227
234
  // Build play button HTML (conditional)
228
235
  const buttonHTML = this.options.showControls ? `
229
236
  <button class="waveform-btn" aria-label="Play/Pause" style="
@@ -251,7 +258,7 @@ export class WaveformPlayer {
251
258
  <span class="waveform-title" style="color: ${this.options.textColor};"></span>
252
259
  ${this.options.subtitle ? `<span class="waveform-subtitle" style="color: ${this.options.textSecondaryColor};">${this.options.subtitle}</span>` : ''}
253
260
  </div>
254
- <div style="display: flex; align-items: center; gap: 1rem;">
261
+ <div class="waveform-meta" style="display: flex; align-items: center; gap: 1rem;">
255
262
  ${this.options.showBPM ? `
256
263
  <span class="waveform-bpm" style="color: ${this.options.textSecondaryColor}; display: none;">
257
264
  <span class="bpm-value">--</span> BPM
package/src/js/index.js CHANGED
@@ -12,12 +12,15 @@
12
12
 
13
13
  // Import the main class
14
14
  import {WaveformPlayer} from './core.js';
15
- import {formatTime, extractTitleFromUrl, escapeHtml, isSafeHref} from './utils.js';
15
+ import {formatTime, extractTitleFromUrl, escapeHtml, isSafeHref, parseDataAttributes} from './utils.js';
16
16
 
17
17
  // Expose a small set of pure helpers as a single source of truth so consumers
18
- // (e.g. @arraypress/waveform-bar) can reuse them instead of shipping divergent
19
- // copies. Attached to the class so it's reachable from the IIFE global too.
20
- WaveformPlayer.utils = {formatTime, extractTitleFromUrl, escapeHtml, isSafeHref};
18
+ // (e.g. @arraypress/waveform-bar, @arraypress/waveform-playlist) can reuse them
19
+ // instead of shipping divergent copies. `parseDataAttributes` lets wrappers read
20
+ // the player's full `data-*` option surface off a host element without
21
+ // re-implementing (and drifting from) the contract. Attached to the class so
22
+ // it's reachable from the IIFE global too.
23
+ WaveformPlayer.utils = {formatTime, extractTitleFromUrl, escapeHtml, isSafeHref, parseDataAttributes};
21
24
 
22
25
  /**
23
26
  * Whether we're running in a browser (vs. SSR / Node), where `window` and
package/src/js/themes.js CHANGED
@@ -169,6 +169,11 @@ export const DEFAULT_OPTIONS = {
169
169
 
170
170
  // Layout Options
171
171
  buttonAlign: 'auto',
172
+ // Player layout. 'default' = play button + waveform with a left-aligned
173
+ // info row below. 'preview' = compact: the title is centered under the
174
+ // waveform and the meta row (time / speed / BPM) is trimmed — ideal for
175
+ // sample-pack sample previews and dense grids.
176
+ layout: 'default',
172
177
 
173
178
  // Default waveform style
174
179
  waveformStyle: 'mirror',
package/src/js/utils.js CHANGED
@@ -137,6 +137,7 @@ export function parseDataAttributes(element) {
137
137
  setNum('barSpacing');
138
138
  setNum('barRadius');
139
139
  if (element.dataset.buttonAlign) options.buttonAlign = element.dataset.buttonAlign;
140
+ if (element.dataset.layout) options.layout = element.dataset.layout;
140
141
 
141
142
  // Color preset
142
143
  if (element.dataset.colorPreset) options.colorPreset = element.dataset.colorPreset;