@radix-ng/primitives 0.50.0 → 1.0.0-beta.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.
Files changed (207) hide show
  1. package/collection/README.md +1 -0
  2. package/fesm2022/radix-ng-primitives-accordion.mjs +134 -66
  3. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  4. package/fesm2022/radix-ng-primitives-alert-dialog.mjs +224 -132
  5. package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
  6. package/fesm2022/radix-ng-primitives-arrow.mjs +26 -10
  7. package/fesm2022/radix-ng-primitives-arrow.mjs.map +1 -1
  8. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs +6 -6
  9. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs.map +1 -1
  10. package/fesm2022/radix-ng-primitives-avatar.mjs +68 -75
  11. package/fesm2022/radix-ng-primitives-avatar.mjs.map +1 -1
  12. package/fesm2022/radix-ng-primitives-button.mjs +123 -0
  13. package/fesm2022/radix-ng-primitives-button.mjs.map +1 -0
  14. package/fesm2022/radix-ng-primitives-calendar.mjs +104 -103
  15. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  16. package/fesm2022/radix-ng-primitives-checkbox.mjs +414 -80
  17. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  18. package/fesm2022/radix-ng-primitives-collapsible.mjs +193 -92
  19. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-collection.mjs +72 -0
  21. package/fesm2022/radix-ng-primitives-collection.mjs.map +1 -0
  22. package/fesm2022/radix-ng-primitives-config.mjs +5 -5
  23. package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
  24. package/fesm2022/radix-ng-primitives-context-menu.mjs +143 -427
  25. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  26. package/fesm2022/radix-ng-primitives-core.mjs +757 -757
  27. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-cropper.mjs +55 -53
  29. package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-date-field.mjs +93 -86
  31. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  32. package/fesm2022/radix-ng-primitives-dialog.mjs +658 -330
  33. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  34. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +98 -76
  35. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
  36. package/fesm2022/radix-ng-primitives-drawer.mjs +1059 -0
  37. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -0
  38. package/fesm2022/radix-ng-primitives-editable.mjs +20 -20
  39. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  40. package/fesm2022/radix-ng-primitives-field.mjs +363 -0
  41. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -0
  42. package/fesm2022/radix-ng-primitives-fieldset.mjs +79 -0
  43. package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -0
  44. package/fesm2022/radix-ng-primitives-focus-guards.mjs +3 -3
  45. package/fesm2022/radix-ng-primitives-focus-guards.mjs.map +1 -1
  46. package/fesm2022/radix-ng-primitives-focus-scope.mjs +29 -14
  47. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  48. package/fesm2022/radix-ng-primitives-input.mjs +172 -0
  49. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -0
  50. package/fesm2022/radix-ng-primitives-label.mjs +11 -11
  51. package/fesm2022/radix-ng-primitives-label.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-menu.mjs +1484 -353
  53. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-menubar.mjs +290 -162
  55. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  56. package/fesm2022/radix-ng-primitives-meter.mjs +271 -0
  57. package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -0
  58. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +1060 -1553
  59. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-number-field.mjs +1102 -366
  61. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-pagination.mjs +51 -51
  63. package/fesm2022/radix-ng-primitives-pagination.mjs.map +1 -1
  64. package/fesm2022/radix-ng-primitives-popover.mjs +980 -995
  65. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  66. package/fesm2022/radix-ng-primitives-popper.mjs +137 -82
  67. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  68. package/fesm2022/radix-ng-primitives-portal.mjs +40 -16
  69. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  70. package/fesm2022/radix-ng-primitives-presence.mjs +134 -246
  71. package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
  72. package/fesm2022/radix-ng-primitives-preview-card.mjs +997 -0
  73. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -0
  74. package/fesm2022/radix-ng-primitives-progress.mjs +231 -92
  75. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  76. package/fesm2022/radix-ng-primitives-radio.mjs +211 -70
  77. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  78. package/fesm2022/radix-ng-primitives-roving-focus.mjs +127 -77
  79. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  80. package/fesm2022/radix-ng-primitives-select.mjs +791 -511
  81. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  82. package/fesm2022/radix-ng-primitives-separator.mjs +16 -45
  83. package/fesm2022/radix-ng-primitives-separator.mjs.map +1 -1
  84. package/fesm2022/radix-ng-primitives-slider.mjs +976 -720
  85. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  86. package/fesm2022/radix-ng-primitives-stepper.mjs +69 -71
  87. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  88. package/fesm2022/radix-ng-primitives-switch.mjs +128 -124
  89. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  90. package/fesm2022/radix-ng-primitives-tabs.mjs +388 -115
  91. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  92. package/fesm2022/radix-ng-primitives-time-field.mjs +111 -117
  93. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  94. package/fesm2022/radix-ng-primitives-toggle-group.mjs +122 -248
  95. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  96. package/fesm2022/radix-ng-primitives-toggle.mjs +99 -62
  97. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  98. package/fesm2022/radix-ng-primitives-toolbar.mjs +307 -94
  99. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  100. package/fesm2022/radix-ng-primitives-tooltip.mjs +690 -1079
  101. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  102. package/fesm2022/radix-ng-primitives-visually-hidden.mjs +46 -87
  103. package/fesm2022/radix-ng-primitives-visually-hidden.mjs.map +1 -1
  104. package/fesm2022/radix-ng-primitives.mjs.map +1 -1
  105. package/meter/README.md +3 -0
  106. package/navigation-menu/README.md +2 -1
  107. package/package.json +85 -63
  108. package/portal/README.md +2 -0
  109. package/preview-card/README.md +3 -0
  110. package/schematics/collection.json +1 -0
  111. package/schematics/ng-add/index.d.ts +3 -2
  112. package/schematics/ng-add/index.js +62 -31
  113. package/schematics/ng-add/index.js.map +1 -1
  114. package/schematics/ng-add/package-config.d.ts +4 -2
  115. package/schematics/ng-add/package-config.js +10 -2
  116. package/schematics/ng-add/package-config.js.map +1 -1
  117. package/schematics/ng-add/schema.d.ts +3 -0
  118. package/schematics/ng-add/schema.js +3 -0
  119. package/schematics/ng-add/schema.js.map +1 -0
  120. package/schematics/ng-add/schema.json +14 -0
  121. package/select/README.md +2 -0
  122. package/{accordion/index.d.ts → types/radix-ng-primitives-accordion.d.ts} +102 -67
  123. package/types/radix-ng-primitives-alert-dialog.d.ts +114 -0
  124. package/{arrow/index.d.ts → types/radix-ng-primitives-arrow.d.ts} +1 -1
  125. package/{aspect-ratio/index.d.ts → types/radix-ng-primitives-aspect-ratio.d.ts} +1 -1
  126. package/{avatar/index.d.ts → types/radix-ng-primitives-avatar.d.ts} +7 -11
  127. package/types/radix-ng-primitives-button.d.ts +73 -0
  128. package/{calendar/index.d.ts → types/radix-ng-primitives-calendar.d.ts} +2 -3
  129. package/types/radix-ng-primitives-checkbox.d.ts +337 -0
  130. package/types/radix-ng-primitives-collapsible.d.ts +159 -0
  131. package/types/radix-ng-primitives-collection.d.ts +44 -0
  132. package/{config/index.d.ts → types/radix-ng-primitives-config.d.ts} +1 -1
  133. package/types/radix-ng-primitives-context-menu.d.ts +73 -0
  134. package/{core/index.d.ts → types/radix-ng-primitives-core.d.ts} +311 -236
  135. package/{cropper/index.d.ts → types/radix-ng-primitives-cropper.d.ts} +6 -5
  136. package/{date-field/index.d.ts → types/radix-ng-primitives-date-field.d.ts} +42 -27
  137. package/types/radix-ng-primitives-dialog.d.ts +323 -0
  138. package/{dismissable-layer/index.d.ts → types/radix-ng-primitives-dismissable-layer.d.ts} +15 -7
  139. package/types/radix-ng-primitives-drawer.d.ts +448 -0
  140. package/{editable/index.d.ts → types/radix-ng-primitives-editable.d.ts} +1 -1
  141. package/types/radix-ng-primitives-field.d.ts +373 -0
  142. package/types/radix-ng-primitives-fieldset.d.ts +48 -0
  143. package/{focus-scope/index.d.ts → types/radix-ng-primitives-focus-scope.d.ts} +13 -5
  144. package/types/radix-ng-primitives-input.d.ts +87 -0
  145. package/{label/index.d.ts → types/radix-ng-primitives-label.d.ts} +0 -1
  146. package/types/radix-ng-primitives-menu.d.ts +612 -0
  147. package/types/radix-ng-primitives-menubar.d.ts +66 -0
  148. package/types/radix-ng-primitives-meter.d.ts +193 -0
  149. package/types/radix-ng-primitives-navigation-menu.d.ts +488 -0
  150. package/types/radix-ng-primitives-number-field.d.ts +464 -0
  151. package/{pagination/index.d.ts → types/radix-ng-primitives-pagination.d.ts} +2 -2
  152. package/types/radix-ng-primitives-popover.d.ts +416 -0
  153. package/{popper/index.d.ts → types/radix-ng-primitives-popper.d.ts} +50 -9
  154. package/types/radix-ng-primitives-portal.d.ts +30 -0
  155. package/types/radix-ng-primitives-presence.d.ts +55 -0
  156. package/types/radix-ng-primitives-preview-card.d.ts +359 -0
  157. package/types/radix-ng-primitives-progress.d.ts +206 -0
  158. package/{radio/index.d.ts → types/radix-ng-primitives-radio.d.ts} +56 -26
  159. package/{roving-focus/index.d.ts → types/radix-ng-primitives-roving-focus.d.ts} +38 -27
  160. package/types/radix-ng-primitives-select.d.ts +512 -0
  161. package/types/radix-ng-primitives-separator.d.ts +38 -0
  162. package/types/radix-ng-primitives-slider.d.ts +377 -0
  163. package/{stepper/index.d.ts → types/radix-ng-primitives-stepper.d.ts} +21 -22
  164. package/types/radix-ng-primitives-switch.d.ts +121 -0
  165. package/types/radix-ng-primitives-tabs.d.ts +247 -0
  166. package/{time-field/index.d.ts → types/radix-ng-primitives-time-field.d.ts} +46 -31
  167. package/types/radix-ng-primitives-toggle-group.d.ts +116 -0
  168. package/types/radix-ng-primitives-toggle.d.ts +65 -0
  169. package/types/radix-ng-primitives-toolbar.d.ts +180 -0
  170. package/types/radix-ng-primitives-tooltip.d.ts +395 -0
  171. package/{visually-hidden/index.d.ts → types/radix-ng-primitives-visually-hidden.d.ts} +19 -19
  172. package/alert-dialog/index.d.ts +0 -57
  173. package/checkbox/index.d.ts +0 -164
  174. package/collapsible/index.d.ts +0 -85
  175. package/context-menu/index.d.ts +0 -129
  176. package/dialog/index.d.ts +0 -205
  177. package/dropdown-menu/README.md +0 -1
  178. package/dropdown-menu/index.d.ts +0 -171
  179. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs +0 -583
  180. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs.map +0 -1
  181. package/fesm2022/radix-ng-primitives-hover-card.mjs +0 -1246
  182. package/fesm2022/radix-ng-primitives-hover-card.mjs.map +0 -1
  183. package/fesm2022/radix-ng-primitives-tooltip2.mjs +0 -740
  184. package/fesm2022/radix-ng-primitives-tooltip2.mjs.map +0 -1
  185. package/hover-card/README.md +0 -3
  186. package/hover-card/index.d.ts +0 -472
  187. package/menu/index.d.ts +0 -139
  188. package/menubar/index.d.ts +0 -56
  189. package/navigation-menu/index.d.ts +0 -405
  190. package/number-field/index.d.ts +0 -203
  191. package/popover/index.d.ts +0 -403
  192. package/portal/index.d.ts +0 -22
  193. package/presence/index.d.ts +0 -103
  194. package/progress/index.d.ts +0 -79
  195. package/select/index.d.ts +0 -214
  196. package/separator/index.d.ts +0 -63
  197. package/slider/index.d.ts +0 -263
  198. package/switch/index.d.ts +0 -105
  199. package/tabs/index.d.ts +0 -112
  200. package/toggle/index.d.ts +0 -75
  201. package/toggle-group/index.d.ts +0 -194
  202. package/toolbar/index.d.ts +0 -55
  203. package/tooltip/index.d.ts +0 -433
  204. package/tooltip2/README.md +0 -3
  205. package/tooltip2/index.d.ts +0 -325
  206. /package/{focus-guards/index.d.ts → types/radix-ng-primitives-focus-guards.d.ts} +0 -0
  207. /package/{index.d.ts → types/radix-ng-primitives.d.ts} +0 -0
@@ -1,851 +1,1107 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, output, Directive, input, booleanAttribute, viewChild, signal, Input, Component, Injectable, numberAttribute, model, computed, ElementRef, PLATFORM_ID, NgModule } from '@angular/core';
3
- import { NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
2
+ import { inject, ElementRef, DestroyRef, Directive, computed, input, numberAttribute, booleanAttribute, model, output, signal, NgModule } from '@angular/core';
3
+ import { DOCUMENT } from '@angular/common';
4
+ import * as i1 from '@radix-ng/primitives/core';
5
+ import { createContext, clamp, injectControlValueAccessor, injectId, RdxControlValueAccessor } from '@radix-ng/primitives/core';
6
+ export { clamp } from '@radix-ng/primitives/core';
4
7
 
5
- // https://github.com/tmcw-up-for-adoption/simple-linear-scale/blob/master/index.js
6
- function linearScale(input, output) {
7
- return (value) => {
8
- if (input[0] === input[1] || output[0] === output[1])
9
- return output[0];
10
- const ratio = (output[1] - output[0]) / (input[1] - input[0]);
11
- return output[0] + ratio * (value - input[0]);
12
- };
13
- }
14
8
  /**
15
- * Verifies the minimum steps between all values is greater than or equal
16
- * to the expected minimum steps.
9
+ * The Slider context exposes the root directive instance to every child part.
10
+ * The root owns all state, value-change logic and thumb registration; parts read
11
+ * signals and call methods off it.
17
12
  *
18
- * @example
19
- * // returns false
20
- * hasMinStepsBetweenValues([1,2,3], 2);
21
- *
22
- * @example
23
- * // returns true
24
- * hasMinStepsBetweenValues([1,2,3], 1);
13
+ * @see https://base-ui.com/react/components/slider
25
14
  */
26
- function hasMinStepsBetweenValues(values, minStepsBetweenValues) {
27
- if (minStepsBetweenValues > 0) {
28
- const stepsBetweenValues = getStepsBetweenValues(values);
29
- const actualMinStepsBetweenValues = Math.min(...stepsBetweenValues);
30
- return actualMinStepsBetweenValues >= minStepsBetweenValues;
15
+ const [injectSliderRootContext, provideSliderRootContext] = createContext('RdxSliderRootContext');
16
+
17
+ /** Ascending comparator. */
18
+ function asc(a, b) {
19
+ return a - b;
20
+ }
21
+ /** Maps a value within `[min, max]` to a 0–100 percentage. */
22
+ function valueToPercent(value, min, max) {
23
+ return ((value - min) * 100) / (max - min);
24
+ }
25
+ /** Replaces the item at `index` then re-sorts the array ascending. */
26
+ function replaceArrayItemAtIndex(array, index, newValue) {
27
+ const output = array.slice();
28
+ output[index] = newValue;
29
+ return output.sort(asc);
30
+ }
31
+ /** The center point of an element in client coordinates. */
32
+ function getMidpoint(element) {
33
+ const rect = element.getBoundingClientRect();
34
+ return { x: (rect.left + rect.right) / 2, y: (rect.top + rect.bottom) / 2 };
35
+ }
36
+ /** Converts an array of values into clamped 0–100 percentages. */
37
+ function valueArrayToPercentages(values, min, max) {
38
+ return values.map((value) => clamp(valueToPercent(value, min, max), 0, 100));
39
+ }
40
+ /** Number of decimal places in `num`, handling exponential notation for tiny values. */
41
+ function getDecimalPrecision(num) {
42
+ if (num === 0) {
43
+ return 0;
31
44
  }
32
- return true;
45
+ if (Math.abs(num) < 1) {
46
+ const parts = num.toExponential().split('e-');
47
+ const mantissaDecimalPart = parts[0].split('.')[1];
48
+ return (mantissaDecimalPart ? mantissaDecimalPart.length : 0) + parseInt(parts[1], 10);
49
+ }
50
+ const decimalPart = num.toString().split('.')[1];
51
+ return decimalPart ? decimalPart.length : 0;
52
+ }
53
+ /** Snaps `value` to the nearest step, using `min` as the origin of the step grid. */
54
+ function roundValueToStep(value, step, min) {
55
+ const nearest = Math.round((value - min) / step) * step + min;
56
+ return Number(nearest.toFixed(Math.max(getDecimalPrecision(step), getDecimalPrecision(min))));
33
57
  }
34
58
  /**
35
- * Given a `values` array and a `nextValue`, determine which value in
36
- * the array is closest to `nextValue` and return its index.
37
- *
38
- * @example
39
- * // returns 1
40
- * getClosestValueIndex([10, 30], 25);
59
+ * Resolves the value(s) for the keyboard / hidden-input path: clamps to the
60
+ * bounds, and for range sliders also clamps to neighbouring thumbs and re-sorts.
61
+ * Returns a `number` for single sliders and a sorted `number[]` for range sliders.
41
62
  */
42
- function getClosestValueIndex(values, nextValue) {
43
- if (values.length === 1)
44
- return 0;
45
- const distances = values.map((value) => Math.abs(value - nextValue));
46
- const closestDistance = Math.min(...distances);
47
- return distances.indexOf(closestDistance);
63
+ function getSliderValue(valueInput, index, min, max, range, values) {
64
+ let newValue = clamp(valueInput, min, max);
65
+ if (range) {
66
+ newValue = clamp(newValue, values[index - 1] ?? Number.NEGATIVE_INFINITY, values[index + 1] ?? Number.POSITIVE_INFINITY);
67
+ return replaceArrayItemAtIndex(values, index, newValue);
68
+ }
69
+ return newValue;
70
+ }
71
+ /** Returns `false` if any adjacent pair of values is closer than the minimum distance. */
72
+ function validateMinimumDistance(values, step, minStepsBetweenValues) {
73
+ if (!Array.isArray(values)) {
74
+ return true;
75
+ }
76
+ const distances = values.reduce((acc, val, index, vals) => {
77
+ if (index === vals.length - 1) {
78
+ return acc;
79
+ }
80
+ acc.push(Math.abs(val - vals[index + 1]));
81
+ return acc;
82
+ }, []);
83
+ return Math.min(...distances) >= step * minStepsBetweenValues;
84
+ }
85
+ /** Keyboard step helper: increments/decrements `thumbValue` and clamps to bounds. */
86
+ function getNewValue(thumbValue, increment, direction, min, max) {
87
+ const value = direction === 1 ? thumbValue + increment : thumbValue - increment;
88
+ const roundedValue = Number(value.toFixed(Math.max(getDecimalPrecision(thumbValue), getDecimalPrecision(increment), getDecimalPrecision(min))));
89
+ return clamp(roundedValue, min, max);
48
90
  }
49
91
  /**
50
- * Gets an array of steps between each value.
51
- *
52
- * @example
53
- * // returns [1, 9]
54
- * getStepsBetweenValues([10, 11, 20]);
92
+ * The "push" collision algorithm: moves the pressed thumb and pushes its
93
+ * neighbours only as far as needed, letting them spring back toward their
94
+ * initial positions as the pressed thumb retreats.
55
95
  */
56
- function getStepsBetweenValues(values) {
57
- return values.slice(0, -1).map((value, index) => values[index + 1] - value);
96
+ function getPushedThumbValues(params) {
97
+ const { values, index, nextValue, min, max, step, minStepsBetweenValues, initialValues } = params;
98
+ if (values.length === 0) {
99
+ return [];
100
+ }
101
+ const nextValues = values.slice();
102
+ const minValueDifference = step * minStepsBetweenValues;
103
+ const lastIndex = nextValues.length - 1;
104
+ const baseInitialValues = initialValues ?? values;
105
+ const indexMin = min + index * minValueDifference;
106
+ const indexMax = max - (lastIndex - index) * minValueDifference;
107
+ nextValues[index] = clamp(nextValue, indexMin, indexMax);
108
+ // push thumbs to the right
109
+ for (let i = index + 1; i <= lastIndex; i += 1) {
110
+ const minAllowed = nextValues[i - 1] + minValueDifference;
111
+ const maxAllowed = max - (lastIndex - i) * minValueDifference;
112
+ const initialValue = baseInitialValues[i] ?? nextValues[i];
113
+ let candidate = Math.max(nextValues[i], minAllowed);
114
+ if (initialValue < candidate) {
115
+ candidate = Math.max(initialValue, minAllowed);
116
+ }
117
+ nextValues[i] = clamp(candidate, minAllowed, maxAllowed);
118
+ }
119
+ // push thumbs to the left
120
+ for (let i = index - 1; i >= 0; i -= 1) {
121
+ const maxAllowed = nextValues[i + 1] - minValueDifference;
122
+ const minAllowed = min + i * minValueDifference;
123
+ const initialValue = baseInitialValues[i] ?? nextValues[i];
124
+ let candidate = Math.min(nextValues[i], maxAllowed);
125
+ if (initialValue > candidate) {
126
+ candidate = Math.min(initialValue, maxAllowed);
127
+ }
128
+ nextValues[i] = clamp(candidate, minAllowed, maxAllowed);
129
+ }
130
+ for (let i = 0; i <= lastIndex; i += 1) {
131
+ nextValues[i] = Number(nextValues[i].toFixed(12));
132
+ }
133
+ return nextValues;
134
+ }
135
+ /** Dispatches the pressed thumb's new value through the configured collision behavior. */
136
+ function resolveThumbCollision(params) {
137
+ const { behavior, values, currentValues, initialValues, pressedIndex, nextValue, min, max, step, minStepsBetweenValues } = params;
138
+ const activeValues = (currentValues ?? values).slice();
139
+ const baselineValues = initialValues ?? values;
140
+ const range = activeValues.length > 1;
141
+ const minValueDifference = step * minStepsBetweenValues;
142
+ if (!range) {
143
+ return { value: nextValue, thumbIndex: 0, didSwap: false };
144
+ }
145
+ if (behavior === 'push') {
146
+ const value = getPushedThumbValues({
147
+ values: activeValues,
148
+ index: pressedIndex,
149
+ nextValue,
150
+ min,
151
+ max,
152
+ step,
153
+ minStepsBetweenValues
154
+ });
155
+ return { value, thumbIndex: pressedIndex, didSwap: false };
156
+ }
157
+ if (behavior === 'swap') {
158
+ const pressedInitialValue = activeValues[pressedIndex];
159
+ const epsilon = 1e-7;
160
+ const candidateValues = activeValues.slice();
161
+ const previousNeighbor = candidateValues[pressedIndex - 1];
162
+ const nextNeighbor = candidateValues[pressedIndex + 1];
163
+ const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
164
+ const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
165
+ const constrainedValue = clamp(nextValue, lowerBound, upperBound);
166
+ const pressedValueAfterClamp = Number(constrainedValue.toFixed(12));
167
+ candidateValues[pressedIndex] = pressedValueAfterClamp;
168
+ const movingForward = nextValue > pressedInitialValue;
169
+ const movingBackward = nextValue < pressedInitialValue;
170
+ const shouldSwapForward = movingForward && nextNeighbor != null && nextValue >= nextNeighbor - epsilon;
171
+ const shouldSwapBackward = movingBackward && previousNeighbor != null && nextValue <= previousNeighbor + epsilon;
172
+ if (!shouldSwapForward && !shouldSwapBackward) {
173
+ return { value: candidateValues, thumbIndex: pressedIndex, didSwap: false };
174
+ }
175
+ const targetIndex = shouldSwapForward ? pressedIndex + 1 : pressedIndex - 1;
176
+ const initialValuesForPush = candidateValues.map((_, idx) => {
177
+ if (idx === pressedIndex) {
178
+ return pressedValueAfterClamp;
179
+ }
180
+ const baseline = baselineValues[idx];
181
+ return baseline != null ? baseline : activeValues[idx];
182
+ });
183
+ const nextValueForTarget = shouldSwapForward
184
+ ? Math.max(nextValue, candidateValues[targetIndex])
185
+ : Math.min(nextValue, candidateValues[targetIndex]);
186
+ const adjustedValues = getPushedThumbValues({
187
+ values: candidateValues,
188
+ index: targetIndex,
189
+ nextValue: nextValueForTarget,
190
+ min,
191
+ max,
192
+ step,
193
+ minStepsBetweenValues,
194
+ initialValues: initialValuesForPush
195
+ });
196
+ const neighborIndex = shouldSwapForward ? targetIndex - 1 : targetIndex + 1;
197
+ if (neighborIndex >= 0 && neighborIndex < adjustedValues.length) {
198
+ const previousValue = adjustedValues[neighborIndex - 1];
199
+ const nextValueAfter = adjustedValues[neighborIndex + 1];
200
+ let neighborLowerBound = previousValue != null ? previousValue + minValueDifference : min;
201
+ neighborLowerBound = Math.max(neighborLowerBound, min + neighborIndex * minValueDifference);
202
+ let neighborUpperBound = nextValueAfter != null ? nextValueAfter - minValueDifference : max;
203
+ neighborUpperBound = Math.min(neighborUpperBound, max - (adjustedValues.length - 1 - neighborIndex) * minValueDifference);
204
+ const restoredValue = clamp(pressedValueAfterClamp, neighborLowerBound, neighborUpperBound);
205
+ adjustedValues[neighborIndex] = Number(restoredValue.toFixed(12));
206
+ }
207
+ return { value: adjustedValues, thumbIndex: targetIndex, didSwap: true };
208
+ }
209
+ // behavior === 'none' — clamp the pressed thumb between its neighbours; thumbs never cross.
210
+ const previousNeighbor = activeValues[pressedIndex - 1];
211
+ const nextNeighbor = activeValues[pressedIndex + 1];
212
+ const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
213
+ const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
214
+ const constrained = Number(clamp(nextValue, lowerBound, upperBound).toFixed(12));
215
+ const value = activeValues.slice();
216
+ value[pressedIndex] = constrained;
217
+ return { value, thumbIndex: pressedIndex, didSwap: false };
58
218
  }
59
219
  /**
60
- * Offsets the thumb centre point while sliding to ensure it remains
61
- * within the bounds of the slider when reaching the edges
220
+ * Border + padding on the leading/trailing edge of the control along the active
221
+ * axis. Uses physical longhands (`left`/`right`/`top`/`bottom`) rather than
222
+ * logical ones (`inline-start`/…) because `getComputedStyle` resolves the
223
+ * physical properties in every browser, whereas logical longhands return an
224
+ * empty string in some engines.
62
225
  */
63
- function getThumbInBoundsOffset(width, left, direction) {
64
- const halfWidth = width / 2;
65
- const halfPercent = 50;
66
- const offset = linearScale([0, halfPercent], [0, halfWidth]);
67
- return (halfWidth - offset(left) * direction) * direction;
68
- }
69
- function convertValueToPercentage(value, min, max) {
70
- const maxSteps = max - min;
71
- const percentPerStep = 100 / maxSteps;
72
- const percentage = percentPerStep * (value - min);
73
- return clamp(percentage, 0, 100);
226
+ function getControlOffset(styles, vertical, rtl) {
227
+ if (!styles) {
228
+ return { start: 0, end: 0 };
229
+ }
230
+ const parseSize = (v) => {
231
+ const p = parseFloat(v);
232
+ return Number.isNaN(p) ? 0 : p;
233
+ };
234
+ const sideOffset = (side) => parseSize(styles.getPropertyValue(`border-${side}-width`)) +
235
+ parseSize(styles.getPropertyValue(`padding-${side}`));
236
+ let startSide;
237
+ let endSide;
238
+ if (vertical) {
239
+ startSide = 'top';
240
+ endSide = 'bottom';
241
+ }
242
+ else if (rtl) {
243
+ startSide = 'right';
244
+ endSide = 'left';
245
+ }
246
+ else {
247
+ startSide = 'left';
248
+ endSide = 'right';
249
+ }
250
+ return { start: sideOffset(startSide), end: sideOffset(endSide) };
74
251
  }
75
- function getDecimalCount(value) {
76
- return (String(value).split('.')[1] || '').length;
252
+ const formatterCache = new Map();
253
+ function getFormatter(locale, options) {
254
+ const key = JSON.stringify({ locale: locale ?? null, options: options ?? null });
255
+ let formatter = formatterCache.get(key);
256
+ if (!formatter) {
257
+ formatter = new Intl.NumberFormat(locale, options);
258
+ formatterCache.set(key, formatter);
259
+ }
260
+ return formatter;
77
261
  }
78
- function roundValue(value, decimalCount) {
79
- const rounder = 10 ** decimalCount;
80
- return Math.round(value * rounder) / rounder;
262
+ /** Formats a number with a cached `Intl.NumberFormat` instance. */
263
+ function formatNumber(value, locale, options) {
264
+ if (value == null) {
265
+ return '';
266
+ }
267
+ return getFormatter(locale, options).format(value);
81
268
  }
82
- function getNextSortedValues(prevValues = [], nextValue, atIndex) {
83
- const nextValues = [...prevValues];
84
- nextValues[atIndex] = nextValue;
85
- return nextValues.sort((a, b) => a - b);
269
+ /** Default `aria-valuetext` for a two-thumb range, or a formatted value when `format` is set. */
270
+ function getDefaultAriaValueText(values, index, format, locale) {
271
+ if (index < 0) {
272
+ return undefined;
273
+ }
274
+ if (values.length === 2) {
275
+ return index === 0
276
+ ? `${formatNumber(values[index], locale, format)} start range`
277
+ : `${formatNumber(values[index], locale, format)} end range`;
278
+ }
279
+ return format ? formatNumber(values[index], locale, format) : undefined;
86
280
  }
87
- const PAGE_KEYS = ['PageUp', 'PageDown'];
88
281
  const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
89
- const BACK_KEYS = {
90
- 'from-left': ['Home', 'PageDown', 'ArrowDown', 'ArrowLeft'],
91
- 'from-right': ['Home', 'PageDown', 'ArrowDown', 'ArrowRight'],
92
- 'from-bottom': ['Home', 'PageDown', 'ArrowDown', 'ArrowLeft'],
93
- 'from-top': ['Home', 'PageUp', 'ArrowUp', 'ArrowLeft']
94
- };
95
- function clamp(value, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY) {
96
- return Math.min(Math.max(value, min), max);
282
+ const COMPOSITE_KEYS = new Set([...ARROW_KEYS, 'Home', 'End']);
283
+ const ALL_KEYS = new Set([...COMPOSITE_KEYS, 'PageUp', 'PageDown']);
284
+ function areValuesEqual(a, b) {
285
+ if (Array.isArray(a) && Array.isArray(b)) {
286
+ return a.length === b.length && a.every((v, i) => v === b[i]);
287
+ }
288
+ return a === b;
97
289
  }
98
290
 
99
- class RdxSliderImplDirective {
291
+ const INTENTIONAL_DRAG_COUNT_THRESHOLD = 2;
292
+ /**
293
+ * The interactive area of the slider. Handles pointer presses and drags on the
294
+ * track, mapping pointer position to a value and moving the closest thumb.
295
+ *
296
+ * @see https://base-ui.com/react/components/slider
297
+ */
298
+ class RdxSliderControl {
100
299
  constructor() {
101
- this.rootContext = inject(RdxSliderRootComponent);
102
- this.slideStart = output();
103
- this.slideMove = output();
104
- this.slideEnd = output();
105
- this.homeKeyDown = output();
106
- this.endKeyDown = output();
107
- this.stepKeyDown = output();
300
+ this.root = injectSliderRootContext();
301
+ this.elementRef = inject(ElementRef);
302
+ this.document = inject(DOCUMENT);
303
+ this.styles = null;
304
+ this.moveCount = 0;
305
+ this.currentInteractionValue = null;
306
+ this.onMove = (event) => this.handleMove(event);
307
+ this.onUp = (event) => this.handleUp(event);
308
+ this.onCancel = (event) => this.handleUp(event);
309
+ this.root.controlRef.set(this.elementRef.nativeElement);
310
+ inject(DestroyRef).onDestroy(() => this.stopListening());
108
311
  }
109
- onKeyDown(event) {
110
- if (event.key === 'Home') {
111
- this.homeKeyDown.emit(event);
112
- // Prevent scrolling to page start
113
- event.preventDefault();
312
+ onPointerDown(event) {
313
+ const control = this.elementRef.nativeElement;
314
+ if (this.root.isDisabled() || event.defaultPrevented || event.button !== 0) {
315
+ return;
114
316
  }
115
- else if (event.key === 'End') {
116
- this.endKeyDown.emit(event);
117
- // Prevent scrolling to page end
118
- event.preventDefault();
317
+ const target = event.target;
318
+ if (!target) {
319
+ return;
119
320
  }
120
- else if (PAGE_KEYS.concat(ARROW_KEYS).includes(event.key)) {
121
- this.stepKeyDown.emit(event);
122
- // Prevent scrolling for directional key presses
123
- event.preventDefault();
321
+ // Suppress the nested range input's native click-to-set and drag so the
322
+ // control fully owns pointer interaction (otherwise releasing on a thumb
323
+ // fires a native change that snaps the value to the press point inside
324
+ // the thumb-sized input). Focus is restored manually via focusThumb.
325
+ event.preventDefault();
326
+ this.styles = this.document.defaultView?.getComputedStyle(control) ?? null;
327
+ this.startPressing({ x: event.clientX, y: event.clientY });
328
+ const finger = this.getFingerState({ x: event.clientX, y: event.clientY });
329
+ if (finger == null) {
330
+ return;
331
+ }
332
+ this.root.setDragging(true);
333
+ // Pressing directly on a thumb sets a center offset; only a rail press changes value on down.
334
+ if (this.root.pressedThumbCenterOffset == null) {
335
+ this.setValueFromPointer(finger, 'track-press');
124
336
  }
337
+ this.root.focusThumb(finger.thumbIndex);
338
+ control.setPointerCapture(event.pointerId);
339
+ this.moveCount = 0;
340
+ this.document.addEventListener('pointermove', this.onMove);
341
+ this.document.addEventListener('pointerup', this.onUp, { once: true });
342
+ this.document.addEventListener('pointercancel', this.onCancel, { once: true });
125
343
  }
126
- onPointerDown(event) {
127
- const target = event.target;
128
- target.setPointerCapture(event.pointerId);
129
- // Prevent browser focus behaviour because we focus a thumb manually when values change.
130
- event.preventDefault();
131
- // Touch devices have a delay before focusing so won't focus if touch immediately moves
132
- // away from target (sliding). We want thumb to focus regardless.
133
- if (this.rootContext.thumbElements.includes(target)) {
134
- target.focus();
344
+ handleMove(event) {
345
+ this.moveCount += 1;
346
+ if (event.buttons === 0) {
347
+ this.handleUp(event);
348
+ return;
349
+ }
350
+ const finger = this.getFingerState({ x: event.clientX, y: event.clientY });
351
+ if (finger == null) {
352
+ return;
353
+ }
354
+ if (validateMinimumDistance(finger.value, this.root.step(), this.root.minStepsBetweenValues())) {
355
+ if (!this.root.dragging() && this.moveCount > INTENTIONAL_DRAG_COUNT_THRESHOLD) {
356
+ this.root.setDragging(true);
357
+ }
358
+ const applied = this.setValueFromPointer(finger, 'drag');
359
+ if (applied && finger.didSwap) {
360
+ this.root.focusThumb(finger.thumbIndex);
361
+ }
362
+ }
363
+ }
364
+ handleUp(event) {
365
+ this.root.setActive(-1);
366
+ this.root.setDragging(false);
367
+ this.root.pressedThumbCenterOffset = null;
368
+ this.root.pressedInput = null;
369
+ if (this.currentInteractionValue != null) {
370
+ this.root.commitValue();
371
+ }
372
+ const control = this.elementRef.nativeElement;
373
+ if (control.hasPointerCapture?.(event.pointerId)) {
374
+ control.releasePointerCapture(event.pointerId);
375
+ }
376
+ this.root.resetPressedThumb();
377
+ this.root.pressedValues = null;
378
+ this.currentInteractionValue = null;
379
+ this.stopListening();
380
+ }
381
+ stopListening() {
382
+ this.document.removeEventListener('pointermove', this.onMove);
383
+ this.document.removeEventListener('pointerup', this.onUp);
384
+ this.document.removeEventListener('pointercancel', this.onCancel);
385
+ }
386
+ startPressing(finger) {
387
+ const values = this.root.values();
388
+ const range = this.root.range();
389
+ this.root.pressedValues = range ? values.slice() : null;
390
+ this.currentInteractionValue = null;
391
+ const pressedThumbIndex = this.root.pressedThumbIndex;
392
+ let closestThumbIndex = pressedThumbIndex;
393
+ if (pressedThumbIndex > -1 && pressedThumbIndex < values.length) {
394
+ // Pressed directly on a thumb sitting on max — walk left over stacked max thumbs.
395
+ if (values[pressedThumbIndex] === this.root.max()) {
396
+ let c = pressedThumbIndex;
397
+ while (c > 0 && values[c - 1] === this.root.max()) {
398
+ c -= 1;
399
+ }
400
+ closestThumbIndex = c;
401
+ }
135
402
  }
136
403
  else {
137
- this.slideStart.emit(event);
404
+ // Pressed on the rail — find the nearest enabled thumb by midpoint distance.
405
+ const axis = this.root.orientation() === 'horizontal' ? 'x' : 'y';
406
+ const thumbs = this.root.thumbList();
407
+ let minDistance;
408
+ closestThumbIndex = -1;
409
+ for (let i = 0; i < thumbs.length; i += 1) {
410
+ const thumb = thumbs[i];
411
+ if (thumb.disabled()) {
412
+ continue;
413
+ }
414
+ const midpoint = getMidpoint(thumb.element);
415
+ const distance = Math.abs(finger[axis] - midpoint[axis]);
416
+ if (minDistance === undefined || distance <= minDistance) {
417
+ closestThumbIndex = i;
418
+ minDistance = distance;
419
+ }
420
+ }
421
+ }
422
+ if (closestThumbIndex > -1 && closestThumbIndex !== pressedThumbIndex) {
423
+ this.root.pressedThumbIndex = closestThumbIndex;
424
+ this.root.pressedInput = this.root.thumbList()[closestThumbIndex]?.inputElement ?? null;
138
425
  }
139
426
  }
140
- onPointerMove(event) {
141
- const target = event.target;
142
- if (target.hasPointerCapture(event.pointerId)) {
143
- this.slideMove.emit(event);
427
+ setValueFromPointer(finger, reason) {
428
+ const nextValues = Array.isArray(finger.value) ? finger.value : [finger.value];
429
+ const applied = this.root.setValue(nextValues, reason);
430
+ if (applied) {
431
+ this.currentInteractionValue = finger.value;
432
+ if (finger.didSwap) {
433
+ this.root.pressedThumbIndex = finger.thumbIndex;
434
+ this.root.pressedInput = this.root.thumbList()[finger.thumbIndex]?.inputElement ?? null;
435
+ }
144
436
  }
437
+ return applied;
145
438
  }
146
- onPointerUp(event) {
147
- const target = event.target;
148
- if (target.hasPointerCapture(event.pointerId)) {
149
- target.releasePointerCapture(event.pointerId);
150
- this.slideEnd.emit(event);
439
+ /** Projects a pointer position onto the track and resolves it to a value (+ collision). */
440
+ getFingerState(finger) {
441
+ const control = this.root.controlRef();
442
+ const values = this.root.values();
443
+ const range = this.root.range();
444
+ const thumbIndex = this.root.pressedThumbIndex;
445
+ const vertical = this.root.orientation() === 'vertical';
446
+ const rtl = this.root.dir() === 'rtl';
447
+ const min = this.root.min();
448
+ const max = this.root.max();
449
+ const step = this.root.step();
450
+ if (!control || (!range && (thumbIndex < 0 || thumbIndex >= values.length))) {
451
+ return null;
452
+ }
453
+ const { width, height, bottom, left, right } = control.getBoundingClientRect();
454
+ const controlOffset = getControlOffset(this.styles, vertical, rtl);
455
+ const controlSize = (vertical ? height : width) - controlOffset.start - controlOffset.end;
456
+ // A collapsed/unmeasurable track would divide by zero and yield NaN values.
457
+ if (!(controlSize > 0)) {
458
+ return null;
459
+ }
460
+ const thumbCenterOffset = this.root.pressedThumbCenterOffset ?? 0;
461
+ const fingerX = finger.x - thumbCenterOffset;
462
+ const fingerY = finger.y - thumbCenterOffset;
463
+ const valueSize = vertical
464
+ ? bottom - fingerY - controlOffset.end
465
+ : (rtl ? right - fingerX : fingerX - left) - controlOffset.start;
466
+ const valueRescaled = clamp(valueSize / controlSize, 0, 1);
467
+ let newValue = (max - min) * valueRescaled + min;
468
+ newValue = roundValueToStep(newValue, step, min);
469
+ newValue = clamp(newValue, min, max);
470
+ if (!range) {
471
+ return { value: newValue, thumbIndex, didSwap: false };
151
472
  }
473
+ if (thumbIndex < 0) {
474
+ return null;
475
+ }
476
+ return resolveThumbCollision({
477
+ behavior: this.root.thumbCollisionBehavior(),
478
+ values,
479
+ currentValues: values,
480
+ initialValues: this.root.pressedValues,
481
+ pressedIndex: thumbIndex,
482
+ nextValue: newValue,
483
+ min,
484
+ max,
485
+ step,
486
+ minStepsBetweenValues: this.root.minStepsBetweenValues()
487
+ });
152
488
  }
153
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderImplDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
154
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxSliderImplDirective, isStandalone: true, selector: "[rdxSliderImpl]", outputs: { slideStart: "slideStart", slideMove: "slideMove", slideEnd: "slideEnd", homeKeyDown: "homeKeyDown", endKeyDown: "endKeyDown", stepKeyDown: "stepKeyDown" }, host: { attributes: { "role": "slider", "tabindex": "0" }, listeners: { "keydown": "onKeyDown($event)", "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp($event)" } }, ngImport: i0 }); }
489
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderControl, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
490
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSliderControl, isStandalone: true, selector: "div[rdxSliderControl]", host: { listeners: { "pointerdown": "onPointerDown($event)" }, properties: { "attr.data-orientation": "root.orientation()", "attr.data-disabled": "root.isDisabled() ? \"\" : undefined", "attr.data-dragging": "root.dragging() ? \"\" : undefined" } }, exportAs: ["rdxSliderControl"], ngImport: i0 }); }
155
491
  }
156
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderImplDirective, decorators: [{
492
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderControl, decorators: [{
157
493
  type: Directive,
158
494
  args: [{
159
- selector: '[rdxSliderImpl]',
495
+ selector: 'div[rdxSliderControl]',
496
+ exportAs: 'rdxSliderControl',
160
497
  host: {
161
- role: 'slider',
162
- tabindex: '0',
163
- '(keydown)': 'onKeyDown($event)',
164
- '(pointerdown)': 'onPointerDown($event)',
165
- '(pointermove)': 'onPointerMove($event)',
166
- '(pointerup)': 'onPointerUp($event)'
498
+ '[attr.data-orientation]': 'root.orientation()',
499
+ '[attr.data-disabled]': 'root.isDisabled() ? "" : undefined',
500
+ '[attr.data-dragging]': 'root.dragging() ? "" : undefined',
501
+ '(pointerdown)': 'onPointerDown($event)'
167
502
  }
168
503
  }]
169
- }] });
504
+ }], ctorParameters: () => [] });
170
505
 
171
- class RdxSliderHorizontalComponent {
506
+ /**
507
+ * Visualises the portion of the track between the slider's minimum (or the first
508
+ * thumb in a range) and the active value.
509
+ *
510
+ * @see https://base-ui.com/react/components/slider
511
+ */
512
+ class RdxSliderIndicator {
172
513
  constructor() {
173
- this.rootContext = inject(RdxSliderRootComponent);
174
- this.dir = 'ltr';
175
- this.inverted = input(false, ...(ngDevMode ? [{ debugName: "inverted", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
176
- this.min = 0;
177
- this.max = 100;
178
- this.className = '';
179
- this.slideStart = output();
180
- this.slideMove = output();
181
- this.slideEnd = output();
182
- this.stepKeyDown = output();
183
- this.endKeyDown = output();
184
- this.homeKeyDown = output();
185
- this.sliderElement = viewChild('sliderElement', ...(ngDevMode ? [{ debugName: "sliderElement" }] : []));
186
- this.rect = signal(undefined, ...(ngDevMode ? [{ debugName: "rect" }] : []));
187
- }
188
- onSlideStart(event) {
189
- const value = this.getValueFromPointer(event.clientX);
190
- this.slideStart.emit(value);
191
- }
192
- onSlideMove(event) {
193
- const value = this.getValueFromPointer(event.clientX);
194
- this.slideMove.emit(value);
195
- }
196
- onSlideEnd() {
197
- this.rect.set(undefined);
198
- this.slideEnd.emit();
199
- }
200
- onStepKeyDown(event) {
201
- const slideDirection = this.rootContext.isSlidingFromLeft() ? 'from-left' : 'from-right';
202
- const isBackKey = BACK_KEYS[slideDirection].includes(event.key);
203
- this.stepKeyDown.emit({ event, direction: isBackKey ? -1 : 1 });
204
- }
205
- getValueFromPointer(pointerPosition) {
206
- this.rect.set(this.sliderElement()?.nativeElement.getBoundingClientRect());
207
- const rect = this.rect();
208
- if (!rect)
209
- return 0;
210
- const input = [0, rect.width];
211
- const output = this.rootContext.isSlidingFromLeft()
212
- ? [this.min, this.max]
213
- : [this.max, this.min];
214
- const value = linearScale(input, output);
215
- this.rect.set(rect);
216
- return value(pointerPosition - rect.left);
217
- }
218
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderHorizontalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
219
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.3", type: RdxSliderHorizontalComponent, isStandalone: true, selector: "rdx-slider-horizontal", inputs: { dir: { classPropertyName: "dir", publicName: "dir", isSignal: false, isRequired: false, transformFunction: null }, inverted: { classPropertyName: "inverted", publicName: "inverted", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: false, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: false, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { slideStart: "slideStart", slideMove: "slideMove", slideEnd: "slideEnd", stepKeyDown: "stepKeyDown", endKeyDown: "endKeyDown", homeKeyDown: "homeKeyDown" }, viewQueries: [{ propertyName: "sliderElement", first: true, predicate: ["sliderElement"], descendants: true, isSignal: true }], ngImport: i0, template: `
220
- <span
221
- #sliderElement
222
- [class]="className"
223
- [attr.data-orientation]="'horizontal'"
224
- [style]="{ '--rdx-slider-thumb-transform': 'translateX(-50%)' }"
225
- (slideStart)="onSlideStart($event)"
226
- (slideMove)="onSlideMove($event)"
227
- (slideEnd)="onSlideEnd()"
228
- (stepKeyDown)="onStepKeyDown($event)"
229
- (endKeyDown)="endKeyDown.emit($event)"
230
- (homeKeyDown)="homeKeyDown.emit($event)"
231
- rdxSliderImpl
232
- >
233
- <ng-content />
234
- </span>
235
- `, isInline: true, dependencies: [{ kind: "directive", type: RdxSliderImplDirective, selector: "[rdxSliderImpl]", outputs: ["slideStart", "slideMove", "slideEnd", "homeKeyDown", "endKeyDown", "stepKeyDown"] }] }); }
514
+ this.root = injectSliderRootContext();
515
+ this.indicatorStyle = computed(() => {
516
+ const vertical = this.root.orientation() === 'vertical';
517
+ const range = this.root.range();
518
+ const values = this.root.values();
519
+ const min = this.root.min();
520
+ const max = this.root.max();
521
+ const startEdge = vertical ? 'bottom' : 'inset-inline-start';
522
+ const mainSide = vertical ? 'height' : 'width';
523
+ const crossSide = vertical ? 'width' : 'height';
524
+ const start = valueToPercent(values[0], min, max);
525
+ const end = valueToPercent(values[values.length - 1], min, max);
526
+ const styles = {
527
+ position: vertical ? 'absolute' : 'relative',
528
+ [crossSide]: 'inherit'
529
+ };
530
+ if (!range) {
531
+ styles[startEdge] = 0;
532
+ styles[mainSide] = `${start}%`;
533
+ return styles;
534
+ }
535
+ styles[startEdge] = `${start}%`;
536
+ styles[mainSide] = `${end - start}%`;
537
+ return styles;
538
+ }, ...(ngDevMode ? [{ debugName: "indicatorStyle" }] : /* istanbul ignore next */ []));
539
+ }
540
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderIndicator, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
541
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSliderIndicator, isStandalone: true, selector: "div[rdxSliderIndicator]", host: { properties: { "style": "indicatorStyle()", "attr.data-orientation": "root.orientation()", "attr.data-disabled": "root.isDisabled() ? \"\" : undefined", "attr.data-dragging": "root.dragging() ? \"\" : undefined" } }, exportAs: ["rdxSliderIndicator"], ngImport: i0 }); }
236
542
  }
237
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderHorizontalComponent, decorators: [{
238
- type: Component,
543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderIndicator, decorators: [{
544
+ type: Directive,
239
545
  args: [{
240
- selector: 'rdx-slider-horizontal',
241
- imports: [RdxSliderImplDirective],
242
- template: `
243
- <span
244
- #sliderElement
245
- [class]="className"
246
- [attr.data-orientation]="'horizontal'"
247
- [style]="{ '--rdx-slider-thumb-transform': 'translateX(-50%)' }"
248
- (slideStart)="onSlideStart($event)"
249
- (slideMove)="onSlideMove($event)"
250
- (slideEnd)="onSlideEnd()"
251
- (stepKeyDown)="onStepKeyDown($event)"
252
- (endKeyDown)="endKeyDown.emit($event)"
253
- (homeKeyDown)="homeKeyDown.emit($event)"
254
- rdxSliderImpl
255
- >
256
- <ng-content />
257
- </span>
258
- `
546
+ selector: 'div[rdxSliderIndicator]',
547
+ exportAs: 'rdxSliderIndicator',
548
+ host: {
549
+ '[style]': 'indicatorStyle()',
550
+ '[attr.data-orientation]': 'root.orientation()',
551
+ '[attr.data-disabled]': 'root.isDisabled() ? "" : undefined',
552
+ '[attr.data-dragging]': 'root.dragging() ? "" : undefined'
553
+ }
259
554
  }]
260
- }], propDecorators: { dir: [{
261
- type: Input
262
- }], min: [{
263
- type: Input
264
- }], max: [{
265
- type: Input
266
- }], className: [{
267
- type: Input
268
- }] } });
269
-
270
- class RdxSliderOrientationContextService {
271
- constructor() {
272
- this.contextSignal = signal({
273
- startEdge: 'left',
274
- endEdge: 'right',
275
- direction: 1,
276
- size: 'width'
277
- }, ...(ngDevMode ? [{ debugName: "contextSignal" }] : []));
278
- }
279
- get context() {
280
- return this.contextSignal();
281
- }
282
- updateContext(context) {
283
- this.contextSignal.update((current) => ({
284
- ...current,
285
- ...context
286
- }));
287
- }
288
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderOrientationContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
289
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderOrientationContextService }); }
290
- }
291
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderOrientationContextService, decorators: [{
292
- type: Injectable
293
555
  }] });
294
556
 
295
- class RdxSliderVerticalComponent {
296
- constructor() {
297
- this.rootContext = inject(RdxSliderRootComponent);
298
- this.dir = 'ltr';
299
- this.inverted = input(false, ...(ngDevMode ? [{ debugName: "inverted", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
300
- this.min = 0;
301
- this.max = 100;
302
- this.className = '';
303
- this.slideStart = output();
304
- this.slideMove = output();
305
- this.slideEnd = output();
306
- this.stepKeyDown = output();
307
- this.endKeyDown = output();
308
- this.homeKeyDown = output();
309
- this.sliderElement = viewChild('sliderElement', ...(ngDevMode ? [{ debugName: "sliderElement" }] : []));
310
- this.rect = signal(undefined, ...(ngDevMode ? [{ debugName: "rect" }] : []));
311
- }
312
- onSlideStart(event) {
313
- const value = this.getValueFromPointer(event.clientY);
314
- this.slideStart.emit(value);
315
- }
316
- onSlideMove(event) {
317
- const value = this.getValueFromPointer(event.clientY);
318
- this.slideMove.emit(value);
319
- }
320
- onSlideEnd() {
321
- this.rect.set(undefined);
322
- this.slideEnd.emit();
323
- }
324
- onStepKeyDown(event) {
325
- const slideDirection = this.rootContext.isSlidingFromBottom() ? 'from-bottom' : 'from-top';
326
- const isBackKey = BACK_KEYS[slideDirection].includes(event.key);
327
- this.stepKeyDown.emit({ event, direction: isBackKey ? -1 : 1 });
328
- }
329
- getValueFromPointer(pointerPosition) {
330
- this.rect.set(this.sliderElement()?.nativeElement.getBoundingClientRect());
331
- const rect = this.rect();
332
- if (!rect)
333
- return 0;
334
- const input = [0, rect.height];
335
- const output = this.rootContext.isSlidingFromBottom()
336
- ? [this.max, this.min]
337
- : [this.min, this.max];
338
- const value = linearScale(input, output);
339
- this.rect.set(rect);
340
- return value(pointerPosition - rect.top);
341
- }
342
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderVerticalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
343
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.3", type: RdxSliderVerticalComponent, isStandalone: true, selector: "rdx-slider-vertical", inputs: { dir: { classPropertyName: "dir", publicName: "dir", isSignal: false, isRequired: false, transformFunction: null }, inverted: { classPropertyName: "inverted", publicName: "inverted", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: false, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: false, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { slideStart: "slideStart", slideMove: "slideMove", slideEnd: "slideEnd", stepKeyDown: "stepKeyDown", endKeyDown: "endKeyDown", homeKeyDown: "homeKeyDown" }, viewQueries: [{ propertyName: "sliderElement", first: true, predicate: ["sliderElement"], descendants: true, isSignal: true }], ngImport: i0, template: `
344
- <span
345
- #sliderElement
346
- [class]="className"
347
- [attr.data-orientation]="'vertical'"
348
- [style]="{ '--rdx-slider-thumb-transform': 'translateY(-50%)' }"
349
- (slideStart)="onSlideStart($event)"
350
- (slideMove)="onSlideMove($event)"
351
- (slideEnd)="onSlideEnd()"
352
- (stepKeyDown)="onStepKeyDown($event)"
353
- (endKeyDown)="endKeyDown.emit($event)"
354
- (homeKeyDown)="homeKeyDown.emit($event)"
355
- rdxSliderImpl
356
- >
357
- <ng-content />
358
- </span>
359
- `, isInline: true, dependencies: [{ kind: "directive", type: RdxSliderImplDirective, selector: "[rdxSliderImpl]", outputs: ["slideStart", "slideMove", "slideEnd", "homeKeyDown", "endKeyDown", "stepKeyDown"] }] }); }
557
+ function sortByDomOrder(list) {
558
+ return list.slice().sort((a, b) => {
559
+ const position = a.element.compareDocumentPosition(b.element);
560
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
561
+ return -1;
562
+ }
563
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
564
+ return 1;
565
+ }
566
+ return 0;
567
+ });
360
568
  }
361
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderVerticalComponent, decorators: [{
362
- type: Component,
363
- args: [{
364
- selector: 'rdx-slider-vertical',
365
- imports: [RdxSliderImplDirective],
366
- template: `
367
- <span
368
- #sliderElement
369
- [class]="className"
370
- [attr.data-orientation]="'vertical'"
371
- [style]="{ '--rdx-slider-thumb-transform': 'translateY(-50%)' }"
372
- (slideStart)="onSlideStart($event)"
373
- (slideMove)="onSlideMove($event)"
374
- (slideEnd)="onSlideEnd()"
375
- (stepKeyDown)="onStepKeyDown($event)"
376
- (endKeyDown)="endKeyDown.emit($event)"
377
- (homeKeyDown)="homeKeyDown.emit($event)"
378
- rdxSliderImpl
379
- >
380
- <ng-content />
381
- </span>
382
- `
383
- }]
384
- }], propDecorators: { dir: [{
385
- type: Input
386
- }], min: [{
387
- type: Input
388
- }], max: [{
389
- type: Input
390
- }], className: [{
391
- type: Input
392
- }] } });
393
-
394
569
  /**
395
- * @group Components
570
+ * Groups all parts of the slider and owns its state, value-change logic and
571
+ * thumb registration. A single directive drives both orientations — there are no
572
+ * separate horizontal/vertical components.
573
+ *
574
+ * @see https://base-ui.com/react/components/slider
396
575
  */
397
- class RdxSliderRootComponent {
576
+ class RdxSliderRoot {
398
577
  constructor() {
399
578
  /** @ignore */
400
- this.orientationContext = inject(RdxSliderOrientationContextService);
579
+ this.cva = injectControlValueAccessor();
580
+ this.id = input(injectId('rdx-slider-'), ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
401
581
  /**
402
- * The minimum value for the range.
403
- *
404
- * @group Props
405
- * @defaultValue 0
582
+ * The minimum value of the slider.
583
+ * @default 0
406
584
  */
407
- this.min = input(0, ...(ngDevMode ? [{ debugName: "min", transform: numberAttribute }] : [{ transform: numberAttribute }]));
585
+ this.min = input(0, { ...(ngDevMode ? { debugName: "min" } : /* istanbul ignore next */ {}), transform: numberAttribute });
408
586
  /**
409
- * The maximum value for the range.
410
- *
411
- * @group Props
412
- * @defaultValue 100
587
+ * The maximum value of the slider.
588
+ * @default 100
413
589
  */
414
- this.max = input(100, ...(ngDevMode ? [{ debugName: "max", transform: numberAttribute }] : [{ transform: numberAttribute }]));
590
+ this.max = input(100, { ...(ngDevMode ? { debugName: "max" } : /* istanbul ignore next */ {}), transform: numberAttribute });
415
591
  /**
416
- * The stepping interval.
417
- *
418
- * @group Props
419
- * @defaultValue 1
592
+ * The granularity with which the value can change through user interaction.
593
+ * @default 1
420
594
  */
421
- this.step = input(1, ...(ngDevMode ? [{ debugName: "step", transform: numberAttribute }] : [{ transform: numberAttribute }]));
595
+ this.step = input(1, { ...(ngDevMode ? { debugName: "step" } : /* istanbul ignore next */ {}), transform: numberAttribute });
422
596
  /**
423
- * The minimum permitted steps between multiple thumbs.
424
- *
425
- * @group Props
426
- * @defaultValue 0
597
+ * The granularity with which the value changes on Page Up / Page Down keys and Shift + Arrow keys.
598
+ * @default 10
427
599
  */
428
- this.minStepsBetweenThumbs = input(0, ...(ngDevMode ? [{ debugName: "minStepsBetweenThumbs", transform: numberAttribute }] : [{ transform: numberAttribute }]));
600
+ this.largeStep = input(10, { ...(ngDevMode ? { debugName: "largeStep" } : /* istanbul ignore next */ {}), transform: numberAttribute });
429
601
  /**
430
- * The orientation of the slider.
431
- *
432
- * @group Props
433
- * @defaultValue 'horizontal'
602
+ * The minimum number of steps that must separate two thumbs in a range slider.
603
+ * @default 0
434
604
  */
435
- this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
605
+ this.minStepsBetweenValues = input(0, { ...(ngDevMode ? { debugName: "minStepsBetweenValues" } : /* istanbul ignore next */ {}), transform: numberAttribute });
436
606
  /**
437
- * When true, prevents the user from interacting with the slider.
438
- *
439
- * @group Props
440
- * @defaultValue false
441
- */
442
- this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
443
- /**
444
- * Whether the slider is visually inverted.
445
- *
446
- * @group Props
447
- * @defaultValue false
448
- */
449
- this.inverted = input(false, ...(ngDevMode ? [{ debugName: "inverted", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
450
- /**
451
- * The reading direction of the combobox when applicable.
452
- *
453
- * @group Props
454
- * @defaultValue 'ltr'
455
- */
456
- this.dir = input('ltr', ...(ngDevMode ? [{ debugName: "dir" }] : []));
457
- this.className = '';
458
- /**
459
- * Style class of the component.
460
- *
461
- * @group Props
607
+ * The orientation of the slider.
608
+ * @default 'horizontal'
462
609
  */
463
- this.styleClass = input(...(ngDevMode ? [undefined, { debugName: "styleClass" }] : []));
610
+ this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
464
611
  /**
465
- * The controlled value of the slider.
466
- *
467
- * @group Props
612
+ * The reading direction. Mirrors the horizontal axis when set to `'rtl'`.
613
+ * @default 'ltr'
468
614
  */
469
- this.modelValue = model([0], ...(ngDevMode ? [{ debugName: "modelValue" }] : []));
615
+ this.dir = input('ltr', ...(ngDevMode ? [{ debugName: "dir" }] : /* istanbul ignore next */ []));
470
616
  /**
471
- * Event handler called when the slider value changes.
472
- *
473
- * @group Emits
617
+ * How thumbs behave when they meet in a range slider.
618
+ * @default 'push'
474
619
  */
475
- this.valueChange = output();
620
+ this.thumbCollisionBehavior = input('push', ...(ngDevMode ? [{ debugName: "thumbCollisionBehavior" }] : /* istanbul ignore next */ []));
621
+ /** Options forwarded to `Intl.NumberFormat` when displaying and announcing values. */
622
+ this.format = input(...(ngDevMode ? [undefined, { debugName: "format" }] : /* istanbul ignore next */ []));
623
+ /** Locale used for value formatting. */
624
+ this.locale = input(...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
625
+ /** Name of the hidden inputs rendered by each thumb, for form submission. */
626
+ this.name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
627
+ /** Id of the form the slider belongs to. */
628
+ this.form = input(...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
476
629
  /**
477
- * Event handler called when the value changes at the end of an interaction.
478
- *
479
- * Useful when you only need to capture a final value e.g. to update a backend service.
480
- *
481
- * @group Emits
630
+ * When `true`, the user cannot interact with the slider.
631
+ * @default false
482
632
  */
483
- this.valueCommit = output();
633
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
634
+ /** The uncontrolled value of the slider when it is initially rendered. */
635
+ this.defaultValue = input(...(ngDevMode ? [undefined, { debugName: "defaultValue" }] : /* istanbul ignore next */ []));
636
+ /** The controlled value of the slider. Use with `(onValueChange)` or two-way `[(value)]`. */
637
+ this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
638
+ this.ariaLabelledBy = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabelledBy" } : /* istanbul ignore next */ {}), alias: 'aria-labelledby' });
639
+ /** Emitted when the value changes (during interaction). */
640
+ this.onValueChange = output();
641
+ /** Emitted when interaction ends, with the final value — useful for committing to a backend. */
642
+ this.onValueCommitted = output();
484
643
  /** @ignore */
485
- this.valueIndexToChange = model(0, ...(ngDevMode ? [{ debugName: "valueIndexToChange" }] : []));
644
+ this.controlRef = signal(null, ...(ngDevMode ? [{ debugName: "controlRef" }] : /* istanbul ignore next */ []));
645
+ /** @ignore Active thumb index (-1 when none). */
646
+ this.active = signal(-1, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
647
+ /** @ignore Last thumb index that was focused/used, drives z-index stacking. */
648
+ this.lastUsedThumbIndex = signal(-1, ...(ngDevMode ? [{ debugName: "lastUsedThumbIndex" }] : /* istanbul ignore next */ []));
649
+ /** @ignore Whether a pointer drag is in progress. */
650
+ this.dragging = signal(false, ...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
651
+ /** @ignore Pointer-drag scratch state (not reactive). */
652
+ this.pressedThumbIndex = -1;
486
653
  /** @ignore */
487
- this.valuesBeforeSlideStart = model([], ...(ngDevMode ? [{ debugName: "valuesBeforeSlideStart" }] : []));
654
+ this.pressedThumbCenterOffset = null;
488
655
  /** @ignore */
489
- this.isSlidingFromLeft = computed(() => (this.dir() === 'ltr' && !this.inverted()) || (this.dir() !== 'ltr' && this.inverted()), ...(ngDevMode ? [{ debugName: "isSlidingFromLeft" }] : []));
656
+ this.pressedInput = null;
657
+ /** @ignore Snapshot of values at drag start, the baseline for push/swap. */
658
+ this.pressedValues = null;
490
659
  /** @ignore */
491
- this.isSlidingFromBottom = computed(() => !this.inverted(), ...(ngDevMode ? [{ debugName: "isSlidingFromBottom" }] : []));
660
+ this.lastChangeReason = 'none';
492
661
  /** @ignore */
493
- this.thumbElements = [];
662
+ this.isDisabled = computed(() => !!this.cva.disabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
663
+ /** @ignore The current value source (controlled value, else default, else min). */
664
+ this.currentRaw = computed(() => this.cva.value() ?? this.defaultValue() ?? this.min(), ...(ngDevMode ? [{ debugName: "currentRaw" }] : /* istanbul ignore next */ []));
665
+ /** Whether the slider has multiple thumbs (the value is an array). */
666
+ this.range = computed(() => Array.isArray(this.cva.value() ?? this.defaultValue()), ...(ngDevMode ? [{ debugName: "range" }] : /* istanbul ignore next */ []));
667
+ /** The clamped values rendered to the user, sorted ascending for range sliders. */
668
+ this.values = computed(() => {
669
+ const raw = this.currentRaw();
670
+ const min = this.min();
671
+ const max = this.max();
672
+ const arr = (Array.isArray(raw) ? raw.slice() : [raw]).map((v) => clamp(v, min, max));
673
+ return this.range() ? arr.sort(asc) : arr;
674
+ }, ...(ngDevMode ? [{ debugName: "values" }] : /* istanbul ignore next */ []));
675
+ this.thumbs = signal([], ...(ngDevMode ? [{ debugName: "thumbs" }] : /* istanbul ignore next */ []));
676
+ /** Registered thumbs in DOM order. */
677
+ this.thumbList = this.thumbs.asReadonly();
494
678
  }
495
679
  /** @ignore */
496
- ngOnInit() {
497
- const isHorizontal = this.orientation() === 'horizontal';
498
- if (isHorizontal) {
499
- this.orientationContext.updateContext({
500
- direction: this.isSlidingFromLeft() ? 1 : -1,
501
- size: 'width',
502
- startEdge: this.isSlidingFromLeft() ? 'left' : 'right',
503
- endEdge: this.isSlidingFromLeft() ? 'right' : 'left'
504
- });
505
- }
506
- else {
507
- this.orientationContext.updateContext({
508
- direction: this.isSlidingFromBottom() ? -1 : 1,
509
- size: 'height',
510
- startEdge: this.isSlidingFromBottom() ? 'bottom' : 'top',
511
- endEdge: this.isSlidingFromBottom() ? 'top' : 'bottom'
512
- });
513
- }
680
+ registerThumb(thumb) {
681
+ this.thumbs.update((list) => sortByDomOrder([...list, thumb]));
514
682
  }
515
683
  /** @ignore */
516
- onPointerDown() {
517
- this.valuesBeforeSlideStart.set([...this.modelValue()]);
684
+ unregisterThumb(thumb) {
685
+ this.thumbs.update((list) => list.filter((t) => t !== thumb));
518
686
  }
519
687
  /** @ignore */
520
- handleSlideStart(value) {
521
- const closestIndex = getClosestValueIndex(this.modelValue(), value);
522
- this.updateValues(value, closestIndex);
688
+ thumbIndexOf(thumb) {
689
+ return this.thumbList().indexOf(thumb);
523
690
  }
524
691
  /** @ignore */
525
- handleSlideMove(value) {
526
- this.updateValues(value, this.valueIndexToChange());
527
- }
528
- /** @ignore */
529
- handleSlideEnd() {
530
- const prevValue = this.valuesBeforeSlideStart()[this.valueIndexToChange()];
531
- const nextValue = this.modelValue()[this.valueIndexToChange()];
532
- const hasChanged = nextValue !== prevValue;
533
- if (hasChanged) {
534
- this.valueCommit.emit([...this.modelValue()]);
692
+ setActive(index) {
693
+ this.active.set(index);
694
+ if (index !== -1) {
695
+ this.lastUsedThumbIndex.set(index);
535
696
  }
536
697
  }
537
698
  /** @ignore */
538
- handleStepKeyDown(event) {
539
- const stepInDirection = this.step() * event.direction;
540
- const atIndex = this.valueIndexToChange();
541
- const currentValue = this.modelValue()[atIndex];
542
- this.updateValues(currentValue + stepInDirection, atIndex, true);
699
+ focusThumb(index) {
700
+ this.thumbList()[index]?.inputElement?.focus({ preventScroll: true });
543
701
  }
544
702
  /** @ignore */
545
- updateValues(value, atIndex, commit = false) {
546
- const decimalCount = getDecimalCount(this.step());
547
- const snapToStep = roundValue(Math.round((value - this.min()) / this.step()) * this.step() + this.min(), decimalCount);
548
- const nextValue = clamp(snapToStep, this.min(), this.max());
549
- const nextValues = getNextSortedValues(this.modelValue(), nextValue, atIndex);
550
- if (hasMinStepsBetweenValues(nextValues, this.minStepsBetweenThumbs() * this.step())) {
551
- this.valueIndexToChange.set(nextValues.indexOf(nextValue));
552
- const hasChanged = String(nextValues) !== String(this.modelValue());
553
- if (hasChanged) {
554
- this.modelValue.set(nextValues);
555
- this.valueChange.emit([...this.modelValue()]);
556
- this.thumbElements[this.valueIndexToChange()]?.focus();
557
- if (commit) {
558
- this.valueCommit.emit([...this.modelValue()]);
559
- }
560
- }
703
+ formatValue(value) {
704
+ return formatNumber(value, this.locale(), this.format());
705
+ }
706
+ /** @ignore Output value matching the original value shape (number vs array). */
707
+ outputValue() {
708
+ const raw = this.cva.value();
709
+ if (raw !== undefined) {
710
+ return raw;
561
711
  }
712
+ return this.range() ? this.values() : this.values()[0];
562
713
  }
563
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderRootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
564
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.3", type: RdxSliderRootComponent, isStandalone: true, selector: "rdx-slider", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, minStepsBetweenThumbs: { classPropertyName: "minStepsBetweenThumbs", publicName: "minStepsBetweenThumbs", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, inverted: { classPropertyName: "inverted", publicName: "inverted", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: false, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, modelValue: { classPropertyName: "modelValue", publicName: "modelValue", isSignal: true, isRequired: false, transformFunction: null }, valueIndexToChange: { classPropertyName: "valueIndexToChange", publicName: "valueIndexToChange", isSignal: true, isRequired: false, transformFunction: null }, valuesBeforeSlideStart: { classPropertyName: "valuesBeforeSlideStart", publicName: "valuesBeforeSlideStart", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modelValue: "modelValueChange", valueChange: "valueChange", valueCommit: "valueCommit", valueIndexToChange: "valueIndexToChangeChange", valuesBeforeSlideStart: "valuesBeforeSlideStartChange" }, providers: [RdxSliderOrientationContextService], ngImport: i0, template: `
565
- <ng-template #transclude><ng-content /></ng-template>
566
-
567
- @if (orientation() === 'horizontal') {
568
- <rdx-slider-horizontal
569
- [className]="styleClass() || className"
570
- [min]="min()"
571
- [max]="max()"
572
- [dir]="dir()"
573
- [inverted]="inverted()"
574
- [attr.aria-disabled]="disabled()"
575
- [attr.data-disabled]="disabled() ? '' : undefined"
576
- (pointerdown)="onPointerDown()"
577
- (slideStart)="handleSlideStart($event)"
578
- (slideMove)="handleSlideMove($event)"
579
- (slideEnd)="handleSlideEnd()"
580
- (homeKeyDown)="updateValues(min(), 0, true)"
581
- (endKeyDown)="updateValues(max(), modelValue().length - 1, true)"
582
- (stepKeyDown)="handleStepKeyDown($event)"
583
- >
584
- <ng-container *ngTemplateOutlet="transclude" />
585
- </rdx-slider-horizontal>
714
+ /**
715
+ * @ignore
716
+ * Applies a new full set of values, preserving the single/range value shape.
717
+ * Returns `false` when the value did not change.
718
+ */
719
+ setValue(nextValues, reason) {
720
+ const next = this.range() ? nextValues : nextValues[0];
721
+ const current = this.outputValue();
722
+ const hasNaN = Array.isArray(next) ? next.some((v) => Number.isNaN(v)) : Number.isNaN(next);
723
+ if (hasNaN || areValuesEqual(next, current)) {
724
+ return false;
586
725
  }
587
-
588
- @if (orientation() === 'vertical') {
589
- <rdx-slider-vertical
590
- [className]="styleClass() || className"
591
- [min]="min()"
592
- [max]="max()"
593
- [dir]="dir()"
594
- [inverted]="inverted()"
595
- [attr.aria-disabled]="disabled()"
596
- [attr.data-disabled]="disabled() ? '' : undefined"
597
- (pointerdown)="onPointerDown()"
598
- (slideStart)="handleSlideStart($event)"
599
- (slideMove)="handleSlideMove($event)"
600
- (slideEnd)="handleSlideEnd()"
601
- (homeKeyDown)="updateValues(min(), 0, true)"
602
- (endKeyDown)="updateValues(max(), modelValue().length - 1, true)"
603
- (stepKeyDown)="handleStepKeyDown($event)"
604
- >
605
- <ng-container *ngTemplateOutlet="transclude" />
606
- </rdx-slider-vertical>
607
- }
608
- `, isInline: true, dependencies: [{ kind: "component", type: RdxSliderHorizontalComponent, selector: "rdx-slider-horizontal", inputs: ["dir", "inverted", "min", "max", "className"], outputs: ["slideStart", "slideMove", "slideEnd", "stepKeyDown", "endKeyDown", "homeKeyDown"] }, { kind: "component", type: RdxSliderVerticalComponent, selector: "rdx-slider-vertical", inputs: ["dir", "inverted", "min", "max", "className"], outputs: ["slideStart", "slideMove", "slideEnd", "stepKeyDown", "endKeyDown", "homeKeyDown"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
726
+ this.lastChangeReason = reason;
727
+ this.value.set(next);
728
+ this.cva.setValue(next);
729
+ this.onValueChange.emit(next);
730
+ return true;
731
+ }
732
+ /** @ignore Keyboard / native input path: clamps to neighbours, commits immediately. */
733
+ handleInputChange(valueInput, index, reason = 'keyboard') {
734
+ if (this.isDisabled()) {
735
+ return;
736
+ }
737
+ const result = getSliderValue(valueInput, index, this.min(), this.max(), this.range(), this.values());
738
+ if (!validateMinimumDistance(result, this.step(), this.minStepsBetweenValues())) {
739
+ return;
740
+ }
741
+ const arr = Array.isArray(result) ? result : [result];
742
+ const applied = this.setValue(arr, reason);
743
+ this.cva.markAsTouched();
744
+ if (applied) {
745
+ this.onValueCommitted.emit(this.outputValue());
746
+ }
747
+ }
748
+ /** @ignore Emits the committed value at the end of a pointer drag. */
749
+ commitValue() {
750
+ this.onValueCommitted.emit(this.outputValue());
751
+ }
752
+ /** @ignore */
753
+ markAsTouched() {
754
+ this.cva.markAsTouched();
755
+ }
756
+ /** @ignore */
757
+ setDragging(dragging) {
758
+ this.dragging.set(dragging);
759
+ }
760
+ /** @ignore */
761
+ resetPressedThumb() {
762
+ this.pressedThumbIndex = -1;
763
+ this.pressedThumbCenterOffset = null;
764
+ this.pressedInput = null;
765
+ }
766
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
767
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSliderRoot, isStandalone: true, selector: "div[rdxSliderRoot]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, largeStep: { classPropertyName: "largeStep", publicName: "largeStep", isSignal: true, isRequired: false, transformFunction: null }, minStepsBetweenValues: { classPropertyName: "minStepsBetweenValues", publicName: "minStepsBetweenValues", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, thumbCollisionBehavior: { classPropertyName: "thumbCollisionBehavior", publicName: "thumbCollisionBehavior", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onValueChange: "onValueChange", onValueCommitted: "onValueCommitted" }, host: { attributes: { "role": "group" }, properties: { "id": "id()", "attr.aria-labelledby": "ariaLabelledBy()", "attr.dir": "dir()", "attr.data-orientation": "orientation()", "attr.data-disabled": "isDisabled() ? \"\" : undefined", "attr.data-dragging": "dragging() ? \"\" : undefined" } }, providers: [provideSliderRootContext(() => inject(RdxSliderRoot))], exportAs: ["rdxSliderRoot"], hostDirectives: [{ directive: i1.RdxControlValueAccessor, inputs: ["value", "value", "disabled", "disabled"] }], ngImport: i0 }); }
609
768
  }
610
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderRootComponent, decorators: [{
611
- type: Component,
769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderRoot, decorators: [{
770
+ type: Directive,
612
771
  args: [{
613
- selector: 'rdx-slider',
614
- imports: [RdxSliderHorizontalComponent, RdxSliderVerticalComponent, NgTemplateOutlet],
615
- providers: [RdxSliderOrientationContextService],
616
- template: `
617
- <ng-template #transclude><ng-content /></ng-template>
618
-
619
- @if (orientation() === 'horizontal') {
620
- <rdx-slider-horizontal
621
- [className]="styleClass() || className"
622
- [min]="min()"
623
- [max]="max()"
624
- [dir]="dir()"
625
- [inverted]="inverted()"
626
- [attr.aria-disabled]="disabled()"
627
- [attr.data-disabled]="disabled() ? '' : undefined"
628
- (pointerdown)="onPointerDown()"
629
- (slideStart)="handleSlideStart($event)"
630
- (slideMove)="handleSlideMove($event)"
631
- (slideEnd)="handleSlideEnd()"
632
- (homeKeyDown)="updateValues(min(), 0, true)"
633
- (endKeyDown)="updateValues(max(), modelValue().length - 1, true)"
634
- (stepKeyDown)="handleStepKeyDown($event)"
635
- >
636
- <ng-container *ngTemplateOutlet="transclude" />
637
- </rdx-slider-horizontal>
638
- }
639
-
640
- @if (orientation() === 'vertical') {
641
- <rdx-slider-vertical
642
- [className]="styleClass() || className"
643
- [min]="min()"
644
- [max]="max()"
645
- [dir]="dir()"
646
- [inverted]="inverted()"
647
- [attr.aria-disabled]="disabled()"
648
- [attr.data-disabled]="disabled() ? '' : undefined"
649
- (pointerdown)="onPointerDown()"
650
- (slideStart)="handleSlideStart($event)"
651
- (slideMove)="handleSlideMove($event)"
652
- (slideEnd)="handleSlideEnd()"
653
- (homeKeyDown)="updateValues(min(), 0, true)"
654
- (endKeyDown)="updateValues(max(), modelValue().length - 1, true)"
655
- (stepKeyDown)="handleStepKeyDown($event)"
656
- >
657
- <ng-container *ngTemplateOutlet="transclude" />
658
- </rdx-slider-vertical>
659
- }
660
- `
772
+ selector: 'div[rdxSliderRoot]',
773
+ exportAs: 'rdxSliderRoot',
774
+ providers: [provideSliderRootContext(() => inject(RdxSliderRoot))],
775
+ hostDirectives: [
776
+ {
777
+ directive: RdxControlValueAccessor,
778
+ inputs: ['value: value', 'disabled']
779
+ }
780
+ ],
781
+ host: {
782
+ role: 'group',
783
+ '[id]': 'id()',
784
+ '[attr.aria-labelledby]': 'ariaLabelledBy()',
785
+ '[attr.dir]': 'dir()',
786
+ '[attr.data-orientation]': 'orientation()',
787
+ '[attr.data-disabled]': 'isDisabled() ? "" : undefined',
788
+ '[attr.data-dragging]': 'dragging() ? "" : undefined'
789
+ }
661
790
  }]
662
- }], propDecorators: { className: [{
663
- type: Input
664
- }] } });
791
+ }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], largeStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "largeStep", required: false }] }], minStepsBetweenValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "minStepsBetweenValues", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], thumbCollisionBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "thumbCollisionBehavior", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onValueCommitted: [{ type: i0.Output, args: ["onValueCommitted"] }] } });
665
792
 
666
- class RdxSliderRangeComponent {
793
+ /**
794
+ * A draggable handle. Render one per value; place an `input[rdxSliderThumbInput]`
795
+ * inside it for keyboard, accessibility and form submission.
796
+ *
797
+ * @see https://base-ui.com/react/components/slider
798
+ */
799
+ class RdxSliderThumb {
667
800
  constructor() {
668
- this.rootContext = inject(RdxSliderRootComponent);
669
- this.percentages = computed(() => this.rootContext
670
- .modelValue()
671
- ?.map((value) => convertValueToPercentage(value, this.rootContext.min(), this.rootContext.max())), ...(ngDevMode ? [{ debugName: "percentages" }] : []));
672
- this.offsetStart = computed(() => (this.rootContext.modelValue().length > 1 ? Math.min(...this.percentages()) : 0), ...(ngDevMode ? [{ debugName: "offsetStart" }] : []));
673
- this.offsetEnd = computed(() => 100 - Math.max(...this.percentages()), ...(ngDevMode ? [{ debugName: "offsetEnd" }] : []));
674
- this.rangeStyles = computed(() => {
675
- const context = this.rootContext.orientationContext.context;
676
- return {
677
- [context.startEdge]: `${this.offsetStart()}%`,
678
- [context.endEdge]: `${this.offsetEnd()}%`
801
+ this.root = injectSliderRootContext();
802
+ this.element = inject(ElementRef).nativeElement;
803
+ /** The nested range input, set by `[rdxSliderThumbInput]`. */
804
+ this.inputElement = null;
805
+ /** Explicit index for this thumb (required for SSR range sliders). */
806
+ this.indexInput = input(undefined, { ...(ngDevMode ? { debugName: "indexInput" } : /* istanbul ignore next */ {}), alias: 'index',
807
+ transform: (v) => (v == null ? undefined : numberAttribute(v)) });
808
+ /** Disables this individual thumb. */
809
+ this.thumbDisabled = input(false, { ...(ngDevMode ? { debugName: "thumbDisabled" } : /* istanbul ignore next */ {}), alias: 'disabled', transform: booleanAttribute });
810
+ /** The position of this thumb among its siblings. */
811
+ this.index = computed(() => this.indexInput() ?? this.root.thumbIndexOf(this), ...(ngDevMode ? [{ debugName: "index" }] : /* istanbul ignore next */ []));
812
+ /** Whether this thumb is disabled (own state OR root disabled). */
813
+ this.disabled = computed(() => this.thumbDisabled() || this.root.isDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
814
+ /** The value represented by this thumb. */
815
+ this.value = computed(() => this.root.values()[this.index()], ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
816
+ this.percent = computed(() => {
817
+ const value = this.value();
818
+ return value === undefined ? NaN : valueToPercent(value, this.root.min(), this.root.max());
819
+ }, ...(ngDevMode ? [{ debugName: "percent" }] : /* istanbul ignore next */ []));
820
+ this.thumbStyle = computed(() => {
821
+ const vertical = this.root.orientation() === 'vertical';
822
+ const rtl = this.root.dir() === 'rtl';
823
+ const startEdge = vertical ? 'bottom' : 'inset-inline-start';
824
+ const crossOffset = vertical ? 'left' : 'top';
825
+ const percent = this.percent();
826
+ if (!Number.isFinite(percent)) {
827
+ return { position: 'absolute', visibility: 'hidden' };
828
+ }
829
+ const index = this.index();
830
+ let zIndex;
831
+ if (this.root.range()) {
832
+ if (this.root.active() === index) {
833
+ zIndex = 2;
834
+ }
835
+ else if (this.root.lastUsedThumbIndex() === index) {
836
+ zIndex = 1;
837
+ }
838
+ }
839
+ else if (this.root.active() === index) {
840
+ zIndex = 1;
841
+ }
842
+ const style = {
843
+ position: 'absolute',
844
+ [startEdge]: `${percent}%`,
845
+ [crossOffset]: '50%',
846
+ translate: `${(vertical || !rtl ? -1 : 1) * 50}% ${(vertical ? 1 : -1) * 50}%`
679
847
  };
680
- }, ...(ngDevMode ? [{ debugName: "rangeStyles" }] : []));
848
+ if (zIndex !== undefined) {
849
+ style['z-index'] = zIndex;
850
+ }
851
+ return style;
852
+ }, ...(ngDevMode ? [{ debugName: "thumbStyle" }] : /* istanbul ignore next */ []));
853
+ // Registration is DOM-order sorted on the root and reads no inputs, so the constructor
854
+ // (where the host element already exists) is the right place; cleanup goes via DestroyRef.
855
+ this.root.registerThumb(this);
856
+ inject(DestroyRef).onDestroy(() => this.root.unregisterThumb(this));
681
857
  }
682
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderRangeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
683
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.3", type: RdxSliderRangeComponent, isStandalone: true, selector: "rdx-slider-range", host: { properties: { "attr.data-disabled": "rootContext.disabled() ? \"\" : undefined", "attr.data-orientation": "rootContext.orientation()", "style": "rangeStyles()" } }, ngImport: i0, template: `
684
- <ng-content />
685
- `, isInline: true }); }
858
+ onPointerDown(event) {
859
+ if (this.disabled()) {
860
+ return;
861
+ }
862
+ const index = this.index();
863
+ this.root.pressedThumbIndex = index;
864
+ const axis = this.root.orientation() === 'horizontal' ? 'x' : 'y';
865
+ const rect = this.element.getBoundingClientRect();
866
+ const midpoint = axis === 'x' ? (rect.left + rect.right) / 2 : (rect.top + rect.bottom) / 2;
867
+ const pointer = axis === 'x' ? event.clientX : event.clientY;
868
+ this.root.pressedThumbCenterOffset = pointer - midpoint;
869
+ if (this.inputElement) {
870
+ this.root.pressedInput = this.inputElement;
871
+ }
872
+ }
873
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderThumb, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
874
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSliderThumb, isStandalone: true, selector: "div[rdxSliderThumb]", inputs: { indexInput: { classPropertyName: "indexInput", publicName: "index", isSignal: true, isRequired: false, transformFunction: null }, thumbDisabled: { classPropertyName: "thumbDisabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "pointerdown": "onPointerDown($event)" }, properties: { "style": "thumbStyle()", "attr.data-index": "index()", "attr.data-orientation": "root.orientation()", "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.data-dragging": "root.dragging() ? \"\" : undefined" } }, exportAs: ["rdxSliderThumb"], ngImport: i0 }); }
686
875
  }
687
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderRangeComponent, decorators: [{
688
- type: Component,
876
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderThumb, decorators: [{
877
+ type: Directive,
689
878
  args: [{
690
- selector: 'rdx-slider-range',
879
+ selector: 'div[rdxSliderThumb]',
880
+ exportAs: 'rdxSliderThumb',
691
881
  host: {
692
- '[attr.data-disabled]': 'rootContext.disabled() ? "" : undefined',
693
- '[attr.data-orientation]': 'rootContext.orientation()',
694
- '[style]': 'rangeStyles()'
695
- },
696
- template: `
697
- <ng-content />
698
- `
882
+ '[style]': 'thumbStyle()',
883
+ '[attr.data-index]': 'index()',
884
+ '[attr.data-orientation]': 'root.orientation()',
885
+ '[attr.data-disabled]': 'disabled() ? "" : undefined',
886
+ '[attr.data-dragging]': 'root.dragging() ? "" : undefined',
887
+ '(pointerdown)': 'onPointerDown($event)'
888
+ }
699
889
  }]
700
- }] });
890
+ }], ctorParameters: () => [], propDecorators: { indexInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: false }] }], thumbDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
701
891
 
702
- class RdxSliderThumbImplDirective {
892
+ /**
893
+ * The native `input[type=range]` nested inside a thumb. It is visually hidden but
894
+ * remains the focusable element that drives keyboard interaction, accessibility
895
+ * and form submission.
896
+ *
897
+ * @see https://base-ui.com/react/components/slider
898
+ */
899
+ class RdxSliderThumbInput {
703
900
  constructor() {
704
- this.rootContext = inject(RdxSliderRootComponent);
705
- this.elementRef = inject(ElementRef);
706
- this.platformId = inject(PLATFORM_ID);
707
- this.isMounted = signal(false, ...(ngDevMode ? [{ debugName: "isMounted" }] : []));
708
- this.thumbIndex = computed(() => {
709
- const thumbElement = this.elementRef.nativeElement;
710
- const index = this.rootContext.thumbElements.indexOf(thumbElement);
711
- return index >= 0 ? index : null;
712
- }, ...(ngDevMode ? [{ debugName: "thumbIndex" }] : []));
713
- this.value = computed(() => {
714
- const index = this.thumbIndex();
715
- if (index === null)
716
- return undefined;
717
- return this.rootContext.modelValue()?.[index];
718
- }, ...(ngDevMode ? [{ debugName: "value" }] : []));
719
- this.percent = computed(() => {
720
- const val = this.value();
721
- if (val === undefined)
722
- return 0;
723
- return convertValueToPercentage(val, this.rootContext.min(), this.rootContext.max());
724
- }, ...(ngDevMode ? [{ debugName: "percent" }] : []));
725
- this.transform = computed(() => {
726
- const percent = this.percent();
727
- const offset = this.thumbInBoundsOffset();
728
- return `calc(${percent}% + ${offset}px)`;
729
- }, ...(ngDevMode ? [{ debugName: "transform" }] : []));
730
- this.orientationSize = signal(0, ...(ngDevMode ? [{ debugName: "orientationSize" }] : []));
731
- this.thumbInBoundsOffset = computed(() => {
732
- const context = this.rootContext.orientationContext.context;
733
- const size = this.orientationSize();
734
- const percent = this.percent();
735
- const direction = context.direction;
736
- return size ? getThumbInBoundsOffset(size, percent, direction) : 0;
737
- }, ...(ngDevMode ? [{ debugName: "thumbInBoundsOffset" }] : []));
738
- this.combinedStyles = computed(() => {
739
- const context = this.rootContext.orientationContext.context;
740
- const startEdge = context.startEdge;
741
- const percent = this.percent();
742
- const offset = this.thumbInBoundsOffset();
743
- return {
744
- position: 'absolute',
745
- transform: 'var(--rdx-slider-thumb-transform)',
746
- display: (this.isMounted() && this.value()) === false ? 'none' : undefined,
747
- [startEdge]: `calc(${percent}% + ${offset}px)`
748
- };
749
- }, ...(ngDevMode ? [{ debugName: "combinedStyles" }] : []));
901
+ this.root = injectSliderRootContext();
902
+ this.thumb = inject(RdxSliderThumb);
903
+ this.element = inject(ElementRef).nativeElement;
904
+ this.ariaLabel = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
905
+ this.ariaValueTextInput = input(undefined, { ...(ngDevMode ? { debugName: "ariaValueTextInput" } : /* istanbul ignore next */ {}), alias: 'aria-valuetext' });
906
+ this.writingMode = computed(() => this.root.orientation() === 'vertical' ? (this.root.dir() === 'rtl' ? 'vertical-rl' : 'vertical-lr') : undefined, ...(ngDevMode ? [{ debugName: "writingMode" }] : /* istanbul ignore next */ []));
907
+ this.ariaLabelledBy = computed(() => this.ariaLabel() == null ? this.root.ariaLabelledBy() : undefined, ...(ngDevMode ? [{ debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ []));
908
+ this.valueText = computed(() => this.ariaValueTextInput() ??
909
+ getDefaultAriaValueText(this.root.values(), this.thumb.index(), this.root.format(), this.root.locale()), ...(ngDevMode ? [{ debugName: "valueText" }] : /* istanbul ignore next */ []));
910
+ // Host element exists in the constructor and the registration has no input dependency.
911
+ this.thumb.inputElement = this.element;
912
+ inject(DestroyRef).onDestroy(() => {
913
+ if (this.thumb.inputElement === this.element) {
914
+ this.thumb.inputElement = null;
915
+ }
916
+ });
917
+ }
918
+ onChange(event) {
919
+ const value = event.target.valueAsNumber;
920
+ if (!Number.isNaN(value)) {
921
+ this.root.handleInputChange(value, this.thumb.index(), 'input');
922
+ }
750
923
  }
751
924
  onFocus() {
752
- if (this.thumbIndex() !== null) {
753
- this.rootContext.valueIndexToChange.set(this.thumbIndex());
754
- }
755
- }
756
- ngOnInit() {
757
- if (isPlatformBrowser(this.platformId)) {
758
- const thumbElement = this.elementRef.nativeElement;
759
- this.rootContext.thumbElements.push(thumbElement);
760
- this.resizeObserver = new ResizeObserver(() => {
761
- const rect = thumbElement.getBoundingClientRect();
762
- const context = this.rootContext.orientationContext.context;
763
- const size = context.size === 'width' ? rect.width : rect.height;
764
- this.orientationSize.set(size);
765
- });
766
- this.resizeObserver.observe(thumbElement);
767
- this.isMounted.set(true);
768
- }
769
- }
770
- ngOnDestroy() {
771
- const thumbElement = this.elementRef.nativeElement;
772
- const index = this.rootContext.thumbElements.indexOf(thumbElement);
773
- if (index >= 0)
774
- this.rootContext.thumbElements.splice(index, 1);
775
- if (this.resizeObserver) {
776
- this.resizeObserver.unobserve(thumbElement);
777
- }
778
- this.isMounted.set(false);
779
- }
780
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderThumbImplDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
781
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxSliderThumbImplDirective, isStandalone: true, selector: "[rdxSliderThumbImpl]", host: { attributes: { "role": "slider" }, listeners: { "focus": "onFocus()" }, properties: { "tabindex": "rootContext.disabled() ? undefined : 0", "attr.aria-valuenow": "rootContext.modelValue()", "attr.aria-valuemin": "rootContext.min()", "attr.aria-valuemax": "rootContext.max()", "attr.aria-orientation": "rootContext.orientation()", "attr.data-orientation": "rootContext.orientation()", "attr.data-disabled": "rootContext.disabled() ? \"\" : undefined", "style": "combinedStyles()" } }, ngImport: i0 }); }
925
+ this.root.setActive(this.thumb.index());
926
+ }
927
+ onBlur() {
928
+ this.root.setActive(-1);
929
+ this.root.markAsTouched();
930
+ }
931
+ onKeyDown(event) {
932
+ if (event.defaultPrevented || !ALL_KEYS.has(event.key)) {
933
+ return;
934
+ }
935
+ if (COMPOSITE_KEYS.has(event.key)) {
936
+ event.stopPropagation();
937
+ }
938
+ const min = this.root.min();
939
+ const max = this.root.max();
940
+ const step = this.root.step();
941
+ const largeStep = this.root.largeStep();
942
+ const rtl = this.root.dir() === 'rtl';
943
+ const range = this.root.range();
944
+ const values = this.root.values();
945
+ const index = this.thumb.index();
946
+ const thumbValue = values[index];
947
+ const rounded = roundValueToStep(thumbValue, step, min);
948
+ let newValue = null;
949
+ switch (event.key) {
950
+ case 'ArrowUp':
951
+ newValue = getNewValue(rounded, event.shiftKey ? largeStep : step, 1, min, max);
952
+ break;
953
+ case 'ArrowRight':
954
+ newValue = getNewValue(rounded, event.shiftKey ? largeStep : step, rtl ? -1 : 1, min, max);
955
+ break;
956
+ case 'ArrowDown':
957
+ newValue = getNewValue(rounded, event.shiftKey ? largeStep : step, -1, min, max);
958
+ break;
959
+ case 'ArrowLeft':
960
+ newValue = getNewValue(rounded, event.shiftKey ? largeStep : step, rtl ? 1 : -1, min, max);
961
+ break;
962
+ case 'PageUp':
963
+ newValue = getNewValue(rounded, largeStep, 1, min, max);
964
+ break;
965
+ case 'PageDown':
966
+ newValue = getNewValue(rounded, largeStep, -1, min, max);
967
+ break;
968
+ case 'End':
969
+ newValue =
970
+ range && Number.isFinite(values[index + 1])
971
+ ? values[index + 1] - step * this.root.minStepsBetweenValues()
972
+ : max;
973
+ break;
974
+ case 'Home':
975
+ newValue =
976
+ range && Number.isFinite(values[index - 1])
977
+ ? values[index - 1] + step * this.root.minStepsBetweenValues()
978
+ : min;
979
+ break;
980
+ default:
981
+ break;
982
+ }
983
+ if (newValue !== null) {
984
+ this.root.handleInputChange(newValue, index, 'keyboard');
985
+ event.preventDefault();
986
+ }
987
+ }
988
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderThumbInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
989
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSliderThumbInput, isStandalone: true, selector: "input[rdxSliderThumbInput]", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaValueTextInput: { classPropertyName: "ariaValueTextInput", publicName: "aria-valuetext", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "range" }, listeners: { "keydown": "onKeyDown($event)", "change": "onChange($event)", "focus": "onFocus()", "blur": "onBlur()" }, properties: { "style.writing-mode": "writingMode()", "attr.min": "root.min()", "attr.max": "root.max()", "attr.step": "root.step()", "value": "thumb.value() ?? \"\"", "disabled": "thumb.disabled()", "attr.name": "root.name()", "attr.form": "root.form()", "attr.aria-orientation": "root.orientation()", "attr.aria-valuenow": "thumb.value()", "attr.aria-valuetext": "valueText()", "attr.aria-label": "ariaLabel()", "attr.aria-labelledby": "ariaLabelledBy()", "attr.data-index": "thumb.index()" }, styleAttribute: "position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; cursor: inherit;" }, exportAs: ["rdxSliderThumbInput"], ngImport: i0 }); }
782
990
  }
783
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderThumbImplDirective, decorators: [{
991
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderThumbInput, decorators: [{
784
992
  type: Directive,
785
993
  args: [{
786
- selector: '[rdxSliderThumbImpl]',
994
+ selector: 'input[rdxSliderThumbInput]',
995
+ exportAs: 'rdxSliderThumbInput',
787
996
  host: {
788
- role: 'slider',
789
- '[tabindex]': 'rootContext.disabled() ? undefined : 0',
790
- '[attr.aria-valuenow]': 'rootContext.modelValue()',
791
- '[attr.aria-valuemin]': 'rootContext.min()',
792
- '[attr.aria-valuemax]': 'rootContext.max()',
793
- '[attr.aria-orientation]': 'rootContext.orientation()',
794
- '[attr.data-orientation]': 'rootContext.orientation()',
795
- '[attr.data-disabled]': 'rootContext.disabled() ? "" : undefined',
796
- '[style]': 'combinedStyles()',
797
- '(focus)': 'onFocus()'
997
+ type: 'range',
998
+ style: 'position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; cursor: inherit;',
999
+ '[style.writing-mode]': 'writingMode()',
1000
+ '[attr.min]': 'root.min()',
1001
+ '[attr.max]': 'root.max()',
1002
+ '[attr.step]': 'root.step()',
1003
+ '[value]': 'thumb.value() ?? ""',
1004
+ '[disabled]': 'thumb.disabled()',
1005
+ '[attr.name]': 'root.name()',
1006
+ '[attr.form]': 'root.form()',
1007
+ '[attr.aria-orientation]': 'root.orientation()',
1008
+ '[attr.aria-valuenow]': 'thumb.value()',
1009
+ '[attr.aria-valuetext]': 'valueText()',
1010
+ '[attr.aria-label]': 'ariaLabel()',
1011
+ '[attr.aria-labelledby]': 'ariaLabelledBy()',
1012
+ '[attr.data-index]': 'thumb.index()',
1013
+ '(keydown)': 'onKeyDown($event)',
1014
+ '(change)': 'onChange($event)',
1015
+ '(focus)': 'onFocus()',
1016
+ '(blur)': 'onBlur()'
798
1017
  }
799
1018
  }]
800
- }] });
1019
+ }], ctorParameters: () => [], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaValueTextInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-valuetext", required: false }] }] } });
801
1020
 
802
- class RdxSliderThumbComponent {
803
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderThumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
804
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.3", type: RdxSliderThumbComponent, isStandalone: true, selector: "rdx-slider-thumb", hostDirectives: [{ directive: RdxSliderThumbImplDirective }], ngImport: i0, template: `
805
- <ng-content />
806
- `, isInline: true }); }
1021
+ /**
1022
+ * The track of the slider the positioning context for the indicator and thumbs.
1023
+ *
1024
+ * @see https://base-ui.com/react/components/slider
1025
+ */
1026
+ class RdxSliderTrack {
1027
+ constructor() {
1028
+ this.root = injectSliderRootContext();
1029
+ }
1030
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderTrack, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1031
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSliderTrack, isStandalone: true, selector: "div[rdxSliderTrack]", host: { properties: { "attr.data-orientation": "root.orientation()", "attr.data-disabled": "root.isDisabled() ? \"\" : undefined", "attr.data-dragging": "root.dragging() ? \"\" : undefined" }, styleAttribute: "position: relative;" }, exportAs: ["rdxSliderTrack"], ngImport: i0 }); }
807
1032
  }
808
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderThumbComponent, decorators: [{
809
- type: Component,
1033
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderTrack, decorators: [{
1034
+ type: Directive,
810
1035
  args: [{
811
- selector: 'rdx-slider-thumb',
812
- hostDirectives: [RdxSliderThumbImplDirective],
813
- template: `
814
- <ng-content />
815
- `
1036
+ selector: 'div[rdxSliderTrack]',
1037
+ exportAs: 'rdxSliderTrack',
1038
+ host: {
1039
+ style: 'position: relative;',
1040
+ '[attr.data-orientation]': 'root.orientation()',
1041
+ '[attr.data-disabled]': 'root.isDisabled() ? "" : undefined',
1042
+ '[attr.data-dragging]': 'root.dragging() ? "" : undefined'
1043
+ }
816
1044
  }]
817
1045
  }] });
818
1046
 
819
- class RdxSliderTrackComponent {
1047
+ /**
1048
+ * Displays the slider's current value(s) as formatted text. Renders into an
1049
+ * `output` element; the displayed value honours the root `format` and `locale`.
1050
+ *
1051
+ * @see https://base-ui.com/react/components/slider
1052
+ */
1053
+ class RdxSliderValue {
820
1054
  constructor() {
821
- this.rootContext = inject(RdxSliderRootComponent);
1055
+ this.root = injectSliderRootContext();
1056
+ /** The separator placed between values of a range slider. */
1057
+ this.separator = input(' – ', ...(ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []));
1058
+ this.display = computed(() => this.root
1059
+ .values()
1060
+ .map((value) => this.root.formatValue(value) || `${value}`)
1061
+ .join(this.separator()), ...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []));
822
1062
  }
823
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderTrackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
824
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.3", type: RdxSliderTrackComponent, isStandalone: true, selector: "rdx-slider-track", host: { properties: { "attr.data-disabled": "rootContext.disabled() ? '' : undefined", "attr.data-orientation": "rootContext.orientation()" } }, ngImport: i0, template: `
825
- <ng-content />
826
- `, isInline: true }); }
1063
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderValue, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1064
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSliderValue, isStandalone: true, selector: "output[rdxSliderValue]", inputs: { separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-live": "off" }, properties: { "textContent": "display()" } }, exportAs: ["rdxSliderValue"], ngImport: i0 }); }
827
1065
  }
828
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderTrackComponent, decorators: [{
829
- type: Component,
1066
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderValue, decorators: [{
1067
+ type: Directive,
830
1068
  args: [{
831
- selector: 'rdx-slider-track',
1069
+ selector: 'output[rdxSliderValue]',
1070
+ exportAs: 'rdxSliderValue',
832
1071
  host: {
833
- '[attr.data-disabled]': "rootContext.disabled() ? '' : undefined",
834
- '[attr.data-orientation]': 'rootContext.orientation()'
835
- },
836
- template: `
837
- <ng-content />
838
- `
1072
+ 'aria-live': 'off',
1073
+ '[textContent]': 'display()'
1074
+ }
839
1075
  }]
840
- }] });
1076
+ }], propDecorators: { separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }] } });
841
1077
 
842
- const _imports = [RdxSliderRootComponent, RdxSliderTrackComponent, RdxSliderRangeComponent, RdxSliderThumbComponent];
1078
+ const _imports = [
1079
+ RdxSliderRoot,
1080
+ RdxSliderControl,
1081
+ RdxSliderTrack,
1082
+ RdxSliderIndicator,
1083
+ RdxSliderThumb,
1084
+ RdxSliderThumbInput,
1085
+ RdxSliderValue
1086
+ ];
843
1087
  class RdxSliderModule {
844
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
845
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderModule, imports: [RdxSliderRootComponent, RdxSliderTrackComponent, RdxSliderRangeComponent, RdxSliderThumbComponent], exports: [RdxSliderRootComponent, RdxSliderTrackComponent, RdxSliderRangeComponent, RdxSliderThumbComponent] }); }
846
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderModule }); }
1088
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1089
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderModule, imports: [RdxSliderRoot,
1090
+ RdxSliderControl,
1091
+ RdxSliderTrack,
1092
+ RdxSliderIndicator,
1093
+ RdxSliderThumb,
1094
+ RdxSliderThumbInput,
1095
+ RdxSliderValue], exports: [RdxSliderRoot,
1096
+ RdxSliderControl,
1097
+ RdxSliderTrack,
1098
+ RdxSliderIndicator,
1099
+ RdxSliderThumb,
1100
+ RdxSliderThumbInput,
1101
+ RdxSliderValue] }); }
1102
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderModule }); }
847
1103
  }
848
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxSliderModule, decorators: [{
1104
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSliderModule, decorators: [{
849
1105
  type: NgModule,
850
1106
  args: [{
851
1107
  imports: [..._imports],
@@ -857,5 +1113,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
857
1113
  * Generated bundle index. Do not edit.
858
1114
  */
859
1115
 
860
- export { RdxSliderHorizontalComponent, RdxSliderImplDirective, RdxSliderModule, RdxSliderRangeComponent, RdxSliderRootComponent, RdxSliderThumbComponent, RdxSliderThumbImplDirective, RdxSliderTrackComponent, RdxSliderVerticalComponent };
1116
+ export { ALL_KEYS, ARROW_KEYS, COMPOSITE_KEYS, RdxSliderControl, RdxSliderIndicator, RdxSliderModule, RdxSliderRoot, RdxSliderThumb, RdxSliderThumbInput, RdxSliderTrack, RdxSliderValue, areValuesEqual, asc, formatNumber, getControlOffset, getDecimalPrecision, getDefaultAriaValueText, getMidpoint, getNewValue, getPushedThumbValues, getSliderValue, injectSliderRootContext, provideSliderRootContext, replaceArrayItemAtIndex, resolveThumbCollision, roundValueToStep, validateMinimumDistance, valueArrayToPercentages, valueToPercent };
861
1117
  //# sourceMappingURL=radix-ng-primitives-slider.mjs.map