@aquera/nile-elements 2.0.2 → 2.0.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.
Files changed (41) hide show
  1. package/README.md +3 -0
  2. package/dist/index.cjs.js +1 -1
  3. package/dist/index.esm.js +1 -1
  4. package/dist/index.js +949 -640
  5. package/dist/nile-segmented-progress-bar/index.cjs.js +2 -0
  6. package/dist/nile-segmented-progress-bar/index.cjs.js.map +1 -0
  7. package/dist/nile-segmented-progress-bar/index.esm.js +1 -0
  8. package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.cjs.js +2 -0
  9. package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.cjs.js.map +1 -0
  10. package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.css.cjs.js +2 -0
  11. package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.css.cjs.js.map +1 -0
  12. package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.css.esm.js +243 -0
  13. package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.esm.js +69 -0
  14. package/dist/nile-wysiwyg-editor/engine/commands.cjs.js +1 -1
  15. package/dist/nile-wysiwyg-editor/engine/commands.cjs.js.map +1 -1
  16. package/dist/nile-wysiwyg-editor/engine/commands.esm.js +1 -1
  17. package/dist/src/index.d.ts +2 -0
  18. package/dist/src/index.js +1 -0
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/nile-segmented-progress-bar/index.d.ts +2 -0
  21. package/dist/src/nile-segmented-progress-bar/index.js +2 -0
  22. package/dist/src/nile-segmented-progress-bar/index.js.map +1 -0
  23. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.css.d.ts +9 -0
  24. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.css.js +252 -0
  25. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.css.js.map +1 -0
  26. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.d.ts +135 -0
  27. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.js +373 -0
  28. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.js.map +1 -0
  29. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.test.d.ts +1 -0
  30. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.test.js +961 -0
  31. package/dist/src/nile-segmented-progress-bar/nile-segmented-progress-bar.test.js.map +1 -0
  32. package/dist/src/version.js +1 -1
  33. package/dist/src/version.js.map +1 -1
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +2 -1
  36. package/src/index.ts +5 -0
  37. package/src/nile-segmented-progress-bar/index.ts +5 -0
  38. package/src/nile-segmented-progress-bar/nile-segmented-progress-bar.css.ts +254 -0
  39. package/src/nile-segmented-progress-bar/nile-segmented-progress-bar.test.ts +1298 -0
  40. package/src/nile-segmented-progress-bar/nile-segmented-progress-bar.ts +437 -0
  41. package/vscode-html-custom-data.json +113 -0
@@ -0,0 +1,437 @@
1
+ /**
2
+ * Copyright Aquera Inc 2026
3
+ *
4
+ * This source code is licensed under the BSD-3-Clause license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import { html, nothing } from 'lit';
9
+ import { styles } from './nile-segmented-progress-bar.css';
10
+ import { classMap } from 'lit/directives/class-map.js';
11
+ import { styleMap } from 'lit/directives/style-map.js';
12
+ import { customElement, property } from 'lit/decorators.js';
13
+ import NileElement from '../internal/nile-element';
14
+ import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
15
+ import '../nile-lite-tooltip/index';
16
+
17
+ /** A single slice of the distribution rendered by `nile-segmented-progress-bar`. */
18
+ export interface NileProgressSegment {
19
+ /** Legend label, also used in the default tooltip text. */
20
+ label: string;
21
+ /** Raw magnitude of this segment. */
22
+ value: number;
23
+ /** Any CSS color; falls back to the palette rotation when omitted. */
24
+ color?: string;
25
+ /** Overrides the default tooltip content for this segment. */
26
+ tooltip?: string;
27
+ }
28
+
29
+ /** Placement values forwarded to `nile-lite-tooltip`. */
30
+ export type NileSegmentTooltipPlacement =
31
+ | 'top'
32
+ | 'top-start'
33
+ | 'top-end'
34
+ | 'right'
35
+ | 'right-start'
36
+ | 'right-end'
37
+ | 'bottom'
38
+ | 'bottom-start'
39
+ | 'bottom-end'
40
+ | 'left'
41
+ | 'left-start'
42
+ | 'left-end'
43
+ | 'auto'
44
+ | 'auto-start'
45
+ | 'auto-end';
46
+
47
+ /** The number of palette classes declared in the stylesheet. */
48
+ const PALETTE_LENGTH = 10;
49
+
50
+ /**
51
+ * Nile segmented progress bar component.
52
+ *
53
+ * @tag nile-segmented-progress-bar
54
+ *
55
+ * @summary A config-driven, responsive multi-segment progress / distribution bar
56
+ * with an optional wrapping legend — a single rounded track split into colored
57
+ * proportional segments (for example Success / Failure / Errors / Running / Other).
58
+ * @status experimental
59
+ *
60
+ * @event nile-segment-click - Emitted when a segment or its legend entry is activated by click,
61
+ * `Enter` or `Space`. The `detail` contains `{ segment, index, percentage }`.
62
+ *
63
+ * @csspart container - The component's base wrapper.
64
+ * @csspart label - The optional heading above the bar.
65
+ * @csspart bar - The bar/track element (also exposed as `track`).
66
+ * @csspart track - The bar/track element (also exposed as `bar`).
67
+ * @csspart segment - An individual colored segment inside the track.
68
+ * @csspart legend - The wrapping legend row.
69
+ * @csspart legend-item - A single legend entry (swatch + label + value).
70
+ * @csspart legend-swatch - The small rounded square in the segment color.
71
+ * @csspart legend-label - The legend entry's label text.
72
+ * @csspart legend-value - The legend entry's bold value.
73
+ *
74
+ * @example
75
+ * <nile-segmented-progress-bar
76
+ * label="Run outcomes"
77
+ * .segments=${[
78
+ * { label: 'Success', value: 45623 },
79
+ * { label: 'Failure', value: 50342 },
80
+ * { label: 'Errors', value: 682 },
81
+ * { label: 'Running', value: 166 },
82
+ * { label: 'Other', value: 1552 },
83
+ * ]}
84
+ * ></nile-segmented-progress-bar>
85
+ */
86
+ @customElement('nile-segmented-progress-bar')
87
+ export class NileSegmentedProgressBar extends NileElement {
88
+ static styles: CSSResultGroup = styles;
89
+
90
+ /** The segments to distribute across the bar. This is the component's config. */
91
+ @property({ type: Array }) segments: NileProgressSegment[] = [];
92
+
93
+ /** Optional heading rendered above the bar. Nothing renders when empty. */
94
+ @property({ type: String, reflect: true }) label = '';
95
+
96
+ /** Renders the legend below the bar. */
97
+ @property({ type: Boolean, attribute: 'show-legend' }) showLegend = true;
98
+
99
+ /** Wraps every segment in a `nile-lite-tooltip`. */
100
+ @property({ type: Boolean, attribute: 'show-tooltip' }) showTooltip = true;
101
+
102
+ /** Renders the bold value alongside each legend label. */
103
+ @property({ type: Boolean, attribute: 'show-values' }) showValues = true;
104
+
105
+ /** The thickness of the bar. */
106
+ @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
107
+
108
+ /**
109
+ * Optional denominator. When omitted the denominator is the sum of the segment
110
+ * values, so the segments always fill 100%. When larger than the sum, the
111
+ * remainder renders as an unfilled track.
112
+ */
113
+ @property({ type: Number }) total?: number;
114
+
115
+ /** Rounds the bar's outer ends. */
116
+ @property({ type: Boolean }) rounded = true;
117
+
118
+ /**
119
+ * Minimum rendered width, in pixels, of a non-zero segment. Guarantees sub-1%
120
+ * segments stay a discernible sliver. The largest segment absorbs whatever
121
+ * overflow this introduces, so the row still totals exactly 100%.
122
+ */
123
+ @property({ type: Number, attribute: 'min-segment-width' })
124
+ minSegmentWidth = 2;
125
+
126
+ /** Passed straight through to `nile-lite-tooltip`'s `placement`. */
127
+ @property({ attribute: 'tooltip-placement' })
128
+ tooltipPlacement: NileSegmentTooltipPlacement = 'top';
129
+
130
+ /* #region Math */
131
+
132
+ /** Coerces a configured value into a usable, non-negative, finite number. */
133
+ private sanitizeValue(value: unknown): number {
134
+ const numeric = Number(value);
135
+ if (!Number.isFinite(numeric) || numeric < 0) return 0;
136
+ return numeric;
137
+ }
138
+
139
+ /** The sanitized magnitude of every configured segment, in config order. */
140
+ private get values(): number[] {
141
+ const list = Array.isArray(this.segments) ? this.segments : [];
142
+ return list.map(segment => this.sanitizeValue(segment?.value));
143
+ }
144
+
145
+ /** The sum of every sanitized segment value. */
146
+ private get sum(): number {
147
+ return this.values.reduce((runningTotal, value) => runningTotal + value, 0);
148
+ }
149
+
150
+ /** The denominator the percentages are computed against. */
151
+ private get denominator(): number {
152
+ const sum = this.sum;
153
+ const total = Number(this.total);
154
+ if (Number.isFinite(total) && total > sum) return total;
155
+ return sum;
156
+ }
157
+
158
+ /** Each segment's share of the denominator, in config order. */
159
+ private get percentages(): number[] {
160
+ const denominator = this.denominator;
161
+ if (denominator <= 0) return this.values.map(() => 0);
162
+ return this.values.map(value => (value / denominator) * 100);
163
+ }
164
+
165
+ /**
166
+ * The index of the widest rendered segment. That segment is the one allowed to
167
+ * shrink, so it absorbs the overflow introduced by `minSegmentWidth` on the
168
+ * tiny ones and the row still adds up to exactly 100% of the track.
169
+ */
170
+ private get largestIndex(): number {
171
+ const values = this.values;
172
+ let largest = -1;
173
+ let largestValue = 0;
174
+ values.forEach((value, index) => {
175
+ if (value > largestValue) {
176
+ largestValue = value;
177
+ largest = index;
178
+ }
179
+ });
180
+ return largest;
181
+ }
182
+
183
+ /** Formats a percentage to one decimal, trimming a trailing `.0`. */
184
+ private formatPercentage(percentage: number): string {
185
+ if (!Number.isFinite(percentage)) return '0';
186
+ const rounded = Math.round(percentage * 10) / 10;
187
+ return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);
188
+ }
189
+
190
+ /* #endregion */
191
+
192
+ /* #region Text */
193
+
194
+ /** The default tooltip / aria text for a segment. */
195
+ private describeSegment(index: number): string {
196
+ const segment = this.segments?.[index];
197
+ const value = this.values[index] ?? 0;
198
+ const percentage = this.formatPercentage(this.percentages[index] ?? 0);
199
+ return `${segment?.label ?? ''}: ${value} (${percentage}%)`;
200
+ }
201
+
202
+ /** The tooltip content for a segment, honouring a per-segment override. */
203
+ private tooltipFor(index: number): string {
204
+ const override = this.segments?.[index]?.tooltip;
205
+ return override && override.length > 0
206
+ ? override
207
+ : this.describeSegment(index);
208
+ }
209
+
210
+ /**
211
+ * A single sentence describing the whole distribution, used as the track's
212
+ * accessible name so screen readers get the breakdown without tabbing it.
213
+ */
214
+ private get accessibleSummary(): string {
215
+ const list = Array.isArray(this.segments) ? this.segments : [];
216
+ const parts = list.map((_, index) => this.describeSegment(index));
217
+ const body = parts.length > 0 ? parts.join(', ') : 'No data';
218
+ return this.label ? `${this.label}: ${body}` : body;
219
+ }
220
+
221
+ /* #endregion */
222
+
223
+ /* #region Validation */
224
+
225
+ override updated(changedProperties: PropertyValues): void {
226
+ super.updated(changedProperties);
227
+ if (changedProperties.has('segments') || changedProperties.has('total')) {
228
+ this.validateConfig();
229
+ }
230
+ }
231
+
232
+ /** Logs invalid config the way `nile-progress-bar` reports out-of-range values. */
233
+ private validateConfig(): void {
234
+ const list = Array.isArray(this.segments) ? this.segments : [];
235
+
236
+ list.forEach((segment, index) => {
237
+ const numeric = Number(segment?.value);
238
+ if (!Number.isFinite(numeric)) {
239
+ console.error(
240
+ `[NileSegmentedProgressBar]: Invalid value (${String(
241
+ segment?.value
242
+ )}) detected at segment index ${index}. Value must be a finite number. Falling back to 0.`
243
+ );
244
+ return;
245
+ }
246
+ if (numeric < 0) {
247
+ console.error(
248
+ `[NileSegmentedProgressBar]: Invalid value (${numeric}) detected at segment index ${index}. Value must be greater than or equal to 0. Falling back to 0.`
249
+ );
250
+ }
251
+ });
252
+
253
+ const total = Number(this.total);
254
+ if (this.total !== undefined && this.total !== null) {
255
+ if (!Number.isFinite(total) || total < 0) {
256
+ console.error(
257
+ `[NileSegmentedProgressBar]: Invalid total (${String(
258
+ this.total
259
+ )}) detected. Total must be a finite number greater than or equal to 0. Falling back to the sum of the segment values.`
260
+ );
261
+ } else if (total < this.sum) {
262
+ console.error(
263
+ `[NileSegmentedProgressBar]: Invalid total (${total}) detected. Total must be greater than or equal to the sum of the segment values (${this.sum}). Falling back to the sum.`
264
+ );
265
+ }
266
+ }
267
+ }
268
+
269
+ /* #endregion */
270
+
271
+ /* #region Interaction */
272
+
273
+ private activate(index: number): void {
274
+ const segment = this.segments?.[index];
275
+ if (!segment) return;
276
+ this.emit('nile-segment-click', {
277
+ segment,
278
+ index,
279
+ percentage: this.percentages[index] ?? 0,
280
+ });
281
+ }
282
+
283
+ /**
284
+ * `Enter` and `Space` activate a segment or legend entry. The affordances are
285
+ * `role="button"` elements rather than native buttons, so activation is wired
286
+ * up explicitly and a key press never double-fires alongside a synthetic click.
287
+ */
288
+ private handleKeyDown(event: KeyboardEvent, index: number): void {
289
+ if (
290
+ event.key !== 'Enter' &&
291
+ event.key !== ' ' &&
292
+ event.key !== 'Spacebar'
293
+ ) {
294
+ return;
295
+ }
296
+ event.preventDefault();
297
+ this.activate(index);
298
+ }
299
+
300
+ /* #endregion */
301
+
302
+ /* #region Render */
303
+
304
+ private renderSegment(index: number): TemplateResult | typeof nothing {
305
+ const segment = this.segments[index];
306
+ const percentage = this.percentages[index] ?? 0;
307
+ if (percentage <= 0) return nothing;
308
+
309
+ const isLargest = index === this.largestIndex;
310
+ const minWidth = Math.max(0, Number(this.minSegmentWidth) || 0);
311
+ const description = this.describeSegment(index);
312
+
313
+ const bar = html`
314
+ <div
315
+ part="segment"
316
+ role="button"
317
+ tabindex="0"
318
+ data-index=${index}
319
+ class=${classMap({
320
+ 'segmented-progress-bar__segment': true,
321
+ [`segmented-progress-bar__palette-${index % PALETTE_LENGTH}`]:
322
+ !segment.color,
323
+ })}
324
+ style=${styleMap({
325
+ flexBasis: `${percentage}%`,
326
+ // Only the widest segment may shrink, so it soaks up every pixel the
327
+ // min-width floors add to the row and the total stays at 100%.
328
+ flexShrink: isLargest ? '1' : '0',
329
+ minWidth: isLargest ? '0px' : `${minWidth}px`,
330
+ backgroundColor: segment.color || undefined,
331
+ })}
332
+ aria-label=${description}
333
+ @click=${() => this.activate(index)}
334
+ @keydown=${(event: KeyboardEvent) => this.handleKeyDown(event, index)}
335
+ ></div>
336
+ `;
337
+
338
+ if (!this.showTooltip) return bar;
339
+
340
+ return html`
341
+ <nile-lite-tooltip
342
+ size="small"
343
+ content=${this.tooltipFor(index)}
344
+ placement=${this.tooltipPlacement}
345
+ >
346
+ ${bar}
347
+ </nile-lite-tooltip>
348
+ `;
349
+ }
350
+
351
+ private renderLegendItem(index: number): TemplateResult {
352
+ const segment = this.segments[index];
353
+ const value = this.values[index] ?? 0;
354
+
355
+ return html`
356
+ <div
357
+ part="legend-item"
358
+ role="button"
359
+ tabindex="0"
360
+ data-index=${index}
361
+ class="segmented-progress-bar__legend-item"
362
+ aria-label=${this.describeSegment(index)}
363
+ @click=${() => this.activate(index)}
364
+ @keydown=${(event: KeyboardEvent) => this.handleKeyDown(event, index)}
365
+ >
366
+ <span
367
+ part="legend-swatch"
368
+ aria-hidden="true"
369
+ class=${classMap({
370
+ 'segmented-progress-bar__legend-swatch': true,
371
+ [`segmented-progress-bar__palette-${index % PALETTE_LENGTH}`]:
372
+ !segment.color,
373
+ })}
374
+ style=${styleMap({ backgroundColor: segment.color || undefined })}
375
+ ></span>
376
+ <span part="legend-label" class="segmented-progress-bar__legend-label"
377
+ >${segment.label}</span
378
+ >
379
+ ${this.showValues
380
+ ? html`<span
381
+ part="legend-value"
382
+ class="segmented-progress-bar__legend-value"
383
+ >${value}</span
384
+ >`
385
+ : nothing}
386
+ </div>
387
+ `;
388
+ }
389
+
390
+ render(): TemplateResult {
391
+ const segments = Array.isArray(this.segments) ? this.segments : [];
392
+
393
+ return html`
394
+ <div
395
+ part="container"
396
+ class=${classMap({
397
+ 'segmented-progress-bar': true,
398
+ 'segmented-progress-bar--small': this.size === 'small',
399
+ 'segmented-progress-bar--medium': this.size === 'medium',
400
+ 'segmented-progress-bar--large': this.size === 'large',
401
+ 'segmented-progress-bar--rounded': this.rounded,
402
+ })}
403
+ >
404
+ ${this.label
405
+ ? html`<div part="label" class="segmented-progress-bar__label">
406
+ ${this.label}
407
+ </div>`
408
+ : nothing}
409
+
410
+ <div
411
+ part="bar track"
412
+ class="segmented-progress-bar__track"
413
+ role="group"
414
+ aria-label=${this.accessibleSummary}
415
+ >
416
+ ${segments.map((_, index) => this.renderSegment(index))}
417
+ </div>
418
+
419
+ ${this.showLegend
420
+ ? html`<div part="legend" class="segmented-progress-bar__legend">
421
+ ${segments.map((_, index) => this.renderLegendItem(index))}
422
+ </div>`
423
+ : nothing}
424
+ </div>
425
+ `;
426
+ }
427
+
428
+ /* #endregion */
429
+ }
430
+
431
+ export default NileSegmentedProgressBar;
432
+
433
+ declare global {
434
+ interface HTMLElementTagNameMap {
435
+ 'nile-segmented-progress-bar': NileSegmentedProgressBar;
436
+ }
437
+ }
@@ -5916,6 +5916,119 @@
5916
5916
  }
5917
5917
  ]
5918
5918
  },
5919
+ {
5920
+ "name": "nile-segmented-progress-bar",
5921
+ "description": "Nile segmented progress bar component.\n\nEvents:\n\n * `nile-segment-click` {} - Emitted when a segment or its legend entry is activated by click,\n`Enter` or `Space`. The `detail` contains `{ segment, index, percentage }`.\n\nAttributes:\n\n * `segments` {`NileProgressSegment[]`} - The segments to distribute across the bar. This is the component's config.\n\n * `label` {`string`} - Optional heading rendered above the bar. Nothing renders when empty.\n\n * `show-legend` {`boolean`} - Renders the legend below the bar.\n\n * `show-tooltip` {`boolean`} - Wraps every segment in a `nile-lite-tooltip`.\n\n * `show-values` {`boolean`} - Renders the bold value alongside each legend label.\n\n * `size` {`\"small\" | \"medium\" | \"large\"`} - The thickness of the bar.\n\n * `total` {`number | undefined`} - Optional denominator. When omitted the denominator is the sum of the segment\nvalues, so the segments always fill 100%. When larger than the sum, the\nremainder renders as an unfilled track.\n\n * `rounded` {`boolean`} - Rounds the bar's outer ends.\n\n * `min-segment-width` {`number`} - Minimum rendered width, in pixels, of a non-zero segment. Guarantees sub-1%\nsegments stay a discernible sliver. The largest segment absorbs whatever\noverflow this introduces, so the row still totals exactly 100%.\n\n * `tooltip-placement` {`\"left\" | \"right\" | \"top\" | \"top-start\" | \"top-end\" | \"right-start\" | \"right-end\" | \"bottom\" | \"bottom-start\" | \"bottom-end\" | \"left-start\" | \"left-end\" | \"auto\" | \"auto-start\" | \"auto-end\"`} - Passed straight through to `nile-lite-tooltip`'s `placement`.\n\nProperties:\n\n * `styles` - \n\n * `segments` {`NileProgressSegment[]`} - The segments to distribute across the bar. This is the component's config.\n\n * `label` {`string`} - Optional heading rendered above the bar. Nothing renders when empty.\n\n * `showLegend` {`boolean`} - Renders the legend below the bar.\n\n * `showTooltip` {`boolean`} - Wraps every segment in a `nile-lite-tooltip`.\n\n * `showValues` {`boolean`} - Renders the bold value alongside each legend label.\n\n * `size` {`\"small\" | \"medium\" | \"large\"`} - The thickness of the bar.\n\n * `total` {`number | undefined`} - Optional denominator. When omitted the denominator is the sum of the segment\nvalues, so the segments always fill 100%. When larger than the sum, the\nremainder renders as an unfilled track.\n\n * `rounded` {`boolean`} - Rounds the bar's outer ends.\n\n * `minSegmentWidth` {`number`} - Minimum rendered width, in pixels, of a non-zero segment. Guarantees sub-1%\nsegments stay a discernible sliver. The largest segment absorbs whatever\noverflow this introduces, so the row still totals exactly 100%.\n\n * `tooltipPlacement` {`\"left\" | \"right\" | \"top\" | \"top-start\" | \"top-end\" | \"right-start\" | \"right-end\" | \"bottom\" | \"bottom-start\" | \"bottom-end\" | \"left-start\" | \"left-end\" | \"auto\" | \"auto-start\" | \"auto-end\"`} - Passed straight through to `nile-lite-tooltip`'s `placement`.\n\n * `values` {`number[]`} - The sanitized magnitude of every configured segment, in config order.\n\n * `sum` {`number`} - The sum of every sanitized segment value.\n\n * `denominator` {`number`} - The denominator the percentages are computed against.\n\n * `percentages` {`number[]`} - Each segment's share of the denominator, in config order.\n\n * `largestIndex` {`number`} - The index of the widest rendered segment. That segment is the one allowed to\nshrink, so it absorbs the overflow introduced by `minSegmentWidth` on the\ntiny ones and the row still adds up to exactly 100% of the track.\n\n * `accessibleSummary` {`string`} - A single sentence describing the whole distribution, used as the track's\naccessible name so screen readers get the breakdown without tabbing it.\n\n * `override` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
5922
+ "attributes": [
5923
+ {
5924
+ "name": "segments",
5925
+ "description": "`segments` {`NileProgressSegment[]`} - The segments to distribute across the bar. This is the component's config.\n\nProperty: segments\n\nDefault: "
5926
+ },
5927
+ {
5928
+ "name": "label",
5929
+ "description": "`label` {`string`} - Optional heading rendered above the bar. Nothing renders when empty.\n\nProperty: label\n\nDefault: "
5930
+ },
5931
+ {
5932
+ "name": "show-legend",
5933
+ "description": "`show-legend` {`boolean`} - Renders the legend below the bar.\n\nProperty: showLegend\n\nDefault: true",
5934
+ "valueSet": "v"
5935
+ },
5936
+ {
5937
+ "name": "show-tooltip",
5938
+ "description": "`show-tooltip` {`boolean`} - Wraps every segment in a `nile-lite-tooltip`.\n\nProperty: showTooltip\n\nDefault: true",
5939
+ "valueSet": "v"
5940
+ },
5941
+ {
5942
+ "name": "show-values",
5943
+ "description": "`show-values` {`boolean`} - Renders the bold value alongside each legend label.\n\nProperty: showValues\n\nDefault: true",
5944
+ "valueSet": "v"
5945
+ },
5946
+ {
5947
+ "name": "size",
5948
+ "description": "`size` {`\"small\" | \"medium\" | \"large\"`} - The thickness of the bar.\n\nProperty: size\n\nDefault: medium",
5949
+ "values": [
5950
+ {
5951
+ "name": "small"
5952
+ },
5953
+ {
5954
+ "name": "medium"
5955
+ },
5956
+ {
5957
+ "name": "large"
5958
+ }
5959
+ ]
5960
+ },
5961
+ {
5962
+ "name": "total",
5963
+ "description": "`total` {`number | undefined`} - Optional denominator. When omitted the denominator is the sum of the segment\nvalues, so the segments always fill 100%. When larger than the sum, the\nremainder renders as an unfilled track.\n\nProperty: total",
5964
+ "values": []
5965
+ },
5966
+ {
5967
+ "name": "rounded",
5968
+ "description": "`rounded` {`boolean`} - Rounds the bar's outer ends.\n\nProperty: rounded\n\nDefault: true",
5969
+ "valueSet": "v"
5970
+ },
5971
+ {
5972
+ "name": "min-segment-width",
5973
+ "description": "`min-segment-width` {`number`} - Minimum rendered width, in pixels, of a non-zero segment. Guarantees sub-1%\nsegments stay a discernible sliver. The largest segment absorbs whatever\noverflow this introduces, so the row still totals exactly 100%.\n\nProperty: minSegmentWidth\n\nDefault: 2"
5974
+ },
5975
+ {
5976
+ "name": "tooltip-placement",
5977
+ "description": "`tooltip-placement` {`\"left\" | \"right\" | \"top\" | \"top-start\" | \"top-end\" | \"right-start\" | \"right-end\" | \"bottom\" | \"bottom-start\" | \"bottom-end\" | \"left-start\" | \"left-end\" | \"auto\" | \"auto-start\" | \"auto-end\"`} - Passed straight through to `nile-lite-tooltip`'s `placement`.\n\nProperty: tooltipPlacement\n\nDefault: top",
5978
+ "values": [
5979
+ {
5980
+ "name": "left"
5981
+ },
5982
+ {
5983
+ "name": "right"
5984
+ },
5985
+ {
5986
+ "name": "top"
5987
+ },
5988
+ {
5989
+ "name": "top-start"
5990
+ },
5991
+ {
5992
+ "name": "top-end"
5993
+ },
5994
+ {
5995
+ "name": "right-start"
5996
+ },
5997
+ {
5998
+ "name": "right-end"
5999
+ },
6000
+ {
6001
+ "name": "bottom"
6002
+ },
6003
+ {
6004
+ "name": "bottom-start"
6005
+ },
6006
+ {
6007
+ "name": "bottom-end"
6008
+ },
6009
+ {
6010
+ "name": "left-start"
6011
+ },
6012
+ {
6013
+ "name": "left-end"
6014
+ },
6015
+ {
6016
+ "name": "auto"
6017
+ },
6018
+ {
6019
+ "name": "auto-start"
6020
+ },
6021
+ {
6022
+ "name": "auto-end"
6023
+ }
6024
+ ]
6025
+ },
6026
+ {
6027
+ "name": "onnile-segment-click",
6028
+ "description": "`nile-segment-click` {} - Emitted when a segment or its legend entry is activated by click,\n`Enter` or `Space`. The `detail` contains `{ segment, index, percentage }`."
6029
+ }
6030
+ ]
6031
+ },
5919
6032
  {
5920
6033
  "name": "nile-select",
5921
6034
  "description": "Events:\n\n * `nile-change` {} - Emitted when the control's value changes.\n\n * `nile-clear` {} - Emitted when the control's value is cleared.\n\n * `nile-input` {} - Emitted when the control receives input.\n\n * `nile-focus` {} - Emitted when the control gains focus.\n\n * `nile-blur` {} - Emitted when the control loses focus.\n\n * `nile-show` {} - Emitted when the select's menu opens.\n\n * `nile-after-show` {} - Emitted after the select's menu opens and all animations are complete.\n\n * `nile-hide` {} - Emitted when the select's menu closes.\n\n * `nile-after-hide` {} - Emitted after the select's menu closes and all animations are complete.\n\n * `nile-invalid` {} - Emitted when the form control has been checked for validity and its constraints aren't satisfied.\n\n * `nile-search` {} - Emitted when the user types in the search input. The event payload includes the search query for backend search functionality.\n\n * `nile-scroll` {} - Emitted when the user scrolls within the listbox. The event payload includes scroll position information.\n\n * `nile-scroll-start` {} - Emitted when the user starts scrolling within the listbox.\n\n * `nile-scroll-end` {} - Emitted when the user stops scrolling and reaches the bottom of the listbox (debounced).\n\nSlots:\n\n * ` ` {} - The listbox options. Must be `<nile-option>` elements. You can use `<nile-divider>` to group items visually.\n\n * `label` {} - The input's label. Alternatively, you can use the `label` attribute.\n\n * `prefix` {} - Used to prepend a presentational icon or similar element to the combobox.\n\n * `clear-icon` {} - An icon to use in lieu of the default clear icon.\n\n * `expand-icon` {} - The icon to show when the control is expanded and collapsed. Rotates on open and close.\n\n * `help-text` {} - Text that describes how to use the input. Alternatively, you can use the `help-text` attribute.\n\n * `pre-footer` {} - Content to display at the bottom of the dropdown listbox. Useful for action buttons like \"Create New\". In multi-select mode, appears above the \"Show Selected\" / \"Clear All\" bar.\n\nAttributes:\n\n * `size` {`\"small\" | \"medium\" | \"large\"`} - The select's size.\n\n * `placeholder` {`string`} - Placeholder text to show as a hint when the select is empty.\n\n * `searchEnabled` {`boolean`} - \n\n * `legacy` {`boolean`} - \n\n * `tickOnSelect` {`boolean`} - Variant: show a tick on the right of the selected option (single-select). Propagated to options.\n\n * `internal-search-placeholder` {`string`} - \n\n * `enableVisibilityEffect` {`boolean`} - \n\n * `blockValueChange` {`boolean`} - \n\n * `disableLocalSearch` {`boolean`} - \n\n * `optionsLoading` {`boolean`} - \n\n * `noWidthSync` {`boolean`} - \n\n * `portal` {`boolean`} - When true, the listbox will be appended to the document body instead of the parent container.\nThis is useful when the parent has overflow: hidden, clip-path, or transform applied.\n\n * `multiple` {`string | boolean`} - Allows more than one option to be selected.\n\n * `helpText` {`string`} - \n\n * `help-text` {`string`} - \n\n * `autoResize` {`boolean`} - \n\n * `error-message` {`string`} - \n\n * `warning` {`boolean`} - Sets the input to a warning state, changing its visual appearance.\n\n * `error` {`boolean`} - Sets the input to an error state, changing its visual appearance.\n\n * `success` {`boolean`} - Sets the input to a success state, changing its visual appearance.\n\n * `max-options-visible` {`number`} - The maximum number of selected options to show when `multiple` is true. After the maximum, \"+n\" will be shown to\nindicate the number of additional items that are selected. Set to 0 to remove the limit.\n\n * `clearable` {`boolean`} - Adds a clear button when the select is not empty.\n\n * `open` {`boolean`} - Indicates whether or not the select is open. You can toggle this attribute to show and hide the menu, or you can\nuse the `show()` and `hide()` methods and this attribute will reflect the select's open state.\n\n * `hoist` {`boolean`} - Enable this option to prevent the listbox from being clipped when the component is placed inside a container with\n`overflow: auto|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all, scenarios.\n\n * `filled` {`boolean`} - Draws a filled select.\n\n * `pill` {`boolean`} - Draws a pill-style select with rounded edges.\n\n * `label` {`string`} - The select's label. If you need to display HTML, use the `label` slot instead.\n\n * `placement` {`ComboboxPlacement`} - The preferred placement of the select's menu. Note that the actual placement may vary as needed to keep the listbox\ninside of the viewport.\n\n * `showSelected` {`boolean`} - \n\n * `enableTabClose` {`boolean`} - \n\n * `showNoResults` {`boolean`} - \n\n * `noResultsMessage` {`string`} - \n\n * `data` - \n\n * `enableVirtualScroll` {`boolean`} - \n\n * `enableGroupHeader` {`boolean`} - To enable the group header in the select\n\n * `autoFocusSearch` {`boolean`} - To auto focus the search input when the select is opened\n\n * `loading` {`boolean`} - loading indicator for virtual select\n\n * `stickyHeader` {`boolean`} - \n\n * `descriptionSearchEnabled` {`boolean`} - \n\n * `enableDescription` {`boolean`} - \n\n * `allowHtmlLabel` {`boolean`} - \n\n * `name` {`string`} - The name of the select, submitted as a name/value pair with form data.\n\n * `value` {`string | string[]`} - The current value of the select, submitted as a name/value pair with form data. When `multiple` is enabled, the\nvalue will be a space-delimited list of values based on the options selected.\n\n * `disabled` {`boolean`} - Disables the select control.\n\n * `form` {`string`} - By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you\nto place the form control outside of a form and associate it with the form that has this `id`. The form must be in\nthe same document or shadow root for this to work.\n\n * `required` {`boolean`} - The select's required attribute.\n\nProperties:\n\n * `styles` - \n\n * `formControlController` - \n\n * `virtualScrollHelper` - \n\n * `portalManager` - \n\n * `hasSlotController` - \n\n * `typeToSelectString` {`string`} - \n\n * `typeToSelectTimeout` {`number`} - \n\n * `scrollTimeout` {`number | undefined`} - \n\n * `scrolling` {`boolean`} - \n\n * `options` {`NileOption[]`} - \n\n * `resizeController` - \n\n * `visibilityManager` - \n\n * `popup` - \n\n * `combobox` {`HTMLSlotElement`} - \n\n * `displayInput` {`HTMLInputElement`} - \n\n * `valueInput` {`HTMLInputElement`} - \n\n * `listbox` {`HTMLSlotElement`} - \n\n * `hasFocus` {`boolean`} - \n\n * `displayLabel` {`string`} - \n\n * `currentOption` - \n\n * `selectedOptions` {`NileOption[]`} - \n\n * `oldValue` {`string | string[]`} - \n\n * `size` {`\"small\" | \"medium\" | \"large\"`} - The select's size.\n\n * `placeholder` {`string`} - Placeholder text to show as a hint when the select is empty.\n\n * `searchValue` {`string`} - Placeholder text to show as a hint when the select is empty.\n\n * `searchEnabled` {`boolean`} - \n\n * `legacy` {`boolean`} - \n\n * `tickOnSelect` {`boolean`} - Variant: show a tick on the right of the selected option (single-select). Propagated to options.\n\n * `internalSearchPlaceHolder` {`string`} - \n\n * `enableVisibilityEffect` {`boolean`} - \n\n * `blockValueChange` {`boolean`} - \n\n * `disableLocalSearch` {`boolean`} - \n\n * `optionsLoading` {`boolean`} - \n\n * `noWidthSync` {`boolean`} - \n\n * `portal` {`boolean`} - When true, the listbox will be appended to the document body instead of the parent container.\nThis is useful when the parent has overflow: hidden, clip-path, or transform applied.\n\n * `multiple` {`string | boolean`} - Allows more than one option to be selected.\n\n * `helpText` {`string`} - \n\n * `help_text` {`string`} - \n\n * `autoResize` {`boolean`} - \n\n * `errorMessage` {`string`} - \n\n * `warning` {`boolean`} - Sets the input to a warning state, changing its visual appearance.\n\n * `error` {`boolean`} - Sets the input to an error state, changing its visual appearance.\n\n * `success` {`boolean`} - Sets the input to a success state, changing its visual appearance.\n\n * `maxOptionsVisible` {`number`} - The maximum number of selected options to show when `multiple` is true. After the maximum, \"+n\" will be shown to\nindicate the number of additional items that are selected. Set to 0 to remove the limit.\n\n * `clearable` {`boolean`} - Adds a clear button when the select is not empty.\n\n * `open` {`boolean`} - Indicates whether or not the select is open. You can toggle this attribute to show and hide the menu, or you can\nuse the `show()` and `hide()` methods and this attribute will reflect the select's open state.\n\n * `hoist` {`boolean`} - Enable this option to prevent the listbox from being clipped when the component is placed inside a container with\n`overflow: auto|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all, scenarios.\n\n * `filled` {`boolean`} - Draws a filled select.\n\n * `pill` {`boolean`} - Draws a pill-style select with rounded edges.\n\n * `label` {`string`} - The select's label. If you need to display HTML, use the `label` slot instead.\n\n * `placement` {`ComboboxPlacement`} - The preferred placement of the select's menu. Note that the actual placement may vary as needed to keep the listbox\ninside of the viewport.\n\n * `showSelected` {`boolean`} - \n\n * `oldMaxOptionsVisible` {`number`} - \n\n * `enableTabClose` {`boolean`} - \n\n * `showNoResults` {`boolean`} - \n\n * `noResultsMessage` {`string`} - \n\n * `renderItemConfig` {`RenderItemConfig | undefined`} - Enhanced configuration for rendering items with support for display text, value, and search text\n\n * `data` - \n\n * `enableVirtualScroll` {`boolean`} - \n\n * `enableGroupHeader` {`boolean`} - To enable the group header in the select\n\n * `autoFocusSearch` {`boolean`} - To auto focus the search input when the select is opened\n\n * `loading` {`boolean`} - loading indicator for virtual select\n\n * `stickyHeader` {`boolean`} - \n\n * `descriptionSearchEnabled` {`boolean`} - \n\n * `enableDescription` {`boolean`} - \n\n * `allowHtmlLabel` {`boolean`} - \n\n * `handleWindowResize` - \n\n * `handleWindowScroll` - \n\n * `name` {`string`} - The name of the select, submitted as a name/value pair with form data.\n\n * `value` {`string | string[]`} - The current value of the select, submitted as a name/value pair with form data. When `multiple` is enabled, the\nvalue will be a space-delimited list of values based on the options selected.\n\n * `disabled` {`boolean`} - Disables the select control.\n\n * `defaultValue` {`string | string[]`} - The default value of the form control. Primarily used for resetting the form control.\n\n * `defaultChecked` {`boolean | undefined`} - \n\n * `form` {`string`} - By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you\nto place the form control outside of a form and associate it with the form that has this `id`. The form must be in\nthe same document or shadow root for this to work.\n\n * `pattern` {`string | undefined`} - \n\n * `min` {`string | number | Date | undefined`} - \n\n * `max` {`string | number | Date | undefined`} - \n\n * `step` {`number | \"any\" | undefined`} - \n\n * `required` {`boolean`} - The select's required attribute.\n\n * `minlength` {`number | undefined`} - \n\n * `maxlength` {`number | undefined`} - \n\n * `validity` {`ValidityState`} - Gets the validity state object\n\n * `validationMessage` {`string`} - Gets the validation message\n\n * `checkValidity` - \n\n * `getForm` - \n\n * `reportValidity` - \n\n * `setCustomValidity` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",