@rogieking/figui3 11.2.2 → 11.3.1

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.
@@ -2,7 +2,7 @@
2
2
  name: fig-lab
3
3
  description: >-
4
4
  Guides FigUI3 experimental Lab components: fig-canvas-control,
5
- fig-input-audio, fig-input-wheel, and AI composer components,
5
+ fig-input-wheel, and AI composer components,
6
6
  including React JSX usage. APIs are unstable.
7
7
  user-invocable: false
8
8
  ---
@@ -22,4 +22,4 @@ import "@rogieking/figui3/fig-lab.css";
22
22
  import "@rogieking/figui3/fig-lab.js";
23
23
  ```
24
24
 
25
- Use Lab for audio and wheel inputs, canvas handles, and AI composition surfaces. Keep Lab out of `fig.js`.
25
+ Use Lab for wheel inputs, canvas handles, and AI composition surfaces. Keep Lab out of `fig.js`.
@@ -2,29 +2,6 @@
2
2
 
3
3
  Experimental. APIs may change. React contract: [../figui3/react.md](../figui3/react.md). Attrs: [reference.md](reference.md).
4
4
 
5
-
6
- Handlers below assume `onInput` / `onChange` from the React contract.
7
-
8
- ## Inputs
9
-
10
- ### `fig-input-audio`
11
-
12
- ```tsx
13
- <fig-input-audio
14
- accepts="audio/*"
15
- label="Upload audio"
16
- full
17
- onInput={onInput}
18
- onChange={onChange}
19
- />
20
- ```
21
-
22
- - Single-file waveform preview; no playback or seeking.
23
- - Attrs: `url`, `filename`, `label`, `accepts`, `variant`, `disabled`, `full`.
24
- - Props: `files`, `value`. Method: `clear()`.
25
- - `input` and `change` bubble with `{ files }`; clear adds `{ cleared: true }`.
26
- - URL previews require CORS access.
27
-
28
5
  ## Spatial
29
6
 
30
7
  ### `fig-canvas-control`
@@ -2,24 +2,6 @@
2
2
 
3
3
  React recipes: [components.md](components.md).
4
4
 
5
- ## `fig-input-audio`
6
-
7
- Single-audio upload with a responsive, preview-only waveform.
8
-
9
- - Attrs: `url`, `filename`, `label` (default `Upload audio`), `accepts` (default `audio/*`), `variant`, `disabled`, `full`
10
- - Props: `files`, `value`
11
- - Method: `clear()`
12
- - Events: `input` and `change`, bubbling and composed, with `{ files }` and optional `cleared`
13
- - Clicking the waveform replaces the file; the minus action removes it
14
- - URL decoding requires CORS; fetch and decode failures fall back quietly
15
- - CSS: `--fig-input-audio-waveform-stroke-width` controls bar thickness (default `2px`)
16
- - Not supported: multiple files, playback, or seeking
17
-
18
- ```html
19
- <fig-input-audio></fig-input-audio>
20
- <fig-input-audio url="https://example.com/audio.wav" filename="audio.wav" full></fig-input-audio>
21
- ```
22
-
23
5
  ## `fig-input-wheel`
24
6
 
25
7
  Standalone interactive SVG tick + handle scrubber in the lab bundle.
@@ -133,18 +133,34 @@ Handlers below assume `onInput` / `onChange` / `onClick` from [react.md](react.m
133
133
 
134
134
  - Children stay in light DOM.
135
135
 
136
+ ### `fig-audio-waveform`
137
+
138
+ ```tsx
139
+ <fig-audio-waveform url="https://example.com/audio.wav" progress="0.42" />
140
+ ```
141
+
142
+ - Responsive waveform generated from the `url` attribute.
143
+ - `progress` is a clamped `0`–`1` fraction; the completed waveform uses the selected icon color.
144
+ - `polarization` controls waveform contrast around half-height; default `1.5`, `1` is neutral.
145
+ - `full` fills the available width.
146
+ - URL decoding requires CORS access.
147
+ - No upload, playback, label, or button UI.
148
+
136
149
  ### `fig-input-file`
137
150
 
138
151
  ```tsx
139
152
  <fig-input-file
140
- label="Upload"
141
153
  accepts="image/*"
154
+ preview
142
155
  multiple
143
156
  onChange={onChange}
144
157
  />
145
158
  ```
146
159
 
147
- - Attrs: `label`, `accepts`, `multiple`, `disabled`, `variant` (`input`, `primary`, `secondary`, `ghost`, `link`, `overlay`)
160
+ - Attrs: `preview`, `label`, `accepts`, `multiple`, `disabled`, `variant` (forwards `fig-button` variants; defaults to `property`)
161
+ - Blank or omitted `label` defaults to `Upload audio`, `Upload image`, or `Upload file` based on the known file type. An explicit label overrides it.
162
+ - `preview` renders supported image extensions in a full-width checkerboard `fig-image` at `4/3`, or turns known audio files into play/pause buttons with a waveform and filename tooltip.
163
+ - `accepts` controls the native chooser filter; file icons and previews are detected independently.
148
164
  - Events: `change` / `input` with files on the host
149
165
 
150
166
  ### `fig-checkbox`
@@ -203,6 +219,7 @@ Handlers below assume `onInput` / `onChange` / `onClick` from [react.md](react.m
203
219
  ```
204
220
 
205
221
  - Attrs: `type` (`range`, `opacity`, `hue`, `stepper`, `delta`), `min`, `max`, `step`, `text`, `units`, `transform`, `color`, `default`, `variant` (`classic`), `placeholder`, `full`, `disabled`
222
+ - A valid explicit `default` adds a tick and native snap target for range, opacity, and hue sliders. Inferred defaults do not render a tick.
206
223
  - Events: `input` / `change` → `currentTarget.value`
207
224
  - React: keep `value` a string; do not remount during drag. Opacity: set `color`. Delta: set `default`. Stepper: include a `<datalist>` of stops.
208
225
 
@@ -55,6 +55,7 @@ Public API: `README.md`. React recipes: [components.md](components.md).
55
55
  - Always set `min`, `max`, `step`; `units` when displayed
56
56
  - `transform` when internal scale ≠ UI scale
57
57
  - `variant="classic"` for the older appearance
58
+ - Valid explicit `default` values add a tick and native snap target for range, opacity, and hue; inferred defaults do not
58
59
  - Opacity: set `color` and usually `units="%"`
59
60
  - Delta: include `default` and typically symmetric min/max
60
61
  - Stepper: include a `<datalist>` of stops
package/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [11.3.1]
6
+
7
+ ### Added
8
+
9
+ - Added explicit `fig-slider` default ticks and native snap targets for valid range, hue, and opacity defaults.
10
+ - Added an optional slider default control to the playground.
11
+
12
+ ### Changed
13
+
14
+ - Made `fig-input-number` steppers repeat while held, emitting continuous input updates and one change event on release.
15
+
16
+ ### Fixed
17
+
18
+ - Kept generated slider default ticks within variant-specific track endpoints.
19
+
20
+ ## [11.3.0]
21
+
22
+ ### Added
23
+
24
+ - Added the core `fig-audio-waveform` component with URL decoding, RMS energy rendering, polarization, fractional progress, and full-width support.
25
+
26
+ ### Changed
27
+
28
+ - Enhanced `fig-input-file` with generated type-aware labels and previewable audio playback using synchronized waveform progress.
29
+ - Moved the audio waveform example and documentation from Lab into the main FigUI3 Utilities section.
30
+ - Updated playground attribute editing to patch live component attributes without remounting unchanged component structures.
31
+
32
+ ### Fixed
33
+
34
+ - Prevented waveform progress updates from rebuilding waveform geometry and flickering.
35
+ - Reset audio waveform progress and playback selection styling when playback ends.
36
+
5
37
  ## [11.2.2]
6
38
 
7
39
  ### Changed
package/README.md CHANGED
@@ -103,10 +103,11 @@ Minimal example:
103
103
  | [Radio](#radio) | `<fig-radio>` | Radio button |
104
104
  | [Switch](#switch) | `<fig-switch>` | Toggle switch |
105
105
  | [Slider](#slider) | `<fig-slider>` | Range, hue, opacity, delta, stepper |
106
- | [Audio Input](#audio-input) | `<fig-input-audio>` | Audio upload with responsive waveform preview |
106
+ | [Audio Waveform](#audio-waveform) | `<fig-audio-waveform>` | Responsive waveform generated from an audio URL |
107
107
  | [Input Wheel](#input-wheel) | `<fig-input-wheel>` | Standalone SVG tick-and-handle numeric scrubber |
108
108
  | [Text Input](#text-input) | `<fig-input-text>` | Styled text/textarea input |
109
109
  | [Number Input](#number-input) | `<fig-input-number>` | Numeric input with units |
110
+ | [File Input](#file-input) | `<fig-input-file>` | File upload with image previews and audio playback waveforms |
110
111
  | [Angle](#angle) | `<fig-angle>` | Instrument-style angle/rotation dial |
111
112
  | [Swatch](#swatch) | `<fig-swatch>` | Color/gradient/image swatch |
112
113
  | [Color Tip](#color-tip) | `<fig-color-tip>` | Compact color tip with picker |
@@ -355,7 +356,7 @@ The suggestion trigger uses `fig-select` when `fig-editor.js` is registered and
355
356
  | `min` | number | `0` | Minimum |
356
357
  | `max` | number | `100` | Maximum |
357
358
  | `step` | number | `1` | Step increment |
358
- | `default` | number | — | Default/reset value (shown as marker) |
359
+ | `default` | number | — | Explicit reference value; adds a tick and native snap target when valid |
359
360
  | `text` | boolean | `true` | Show text input; set `text="false"` to hide |
360
361
  | `placeholder` | string | `"##"` | Text input placeholder |
361
362
  | `units` | string | — | Unit label (e.g. `"%"`, `"px"`) |
@@ -368,42 +369,35 @@ The suggestion trigger uses `fig-select` when `fig-editor.js` is registered and
368
369
  **Events:** `input` (continuous), `change` (on release), with detail `{ value, angle, units }`. Event values are rounded to `precision`; the component retains its higher-precision internal value.
369
370
 
370
371
  ```html
371
- <fig-slider min="0" max="100" value="50" units="%"></fig-slider>
372
+ <fig-slider min="0" max="100" value="50" default="25" units="%"></fig-slider>
372
373
  <fig-slider type="hue" value="180" text="false"></fig-slider>
373
374
  <fig-slider type="opacity" value="75" color="#FF5733" units="%"></fig-slider>
374
375
  ```
375
376
 
376
- For `type="range"`, omitting `value` follows native range behavior and starts at the midpoint of `min` and `max`. Arrow keys move by `step`; hold Shift to move by a larger step.
377
+ For `type="range"`, omitting `value` follows native range behavior and starts at the midpoint of `min` and `max`. An explicitly authored, in-range, step-aligned `default` renders a tick and is passed to the native range input as a snap target; internally inferred defaults do not. Arrow keys move by `step`; hold Shift to move by a larger step.
377
378
 
378
379
  ---
379
380
 
380
- #### Audio Input
381
+ #### Audio Waveform
381
382
 
382
- `<fig-input-audio>`
383
+ `<fig-audio-waveform>`
383
384
 
384
- An experimental single-audio upload control with a responsive waveform preview. Requires `fig-lab.js` and `fig-lab.css`. The waveform is preview-only and has no playback or seeking controls.
385
+ A responsive waveform generated from an audio URL. Included in `fig.js` and `fig.css`.
385
386
 
386
387
  | Attribute | Type | Default | Description |
387
388
  |---|---|---|---|
388
- | `url` | string | — | CORS-enabled audio URL to decode and preview |
389
- | `filename` | string | URL filename | Display filename for URL-backed audio |
390
- | `label` | string | `"Upload audio"` | Empty-state upload label |
391
- | `accepts` | string | `"audio/*"` | Native file accept filter |
392
- | `variant` | string | `"input"` | Upload button variant |
393
- | `disabled` | boolean | `false` | Disable upload, replacement, and removal |
389
+ | `url` | string | — | CORS-enabled audio URL to fetch, decode, and render |
390
+ | `progress` | number | `0` | Completed fraction from `0` to `1`; values are clamped |
391
+ | `polarization` | number | `1.5` | Waveform contrast factor around half-height (`1` is neutral) |
394
392
  | `full` | boolean | `false` | Fill the available width |
395
393
 
396
- Set `--fig-input-audio-waveform-stroke-width` (default `2px`) to control waveform bar thickness.
397
-
398
- `files` and `value` mirror the composed file input. `clear()` removes the current source. The component emits bubbling, composed `input` and `change` events with `{ files }` and `{ files, cleared: true }` when cleared. URL fetch or decode failures render a quiet flat waveform fallback.
394
+ Set `--fig-audio-waveform-stroke-width` (default `1px`) to control waveform bar thickness. The responsive waveform targets one bar per 3px. URL fetch or decode failures render a quiet flat waveform fallback.
399
395
 
400
396
  ```html
401
- <fig-input-audio></fig-input-audio>
402
- <fig-input-audio
397
+ <fig-audio-waveform
403
398
  url="https://example.com/audio.wav"
404
- filename="audio.wav"
405
- full
406
- ></fig-input-audio>
399
+ progress="0.42"
400
+ ></fig-audio-waveform>
407
401
  ```
408
402
 
409
403
  ---
@@ -492,6 +486,30 @@ The `value`, `min`, `max`, and `step` properties mirror their attributes. `aria-
492
486
 
493
487
  ---
494
488
 
489
+ #### File Input
490
+
491
+ `<fig-input-file>` — [demo](https://rog.ie/figui3/#file-input)
492
+
493
+ | Attribute | Type | Default | Description |
494
+ |---|---|---|---|
495
+ | `accepts` | string | — | Native file chooser filter |
496
+ | `preview` | boolean | `false` | Preview supported images or enable button playback for supported audio files |
497
+ | `label` | string | generated | Empty-state button label; defaults to `Upload audio`, `Upload image`, or `Upload file` from the known file type |
498
+ | `multiple` | boolean | `false` | Allow multiple files |
499
+ | `disabled` | boolean | `false` | Disabled state |
500
+ | `variant` | string | `"property"` | Internal button variant |
501
+
502
+ Known image and audio files use the image or sound icon; unmatched files retain the upload icon. With `preview`, image files render in a full-width 4:3 `fig-image`, while an audio file becomes a play/pause button with a polarized waveform, synchronized playback progress, and its filename in a tooltip. Image preview supports `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.svg`, and `.avif`; audio playback supports `.mp3`, `.wav`, `.aac`, `.m4a`, `.ogg`, and `.flac`.
503
+
504
+ ```html
505
+ <fig-input-file accepts="image/*"></fig-input-file>
506
+ <fig-input-file accepts="image/*" preview></fig-input-file>
507
+ <fig-input-file accepts="audio/*"></fig-input-file>
508
+ <fig-input-file accepts=".mp3,.opus" label="Choose audio"></fig-input-file>
509
+ ```
510
+
511
+ ---
512
+
495
513
  #### Angle
496
514
 
497
515
  `<fig-angle>` — [demo](https://rog.ie/figui3/#angle)
package/components.css CHANGED
@@ -426,11 +426,14 @@
426
426
  --icon-16-copy: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.5 5C13.3284 5 14 5.67157 14 6.5V12.5C14 13.3284 13.3284 14 12.5 14H6.5C5.67157 14 5 13.3284 5 12.5C5 12.2239 5.22386 12 5.5 12C5.74171 12 5.94371 12.1714 5.99023 12.3994L6.00977 12.6006C6.05629 12.8286 6.25829 13 6.5 13H12.5C12.7761 13 13 12.7761 13 12.5V6.5C13 6.25829 12.8286 6.05629 12.6006 6.00977L12.3994 5.99023C12.1714 5.94371 12 5.74171 12 5.5C12 5.22386 12.2239 5 12.5 5ZM9.5 2C10.3284 2 11 2.67157 11 3.5V9.5C11 10.3284 10.3284 11 9.5 11H3.5C2.67157 11 2 10.3284 2 9.5V3.5C2 2.67157 2.67157 2 3.5 2H9.5ZM3.5 3C3.22386 3 3 3.22386 3 3.5V9.5C3 9.77614 3.22386 10 3.5 10H9.5C9.77614 10 10 9.77614 10 9.5V3.5C10 3.22386 9.77614 3 9.5 3H3.5Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
427
427
  --icon-24-trash: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16.3545 9C16.6385 9.00024 16.8652 9.23672 16.8535 9.52051L16.5801 16.083L16.5615 16.2812C16.4332 17.1916 15.6952 17.8997 14.7803 17.9902L14.582 18H9.41797C8.34615 17.9996 7.46456 17.154 7.41992 16.083L7.14746 9.52051C7.13579 9.23663 7.36236 9.0001 7.64648 9C7.91454 9 8.13534 9.21167 8.14648 9.47949L8.41895 16.042C8.44144 16.5772 8.88236 16.9996 9.41797 17H14.582C15.1176 16.9996 15.5586 16.5772 15.5811 16.042L15.8545 9.47949C15.8656 9.21167 16.0864 9 16.3545 9ZM11 10C11.2761 10 11.5 10.2239 11.5 10.5V14.5C11.5 14.7761 11.2761 15 11 15C10.724 14.9999 10.5 14.7761 10.5 14.5V10.5C10.5 10.2239 10.724 10.0001 11 10ZM13 10C13.2761 10 13.5 10.2239 13.5 10.5V14.5C13.5 14.7761 13.2761 15 13 15C12.724 14.9999 12.5 14.7761 12.5 14.5V10.5C12.5 10.2239 12.724 10.0001 13 10ZM13 5C13.5523 5 14 5.44772 14 6V7H17.5C17.7761 7 18 7.22386 18 7.5C18 7.77614 17.7761 8 17.5 8H6.5C6.22386 8 6 7.77614 6 7.5C6 7.22386 6.22386 7 6.5 7H10V6C10 5.44772 10.4477 5 11 5H13ZM11 7H13V6H11V7Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
428
428
  --icon-16-trash: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11.2954 6C11.5803 6.00009 11.8072 6.23788 11.7944 6.52246L11.5659 11.5674L11.5513 11.7148C11.446 12.4443 10.8186 12.9988 10.0669 12.999H5.93408L5.78564 12.9922C5.1008 12.9249 4.54803 12.3959 4.44971 11.7148L4.43506 11.5674L4.20557 6.52246C4.19278 6.23794 4.4198 6.00019 4.70459 6C4.97189 6 5.19245 6.21051 5.20459 6.47754L5.43408 11.5215C5.44622 11.7885 5.66677 11.999 5.93408 11.999H10.0669C10.334 11.9988 10.5548 11.7884 10.5669 11.5215L10.7954 6.47754C10.8075 6.21051 11.0281 6 11.2954 6ZM7.00049 6.5C7.27657 6.50007 7.50049 6.7239 7.50049 7V10C7.50049 10.2761 7.27657 10.4999 7.00049 10.5C6.72435 10.5 6.50049 10.2761 6.50049 10V7C6.50049 6.72386 6.72435 6.5 7.00049 6.5ZM9.00049 6.5C9.27657 6.50007 9.50049 6.7239 9.50049 7V10C9.50049 10.2761 9.27657 10.4999 9.00049 10.5C8.72435 10.5 8.50049 10.2761 8.50049 10V7C8.50049 6.72386 8.72435 6.5 9.00049 6.5ZM9.00049 2C9.55255 2.00026 10.0005 2.44788 10.0005 3V4H12.5005C12.7764 4.00026 13.0005 4.22402 13.0005 4.5C13.0005 4.77598 12.7764 4.99974 12.5005 5H3.50049C3.22435 5 2.99951 4.77614 2.99951 4.5C2.99951 4.22386 3.22435 4 3.50049 4H6.00049V3C6.00049 2.44772 6.4482 2 7.00049 2H9.00049ZM7.00049 4H9.00049V3H7.00049V4Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
429
-
429
+ --icon-24-sound: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11.293 5.29297C11.579 5.00699 12.0091 4.9214 12.3828 5.07617C12.7564 5.23099 13 5.59561 13 6V18C13 18.4044 12.7564 18.769 12.3828 18.9238C12.0092 19.0786 11.579 18.993 11.293 18.707L8.58594 16H6.5C5.67161 16 5.00005 15.3284 5 14.5V9.5C5.00002 8.67159 5.67158 8 6.5 8H8.58594L11.293 5.29297ZM9 9H6.5C6.22387 9 6.00002 9.22387 6 9.5V14.5C6.00005 14.7761 6.22389 15 6.5 15H9L12 18V6L9 9ZM14.5615 8.66504C15.9753 9.1144 16.9998 10.4373 17 12C16.9998 13.5627 15.9753 14.8855 14.5615 15.335C14.2716 15.4271 14.0001 15.191 14 14.8867V14.8574C14.0001 14.6199 14.1697 14.4199 14.3916 14.335C15.3316 13.9759 15.9998 13.0662 16 12C15.9999 10.9338 15.3325 10.0224 14.3926 9.66309C14.1705 9.5782 14 9.37839 14 9.14062V9.11328C14.0001 8.8091 14.2716 8.57301 14.5615 8.66504ZM14 11.2939C14 10.9489 14.3501 10.7179 14.5879 10.9678C14.8432 11.2363 14.9999 11.6001 15 12C14.9999 12.3998 14.8432 12.7628 14.5879 13.0312C14.3501 13.2812 14.0001 13.0501 14 12.7051V11.2939Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
430
+ --icon-16-sound: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7.29297 3.29297C7.57896 3.00699 8.00915 2.9214 8.38281 3.07617C8.7564 3.23098 8.99999 3.5956 9 4V12C8.99999 12.4044 8.7564 12.769 8.38281 12.9238C8.00915 13.0786 7.57896 12.993 7.29297 12.707L5.58594 11H4.5C3.67158 11 3.00002 10.3284 3 9.5V6.5C3.00002 5.67159 3.67158 5 4.5 5H5.58594L7.29297 3.29297ZM6 6H4.5C4.22387 6 4.00002 6.22387 4 6.5V9.5C4.00002 9.77613 4.22387 10 4.5 10H6L8 12V4L6 6ZM10.498 5.04102C11.9178 5.27825 13 6.51286 13 8C13 9.48717 11.9179 10.7218 10.498 10.959C10.2257 11.0045 10 10.7761 10 10.5C10 10.2239 10.2275 10.0066 10.4951 9.93848C11.3602 9.71818 12 8.93368 12 8C12 7.06635 11.3602 6.28183 10.4951 6.06152C10.2275 5.99339 10 5.77613 10 5.5C10 5.22387 10.2257 4.99552 10.498 5.04102ZM10 7.5C10 7.2239 10.2373 6.98956 10.4795 7.12207C10.7896 7.29187 11 7.6215 11 8C11 8.37853 10.7897 8.70814 10.4795 8.87793C10.2373 9.01044 10 8.7761 10 8.5V7.5Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
431
+ --icon-24-sound-off: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.1465 11.9746C12.4615 11.6597 13 11.8827 13 12.3281V17.999C13 18.4034 12.7564 18.768 12.3828 18.9229C12.0092 19.0776 11.579 18.992 11.293 18.7061L8.58887 16.002C8.58705 16.0001 8.5846 15.9991 8.58203 15.999C8.41225 15.999 8.32734 15.794 8.44727 15.6738L8.78516 15.335C8.93708 15.1829 9.18394 15.183 9.33594 15.335L11.9834 17.9824C11.9897 17.988 12 17.9833 12 17.9746V12.3281C12 12.1955 12.0527 12.0684 12.1465 11.9746ZM15.1465 6.14648C15.3417 5.95122 15.6583 5.95122 15.8535 6.14648C16.0487 6.34176 16.0487 6.65829 15.8535 6.85352L4.85352 17.8535C4.65828 18.0486 4.34172 18.0486 4.14648 17.8535C3.95126 17.6583 3.95133 17.3418 4.14648 17.1465L15.1465 6.14648ZM11.293 5.29199C11.579 5.00601 12.0091 4.92042 12.3828 5.0752C12.7564 5.23001 13 5.59463 13 5.99902V6.67188C13 6.80445 12.9473 6.93165 12.8535 7.02539C12.5386 7.34027 12.0001 7.11723 12 6.67188V6.02344C12 6.01475 11.9897 6.01001 11.9834 6.01562L9.00293 8.99609C9.00111 8.9979 8.99865 8.99896 8.99609 8.99902H6.5C6.22387 8.99902 6.00002 9.22289 6 9.49902V13.6719C5.99993 13.8045 5.9473 13.9317 5.85352 14.0254L5.28125 14.5967C5.17556 14.7019 5.00003 14.6483 5 14.499V9.49902C5.00002 8.67061 5.67158 7.99902 6.5 7.99902H8.58203C8.58459 7.99896 8.58705 7.9979 8.58887 7.99609L11.293 5.29199Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
432
+ --icon-16-sound-off: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.1465 3.14648C12.3417 2.95139 12.6583 2.95139 12.8535 3.14648C13.0487 3.3417 13.0487 3.65824 12.8535 3.85352L3.85352 12.8535C3.65825 13.0488 3.34175 13.0488 3.14648 12.8535C2.95135 12.6582 2.95126 12.3417 3.14648 12.1465L12.1465 3.14648ZM10 12C9.99999 12.4044 9.7564 12.769 9.38281 12.9238C9.00916 13.0786 8.57895 12.993 8.29297 12.707L6.85352 11.2676L7.56055 10.5605L9 12V9.12109L10 8.12109V12ZM8.29297 3.29297C8.57896 3.00699 9.00915 2.92142 9.38281 3.07617C9.72107 3.21634 9.95041 3.52875 9.99121 3.88672L9 4.87891V4L7 6H5.5C5.22389 6.00002 5.00002 6.22388 5 6.5V8.87891L4.03906 9.83887C4.01389 9.72993 4 9.61658 4 9.5V6.5C4.00002 5.6716 4.6716 5.00002 5.5 5H6.58594L8.29297 3.29297Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
433
+ --icon-24-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 6C6.67157 6 6 6.67157 6 7.5V16.5C6 17.3284 6.67157 18 7.5 18H16.5C17.3284 18 18 17.3284 18 16.5V7.5C18 6.67157 17.3284 6 16.5 6H7.5ZM7 7.5C7 7.22386 7.22386 7 7.5 7H16.5C16.7761 7 17 7.22386 17 7.5V14.793L14.3536 12.1464C14.1583 11.9512 13.8417 11.9512 13.6464 12.1464L12 13.7929L9.85355 11.6464C9.65829 11.4512 9.34171 11.4512 9.14645 11.6464L7 13.7929V7.5ZM7 15.2071V16.5C7 16.7761 7.22386 17 7.5 17H16.5C16.7761 17 17 16.7761 17 16.5V16.2071L14 13.2071L12.3536 14.8536C12.1583 15.0488 11.8417 15.0488 11.6464 14.8536L9.5 12.7071L7 15.2071ZM13.5 8C14.3284 8 15 8.67157 15 9.5C15 10.3284 14.3284 11 13.5 11C12.6716 11 12 10.3284 12 9.5C12 8.67157 12.6716 8 13.5 8ZM13.5 9C13.2239 9 13 9.22386 13 9.5C13 9.77614 13.2239 10 13.5 10C13.7761 10 14 9.77614 14 9.5C14 9.22386 13.7761 9 13.5 9Z' fill='black' fill-opacity='0.9'/%3E%3C/svg%3E");
430
434
  --tip-pointer: path("M8 6L2 0H14L8 6Z");
431
435
 
432
436
 
433
-
434
437
  /* Elevations — light-dark() handles theme switching inline */
435
438
  --figma-elevation-100:
436
439
  0px 0px 0.5px 0px light-dark(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.5)),
@@ -1725,6 +1728,49 @@ fig-truncate {
1725
1728
  }
1726
1729
  }
1727
1730
 
1731
+ fig-audio-waveform {
1732
+ --fig-audio-waveform-stroke-width: 1px;
1733
+ --fig-audio-waveform-stroke-color: var(--figma-color-icon-tertiary);
1734
+ --fig-audio-waveform-progress-color: var(
1735
+ --figma-color-icon-selected-secondary
1736
+ );
1737
+
1738
+ display: block;
1739
+ box-sizing: border-box;
1740
+ max-width: 100%;
1741
+ min-width: var(--spacer-4);
1742
+ height: var(--control-height);
1743
+ overflow: hidden;
1744
+ color: var(--fig-audio-waveform-stroke-color);
1745
+
1746
+ &[full]:not([full="false"]) {
1747
+ width: 100%;
1748
+ }
1749
+
1750
+ .fig-audio-waveform-surface {
1751
+ display: block;
1752
+ width: calc(100% - var(--spacer-3));
1753
+ height: 100%;
1754
+ }
1755
+
1756
+ .fig-audio-waveform-surface > svg {
1757
+ display: block;
1758
+ width: 100%;
1759
+ height: 100%;
1760
+ overflow: visible;
1761
+ }
1762
+
1763
+ .fig-audio-waveform-path,
1764
+ .fig-audio-waveform-progress {
1765
+ fill: currentColor;
1766
+ stroke: none;
1767
+ }
1768
+
1769
+ .fig-audio-waveform-progress {
1770
+ fill: var(--fig-audio-waveform-progress-color);
1771
+ }
1772
+ }
1773
+
1728
1774
  fig-input-file {
1729
1775
  display: flex;
1730
1776
  align-items: center;
@@ -1732,6 +1778,10 @@ fig-input-file {
1732
1778
  min-width: 0;
1733
1779
  max-width: 100%;
1734
1780
 
1781
+ &[data-previewing] {
1782
+ width: 100%;
1783
+ }
1784
+
1735
1785
  &[full]:not([full="false"]) {
1736
1786
  flex: 1 1 auto;
1737
1787
  width: 100%;
@@ -1752,10 +1802,40 @@ fig-input-file {
1752
1802
  min-width: 0;
1753
1803
  }
1754
1804
 
1805
+ .fig-input-file-filename:has(> .fig-input-file-audio-waveform) {
1806
+ column-gap: var(--spacer-1);
1807
+ overflow: hidden;
1808
+ }
1809
+
1810
+ .fig-input-file-audio-waveform {
1811
+ flex: 1 1 auto;
1812
+ width: auto;
1813
+ min-width: 0;
1814
+ pointer-events: none;
1815
+
1816
+ .fig-audio-waveform-surface {
1817
+ width: 100%;
1818
+ }
1819
+ }
1820
+
1821
+ .fig-input-file-filename[selected]:not([selected="false"])
1822
+ > .fig-input-file-audio-waveform {
1823
+ --fig-audio-waveform-stroke-color: var(
1824
+ --figma-color-bordertranslucentstrong
1825
+ );
1826
+ --fig-audio-waveform-progress-color: var(--figma-color-icon-selected);
1827
+ }
1828
+
1755
1829
  .fig-input-file-clear {
1830
+ display: none;
1756
1831
  flex-shrink: 0;
1757
1832
  }
1758
1833
 
1834
+ &:is(:hover, :focus-within) .fig-input-file-clear,
1835
+ fig-field:hover & .fig-input-file-clear {
1836
+ display: flex;
1837
+ }
1838
+
1759
1839
  fig-button:has(> input[type="file"]:focus-visible) {
1760
1840
  outline: var(--figma-focus-outline);
1761
1841
  outline-offset: var(--figma-focus-outline-offset);
@@ -3077,8 +3157,9 @@ fig-slider {
3077
3157
  --slider-tick-radius: 100%;
3078
3158
  --slider-border-radius: calc(var(--slider-height) / 2);
3079
3159
  --slider-stepper-padding: calc(
3080
- (var(--slider-height) / 2) - var(--slider-tick-width) / 2
3160
+ (var(--slider-thumb-size) / 2) - var(--slider-tick-width) / 2
3081
3161
  );
3162
+ --slider-default-tick-end-inset: calc(var(--slider-stepper-padding) * 2);
3082
3163
  --slider-track-color: var(--figma-color-bg-secondary);
3083
3164
  --slider-percent: calc(var(--slider-complete) * 100%);
3084
3165
  --start-percent: calc(var(--default, 0) * 100%);
@@ -3369,11 +3450,25 @@ fig-slider {
3369
3450
  }
3370
3451
  }
3371
3452
 
3453
+ datalist[data-generated="slider-default"] option:first-child:last-child {
3454
+ position: absolute;
3455
+ margin: 0;
3456
+ left: clamp(
3457
+ var(--slider-stepper-padding),
3458
+ calc(var(--start-percent) - var(--slider-tick-width) / 2),
3459
+ calc(100% - var(--slider-default-tick-end-inset))
3460
+ );
3461
+ top: calc(50% - var(--slider-tick-height) / 2);
3462
+ }
3463
+
3372
3464
  &:not([variant="classic"]) {
3373
3465
  --slider-height: 0.375rem;
3374
3466
  --slider-thumb-size: 0.75rem;
3375
3467
  --slider-tick-width: calc(var(--slider-height) / 2);
3376
3468
  --slider-tick-height: calc(var(--slider-height) / 2);
3469
+ --slider-default-tick-end-inset: calc(
3470
+ var(--slider-thumb-size) / 2 + var(--slider-tick-width) / 2 - 0.125rem
3471
+ );
3377
3472
  --slider-number-width: var(--input-opacity-width);
3378
3473
  --handle-transition: none;
3379
3474
  --slider-transition: none;