diff --git a/CHANGELOG.md b/CHANGELOG.md index ad979a9..beef897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,37 +1,3 @@ -# v4.0.0 -- [+] новые миксины: `mvk`, `odr`, `scaleWidthHeight`, `aspectRatio`, `fixSafariRadiusOverflow`, `customScrollbar`, `ifFlexGapNotSupported`, `flexGap` -- [+] новые функции: `px-to-rem`, `round`, `fluid`, `safe-top-value`, `safe-bottom-value` -- [*] в миксинах `backgroundImageCover`, `backgroundImageContain` параметр `image` стал необязательным -- [*] миксин `centerPos` теперь принимает в качестве параметра объект с настройками: выбор оси - `axis`, дополнительные значения transform - `properties` и возможность использовать transform3d вместо transform - `is-3d` -- [*] утилита markup переписана на классах, появилась возможность обращаться к `currentHtmlFontSize` -- [-] из зависимостей убрана библиотека @ktsstudio/mediaproject-utils - -# v3.0.0 -- [-] удалены миксины и утилиты, использующие переменные vkui - -### v2.0.3 -- [+] сборка на rollup -- [*] getNumberProperty ([issue](https://github.com/ktsstudio/mediaproject-style/issues/5)) - -### v2.0.2 -- [*] экранированы переменные в миксинах -- [*] добавлена инструкция для работы с SSR - -### v2.0.1 -- [*] markup defaultMobileSize изменен на размер iphone x -- [*] опечатка в миксине centerPosY (closing issue #4) - -# v2.0.0 -- [+] appearAnimation -- [+] утилиты для работы с отступами и хедером в ВК-миниаппе -- [*] исправлены миксины с использованием глобальных классов -- [*] fadeAnimation принимает длительность анимации и параметр наличия анимации пульсации - # v1.0.0 -- [+] checkIOS -- [+] checkMobile -- [+] markup - [+] mixins -- [+] fade animations -- [+] useAndroidKeyboard -- [+] useOrientationChange +- [+] animations diff --git a/README.md b/README.md index c0e3e68..5ffd185 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,32 @@ ![kts](./logo.png) -# @ktsstudio/mediaproject-style +# @ktsstudio/mediaproject-styled-components -Пакет с общими стилями для медиапроектов. +Пакет с общими миксинами и анимациями на styled-components для медиапроектов. ## Использование -`npm install @ktsstudio/mediaproject-style` +`npm install @ktsstudio/mediaproject-styled-components` -`yarn add @ktsstudio/mediaproject-style` +`yarn add @ktsstudio/mediaproject-styled-components` ## Содержимое -### Утилиты - -* [markup](./src/markup) — утилита для адаптивной верстки на rem - -Чтобы использовать адаптивную верстку на rem, необходимо при инициализации приложения вызвать функцию initMarkup и передать в нее нужные параметры: - -```typescript -import { initMarkup } from '@ktsstudio/mediaproject-style'; - -... - -initMarkup(); -``` - -Утилита создает объект типа Markup и экспортирует его в виде переменной markup. При необходимости к ней можно обратиться: - -```typescript -import { markup } from '@ktsstudio/mediaproject-style'; - -... - -console.log(markup.currentHtmlFontSize); -``` - ### Миксины и анимации -* [mixins.ts](./src/mixins.ts) — миксины для styled-components -* [animations.ts](./src/animations.ts) — анимации для styled-components -* [mixins.scss](./src/mixins.scss) — миксины для Sass -* [animations.scss](./src/animations.scss) — анимации для Sass +* [mixins.ts](./src/mixins.ts) — миксины +* [animations.ts](./src/animations.ts) — анимации Чтобы использовать миксин или анимацию в проекте с styled-components, импортируйте нужный объект из библиотеки: ```typescript -import { mixins } from '@ktsstudio/mediaproject-style'; +import { mixins } from '@ktsstudio/mediaproject-styled-components'; ... ${mixins.centerPos()}; ``` -Чтобы использовать миксин или анимацию в проекте с Sass, импортируйте файл с ними: - -```scss -@import '~@ktsstudio/mediaproject-style/dist/mixins'; - -... - -@include centerPos; -``` - -### Использование с SSR на примере Next.js - -Для корректной работы утилиты markup с Next.js необходимо вызывать функцию инициализации в useEffect. - -Пример: - -```typescript -import { initMarkup } from '@ktsstudio/mediaproject-style'; - -... - -React.useEffect(() => { - initMarkup(); -}, []); -``` - -Импорт миксинов и анимаций в SSR не меняется. - ## Обратная связь -Любой фидбэк вы можете передать нам на почту [hello@ktsstudio.ru](mailto:hello@ktsstudio.ru) в письме с темой "mediaproject-style" +Любой фидбэк вы можете передать нам на почту [hello@ktsstudio.ru](mailto:hello@ktsstudio.ru) в письме с темой "mediaproject-styled-components" diff --git a/package.json b/package.json index 92390e0..851c15f 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,17 @@ { - "name": "@ktsstudio/mediaproject-style", - "version": "4.0.0", - "description": "Package with common styles for media projects", + "name": "@ktsstudio/mediaproject-styled-components", + "version": "1.0.0", + "description": "Package with common mixins and animation for styled-components", "author": "KTS Studio (https://kts.studio)", "repository": { "type": "git", - "url": "https://github.com/ktsstudio/mediaproject-style.git" + "url": "https://github.com/ktsstudio/mediaproject-styled-components.git" }, "bugs": { "email": "hello@ktsstudio.ru", - "url": "https://github.com/ktsstudio/mediaproject-style/issues" + "url": "https://github.com/ktsstudio/mediaproject-styled-components/issues" }, - "homepage": "https://github.com/ktsstudio/mediaproject-style#readme", + "homepage": "https://github.com/ktsstudio/mediaproject-styled-components#readme", "license": "MIT", "main": "./dist/cjs/index.js", "browser": "./dist/es/index.js", diff --git a/src/animations.scss b/src/animations.scss deleted file mode 100644 index 2c312e9..0000000 --- a/src/animations.scss +++ /dev/null @@ -1,34 +0,0 @@ -@mixin fadeAnimation($duration: 5, $withScale: true) { - @keyframes fadeKeyframes { - 0%, - 100% { - opacity: 1; - @if $withScale { - transform: scale(1.2); - } - } - - 50% { - opacity: 0.6; - @if $withScale { - transform: scale(1); - } - } - } - - animation: fadeKeyframes #{$duration}s linear infinite; -} - -@keyframes appearKeyframes { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -@mixin appearAnimation($duration: 500) { - animation: appearKeyframes #{$duration}ms linear backwards; -} diff --git a/src/index.ts b/src/index.ts index 8eec406..1c6109c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ import { fadeAnimation, appearAnimation } from './animations'; -import { markup, initMarkup, Markup } from './markup'; import { mobile, desktop, @@ -28,7 +27,6 @@ import { adaptiveSidePadding, adaptiveContentWidth, } from './mixins'; -import { WindowSize, MarkupConfig } from './types/markup'; const mixins = { mobile, @@ -64,6 +62,4 @@ const animations = { appearAnimation, }; -export { markup, initMarkup, Markup, mixins, animations }; - -export { WindowSize, MarkupConfig }; +export { mixins, animations }; diff --git a/src/markup/Markup.ts b/src/markup/Markup.ts deleted file mode 100644 index 4892df1..0000000 --- a/src/markup/Markup.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { WindowSize, IMarkup, MarkupConfig } from '../types/markup'; -import { throttle } from '../utils/throttle'; - -const DEFAULT_HTML_FONT_SIZE = 10; - -const MIN_HTML_FONT_SIZE = 5; - -const DEFAULT_MOBILE_SIZE: WindowSize = { - width: 375, - height: 812, -}; - -const DEFAULT_DESKTOP_SIZE: WindowSize = { - width: 1280, - height: 820, -}; - -export default class Markup implements IMarkup { - /** Пересчитывать ли размер шрифта при ресайзе экрана или перевороте экрана моб. устройства */ - private readonly _isFitOnResize: boolean; - - /** Является ли девайс мобильным устройством */ - private readonly _isMobile: boolean; - - /** Размеры мобильного девайса, под который ориентированы макеты */ - private readonly _mobileWindowSize: WindowSize; - - /** Размеры десктопного девайса, под который ориентированы макеты */ - private readonly _desktopWindowSize: WindowSize; - - /** Размер шрифта html по умолчанию, то есть значение 1rem */ - private readonly _htmlFontSize: number; - - /** Минимальный размер шрифта html, чтобы содержимое страницы не было слишком мелким */ - private readonly _minFontSize: number; - - /** Максимальный размер шрифта html */ - private readonly _maxFontSize: number | null; - - /* Текущий размер шрифта тега html */ - // @ts-ignore - private _currentHtmlFontSize: number; - - constructor(config?: MarkupConfig) { - this._isFitOnResize = config?.isFitOnResize ?? false; - this._isMobile = config?.isMobile ?? true; - this._mobileWindowSize = config?.mobileWindowSize ?? DEFAULT_MOBILE_SIZE; - this._desktopWindowSize = config?.desktopWindowSize ?? DEFAULT_DESKTOP_SIZE; - this._htmlFontSize = config?.htmlFontSize ?? DEFAULT_HTML_FONT_SIZE; - this._minFontSize = config?.minFontSize ?? MIN_HTML_FONT_SIZE; - this._maxFontSize = config?.maxFontSize ?? null; - - this.fit(); - - if (this._isFitOnResize) { - window.addEventListener('resize', this.throttledFit); - } - } - - get throttledFit(): VoidFunction { - return throttle(this.fit.bind(this)); - } - - get currentHtmlFontSize(): number { - return this._currentHtmlFontSize; - } - - set currentHtmlFontSize(value: number) { - if (this._maxFontSize !== null && value > this._maxFontSize) { - this._currentHtmlFontSize = this._maxFontSize; - - return; - } - - if (value < this._minFontSize) { - this._currentHtmlFontSize = this._minFontSize; - - return; - } - - this._currentHtmlFontSize = value; - } - - fit(): void { - const currentWindowWidth = window.innerWidth; - const currentWindowHeight = window.innerHeight; - - const { width: windowWidth, height: windowHeight } = this._isMobile - ? this._mobileWindowSize - : this._desktopWindowSize; - - let scaleX = currentWindowWidth / windowWidth; - let scaleY = currentWindowHeight / windowHeight; - - if (scaleX * windowHeight > currentWindowHeight) { - scaleX = currentWindowHeight / windowHeight; - } - - if (scaleY * windowWidth > currentWindowWidth) { - scaleY = currentWindowWidth / windowWidth; - } - - let currentScale = Math.min(scaleX, scaleY); - - if (currentWindowHeight > currentWindowWidth * 2) { - currentScale += - 0.1 * - (currentWindowHeight / (currentWindowWidth * 2 + currentWindowHeight)); - } - - const result = currentScale * this._htmlFontSize; - - this.currentHtmlFontSize = this.round(result); - - document.documentElement.style.fontSize = `${this._currentHtmlFontSize}px`; - } - - round(value: number): number { - return Math.round(value * 2) / 2; - } - - remToPx(rem: number): number { - return this.round(rem * this._currentHtmlFontSize); - } - - pxToRem(px: number): number { - return px / this._currentHtmlFontSize; - } - - destroy(): void { - window.removeEventListener('resize', this.throttledFit); - } -} diff --git a/src/markup/index.ts b/src/markup/index.ts deleted file mode 100644 index 0941996..0000000 --- a/src/markup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './init'; diff --git a/src/markup/init.ts b/src/markup/init.ts deleted file mode 100644 index 990a093..0000000 --- a/src/markup/init.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MarkupConfig } from '../types/markup'; - -import Markup from './Markup'; - -let markup: Markup; - -/** - * @param {boolean} config.isFitOnResize Пересчитывать ли размер шрифта при ресайзе экрана или перевороте экрана моб. устройства - * @param {boolean} config.isMobile Является ли девайс мобильным устройством - * @param {WindowSize} config.mobileWindowSize Размеры мобильного девайса, под который ориентированы макеты - * @param {WindowSize} config.desktopWindowSize Размеры десктопного девайса, под который ориентированы макеты - * @param {number} config.htmlFontSize Размер шрифта html - * @param {number | null} config.minFontSize Минимальный размер шрифта html, чтобы содержимое страницы не было слишком мелким - * @param {number | null} config.maxFontSize Максимальный размер шрифта html - */ -const initMarkup = (config?: MarkupConfig): void => { - markup = new Markup(config); -}; - -export { markup, initMarkup, Markup }; diff --git a/src/mixins.scss b/src/mixins.scss deleted file mode 100644 index a46e8cf..0000000 --- a/src/mixins.scss +++ /dev/null @@ -1,430 +0,0 @@ -@use 'sass:math'; -@use 'sass:map'; - -@mixin mobile { - :global(.mobile) & { - @content; - } -} - -@mixin desktop { - :global(.desktop) & { - @content; - } -} - -@mixin ios { - :global(.ios) & { - @content; - } -} - -@mixin android { - :global(.android) & { - @content; - } -} - -@mixin mvk { - :global(.mvk) & { - @content; - } -} - -@mixin odr { - :global(.odr) & { - @content; - } -} - -@mixin minHeight($height) { - @media (min-height: $height) { - @content; - } -} - -@mixin maxHeight($height) { - @media (max-height: $height) { - @content; - } -} - -@mixin longScreen { - @media (max-aspect-ratio: 1/2) { - @content; - } -} - -@mixin portraitOrientation { - @media (orientation: portrait) { - @content; - } -} - -@mixin landscapeOrientation { - @media (orientation: landscape) { - @content; - } -} - -@mixin hover { - :global(.desktop) & { - &:hover { - cursor: pointer; - @content; - } - } - - :global(.mobile) & { - &:active { - @content; - } - } -} - -@mixin animate($properties, $transitionTime: 0.2) { - $resultElements: (); - @each $property in $properties { - $resultElements: append( - $resultElements, - $property #{$transitionTime}s ease - ); - } - - transition: join($resultElements, (), comma); -} - -@mixin square($side) { - width: $side; - height: $side; -} - -/// Центрирует элемент. -/// Идея была добавить возможность выбирать translate3d или translate. -/// Использовать translate3d стоит с осторожностью. Например, если элемент -/// содержит тяжелую графику, то это может плохо сказываться на производительности, -/// т.к. все translate3d передаются на обработку в gpu. -/// Также надо следить за отображением в сафари, т.к. бывают проблемы с z-index. -/// -/// @param $config - scss map с настройками -/// @param $config[is-3d] Использовать ли translate3d() вместо translate() -/// @param $config[axis] Ось, относительно которой центрировать. Необязательный параметр. По умолчанию центрируется по обеим осям -/// @param $config[properties] Дополнительные значения transform (rotate, scale и т.д.) Необязательный параметр. -/// -/// @example -/// @include centerPos; -/// -/// @example -/// @include centerPos(( -/// is-3d: true, -/// axis: y, -/// properties: scale(.5) rotate(45deg) -/// )); -@mixin centerPos( - $config: ( - is-3d: false, - ) -) { - $x: if(map.get($config, axis) == x or not map.get($config, axis), -50%, 0); - $y: if(map.get($config, axis) == y or not map.get($config, axis), -50%, 0); - $translate: if( - map.get($config, is-3d), - translate3d($x, $y, 0), - translate($x, $y) - ); - - @if $y == -50% { - top: 50%; - } - - @if $x == -50% { - left: 50%; - } - - transform: $translate map.get($config, properties); -} - -@mixin backgroundImageCover($image: false) { - background-repeat: no-repeat; - background-position: center; - background-size: cover; - - @if $image { - background-image: url(#{$image}); - } -} - -@mixin backgroundImageContain($image: false) { - background-repeat: no-repeat; - background-position: center; - background-size: contain; - - @if $image { - background-image: url(#{$image}); - } -} - -@mixin backgroundPosition($zIndex: -1) { - width: 100%; - height: 100%; - left: 0; - top: 0; - z-index: $zIndex; -} - -@mixin absoluteBackgroundPosition($zIndex: -1) { - position: absolute; - @include backgroundPosition($zIndex); -} - -@mixin fixedBackgroundPosition($zIndex: -1) { - position: fixed; - @include backgroundPosition($zIndex); -} - -@mixin autoCropText { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -@mixin hideScrollbar { - &::-webkit-scrollbar { - display: none; - } -} - -@mixin inputStyles { - -webkit-appearance: none; - line-height: initial; - user-select: auto; -} - -@mixin placeholderStyles { - &::-webkit-input-placeholder { - @content; - } - &::-moz-placeholder { - @content; - } - &:-moz-placeholder { - @content; - } - &:-ms-input-placeholder { - @content; - } -} - -@mixin sidePadding($padding) { - padding-left: $padding; - padding-right: $padding; -} - -@mixin contentWidth($sidePadding) { - width: calc(100vw - 2 * #{$sidePadding}); -} - -@mixin adaptiveSidePadding($mobilePadding, $desktopPadding) { - padding-left: $mobilePadding; - padding-right: $mobilePadding; - - @include desktop { - padding-left: $desktopPadding; - padding-right: $desktopPadding; - } -} - -@mixin adaptiveContentWidth($mobilePadding, $desktopPadding) { - width: calc(100vw - 2 * #{$mobilePadding}); - - @include desktop { - width: calc(100vw - 2 * #{$desktopPadding}); - } -} - -/// Умножает на один и тот же множитель переданные ширину и высоту -@mixin scaleWidthHeight($width, $height, $factor: 1) { - width: calc($width * $factor); - height: calc($height * $factor); -} - -/// Устанавливает соотношение сторон элемента, равное $width / $height. -/// Не сработает, когда у элемента заданы и ширина, и высота, -/// или в случае, если не задан ни один из размеров. -/// Если свойство aspect-ratio не поддерживается, то используется прием с padding-top. -@mixin aspectRatio($width, $height) { - $aspectRatio: math.div($width, $height); - - aspect-ratio: $aspectRatio; - - @supports not (aspect-ratio: $aspectRatio) { - &::after { - content: ''; - display: block; - width: 100%; - padding-bottom: calc(100% * ($height / $width)); - } - } -} - -/// Фиксит в safari мерцание острых углов при overflow:hidden и border-radius -/// Здесь data:image/png - это квадратное изображение 1x1 с черным фоном -@mixin fixSafariRadiusOverflow { - -webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); -} - -/// Кастомизирует нативный скролбар -/// -/// @param $config - scss map с настройками -/// @param $config[thumb-color] Цвет ползунка -/// @param $config[bg-color] Цвет фона области прокрутки -/// @param $config[size] Размер скролбара. Для горизонтального это высота, для вертикального - ширина -/// @param $config[radius] Скругление ползунка и фона. Необязательный параметр, по умолчанию без скругления -/// @param $config[orientation] Значение overflow: all | y | x. Необязательный параметр, по умолчанию all -/// -/// @example -/// @include customScrollbar(( -/// thumb-color: green, -/// bg-color: lime, -/// size: 10px, -/// )); -@mixin customScrollbar($config) { - $thumbColor: map.get($config, thumb-color); - $bgColor: map.get($config, bg-color); - $size: map.get($config, size); - $radius: if(map.get($config, radius), map.get($config, radius), 0); - $orientation: if( - map.get($config, orientation), - map.get($config, orientation), - all - ); - - @if $orientation == all { - overflow: auto; - - &::-webkit-scrollbar { - width: $size; - height: $size; - position: absolute; - right: 0; - top: 0; - } - } - - @if $orientation == y { - overflow-x: hidden; - overflow-y: auto; - - &::-webkit-scrollbar { - width: $size; - height: 0; - } - } - - @if $orientation == x { - overflow-x: auto; - overflow-y: hidden; - - &::-webkit-scrollbar { - width: 0; - height: $size; - } - } - - &::-webkit-scrollbar-track { - background-color: $bgColor; - border-radius: $radius; - } - - &::-webkit-scrollbar-thumb { - border-radius: $radius; - box-shadow: 0 0 20px 20px $thumbColor inset; - } - - // стилизация элементов прокрутки для Firefox - scrollbar-color: $thumbColor $bgColor; - scrollbar-width: $size; - - // стилизация элементов прокрутки для IE и Edge - -ms-overflow-style: none; - scrollbar-base-color: $bgColor; - scrollbar-face-color: $thumbColor; - scrollbar-arrow-color: $bgColor; -} - -/// Проверка поддержки __flexbox gaps__ по наиболее близкому по поддержке свойству -/// @link https://github.com/w3c/csswg-drafts/issues/3559#issuecomment-1758459996 -/// -/// @example -/// .flex-row { -/// display: flex; -/// flex-flow: row; -/// gap: 15px; -/// -/// @include ifFlexGapNotSupported { -/// & > *:not(:last-child) { -/// margin-right: 15px; -/// } -/// } -/// } -@mixin ifFlexGapNotSupported { - @supports not (inset: 0) { - @content; - } -} - -/// Установка __flexbox gaps__ с простым вариантом fallback -/// -/// (!) В случае fallback'а на контейнере будут установлены отрицательные margin -@mixin flexGap($row: 0, $col: 0) { - gap: $row $col; - - @include ifFlexGapNotSupported { - margin: calc(-1 * $row / 2) calc(-1 * $col / 2); - - & > * { - margin: calc($row / 2) calc($col / 2); - } - } -} - -@function px-to-rem($px, $baseRemInPx: 16px) { - $rems: math.div($px, $baseRemInPx) * 1rem; - - @return $rems; -} - -@function round($number, $decimals: 0) { - $pow: math.pow(10, $decimals); - - @return math.div(math.round($number * $pow), $pow); -} - -/// Задание адаптивного размера -/// @link https://www.smashingmagazine.com/2022/10/fluid-typography-clamp-sass-functions/ -@function fluid( - $minSize, - $maxSize, - $minBreakpoint: 320px, - $maxBreakpoint: 1440px, - $unit: vw -) { - $slope: math.div($maxSize - $minSize, $maxBreakpoint - $minBreakpoint); - $slopeToUnit: round($slope * 100, 3); - $interceptRem: round(px-to-rem($minSize - $slope * $minBreakpoint), 3); - $minSizeRem: round(px-to-rem($minSize), 3); - $maxSizeRem: round(px-to-rem($maxSize), 3); - - @return min( - max(#{$minSizeRem}, #{$slopeToUnit}#{$unit} + #{$interceptRem}), - #{$maxSizeRem} - ); -} - -@function safe-top-value($value: 0) { - @return calc($value + env(safe-area-inset-top)); -} - -@function safe-bottom-value($value: 0) { - @return calc($value + env(safe-area-inset-bottom)); -} diff --git a/src/types/markup.ts b/src/types/markup.ts deleted file mode 100644 index 5d61a17..0000000 --- a/src/types/markup.ts +++ /dev/null @@ -1,30 +0,0 @@ -export interface WindowSize { - width: number; - height: number; -} - -export interface IMarkup { - currentHtmlFontSize: number | null; - fit: VoidFunction; - round: (value: number) => number; - remToPx: (rem: number) => number | null; - pxToRem: (px: number) => number; - destroy: VoidFunction; -} - -export type MarkupConfig = { - /** Пересчитывать ли размер шрифта при ресайзе экрана или перевороте экрана моб. устройства */ - isFitOnResize?: boolean; - /** Является ли девайс мобильным устройством */ - isMobile?: boolean; - /** Размеры мобильного девайса, под который ориентированы макеты */ - mobileWindowSize?: WindowSize; - /** Размеры десктопного девайса, под который ориентированы макеты */ - desktopWindowSize?: WindowSize; - /** Размер шрифта html, то есть значение 1rem */ - htmlFontSize?: number; - /** Минимальный размер шрифта html, чтобы содержимое страницы не было слишком мелким */ - minFontSize?: number | null; - /** Максимальный размер шрифта html */ - maxFontSize?: number | null; -}; diff --git a/src/utils/throttle.ts b/src/utils/throttle.ts deleted file mode 100644 index 08a2201..0000000 --- a/src/utils/throttle.ts +++ /dev/null @@ -1,31 +0,0 @@ -export const throttle = any>( - func: F, - ms = 250 -) => { - let isThrottled = false; - let savedArgs: any[] | null; - let savedThis: any; - - function wrapper(this: any, ...args: any[]) { - if (isThrottled) { - savedArgs = args; - savedThis = this; - return; - } - - func.apply(this, args); // (1) - - isThrottled = true; - - setTimeout(() => { - isThrottled = false; // (3) - - if (savedArgs) { - wrapper.apply(savedThis, savedArgs); - savedArgs = savedThis = null; - } - }, ms); - } - - return wrapper; -};