@rcarls/rc-progress 0.1.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/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @rcarls/rc-progress
2
+
3
+ Native `<progress>` enhancer with a formatted value display, a track and fill
4
+ you can restyle with CSS custom properties, and a built-in fix for the
5
+ indeterminate/undefined-binding footgun.
6
+
7
+ Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-progress](https://richardcarls.github.io/rc-webcomponents/components/rc-progress).
8
+
9
+ ## Styling Hooks
10
+
11
+ `rc-progress` progressively enhances a direct child `<progress>`. The element
12
+ remains consumer-owned light DOM (so it keeps its native `role="progressbar"`
13
+ and any `id`-based associations), while the component renders its track, fill,
14
+ and value display in shadow DOM.
15
+
16
+ ```html
17
+ <rc-progress display="inline-end" value-text="4 of 10 recipes synced">
18
+ <progress value="4" max="10" aria-label="Sync progress"></progress>
19
+ </rc-progress>
20
+ ```
21
+
22
+ The component exposes `root`, `control`, `track`, `fill`, and `value-display`
23
+ CSS parts.
24
+
25
+ ## Indeterminate
26
+
27
+ Toggle the `indeterminate` attribute instead of binding `undefined` to the
28
+ native element's `value`: the component removes/restores the attribute for
29
+ you, avoiding the well-known `<progress>.value = undefined` throw:
30
+
31
+ ```html
32
+ <rc-progress indeterminate>
33
+ <progress aria-label="Preparing…"></progress>
34
+ </rc-progress>
35
+ ```
@@ -0,0 +1,500 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "readme": "",
4
+ "modules": [
5
+ {
6
+ "kind": "javascript-module",
7
+ "path": "src/define.ts",
8
+ "declarations": [],
9
+ "exports": [
10
+ {
11
+ "kind": "custom-element-definition",
12
+ "name": "rc-progress",
13
+ "declaration": {
14
+ "name": "RCProgress",
15
+ "module": "/src/index.js"
16
+ }
17
+ },
18
+ {
19
+ "kind": "js",
20
+ "name": "*",
21
+ "declaration": {
22
+ "name": "*",
23
+ "module": "src/index.js"
24
+ }
25
+ }
26
+ ]
27
+ },
28
+ {
29
+ "kind": "javascript-module",
30
+ "path": "src/index.ts",
31
+ "declarations": [],
32
+ "exports": [
33
+ {
34
+ "kind": "js",
35
+ "name": "*",
36
+ "declaration": {
37
+ "name": "*",
38
+ "module": "src/rc-progress.js"
39
+ }
40
+ }
41
+ ]
42
+ },
43
+ {
44
+ "kind": "javascript-module",
45
+ "path": "src/rc-progress.ts",
46
+ "declarations": [
47
+ {
48
+ "kind": "class",
49
+ "description": "Enhances a native `<progress>` with a custom track/fill and an optional\nformatted value display, following the same progressive-enhancement shape\nas `rc-slider`.\n\nDeliberately does one job: it does not render a dialog, own any phase\nstate, or assume anything about where it's placed. Compose it with\n`rc-dialog`, a card, or an inline status row as needed.\n\nLabel association:\n- Explicit `for`/`id`: `<label for=\"sync\">Sync</label><rc-progress><progress id=\"sync\" …></rc-progress>`\n- Direct `aria-label` on the `<progress>`: `<progress aria-label=\"Sync\" …>`\n\nThese patterns all work without JavaScript. The component does not render\na label itself — the consumer is responsible for accessible naming.",
50
+ "name": "RCProgress",
51
+ "cssProperties": [
52
+ {
53
+ "description": "Track hit-area block size.",
54
+ "name": "--rc-progress-control-size",
55
+ "default": "0.5rem"
56
+ },
57
+ {
58
+ "description": "Track length when `orientation=\"vertical\"`.",
59
+ "name": "--rc-progress-vertical-size",
60
+ "default": "12.5rem"
61
+ },
62
+ {
63
+ "description": "Gap between track and inline value display.",
64
+ "name": "--rc-progress-gap",
65
+ "default": "var(--rc-control-gap)"
66
+ },
67
+ {
68
+ "description": "Unfilled track color.",
69
+ "name": "--rc-progress-track-background",
70
+ "default": "CanvasText"
71
+ },
72
+ {
73
+ "description": "Unfilled track opacity.",
74
+ "name": "--rc-progress-track-opacity",
75
+ "default": "0.25"
76
+ },
77
+ {
78
+ "description": "Track border radius.",
79
+ "name": "--rc-progress-track-radius",
80
+ "default": "var(--rc-control-radius)"
81
+ },
82
+ {
83
+ "description": "Filled track color.",
84
+ "name": "--rc-progress-fill-background",
85
+ "default": "var(--rc-accent)"
86
+ },
87
+ {
88
+ "description": "Value display text color.",
89
+ "name": "--rc-progress-value-color",
90
+ "default": "var(--rc-text-disabled)"
91
+ }
92
+ ],
93
+ "cssParts": [
94
+ {
95
+ "description": "Root layout wrapper.",
96
+ "name": "root"
97
+ },
98
+ {
99
+ "description": "Track positioning wrapper.",
100
+ "name": "control"
101
+ },
102
+ {
103
+ "description": "Visual track.",
104
+ "name": "track"
105
+ },
106
+ {
107
+ "description": "Filled progress segment.",
108
+ "name": "fill"
109
+ },
110
+ {
111
+ "description": "Rendered value text.",
112
+ "name": "value-display"
113
+ }
114
+ ],
115
+ "slots": [
116
+ {
117
+ "description": "Place a `<progress>` element here.",
118
+ "name": ""
119
+ },
120
+ {
121
+ "description": "Optional replacement for the rendered value text.",
122
+ "name": "value-display"
123
+ }
124
+ ],
125
+ "members": [
126
+ {
127
+ "kind": "field",
128
+ "name": "_value",
129
+ "type": {
130
+ "text": "number | undefined"
131
+ },
132
+ "privacy": "private"
133
+ },
134
+ {
135
+ "kind": "field",
136
+ "name": "_defaultValue",
137
+ "type": {
138
+ "text": "number | undefined"
139
+ },
140
+ "privacy": "private"
141
+ },
142
+ {
143
+ "kind": "field",
144
+ "name": "_valueInitialized",
145
+ "type": {
146
+ "text": "boolean"
147
+ },
148
+ "privacy": "private",
149
+ "default": "false"
150
+ },
151
+ {
152
+ "kind": "field",
153
+ "name": "value",
154
+ "type": {
155
+ "text": "number"
156
+ },
157
+ "description": "Current progress value.",
158
+ "attribute": "value"
159
+ },
160
+ {
161
+ "kind": "field",
162
+ "name": "defaultValue",
163
+ "type": {
164
+ "text": "number | undefined"
165
+ },
166
+ "description": "Initial uncontrolled value. Has no effect after the first host write.",
167
+ "attribute": "default-value"
168
+ },
169
+ {
170
+ "kind": "field",
171
+ "name": "max",
172
+ "type": {
173
+ "text": "number"
174
+ },
175
+ "description": "Maximum progress value, read directly from the native `<progress>`\nchild's own `max` IDL property (native default `1`) rather than\nduplicated as a separate host attribute — the consumer already owns it\nby setting `max` on the slotted `<progress>` element.",
176
+ "readonly": true
177
+ },
178
+ {
179
+ "kind": "field",
180
+ "name": "indeterminate",
181
+ "type": {
182
+ "text": "boolean"
183
+ },
184
+ "default": "false",
185
+ "description": "When present, the component removes the native `<progress>`'s `value`\nattribute instead of asking the consumer to bind `undefined` to it —\nbinding `undefined` to a live `<progress>.value` throws.",
186
+ "attribute": "indeterminate",
187
+ "reflects": true
188
+ },
189
+ {
190
+ "kind": "field",
191
+ "name": "disabled",
192
+ "type": {
193
+ "text": "boolean"
194
+ },
195
+ "default": "false",
196
+ "description": "Visual-only dimming; native `<progress>` has no functional disabled state.",
197
+ "attribute": "disabled",
198
+ "reflects": true
199
+ },
200
+ {
201
+ "kind": "field",
202
+ "name": "display",
203
+ "type": {
204
+ "text": "DisplayValue"
205
+ },
206
+ "default": "null",
207
+ "description": "Controls the live value display.\n\n- Absent (default) — no value shown.\n- `overlay` (or bare `display`) — centered on the bar.\n- `display=\"inline-start\"` — rendered before the track, inline in the grid.\n- `display=\"inline-end\"` — rendered after the track, inline in the grid.",
208
+ "attribute": "display",
209
+ "reflects": true
210
+ },
211
+ {
212
+ "kind": "field",
213
+ "name": "valueText",
214
+ "type": {
215
+ "text": "string"
216
+ },
217
+ "default": "''",
218
+ "description": "Screen-reader value text. When set, forwarded as `aria-valuetext` on the\nnative `<progress>` and used as the default formatted display text.",
219
+ "attribute": "value-text"
220
+ },
221
+ {
222
+ "kind": "field",
223
+ "name": "orientation",
224
+ "type": {
225
+ "text": "'horizontal' | 'vertical'"
226
+ },
227
+ "default": "'horizontal'",
228
+ "description": "Orientation; reflected as an attribute and forwarded to `aria-orientation`.",
229
+ "attribute": "orientation",
230
+ "reflects": true
231
+ },
232
+ {
233
+ "kind": "field",
234
+ "name": "_$nativeProgress",
235
+ "type": {
236
+ "text": "HTMLProgressElement | null"
237
+ },
238
+ "privacy": "private",
239
+ "default": "null"
240
+ },
241
+ {
242
+ "kind": "field",
243
+ "name": "_completedDispatched",
244
+ "type": {
245
+ "text": "boolean"
246
+ },
247
+ "privacy": "private",
248
+ "default": "false"
249
+ },
250
+ {
251
+ "kind": "field",
252
+ "name": "_nativeValueBeforeIndeterminate",
253
+ "type": {
254
+ "text": "number | undefined"
255
+ },
256
+ "privacy": "private"
257
+ },
258
+ {
259
+ "kind": "field",
260
+ "name": "_progressObserver",
261
+ "type": {
262
+ "text": "MutationObserver | null"
263
+ },
264
+ "privacy": "private",
265
+ "default": "null"
266
+ },
267
+ {
268
+ "kind": "field",
269
+ "name": "_nativeProgressController",
270
+ "privacy": "private",
271
+ "readonly": true,
272
+ "default": "new NativeChildController<HTMLProgressElement>( this, { selector: ':scope > progress', observe: true, onChange: ($progress, $previous) => this._setupProgress($progress, $previous), onMissing: () => { if (import.meta.env.DEV) { warnMissingDirectChild(this, { selector: ':scope > progress', message: '[rc-progress] Requires a child <progress> element.', }); } }, }, )"
273
+ },
274
+ {
275
+ "kind": "field",
276
+ "name": "_displayText",
277
+ "type": {
278
+ "text": "string"
279
+ },
280
+ "privacy": "private",
281
+ "readonly": true
282
+ },
283
+ {
284
+ "kind": "field",
285
+ "name": "_nativeProgressValue",
286
+ "type": {
287
+ "text": "number"
288
+ },
289
+ "privacy": "private",
290
+ "readonly": true
291
+ },
292
+ {
293
+ "kind": "method",
294
+ "name": "_setupProgress",
295
+ "privacy": "private",
296
+ "return": {
297
+ "type": {
298
+ "text": "void"
299
+ }
300
+ },
301
+ "parameters": [
302
+ {
303
+ "name": "$progress",
304
+ "type": {
305
+ "text": "HTMLProgressElement | null"
306
+ }
307
+ },
308
+ {
309
+ "name": "$previous",
310
+ "optional": true,
311
+ "type": {
312
+ "text": "HTMLProgressElement | null"
313
+ }
314
+ }
315
+ ]
316
+ },
317
+ {
318
+ "kind": "field",
319
+ "name": "_onDefaultSlotChange",
320
+ "privacy": "private"
321
+ },
322
+ {
323
+ "kind": "method",
324
+ "name": "_applyInitialValueToNative",
325
+ "privacy": "private",
326
+ "return": {
327
+ "type": {
328
+ "text": "void"
329
+ }
330
+ }
331
+ },
332
+ {
333
+ "kind": "method",
334
+ "name": "_applyValueToNative",
335
+ "privacy": "private",
336
+ "return": {
337
+ "type": {
338
+ "text": "void"
339
+ }
340
+ },
341
+ "parameters": [
342
+ {
343
+ "name": "value",
344
+ "type": {
345
+ "text": "number"
346
+ }
347
+ }
348
+ ]
349
+ },
350
+ {
351
+ "kind": "method",
352
+ "name": "_applyIndeterminate",
353
+ "privacy": "private",
354
+ "return": {
355
+ "type": {
356
+ "text": "void"
357
+ }
358
+ },
359
+ "description": "Adds or removes the native `<progress>`'s `value` attribute/property to\nreflect `indeterminate` — the one piece of state this component owns so\nconsumers never bind `undefined` to a live `<progress>.value` themselves."
360
+ },
361
+ {
362
+ "kind": "method",
363
+ "name": "_syncAriaAttributes",
364
+ "privacy": "private",
365
+ "return": {
366
+ "type": {
367
+ "text": "void"
368
+ }
369
+ },
370
+ "parameters": [
371
+ {
372
+ "name": "$progress",
373
+ "type": {
374
+ "text": "HTMLProgressElement"
375
+ }
376
+ }
377
+ ]
378
+ },
379
+ {
380
+ "kind": "method",
381
+ "name": "_checkComplete",
382
+ "privacy": "private",
383
+ "return": {
384
+ "type": {
385
+ "text": "void"
386
+ }
387
+ }
388
+ },
389
+ {
390
+ "kind": "method",
391
+ "name": "_fillStyle",
392
+ "privacy": "private",
393
+ "return": {
394
+ "type": {
395
+ "text": "string"
396
+ }
397
+ }
398
+ }
399
+ ],
400
+ "events": [
401
+ {
402
+ "name": "rc-progress-complete",
403
+ "type": {
404
+ "text": "CustomEvent"
405
+ },
406
+ "description": "Fires once when `value` reaches `max` while not indeterminate. Does not re-fire on subsequent updates while already at max."
407
+ }
408
+ ],
409
+ "attributes": [
410
+ {
411
+ "description": "Current progress value.",
412
+ "name": "value",
413
+ "type": {
414
+ "text": "number"
415
+ },
416
+ "fieldName": "value"
417
+ },
418
+ {
419
+ "description": "Initial uncontrolled value. Has no effect after the first host write.",
420
+ "name": "default-value",
421
+ "type": {
422
+ "text": "number | undefined"
423
+ },
424
+ "fieldName": "defaultValue"
425
+ },
426
+ {
427
+ "description": "When present, the component removes the native `<progress>`'s `value`\nattribute instead of asking the consumer to bind `undefined` to it —\nbinding `undefined` to a live `<progress>.value` throws.",
428
+ "name": "indeterminate",
429
+ "type": {
430
+ "text": "boolean"
431
+ },
432
+ "default": "false",
433
+ "fieldName": "indeterminate"
434
+ },
435
+ {
436
+ "description": "Controls the live value display.\n\n- Absent (default) — no value shown.\n- `overlay` (or bare `display`) — centered on the bar.\n- `display=\"inline-start\"` — rendered before the track, inline in the grid.\n- `display=\"inline-end\"` — rendered after the track, inline in the grid.",
437
+ "name": "display",
438
+ "type": {
439
+ "text": "DisplayValue"
440
+ },
441
+ "default": "null",
442
+ "fieldName": "display"
443
+ },
444
+ {
445
+ "description": "Screen-reader value text. When set, forwarded as `aria-valuetext` on the\nnative `<progress>` and used as the default formatted display text.",
446
+ "name": "value-text",
447
+ "type": {
448
+ "text": "string"
449
+ },
450
+ "default": "''",
451
+ "fieldName": "valueText"
452
+ },
453
+ {
454
+ "description": "Orientation; reflected as an attribute and forwarded to `aria-orientation`.",
455
+ "name": "orientation",
456
+ "type": {
457
+ "text": "'horizontal' | 'vertical'"
458
+ },
459
+ "default": "'horizontal'",
460
+ "fieldName": "orientation"
461
+ },
462
+ {
463
+ "description": "Visual-only dimming; native `<progress>` has no functional disabled state.",
464
+ "name": "disabled",
465
+ "type": {
466
+ "text": "boolean"
467
+ },
468
+ "default": "false",
469
+ "fieldName": "disabled"
470
+ }
471
+ ],
472
+ "superclass": {
473
+ "name": "LitElement",
474
+ "package": "lit"
475
+ },
476
+ "tagName": "rc-progress",
477
+ "customElement": true
478
+ }
479
+ ],
480
+ "exports": [
481
+ {
482
+ "kind": "js",
483
+ "name": "RCProgress",
484
+ "declaration": {
485
+ "name": "RCProgress",
486
+ "module": "src/rc-progress.ts"
487
+ }
488
+ },
489
+ {
490
+ "kind": "js",
491
+ "name": "default",
492
+ "declaration": {
493
+ "name": "RCProgress",
494
+ "module": "src/rc-progress.ts"
495
+ }
496
+ }
497
+ ]
498
+ }
499
+ ]
500
+ }
@@ -0,0 +1,316 @@
1
+ import { LitElement as d, css as v, nothing as a, html as h } from "lit";
2
+ import { property as n } from "lit/decorators.js";
3
+ import { ifDefined as g } from "lit/directives/if-defined.js";
4
+ import { NativeChildController as f } from "@rcarls/rc-common";
5
+ var m = Object.defineProperty, _ = Object.getOwnPropertyDescriptor, o = (i, e, t, l) => {
6
+ for (var s = l > 1 ? void 0 : l ? _(e, t) : e, u = i.length - 1, p; u >= 0; u--)
7
+ (p = i[u]) && (s = (l ? p(e, t, s) : p(s)) || s);
8
+ return l && s && m(e, t, s), s;
9
+ };
10
+ const y = {
11
+ fromAttribute(i) {
12
+ return i === null ? null : i === "" || i === "overlay" ? "overlay" : i === "inline-start" ? "inline-start" : i === "inline-end" ? "inline-end" : null;
13
+ },
14
+ toAttribute(i) {
15
+ return i;
16
+ }
17
+ }, c = class c extends d {
18
+ constructor() {
19
+ super(...arguments), this._valueInitialized = !1, this.indeterminate = !1, this.disabled = !1, this.display = null, this.valueText = "", this.orientation = "horizontal", this._$nativeProgress = null, this._completedDispatched = !1, this._progressObserver = null, this._nativeProgressController = new f(
20
+ this,
21
+ {
22
+ selector: ":scope > progress",
23
+ observe: !0,
24
+ onChange: (e, t) => this._setupProgress(e, t),
25
+ onMissing: () => {
26
+ }
27
+ }
28
+ ), this._onDefaultSlotChange = () => {
29
+ this._nativeProgressController.sync(), this.requestUpdate();
30
+ };
31
+ }
32
+ get value() {
33
+ return this._value ?? this._defaultValue ?? this._nativeProgressValue;
34
+ }
35
+ set value(e) {
36
+ const t = this.value;
37
+ this._value = e ?? void 0, this._valueInitialized = !0, this._applyValueToNative(this.value), this.requestUpdate("value", t);
38
+ }
39
+ get defaultValue() {
40
+ return this._defaultValue;
41
+ }
42
+ set defaultValue(e) {
43
+ const t = this._defaultValue;
44
+ this._defaultValue = e, !this._valueInitialized && this._value === void 0 && e !== void 0 && (this._applyValueToNative(e), this.requestUpdate("value", void 0)), this.requestUpdate("defaultValue", t);
45
+ }
46
+ /**
47
+ * Maximum progress value, read directly from the native `<progress>`
48
+ * child's own `max` IDL property (native default `1`) rather than
49
+ * duplicated as a separate host attribute — the consumer already owns it
50
+ * by setting `max` on the slotted `<progress>` element.
51
+ */
52
+ get max() {
53
+ return this._$nativeProgress?.max ?? 1;
54
+ }
55
+ disconnectedCallback() {
56
+ this._progressObserver?.disconnect(), super.disconnectedCallback();
57
+ }
58
+ updated(e) {
59
+ const t = this._$nativeProgress;
60
+ t && this._syncAriaAttributes(t), e.has("indeterminate") && this._applyIndeterminate(), (e.has("value") || e.has("indeterminate")) && this._checkComplete();
61
+ }
62
+ render() {
63
+ if (!this._$nativeProgress)
64
+ return a;
65
+ const t = h`
66
+ <span part="value-display" class="rc-progress-value" aria-hidden="true">
67
+ <slot name="value-display">${this._displayText}</slot>
68
+ </span>
69
+ `;
70
+ return h`
71
+ <div
72
+ part="root"
73
+ class="rc-progress-root"
74
+ data-display=${this.display ?? a}
75
+ data-orientation=${this.orientation}
76
+ data-disabled=${this.disabled ? "" : a}
77
+ data-has-value-text=${this.valueText ? "" : a}
78
+ >
79
+ ${this.display === "inline-start" ? t : a}
80
+
81
+ <span part="control" class="rc-progress-control">
82
+ <span part="track" class="rc-progress-track" aria-hidden="true">
83
+ <span
84
+ part="fill"
85
+ class="rc-progress-fill"
86
+ style=${g(this.indeterminate ? void 0 : this._fillStyle())}
87
+ ></span>
88
+ </span>
89
+
90
+ <slot @slotchange=${this._onDefaultSlotChange}></slot>
91
+ ${this.display === "overlay" ? t : a}
92
+ </span>
93
+
94
+ ${this.display === "inline-end" ? t : a}
95
+ </div>
96
+ `;
97
+ }
98
+ get _displayText() {
99
+ if (this.valueText)
100
+ return this.valueText;
101
+ if (this.indeterminate)
102
+ return "";
103
+ const e = this.max > 0 ? this.value / this.max * 100 : 0;
104
+ return `${Math.round(e)}%`;
105
+ }
106
+ get _nativeProgressValue() {
107
+ const e = this._$nativeProgress?.value;
108
+ return e === void 0 || isNaN(e) ? 0 : e;
109
+ }
110
+ _setupProgress(e, t) {
111
+ if (this._progressObserver?.disconnect(), this._progressObserver = null, !e) {
112
+ this._$nativeProgress = null;
113
+ return;
114
+ }
115
+ this._$nativeProgress = e, this._applyInitialValueToNative(), this._applyIndeterminate(), typeof MutationObserver == "function" && (this._progressObserver = new MutationObserver(() => {
116
+ this.indeterminate && this._applyIndeterminate(), this.requestUpdate(), this._checkComplete();
117
+ }), this._progressObserver.observe(e, {
118
+ attributes: !0,
119
+ attributeFilter: ["max", "value"]
120
+ })), this.requestUpdate();
121
+ }
122
+ _applyInitialValueToNative() {
123
+ if (this._value !== void 0) {
124
+ this._applyValueToNative(this._value);
125
+ return;
126
+ }
127
+ if (this._defaultValue !== void 0) {
128
+ this._applyValueToNative(this._defaultValue);
129
+ return;
130
+ }
131
+ }
132
+ _applyValueToNative(e) {
133
+ !this._$nativeProgress || this.indeterminate || (this._$nativeProgress.value = e);
134
+ }
135
+ /**
136
+ * Adds or removes the native `<progress>`'s `value` attribute/property to
137
+ * reflect `indeterminate` — the one piece of state this component owns so
138
+ * consumers never bind `undefined` to a live `<progress>.value` themselves.
139
+ */
140
+ _applyIndeterminate() {
141
+ const e = this._$nativeProgress;
142
+ e && (this.indeterminate ? (e.hasAttribute("value") && (this._nativeValueBeforeIndeterminate = e.value), e.removeAttribute("value")) : (e.value = this._value ?? this._defaultValue ?? this._nativeValueBeforeIndeterminate ?? this._nativeProgressValue, this._nativeValueBeforeIndeterminate = void 0));
143
+ }
144
+ _syncAriaAttributes(e) {
145
+ this.valueText ? e.setAttribute("aria-valuetext", this.valueText) : e.removeAttribute("aria-valuetext"), this.orientation === "vertical" ? e.setAttribute("aria-orientation", "vertical") : e.removeAttribute("aria-orientation");
146
+ }
147
+ _checkComplete() {
148
+ const e = !this.indeterminate && this.max > 0 && this.value >= this.max;
149
+ e && !this._completedDispatched ? (this._completedDispatched = !0, this.dispatchEvent(
150
+ new CustomEvent("rc-progress-complete", { bubbles: !0, composed: !0 })
151
+ )) : e || (this._completedDispatched = !1);
152
+ }
153
+ _fillStyle() {
154
+ const e = this.max > 0 ? Math.min(100, Math.max(0, this.value / this.max * 100)) : 0;
155
+ return this.orientation === "vertical" ? `inset-block-start:${(100 - e).toFixed(3)}%;block-size:${e.toFixed(3)}%` : `inline-size:${e.toFixed(3)}%`;
156
+ }
157
+ };
158
+ c.styles = v`
159
+ :host {
160
+ display: block;
161
+ }
162
+
163
+ .rc-progress-root {
164
+ display: grid;
165
+ gap: var(--rc-progress-gap, var(--rc-control-gap, 0.5rem));
166
+ align-items: center;
167
+ font-family: var(--rc-font-family, inherit);
168
+ font-size: var(--rc-font-size, inherit);
169
+ line-height: var(--rc-line-height, normal);
170
+ }
171
+
172
+ .rc-progress-root[data-display='inline-start'] {
173
+ grid-template-columns: auto minmax(0, 1fr);
174
+ }
175
+
176
+ .rc-progress-root[data-display='inline-end'] {
177
+ grid-template-columns: minmax(0, 1fr) auto;
178
+ }
179
+
180
+ .rc-progress-control {
181
+ position: relative;
182
+ display: block;
183
+ min-width: 0;
184
+ /*
185
+ * Everything this wraps (the track, the fill, the slotted <progress>)
186
+ * is position: absolute, contributing nothing to normal-flow height.
187
+ * Without an explicit block-size here, this collapses to 0px and the
188
+ * whole bar renders invisible whenever no value-display text (the
189
+ * only other thing that could give the shared grid row a height) is
190
+ * shown alongside it — the default, since display is unset unless a
191
+ * consumer opts into inline-start/inline-end/overlay.
192
+ */
193
+ block-size: var(--rc-progress-control-size, 0.5rem);
194
+ }
195
+
196
+ .rc-progress-track,
197
+ .rc-progress-fill {
198
+ position: absolute;
199
+ pointer-events: none;
200
+ }
201
+
202
+ .rc-progress-track {
203
+ inset: 0;
204
+ block-size: var(--rc-progress-control-size, 0.5rem);
205
+ background: var(--rc-progress-track-background, CanvasText);
206
+ opacity: var(--rc-progress-track-opacity, 0.25);
207
+ border-radius: var(--rc-progress-track-radius, var(--rc-control-radius, 0));
208
+ overflow: hidden;
209
+ z-index: 0;
210
+ }
211
+
212
+ ::slotted(progress) {
213
+ position: absolute;
214
+ inset: 0;
215
+ inline-size: 100%;
216
+ block-size: 100%;
217
+ margin: 0;
218
+ opacity: 0;
219
+ z-index: 2;
220
+ }
221
+
222
+ .rc-progress-fill {
223
+ inset-block: 0;
224
+ inset-inline-start: 0;
225
+ background: var(--rc-progress-fill-background, var(--rc-accent, Highlight));
226
+ border-radius: inherit;
227
+ z-index: 1;
228
+ transition: inline-size 0.15s ease-out;
229
+ }
230
+
231
+ :host([indeterminate]) .rc-progress-fill {
232
+ inline-size: 40% !important;
233
+ animation: rc-progress-indeterminate 1.4s ease-in-out infinite;
234
+ }
235
+
236
+ @keyframes rc-progress-indeterminate {
237
+ 0% {
238
+ inset-inline-start: -40%;
239
+ }
240
+ 100% {
241
+ inset-inline-start: 100%;
242
+ }
243
+ }
244
+
245
+ @media (prefers-reduced-motion: reduce) {
246
+ :host([indeterminate]) .rc-progress-fill {
247
+ animation: none;
248
+ inset-inline-start: 0;
249
+ }
250
+ }
251
+
252
+ .rc-progress-value {
253
+ font-variant-numeric: tabular-nums;
254
+ white-space: nowrap;
255
+ color: var(--rc-progress-value-color, var(--rc-text-disabled, GrayText));
256
+ }
257
+
258
+ .rc-progress-root[data-display='overlay'] .rc-progress-value {
259
+ position: absolute;
260
+ inset: 0;
261
+ display: flex;
262
+ align-items: center;
263
+ justify-content: center;
264
+ pointer-events: none;
265
+ z-index: 3;
266
+ }
267
+
268
+ :host([orientation='vertical']) {
269
+ display: inline-block;
270
+ }
271
+
272
+ :host([orientation='vertical']) .rc-progress-control {
273
+ inline-size: var(--rc-progress-control-size, 0.5rem);
274
+ block-size: var(--rc-progress-vertical-size, 12.5rem);
275
+ }
276
+
277
+ :host([orientation='vertical']) .rc-progress-track {
278
+ inline-size: var(--rc-progress-control-size, 0.5rem);
279
+ block-size: auto;
280
+ }
281
+
282
+ :host([orientation='vertical']) .rc-progress-fill {
283
+ inset-inline: 0;
284
+ inset-block-start: auto;
285
+ }
286
+
287
+ :host([disabled]) {
288
+ opacity: 0.5;
289
+ }
290
+ `;
291
+ let r = c;
292
+ o([
293
+ n({ type: Number })
294
+ ], r.prototype, "value", 1);
295
+ o([
296
+ n({ type: Number, attribute: "default-value" })
297
+ ], r.prototype, "defaultValue", 1);
298
+ o([
299
+ n({ type: Boolean, reflect: !0 })
300
+ ], r.prototype, "indeterminate", 2);
301
+ o([
302
+ n({ type: Boolean, reflect: !0 })
303
+ ], r.prototype, "disabled", 2);
304
+ o([
305
+ n({ reflect: !0, converter: y })
306
+ ], r.prototype, "display", 2);
307
+ o([
308
+ n({ attribute: "value-text" })
309
+ ], r.prototype, "valueText", 2);
310
+ o([
311
+ n({ reflect: !0 })
312
+ ], r.prototype, "orientation", 2);
313
+ export {
314
+ r as R
315
+ };
316
+ //# sourceMappingURL=rc-progress-Q8vVdyM1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-progress-Q8vVdyM1.js","sources":["../src/rc-progress.ts"],"sourcesContent":["import { LitElement, css, html, nothing } from 'lit';\nimport type { ComplexAttributeConverter, PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\nimport { NativeChildController, warnMissingDirectChild } from '@rcarls/rc-common';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-progress': RCProgress;\n }\n\n interface HTMLElementEventMap {\n 'rc-progress-complete': CustomEvent<Record<string, never>>;\n }\n}\n\ntype DisplayValue = 'inline-start' | 'inline-end' | 'overlay' | null;\n\n/**\n * Normalises the `display` attribute.\n * A bare boolean attribute (`display` with no value) maps to `'overlay'` so\n * the reflected attribute is always an explicit string, never an empty string.\n */\nconst displayConverter: ComplexAttributeConverter<DisplayValue> = {\n fromAttribute(v: string | null): DisplayValue {\n if (v === null) {\n return null;\n }\n\n if (v === '' || v === 'overlay') {\n return 'overlay';\n }\n\n if (v === 'inline-start') {\n return 'inline-start';\n }\n\n if (v === 'inline-end') {\n return 'inline-end';\n }\n\n return null;\n },\n toAttribute(v: DisplayValue): string | null {\n return v;\n },\n};\n\n/**\n * Enhances a native `<progress>` with a custom track/fill and an optional\n * formatted value display, following the same progressive-enhancement shape\n * as `rc-slider`.\n *\n * Deliberately does one job: it does not render a dialog, own any phase\n * state, or assume anything about where it's placed. Compose it with\n * `rc-dialog`, a card, or an inline status row as needed.\n *\n * Label association:\n * - Explicit `for`/`id`: `<label for=\"sync\">Sync</label><rc-progress><progress id=\"sync\" …></rc-progress>`\n * - Direct `aria-label` on the `<progress>`: `<progress aria-label=\"Sync\" …>`\n *\n * These patterns all work without JavaScript. The component does not render\n * a label itself — the consumer is responsible for accessible naming.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-progress rc-progress docs}\n *\n * @slot - Place a `<progress>` element here.\n * @slot value-display - Optional replacement for the rendered value text.\n *\n * @fires rc-progress-complete - Fires once when `value` reaches `max` while\n * not indeterminate. Does not re-fire on subsequent updates while already\n * at max.\n *\n * @attr value - Current progress value. Host writes are silent.\n * @attr default-value - Initial uncontrolled value. Has no effect after the first\n * host write.\n * @attr indeterminate - When present, the component removes the native `<progress>`'s\n * `value` attribute instead of asking the consumer to bind `undefined` to it.\n * @attr display - Controls the live value display: absent (none), `overlay` (centered on\n * the bar), `inline-start`, or `inline-end`.\n * @attr value-text - Screen-reader value text, forwarded as `aria-valuetext` on the\n * native `<progress>`. Also used as the default formatted display text when set.\n * @attr orientation - Orientation, forwarded to `aria-orientation`: `horizontal` or\n * `vertical`.\n * @attr disabled - Visual-only dimming; native `<progress>` has no functional disabled state.\n *\n * @cssprop [--rc-progress-control-size=0.5rem] - Track hit-area block size.\n * @cssprop [--rc-progress-vertical-size=12.5rem] - Track length when `orientation=\"vertical\"`.\n * @cssprop [--rc-progress-gap=var(--rc-control-gap)] - Gap between track and inline value display.\n * @cssprop [--rc-progress-track-background=CanvasText] - Unfilled track color.\n * @cssprop [--rc-progress-track-opacity=0.25] - Unfilled track opacity.\n * @cssprop [--rc-progress-track-radius=var(--rc-control-radius)] - Track border radius.\n * @cssprop [--rc-progress-fill-background=var(--rc-accent)] - Filled track color.\n * @cssprop [--rc-progress-value-color=var(--rc-text-disabled)] - Value display text color.\n *\n * @csspart root - Root layout wrapper.\n * @csspart control - Track positioning wrapper.\n * @csspart track - Visual track.\n * @csspart fill - Filled progress segment.\n * @csspart value-display - Rendered value text.\n */\nexport class RCProgress extends LitElement {\n static override styles = css`\n :host {\n display: block;\n }\n\n .rc-progress-root {\n display: grid;\n gap: var(--rc-progress-gap, var(--rc-control-gap, 0.5rem));\n align-items: center;\n font-family: var(--rc-font-family, inherit);\n font-size: var(--rc-font-size, inherit);\n line-height: var(--rc-line-height, normal);\n }\n\n .rc-progress-root[data-display='inline-start'] {\n grid-template-columns: auto minmax(0, 1fr);\n }\n\n .rc-progress-root[data-display='inline-end'] {\n grid-template-columns: minmax(0, 1fr) auto;\n }\n\n .rc-progress-control {\n position: relative;\n display: block;\n min-width: 0;\n /*\n * Everything this wraps (the track, the fill, the slotted <progress>)\n * is position: absolute, contributing nothing to normal-flow height.\n * Without an explicit block-size here, this collapses to 0px and the\n * whole bar renders invisible whenever no value-display text (the\n * only other thing that could give the shared grid row a height) is\n * shown alongside it — the default, since display is unset unless a\n * consumer opts into inline-start/inline-end/overlay.\n */\n block-size: var(--rc-progress-control-size, 0.5rem);\n }\n\n .rc-progress-track,\n .rc-progress-fill {\n position: absolute;\n pointer-events: none;\n }\n\n .rc-progress-track {\n inset: 0;\n block-size: var(--rc-progress-control-size, 0.5rem);\n background: var(--rc-progress-track-background, CanvasText);\n opacity: var(--rc-progress-track-opacity, 0.25);\n border-radius: var(--rc-progress-track-radius, var(--rc-control-radius, 0));\n overflow: hidden;\n z-index: 0;\n }\n\n ::slotted(progress) {\n position: absolute;\n inset: 0;\n inline-size: 100%;\n block-size: 100%;\n margin: 0;\n opacity: 0;\n z-index: 2;\n }\n\n .rc-progress-fill {\n inset-block: 0;\n inset-inline-start: 0;\n background: var(--rc-progress-fill-background, var(--rc-accent, Highlight));\n border-radius: inherit;\n z-index: 1;\n transition: inline-size 0.15s ease-out;\n }\n\n :host([indeterminate]) .rc-progress-fill {\n inline-size: 40% !important;\n animation: rc-progress-indeterminate 1.4s ease-in-out infinite;\n }\n\n @keyframes rc-progress-indeterminate {\n 0% {\n inset-inline-start: -40%;\n }\n 100% {\n inset-inline-start: 100%;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host([indeterminate]) .rc-progress-fill {\n animation: none;\n inset-inline-start: 0;\n }\n }\n\n .rc-progress-value {\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n color: var(--rc-progress-value-color, var(--rc-text-disabled, GrayText));\n }\n\n .rc-progress-root[data-display='overlay'] .rc-progress-value {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n z-index: 3;\n }\n\n :host([orientation='vertical']) {\n display: inline-block;\n }\n\n :host([orientation='vertical']) .rc-progress-control {\n inline-size: var(--rc-progress-control-size, 0.5rem);\n block-size: var(--rc-progress-vertical-size, 12.5rem);\n }\n\n :host([orientation='vertical']) .rc-progress-track {\n inline-size: var(--rc-progress-control-size, 0.5rem);\n block-size: auto;\n }\n\n :host([orientation='vertical']) .rc-progress-fill {\n inset-inline: 0;\n inset-block-start: auto;\n }\n\n :host([disabled]) {\n opacity: 0.5;\n }\n `;\n\n private _value: number | undefined;\n private _defaultValue: number | undefined;\n private _valueInitialized = false;\n\n /** Current progress value. */\n @property({ type: Number })\n get value(): number {\n return this._value ?? this._defaultValue ?? this._nativeProgressValue;\n }\n\n set value(value: number | undefined) {\n const oldValue = this.value;\n\n this._value = value ?? undefined;\n this._valueInitialized = true;\n this._applyValueToNative(this.value);\n this.requestUpdate('value', oldValue);\n }\n\n /** Initial uncontrolled value. Has no effect after the first host write. */\n @property({ type: Number, attribute: 'default-value' })\n get defaultValue(): number | undefined {\n return this._defaultValue;\n }\n\n set defaultValue(value: number | undefined) {\n const oldValue = this._defaultValue;\n\n this._defaultValue = value;\n\n if (!this._valueInitialized && this._value === undefined && value !== undefined) {\n this._applyValueToNative(value);\n this.requestUpdate('value', undefined);\n }\n\n this.requestUpdate('defaultValue', oldValue);\n }\n\n /**\n * Maximum progress value, read directly from the native `<progress>`\n * child's own `max` IDL property (native default `1`) rather than\n * duplicated as a separate host attribute — the consumer already owns it\n * by setting `max` on the slotted `<progress>` element.\n */\n get max(): number {\n return this._$nativeProgress?.max ?? 1;\n }\n\n /**\n * When present, the component removes the native `<progress>`'s `value`\n * attribute instead of asking the consumer to bind `undefined` to it —\n * binding `undefined` to a live `<progress>.value` throws.\n */\n @property({ type: Boolean, reflect: true }) indeterminate = false;\n\n /** Visual-only dimming; native `<progress>` has no functional disabled state. */\n @property({ type: Boolean, reflect: true }) disabled = false;\n\n /**\n * Controls the live value display.\n *\n * - Absent (default) — no value shown.\n * - `overlay` (or bare `display`) — centered on the bar.\n * - `display=\"inline-start\"` — rendered before the track, inline in the grid.\n * - `display=\"inline-end\"` — rendered after the track, inline in the grid.\n */\n @property({ reflect: true, converter: displayConverter })\n display: DisplayValue = null;\n\n /**\n * Screen-reader value text. When set, forwarded as `aria-valuetext` on the\n * native `<progress>` and used as the default formatted display text.\n */\n @property({ attribute: 'value-text' }) valueText = '';\n\n /** Orientation; reflected as an attribute and forwarded to `aria-orientation`. */\n @property({ reflect: true }) orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n private _$nativeProgress: HTMLProgressElement | null = null;\n private _completedDispatched = false;\n private _nativeValueBeforeIndeterminate: number | undefined;\n private _progressObserver: MutationObserver | null = null;\n\n private readonly _nativeProgressController = new NativeChildController<HTMLProgressElement>(\n this,\n {\n selector: ':scope > progress',\n observe: true,\n onChange: ($progress, $previous) => this._setupProgress($progress, $previous),\n onMissing: () => {\n if (import.meta.env.DEV) {\n warnMissingDirectChild(this, {\n selector: ':scope > progress',\n message: '[rc-progress] Requires a child <progress> element.',\n });\n }\n },\n },\n );\n\n override disconnectedCallback(): void {\n this._progressObserver?.disconnect();\n\n super.disconnectedCallback();\n }\n\n override updated(changed: PropertyValues): void {\n const $progress = this._$nativeProgress;\n\n if ($progress) {\n this._syncAriaAttributes($progress);\n }\n\n if (changed.has('indeterminate')) {\n this._applyIndeterminate();\n }\n\n if (changed.has('value') || changed.has('indeterminate')) {\n this._checkComplete();\n }\n }\n\n override render() {\n const $progress = this._$nativeProgress;\n\n if (!$progress) {\n return nothing;\n }\n\n const valueDisplay = html`\n <span part=\"value-display\" class=\"rc-progress-value\" aria-hidden=\"true\">\n <slot name=\"value-display\">${this._displayText}</slot>\n </span>\n `;\n\n return html`\n <div\n part=\"root\"\n class=\"rc-progress-root\"\n data-display=${this.display ?? nothing}\n data-orientation=${this.orientation}\n data-disabled=${this.disabled ? '' : nothing}\n data-has-value-text=${this.valueText ? '' : nothing}\n >\n ${this.display === 'inline-start' ? valueDisplay : nothing}\n\n <span part=\"control\" class=\"rc-progress-control\">\n <span part=\"track\" class=\"rc-progress-track\" aria-hidden=\"true\">\n <span\n part=\"fill\"\n class=\"rc-progress-fill\"\n style=${ifDefined(this.indeterminate ? undefined : this._fillStyle())}\n ></span>\n </span>\n\n <slot @slotchange=${this._onDefaultSlotChange}></slot>\n ${this.display === 'overlay' ? valueDisplay : nothing}\n </span>\n\n ${this.display === 'inline-end' ? valueDisplay : nothing}\n </div>\n `;\n }\n\n private get _displayText(): string {\n if (this.valueText) {\n return this.valueText;\n }\n\n if (this.indeterminate) {\n return '';\n }\n\n const percent = this.max > 0 ? (this.value / this.max) * 100 : 0;\n\n return `${Math.round(percent)}%`;\n }\n\n private get _nativeProgressValue(): number {\n const value = this._$nativeProgress?.value;\n\n return value === undefined || isNaN(value) ? 0 : value;\n }\n\n private _setupProgress(\n $progress: HTMLProgressElement | null,\n $previous?: HTMLProgressElement | null,\n ): void {\n void $previous;\n\n this._progressObserver?.disconnect();\n this._progressObserver = null;\n\n if (!$progress) {\n this._$nativeProgress = null;\n\n return;\n }\n\n this._$nativeProgress = $progress;\n this._applyInitialValueToNative();\n this._applyIndeterminate();\n\n if (typeof MutationObserver === 'function') {\n this._progressObserver = new MutationObserver(() => {\n if (this.indeterminate) {\n this._applyIndeterminate();\n }\n\n this.requestUpdate();\n this._checkComplete();\n });\n\n this._progressObserver.observe($progress, {\n attributes: true,\n attributeFilter: ['max', 'value'],\n });\n }\n\n this.requestUpdate();\n }\n\n private _onDefaultSlotChange = (): void => {\n this._nativeProgressController.sync();\n this.requestUpdate();\n };\n\n private _applyInitialValueToNative(): void {\n if (this._value !== undefined) {\n this._applyValueToNative(this._value);\n\n return;\n }\n\n if (this._defaultValue !== undefined) {\n this._applyValueToNative(this._defaultValue);\n\n return;\n }\n\n // With no host-owned value, keep reading the live native control rather\n // than copying its initial value into component state. This preserves the\n // native element as the uncontrolled source of truth.\n }\n\n private _applyValueToNative(value: number): void {\n if (!this._$nativeProgress || this.indeterminate) {\n return;\n }\n\n this._$nativeProgress.value = value;\n }\n\n /**\n * Adds or removes the native `<progress>`'s `value` attribute/property to\n * reflect `indeterminate` — the one piece of state this component owns so\n * consumers never bind `undefined` to a live `<progress>.value` themselves.\n */\n private _applyIndeterminate(): void {\n const $progress = this._$nativeProgress;\n\n if (!$progress) {\n return;\n }\n\n if (this.indeterminate) {\n if ($progress.hasAttribute('value')) {\n this._nativeValueBeforeIndeterminate = $progress.value;\n }\n\n $progress.removeAttribute('value');\n } else {\n $progress.value =\n this._value ??\n this._defaultValue ??\n this._nativeValueBeforeIndeterminate ??\n this._nativeProgressValue;\n\n this._nativeValueBeforeIndeterminate = undefined;\n }\n }\n\n private _syncAriaAttributes($progress: HTMLProgressElement): void {\n if (this.valueText) {\n $progress.setAttribute('aria-valuetext', this.valueText);\n } else {\n $progress.removeAttribute('aria-valuetext');\n }\n\n if (this.orientation === 'vertical') {\n $progress.setAttribute('aria-orientation', 'vertical');\n } else {\n $progress.removeAttribute('aria-orientation');\n }\n }\n\n private _checkComplete(): void {\n const isComplete = !this.indeterminate && this.max > 0 && this.value >= this.max;\n\n if (isComplete && !this._completedDispatched) {\n this._completedDispatched = true;\n\n this.dispatchEvent(\n new CustomEvent('rc-progress-complete', { bubbles: true, composed: true }),\n );\n } else if (!isComplete) {\n this._completedDispatched = false;\n }\n }\n\n private _fillStyle(): string {\n const percent = this.max > 0 ? Math.min(100, Math.max(0, (this.value / this.max) * 100)) : 0;\n\n if (this.orientation === 'vertical') {\n return `inset-block-start:${(100 - percent).toFixed(3)}%;block-size:${percent.toFixed(3)}%`;\n }\n\n return `inline-size:${percent.toFixed(3)}%`;\n }\n}\n\nexport default RCProgress;\n"],"names":["displayConverter","v","_RCProgress","LitElement","NativeChildController","$progress","$previous","value","oldValue","changed","nothing","valueDisplay","html","ifDefined","percent","isComplete","css","RCProgress","__decorateClass","property"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { R as e } from "./rc-progress-Q8vVdyM1.js";
2
+ customElements.get("rc-progress") || customElements.define("rc-progress", e);
3
+ export {
4
+ e as RCProgress
5
+ };
6
+ //# sourceMappingURL=rc-progress-define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-progress-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCProgress } from './index.js';\n\ncustomElements.get('rc-progress') || customElements.define('rc-progress', RCProgress);\n\nexport * from './index.js';\n"],"names":["RCProgress"],"mappings":";AAEA,eAAe,IAAI,aAAa,KAAK,eAAe,OAAO,eAAeA,CAAU;"}
@@ -0,0 +1,5 @@
1
+ import { R as s } from "./rc-progress-Q8vVdyM1.js";
2
+ export {
3
+ s as RCProgress
4
+ };
5
+ //# sourceMappingURL=rc-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-progress.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1 @@
1
+ export * from './index.js';
@@ -0,0 +1 @@
1
+ export * from './rc-progress.js';
@@ -0,0 +1,130 @@
1
+ import { LitElement, nothing, PropertyValues } from 'lit';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'rc-progress': RCProgress;
5
+ }
6
+ interface HTMLElementEventMap {
7
+ 'rc-progress-complete': CustomEvent<Record<string, never>>;
8
+ }
9
+ }
10
+ type DisplayValue = 'inline-start' | 'inline-end' | 'overlay' | null;
11
+ /**
12
+ * Enhances a native `<progress>` with a custom track/fill and an optional
13
+ * formatted value display, following the same progressive-enhancement shape
14
+ * as `rc-slider`.
15
+ *
16
+ * Deliberately does one job: it does not render a dialog, own any phase
17
+ * state, or assume anything about where it's placed. Compose it with
18
+ * `rc-dialog`, a card, or an inline status row as needed.
19
+ *
20
+ * Label association:
21
+ * - Explicit `for`/`id`: `<label for="sync">Sync</label><rc-progress><progress id="sync" …></rc-progress>`
22
+ * - Direct `aria-label` on the `<progress>`: `<progress aria-label="Sync" …>`
23
+ *
24
+ * These patterns all work without JavaScript. The component does not render
25
+ * a label itself — the consumer is responsible for accessible naming.
26
+ *
27
+ * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-progress rc-progress docs}
28
+ *
29
+ * @slot - Place a `<progress>` element here.
30
+ * @slot value-display - Optional replacement for the rendered value text.
31
+ *
32
+ * @fires rc-progress-complete - Fires once when `value` reaches `max` while
33
+ * not indeterminate. Does not re-fire on subsequent updates while already
34
+ * at max.
35
+ *
36
+ * @attr value - Current progress value. Host writes are silent.
37
+ * @attr default-value - Initial uncontrolled value. Has no effect after the first
38
+ * host write.
39
+ * @attr indeterminate - When present, the component removes the native `<progress>`'s
40
+ * `value` attribute instead of asking the consumer to bind `undefined` to it.
41
+ * @attr display - Controls the live value display: absent (none), `overlay` (centered on
42
+ * the bar), `inline-start`, or `inline-end`.
43
+ * @attr value-text - Screen-reader value text, forwarded as `aria-valuetext` on the
44
+ * native `<progress>`. Also used as the default formatted display text when set.
45
+ * @attr orientation - Orientation, forwarded to `aria-orientation`: `horizontal` or
46
+ * `vertical`.
47
+ * @attr disabled - Visual-only dimming; native `<progress>` has no functional disabled state.
48
+ *
49
+ * @cssprop [--rc-progress-control-size=0.5rem] - Track hit-area block size.
50
+ * @cssprop [--rc-progress-vertical-size=12.5rem] - Track length when `orientation="vertical"`.
51
+ * @cssprop [--rc-progress-gap=var(--rc-control-gap)] - Gap between track and inline value display.
52
+ * @cssprop [--rc-progress-track-background=CanvasText] - Unfilled track color.
53
+ * @cssprop [--rc-progress-track-opacity=0.25] - Unfilled track opacity.
54
+ * @cssprop [--rc-progress-track-radius=var(--rc-control-radius)] - Track border radius.
55
+ * @cssprop [--rc-progress-fill-background=var(--rc-accent)] - Filled track color.
56
+ * @cssprop [--rc-progress-value-color=var(--rc-text-disabled)] - Value display text color.
57
+ *
58
+ * @csspart root - Root layout wrapper.
59
+ * @csspart control - Track positioning wrapper.
60
+ * @csspart track - Visual track.
61
+ * @csspart fill - Filled progress segment.
62
+ * @csspart value-display - Rendered value text.
63
+ */
64
+ export declare class RCProgress extends LitElement {
65
+ static styles: import('lit').CSSResult;
66
+ private _value;
67
+ private _defaultValue;
68
+ private _valueInitialized;
69
+ /** Current progress value. */
70
+ get value(): number;
71
+ set value(value: number | undefined);
72
+ /** Initial uncontrolled value. Has no effect after the first host write. */
73
+ get defaultValue(): number | undefined;
74
+ set defaultValue(value: number | undefined);
75
+ /**
76
+ * Maximum progress value, read directly from the native `<progress>`
77
+ * child's own `max` IDL property (native default `1`) rather than
78
+ * duplicated as a separate host attribute — the consumer already owns it
79
+ * by setting `max` on the slotted `<progress>` element.
80
+ */
81
+ get max(): number;
82
+ /**
83
+ * When present, the component removes the native `<progress>`'s `value`
84
+ * attribute instead of asking the consumer to bind `undefined` to it —
85
+ * binding `undefined` to a live `<progress>.value` throws.
86
+ */
87
+ indeterminate: boolean;
88
+ /** Visual-only dimming; native `<progress>` has no functional disabled state. */
89
+ disabled: boolean;
90
+ /**
91
+ * Controls the live value display.
92
+ *
93
+ * - Absent (default) — no value shown.
94
+ * - `overlay` (or bare `display`) — centered on the bar.
95
+ * - `display="inline-start"` — rendered before the track, inline in the grid.
96
+ * - `display="inline-end"` — rendered after the track, inline in the grid.
97
+ */
98
+ display: DisplayValue;
99
+ /**
100
+ * Screen-reader value text. When set, forwarded as `aria-valuetext` on the
101
+ * native `<progress>` and used as the default formatted display text.
102
+ */
103
+ valueText: string;
104
+ /** Orientation; reflected as an attribute and forwarded to `aria-orientation`. */
105
+ orientation: 'horizontal' | 'vertical';
106
+ private _$nativeProgress;
107
+ private _completedDispatched;
108
+ private _nativeValueBeforeIndeterminate;
109
+ private _progressObserver;
110
+ private readonly _nativeProgressController;
111
+ disconnectedCallback(): void;
112
+ updated(changed: PropertyValues): void;
113
+ render(): typeof nothing | import('lit').TemplateResult<1>;
114
+ private get _displayText();
115
+ private get _nativeProgressValue();
116
+ private _setupProgress;
117
+ private _onDefaultSlotChange;
118
+ private _applyInitialValueToNative;
119
+ private _applyValueToNative;
120
+ /**
121
+ * Adds or removes the native `<progress>`'s `value` attribute/property to
122
+ * reflect `indeterminate` — the one piece of state this component owns so
123
+ * consumers never bind `undefined` to a live `<progress>.value` themselves.
124
+ */
125
+ private _applyIndeterminate;
126
+ private _syncAriaAttributes;
127
+ private _checkComplete;
128
+ private _fillStyle;
129
+ }
130
+ export default RCProgress;
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@rcarls/rc-progress",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.1.0",
7
+ "description": "Native <progress> enhancer with a formatted value display, restyleable track/fill, and a built-in fix for the indeterminate/undefined-binding footgun.",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/richardcarls/rc-webcomponents.git",
11
+ "directory": "packages/rc-progress"
12
+ },
13
+ "homepage": "https://richardcarls.github.io/rc-webcomponents/components/rc-progress",
14
+ "license": "MIT",
15
+ "type": "module",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "module": "./dist/rc-progress.js",
20
+ "exports": {
21
+ ".": {
22
+ "import": {
23
+ "types": "./dist/types/packages/rc-progress/src/index.d.ts",
24
+ "default": "./dist/rc-progress.js"
25
+ }
26
+ },
27
+ "./define": {
28
+ "import": {
29
+ "types": "./dist/types/packages/rc-progress/src/define.d.ts",
30
+ "default": "./dist/rc-progress-define.js"
31
+ }
32
+ }
33
+ },
34
+ "types": "./dist/types/packages/rc-progress/src/index.d.ts",
35
+ "sideEffects": [
36
+ "./dist/rc-progress-define.js"
37
+ ],
38
+ "customElements": "dist/custom-elements.json",
39
+ "scripts": {
40
+ "build": "tsc && vite build && cem analyze",
41
+ "cem:analyze": "cem analyze",
42
+ "preview": "vite preview",
43
+ "test:browser": "vitest --run",
44
+ "test:browser:chrome": "vitest --run --project=chromium",
45
+ "test:browser:firefox": "vitest --run --project=firefox"
46
+ },
47
+ "devDependencies": {
48
+ "@custom-elements-manifest/analyzer": "0.11.0",
49
+ "@vitest/browser-playwright": "4.1.5",
50
+ "lit": "^3.0.0",
51
+ "playwright": "^1.56.0",
52
+ "rollup": "^4.60.2",
53
+ "typescript": "~5.9.3",
54
+ "vite": "^7.1.7",
55
+ "vite-plugin-dts": "^4.5.4",
56
+ "vitest": "^4.0.6",
57
+ "vitest-browser-lit": "^1.0.1"
58
+ },
59
+ "dependencies": {
60
+ "@rcarls/rc-common": "0.5.0"
61
+ },
62
+ "peerDependencies": {
63
+ "lit": "^3.0.0"
64
+ }
65
+ }