From 0b1e8f9be7b02607cae064b18dcd3b5ad4e9365b Mon Sep 17 00:00:00 2001 From: Alex Yatsenko Date: Thu, 24 Oct 2024 13:17:12 +0300 Subject: [PATCH] feat: add core-config --- .github/workflows/core-config-publish.yml | 54 +++++++++++++++++++ external/core-config/LICENSE | 21 ++++++++ external/core-config/README.md | 0 external/core-config/package.json | 17 ++++++ .../core-config/src/CoreConfigContext.tsx | 26 +++++++++ external/core-config/src/index.ts | 1 + external/core-config/tsconfig.json | 14 +++++ packages/button/src/Component.responsive.tsx | 15 +++--- packages/button/src/typings.ts | 6 +++ packages/mq/src/index.ts | 1 + packages/mq/src/useIsDesktop.ts | 20 +++++++ 11 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/core-config-publish.yml create mode 100644 external/core-config/LICENSE create mode 100644 external/core-config/README.md create mode 100644 external/core-config/package.json create mode 100644 external/core-config/src/CoreConfigContext.tsx create mode 100644 external/core-config/src/index.ts create mode 100644 external/core-config/tsconfig.json create mode 100644 packages/mq/src/useIsDesktop.ts diff --git a/.github/workflows/core-config-publish.yml b/.github/workflows/core-config-publish.yml new file mode 100644 index 0000000000..e29278fec0 --- /dev/null +++ b/.github/workflows/core-config-publish.yml @@ -0,0 +1,54 @@ +name: Publish core-config + +on: + workflow_dispatch: + inputs: + version: + description: 'Введите версию x.x.x' + required: true + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Check permissions + if: ${{ contains(fromJSON('["reme3d2y","Valeri8888","SiebenSieben","fulcanellee"]'), github.actor) == false }} + uses: actions/github-script@v6 + with: + script: | + core.setFailed("you don't have permission to run this workflow!"); + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: yarn --pure-lockfile + + - name: Build app + run: | + cd ./external/core-config + yarn build + + - name: Set version + if: success() + run: | + cd ./external/core-config + git config user.name core-ds-bot + git config user.email ds@gitmax.tech + yarn --new-version version ${{ github.event.inputs.version }} + git push + + - name: Publish + if: success() + run: | + cd ./external/core-config + npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/external/core-config/LICENSE b/external/core-config/LICENSE new file mode 100644 index 0000000000..c0cf8553fa --- /dev/null +++ b/external/core-config/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 core-ds + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external/core-config/README.md b/external/core-config/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/external/core-config/package.json b/external/core-config/package.json new file mode 100644 index 0000000000..994c82fbf4 --- /dev/null +++ b/external/core-config/package.json @@ -0,0 +1,17 @@ +{ + "name": "@alfalab/core-config", + "version": "0.0.0", + "description": "Глобальный конфиг для настройки core-components", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "files": [ + "/dist" + ], + "scripts": { + "build": "tsc" + } +} diff --git a/external/core-config/src/CoreConfigContext.tsx b/external/core-config/src/CoreConfigContext.tsx new file mode 100644 index 0000000000..bc491b32a8 --- /dev/null +++ b/external/core-config/src/CoreConfigContext.tsx @@ -0,0 +1,26 @@ +import { createContext, useContext } from 'react'; + +export type CoreConfigContext = { + breakpoint: number; + ssrView: 'desktop' | 'mobile'; +}; + +export const CoreConfigContext = createContext({ + breakpoint: 1024, + ssrView: 'desktop', +}); + +export const useCoreConfig = (overrides: Partial = {}) => { + const config = useContext(CoreConfigContext); + + Object.entries(overrides).forEach(([key, value]) => { + if (value === undefined) { + delete overrides[key as keyof typeof overrides]; + } + }); + + return { + ...config, + ...overrides, + }; +}; diff --git a/external/core-config/src/index.ts b/external/core-config/src/index.ts new file mode 100644 index 0000000000..35d9f5fbce --- /dev/null +++ b/external/core-config/src/index.ts @@ -0,0 +1 @@ +export * from './CoreConfigContext'; diff --git a/external/core-config/tsconfig.json b/external/core-config/tsconfig.json new file mode 100644 index 0000000000..f740f89b0b --- /dev/null +++ b/external/core-config/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2016", + "jsx": "react", + "module": "commonjs", + "declaration": true, + "outDir": "./dist", + "declarationDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} diff --git a/packages/button/src/Component.responsive.tsx b/packages/button/src/Component.responsive.tsx index ea95b455ef..21dd37e2b0 100644 --- a/packages/button/src/Component.responsive.tsx +++ b/packages/button/src/Component.responsive.tsx @@ -1,7 +1,6 @@ import React, { forwardRef } from 'react'; -import { useMatchMedia } from '@alfalab/core-components-mq'; -import { getComponentBreakpoint } from '@alfalab/core-components-shared'; +import { useIsDesktop } from '@alfalab/core-components-mq'; import { ButtonDesktop } from './desktop'; import { ButtonMobile } from './mobile'; @@ -9,12 +8,16 @@ import { ButtonProps } from './typings'; export const Button = forwardRef( ( - { children, breakpoint = getComponentBreakpoint(), defaultMatchMediaValue, ...restProps }, + { + children, + breakpoint, + ssrView, + defaultMatchMediaValue = ssrView !== undefined ? ssrView === 'desktop' : undefined, + ...restProps + }, ref, ) => { - const query = `(min-width: ${breakpoint}px)`; - - const [isDesktop] = useMatchMedia(query, defaultMatchMediaValue); + const isDesktop = useIsDesktop(breakpoint, defaultMatchMediaValue); const Component = isDesktop ? ButtonDesktop : ButtonMobile; diff --git a/packages/button/src/typings.ts b/packages/button/src/typings.ts index 0eb97adbf2..583b5b348b 100644 --- a/packages/button/src/typings.ts +++ b/packages/button/src/typings.ts @@ -143,8 +143,14 @@ export type ButtonProps = CommonButtonProps & { */ breakpoint?: number; + /** + * Версия, которая будет использоваться при серверном рендеринге + */ + ssrView?: 'desktop' | 'mobile'; + /** * Значение по-умолчанию для хука useMatchMedia + * @deprecated Используйте ssrView */ defaultMatchMediaValue?: boolean | (() => boolean); }; diff --git a/packages/mq/src/index.ts b/packages/mq/src/index.ts index f4a886a4e1..5793ea956d 100644 --- a/packages/mq/src/index.ts +++ b/packages/mq/src/index.ts @@ -1,2 +1,3 @@ export * from './Component'; export * from './useMatchMedia'; +export * from './useIsDesktop'; diff --git a/packages/mq/src/useIsDesktop.ts b/packages/mq/src/useIsDesktop.ts new file mode 100644 index 0000000000..260a1de66e --- /dev/null +++ b/packages/mq/src/useIsDesktop.ts @@ -0,0 +1,20 @@ +import { useCoreConfig } from '@alfalab/core-config'; +import { useMatchMedia } from './useMatchMedia'; + +export function useIsDesktop(breakpoint?: number, defaultValue?: boolean | (() => boolean)) { + let ssrView; + + if (typeof defaultValue === 'boolean') { + ssrView = defaultValue ? 'desktop' : 'mobile'; + } else if (typeof defaultValue === 'function') { + ssrView = defaultValue() ? 'desktop' : 'mobile'; + } + + const config = useCoreConfig({ breakpoint, ssrView }); + + const query = `(min-width: ${config.breakpoint}px)`; + + const [isDesktop] = useMatchMedia(query, config.ssrView === 'desktop'); + + return isDesktop; +}