@officesdk/design 0.2.1 → 0.2.2

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.
@@ -301,6 +301,25 @@ interface CheckboxProps {
301
301
  */
302
302
  declare const Checkbox: React$1.FC<CheckboxProps>;
303
303
 
304
+ /**
305
+ * Value map utilities for piecewise linear mapping (non-linear slider)
306
+ */
307
+ interface ValueMapPiece {
308
+ /** Size of the piece (value range) */
309
+ size: number;
310
+ /** Step increment, defaults to 1 */
311
+ step?: number;
312
+ /** Visual size (relative), defaults to size/step */
313
+ visualSize?: number;
314
+ }
315
+ interface ValueMap {
316
+ type: 'piecewise';
317
+ /** Starting value */
318
+ start: number;
319
+ /** Array of pieces defining the mapping */
320
+ pieces: ValueMapPiece[];
321
+ }
322
+
304
323
  interface SliderProps {
305
324
  /**
306
325
  * Current value (0-100)
@@ -326,6 +345,15 @@ interface SliderProps {
326
345
  * Whether the slider is disabled
327
346
  */
328
347
  disabled?: boolean;
348
+ /**
349
+ * Slider direction
350
+ */
351
+ direction?: 'horizontal' | 'vertical';
352
+ /**
353
+ * Value map for piecewise linear mapping (non-linear slider)
354
+ * When provided, min/max/step props are ignored
355
+ */
356
+ valueMap?: ValueMap;
329
357
  /**
330
358
  * Callback when value changes
331
359
  */
@@ -907,38 +907,199 @@ var init_Button = __esm({
907
907
  exports.Button.displayName = "Button";
908
908
  }
909
909
  });
910
+
911
+ // src/Slider/valueMap.ts
912
+ var toFixed, createSinglePiecewiseMap, extendValueMap, snapToStep, valueToVisualPercentage, visualPercentToValue, changeByStep;
913
+ var init_valueMap = __esm({
914
+ "src/Slider/valueMap.ts"() {
915
+ toFixed = (num, precision = 10) => {
916
+ return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
917
+ };
918
+ createSinglePiecewiseMap = (min, max, step) => {
919
+ return {
920
+ type: "piecewise",
921
+ start: min,
922
+ pieces: [
923
+ {
924
+ size: max - min,
925
+ step,
926
+ visualSize: 100
927
+ }
928
+ ]
929
+ };
930
+ };
931
+ extendValueMap = (valueMap) => {
932
+ const piecesExt = [];
933
+ valueMap.pieces.forEach((p) => {
934
+ const start2 = piecesExt.length ? piecesExt[piecesExt.length - 1].end : valueMap.start;
935
+ const end2 = start2 + p.size;
936
+ const visualStart2 = piecesExt.length ? piecesExt[piecesExt.length - 1].visualEnd : 0;
937
+ const step = p.step || 1;
938
+ const visualSize2 = p.visualSize || p.size / step;
939
+ const visualEnd2 = visualStart2 + visualSize2;
940
+ const stepStart = piecesExt.length ? piecesExt[piecesExt.length - 1].stepEnd : 0;
941
+ const stepEnd = stepStart + Math.ceil(p.size / step);
942
+ piecesExt.push({
943
+ size: p.size,
944
+ step,
945
+ visualSize: visualSize2,
946
+ start: start2,
947
+ end: end2,
948
+ visualStart: visualStart2,
949
+ visualEnd: visualEnd2,
950
+ stepStart,
951
+ stepEnd
952
+ });
953
+ });
954
+ const firstPiece = piecesExt[0];
955
+ const lastPiece = piecesExt[piecesExt.length - 1];
956
+ const start = firstPiece.start;
957
+ const end = lastPiece.end;
958
+ const size = end - start;
959
+ const visualStart = firstPiece.visualStart;
960
+ const visualEnd = lastPiece.visualEnd;
961
+ const visualSize = visualEnd - visualStart;
962
+ return {
963
+ type: "piecewise",
964
+ size,
965
+ start,
966
+ end,
967
+ visualSize,
968
+ visualStart,
969
+ visualEnd,
970
+ pieces: piecesExt,
971
+ stepStart: firstPiece.stepStart,
972
+ stepEnd: lastPiece.stepEnd
973
+ };
974
+ };
975
+ snapToStep = (value, valueMap) => {
976
+ const { pieces, start, end } = valueMap;
977
+ if (value <= start) return start;
978
+ if (value >= end) return end;
979
+ const p = pieces.find((piece) => value >= piece.start && value <= piece.end);
980
+ if (!p) return value;
981
+ const pieceStep = p.step;
982
+ const steps = (value - p.start) / pieceStep;
983
+ const decimal = steps % 1;
984
+ let snapped;
985
+ if (decimal < 0.5) {
986
+ snapped = Math.max(start, toFixed(p.start + Math.floor(steps) * pieceStep));
987
+ } else {
988
+ snapped = Math.min(end, toFixed(p.start + Math.ceil(steps) * pieceStep));
989
+ }
990
+ return toFixed(snapped);
991
+ };
992
+ valueToVisualPercentage = (value, valueMap) => {
993
+ const { pieces, start, end, visualSize } = valueMap;
994
+ if (value <= start) return 0;
995
+ if (value >= end) return 1;
996
+ const p = pieces.find((piece) => value >= piece.start && value <= piece.end);
997
+ if (!p) return 0;
998
+ const visualPosition = p.visualStart + (value - p.start) / p.size * p.visualSize;
999
+ return visualPosition / visualSize;
1000
+ };
1001
+ visualPercentToValue = (visualPercent, valueMap) => {
1002
+ const { pieces, start, end, visualSize } = valueMap;
1003
+ if (visualPercent <= 0) return start;
1004
+ if (visualPercent >= 1) return end;
1005
+ const visualPosition = visualSize * visualPercent;
1006
+ const p = pieces.find(
1007
+ (piece) => visualPosition >= piece.visualStart && visualPosition <= piece.visualEnd
1008
+ );
1009
+ if (!p) return start;
1010
+ return p.start + (visualPosition - p.visualStart) / p.visualSize * p.size;
1011
+ };
1012
+ changeByStep = (value, steps, valueMap) => {
1013
+ const { pieces, start, end } = valueMap;
1014
+ const p = pieces.find((piece) => value >= piece.start && value <= piece.end);
1015
+ if (!p) {
1016
+ if (value < start) return start;
1017
+ if (value > end) return end;
1018
+ return value;
1019
+ }
1020
+ const curStepNo = (value - p.start) / p.step + p.stepStart;
1021
+ const curStepRounded = Math.round(curStepNo);
1022
+ let stepsInValueMap;
1023
+ if (Math.abs(curStepRounded - curStepNo) < 1e-5) {
1024
+ stepsInValueMap = Math.round(curStepNo) + steps;
1025
+ } else if (steps < 0) {
1026
+ stepsInValueMap = Math.ceil(curStepNo) + steps;
1027
+ } else {
1028
+ stepsInValueMap = Math.floor(curStepNo) + steps;
1029
+ }
1030
+ if (stepsInValueMap <= valueMap.stepStart) {
1031
+ return valueMap.start;
1032
+ }
1033
+ if (stepsInValueMap >= valueMap.stepEnd) {
1034
+ return valueMap.end;
1035
+ }
1036
+ const newPiece = pieces.find(
1037
+ (piece) => stepsInValueMap >= piece.stepStart && stepsInValueMap <= piece.stepEnd
1038
+ );
1039
+ if (!newPiece) return value;
1040
+ const newValue = newPiece.start + (stepsInValueMap - newPiece.stepStart) * newPiece.step;
1041
+ return toFixed(newValue);
1042
+ };
1043
+ }
1044
+ });
910
1045
  var SliderContainer, SliderTrack, SliderFill, SliderThumb; exports.Slider = void 0;
911
1046
  var init_Slider = __esm({
912
1047
  "src/Slider/Slider.tsx"() {
913
1048
  init_styled();
1049
+ init_valueMap();
914
1050
  SliderContainer = exports.styled.div`
915
1051
  position: relative;
916
1052
  display: flex;
917
1053
  align-items: center;
918
- width: 100%;
919
- height: 18px;
1054
+ justify-content: center;
1055
+ ${({ $direction }) => $direction === "vertical" ? `
1056
+ width: 18px;
1057
+ height: 100%;
1058
+ flex: 1;
1059
+ flex-direction: column;
1060
+ ` : `
1061
+ width: 100%;
1062
+ height: 18px;
1063
+ flex-direction: row;
1064
+ `}
920
1065
  cursor: ${({ $disabled }) => $disabled ? "not-allowed" : "pointer"};
921
1066
  user-select: none;
922
1067
  `;
923
1068
  SliderTrack = exports.styled.div`
924
1069
  position: absolute;
925
- left: 0;
926
- right: 0;
927
- height: ${({ theme: theme2 }) => theme2.components.slider.track.height};
928
1070
  background: ${({ theme: theme2 }) => theme2.colors.palettes.transparency["20"]};
929
1071
  border-radius: 1000px;
930
- top: 50%;
931
- transform: translateY(-50%);
1072
+ ${({ $direction, theme: theme2 }) => $direction === "vertical" ? `
1073
+ top: 0;
1074
+ bottom: 0;
1075
+ width: ${theme2.components.slider.track.height};
1076
+ left: 50%;
1077
+ transform: translateX(-50%);
1078
+ ` : `
1079
+ left: 0;
1080
+ right: 0;
1081
+ height: ${theme2.components.slider.track.height};
1082
+ top: 50%;
1083
+ transform: translateY(-50%);
1084
+ `}
932
1085
  `;
933
1086
  SliderFill = exports.styled.div`
934
1087
  position: absolute;
935
- left: 0;
936
- height: ${({ theme: theme2 }) => theme2.components.slider.track.height};
937
1088
  border-radius: ${({ theme: theme2 }) => theme2.components.slider.track.borderRadius};
938
- top: 50%;
939
- transform: translateY(-50%);
940
- width: ${({ $percentage }) => $percentage}%;
941
1089
  background: ${({ $disabled, theme: theme2 }) => $disabled ? theme2.components.slider.track.filledBackgroundDisabled : theme2.components.slider.track.filledBackground};
1090
+ ${({ $direction, $percentage, theme: theme2 }) => $direction === "vertical" ? `
1091
+ bottom: 0;
1092
+ width: ${theme2.components.slider.track.height};
1093
+ left: 50%;
1094
+ transform: translateX(-50%);
1095
+ height: ${$percentage}%;
1096
+ ` : `
1097
+ left: 0;
1098
+ height: ${theme2.components.slider.track.height};
1099
+ top: 50%;
1100
+ transform: translateY(-50%);
1101
+ width: ${$percentage}%;
1102
+ `}
942
1103
  `;
943
1104
  SliderThumb = exports.styled.div`
944
1105
  position: absolute;
@@ -946,12 +1107,19 @@ var init_Slider = __esm({
946
1107
  height: ${({ theme: theme2 }) => theme2.components.slider.large.thumbSize};
947
1108
  border-radius: 50%;
948
1109
  background: ${({ $disabled, theme: theme2 }) => $disabled ? theme2.components.slider.thumb.backgroundDisabled : theme2.components.slider.thumb.background};
949
- left: ${({ $percentage }) => $percentage}%;
950
- top: 50%;
951
- transform: translate(-50%, -50%);
952
1110
  cursor: ${({ $disabled }) => $disabled ? "not-allowed" : "grab"};
953
- transition: ${({ $isDragging }) => $isDragging ? "none" : "left 0.1s ease"};
954
1111
  box-shadow: ${({ theme: theme2 }) => theme2.components.slider.thumb.boxShadow};
1112
+ ${({ $direction, $percentage, $isDragging }) => $direction === "vertical" ? `
1113
+ bottom: ${$percentage}%;
1114
+ left: 50%;
1115
+ transform: translate(-50%, 50%);
1116
+ transition: ${$isDragging ? "none" : "bottom 0.1s ease"};
1117
+ ` : `
1118
+ left: ${$percentage}%;
1119
+ top: 50%;
1120
+ transform: translate(-50%, -50%);
1121
+ transition: ${$isDragging ? "none" : "left 0.1s ease"};
1122
+ `}
955
1123
 
956
1124
  ${({ $disabled, theme: theme2 }) => !$disabled && `
957
1125
  &:hover {
@@ -971,49 +1139,72 @@ var init_Slider = __esm({
971
1139
  max = 100,
972
1140
  step = 1,
973
1141
  disabled = false,
1142
+ direction = "horizontal",
1143
+ valueMap: valueMapProp,
974
1144
  onChange,
975
1145
  onDragStart,
976
1146
  onDragEnd,
977
1147
  className,
978
1148
  style
979
1149
  }) => {
1150
+ const extendedValueMap = React3.useMemo(() => {
1151
+ if (valueMapProp) {
1152
+ return extendValueMap(valueMapProp);
1153
+ }
1154
+ return extendValueMap(createSinglePiecewiseMap(min, max, step));
1155
+ }, [valueMapProp, min, max, step]);
1156
+ const effectiveMin = extendedValueMap.start;
1157
+ const effectiveMax = extendedValueMap.end;
980
1158
  const [internalValue, setInternalValue] = React3.useState(
981
1159
  controlledValue ?? defaultValue
982
1160
  );
983
1161
  const [isDragging, setIsDragging] = React3.useState(false);
984
1162
  const containerRef = React3.useRef(null);
985
1163
  const value = controlledValue !== void 0 ? controlledValue : internalValue;
986
- const percentage = (value - min) / (max - min) * 100;
1164
+ const percentage = valueToVisualPercentage(value, extendedValueMap) * 100;
987
1165
  const updateValue = React3.useCallback(
988
- (clientX) => {
1166
+ (clientX, clientY) => {
989
1167
  if (!containerRef.current || disabled) return;
990
1168
  const rect = containerRef.current.getBoundingClientRect();
991
- const offsetX = clientX - rect.left;
992
- const newPercentage = Math.max(0, Math.min(100, offsetX / rect.width * 100));
993
- const rawValue = newPercentage / 100 * (max - min) + min;
994
- const steppedValue = Math.round(rawValue / step) * step;
995
- const clampedValue = Math.max(min, Math.min(max, steppedValue));
1169
+ let visualPercent;
1170
+ if (direction === "vertical") {
1171
+ const offsetY = rect.bottom - clientY;
1172
+ visualPercent = Math.max(0, Math.min(1, offsetY / rect.height));
1173
+ } else {
1174
+ const offsetX = clientX - rect.left;
1175
+ visualPercent = Math.max(0, Math.min(1, offsetX / rect.width));
1176
+ }
1177
+ const rawValue = visualPercentToValue(visualPercent, extendedValueMap);
1178
+ const snappedValue = snapToStep(rawValue, extendedValueMap);
996
1179
  if (controlledValue === void 0) {
997
- setInternalValue(clampedValue);
1180
+ setInternalValue(snappedValue);
998
1181
  }
999
- onChange?.(clampedValue);
1182
+ onChange?.(snappedValue);
1183
+ },
1184
+ [disabled, controlledValue, onChange, direction, extendedValueMap]
1185
+ );
1186
+ const handleTrackClick = React3.useCallback(
1187
+ (e) => {
1188
+ if (disabled) return;
1189
+ e.preventDefault();
1190
+ updateValue(e.clientX, e.clientY);
1000
1191
  },
1001
- [min, max, step, disabled, controlledValue, onChange]
1192
+ [disabled, updateValue]
1002
1193
  );
1003
- const handleMouseDown = React3.useCallback(
1194
+ const handleThumbMouseDown = React3.useCallback(
1004
1195
  (e) => {
1005
1196
  if (disabled) return;
1006
1197
  e.preventDefault();
1198
+ e.stopPropagation();
1007
1199
  setIsDragging(true);
1008
1200
  onDragStart?.();
1009
- updateValue(e.clientX);
1010
1201
  },
1011
- [disabled, onDragStart, updateValue]
1202
+ [disabled, onDragStart]
1012
1203
  );
1013
1204
  React3.useEffect(() => {
1014
1205
  if (!isDragging) return;
1015
1206
  const handleMouseMove = (e) => {
1016
- updateValue(e.clientX);
1207
+ updateValue(e.clientX, e.clientY);
1017
1208
  };
1018
1209
  const handleMouseUp = () => {
1019
1210
  setIsDragging(false);
@@ -1034,20 +1225,20 @@ var init_Slider = __esm({
1034
1225
  case "ArrowLeft":
1035
1226
  case "ArrowDown":
1036
1227
  e.preventDefault();
1037
- newValue = Math.max(min, value - step);
1228
+ newValue = changeByStep(value, -1, extendedValueMap);
1038
1229
  break;
1039
1230
  case "ArrowRight":
1040
1231
  case "ArrowUp":
1041
1232
  e.preventDefault();
1042
- newValue = Math.min(max, value + step);
1233
+ newValue = changeByStep(value, 1, extendedValueMap);
1043
1234
  break;
1044
1235
  case "Home":
1045
1236
  e.preventDefault();
1046
- newValue = min;
1237
+ newValue = effectiveMin;
1047
1238
  break;
1048
1239
  case "End":
1049
1240
  e.preventDefault();
1050
- newValue = max;
1241
+ newValue = effectiveMax;
1051
1242
  break;
1052
1243
  default:
1053
1244
  return;
@@ -1057,32 +1248,36 @@ var init_Slider = __esm({
1057
1248
  }
1058
1249
  onChange?.(newValue);
1059
1250
  },
1060
- [disabled, value, min, max, step, controlledValue, onChange]
1251
+ [disabled, value, effectiveMin, effectiveMax, controlledValue, onChange, extendedValueMap]
1061
1252
  );
1062
1253
  return /* @__PURE__ */ React3__default.default.createElement(
1063
1254
  SliderContainer,
1064
1255
  {
1065
1256
  ref: containerRef,
1066
1257
  $disabled: disabled,
1258
+ $direction: direction,
1067
1259
  className,
1068
1260
  style,
1069
- onMouseDown: handleMouseDown,
1261
+ onMouseDown: handleTrackClick,
1070
1262
  onKeyDown: handleKeyDown,
1071
1263
  tabIndex: disabled ? -1 : 0,
1072
1264
  role: "slider",
1073
- "aria-valuemin": min,
1074
- "aria-valuemax": max,
1265
+ "aria-valuemin": effectiveMin,
1266
+ "aria-valuemax": effectiveMax,
1075
1267
  "aria-valuenow": value,
1076
- "aria-disabled": disabled
1268
+ "aria-disabled": disabled,
1269
+ "aria-orientation": direction
1077
1270
  },
1078
- /* @__PURE__ */ React3__default.default.createElement(SliderTrack, { $disabled: disabled }),
1079
- /* @__PURE__ */ React3__default.default.createElement(SliderFill, { $percentage: percentage, $disabled: disabled }),
1271
+ /* @__PURE__ */ React3__default.default.createElement(SliderTrack, { $disabled: disabled, $direction: direction }),
1272
+ /* @__PURE__ */ React3__default.default.createElement(SliderFill, { $percentage: percentage, $disabled: disabled, $direction: direction }),
1080
1273
  /* @__PURE__ */ React3__default.default.createElement(
1081
1274
  SliderThumb,
1082
1275
  {
1083
1276
  $percentage: percentage,
1084
1277
  $disabled: disabled,
1085
- $isDragging: isDragging
1278
+ $isDragging: isDragging,
1279
+ $direction: direction,
1280
+ onMouseDown: handleThumbMouseDown
1086
1281
  }
1087
1282
  )
1088
1283
  );
@@ -1095,6 +1290,7 @@ var init_Slider = __esm({
1095
1290
  var init_Slider2 = __esm({
1096
1291
  "src/Slider/index.ts"() {
1097
1292
  init_Slider();
1293
+ init_valueMap();
1098
1294
  }
1099
1295
  });
1100
1296
  var NumberInputContainer, InputWrapper, UnitText, StyledInput, ButtonGroup, StepButton, UpArrow, DownArrow; exports.NumberInput = void 0;