Skip to content

Commit 60ca360

Browse files
committed
main 🧊 v0.3.37
1 parent eb508fa commit 60ca360

33 files changed

Lines changed: 2350 additions & 740 deletions

‎packages/core/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@siberiacancode/reactuse",
3-
"version": "0.3.35",
3+
"version": "0.3.37",
44
"description": "The ultimate collection of react hooks",
55
"author": {
66
"name": "SIBERIA CAN CODE 🧊",

‎packages/core/src/bundle/hooks/useMask/useMask.js‎

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ export const generatePattern = (mode, options) => {
358358
*
359359
* @param {UseMaskOptions} options The hook options
360360
* @param {boolean} [options.autoClear=false] Clear value on blur when mask is incomplete
361+
* @param {string} [options.initialValue=""] Initial raw value
361362
* @param {string | Array<string | RegExp>} options.mask Mask pattern string or array of literals and RegExp tokens
362363
* @param {(value: string) => Partial<Pick<UseMaskOptions, 'mask' | 'showMask' | 'slot' | 'tokens'>>} [options.modify] Called before masking and can return dynamic mask option overrides
363364
* @param {UseMaskShow} [options.showMask="focus"] Defines when placeholder slots are displayed
@@ -375,18 +376,32 @@ export const generatePattern = (mode, options) => {
375376
export const useMask = (options) => {
376377
const optionsRef = useRef(options);
377378
optionsRef.current = options;
379+
const initialRawValue = options.initialValue ?? '';
380+
const initialResolvedOptions = getResolvedOptions(options, initialRawValue);
381+
const initialMaskedValue = applyMaskToRaw(
382+
initialRawValue,
383+
initialResolvedOptions.slots,
384+
initialResolvedOptions.transform
385+
);
386+
const initialDisplayValue = buildDisplayValue(
387+
initialMaskedValue,
388+
initialResolvedOptions.slots,
389+
initialResolvedOptions.slot,
390+
shouldShowMask(initialResolvedOptions.showMask, false, initialMaskedValue)
391+
);
392+
const initialFilled = checkComplete(initialMaskedValue, initialResolvedOptions.slots);
378393
const inputRef = useRef(null);
379394
const valueRef = useRef({
380-
displayValue: '',
381-
filled: false,
382-
maskedValue: '',
383-
rawValue: '',
384-
value: ''
395+
displayValue: initialDisplayValue,
396+
filled: initialFilled,
397+
maskedValue: initialMaskedValue,
398+
rawValue: initialRawValue,
399+
value: initialDisplayValue
385400
});
386-
const processedRef = useRef('');
387-
const displayValueRef = useRef('');
388-
const rawValueRef = useRef('');
389-
const wasCompleteRef = useRef(false);
401+
const processedRef = useRef(initialMaskedValue);
402+
const displayValueRef = useRef(initialDisplayValue);
403+
const rawValueRef = useRef(initialRawValue);
404+
const wasCompleteRef = useRef(initialFilled);
390405
const isFocusedRef = useRef(false);
391406
const watchingRef = useRef(false);
392407
const undoStackRef = useRef([]);
@@ -506,11 +521,20 @@ export const useMask = (options) => {
506521
const nextMaskedValue = applyMaskToRaw(state.rawValue, slots, transform);
507522
updateValue(nextMaskedValue, state.selectionStart);
508523
};
509-
const set = (value) => {
524+
const setValue = (value) => {
510525
const { slots, transform } = getResolvedOptions(optionsRef.current, value);
511526
const nextMaskedValue = applyMaskToRaw(value, slots, transform);
512527
updateValue(nextMaskedValue);
513528
};
529+
const getValue = (type = 'raw') => {
530+
if (type === 'display') {
531+
return valueRef.current.displayValue;
532+
}
533+
if (type === 'masked') {
534+
return valueRef.current.maskedValue;
535+
}
536+
return valueRef.current.rawValue;
537+
};
514538
const clampCursorToProcessed = (element) => {
515539
const start = element.selectionStart ?? 0;
516540
const end = element.selectionEnd ?? 0;
@@ -534,14 +558,13 @@ export const useMask = (options) => {
534558
if (!node || node.value) {
535559
return;
536560
}
537-
const { showMask, slots, slot } = getResolvedOptions(optionsRef.current, '');
538-
if (!shouldShowMask(showMask, false, '')) {
539-
return;
540-
}
541-
const displayValue = buildDisplayValue('', slots, slot, true);
542-
node.value = displayValue;
543-
displayValueRef.current = displayValue;
544-
updateRefs({ displayValue });
561+
node.value = displayValueRef.current;
562+
updateRefs({
563+
displayValue: displayValueRef.current,
564+
filled: wasCompleteRef.current,
565+
maskedValue: processedRef.current,
566+
rawValue: rawValueRef.current
567+
});
545568
},
546569
onChange: (event) => {
547570
const element = event.currentTarget;
@@ -816,42 +839,41 @@ export const useMask = (options) => {
816839
const reset = () => {
817840
const input = inputRef.current;
818841
const hookOptions = optionsRef.current;
819-
processedRef.current = '';
820-
displayValueRef.current = '';
821-
rawValueRef.current = '';
842+
const nextRawValue = hookOptions.initialValue ?? '';
843+
const { showMask, slots, slot, transform } = getResolvedOptions(hookOptions, nextRawValue);
844+
const nextMaskedValue = applyMaskToRaw(nextRawValue, slots, transform);
845+
const nextDisplayValue = buildDisplayValue(
846+
nextMaskedValue,
847+
slots,
848+
slot,
849+
shouldShowMask(showMask, false, nextMaskedValue)
850+
);
851+
const complete = checkComplete(nextMaskedValue, slots);
852+
processedRef.current = nextMaskedValue;
853+
displayValueRef.current = nextDisplayValue;
854+
rawValueRef.current = nextRawValue;
822855
undoStackRef.current = [];
823856
redoStackRef.current = [];
824857
updateRefs({
825-
displayValue: '',
826-
filled: false,
827-
maskedValue: '',
828-
rawValue: ''
858+
displayValue: nextDisplayValue,
859+
filled: complete,
860+
maskedValue: nextMaskedValue,
861+
rawValue: nextRawValue
829862
});
830-
wasCompleteRef.current = false;
831-
let nextDisplayValue = '';
863+
wasCompleteRef.current = complete;
832864
if (input) {
833-
const { showMask, slots, slot } = getResolvedOptions(hookOptions, '');
834-
if (shouldShowMask(showMask, false, '')) {
835-
nextDisplayValue = buildDisplayValue('', slots, slot, true);
836-
displayValueRef.current = nextDisplayValue;
837-
updateRefs({ displayValue: nextDisplayValue });
838-
}
839865
input.value = nextDisplayValue;
840866
}
841-
hookOptions.onChangeRaw?.('', nextDisplayValue);
867+
hookOptions.onChangeRaw?.(nextRawValue, nextDisplayValue);
842868
};
843869
const watch = () => {
844870
watchingRef.current = true;
845871
return valueRef.current;
846872
};
847873
return {
874+
getValue,
848875
register,
849-
displayValue: valueRef.current.displayValue,
850-
value: valueRef.current.value,
851-
maskedValue: valueRef.current.maskedValue,
852-
rawValue: valueRef.current.rawValue,
853-
filled: valueRef.current.filled,
854-
set,
876+
setValue,
855877
reset,
856878
watch
857879
};

‎packages/core/src/bundle/hooks/useMediaControls/useMediaControls.js‎

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ export const useMediaControls = (...params) => {
6464
const [buffered, setBuffered] = useState([]);
6565
const [stalled, setStalled] = useState(false);
6666
const [ended, setEnded] = useState(false);
67-
const [playbackRate, setPlaybackRateState] = useState(1);
68-
const [muted, setMutedState] = useState(false);
69-
const [volume, setVolumeState] = useState(1);
67+
const [playbackRate, setPlaybackRate] = useState(1);
68+
const [muted, setMuted] = useState(false);
69+
const [volume, setVolume] = useState(1);
7070
useEffect(() => {
7171
const element = target ? isTarget.getElement(target) : internalRef.current;
7272
if (!element) return;
@@ -76,11 +76,10 @@ export const useMediaControls = (...params) => {
7676
if (options.media) element.setAttribute('media', options.media);
7777
setDuration(element.duration);
7878
setCurrentTime(element.currentTime);
79-
setPlaying(false);
8079
setEnded(element.ended);
81-
setMutedState(element.muted);
82-
setVolumeState(element.volume);
83-
setPlaybackRateState(element.playbackRate);
80+
setMuted(element.muted);
81+
setVolume(element.volume);
82+
setPlaybackRate(element.playbackRate);
8483
const onPlaying = () => {
8584
setPlaying(true);
8685
setStalled(false);
@@ -97,10 +96,10 @@ export const useMediaControls = (...params) => {
9796
const onDurationChange = () => setDuration(element.duration);
9897
const onTimeUpdate = () => setCurrentTime(element.currentTime);
9998
const onVolumechange = () => {
100-
setMutedState(element.muted);
101-
setVolumeState(element.volume);
99+
setMuted(element.muted);
100+
setVolume(element.volume);
102101
};
103-
const onRatechange = () => setPlaybackRateState(element.playbackRate);
102+
const onRatechange = () => setPlaybackRate(element.playbackRate);
104103
const onProgress = () => setBuffered(timeRangeToArray(element.buffered));
105104
element.addEventListener('playing', onPlaying);
106105
element.addEventListener('pause', onPause);
@@ -114,6 +113,7 @@ export const useMediaControls = (...params) => {
114113
element.addEventListener('timeupdate', onTimeUpdate);
115114
element.addEventListener('volumechange', onVolumechange);
116115
element.addEventListener('ratechange', onRatechange);
116+
if (playing) element.play();
117117
return () => {
118118
element.removeEventListener('playing', onPlaying);
119119
element.removeEventListener('pause', onPause);
@@ -128,7 +128,13 @@ export const useMediaControls = (...params) => {
128128
element.removeEventListener('volumechange', onVolumechange);
129129
element.removeEventListener('ratechange', onRatechange);
130130
};
131-
}, [target && isTarget.getRawElement(target), internalRef.state]);
131+
}, [
132+
target && isTarget.getRawElement(target),
133+
internalRef.state,
134+
options.src,
135+
options.type,
136+
options.media
137+
]);
132138
const play = async () => {
133139
const element = elementRef.current;
134140
if (!element) return;

‎packages/core/src/hooks/useFul/useFul.demo.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const Demo = () => {
1313
check{' '}
1414
<a
1515
className='text-primary underline'
16-
href='/new/hooks/useLess'
16+
href='/new/functions/hooks/useLess'
1717
rel='noreferrer'
1818
target='_blank'
1919
>

‎packages/core/src/hooks/useLastChanged/useLastChanged.demo.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ const formatTime = (timestamp: number) => {
66
const date = new Date(timestamp);
77
const hours = String(date.getHours()).padStart(2, '0');
88
const minutes = String(date.getMinutes()).padStart(2, '0');
9-
return `${hours}:${minutes}`;
9+
const seconds = String(date.getSeconds()).padStart(2, '0');
10+
11+
return `${hours}:${minutes}:${seconds}`;
1012
};
1113

1214
const Demo = () => {

‎packages/core/src/hooks/useLess/useLess.demo.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const Demo = () => {
1313
check{' '}
1414
<a
1515
className='text-primary underline'
16-
href='/new/hooks/useFul'
16+
href='/new/functions/hooks/useFul'
1717
rel='noreferrer'
1818
target='_blank'
1919
>

‎packages/core/src/hooks/useMask/useMask.demo.tsx‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ interface Country {
99
name: string;
1010
}
1111

12-
const COUNTRIES: Country[] = [
12+
const COUNTRIES = [
1313
{ code: '7', name: 'Russia', flag: '🇷🇺', mask: '+9 (999) 999-99-99' },
1414
{ code: '1', name: 'USA', flag: '🇺🇸', mask: '+9 (999) 999-9999' },
1515
{ code: '44', name: 'UK', flag: '🇬🇧', mask: '+99 9999 999999' },
1616
{ code: '77', name: 'Kazakhstan', flag: '🇰🇿', mask: '+99 (999) 999-99-99' },
1717
{ code: '380', name: 'Ukraine', flag: '🇺🇦', mask: '+999 (99) 999-99-99' },
1818
{ code: '998', name: 'Uzbekistan', flag: '🇺🇿', mask: '+999 (99) 999-99-99' }
19-
];
19+
] as const;
2020

2121
const DEFAULT_MASK = '999999999999999';
2222

@@ -29,23 +29,23 @@ const Demo = () => {
2929
const name = useField('');
3030
const cvv = useField('');
3131

32-
const phone = useMask({
32+
const phoneMask = useMask({
3333
mask: DEFAULT_MASK,
3434
showMask: 'never',
35-
slot: null,
3635
modify: (rawValue) => ({ mask: detectCountry(rawValue)?.mask ?? DEFAULT_MASK }),
37-
beforeMaskedStateChange: ({ nextState }) => ({
36+
beforeMaskedChange: ({ nextState }) => ({
3837
...nextState,
3938
selection: { start: nextState.value.length, end: nextState.value.length }
4039
})
4140
});
4241

42+
const phone = phoneMask.watch();
43+
4344
const cardNumber = useMask({
4445
mask: '9999 9999 9999 9999',
45-
showMask: 'never',
46-
slot: null
46+
showMask: 'never'
4747
});
48-
const expiry = useMask({ mask: '99/99', showMask: 'never', slot: null });
48+
const expiry = useMask({ mask: '99/99', showMask: 'never' });
4949

5050
const country = detectCountry(phone.rawValue);
5151

@@ -82,7 +82,7 @@ const Demo = () => {
8282
)}
8383
inputMode='tel'
8484
placeholder='Start typing with country code'
85-
{...phone.register()}
85+
{...phoneMask.register()}
8686
/>
8787
</div>
8888
{country && <span className='text-muted-foreground px-1 text-[10px]'>{country.name}</span>}

0 commit comments

Comments
 (0)