diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index 89ed147ed7e..59ecaa591ae 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -4,28 +4,31 @@ description: Installs npm packages and manages it's cache runs: using: composite steps: - - name: Install Yarn - run: npm install -g yarn - shell: bash + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: latest - name: Cache setup for node modules uses: actions/cache@v3 id: cache with: path: | - ~/.yarn + ~/.pnpm-store ./node_modules ./packages/**/node_modules - key: ${{ runner.os }}-blade-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-blade-${{ hashFiles('**/pnpm-lock.yaml') }} - # cache miss - install packages with `yarn --frozen-lockfile` - # cache hit - download packages from the cache and explicitly run postinstall script + # cache miss - install packages with pnpm install --frozen-lockfile + # cache hit - download packages from the cache - name: install packages if cache miss - run: yarn --frozen-lockfile + run: | + pnpm install --frozen-lockfile shell: bash if: steps.cache.outputs.cache-hit != 'true' - - name: Run postinstall script - run: yarn postinstall + - name: Run postinstall script and ensure dependencies + run: | + pnpm run postinstall shell: bash if: steps.cache.outputs.cache-hit == 'true' diff --git a/.github/workflows/blade-bundle-size.yml b/.github/workflows/blade-bundle-size.yml index 4d3be6bb534..0f6c3441ba4 100644 --- a/.github/workflows/blade-bundle-size.yml +++ b/.github/workflows/blade-bundle-size.yml @@ -25,10 +25,10 @@ jobs: - name: Setup Cache & Install Dependencies uses: ./.github/actions/install-dependencies - name: Update Bundle Size Data - run: yarn generate-bundle-size-info + run: pnpm generate-bundle-size-info working-directory: packages/blade - name: Danger - run: yarn danger ci + run: pnpm danger ci working-directory: packages/blade env: DANGER_GITHUB_API_TOKEN: ${{ env.GITHUB_ACCESS_TOKEN }} @@ -51,10 +51,10 @@ jobs: - name: Setup Cache & Install Dependencies uses: ./.github/actions/install-dependencies - name: Build Blade React Production - run: yarn run-s build:clean build:generate-types build:react-prod + run: pnpm run-s build:clean build:generate-types build:react-prod working-directory: packages/blade - name: Update Bundle Size Data - run: yarn generate-bundle-size-info + run: pnpm generate-bundle-size-info working-directory: packages/blade env: BUNDLE_SIZE_STATS_FILENAME: 'baseBundleSizeStats.json' diff --git a/.github/workflows/blade-chromatic.yml b/.github/workflows/blade-chromatic.yml index 46a9faf392d..07580ff3384 100644 --- a/.github/workflows/blade-chromatic.yml +++ b/.github/workflows/blade-chromatic.yml @@ -30,7 +30,7 @@ jobs: buildScriptName: react:storybook:build exitOnceUploaded: true onlyChanged: true - untraced: '**/package.json' + untraced: '**/package.json **/pnpm-lock.yaml' traceChanged: 'expanded' env: GITHUB_SHA: ${{ github.sha }} diff --git a/.github/workflows/blade-icon-to-code.yml b/.github/workflows/blade-icon-to-code.yml index 10684adc37b..67e78be42e1 100644 --- a/.github/workflows/blade-icon-to-code.yml +++ b/.github/workflows/blade-icon-to-code.yml @@ -20,45 +20,39 @@ jobs: with: fetch-depth: 0 - # 2. decide what text we’ll put in the file + # 2. decide what text we'll put in the file - name: Set up Node.js uses: actions/setup-node@v2 with: node-version: '20' - - name: Install Yarn - run: npm install --global yarn + - name: Setup Cache & Install Dependencies + uses: ./.github/actions/install-dependencies - - name: Install dependencies - run: | - cd packages/blade - yarn install --frozen-lockfile - - name: Update icons.json env: FIGMA_API_TOKEN: ${{ secrets.FIGMA_API_TOKEN }} run: | cd packages/blade - yarn run fetch-icons + pnpm run fetch-icons - - - name : Update icons Script + - name: Update icons Script run: | cd packages/blade - yarn run generate-icons - # 4. create the pull request - - name : Update React Tests + pnpm run generate-icons + + - name: Update React Tests run: | cd packages/blade - yarn run test:react Icons --updateSnapshot + pnpm run test:react Icons --updateSnapshot - - name : Update React-Native Tests + - name: Update React-Native Tests run: | cd packages/blade - yarn run test:react-native Icons --updateSnapshot + pnpm run test:react-native Icons --updateSnapshot - name: Lint Source Code - run: yarn lint:fix + run: pnpm lint:fix continue-on-error: true - name: Create Pull Request @@ -74,4 +68,3 @@ jobs: This PR was automatically generated by the **Create Random File PR** workflow. It adds `${{ github.event.inputs.filename }}` containing random or provided text. delete-branch: true - # cleans up after merge diff --git a/.github/workflows/blade-interaction-tests.yml b/.github/workflows/blade-interaction-tests.yml index 6edbdeecf35..b74e67fca2c 100644 --- a/.github/workflows/blade-interaction-tests.yml +++ b/.github/workflows/blade-interaction-tests.yml @@ -39,5 +39,5 @@ jobs: - name: Run Interaction Tests run: | npx playwright install chromium firefox --with-deps - yarn test:react:interaction:ci + pnpm test:react:interaction:ci working-directory: packages/blade diff --git a/.github/workflows/blade-validate.yml b/.github/workflows/blade-validate.yml index 8c42fd4450c..08e8597d28c 100644 --- a/.github/workflows/blade-validate.yml +++ b/.github/workflows/blade-validate.yml @@ -22,17 +22,19 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18.12.1 - - name: Pre-Generate Documentation Lock File - run: yarn generate-docs-lockfile - name: Setup Cache & Install Dependencies uses: ./.github/actions/install-dependencies + - name: Pre-Generate Documentation Lock File + run: pnpm generate-docs-lockfile + # check version of npm run all which is installed + - name: Check version of npm-run-all using pnpm + run: pnpm list npm-run-all - name: Build Blade - run: yarn build - working-directory: packages/blade + run: pnpm --filter @razorpay/blade build - name: Lint Source Code - run: yarn lint + run: pnpm lint - name: Run TypeScript Checks - run: yarn typecheck + run: pnpm typecheck working-directory: packages/blade test: @@ -53,7 +55,7 @@ jobs: - name: Setup Cache & Install Dependencies uses: ./.github/actions/install-dependencies - name: Run Unit Tests - run: yarn test + run: pnpm test working-directory: packages/blade env: SHARD: ${{ matrix.shard }}/${{ matrix.totalShards }} @@ -110,10 +112,10 @@ jobs: ls -la .nyc_output/ # Generate merged report and capture text-summary - yarn --silent nyc report --reporter=json --reporter=text-summary > coverage-summary.txt + pnpm --silent nyc report --reporter=json --reporter=text-summary > coverage-summary.txt # Generate full coverage report - yarn --silent nyc report --reporter=json --reporter=text > coverage-full.txt + pnpm --silent nyc report --reporter=json --reporter=text > coverage-full.txt # Ensure output directory exists mkdir -p packages/blade/coverage diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 205bd43c232..8b2bce7ce45 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: BLADE_MCP_SENTRY_DSN: ${{ secrets.BLADE_MCP_SENTRY_DSN }} BLADE_SEGMENT_KEY: ${{ secrets.BLADE_SEGMENT_KEY }} with: - publish: yarn release + publish: pnpm release commit: 'build: update version' title: 'build: update version' - name: Publish to public npm registry @@ -42,11 +42,11 @@ jobs: BLADE_MCP_SENTRY_DSN: ${{ secrets.BLADE_MCP_SENTRY_DSN }} BLADE_SEGMENT_KEY: ${{ secrets.BLADE_SEGMENT_KEY }} PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} - run: yarn publish-npm + run: pnpm publish-npm - name: Build Blade if not built by changeset if: steps.changesets.outputs.published == 'false' working-directory: packages/blade - run: yarn build + run: pnpm build - name: Publish to Chromatic uses: chromaui/action@v1 if: steps.changesets.outputs.published == 'true' || github.event_name == 'workflow_dispatch' # run when the package is published via changeset or if a release is triggered manually. @@ -58,7 +58,7 @@ jobs: buildScriptName: react:storybook:build exitOnceUploaded: true onlyChanged: true - untraced: '**/package.json' + untraced: '**/package.json **/pnpm-lock.yaml' traceChanged: 'expanded' env: GITHUB_SHA: ${{ github.sha }} diff --git a/.npmrc b/.npmrc index f6573d967ed..733b415babd 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ @razorpay:registry=https://registry.npmjs.org/ +shared-workspace-lockfile=true \ No newline at end of file diff --git a/lerna.json b/lerna.json index bb04f83c50c..e1753b7b72c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,6 @@ { "version": "independent", - "npmClient": "yarn", - "useWorkspaces": true, + "npmClient": "pnpm", "command": { "bootstrap": { "ignoreScripts": true diff --git a/package.json b/package.json index 6cde9ed59d5..3ff50205167 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,11 @@ "engines": { "node": ">=18.12.1" }, + "pnpm": { + "overrides": { + "canvas": "npm:@napi-rs/canvas@0.1.69" + } + }, "workspaces": { "packages": [ "packages/blade", @@ -23,8 +28,8 @@ "lint:fix": "eslint --ext js,jsx,ts,tsx packages --fix && stylelint '**/*.{js,jsx,ts,tsx}' --fix", "publish-npm": "node ./scripts/publishToNpm.js", "release": "node ./scripts/generateGitHubRegistryNpmrc.js && changeset publish", - "postinstall": "yarn build:eslint-plugin-blade", - "build": "npm-run-all --parallel build:*", + "postinstall": "pnpm run build:eslint-plugin-blade", + "build": "npm-run-all build:*", "build:blade": "lerna run --scope @razorpay/blade build", "build:blade-mcp": "lerna run --scope @razorpay/blade-mcp build", "build:eslint-plugin-blade": "lerna run --scope eslint-plugin-blade build", diff --git a/packages/blade-mcp/package.json b/packages/blade-mcp/package.json index 315cd8795c0..94fcf8267d9 100644 --- a/packages/blade-mcp/package.json +++ b/packages/blade-mcp/package.json @@ -19,7 +19,7 @@ "base-blade-template" ], "scripts": { - "prepare": "yarn build", + "prepare": "pnpm build", "build": "cross-env NODE_ENV=production sh -c \"tsc && chmod +x dist/server.js && node src/replaceEnv.js\"", "dev": "tsx src/server.ts", "inspect": "npx -y @modelcontextprotocol/inspector node dist/server.js", diff --git a/packages/blade/.storybook/react/main.ts b/packages/blade/.storybook/react/main.ts index 63f5225ee1d..6646a561fb4 100644 --- a/packages/blade/.storybook/react/main.ts +++ b/packages/blade/.storybook/react/main.ts @@ -48,6 +48,10 @@ const config: StorybookConfig = { // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION' // You can change the configuration based on that. // 'PRODUCTION' is used when building the static version of storybook. + + // Add the devtool configuration here + config.devtool = 'eval'; + config.resolve.extensions = [ '.web.tsx', '.web.ts', diff --git a/packages/blade/jest.native.config.js b/packages/blade/jest.native.config.js index 64b0abfa7f0..bd666c1311c 100644 --- a/packages/blade/jest.native.config.js +++ b/packages/blade/jest.native.config.js @@ -19,7 +19,7 @@ module.exports = { }, testEnvironment: 'node', // Ref: https://github.com/callstack/react-native-testing-library/issues/896#issuecomment-1190249878 transformIgnorePatterns: [ - 'node_modules/(?!(react-native.*|@react-native.*|@?react-navigation.*|@?react-navigation-stack)/)', + 'node_modules/.pnpm/(?!(react-native.*|@react-native.*|@?react-navigation.*|@?react-navigation-stack)/)', ], setupFilesAfterEnv: [ '@testing-library/jest-native/extend-expect', diff --git a/packages/blade/jest.web.config.js b/packages/blade/jest.web.config.js index 6836cfb0f74..6db011d95bf 100644 --- a/packages/blade/jest.web.config.js +++ b/packages/blade/jest.web.config.js @@ -17,7 +17,7 @@ const baseConfig = { transform: { '\\.(js|ts|tsx)?$': './jest-preprocess.js', }, - transformIgnorePatterns: ['/node_modules/(?!(@table-library)/)'], + transformIgnorePatterns: ['/node_modules/(?!(.pnpm/)?@table-library.*)'], testEnvironment: 'jsdom', setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect', './jest-setup.web.js'], moduleNameMapper: { diff --git a/packages/blade/package.json b/packages/blade/package.json index 012c4971a76..b8f8f93bd52 100644 --- a/packages/blade/package.json +++ b/packages/blade/package.json @@ -85,16 +85,16 @@ } }, "scripts": { - "typecheck": "run-p types:typecheck:*", - "test": "run-p test:*", - "prepare": "yarn build", - "build": "run-s build:clean build:generate-types build:react-prod build:react-dev build:react-native build:clean-declarations build:generate-root-imports build:clean-theme-bundle", - "clearCache": "jest --clearCache", + "typecheck": "pnpm run --parallel types:typecheck:*", + "test": "npm-run-all test:*", + "prepare": "pnpm run build", + "build": "npm-run-all build:clean build:generate-types build:react-prod build:react-dev build:react-native build:clean-declarations build:generate-root-imports build:clean-theme-bundle", + "clearCache": "pnpm run jest --clearCache", "build:clean": "rm -rf build", "build:generate-types": "run-s types:generate-types:*", "build:copy-declarations": "run-s types:copy-declarations:*", - "types:generate-types:web": "tsc -p ./tsconfig-generate-types.web.json && yarn tsc-alias -p ./tsconfig-generate-types.web.json", - "types:generate-types:native": "tsc -p ./tsconfig-generate-types.native.json && yarn tsc-alias -p ./tsconfig-generate-types.native.json", + "types:generate-types:web": "tsc -p ./tsconfig-generate-types.web.json && pnpm tsc-alias -p ./tsconfig-generate-types.web.json", + "types:generate-types:native": "tsc -p ./tsconfig-generate-types.native.json && pnpm tsc-alias -p ./tsconfig-generate-types.native.json", "types:typecheck:web": "tsc -p ./tsconfig-typecheck.web.json", "types:typecheck:native": "tsc -p ./tsconfig-typecheck.native.json", "types:copy-declarations:web": "copyfiles -u 1 build/types/web/components/**/*.d.ts build/components/**/*", @@ -105,29 +105,29 @@ "build:react-prod": "cross-env FRAMEWORK=REACT NODE_ENV=production rollup -c", "build:react-native": "cross-env FRAMEWORK=REACT_NATIVE rollup -c", "build:clean-theme-bundle": "rm -rf build/js-bundle-for-css", - "react-native:get-stories": "sb-rn-get-stories --config-path=./.storybook/react-native && yarn prettier --write ./.storybook/react-native/storybook.requires.js", - "react-native:storybook:android": "yarn react-native:get-stories && cross-env FRAMEWORK=REACT_NATIVE react-native run-android", - "react-native:storybook:ios": "yarn react-native:get-stories && cross-env FRAMEWORK=REACT_NATIVE react-native run-ios", - "react-native:storybook:start": "yarn react-native:get-stories && cross-env NODE_OPTIONS=--openssl-legacy-provider FRAMEWORK=REACT_NATIVE react-native start --reset-cache", - "react": "yarn run react:storybook", + "react-native:get-stories": "sb-rn-get-stories --config-path=./.storybook/react-native && pnpm prettier --write ./.storybook/react-native/storybook.requires.js", + "react-native:storybook:android": "pnpm react-native:get-stories && cross-env FRAMEWORK=REACT_NATIVE react-native run-android", + "react-native:storybook:ios": "pnpm react-native:get-stories && cross-env FRAMEWORK=REACT_NATIVE react-native run-ios", + "react-native:storybook:start": "pnpm react-native:get-stories && cross-env NODE_OPTIONS=--openssl-legacy-provider FRAMEWORK=REACT_NATIVE react-native start --reset-cache", + "react": "pnpm run react:storybook", "react:storybook": "cross-env FRAMEWORK=REACT storybook dev -c ./.storybook/react -p 9009", - "react:storybook:build": "yarn generate-docs-lockfile && cross-env FRAMEWORK=REACT storybook build -c ./.storybook/react -o storybook-site --quiet", + "react:storybook:build": "pnpm run generate-docs-lockfile && cross-env FRAMEWORK=REACT storybook build -c ./.storybook/react -o storybook-site --quiet", "react:storybook:serve": "http-server storybook-site --port 9009 --silent", - "react:storybook:serve:test": "wait-on http://127.0.0.1:9009/ && yarn test:react:interaction", + "react:storybook:serve:test": "wait-on http://127.0.0.1:9009/ && pnpm run test:react:interaction", "test:react:interaction": "cross-env FRAMEWORK=REACT test-storybook -c ./.storybook/react --url http://127.0.0.1:9009/", - "test:react:interaction:ci": "yarn react:storybook:build && run-p react:storybook:serve react:storybook:serve:test --race", + "test:react:interaction:ci": "pnpm run react:storybook:build && --parallel react:storybook:serve react:storybook:serve:test --race", "test:react": "cross-env FRAMEWORK=REACT jest -c ./jest.web.config.js --shard=$SHARD --coverage --forceExit", "test:react-native": "cross-env FRAMEWORK=REACT_NATIVE jest -c ./jest.native.config.js --shard=$SHARD --forceExit", - "start:ios": "cross-env NODE_OPTIONS=--openssl-legacy-provider run-p react-native:storybook:start react-native:storybook:ios", - "start:android": "cross-env NODE_OPTIONS=--openssl-legacy-provider run-p react-native:storybook:start react-native:storybook:android", - "start:native": "cross-env NODE_OPTIONS=--openssl-legacy-provider run-p react-native:storybook:start react-native:storybook:android react-native:storybook:ios", - "start:web": "cross-env NODE_OPTIONS=--openssl-legacy-provider yarn react", - "start:all": "run-p start:native start:web", - "watch:test": "run-p watch:test:*", - "watch:test:react": "yarn test:react --watch --onlyChanged", - "watch:test:react-native": "yarn test:react-native --watch --onlyChanged", + "start:ios": "cross-env NODE_OPTIONS=--openssl-legacy-provider --parallel react-native:storybook:start react-native:storybook:ios", + "start:android": "cross-env NODE_OPTIONS=--openssl-legacy-provider --parallel react-native:storybook:start react-native:storybook:android", + "start:native": "cross-env NODE_OPTIONS=--openssl-legacy-provider --parallel react-native:storybook:start react-native:storybook:android react-native:storybook:ios", + "start:web": "cross-env NODE_OPTIONS=--openssl-legacy-provider pnpm react", + "start:all": "--parallel start:native start:web", + "watch:test": "--parallel watch:test:*", + "watch:test:react": "pnpm run test:react --watch --onlyChanged", + "watch:test:react-native": "pnpm run test:react-native --watch --onlyChanged", "chromatic": "npx chromatic", - "pregenerate-bundle-size-info": "yarn run-s build:clean build:generate-types build:react-prod", + "pregenerate-bundle-size-info": "npm-run-all build:clean build:generate-types build:react-prod", "generate-bundle-size-info": "node ./scripts/generateBundleSizeInfo.js", "generate-docs-lockfile": "node ./scripts/generateDocsLockFile.mjs", "generate-icons": "node ./scripts/generateIcons.mjs", @@ -211,6 +211,7 @@ "@storybook/test-runner": "0.16.0", "@storybook/testing-library": "0.2.2", "@testing-library/jest-dom": "5.16.4", + "@types/testing-library__jest-dom": "*", "@testing-library/jest-native": "5.4.2", "@testing-library/react": "13.4.0", "@testing-library/react-hooks": "8.0.1", @@ -223,6 +224,7 @@ "@types/jscodeshift": "0.11.6", "@types/jsdom": "20.0.1", "@types/react": "18.2.24", + "@types/react-dom": "18.2.6", "@types/react-native": "0.72.2", "@types/react-router-dom": "5.3.3", "@types/react-test-renderer": "17.0.1", @@ -327,13 +329,13 @@ "optional": true } }, - "resolutions": { - "@storybook/**/react-dom": "18.2.0", - "@storybook/**/react": "18.2.0", - "react-dom": "18.2.0", - "react": "18.2.0", - "@types/react": "18.2.24", - "@types/styled-components": "5.1.34", - "styled-components": "^5" + "pnpm": { + "overrides": { + "react-dom": "18.2.0", + "react": "18.2.0", + "@types/react": "18.2.24", + "@types/styled-components": "5.1.34", + "styled-components": "^5" + } } } diff --git a/packages/blade/scripts/generateDocsLockFile.mjs b/packages/blade/scripts/generateDocsLockFile.mjs index 28654fc1615..c2f58004458 100644 --- a/packages/blade/scripts/generateDocsLockFile.mjs +++ b/packages/blade/scripts/generateDocsLockFile.mjs @@ -25,13 +25,19 @@ const generateLockFileContent = ({ dependencies, devDependencies }) => { try { console.log('[lockfile-generation]: Creating package.json'); fs.writeFileSync(resolve('lock-generation/package.json'), JSON.stringify(packageJSON, null, 2)); - fs.writeFileSync(resolve('lock-generation/.npmrc'), 'auto-install-peers = false'); + fs.writeFileSync( + resolve('lock-generation/.npmrc'), + 'auto-install-peers = false\nstrict-peer-dependencies = false', + ); console.log('[lockfile-generation]: Installing Dependencies'); - execSync('yarn', { cwd: resolve('lock-generation'), stdio: 'inherit' }); + execSync('pnpm install --lockfile-only', { cwd: resolve('lock-generation'), stdio: 'inherit' }); - console.log('[lockfile-generation]: Moving lock file to /public/docs-yarn-lock.yaml'); - fs.renameSync(resolve('lock-generation/yarn.lock'), resolve('../public/docs-yarn-lock.yaml')); + console.log('[lockfile-generation]: Moving lock file to /public/docs-pnpm-lock.yaml'); + fs.renameSync( + resolve('lock-generation/pnpm-lock.yaml'), + resolve('../public/docs-pnpm-lock.yaml'), + ); } catch (err) { console.error(err); } finally { diff --git a/packages/blade/src/components/Accordion/Accordion.tsx b/packages/blade/src/components/Accordion/Accordion.tsx index 52d8e62cd5f..844a193c3c5 100644 --- a/packages/blade/src/components/Accordion/Accordion.tsx +++ b/packages/blade/src/components/Accordion/Accordion.tsx @@ -1,4 +1,9 @@ -import type { ReactElement } from 'react'; +import type { + ReactElement, + ForwardRefRenderFunction, + ForwardRefExoticComponent, + RefAttributes, +} from 'react'; import React, { useCallback, useMemo, useState, cloneElement, Children } from 'react'; import type { AccordionContextState } from './AccordionContext'; import { AccordionContext } from './AccordionContext'; @@ -63,7 +68,7 @@ const getVariantStyles = (variant: AccordionProps['variant']): BoxProps => { * Checkout https://blade.razorpay.com/?path=/docs/components-accordion--docs * */ -const _Accordion = ( +const _Accordion: ForwardRefRenderFunction = ( { defaultExpandedIndex, expandedIndex, @@ -141,6 +146,8 @@ const _Accordion = ( ); }; -const Accordion = React.forwardRef(_Accordion); +const Accordion: ForwardRefExoticComponent< + AccordionProps & RefAttributes +> = React.forwardRef(_Accordion); export { Accordion }; diff --git a/packages/blade/src/components/ActionList/styles/StyledActionList.native.tsx b/packages/blade/src/components/ActionList/styles/StyledActionList.native.tsx index 2c86950d94f..ba9a98e8b33 100644 --- a/packages/blade/src/components/ActionList/styles/StyledActionList.native.tsx +++ b/packages/blade/src/components/ActionList/styles/StyledActionList.native.tsx @@ -12,7 +12,9 @@ const BaseStyledActionList = styled(BaseBox)((props) => { }; }); -const StyledActionList = ({ +const StyledActionList: React.FC< + { children: React.ReactNode } & BaseBoxProps & StyledActionListProps +> = ({ children, onTouchEnd, onTouchStart, diff --git a/packages/blade/src/components/ActionList/styles/StyledActionList.web.tsx b/packages/blade/src/components/ActionList/styles/StyledActionList.web.tsx index bc9452ab8d7..5ee4e4fdb12 100644 --- a/packages/blade/src/components/ActionList/styles/StyledActionList.web.tsx +++ b/packages/blade/src/components/ActionList/styles/StyledActionList.web.tsx @@ -1,9 +1,14 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import { getBaseActionListStyles } from './getBaseActionListStyles'; import type { StyledActionListProps } from './getBaseActionListStyles'; import BaseBox from '~components/Box/BaseBox'; -const StyledActionList = styled(BaseBox)((props) => { +const StyledActionList: StyledComponent< + typeof BaseBox, + DefaultTheme, + StyledActionListProps +> = styled(BaseBox)((props) => { return { ...getBaseActionListStyles(props), }; diff --git a/packages/blade/src/components/ActionList/styles/StyledListBoxWrapper.web.tsx b/packages/blade/src/components/ActionList/styles/StyledListBoxWrapper.web.tsx index f06eba1c831..6c04adc33ff 100644 --- a/packages/blade/src/components/ActionList/styles/StyledListBoxWrapper.web.tsx +++ b/packages/blade/src/components/ActionList/styles/StyledListBoxWrapper.web.tsx @@ -1,12 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { SectionListProps } from 'react-native'; import { getBaseListBoxWrapperStyles } from './getBaseListBoxWrapperStyles'; import BaseBox from '~components/Box/BaseBox'; -const StyledListBoxWrapper = styled(BaseBox)< - Partial> & { isInBottomSheet: boolean } ->((props) => { +const StyledListBoxWrapper: StyledComponent< + typeof BaseBox, + any, + SectionListProps +> = styled(BaseBox)> & { isInBottomSheet: boolean }>((props) => { return { // Hides the last Divider (we don't want divider on last section) [`& [role=group]:last-child > [role=separator]:last-child`]: { diff --git a/packages/blade/src/components/Alert/Alert.tsx b/packages/blade/src/components/Alert/Alert.tsx index 9ae8e511de9..b9c206c5421 100644 --- a/packages/blade/src/components/Alert/Alert.tsx +++ b/packages/blade/src/components/Alert/Alert.tsx @@ -1,4 +1,4 @@ -import type { ReactChild, ReactElement } from 'react'; +import type { ForwardRefExoticComponent, RefAttributes, ReactChild, ReactElement } from 'react'; import React, { Fragment, useState, forwardRef } from 'react'; import { StyledAlert } from './StyledAlert'; @@ -339,7 +339,9 @@ const _Alert = ( ); }; -const Alert = forwardRef(_Alert); +const Alert: ForwardRefExoticComponent> = forwardRef( + _Alert, +); export type { AlertProps }; export { Alert }; diff --git a/packages/blade/src/components/Alert/StyledAlert.tsx b/packages/blade/src/components/Alert/StyledAlert.tsx index 1ea62e32b5b..7b4a0b05c54 100644 --- a/packages/blade/src/components/Alert/StyledAlert.tsx +++ b/packages/blade/src/components/Alert/StyledAlert.tsx @@ -1,6 +1,9 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { StyledAlertProps } from './types'; import { getCommonStyles } from './styles'; import BaseBox from '~components/Box/BaseBox'; -export const StyledAlert = styled(BaseBox)(getCommonStyles); +export const StyledAlert: StyledComponent = styled( + BaseBox, +)(getCommonStyles); diff --git a/packages/blade/src/components/AnimateInteractions/AnimateInteractions.web.tsx b/packages/blade/src/components/AnimateInteractions/AnimateInteractions.web.tsx index ad2b220c6b5..0d288bc7b1e 100644 --- a/packages/blade/src/components/AnimateInteractions/AnimateInteractions.web.tsx +++ b/packages/blade/src/components/AnimateInteractions/AnimateInteractions.web.tsx @@ -49,7 +49,11 @@ const AnimateInteractions = ({ return ( - + controls} + > {children} diff --git a/packages/blade/src/components/Avatar/Avatar.web.tsx b/packages/blade/src/components/Avatar/Avatar.web.tsx index 1a76d0c5383..33f32d89782 100644 --- a/packages/blade/src/components/Avatar/Avatar.web.tsx +++ b/packages/blade/src/components/Avatar/Avatar.web.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import type { AvatarProps } from './types'; import { StyledAvatar } from './StyledAvatar'; @@ -184,7 +185,9 @@ const _Avatar: React.ForwardRefRenderFunction = ( * Checkout {@link https://blade.razorpay.com/?path=/docs/components-avatar-avatar Avatar Documentation} * */ -const Avatar = assignWithoutSideEffects(React.forwardRef(_Avatar), { +const Avatar: ForwardRefExoticComponent< + AvatarProps & RefAttributes +> = assignWithoutSideEffects(React.forwardRef(_Avatar), { displayName: 'Avatar', componentId: 'Avatar', }); diff --git a/packages/blade/src/components/Avatar/AvatarButton.tsx b/packages/blade/src/components/Avatar/AvatarButton.tsx index 91c8e240cf8..52ad78c142f 100644 --- a/packages/blade/src/components/Avatar/AvatarButton.tsx +++ b/packages/blade/src/components/Avatar/AvatarButton.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import { StyledAvatarButton } from './StyledAvatarButton'; import type { AvatarButtonProps } from './types'; @@ -118,6 +119,8 @@ const _AvatarButton: React.ForwardRefRenderFunction +> = React.forwardRef(_AvatarButton); export { AvatarButton }; diff --git a/packages/blade/src/components/Avatar/StyledAvatar.tsx b/packages/blade/src/components/Avatar/StyledAvatar.tsx index 718ffcf7b3c..de86a08c2b6 100644 --- a/packages/blade/src/components/Avatar/StyledAvatar.tsx +++ b/packages/blade/src/components/Avatar/StyledAvatar.tsx @@ -1,10 +1,15 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { StyledAvatarProps } from './types'; import { avatarSizeTokens, avatarBorderRadiusTokens } from './avatarTokens'; import BaseBox from '~components/Box/BaseBox'; import { makeBorderSize, makeSize } from '~utils'; -const StyledAvatar = styled(BaseBox)( +const StyledAvatar: StyledComponent< + typeof BaseBox, + DefaultTheme, + StyledAvatarProps & { isInteractive?: boolean } +> = styled(BaseBox)( ({ theme, variant, size, isInteractive }) => { return { display: 'flex', diff --git a/packages/blade/src/components/Avatar/StyledAvatarButton.tsx b/packages/blade/src/components/Avatar/StyledAvatarButton.tsx index 3b2299730b3..a066e7b2818 100644 --- a/packages/blade/src/components/Avatar/StyledAvatarButton.tsx +++ b/packages/blade/src/components/Avatar/StyledAvatarButton.tsx @@ -1,3 +1,4 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { AvatarButtonProps } from './types'; import { avatarSizeTokens, avatarColorTokens, avatarBorderRadiusTokens } from './avatarTokens'; @@ -5,7 +6,11 @@ import { makeBorderSize, makeSize } from '~utils'; import getIn from '~utils/lodashButBetter/get'; import { getFocusRingStyles } from '~utils/getFocusRingStyles'; -const StyledAvatarButton = styled.button( +const StyledAvatarButton: StyledComponent< + 'button', + DefaultTheme, + AvatarButtonProps & { isInteractive?: boolean } +> = styled.button( ({ theme, size = 'medium', diff --git a/packages/blade/src/components/Avatar/StyledAvatarGroup.tsx b/packages/blade/src/components/Avatar/StyledAvatarGroup.tsx index 7f553e1c693..525f86fd231 100644 --- a/packages/blade/src/components/Avatar/StyledAvatarGroup.tsx +++ b/packages/blade/src/components/Avatar/StyledAvatarGroup.tsx @@ -1,21 +1,24 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { AvatarGroupProps } from './types'; import { avatarSizeTokens } from './avatarTokens'; import BaseBox from '~components/Box/BaseBox'; import { makeSize } from '~utils'; -const StyledAvatarGroup = styled(BaseBox)<{ size: NonNullable }>( - ({ size }) => { - return { - display: 'inline-flex', - flexDirection: 'row', +const StyledAvatarGroup: StyledComponent< + typeof BaseBox, + DefaultTheme, + { size: NonNullable } +> = styled(BaseBox)<{ size: NonNullable }>(({ size }) => { + return { + display: 'inline-flex', + flexDirection: 'row', - [`> *:not(:first-child)`]: { - marginLeft: `-${makeSize(avatarSizeTokens[size] / 2)}`, - zIndex: 2, - }, - }; - }, -); + [`> *:not(:first-child)`]: { + marginLeft: `-${makeSize(avatarSizeTokens[size] / 2)}`, + zIndex: 2, + }, + }; +}); export { StyledAvatarGroup }; diff --git a/packages/blade/src/components/Badge/Badge.tsx b/packages/blade/src/components/Badge/Badge.tsx index ed840669822..aad6aa5dacf 100644 --- a/packages/blade/src/components/Badge/Badge.tsx +++ b/packages/blade/src/components/Badge/Badge.tsx @@ -1,5 +1,5 @@ +import type { ForwardRefExoticComponent, RefAttributes, ReactElement } from 'react'; import React from 'react'; -import type { ReactElement } from 'react'; import type { StyledBadgeProps } from './types'; import { StyledBadge } from './StyledBadge'; import { iconPadding, iconSize, horizontalPadding, badgeHeight } from './badgeTokens'; @@ -173,7 +173,9 @@ const _Badge = ( ); }; -const Badge = assignWithoutSideEffects(React.forwardRef(_Badge), { +const Badge: ForwardRefExoticComponent< + BadgeProps & RefAttributes +> = assignWithoutSideEffects(React.forwardRef(_Badge), { displayName: 'Badge', componentId: 'Badge', }); diff --git a/packages/blade/src/components/Badge/StyledBadge.native.tsx b/packages/blade/src/components/Badge/StyledBadge.native.tsx index ebcb368acd7..d6d56cd5b60 100644 --- a/packages/blade/src/components/Badge/StyledBadge.native.tsx +++ b/packages/blade/src/components/Badge/StyledBadge.native.tsx @@ -1,9 +1,12 @@ import styled from 'styled-components/native'; +import type { DefaultTheme, StyledComponent } from 'styled-components'; import { getStyledBadgeStyles } from './getStyledBadgeStyles'; import type { StyledBadgeProps } from './types'; import BaseBox from '~components/Box/BaseBox'; -const StyledBadge = styled(BaseBox)((props) => ({ +const StyledBadge: StyledComponent = styled( + BaseBox, +)((props) => ({ ...getStyledBadgeStyles(props), alignSelf: 'center', })); diff --git a/packages/blade/src/components/Badge/StyledBadge.web.tsx b/packages/blade/src/components/Badge/StyledBadge.web.tsx index 5eac61cba1b..1c12f3bc7c4 100644 --- a/packages/blade/src/components/Badge/StyledBadge.web.tsx +++ b/packages/blade/src/components/Badge/StyledBadge.web.tsx @@ -1,9 +1,12 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import { getStyledBadgeStyles } from './getStyledBadgeStyles'; import type { StyledBadgeProps } from './types'; import BaseBox from '~components/Box/BaseBox'; -const StyledBadge = styled(BaseBox)((props) => ({ +const StyledBadge: StyledComponent = styled( + BaseBox, +)((props) => ({ ...getStyledBadgeStyles(props), width: 'fit-content', })); diff --git a/packages/blade/src/components/BaseMenu/BaseMenuItem/BaseMenuItem.tsx b/packages/blade/src/components/BaseMenu/BaseMenuItem/BaseMenuItem.tsx index d598c2dfd65..af1dfdb6793 100644 --- a/packages/blade/src/components/BaseMenu/BaseMenuItem/BaseMenuItem.tsx +++ b/packages/blade/src/components/BaseMenu/BaseMenuItem/BaseMenuItem.tsx @@ -128,6 +128,8 @@ const _BaseMenuItem: React.ForwardRefRenderFunction +> = React.forwardRef(_BaseMenuItem); export { BaseMenuItem }; diff --git a/packages/blade/src/components/BaseMenu/BaseMenuItem/StyledMenuItemContainer.web.tsx b/packages/blade/src/components/BaseMenu/BaseMenuItem/StyledMenuItemContainer.web.tsx index 9974d807c98..252bb01e86c 100644 --- a/packages/blade/src/components/BaseMenu/BaseMenuItem/StyledMenuItemContainer.web.tsx +++ b/packages/blade/src/components/BaseMenu/BaseMenuItem/StyledMenuItemContainer.web.tsx @@ -1,3 +1,4 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { StyledBaseMenuItemContainerProps } from '../types'; import { getBaseMenuItemStyles } from './getBaseMenuItemStyles'; @@ -6,7 +7,11 @@ import { getMediaQuery, makeSize } from '~utils'; import { getFocusRingStyles } from '~utils/getFocusRingStyles'; import BaseBox from '~components/Box/BaseBox'; -const StyledMenuItemContainer = styled(BaseBox)((props) => { +const StyledMenuItemContainer: StyledComponent< + 'div', + DefaultTheme, + StyledBaseMenuItemContainerProps +> = styled(BaseBox)((props) => { return { ...getBaseMenuItemStyles({ theme: props.theme }), padding: makeSize(getItemPadding(props.theme).itemPaddingMobile), diff --git a/packages/blade/src/components/BaseMotion/types.ts b/packages/blade/src/components/BaseMotion/types.ts index d2850729fca..74fb627d371 100644 --- a/packages/blade/src/components/BaseMotion/types.ts +++ b/packages/blade/src/components/BaseMotion/types.ts @@ -1,4 +1,5 @@ -import type { AnimationControls, TargetAndTransition, Tween } from 'framer-motion'; +//TODO: check this with @saurab +import type { animationControls, TargetAndTransition, Tween } from 'framer-motion'; import type React from 'react'; import type { Delay } from '~tokens/global/motion'; @@ -56,7 +57,7 @@ type BaseMotionBoxProps = { * animate={controls} * ``` */ - animate?: AnimationControls; + animate?: typeof animationControls; /** * This is for scenarios where you want to conditionally animate a component instead of it having static defined animation. diff --git a/packages/blade/src/components/BottomNav/BottomNav.web.tsx b/packages/blade/src/components/BottomNav/BottomNav.web.tsx index 0ca79f37680..5cb207e6d42 100644 --- a/packages/blade/src/components/BottomNav/BottomNav.web.tsx +++ b/packages/blade/src/components/BottomNav/BottomNav.web.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import styled from 'styled-components'; import type { BottomNavItemProps, BottomNavProps } from './types'; @@ -165,6 +166,8 @@ const BottomNavItem = ({ ); }; -const BottomNav = React.forwardRef(_BottomNav); +const BottomNav: ForwardRefExoticComponent< + BottomNavProps & RefAttributes +> = React.forwardRef(_BottomNav); export { BottomNav, BottomNavItem }; diff --git a/packages/blade/src/components/Box/BaseBox/BaseBox.web.tsx b/packages/blade/src/components/Box/BaseBox/BaseBox.web.tsx index 13ad3f51a6d..198169b7849 100644 --- a/packages/blade/src/components/Box/BaseBox/BaseBox.web.tsx +++ b/packages/blade/src/components/Box/BaseBox/BaseBox.web.tsx @@ -1,3 +1,4 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { BaseBoxProps } from './types'; import { useMemoizedStyles } from './useMemoizedStyles'; @@ -6,7 +7,7 @@ import { metaAttribute, MetaConstants } from '~utils/metaAttribute'; import { assignWithoutSideEffects } from '~utils/assignWithoutSideEffects'; import { makeAnalyticsAttribute } from '~utils/makeAnalyticsAttribute'; -const _BaseBox = styled.div +const _BaseBox: StyledComponent<'div', DefaultTheme, BaseBoxProps> = styled.div .attrs((props) => { return { ...metaAttribute({ diff --git a/packages/blade/src/components/Box/Box.tsx b/packages/blade/src/components/Box/Box.tsx index 791dc9b9c7e..1816e1f472f 100644 --- a/packages/blade/src/components/Box/Box.tsx +++ b/packages/blade/src/components/Box/Box.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import BaseBox from './BaseBox'; import type { BoxProps, BoxRefType, MakeValueResponsive } from './BaseBox/types'; @@ -266,7 +267,9 @@ const _Box: React.ForwardRefRenderFunction = (props, ref) ); }; -const Box = assignWithoutSideEffects(React.forwardRef(_Box), { +const Box: ForwardRefExoticComponent< + BoxProps & RefAttributes +> = assignWithoutSideEffects(React.forwardRef(_Box), { displayName: 'Box', componentId: 'Box', }); diff --git a/packages/blade/src/components/Breadcrumb/Breadcrumb.web.tsx b/packages/blade/src/components/Breadcrumb/Breadcrumb.web.tsx index a4fa00e3e7b..0971bd7cdfa 100644 --- a/packages/blade/src/components/Breadcrumb/Breadcrumb.web.tsx +++ b/packages/blade/src/components/Breadcrumb/Breadcrumb.web.tsx @@ -1,4 +1,5 @@ /* eslint-disable react-native-a11y/has-valid-accessibility-role */ +import type { ForwardRefExoticComponent } from 'react'; import React from 'react'; import type { BreadcrumbProps } from './types'; import { BreadcrumbContext } from './BreadcrumbContext'; @@ -92,6 +93,6 @@ const _Breadcrumb = ( ); }; -const Breadcrumb = React.forwardRef(_Breadcrumb); +const Breadcrumb: ForwardRefExoticComponent = React.forwardRef(_Breadcrumb); export { Breadcrumb }; diff --git a/packages/blade/src/components/Button/BaseButton/AnimatedButtonContent.web.tsx b/packages/blade/src/components/Button/BaseButton/AnimatedButtonContent.web.tsx index 5e9139d938b..03deb742a73 100644 --- a/packages/blade/src/components/Button/BaseButton/AnimatedButtonContent.web.tsx +++ b/packages/blade/src/components/Button/BaseButton/AnimatedButtonContent.web.tsx @@ -1,9 +1,14 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { AnimatedButtonContentProps } from './types'; import getIn from '~utils/lodashButBetter/get'; import BaseBox from '~components/Box/BaseBox'; -const AnimatedButtonContent = styled(BaseBox)((props) => { +const AnimatedButtonContent: StyledComponent< + 'div', + DefaultTheme, + AnimatedButtonContentProps +> = styled(BaseBox)((props) => { return { transform: `scale(${props.isPressed ? '0.95' : '1'})`, transitionDuration: getIn(props.theme.motion, props.motionEasing), diff --git a/packages/blade/src/components/Button/IconButton/IconButton.tsx b/packages/blade/src/components/Button/IconButton/IconButton.tsx index f1cc15a0faf..bda9c5441b0 100644 --- a/packages/blade/src/components/Button/IconButton/IconButton.tsx +++ b/packages/blade/src/components/Button/IconButton/IconButton.tsx @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable react/display-name */ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import type { GestureResponderEvent } from 'react-native'; import StyledIconButton from './StyledIconButton'; @@ -116,7 +117,9 @@ const _IconButton: React.ForwardRefRenderFunction +> = assignWithoutSideEffects(React.forwardRef(_IconButton), { componentId: 'IconButton', }); diff --git a/packages/blade/src/components/Button/IconButton/StyledIconButton.web.tsx b/packages/blade/src/components/Button/IconButton/StyledIconButton.web.tsx index 54789f9e2ac..7553a8d7cde 100644 --- a/packages/blade/src/components/Button/IconButton/StyledIconButton.web.tsx +++ b/packages/blade/src/components/Button/IconButton/StyledIconButton.web.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/display-name */ import styled from 'styled-components'; -import type { ReactElement } from 'react'; +import type { ReactElement, ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import type { StyledIconButtonProps } from './types'; import { highlightedButtonSizeMap, highlightedHoverColorMap } from './tokens'; @@ -14,6 +14,7 @@ import { throwBladeError } from '~utils/logger'; import getIn from '~utils/lodashButBetter/get'; import { makeAnalyticsAttribute } from '~utils/makeAnalyticsAttribute'; import { useStyledProps } from '~components/Box/styledProps'; +import type { BladeElementRef } from '~utils/types'; type StyledButtonProps = { emphasis: SubtleOrIntense; @@ -79,7 +80,9 @@ const StyledButton = styled.button((props) => { }; }); -const StyledIconButton = React.forwardRef( +const StyledIconButton: ForwardRefExoticComponent< + StyledIconButtonProps & RefAttributes +> = React.forwardRef( ( { icon: Icon, @@ -106,7 +109,7 @@ const StyledIconButton = React.forwardRef ( } onClick={castWebType(onClick)} emphasis={emphasis} type="button" diff --git a/packages/blade/src/components/ButtonGroup/ButtonGroup.web.tsx b/packages/blade/src/components/ButtonGroup/ButtonGroup.web.tsx index 8e39143b187..eb718cda9f3 100644 --- a/packages/blade/src/components/ButtonGroup/ButtonGroup.web.tsx +++ b/packages/blade/src/components/ButtonGroup/ButtonGroup.web.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import styled from 'styled-components'; import type { ButtonGroupProps } from './types'; @@ -132,7 +133,9 @@ const _ButtonGroup = ( * Checkout {@link https://blade.razorpay.com/?path=/docs/components-buttongroup FileUpload Documentation} * */ -const ButtonGroup = assignWithoutSideEffects(React.forwardRef(_ButtonGroup), { +const ButtonGroup: ForwardRefExoticComponent< + ButtonGroupProps & RefAttributes +> = assignWithoutSideEffects(React.forwardRef(_ButtonGroup), { displayName: 'ButtonGroup', componentId: 'ButtonGroup', }); diff --git a/packages/blade/src/components/ButtonGroup/StyledButtonGroup.tsx b/packages/blade/src/components/ButtonGroup/StyledButtonGroup.tsx index 688c070eca4..a129d55b51f 100644 --- a/packages/blade/src/components/ButtonGroup/StyledButtonGroup.tsx +++ b/packages/blade/src/components/ButtonGroup/StyledButtonGroup.tsx @@ -1,41 +1,45 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { StyledButtonGroupProps } from './types'; import BaseBox from '~components/Box/BaseBox'; import { makeBorderSize } from '~utils'; -const StyledButtonGroup = styled(BaseBox)( - ({ theme, variant = 'primary', isFullWidth }) => { - return { - display: 'flex', - width: isFullWidth ? '100%' : 'fit-content', - borderWidth: makeBorderSize(theme.border.width.thin), - borderRadius: makeBorderSize(theme.border.radius.medium), - borderStyle: 'solid', - borderColor: 'transparent', - overflow: 'hidden', - 'button[role="button"]': { - flex: isFullWidth ? 1 : 'auto', - borderRadius: 0, - }, +const StyledButtonGroup: StyledComponent< + typeof BaseBox, + DefaultTheme, + StyledButtonGroupProps, + never +> = styled(BaseBox)(({ theme, variant = 'primary', isFullWidth }) => { + return { + display: 'flex', + width: isFullWidth ? '100%' : 'fit-content', + borderWidth: makeBorderSize(theme.border.width.thin), + borderRadius: makeBorderSize(theme.border.radius.medium), + borderStyle: 'solid', + borderColor: 'transparent', + overflow: 'hidden', + 'button[role="button"]': { + flex: isFullWidth ? 1 : 'auto', + borderRadius: 0, + }, - ...(variant === 'secondary' && { - 'button[role="button"]:first-child': { - borderRight: 'none', - borderTopLeftRadius: makeBorderSize(theme.border.radius.medium), - borderBottomLeftRadius: makeBorderSize(theme.border.radius.medium), - }, - 'button[role="button"]:not(:first-child):not(:last-child)': { - borderLeft: 'none', - borderRight: 'none', - }, - 'button[role="button"]:last-child': { - borderLeft: 'none', - borderTopRightRadius: makeBorderSize(theme.border.radius.medium), - borderBottomRightRadius: makeBorderSize(theme.border.radius.medium), - }, - }), - }; - }, -); + ...(variant === 'secondary' && { + 'button[role="button"]:first-child': { + borderRight: 'none', + borderTopLeftRadius: makeBorderSize(theme.border.radius.medium), + borderBottomLeftRadius: makeBorderSize(theme.border.radius.medium), + }, + 'button[role="button"]:not(:first-child):not(:last-child)': { + borderLeft: 'none', + borderRight: 'none', + }, + 'button[role="button"]:last-child': { + borderLeft: 'none', + borderTopRightRadius: makeBorderSize(theme.border.radius.medium), + borderBottomRightRadius: makeBorderSize(theme.border.radius.medium), + }, + }), + }; +}); export { StyledButtonGroup }; diff --git a/packages/blade/src/components/Card/Card.tsx b/packages/blade/src/components/Card/Card.tsx index 3eeb7be559c..05ffc44072f 100644 --- a/packages/blade/src/components/Card/Card.tsx +++ b/packages/blade/src/components/Card/Card.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import type { GestureResponderEvent } from 'react-native'; import { CardSurface } from './CardSurface'; @@ -319,7 +320,9 @@ const _CardBody = ({ height, children, testID, ...rest }: CardBodyProps): React. ); }; -const Card = React.forwardRef(_Card); +const Card: ForwardRefExoticComponent< + CardProps & RefAttributes +> = React.forwardRef(_Card); const CardBody = assignWithoutSideEffects(_CardBody, { componentId: ComponentIds.CardBody }); export { Card, CardBody }; diff --git a/packages/blade/src/components/Card/CardRoot.native.tsx b/packages/blade/src/components/Card/CardRoot.native.tsx index 04db704971a..2b6815f44d5 100644 --- a/packages/blade/src/components/Card/CardRoot.native.tsx +++ b/packages/blade/src/components/Card/CardRoot.native.tsx @@ -96,6 +96,8 @@ const _CardRoot: React.ForwardRefRenderFunction ); }; -const CardRoot = React.forwardRef(_CardRoot); +const CardRoot: React.ForwardRefExoticComponent< + CardRootProps & React.RefAttributes +> = React.forwardRef(_CardRoot); export { CardRoot }; diff --git a/packages/blade/src/components/Card/CardRoot.web.tsx b/packages/blade/src/components/Card/CardRoot.web.tsx index 4fce42338c7..85399198b43 100644 --- a/packages/blade/src/components/Card/CardRoot.web.tsx +++ b/packages/blade/src/components/Card/CardRoot.web.tsx @@ -1,4 +1,5 @@ import styled from 'styled-components'; +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import type { CardRootProps } from './types'; import { CARD_LINK_OVERLAY_ID, CARD_SCALE_DOWN_VALUE, CARD_SCALE_UP_VALUE } from './constants'; @@ -105,6 +106,8 @@ const _CardRoot: React.ForwardRefRenderFunction ); }; -const CardRoot = React.forwardRef(_CardRoot); +const CardRoot: ForwardRefExoticComponent< + CardRootProps & RefAttributes +> = React.forwardRef(_CardRoot); export { CardRoot }; diff --git a/packages/blade/src/components/Card/LinkOverlay.web.tsx b/packages/blade/src/components/Card/LinkOverlay.web.tsx index 714339712dc..d7bed827597 100644 --- a/packages/blade/src/components/Card/LinkOverlay.web.tsx +++ b/packages/blade/src/components/Card/LinkOverlay.web.tsx @@ -1,9 +1,13 @@ -import type { CSSObject } from 'styled-components'; +import type { CSSObject, DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { LinkOverlayProps } from './types'; // https://www.sarasoueidan.com/blog/nested-links/ -const LinkOverlay = styled.a( +const LinkOverlay: StyledComponent< + 'a', + DefaultTheme, + LinkOverlayProps +> = styled.a( (): CSSObject => { return { // Need this to reset the button styles diff --git a/packages/blade/src/components/Carousel/Carousel.web.tsx b/packages/blade/src/components/Carousel/Carousel.web.tsx index a72e6981973..38d7d49d43f 100644 --- a/packages/blade/src/components/Carousel/Carousel.web.tsx +++ b/packages/blade/src/components/Carousel/Carousel.web.tsx @@ -6,6 +6,7 @@ /* eslint-disable react/jsx-no-useless-fragment */ import type { CSSObject } from 'styled-components'; import styled from 'styled-components'; +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import { Indicators } from './Indicators/Indicators'; import { NavigationButton } from './NavigationButton'; @@ -641,6 +642,8 @@ const _Carousel = ( ); }; -const Carousel = React.forwardRef(_Carousel); +const Carousel: ForwardRefExoticComponent< + CarouselProps & RefAttributes +> = React.forwardRef(_Carousel); export { Carousel }; diff --git a/packages/blade/src/components/Checkbox/Checkbox.tsx b/packages/blade/src/components/Checkbox/Checkbox.tsx index 4eab7e3e5ca..54707c68b2e 100644 --- a/packages/blade/src/components/Checkbox/Checkbox.tsx +++ b/packages/blade/src/components/Checkbox/Checkbox.tsx @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/restrict-plus-operands */ /* eslint-disable @typescript-eslint/no-shadow */ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import { useCheckboxGroupContext } from './CheckboxGroup/CheckboxGroupContext'; import { CheckboxIcon } from './CheckboxIcon'; @@ -282,7 +283,9 @@ const _Checkbox: React.ForwardRefRenderFunction ); }; -const Checkbox = assignWithoutSideEffects(React.forwardRef(_Checkbox), { +const Checkbox: ForwardRefExoticComponent< + CheckboxProps & RefAttributes +> = assignWithoutSideEffects(React.forwardRef(_Checkbox), { displayName: 'Checkbox', }); diff --git a/packages/blade/src/components/Chip/AnimatedChip.web.tsx b/packages/blade/src/components/Chip/AnimatedChip.web.tsx index f65897bc7ba..629497ecd74 100644 --- a/packages/blade/src/components/Chip/AnimatedChip.web.tsx +++ b/packages/blade/src/components/Chip/AnimatedChip.web.tsx @@ -1,3 +1,4 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import { getAnimatedChipStyles } from './getAnimatedChipStyles'; import type { AnimatedChipProps } from './types'; @@ -7,7 +8,12 @@ import BaseBox from '~components/Box/BaseBox'; import { makeMotionTime } from '~utils/makeMotionTime'; import { castWebType } from '~utils'; -const AnimatedChip = styled(BaseBox)((props) => { +const AnimatedChip: StyledComponent< + typeof BaseBox, + DefaultTheme, + AnimatedChipProps, + never +> = styled(BaseBox)((props) => { const easing = getIn(props.theme.motion, chipMotionTokens.easing); const duration = castWebType( makeMotionTime(getIn(props.theme.motion, chipMotionTokens.duration)), diff --git a/packages/blade/src/components/Chip/StyledChipWrapper.native.tsx b/packages/blade/src/components/Chip/StyledChipWrapper.native.tsx index 627487671cb..9624a6be694 100644 --- a/packages/blade/src/components/Chip/StyledChipWrapper.native.tsx +++ b/packages/blade/src/components/Chip/StyledChipWrapper.native.tsx @@ -1,15 +1,18 @@ import styled from 'styled-components/native'; +import type { DefaultTheme, StyledComponent } from 'styled-components'; import type { StyledChipWrapperProps } from './types'; import getIn from '~utils/lodashButBetter/get'; import BaseBox from '~components/Box/BaseBox'; -const StyledChipWrapper = styled(BaseBox)( - ({ theme, borderColor, isChecked }) => { - return { - display: 'flex', - borderColor: isChecked ? getIn(theme.colors, borderColor) : 'transparent', - }; - }, -); +const StyledChipWrapper: StyledComponent< + typeof BaseBox, + DefaultTheme, + StyledChipWrapperProps +> = styled(BaseBox)(({ theme, borderColor, isChecked }) => { + return { + display: 'flex', + borderColor: isChecked ? getIn(theme.colors, borderColor) : 'transparent', + }; +}); export { StyledChipWrapper }; diff --git a/packages/blade/src/components/Chip/StyledChipWrapper.web.tsx b/packages/blade/src/components/Chip/StyledChipWrapper.web.tsx index ece17d72734..5c0cf65f7f6 100644 --- a/packages/blade/src/components/Chip/StyledChipWrapper.web.tsx +++ b/packages/blade/src/components/Chip/StyledChipWrapper.web.tsx @@ -1,3 +1,4 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import type { StyledChipWrapperProps } from './types'; import { chipMotionTokens, chipColorTokens } from './chipTokens'; @@ -6,7 +7,12 @@ import BaseBox from '~components/Box/BaseBox'; import { makeMotionTime } from '~utils/makeMotionTime'; import { castWebType } from '~utils'; -const StyledChipWrapper = styled(BaseBox)( +const StyledChipWrapper: StyledComponent< + typeof BaseBox, + DefaultTheme, + StyledChipWrapperProps, + never +> = styled(BaseBox)( ({ theme, borderColor, isChecked, isDisabled, color }) => { const easing = getIn(theme.motion, chipMotionTokens.easing); const duration = castWebType(makeMotionTime(getIn(theme.motion, chipMotionTokens.duration))); diff --git a/packages/blade/src/components/Chip/__tests__/__snapshots__/Chip.web.test.tsx.snap b/packages/blade/src/components/Chip/__tests__/__snapshots__/Chip.web.test.tsx.snap index 96dcc05e415..665cb5798ef 100644 --- a/packages/blade/src/components/Chip/__tests__/__snapshots__/Chip.web.test.tsx.snap +++ b/packages/blade/src/components/Chip/__tests__/__snapshots__/Chip.web.test.tsx.snap @@ -310,7 +310,7 @@ exports[` should accept data-analytics-* 1`] = ` data-blade-component="base-box" >
should accept data-analytics-* 1`] = ` > should accept data-analytics-* 1`] = ` > +> = assignWithoutSideEffects(forwardRef(_Collapsible), { componentId: componentIds.Collapsible, }); diff --git a/packages/blade/src/components/Counter/Counter.tsx b/packages/blade/src/components/Counter/Counter.tsx index 502e2d7cfc3..2d1629db763 100644 --- a/packages/blade/src/components/Counter/Counter.tsx +++ b/packages/blade/src/components/Counter/Counter.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import { StyledCounter } from './StyledCounter'; import type { StyledCounterProps } from './types'; @@ -153,7 +154,9 @@ const _Counter = ( ); }; -const Counter = assignWithoutSideEffects(React.forwardRef(_Counter), { +const Counter: ForwardRefExoticComponent< + CounterProps & RefAttributes +> = assignWithoutSideEffects(React.forwardRef(_Counter), { displayName: 'Counter', componentId: 'Counter', }); diff --git a/packages/blade/src/components/Counter/StyledCounter.native.tsx b/packages/blade/src/components/Counter/StyledCounter.native.tsx index 29f76850134..f7e43e5a57b 100644 --- a/packages/blade/src/components/Counter/StyledCounter.native.tsx +++ b/packages/blade/src/components/Counter/StyledCounter.native.tsx @@ -1,9 +1,12 @@ import styled from 'styled-components/native'; +import type { DefaultTheme, StyledComponent } from 'styled-components'; import { getStyledCounterStyles } from './getStyledCounterStyles'; import type { StyledCounterProps } from './types'; import BaseBox from '~components/Box/BaseBox'; -const StyledCounter = styled(BaseBox)((props) => ({ +const StyledCounter: StyledComponent = styled( + BaseBox, +)((props) => ({ ...getStyledCounterStyles(props), alignSelf: 'center', })); diff --git a/packages/blade/src/components/Counter/StyledCounter.web.tsx b/packages/blade/src/components/Counter/StyledCounter.web.tsx index f1b50ca2941..bc7f94f46df 100644 --- a/packages/blade/src/components/Counter/StyledCounter.web.tsx +++ b/packages/blade/src/components/Counter/StyledCounter.web.tsx @@ -1,9 +1,15 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import { getStyledCounterStyles } from './getStyledCounterStyles'; import type { StyledCounterProps } from './types'; import BaseBox from '~components/Box/BaseBox'; -const StyledCounter = styled(BaseBox)((props) => ({ +const StyledCounter: StyledComponent< + typeof BaseBox, + DefaultTheme, + StyledCounterProps, + never +> = styled(BaseBox)((props) => ({ ...getStyledCounterStyles(props), width: 'fit-content', })); diff --git a/packages/blade/src/components/DatePicker/BaseDatePicker.web.tsx b/packages/blade/src/components/DatePicker/BaseDatePicker.web.tsx index 2b021805dcd..a94b63335e5 100644 --- a/packages/blade/src/components/DatePicker/BaseDatePicker.web.tsx +++ b/packages/blade/src/components/DatePicker/BaseDatePicker.web.tsx @@ -3,6 +3,7 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { DatesProvider } from '@mantine/dates'; +import type { FC } from 'react'; import React from 'react'; import { FloatingFocusManager, FloatingPortal } from '@floating-ui/react'; import { useI18nContext } from '@razorpay/i18nify-react'; @@ -51,7 +52,14 @@ const CALENDAR_HEIGHTS = { DAY_PICKER_WITH_FOOTER: 'auto', } as const; -const BaseDatePicker = ({ +const BaseDatePicker: FC< + DatePickerProps & + StyledPropsBlade & + DataAnalyticsAttribute & { + inputElementType: 'chip' | 'datePickerInput'; + onClearButtonClick?: () => void; + } +> = ({ selectionType, allowSingleDateInRange, value, @@ -88,7 +96,7 @@ const BaseDatePicker = ({ showFooterActions = true, footer, ...props -}: DatePickerProps & +}: DatePickerProps & StyledPropsBlade & DataAnalyticsAttribute & { inputElementType: 'chip' | 'datePickerInput'; diff --git a/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx b/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx index b412a1b1095..964a4be04b6 100644 --- a/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx +++ b/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/restrict-plus-operands */ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import dayjs from 'dayjs'; import type { PickerType } from './types'; @@ -90,83 +91,91 @@ const inRangeCell = { }, } as const; -const CalendarGradientStyles = styled(BaseBox)<{ date: Date; isRange: boolean }>( - ({ theme, date, isRange }) => { - const isMobile = useIsMobile(); - // Bail out if datepicker is not in range mode or on mobile - if (isMobile || !isRange) return {}; +const CalendarGradientStyles: StyledComponent< + typeof BaseBox, + DefaultTheme, + { date: Date; isRange: boolean }, + never +> = styled(BaseBox)<{ date: Date; isRange: boolean }>(({ theme, date, isRange }) => { + const isMobile = useIsMobile(); + // Bail out if datepicker is not in range mode or on mobile + if (isMobile || !isRange) return {}; - // Calculate the first and last day of the month for both calendars in range mode - // This is to apply the gradient to the first and last day of the month - const cal1 = dayjs(date); - const cal1FirstDay = cal1.startOf('month'); - const cal1LastDay = cal1.endOf('month'); - // Check if the first and last day of the month are at the start or end of the week - // If so, we don't apply the gradient, as it will overflow to the previous or next month - // Eg: https://github.com/razorpay/blade/assets/35374649/025b8ed9-90b4-49b6-a307-a746ae5b910f - const cal1IsFirstDayStartOfTheWeek = cal1FirstDay.day() === 0; - const cal1IsLastDayEndOfTheWeek = cal1LastDay.day() === 6; + // Calculate the first and last day of the month for both calendars in range mode + // This is to apply the gradient to the first and last day of the month + const cal1 = dayjs(date); + const cal1FirstDay = cal1.startOf('month'); + const cal1LastDay = cal1.endOf('month'); + // Check if the first and last day of the month are at the start or end of the week + // If so, we don't apply the gradient, as it will overflow to the previous or next month + // Eg: https://github.com/razorpay/blade/assets/35374649/025b8ed9-90b4-49b6-a307-a746ae5b910f + const cal1IsFirstDayStartOfTheWeek = cal1FirstDay.day() === 0; + const cal1IsLastDayEndOfTheWeek = cal1LastDay.day() === 6; - // Do the same for the second calendar - const cal2 = dayjs(date).add(1, 'month'); - const cal2FirstDay = cal2.startOf('month'); - const cal2LastDay = cal2.endOf('month'); - const cal2IsFirstDayStartOfTheWeek = cal2FirstDay.day() === 0; - const cal2IsLastDayEndOfTheWeek = cal2LastDay.day() === 6; + // Do the same for the second calendar + const cal2 = dayjs(date).add(1, 'month'); + const cal2FirstDay = cal2.startOf('month'); + const cal2LastDay = cal2.endOf('month'); + const cal2IsFirstDayStartOfTheWeek = cal2FirstDay.day() === 0; + const cal2IsLastDayEndOfTheWeek = cal2LastDay.day() === 6; - const calendar1FirstGradient = `${cal1.month()}-${cal1FirstDay.date()}`; - const calendar1LastGradient = `${cal1.month()}-${cal1LastDay.date()}`; - const calendar2FirstGradient = `${cal2.month()}-${cal2FirstDay.date()}`; - const calendar2LastGradient = `${cal2.month()}-${cal2LastDay.date()}`; + const calendar1FirstGradient = `${cal1.month()}-${cal1FirstDay.date()}`; + const calendar1LastGradient = `${cal1.month()}-${cal1LastDay.date()}`; + const calendar2FirstGradient = `${cal2.month()}-${cal2FirstDay.date()}`; + const calendar2LastGradient = `${cal2.month()}-${cal2LastDay.date()}`; - const gradientBefore = { - content: '""', - position: 'absolute', - width: '100%', - top: 0, - bottom: 0, - right: 0, - pointerEvents: 'none', - } as const; - const rightGradient = { - ...gradientBefore, - left: '-100%', - background: `linear-gradient(to right, transparent, ${getIn( - theme.colors, - inRangeCell.background.default, - )})`, - }; - const leftGradient = { - ...gradientBefore, - left: '100%', - background: `linear-gradient(to left, transparent, ${getIn( - theme.colors, - inRangeCell.background.default, - )})`, - }; + const gradientBefore = { + content: '""', + position: 'absolute', + width: '100%', + top: 0, + bottom: 0, + right: 0, + pointerEvents: 'none', + } as const; + const rightGradient = { + ...gradientBefore, + left: '-100%', + background: `linear-gradient(to right, transparent, ${getIn( + theme.colors, + inRangeCell.background.default, + )})`, + }; + const leftGradient = { + ...gradientBefore, + left: '100%', + background: `linear-gradient(to left, transparent, ${getIn( + theme.colors, + inRangeCell.background.default, + )})`, + }; - return { - [`.${classes.dayCell}`]: { - // First calendar column - [`&[data-in-range]:not(&[data-first-in-range])[data-date="${calendar1FirstGradient}"]`]: { - '&:before': cal1IsFirstDayStartOfTheWeek ? {} : rightGradient, - }, - [`&[data-in-range]:not(&[data-last-in-range])[data-date="${calendar1LastGradient}"]`]: { - '&:before': cal1IsLastDayEndOfTheWeek ? {} : leftGradient, - }, - // Second calendar column - [`&[data-in-range]:not(&[data-first-in-range])[data-date="${calendar2FirstGradient}"]`]: { - '&:before': cal2IsFirstDayStartOfTheWeek ? {} : rightGradient, - }, - [`&[data-in-range]:not(&[data-last-in-range])[data-date="${calendar2LastGradient}"]`]: { - '&:before': cal2IsLastDayEndOfTheWeek ? {} : leftGradient, - }, + return { + [`.${classes.dayCell}`]: { + // First calendar column + [`&[data-in-range]:not(&[data-first-in-range])[data-date="${calendar1FirstGradient}"]`]: { + '&:before': cal1IsFirstDayStartOfTheWeek ? {} : rightGradient, }, - }; - }, -); + [`&[data-in-range]:not(&[data-last-in-range])[data-date="${calendar1LastGradient}"]`]: { + '&:before': cal1IsLastDayEndOfTheWeek ? {} : leftGradient, + }, + // Second calendar column + [`&[data-in-range]:not(&[data-first-in-range])[data-date="${calendar2FirstGradient}"]`]: { + '&:before': cal2IsFirstDayStartOfTheWeek ? {} : rightGradient, + }, + [`&[data-in-range]:not(&[data-last-in-range])[data-date="${calendar2LastGradient}"]`]: { + '&:before': cal2IsLastDayEndOfTheWeek ? {} : leftGradient, + }, + }, + }; +}); -const CalendarStyles = styled(BaseBox)<{ pickerType?: PickerType }>(({ theme, pickerType }) => { +const CalendarStyles: StyledComponent< + typeof BaseBox, + DefaultTheme, + { pickerType?: PickerType }, + never +> = styled(BaseBox)<{ pickerType?: PickerType }>(({ theme, pickerType }) => { const isMobile = useIsMobile(); const device = isMobile ? 'mobile' : 'desktop'; const isDayPicker = pickerType === 'day'; diff --git a/packages/blade/src/components/DatePicker/__tests__/DatePicker.test.stories.tsx b/packages/blade/src/components/DatePicker/__tests__/DatePicker.test.stories.tsx index f88d2b26bf3..42b3be25737 100644 --- a/packages/blade/src/components/DatePicker/__tests__/DatePicker.test.stories.tsx +++ b/packages/blade/src/components/DatePicker/__tests__/DatePicker.test.stories.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ /* eslint-disable import/no-extraneous-dependencies */ import type { StoryFn } from '@storybook/react'; import { within, userEvent } from '@storybook/testing-library'; diff --git a/packages/blade/src/components/DatePicker/usePopup.ts b/packages/blade/src/components/DatePicker/usePopup.ts index 890718a5868..459d0b57bbe 100644 --- a/packages/blade/src/components/DatePicker/usePopup.ts +++ b/packages/blade/src/components/DatePicker/usePopup.ts @@ -1,5 +1,10 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ -import type { UseFloatingOptions } from '@floating-ui/react'; +import type { CSSProperties } from 'react'; +import type { + UseFloatingOptions, + UseFloatingReturn, + UseInteractionsReturn, +} from '@floating-ui/react'; import { autoUpdate, flip, @@ -25,6 +30,17 @@ type UsePopupProps = { crossAxisOffset?: number; }; +type UsePopupReturn = { + refs: UseFloatingReturn['refs']; + context: UseFloatingReturn['context']; + isMounted: boolean; + floatingStyles: CSSProperties; + animationStyles: CSSProperties; + getReferenceProps: UseInteractionsReturn['getReferenceProps']; + getFloatingProps: UseInteractionsReturn['getFloatingProps']; +}; + +// 💡 Step 2: Apply the return type to the function signature const usePopup = ({ enabled = true, placement, @@ -32,7 +48,7 @@ const usePopup = ({ onOpenChange, referenceRef, crossAxisOffset = 0, -}: UsePopupProps) => { +}: UsePopupProps): UsePopupReturn => { const GAP = spacing[4]; const { theme } = useTheme(); const [side] = getFloatingPlacementParts(placement!); @@ -77,7 +93,6 @@ const usePopup = ({ }, }); - // remove click handler if popover is controlled const click = useClick(context); const dismiss = useDismiss(context, { enabled }); const role = useRole(context); diff --git a/packages/blade/src/components/Divider/Divider.tsx b/packages/blade/src/components/Divider/Divider.tsx index 458b2bce86e..0fff8e957c0 100644 --- a/packages/blade/src/components/Divider/Divider.tsx +++ b/packages/blade/src/components/Divider/Divider.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import type { CSSObject } from 'styled-components'; import styled from 'styled-components'; @@ -100,7 +101,9 @@ const _Divider = ( ); }; -const Divider = React.forwardRef(_Divider); +const Divider: ForwardRefExoticComponent< + DividerProps & RefAttributes +> = React.forwardRef(_Divider); export { Divider }; export type { DividerProps }; diff --git a/packages/blade/src/components/Dropdown/Dropdown.tsx b/packages/blade/src/components/Dropdown/Dropdown.tsx index 83d2ab9b609..4b93af0c6d3 100644 --- a/packages/blade/src/components/Dropdown/Dropdown.tsx +++ b/packages/blade/src/components/Dropdown/Dropdown.tsx @@ -1,3 +1,4 @@ +import type { ForwardRefExoticComponent, RefAttributes } from 'react'; import React from 'react'; import { DropdownContext } from './useDropdown'; import type { DropdownContextType } from './useDropdown'; @@ -260,7 +261,9 @@ const _Dropdown = ( ); }; -const Dropdown = assignWithoutSideEffects(React.forwardRef(_Dropdown), { +const Dropdown: ForwardRefExoticComponent< + DropdownProps & RefAttributes +> = assignWithoutSideEffects(React.forwardRef(_Dropdown), { componentId: dropdownComponentIds.Dropdown, }); diff --git a/packages/blade/src/components/Dropdown/DropdownIconButton.tsx b/packages/blade/src/components/Dropdown/DropdownIconButton.tsx index ce83fb19e0d..c42ba311ec3 100644 --- a/packages/blade/src/components/Dropdown/DropdownIconButton.tsx +++ b/packages/blade/src/components/Dropdown/DropdownIconButton.tsx @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ - import React from 'react'; import { useDropdown } from './useDropdown'; import { dropdownComponentIds } from './dropdownComponentIds'; +import type { BladeElementRef } from '~utils/types'; import { getActionListContainerRole } from '~components/ActionList/getA11yRoles'; import type { BaseButtonProps } from '~components/Button/BaseButton/BaseButton'; import { assignWithoutSideEffects } from '~utils/assignWithoutSideEffects'; @@ -16,7 +16,10 @@ type DropdownIconButtonProps = Omit & { onClick?: IconButtonProps['onClick']; }; -const _DropdownIconButton = ({ +const _DropdownIconButton: React.ForwardRefRenderFunction< + BladeElementRef, + DropdownIconButtonProps +> = ({ icon, isDisabled = false, onClick, @@ -54,17 +57,17 @@ const _DropdownIconButton = ({ controls: `${dropdownBaseId}-actionlist`, activeDescendant: activeIndex >= 0 ? `${dropdownBaseId}-${activeIndex}` : undefined, }} - onClick={(e) => { + onClick={(e: any) => { onTriggerClick(); // Setting it for web fails it on native typecheck and vice versa onClick?.(e as any); }} - onBlur={(e) => { + onBlur={(e: any) => { // With button trigger, there is no "value" as such. It's just clickable items // Setting it for web fails it on native typecheck and vice versa onBlur?.(e as any); }} - onKeyDown={(e) => { + onKeyDown={(e: any) => { onTriggerKeydown?.({ event: e as any }); // Setting it for web fails it on native typecheck and vice versa onKeyDown?.(e as any); diff --git a/packages/blade/src/components/Dropdown/StyledDropdownOverlay.tsx b/packages/blade/src/components/Dropdown/StyledDropdownOverlay.tsx index da9cc21381c..feea9e488da 100644 --- a/packages/blade/src/components/Dropdown/StyledDropdownOverlay.tsx +++ b/packages/blade/src/components/Dropdown/StyledDropdownOverlay.tsx @@ -1,8 +1,16 @@ +import type { DefaultTheme, StyledComponent } from 'styled-components'; import styled from 'styled-components'; import BaseBox from '~components/Box/BaseBox'; import { makeSize } from '~utils'; -const StyledDropdownOverlay = styled(BaseBox)<{ +const StyledDropdownOverlay: StyledComponent< + typeof BaseBox, + DefaultTheme, + { + isInBottomSheet?: boolean; + }, + never +> = styled(BaseBox)<{ isInBottomSheet?: boolean; }>((props) => { const { theme, isInBottomSheet } = props; diff --git a/packages/blade/src/components/Dropdown/__tests__/__snapshots__/Dropdown.web.test.tsx.snap b/packages/blade/src/components/Dropdown/__tests__/__snapshots__/Dropdown.web.test.tsx.snap index 2295de02387..e2c4df222cc 100644 --- a/packages/blade/src/components/Dropdown/__tests__/__snapshots__/Dropdown.web.test.tsx.snap +++ b/packages/blade/src/components/Dropdown/__tests__/__snapshots__/Dropdown.web.test.tsx.snap @@ -571,8 +571,8 @@ exports[` should render autocomplete inside dropdown 1`] = ` >