@sit-onyx/headless 0.4.0-dev-20251112133447 → 0.4.0-dev-20251118074438

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -959,465 +959,204 @@ const createNavigationMenu = createBuilder(({ navigationName }) => {
959
959
  };
960
960
  });
961
961
  const areArraysEqual = (arrayA, arrayB, comparer = (a, b) => a === b) => arrayA.length === arrayB.length && arrayA.every((value, index) => comparer(value, arrayB[index]));
962
- const isFocusVisible = (element) => {
963
- try {
964
- return element.matches(":focus-visible");
965
- } catch {
966
- return false;
967
- }
968
- };
969
- const isTouchEvent = (event) => "touches" in event || "changedTouches" in event || "targetTouches" in event;
970
- const DRAG_MOVE_THRESHOLD = 2;
971
- const KEY = {
972
- Up: "ArrowUp",
973
- Down: "ArrowDown",
974
- Left: "ArrowLeft",
975
- Right: "ArrowRight",
976
- PageUp: "PageUp",
977
- PageDown: "PageDown",
978
- Home: "Home",
979
- End: "End"
980
- };
981
962
  const NAVIGATION_KEYS = /* @__PURE__ */ new Set([
982
- KEY.Up,
983
- KEY.Down,
984
- KEY.Left,
985
- KEY.Right,
986
- KEY.PageUp,
987
- KEY.PageDown,
988
- KEY.Home,
989
- KEY.End
963
+ "ArrowUp",
964
+ "ArrowDown",
965
+ "ArrowLeft",
966
+ "ArrowRight",
967
+ "PageUp",
968
+ "PageDown",
969
+ "Home",
970
+ "End"
990
971
  ]);
991
- const INCREMENT_KEYS = /* @__PURE__ */ new Set([KEY.Right, KEY.Up, KEY.PageUp]);
992
- const DECREMENT_KEYS = /* @__PURE__ */ new Set([KEY.Left, KEY.Down, KEY.PageDown]);
993
- const readThumbIndex = (event) => Number(event.currentTarget?.dataset.index ?? -1);
994
- const roundToStep = (value, step, min) => Number((Math.round((value - min) / step) * step + min).toFixed(MathUtils.decimalsCount(step)));
995
- const findClosestIndex = (values, currentValue) => {
996
- const result = values.reduce((acc, value, index) => {
997
- const distance = Math.abs(currentValue - value);
998
- if (!acc || distance <= acc.closestDistance) {
999
- return {
1000
- closestIndex: index,
1001
- closestDistance: distance
1002
- };
1003
- }
1004
- return acc;
1005
- }, null);
1006
- return result?.closestIndex ?? -1;
1007
- };
1008
- const adjustValueByIndex = ({
1009
- values,
1010
- newValue,
1011
- index
1012
- }) => values.map((value, i) => i === index ? newValue : value).sort((a, b) => a - b);
1013
- const asc = (a, b) => a - b;
1014
- const valueToArray = (value) => Array.isArray(value) ? value : [value];
972
+ const INCREMENT_KEYS = /* @__PURE__ */ new Set(["ArrowRight", "ArrowUp", "PageUp"]);
973
+ const DECREMENT_KEYS = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowDown", "PageDown"]);
1015
974
  const _unstableCreateSlider = createBuilder(
1016
975
  (options) => {
1017
976
  const sliderRef = createElRef();
1018
- const min = computed(() => unref(options.min) ?? 0);
1019
- const max = computed(() => unref(options.max) ?? 100);
1020
- const step = computed(() => unref(options.step) ?? 1);
1021
- const normalizedValues = computed(() => {
1022
- const rawValues = unref(options.value);
1023
- const arrayValues = Array.isArray(rawValues) ? rawValues.sort((a, b) => a - b) : [rawValues];
1024
- if (!arrayValues.length) return [min.value];
1025
- return arrayValues.map((value) => {
1026
- const clamped = MathUtils.clamp(value, min.value, max.value);
1027
- if (isDiscrete.value) {
1028
- return roundToStep(clamped, step.value, min.value);
1029
- }
1030
- return clamped;
1031
- });
977
+ const min = computed(() => toValue(options.min) ?? 0);
978
+ const max = computed(() => toValue(options.max) ?? 100);
979
+ const step = computed(() => toValue(options.step) ?? 1);
980
+ const draggingThumbIndex = ref();
981
+ watch(draggingThumbIndex, (newThumbIndex) => {
982
+ if (newThumbIndex == void 0) return;
983
+ Array.from(sliderRef.value.querySelectorAll('[role="slider"]')).at(newThumbIndex)?.focus();
1032
984
  });
1033
985
  const shiftStep = computed(() => {
1034
- const shiftStep2 = unref(options.shiftStep);
986
+ const shiftStep2 = toValue(options.shiftStep);
1035
987
  if (shiftStep2 != void 0) return shiftStep2;
1036
988
  const stepMultiple = Math.max(1, Math.round((max.value - min.value) * 0.1 / step.value));
1037
989
  return stepMultiple * step.value;
1038
990
  });
1039
- const isDisabled = computed(() => unref(options.disabled) ?? false);
1040
- const isDiscrete = computed(() => unref(options.discrete) ?? false);
1041
991
  const marks = computed(() => {
1042
- const rawMarks = unref(options.marks);
1043
- if (isDiscrete.value && !rawMarks) {
1044
- return true;
992
+ const _marks = toValue(options.marks);
993
+ if (!_marks) return [];
994
+ if (_marks === true) {
995
+ const markCount = Math.floor((max.value - min.value) / step.value) + 1;
996
+ return Array.from({ length: markCount }, (_, index) => {
997
+ return { value: min.value + step.value * index };
998
+ });
1045
999
  }
1046
- return rawMarks ?? false;
1000
+ return _marks.map((mark) => {
1001
+ if (typeof mark === "number") return { value: mark };
1002
+ return mark;
1003
+ }).sort((a, b) => a.value - b.value);
1047
1004
  });
1048
- const label = computed(() => unref(options.label));
1049
- let touchId = null;
1050
- let movesSinceStart = 0;
1051
- let lastChangedValue = null;
1052
- let previousActiveIndex = null;
1053
- const isDragging = ref(false);
1054
- const activeThumbIndex = ref(-1);
1055
- const isRange = computed(() => {
1056
- const unrefValues = unref(options.value);
1057
- return Array.isArray(unrefValues) && unrefValues.length > 1;
1058
- });
1059
- const marksList = computed(() => {
1060
- if (marks.value === false) return [];
1061
- if (marks.value && Array.isArray(marks.value)) {
1062
- return marks.value.map((mark) => typeof mark === "number" ? { value: mark } : mark).filter((mark) => mark.value >= min.value && mark.value <= max.value).sort((a, b) => asc(a.value, b.value));
1063
- }
1064
- if (step.value && step.value > 0) {
1065
- return [...Array(Math.floor((max.value - min.value) / step.value + 1))].map((_, index) => ({
1066
- value: min.value + step.value * index
1067
- }));
1068
- }
1069
- return [];
1005
+ const getNormalizedValue = computed(() => {
1006
+ return (value) => {
1007
+ let values = typeof value === "number" ? [value] : value;
1008
+ values = values.map((value2) => MathUtils.clamp(value2, min.value, max.value)).map((value2) => {
1009
+ const stepDecimals = MathUtils.decimalsCount(step.value);
1010
+ return Number(
1011
+ (Math.round((value2 - min.value) / step.value) * step.value + min.value).toFixed(
1012
+ stepDecimals
1013
+ )
1014
+ );
1015
+ }).sort((a, b) => a - b);
1016
+ return values;
1017
+ };
1070
1018
  });
1071
- const marksValues = computed(() => marksList.value.map((mark) => mark.value));
1072
- const emitChange = (next) => {
1073
- if (!areArraysEqual(normalizedValues.value, next)) {
1074
- const nextValue = isRange.value ? next : next[0];
1075
- if (typeof nextValue !== "undefined") {
1076
- options.onChange?.(nextValue);
1019
+ const normalizedValue = computed(
1020
+ () => getNormalizedValue.value(toValue(options.value))
1021
+ );
1022
+ const updateValue = (value, index) => {
1023
+ const currentValue = normalizedValue.value.slice();
1024
+ const otherIndex = index === 0 ? 1 : 0;
1025
+ const otherValue = currentValue[otherIndex];
1026
+ if (otherValue != void 0) {
1027
+ if (index < otherIndex && value > otherValue) {
1028
+ value = otherValue;
1029
+ } else if (index > otherIndex && value < otherValue) {
1030
+ value = otherValue;
1077
1031
  }
1078
1032
  }
1079
- lastChangedValue = next;
1080
- };
1081
- const emitCommit = (fallback) => {
1082
- const valueWithFallback = lastChangedValue ?? fallback;
1083
- const nextValue = isRange.value ? valueWithFallback : valueWithFallback[0];
1084
- if (typeof nextValue !== "undefined") {
1085
- options.onCommit?.(nextValue);
1086
- }
1033
+ currentValue[index] = value;
1034
+ const normalized = getNormalizedValue.value(currentValue);
1035
+ const newValue = normalized.length > 1 ? normalized : normalized[0];
1036
+ if (areArraysEqual(normalized, normalizedValue.value)) return;
1037
+ options.onChange?.(newValue);
1087
1038
  };
1088
- const ensureFocusOnThumb = (options2) => {
1089
- const { index, shouldSetActive = false } = options2;
1090
- const slider = sliderRef.value;
1091
- if (!slider) return;
1092
- if (slider.contains(document.activeElement) && Number(document.activeElement?.getAttribute("data-index")) !== index) {
1093
- slider.querySelector(`[type="range"][data-index="${index}"]`)?.focus();
1094
- }
1095
- if (shouldSetActive) {
1096
- activeThumbIndex.value = index;
1097
- }
1098
- };
1099
- const eventToCoords = (event, touchId2) => {
1100
- if (touchId2 !== void 0 && isTouchEvent(event)) {
1101
- for (let i = 0; i < event.changedTouches.length; i += 1) {
1102
- const touch = event.changedTouches[i];
1103
- if (touch && touch.identifier === touchId2) {
1104
- return {
1105
- x: touch.clientX,
1106
- y: touch.clientY
1107
- };
1108
- }
1109
- }
1110
- return false;
1111
- }
1112
- const mouseEvent = event;
1113
- return {
1114
- x: mouseEvent.clientX,
1115
- y: mouseEvent.clientY
1039
+ const getValueInPercentage = computed(() => {
1040
+ return (value) => {
1041
+ const percentage = MathUtils.valueToPercent(value, min.value, max.value);
1042
+ return MathUtils.clamp(percentage, 0, 100);
1116
1043
  };
1117
- };
1118
- const getNextFromCoords = (opts) => {
1119
- const { coords, isMoving = false } = opts;
1120
- const slider = sliderRef.value;
1121
- if (!slider) return null;
1122
- const rect = slider.getBoundingClientRect();
1123
- if (rect.width <= 0) return null;
1124
- const percent = MathUtils.clamp((coords.x - rect.left) / rect.width, 0, 1);
1125
- const raw = MathUtils.percentToValue(percent, min.value, max.value);
1126
- const snapped = !isDiscrete.value ? roundToStep(raw, step.value, min.value) : marksValues.value[findClosestIndex(marksValues.value, raw)];
1127
- if (typeof snapped !== "number") return null;
1128
- const candidate = MathUtils.clamp(snapped, min.value, max.value);
1129
- if (!isRange.value) {
1130
- return { newValue: candidate, activeIndex: 0 };
1131
- }
1132
- const closestIndex = findClosestIndex(normalizedValues.value, candidate);
1133
- const index = isMoving && previousActiveIndex != null ? previousActiveIndex : closestIndex;
1134
- const adjustedValues = adjustValueByIndex({
1135
- values: normalizedValues.value,
1136
- newValue: candidate,
1137
- index
1138
- });
1139
- const adjustedIndex = findClosestIndex(adjustedValues, candidate);
1140
- previousActiveIndex = adjustedIndex;
1141
- return { newValue: adjustedValues, activeIndex: adjustedIndex };
1142
- };
1143
- const commitValueFromEvent = (event, input) => {
1144
- const index = readThumbIndex(event);
1145
- const current = normalizedValues.value[index];
1146
- if (typeof current !== "number") {
1147
- return;
1148
- }
1149
- const useMarks = isDiscrete.value && marksList.value.length > 0;
1150
- const snapByMarks = (candidate) => {
1151
- const list = marksList.value;
1152
- const first = list[0];
1153
- const last = list.at(-1);
1154
- if (!first || !last) {
1155
- return current;
1156
- }
1157
- if (candidate <= first.value) {
1158
- return first.value;
1159
- }
1160
- if (candidate >= last.value) {
1161
- return last.value;
1162
- }
1163
- const pos = marksValues.value.indexOf(current);
1164
- const neighbor = candidate < current ? list[pos - 1] : list[pos + 1];
1165
- return neighbor?.value ?? current;
1166
- };
1167
- const scalar = MathUtils.clamp(useMarks ? snapByMarks(input) : input, min.value, max.value);
1168
- const nextValues = isRange.value ? adjustValueByIndex({ values: normalizedValues.value, newValue: scalar, index }) : [scalar];
1169
- if (isRange.value) {
1170
- const activeIndex = nextValues.indexOf(scalar);
1171
- ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
1172
- }
1173
- if (!areArraysEqual(normalizedValues.value, nextValues)) {
1174
- emitChange(nextValues);
1175
- }
1176
- emitCommit(nextValues);
1177
- };
1178
- const handlePointerEnd = (event) => {
1179
- const coords = eventToCoords(event, touchId);
1180
- isDragging.value = false;
1181
- if (!coords) {
1182
- return;
1183
- }
1184
- const next = getNextFromCoords({ coords, isMoving: true });
1185
- if (!next) {
1186
- return;
1187
- }
1188
- const { newValue } = next;
1189
- activeThumbIndex.value = -1;
1190
- emitCommit(valueToArray(newValue));
1191
- movesSinceStart = 0;
1192
- touchId = null;
1193
- stopPointerListening();
1194
- };
1195
- const handlePointerMove = (event) => {
1196
- const coords = eventToCoords(event, touchId);
1197
- if (!coords) return;
1198
- movesSinceStart += 1;
1199
- if (event.type === "mousemove" && event.buttons === 0) {
1200
- handlePointerEnd(event);
1201
- return;
1202
- }
1203
- const nextState = getNextFromCoords({ coords, isMoving: true });
1204
- if (!nextState) {
1205
- handlePointerEnd(event);
1206
- return;
1207
- }
1208
- const { newValue, activeIndex } = nextState;
1209
- if (!isDragging.value && movesSinceStart > DRAG_MOVE_THRESHOLD) {
1210
- isDragging.value = true;
1211
- }
1212
- ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
1213
- emitChange(valueToArray(newValue));
1214
- isDragging.value = true;
1215
- };
1216
- const handlePointerStart = (event) => {
1217
- if (isDisabled.value) {
1218
- return;
1044
+ });
1045
+ const handleKeydown = (event, thumbIndex) => {
1046
+ if (!NAVIGATION_KEYS.has(event.key)) return;
1047
+ event.preventDefault();
1048
+ const currentValue = normalizedValue.value.slice();
1049
+ if (currentValue[thumbIndex] == void 0) return;
1050
+ const stepSize = event.shiftKey ? shiftStep.value : step.value;
1051
+ if (event.key === "Home") {
1052
+ return updateValue(min.value, thumbIndex);
1219
1053
  }
1220
- const touch = event.changedTouches[0];
1221
- if (touch !== null && touch !== void 0) {
1222
- touchId = touch.identifier;
1054
+ if (event.key === "End") {
1055
+ return updateValue(max.value, thumbIndex);
1223
1056
  }
1224
- const coords = eventToCoords(event, touchId);
1225
- if (coords) {
1226
- const nextState = getNextFromCoords({ coords, isMoving: false });
1227
- if (nextState) {
1228
- const { newValue, activeIndex } = nextState;
1229
- ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
1230
- emitChange(valueToArray(newValue));
1231
- }
1057
+ if (INCREMENT_KEYS.has(event.key)) {
1058
+ updateValue(currentValue[thumbIndex] + stepSize, thumbIndex);
1059
+ } else if (DECREMENT_KEYS.has(event.key)) {
1060
+ updateValue(currentValue[thumbIndex] - stepSize, thumbIndex);
1232
1061
  }
1233
- movesSinceStart = 0;
1234
- document.addEventListener("touchmove", handlePointerMove, {
1235
- passive: true
1236
- });
1237
- document.addEventListener("touchend", handlePointerEnd);
1238
- };
1239
- const stopPointerListening = () => {
1240
- document.removeEventListener("mousemove", handlePointerMove);
1241
- document.removeEventListener("mouseup", handlePointerEnd);
1242
- document.removeEventListener("touchmove", handlePointerMove);
1243
- document.removeEventListener("touchend", handlePointerEnd);
1244
1062
  };
1245
- const handleRootMousedown = (event) => {
1246
- if (isDisabled.value) {
1247
- return;
1248
- }
1249
- if (event.button !== 0) {
1250
- return;
1251
- }
1252
- if (event.defaultPrevented) {
1253
- return;
1254
- }
1063
+ const handlePointerdown = (event) => {
1255
1064
  event.preventDefault();
1256
- const coords = eventToCoords(event, touchId);
1257
- if (coords) {
1258
- const nextState = getNextFromCoords({ coords });
1259
- if (nextState) {
1260
- const { newValue, activeIndex } = nextState;
1261
- ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
1262
- emitChange(valueToArray(newValue));
1263
- }
1264
- }
1265
- movesSinceStart = 0;
1266
- document.addEventListener("mousemove", handlePointerMove, {
1267
- passive: true
1268
- });
1269
- document.addEventListener("mouseup", handlePointerEnd);
1270
- };
1271
- const handleHiddenInputChange = (event) => {
1272
- if (isDisabled.value) {
1273
- return;
1274
- }
1275
- const value = event.target.valueAsNumber;
1276
- commitValueFromEvent(event, value);
1065
+ const value = getValueFromCoordinates(event.x);
1066
+ if (value == void 0) return;
1067
+ const thumb = normalizedValue.value.reduce(
1068
+ (previous, thumbValue, index) => {
1069
+ const distance = Math.abs(thumbValue - value);
1070
+ if (distance < previous.distance) return { index, distance };
1071
+ return previous;
1072
+ },
1073
+ { index: 0, distance: Number.POSITIVE_INFINITY }
1074
+ );
1075
+ updateValue(value, thumb.index);
1076
+ draggingThumbIndex.value = thumb.index;
1277
1077
  };
1278
- const handleHiddenInputFocus = (event) => {
1279
- const index = readThumbIndex(event);
1280
- if (isFocusVisible(event.target)) {
1281
- activeThumbIndex.value = index;
1282
- }
1283
- };
1284
- const handleHiddenInputBlur = (event) => {
1285
- if (!isFocusVisible(event.target)) {
1286
- activeThumbIndex.value = -1;
1287
- }
1078
+ const handlePointermove = (event) => {
1079
+ if (draggingThumbIndex.value == void 0) return;
1080
+ const value = getValueFromCoordinates(event.x);
1081
+ if (value == void 0) return;
1082
+ updateValue(value, draggingThumbIndex.value);
1288
1083
  };
1289
- const handleHiddenInputKeydown = (event) => {
1290
- if (!NAVIGATION_KEYS.has(event.key)) return;
1291
- event.preventDefault();
1292
- const index = readThumbIndex(event);
1293
- const value = normalizedValues.value[index];
1294
- if (typeof value !== "number") {
1295
- return;
1296
- }
1297
- if (!isDiscrete.value) {
1298
- const stepSize = event.shiftKey ? shiftStep.value : step.value;
1299
- if (event.key === "Home") return commitValueFromEvent(event, min.value);
1300
- if (event.key === "End") return commitValueFromEvent(event, max.value);
1301
- if (INCREMENT_KEYS.has(event.key)) {
1302
- const next = MathUtils.clamp(value + stepSize, min.value, max.value);
1303
- if (next !== value) commitValueFromEvent(event, next);
1304
- return;
1305
- }
1306
- if (DECREMENT_KEYS.has(event.key)) {
1307
- const next = MathUtils.clamp(value - stepSize, min.value, max.value);
1308
- if (next !== value) commitValueFromEvent(event, next);
1309
- return;
1310
- }
1311
- return;
1312
- } else {
1313
- const values = marksValues.value;
1314
- const lastIndex = values.length - 1;
1315
- const currentIndex = values.indexOf(value);
1316
- const first = values[0];
1317
- const last = values[lastIndex];
1318
- if (event.key === "Home" && typeof first === "number")
1319
- return commitValueFromEvent(event, first);
1320
- if (event.key === "End" && typeof last === "number")
1321
- return commitValueFromEvent(event, last);
1322
- if (INCREMENT_KEYS.has(event.key)) {
1323
- const nextIdx = currentIndex < 0 ? 0 : Math.min(lastIndex, currentIndex + 1);
1324
- const next = values[nextIdx];
1325
- if (next !== value && typeof next === "number") commitValueFromEvent(event, next);
1326
- return;
1327
- }
1328
- if (DECREMENT_KEYS.has(event.key)) {
1329
- const nextIdx = currentIndex < 0 ? 0 : Math.max(0, currentIndex - 1);
1330
- const next = values[nextIdx];
1331
- if (next !== value && typeof next === "number") commitValueFromEvent(event, next);
1332
- return;
1333
- }
1334
- }
1084
+ useGlobalEventListener({
1085
+ type: "pointermove",
1086
+ listener: handlePointermove,
1087
+ disabled: computed(() => draggingThumbIndex.value == void 0)
1088
+ });
1089
+ const handlePointerup = () => {
1090
+ draggingThumbIndex.value = void 0;
1335
1091
  };
1336
- const trackOffset = computed(
1337
- () => MathUtils.valueToPercent(
1338
- isRange.value && normalizedValues.value[0] ? normalizedValues.value[0] : min.value,
1339
- min.value,
1340
- max.value
1341
- )
1342
- );
1343
- const trackLength = computed(
1344
- () => MathUtils.valueToPercent(normalizedValues.value.at(-1) ?? 0, min.value, max.value) - trackOffset.value
1345
- );
1346
- const trackStyle = computed(() => ({
1347
- left: `${trackOffset.value}%`,
1348
- width: `${trackLength.value}%`
1349
- }));
1350
- onBeforeUnmount(stopPointerListening);
1351
- watch(
1352
- () => isDisabled.value,
1353
- () => {
1354
- if (isDisabled.value) {
1355
- isDragging.value = false;
1356
- activeThumbIndex.value = -1;
1357
- stopPointerListening();
1358
- }
1359
- }
1360
- );
1361
- const adjustMarkPosition = (percentage, offset) => {
1362
- if (offset && percentage <= 0) return offset;
1363
- if (offset && percentage >= 100) return `calc(100% - ${offset})`;
1364
- return `${percentage}%`;
1092
+ useGlobalEventListener({
1093
+ type: "pointerup",
1094
+ listener: handlePointerup,
1095
+ disabled: computed(() => draggingThumbIndex.value == void 0)
1096
+ });
1097
+ const getValueFromCoordinates = (x) => {
1098
+ const rect = sliderRef.value.getBoundingClientRect();
1099
+ if (rect.width <= 0) return;
1100
+ const percent = MathUtils.clamp((x - rect.left) / rect.width, 0, 1);
1101
+ return MathUtils.percentToValue(percent, min.value, max.value);
1365
1102
  };
1366
1103
  return {
1367
1104
  elements: {
1368
1105
  /**
1369
1106
  * Root slider container element
1370
1107
  */
1371
- root: computed(() => ({
1372
- ref: sliderRef,
1373
- style: { touchAction: "pan-y" },
1374
- onMousedown: handleRootMousedown,
1375
- onTouchstart: handlePointerStart
1376
- })),
1108
+ root: computed(() => {
1109
+ const events = {
1110
+ onPointerdown: handlePointerdown
1111
+ };
1112
+ return {
1113
+ ref: sliderRef,
1114
+ style: { touchAction: "pan-y" },
1115
+ ...toValue(options.disabled) ? void 0 : events
1116
+ };
1117
+ }),
1377
1118
  /**
1378
1119
  * Individual thumb elements for each value (span)
1379
1120
  */
1380
1121
  thumbContainer: computed(() => (data) => ({
1381
- "data-index": data.index,
1382
- style: {
1383
- left: `${MathUtils.valueToPercent(data.value, min.value, max.value)}%`
1384
- }
1122
+ style: { left: `${getValueInPercentage.value(data.value)}%` }
1385
1123
  })),
1386
1124
  /**
1387
- * Visually hidden input inside each thumb for accessibility
1125
+ * Input inside each thumb for accessibility
1388
1126
  */
1389
- thumbInput: computed(() => (data) => ({
1390
- min: min.value,
1391
- max: max.value,
1392
- value: data.value,
1393
- role: "slider",
1394
- type: "range",
1395
- "aria-label": label.value,
1396
- "aria-valuemin": min.value,
1397
- "aria-valuemax": max.value,
1398
- "aria-valuenow": data.value,
1399
- "aria-orientation": "horizontal",
1400
- "data-index": data.index,
1401
- tabIndex: isDisabled.value ? -1 : 0,
1402
- step: isDiscrete.value && marks.value ? "any" : step.value ?? void 0,
1403
- disabled: typeof isDisabled.value === "boolean" ? isDisabled.value : false,
1404
- onChange: handleHiddenInputChange,
1405
- onFocus: handleHiddenInputFocus,
1406
- onBlur: handleHiddenInputBlur,
1407
- onKeydown: handleHiddenInputKeydown
1408
- })),
1127
+ thumbInput: computed(() => (data) => {
1128
+ const events = {
1129
+ onKeydown: (event) => handleKeydown(event, data.index)
1130
+ };
1131
+ return {
1132
+ min: min.value,
1133
+ max: max.value,
1134
+ value: data.value,
1135
+ role: "slider",
1136
+ type: "range",
1137
+ "aria-label": toValue(options.label),
1138
+ "aria-valuemin": min.value,
1139
+ "aria-valuemax": max.value,
1140
+ "aria-valuenow": data.value,
1141
+ "aria-orientation": "horizontal",
1142
+ step: step.value,
1143
+ disabled: toValue(options.disabled),
1144
+ ...toValue(options.disabled) ? void 0 : events
1145
+ };
1146
+ }),
1409
1147
  /**
1410
- * Mark elements
1148
+ * Single Mark element inside the rail
1411
1149
  */
1412
1150
  mark: computed(() => (data) => {
1413
- const percentage = MathUtils.clamp(
1414
- MathUtils.valueToPercent(data.value, min.value, max.value),
1415
- 0,
1416
- 100
1417
- );
1418
- const position = adjustMarkPosition(percentage, data.positionOffset);
1151
+ const percentage = getValueInPercentage.value(data.value);
1152
+ let position = `${percentage}%`;
1153
+ if (data.positionOffset && percentage <= 0) {
1154
+ position = data.positionOffset;
1155
+ }
1156
+ if (data.positionOffset && percentage >= 100) {
1157
+ position = `calc(100% - ${data.positionOffset})`;
1158
+ }
1419
1159
  return {
1420
- "data-value": data.value,
1421
1160
  "aria-hidden": true,
1422
1161
  style: { left: position }
1423
1162
  };
@@ -1425,83 +1164,46 @@ const _unstableCreateSlider = createBuilder(
1425
1164
  /**
1426
1165
  * Label for each mark
1427
1166
  */
1428
- markLabel: computed(() => (data) => ({
1429
- "data-value": data.value,
1430
- style: {
1431
- left: `${MathUtils.valueToPercent(data.value, min.value, max.value)}%`
1432
- },
1433
- "aria-hidden": true
1434
- })),
1167
+ markLabel: computed(() => (data) => {
1168
+ const left = getValueInPercentage.value(data.value);
1169
+ let translate = "-50%";
1170
+ if (left === 0) {
1171
+ translate = "0%";
1172
+ } else if (left === 100) {
1173
+ translate = "-100%";
1174
+ }
1175
+ return {
1176
+ "aria-hidden": true,
1177
+ style: {
1178
+ left: `${left}%`,
1179
+ transform: translate ? `translateX(${translate})` : void 0
1180
+ }
1181
+ };
1182
+ }),
1435
1183
  /**
1436
1184
  * Track element representing the selected range
1437
1185
  */
1438
- track: computed(() => ({
1439
- role: "presentation",
1440
- "aria-hidden": true,
1441
- style: trackStyle.value
1442
- })),
1443
- /**
1444
- * Rail element representing the full slider range
1445
- */
1446
- rail: computed(() => ({
1447
- role: "presentation",
1448
- "aria-hidden": true
1449
- }))
1186
+ track: computed(() => {
1187
+ const isRange = normalizedValue.value.length > 1;
1188
+ const offsetValue = isRange ? normalizedValue.value[0] : min.value;
1189
+ const left = getValueInPercentage.value(offsetValue);
1190
+ const lengthValue = normalizedValue.value.at(-1);
1191
+ const width = getValueInPercentage.value(lengthValue) - left;
1192
+ return {
1193
+ style: {
1194
+ left: `${left}%`,
1195
+ width: `${width}%`
1196
+ }
1197
+ };
1198
+ })
1450
1199
  },
1451
1200
  state: {
1452
- /**
1453
- * True if the slider is currently being dragged.
1454
- */
1455
- isDragging,
1456
- /**
1457
- * Index of the currently active thumb.
1458
- * Thumb could be active even if not dragging (e.g. click on the rail to move the thumb there).
1459
- * `-1` if no thumb is active.
1460
- */
1461
- activeThumbIndex,
1462
- /**
1463
- * `true` if the slider is a range slider (with two or more thumbs).
1464
- */
1465
- isRange,
1466
- /**
1467
- * Offset of the track as a percentage (0-100).
1468
- */
1469
- trackOffset,
1470
- /**
1471
- * Length of the track as a percentage (0-100).
1472
- */
1473
- trackLength,
1474
- /**
1475
- * List of marks to display on the slider.
1476
- * - If marks option is `true`, marks are generated based on the step value.
1477
- * - If marks option is an array of numbers or objects, it is used as provided (filtered to be within range).
1478
- * - If marks option is `false`, no marks are shown.
1479
- */
1480
- marksList,
1481
- /**
1482
- * Step size when holding shift key or using Page Up/Page Down keys.
1483
- */
1201
+ normalizedValue,
1484
1202
  shiftStep,
1485
- /**
1486
- * Normalized slider values (clamped to min/max and rounded to nearest step/mark).
1487
- */
1488
- normalizedValues
1203
+ marks
1489
1204
  },
1490
1205
  internals: {
1491
- /**
1492
- * Clamps a value to the slider's range.
1493
- * @param value - value to clamp
1494
- * @returns clamped value
1495
- */
1496
- clampValue: computed(() => (value) => MathUtils.clamp(value, min.value, max.value)),
1497
- /**
1498
- * Rounds a value to the nearest valid step.
1499
- * @param value - value to round
1500
- * @returns rounded value
1501
- */
1502
- roundToStep: computed(
1503
- () => (value) => !isDiscrete.value ? roundToStep(value, step.value, min.value) : marksValues.value[findClosestIndex(marksValues.value, value)]
1504
- )
1206
+ updateValue
1505
1207
  }
1506
1208
  };
1507
1209
  }