@basic-ui/core 0.0.43 → 0.0.46

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.
@@ -216,11 +216,13 @@ function wrapEvent(theirHandler, ourHandler) {
216
216
  function useControlledState(valueProp, onChangeProp, defaultValue, defaultOnChange) {
217
217
  const isControlled = valueProp !== undefined;
218
218
  const wasControlled = react.useRef(isControlled);
219
+ const hasWarned = react.useRef(false);
219
220
  const [valueState, setValueState] = react.useState(defaultValue);
220
221
 
221
222
  if (isControlled) {
222
- if (wasControlled.current && process.env.NODE_ENV !== 'production') {
223
+ if (wasControlled.current && process.env.NODE_ENV !== 'production' && !hasWarned.current) {
223
224
  console.warn('Trying to change from controlled to uncontrolled.');
225
+ hasWarned.current = true;
224
226
  }
225
227
 
226
228
  return [// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1153,30 +1155,53 @@ function useFocusManagement(lastActionType, inputRef) {
1153
1155
  });
1154
1156
  }
1155
1157
 
1156
- function getNextItem(currentItem, incr, optionsItems, autocomplete) {
1158
+ function getNextItem(currentItem, key, optionsItems, autocomplete) {
1159
+ const jumpToStartOrEnd = key === 'Home' || key === 'End';
1160
+ let incr = 1;
1161
+
1162
+ switch (key) {
1163
+ case 'PageUp':
1164
+ incr = -10;
1165
+ break;
1166
+
1167
+ case 'PageDown':
1168
+ incr = 10;
1169
+ break;
1170
+
1171
+ case 'End':
1172
+ case 'ArrowUp':
1173
+ incr = -1;
1174
+ break;
1175
+
1176
+ case 'Home':
1177
+ case 'ArrowDown':
1178
+ incr = 1;
1179
+ break;
1180
+ }
1181
+
1157
1182
  const index = currentItem === '' ? -1 : optionsItems.findIndex(n => String(n.id) === currentItem);
1158
1183
  const optionsLen = optionsItems.length; // Nothing selected, either go to start, or end
1159
1184
 
1160
- if (index < 0) {
1185
+ if (index < 0 || jumpToStartOrEnd) {
1161
1186
  if (incr > 0) {
1162
1187
  // Go to start
1163
- return optionsItems[0].id;
1188
+ return optionsItems[0];
1164
1189
  } else {
1165
1190
  // Go to end
1166
- return optionsItems[optionsLen - 1].id;
1191
+ return optionsItems[optionsLen - 1];
1167
1192
  }
1168
1193
  } else if (autocomplete) {
1169
1194
  const nextIndex = index + incr;
1170
1195
 
1171
1196
  if (nextIndex < 0 || nextIndex >= optionsLen) {
1172
1197
  // Next is outside the bounds of list, return nothing selected
1173
- return '';
1198
+ return null;
1174
1199
  }
1175
1200
  } // I'm sure it won't be null, we already check optionsLen above
1176
1201
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1177
1202
 
1178
1203
 
1179
- return optionsItems[getCircularIndex(index + incr, optionsLen)].id;
1204
+ return optionsItems[getCircularIndex(index + incr, optionsLen)];
1180
1205
  } // We want the same events when the input or the popup have focus (HOW COOL ARE
1181
1206
  // HOOKS BTW?) This is probably the hairiest piece but it's not bad.
1182
1207
 
@@ -1201,6 +1226,10 @@ function useKeyDown() {
1201
1226
  const optionNodes = listScope.current.queryAllNodes(scopeQuery$1);
1202
1227
 
1203
1228
  switch (event.key) {
1229
+ case 'Home':
1230
+ case 'End':
1231
+ case 'PageUp':
1232
+ case 'PageDown':
1204
1233
  case 'ArrowUp':
1205
1234
  case 'ArrowDown':
1206
1235
  {
@@ -1220,17 +1249,26 @@ function useKeyDown() {
1220
1249
  persistSelection: persistSelectionRef.current
1221
1250
  });
1222
1251
  } else {
1223
- // ArrowUp decreases index, ArrowDown increases
1224
- const incr = event.key === 'ArrowUp' ? -1 : 1; // When autocompletting, we'll not cycle through the list directly
1225
-
1252
+ // When autocompletting, we'll not cycle through the list directly
1226
1253
  const autocomplete = autocompletePropRef.current; // Get next selected item
1227
1254
 
1228
- const nextItem = getNextItem(navigationItem, incr, optionNodes, autocomplete);
1229
- const value = nextItem !== '' ? optionsRef.current[nextItem].text : null;
1230
- transition(NAVIGATE, {
1231
- value,
1232
- item: nextItem
1233
- });
1255
+ const nextItem = getNextItem(navigationItem, event.key, optionNodes, autocomplete);
1256
+
1257
+ if (nextItem !== null) {
1258
+ nextItem.scrollIntoView({
1259
+ behavior: 'auto',
1260
+ block: 'nearest'
1261
+ });
1262
+ transition(NAVIGATE, {
1263
+ value: optionsRef.current[nextItem.id].text,
1264
+ item: nextItem.id
1265
+ });
1266
+ } else {
1267
+ transition(NAVIGATE, {
1268
+ value: null,
1269
+ item: ''
1270
+ });
1271
+ }
1234
1272
  }
1235
1273
 
1236
1274
  break;
@@ -1999,7 +2037,6 @@ const MenuItem = /*#__PURE__*/react.forwardRef(function MenuItem(props, forwarde
1999
2037
  const handleKeyDown = e => {
2000
2038
  switch (e.key) {
2001
2039
  case 'Enter':
2002
- case ' ':
2003
2040
  if (!disabled) {
2004
2041
  handleSelect(e);
2005
2042
  }
@@ -2037,6 +2074,8 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2037
2074
  defaultActiveItemValue,
2038
2075
  ...otherProps
2039
2076
  } = props;
2077
+ const itemSearchStr = react.useRef('');
2078
+ const itemSearchClearTimeout = react.useRef();
2040
2079
  const {
2041
2080
  menuListIdRef,
2042
2081
  buttonRef,
@@ -2093,6 +2132,7 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2093
2132
  onChange && onChange(e, false);
2094
2133
  e.preventDefault(); // prevents focusing on next element, because we will be handling it
2095
2134
 
2135
+ itemSearchStr.current = '';
2096
2136
  buttonRef.current?.focus();
2097
2137
  break;
2098
2138
  }
@@ -2102,6 +2142,7 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2102
2142
  case 'ArrowDown':
2103
2143
  case 'ArrowUp':
2104
2144
  e.preventDefault();
2145
+ itemSearchStr.current = '';
2105
2146
  const allItems = scope ? scope.current.queryAllNodes(queryScope) : [];
2106
2147
  const currentIndex = allItems.findIndex(e => e === navigationItem);
2107
2148
 
@@ -2137,21 +2178,30 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2137
2178
 
2138
2179
  default:
2139
2180
  {
2140
- if (e.key.length === 1) {
2181
+ if (e.key.length === 1 && !e.ctrlKey && !e.altKey) {
2141
2182
  // A-Z
2142
2183
  e.preventDefault();
2184
+
2185
+ if (itemSearchStr.current.length === 0 || itemSearchStr.current.slice(-1) !== e.key) {
2186
+ itemSearchStr.current = itemSearchStr.current + e.key;
2187
+ }
2188
+
2189
+ clearTimeout(itemSearchClearTimeout.current);
2190
+ itemSearchClearTimeout.current = setTimeout(() => {
2191
+ itemSearchStr.current = '';
2192
+ }, 500);
2143
2193
  const allItems = scope ? scope.current.queryAllNodes(queryScope) : [];
2144
2194
  const currentIndex = allItems.findIndex(e => e === navigationItem);
2145
- const firstLetter = e.key.toLowerCase();
2195
+ const searchStr = itemSearchStr.current;
2146
2196
  let nextIndex = -1;
2147
2197
 
2148
- for (let i = 1; i < allItems.length; i++) {
2198
+ for (let i = searchStr.length === 1 ? 1 : 0; i < allItems.length; i++) {
2149
2199
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2150
2200
  const idx = getCircularIndex(currentIndex + i, allItems.length);
2151
2201
  const dom = allItems[idx];
2152
2202
  const domText = dom.innerText.toLowerCase();
2153
2203
 
2154
- if (domText.length > 0 && domText.charAt(0) === firstLetter) {
2204
+ if (domText.length > 0 && domText.startsWith(searchStr)) {
2155
2205
  nextIndex = idx;
2156
2206
  break;
2157
2207
  }
@@ -2478,27 +2528,7 @@ const RadioGroup = /*#__PURE__*/react.forwardRef(function RadioGroup(props, forw
2478
2528
  });
2479
2529
  });
2480
2530
 
2481
- /**
2482
- * Welcome to @reach/slider!
2483
- *
2484
- * A UI input component where the user selects a value from within a given
2485
- * range. A Slider has a handle that can be moved along a track to change its
2486
- * value. When the user's mouse or focus is on the Slider's handle, the value
2487
- * can be incremented with keyboard controls.
2488
- *
2489
- * Random thoughts/notes:
2490
- * - Currently testing this against the behavior of the native input range
2491
- * element to get our slider on par. We'll explore animated and multi-handle
2492
- * sliders next.
2493
- * - We may want to research some use cases for reversed sliders in RTL
2494
- * languages if that's a thing
2495
- *
2496
- * @see Docs https://reach.tech/slider
2497
- * @see Source https://github.com/reach/reach-ui/tree/main/packages/slider
2498
- * @see WAI-ARIA https://www.w3.org/TR/wai-aria-practices-1.2/#slider
2499
- * @see Example https://github.com/Stanko/aria-progress-range-slider
2500
- * @see Example http://www.oaa-accessibility.org/examplep/slider1/
2501
- */
2531
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
2502
2532
 
2503
2533
  const noop = () => {
2504
2534
  /* noop */
@@ -2544,6 +2574,7 @@ const SliderInput = /*#__PURE__*/react.forwardRef(function SliderInput({
2544
2574
  'aria-labelledby': ariaLabelledBy,
2545
2575
  'aria-valuetext': ariaValueTextProp,
2546
2576
  as: Comp = 'div',
2577
+ innerAs,
2547
2578
  defaultValue,
2548
2579
  disabled = false,
2549
2580
  value: controlledValue,
@@ -2866,6 +2897,8 @@ const SliderInput = /*#__PURE__*/react.forwardRef(function SliderInput({
2866
2897
  rangeStyle: rangeStyle,
2867
2898
  updateValue: onChange,
2868
2899
  children: /*#__PURE__*/jsxRuntime.jsxs(Comp, { ...rest,
2900
+ // @ts-ignore
2901
+ as: innerAs,
2869
2902
  ref: assignMultipleRefs(sliderRef, forwardedRef),
2870
2903
  "data-reach-slider-input": "",
2871
2904
  "data-disabled": disabled ? '' : undefined,
@@ -2906,6 +2939,7 @@ const SliderInput = /*#__PURE__*/react.forwardRef(function SliderInput({
2906
2939
  */
2907
2940
  const SliderTrackImpl = /*#__PURE__*/react.forwardRef(function SliderTrack({
2908
2941
  as: Comp = 'div',
2942
+ innerAs,
2909
2943
  children,
2910
2944
  style = {},
2911
2945
  ...props
@@ -2916,7 +2950,9 @@ const SliderTrackImpl = /*#__PURE__*/react.forwardRef(function SliderTrack({
2916
2950
  trackRef
2917
2951
  } = useSliderContext('SliderTrack');
2918
2952
  return /*#__PURE__*/jsxRuntime.jsx(Comp, {
2919
- ref: assignMultipleRefs(trackRef, forwardedRef),
2953
+ ref: assignMultipleRefs(trackRef, forwardedRef) // @ts-ignore
2954
+ ,
2955
+ as: innerAs,
2920
2956
  style: { ...style,
2921
2957
  position: 'relative'
2922
2958
  },
@@ -2944,6 +2980,7 @@ const SliderTrack = /*#__PURE__*/react.memo(SliderTrackImpl);
2944
2980
  */
2945
2981
  const SliderRangeImpl = /*#__PURE__*/react.forwardRef(function SliderRange({
2946
2982
  as: Comp = 'div',
2983
+ innerAs,
2947
2984
  children,
2948
2985
  style = {},
2949
2986
  ...props
@@ -2954,7 +2991,9 @@ const SliderRangeImpl = /*#__PURE__*/react.forwardRef(function SliderRange({
2954
2991
  rangeStyle
2955
2992
  } = useSliderContext('SliderRange');
2956
2993
  return /*#__PURE__*/jsxRuntime.jsx(Comp, {
2957
- ref: forwardedRef,
2994
+ ref: forwardedRef // @ts-ignore
2995
+ ,
2996
+ as: innerAs,
2958
2997
  style: {
2959
2998
  position: 'absolute',
2960
2999
  ...rangeStyle,
@@ -2988,6 +3027,7 @@ const SliderHandleImpl = /*#__PURE__*/react.forwardRef(function SliderHandle({
2988
3027
  // min,
2989
3028
  // max,
2990
3029
  as: Comp = 'div',
3030
+ innerAs,
2991
3031
  onBlur,
2992
3032
  onFocus,
2993
3033
  style = {},
@@ -3009,7 +3049,9 @@ const SliderHandleImpl = /*#__PURE__*/react.forwardRef(function SliderHandle({
3009
3049
  sliderMax,
3010
3050
  value
3011
3051
  } = useSliderContext('SliderHandle');
3012
- return /*#__PURE__*/jsxRuntime.jsx(Comp, {
3052
+ return /*#__PURE__*/jsxRuntime.jsx(Comp // @ts-ignore
3053
+ , {
3054
+ as: innerAs,
3013
3055
  "aria-disabled": disabled || undefined // If the slider has a visible label, it is referenced by
3014
3056
  // `aria-labelledby` on the slider element. Otherwise, the slider
3015
3057
  // element has a label provided by `aria-label`.
@@ -3086,6 +3128,7 @@ const SliderHandle = /*#__PURE__*/react.memo(SliderHandleImpl);
3086
3128
  */
3087
3129
  const SliderMarkerImpl = /*#__PURE__*/react.forwardRef(function SliderMarker({
3088
3130
  as: Comp = 'div',
3131
+ innerAs,
3089
3132
  children,
3090
3133
  style = {},
3091
3134
  value,
@@ -3099,11 +3142,13 @@ const SliderMarkerImpl = /*#__PURE__*/react.forwardRef(function SliderMarker({
3099
3142
  sliderMax,
3100
3143
  value: sliderValue
3101
3144
  } = useSliderContext('SliderMarker');
3102
- const inRange = !(value < sliderMin || value > sliderMax);
3145
+ const inRange = value >= sliderMin && value <= sliderMax;
3103
3146
  const absoluteStartPosition = `${valueToPercent(value, sliderMin, sliderMax)}%`;
3104
3147
  const state = value < sliderValue ? 'under-value' : value === sliderValue ? 'at-value' : 'over-value';
3105
3148
  return inRange ? /*#__PURE__*/jsxRuntime.jsx(Comp, {
3106
- ref: forwardedRef,
3149
+ ref: forwardedRef // @ts-ignore
3150
+ ,
3151
+ as: innerAs,
3107
3152
  style: {
3108
3153
  position: 'absolute',
3109
3154
  ...(isVertical ? {