diff --git a/package-lock.json b/package-lock.json index 5d98112ba8f..0081900e1bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83355,7 +83355,8 @@ "license": "MIT", "dependencies": { "@salutejs/plasma-new-hope": "0.378.0", - "@salutejs/sdds-themes": "0.79.0" + "@salutejs/sdds-themes": "0.79.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", @@ -83368,7 +83369,10 @@ "@emotion/babel-plugin": "11.11.0", "@emotion/react": ">=11", "@emotion/styled": ">=11", + "@ironkinoko/rollup-plugin-styles": "^4.0.3", "@originjs/vite-plugin-commonjs": "1.0.3", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-node-resolve": "^15.1.0", "@salutejs/plasma-colors": "0.22.0", "@salutejs/plasma-core": "1.241.0", "@salutejs/plasma-cy-utils": "0.171.0", @@ -83384,6 +83388,7 @@ "default-browser-id": "2.0.0", "react": "18.2.0", "react-dom": "18.2.0", + "rollup": "^3.28.0", "styled-components": "5.3.1", "typescript-coverage-report": "0.7.0" }, @@ -83754,6 +83759,23 @@ "react": "^18.2.0" } }, + "packages/sdds-cs/node_modules/rollup": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "packages/sdds-cs/node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -84230,7 +84252,8 @@ "license": "MIT", "dependencies": { "@salutejs/plasma-new-hope": "0.378.0", - "@salutejs/sdds-themes": "0.79.0" + "@salutejs/sdds-themes": "0.79.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", @@ -84834,7 +84857,8 @@ "license": "MIT", "dependencies": { "@salutejs/plasma-new-hope": "0.378.0", - "@salutejs/sdds-themes": "0.79.0" + "@salutejs/sdds-themes": "0.79.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", @@ -86881,7 +86905,8 @@ "license": "MIT", "dependencies": { "@salutejs-ds/sdds_sbcom": "0.1.20", - "@salutejs/plasma-new-hope": "0.378.0" + "@salutejs/plasma-new-hope": "0.378.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", diff --git a/packages/plasma-new-hope/package.json b/packages/plasma-new-hope/package.json index 19b56f01f72..be0650615bb 100644 --- a/packages/plasma-new-hope/package.json +++ b/packages/plasma-new-hope/package.json @@ -23,6 +23,11 @@ "require": "./dist/css/cjs/index.js", "types": "./types/index.d.ts" }, + "./beta": { + "import": "./dist/beta/es/index.js", + "require": "./dist/beta/cjs/index.js", + "types": "./dist/beta/types/components/_beta/index.d.ts" + }, "./types/*": "./types/*" }, "files": ["dist", "types"], @@ -31,20 +36,21 @@ }, "scripts": { "prepare": "npm run build", - "build": "npm run build:css && npm run build:styled-components && npm run build:emotion", + "build": "npm run build:css && npm run build:beta && npm run build:styled-components && npm run build:emotion", "postbuild": "npm run generate:typings", "build:styled-components": "rm -rf dist/styled-components && npm run build:styled-components:esm && npm run build:styled-components:cjs", - "build:styled-components:cjs": "swc ./src -d ./dist/styled-components/cjs --strip-leading-paths --ignore '**/examples/**' --config-file ./swc-sc.config.json -C module.type=commonjs", - "build:styled-components:esm": "swc ./src -d ./dist/styled-components/es --strip-leading-paths --ignore '**/examples/**' --config-file ./swc-sc.config.json -C module.type=es6", + "build:styled-components:cjs": "swc ./src -d ./dist/styled-components/cjs --strip-leading-paths --ignore '**/examples/**,**/components/_beta/**' --config-file ./swc-sc.config.json -C module.type=commonjs", + "build:styled-components:esm": "swc ./src -d ./dist/styled-components/es --strip-leading-paths --ignore '**/examples/**,**/components/_beta/**' --config-file ./swc-sc.config.json -C module.type=es6", "prebuild:emotion": "rm -rf src-emotion && cp -R src src-emotion && node ./scripts/replaceImports.mjs --mode emotion", "build:emotion": "rm -rf dist/emotion && npm run build:emotion:esm && npm run build:emotion:cjs", - "build:emotion:cjs": "swc ./src-emotion -d ./dist/emotion/cjs --strip-leading-paths --ignore '**/examples/**' --config-file ./swc-emotion.config.json -C module.type=commonjs", - "build:emotion:esm": "swc ./src-emotion -d ./dist/emotion/es --strip-leading-paths --ignore '**/examples/**' --config-file ./swc-emotion.config.json -C module.type=es6", + "build:emotion:cjs": "swc ./src-emotion -d ./dist/emotion/cjs --strip-leading-paths --ignore '**/examples/**,**/components/_beta/**' --config-file ./swc-emotion.config.json -C module.type=commonjs", + "build:emotion:esm": "swc ./src-emotion -d ./dist/emotion/es --strip-leading-paths --ignore '**/examples/**,**/components/_beta/**' --config-file ./swc-emotion.config.json -C module.type=es6", "postbuild:emotion": "rm -rf src-emotion", "prebuild:css": "rm -rf src-css && cp -R src src-css && node ./scripts/replaceImports.mjs --mode css", "build:css": "rm -rf dist/css && rollup -c", "postbuild:css": "rm -rf src-css", - "generate:typings": "rm -rf types && tsc && tsc-alias", + "build:beta": "rm -rf dist/beta && rollup -c rollup.beta.config.mjs", + "generate:typings": "tsc && tsc-alias && tsc -p src/components/_beta/tsconfig.json", "storybook": "storybook dev -p ${PORT:-7002} -c .storybook", "storybook:ai-components": "USE_AI_COMPONENTS=true storybook dev -p ${PORT:-7002} -c .storybook", "storybook:build": "storybook build -c .storybook -o build-sb", diff --git a/packages/plasma-new-hope/rollup.beta.config.mjs b/packages/plasma-new-hope/rollup.beta.config.mjs new file mode 100644 index 00000000000..d4bdc7e8186 --- /dev/null +++ b/packages/plasma-new-hope/rollup.beta.config.mjs @@ -0,0 +1,106 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { babel } from '@rollup/plugin-babel'; +import styles from '@ironkinoko/rollup-plugin-styles'; + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); +const sourceDir = path.resolve(dirname, 'src'); +const betaSourceDir = path.join(sourceDir, 'components/_beta'); +const extractedCssModules = new Map(); + +export default { + input: { + index: path.join(betaSourceDir, 'index.ts'), + }, + treeshake: { + propertyReadSideEffects: false, + }, + output: [ + { + preserveModules: true, + dir: 'dist/beta/es', + format: 'es', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + }, + { + preserveModules: true, + dir: 'dist/beta/cjs', + format: 'cjs', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + interop: 'auto', + }, + ], + external: (id) => { + if (id.startsWith('regenerator-runtime') || id === 'tslib') { + return false; + } + return !id.startsWith('.') && !path.isAbsolute(id); + }, + plugins: [ + nodeResolve({ + extensions: ['.tsx', '.ts'], + }), + styles({ + mode: 'extract', + modules: true, + onExtract({ name, css }) { + if (name.endsWith('.module.css.css')) { + extractedCssModules.set(name, css); + } + + return false; + }, + }), + emitCssModulesPlugin(), + babel({ + babelHelpers: 'bundled', + extensions: ['.ts', '.tsx'], + }), + ], +}; + +function emitCssModulesPlugin() { + return { + name: 'emitCssModulesPlugin', + generateBundle: { + order: 'post', + handler(options, bundle) { + Object.values(bundle).forEach((file) => { + if (file.type !== 'chunk' || !file.fileName.endsWith('.module.css.js')) { + return; + } + + const extractedName = file.fileName.replace(/\.js$/, '.css'); + const css = extractedCssModules.get(extractedName); + + if (css === undefined) { + this.error(`Processed CSS Module was not found for ${file.fileName}`); + } + + const cssFileName = file.fileName.replace(/\.module\.css\.js$/, '.css'); + const relativeCssPath = `./${path.posix.relative(path.posix.dirname(file.fileName), cssFileName)}`; + const importCss = + options.format === 'cjs' + ? `require('${relativeCssPath}');\n` + : `import '${relativeCssPath}';\n`; + + file.code = importCss + file.code; + + this.emitFile({ + type: 'asset', + fileName: cssFileName, + source: css, + }); + }); + }, + }, + }; +} diff --git a/packages/plasma-new-hope/src/components/Tour/Tour.tsx b/packages/plasma-new-hope/src/components/Tour/Tour.tsx index 0c9c410edda..1ac99f51eef 100644 --- a/packages/plasma-new-hope/src/components/Tour/Tour.tsx +++ b/packages/plasma-new-hope/src/components/Tour/Tour.tsx @@ -4,9 +4,7 @@ import { useFloating, offset, flip, shift, autoUpdate, arrow, FloatingArrow, Pla import { RootProps } from 'src/engines'; import { canUseDOM, safeUseId } from 'src/utils'; -import { ARROW_HEIGHT, ARROW_PADDING, ARROW_POLYGON, ARROW_WIDTH } from '../_beta/Popover/Popover'; - -import { getHTMLElement } from './utils'; +import { ARROW_HEIGHT, ARROW_PADDING, ARROW_POLYGON, ARROW_WIDTH, getHTMLElement } from './utils'; import type { TourProps, RootTourProps } from './Tour.types'; import { MaskContainer, Mask, Highlight, TourPortal } from './Tour.styles'; import { base as viewCSS } from './variatoins/_view/base'; diff --git a/packages/plasma-new-hope/src/components/Tour/utils/index.ts b/packages/plasma-new-hope/src/components/Tour/utils/index.ts index 85f4429ceb2..b8afbad9cc2 100644 --- a/packages/plasma-new-hope/src/components/Tour/utils/index.ts +++ b/packages/plasma-new-hope/src/components/Tour/utils/index.ts @@ -1,4 +1,13 @@ -import { canUseDOM } from 'src/utils'; +import { canUseDOM } from '../../../utils/canUseDOM'; + +/* Ширина хвостика */ +export const ARROW_WIDTH = 20; +/* Высота хвостика */ +export const ARROW_HEIGHT = 8; +/* SVG хвостика */ +export const ARROW_POLYGON = 'M20 20L0 20C8.88889 20.0001 10 12.5714 10 12C10 12.5714 11.3273 20.006 20 20Z'; +/* Отступ хвостика по краям (чтобы избежать коллизии со скругленными углами) */ +export const ARROW_PADDING = 16; export const getHTMLElement = ( target: string | React.RefObject | HTMLElement, diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.module.css b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.module.css new file mode 100644 index 00000000000..841f5a92624 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.module.css @@ -0,0 +1,153 @@ +.root { + position: relative; + display: block; + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 0; + border: none; + border-radius: var(--plasma-embedded-button-border-radius); + appearance: none; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + background: var(--plasma-embedded-button-background-color); + box-shadow: inset 0 0 0 0.063rem var(--plasma-embedded-button-border-color, transparent); + --plasma_private-focus-border-radius: var(--plasma-embedded-button-border-radius); + --plasma_private-focus-outline-size: 0.0625rem; + --plasma_private-focus-outline-offset: 0.125rem; + --plasma_private-focus-outline-color: var(--plasma-embedded-button-focus-color); +} + +a.root { + text-decoration: none; +} + +.loadWrap { + display: grid; + width: 100%; + height: 100%; + opacity: 1; +} + +.loadWrap[data-loading='true'] { + opacity: var(--plasma-embedded-button-loading-icon-opacity); +} + +.loadWrap[data-position='center'], +.loadWrap[data-position='center-left'], +.loadWrap[data-position='center-right'] { + align-items: center; +} + +.loadWrap[data-position='top'], +.loadWrap[data-position='top-left'], +.loadWrap[data-position='top-right'] { + align-items: start; +} + +.loadWrap[data-position='bottom'], +.loadWrap[data-position='bottom-left'], +.loadWrap[data-position='bottom-right'] { + align-items: end; +} + +.loadWrap[data-position='center'], +.loadWrap[data-position='top'], +.loadWrap[data-position='bottom'] { + justify-items: center; +} + +.loadWrap[data-position='center-left'], +.loadWrap[data-position='top-left'], +.loadWrap[data-position='bottom-left'] { + justify-items: start; +} + +.loadWrap[data-position='center-right'], +.loadWrap[data-position='top-right'], +.loadWrap[data-position='bottom-right'] { + justify-items: end; +} + +.iconContainer { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + color: var(--plasma-embedded-button-color); +} + +.loader { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; +} + +.spinner { + display: inline-flex; + width: var(--plasma-embedded-button-spinner-size); + height: var(--plasma-embedded-button-spinner-size); + color: var(--plasma-embedded-button-spinner-color); + animation: embedded-button-spinner-rotate 1s linear infinite; +} + +.spinner svg { + width: 100%; + height: 100%; +} + +@keyframes embedded-button-spinner-rotate { + from { + transform: rotate(0); + } + + to { + transform: rotate(360deg); + } +} + +@media (hover: hover) and (pointer: fine) { + .root:hover { + background: var( + --plasma-embedded-button-background-color-hover, + var(--plasma-embedded-button-background-color) + ); + box-shadow: inset 0 0 0 0.063rem var(--plasma-embedded-button-border-color-hover, transparent); + } + + .root:hover .iconContainer { + color: var(--plasma-embedded-button-color-hover); + } +} + +.root:active { + background: var( + --plasma-embedded-button-background-color-active, + var(--plasma-embedded-button-background-color) + ); + box-shadow: inset 0 0 0 0.063rem var(--plasma-embedded-button-border-color-active, transparent); +} + +.root:active .iconContainer { + color: var(--plasma-embedded-button-color-active); +} + +.root:disabled { + opacity: var(--plasma-embedded-button-disabled-opacity); + cursor: not-allowed; +} + +@media (hover: hover) and (pointer: fine) { + .root:disabled:hover, + .root:disabled:active { + background: var(--plasma-embedded-button-background-color); + box-shadow: inset 0 0 0 0.063rem var(--plasma-embedded-button-border-color, transparent); + } + + .root:disabled:hover .iconContainer, + .root:disabled:active .iconContainer { + color: var(--plasma-embedded-button-color); + } +} diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.styles.ts b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.styles.ts deleted file mode 100644 index 8a1ce4d474e..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.styles.ts +++ /dev/null @@ -1,95 +0,0 @@ -import styled, { css } from 'styled-components'; -import { addFocus } from 'src/mixins'; -import { component, mergeConfig } from 'src/engines'; - -import { spinnerConfig, spinnerTokens } from '../../Spinner'; - -import type { IconPosition } from './EmbeddedButton.types'; -import { tokens } from './EmbeddedButton.tokens'; - -const mergedConfig = mergeConfig(spinnerConfig); -const Spinner = component(mergedConfig); - -const positionAlignItems: Record = { - center: 'center', - 'center-left': 'center', - 'center-right': 'center', - top: 'start', - 'top-left': 'start', - 'top-right': 'start', - bottom: 'end', - 'bottom-left': 'end', - 'bottom-right': 'end', -}; - -const positionJustifyItems: Record = { - center: 'center', - 'center-left': 'start', - 'center-right': 'end', - top: 'center', - 'top-left': 'start', - 'top-right': 'end', - bottom: 'center', - 'bottom-left': 'start', - 'bottom-right': 'end', -}; - -export const LoadWrap = styled.div<{ position: IconPosition; isLoading?: boolean }>` - opacity: ${({ isLoading }) => (isLoading ? `var(${tokens.loadingIconOpacity})` : '1')}; - display: grid; - width: 100%; - height: 100%; - align-items: ${({ position }) => positionAlignItems[position]}; - justify-items: ${({ position }) => positionJustifyItems[position]}; -`; - -export const IconContainer = styled.div` - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; -`; - -export const Loader = styled.div` - position: absolute; - inset: 0; - display: flex; - align-items: center; - justify-content: center; -`; - -export const StyledSpinner = styled(Spinner)` - ${spinnerTokens.size}: var(${tokens.spinnerSize}); - ${spinnerTokens.color}: var(${tokens.spinnerColor}); -`; - -export const base = css` - position: relative; - display: block; - width: 100%; - height: 100%; - border-radius: var(${tokens.borderRadius}); - box-sizing: border-box; - - appearance: none; - border: none; - cursor: pointer; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - background: transparent; - padding: 0; - - a& { - text-decoration: none; - } - - :focus-visible { - outline: none; - } - - ${addFocus({ - outlineOffset: '0.125rem', - outlineSize: '0.0625rem', - outlineRadius: `var(${tokens.borderRadius})`, - outlineColor: `var(${tokens.focusColor})`, - })} -`; diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.tsx b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.tsx index 0e981d4ccfe..a4195d1c275 100644 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.tsx +++ b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.tsx @@ -1,58 +1,48 @@ import React, { forwardRef } from 'react'; +import cls from 'classnames'; -import type { RootProps } from '../../../engines'; -import { cx } from '../../../utils'; +import addFocusMixin from '../mixins/addFocus.module.css'; -import { base as viewCSS } from './variations/_view/base'; -import { base as sizeCSS } from './variations/_size/base'; -import { base as disabledCSS } from './variations/_disabled/base'; import type { EmbeddedButtonProps } from './EmbeddedButton.types'; -import { base, IconContainer, Loader, LoadWrap, StyledSpinner } from './EmbeddedButton.styles'; import { classes } from './EmbeddedButton.tokens'; +import styles from './EmbeddedButton.module.css'; -export const embeddedButtonRoot = (Root: RootProps) => - forwardRef((props, ref) => { - const { children, view, size, disabled, isLoading, loader, position = 'center', className, ...rest } = props; +const Spinner = () => ( + +); - const isLoadingClass = isLoading ? classes.embeddedButtonLoading : undefined; +export const EmbeddedButton = forwardRef((props, ref) => { + const { + children, + isLoading, + loader, + position = 'center', + as, + forwardedAs, + // @ts-ignore + _configClassName, + ...rest + } = props; - return ( - - - {children} - - {isLoading && {loader || }} - - ); - }); + const Root = (as ?? forwardedAs ?? 'button') as React.ElementType; + const isLoadingClass = isLoading ? classes.embeddedButtonLoading : undefined; -export const embeddedButtonConfig = { - name: 'EmbeddedButton', - tag: 'button', - layout: embeddedButtonRoot, - base, - variations: { - view: { - css: viewCSS, - }, - size: { - css: sizeCSS, - }, - disabled: { - css: disabledCSS, - attrs: true, - }, - }, - defaults: { - view: 'secondary', - size: 'm', - }, -}; + return ( + +
+
{children}
+
+ {isLoading &&
{loader || }
} +
+ ); +}); diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.types.ts b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.types.ts index 32725fb7114..0833250b1ff 100644 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.types.ts +++ b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/EmbeddedButton.types.ts @@ -1,8 +1,11 @@ -import type { ButtonHTMLAttributes, ReactNode } from 'react'; +import type { ButtonHTMLAttributes, ComponentType, ReactNode } from 'react'; -import type { AsProps } from '../../../types'; +type AsProps = { + as?: keyof JSX.IntrinsicElements | ComponentType; + forwardedAs?: keyof JSX.IntrinsicElements | ComponentType; +}; -export type IconPosition = +type IconPosition = | 'center' | 'center-left' | 'center-right' @@ -19,14 +22,6 @@ export type EmbeddedButtonProps = ButtonHTMLAttributes & * Иконка кнопки */ children?: ReactNode; - /** - * Вид кнопки - */ - view?: string; - /** - * Размер контейнера иконки - */ - size?: string; /** * Кнопка неактивна */ diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/index.ts b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/index.ts index 4d10ffc0789..c63c4a7cdc6 100644 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/index.ts +++ b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/index.ts @@ -1,9 +1,2 @@ -export { - embeddedButtonRoot as _beta_embeddedButtonRoot, - embeddedButtonConfig as _beta_embeddedButtonConfig, -} from './EmbeddedButton'; -export type { - EmbeddedButtonProps as _beta_EmbeddedButtonProps, - IconPosition as _beta_IconPosition, -} from './EmbeddedButton.types'; -export { tokens as _beta_embeddedButtonTokens, classes as _beta_embeddedButtonClasses } from './EmbeddedButton.tokens'; +export { EmbeddedButton } from './EmbeddedButton'; +export type { EmbeddedButtonProps } from './EmbeddedButton.types'; diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_disabled/base.ts b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_disabled/base.ts deleted file mode 100644 index 9ef669dfe34..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_disabled/base.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { css } from 'styled-components'; - -import { tokens } from '../../EmbeddedButton.tokens'; -import { IconContainer } from '../../EmbeddedButton.styles'; - -export const base = css` - &[disabled] { - opacity: var(${tokens.disabledOpacity}); - cursor: not-allowed; - - @media (hover: hover) and (pointer: fine) { - :hover, - :active { - background: var(${tokens.backgroundColor}); - box-shadow: inset 0 0 0 0.063rem var(${tokens.borderColor}, inset 0 0 0 0 transparent); - - ${IconContainer} { - color: var(${tokens.color}); - } - } - } - } -`; diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_disabled/tokens.json b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_disabled/tokens.json deleted file mode 100644 index 77c8eac0742..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_disabled/tokens.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "boolean", - "tokens": ["--plasma-embedded-button-disabled-opacity"] -} diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_size/base.ts b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_size/base.ts deleted file mode 100644 index f259885d4ce..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_size/base.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { css } from 'styled-components'; - -export const base = css``; diff --git a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_view/base.ts b/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_view/base.ts deleted file mode 100644 index 5687ce81e7e..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/EmbeddedButton/variations/_view/base.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { css } from 'styled-components'; - -import { tokens } from '../../EmbeddedButton.tokens'; -import { IconContainer } from '../../EmbeddedButton.styles'; - -export const base = css` - background: var(${tokens.backgroundColor}); - box-shadow: inset 0 0 0 0.063rem var(${tokens.borderColor}, inset 0 0 0 0 transparent); - - ${IconContainer} { - color: var(${tokens.color}); - } - - @media (hover: hover) and (pointer: fine) { - :hover { - background: var(${tokens.backgroundColorHover}, var(${tokens.backgroundColor})); - box-shadow: inset 0 0 0 0.063rem var(${tokens.borderColorHover}, inset 0 0 0 0 transparent); - - ${IconContainer} { - color: var(${tokens.colorHover}); - } - } - } - - :active { - background: var(${tokens.backgroundColorActive}, var(${tokens.backgroundColor})); - box-shadow: inset 0 0 0 0.063rem var(${tokens.borderColorActive}, inset 0 0 0 0 transparent); - - ${IconContainer} { - color: var(${tokens.colorActive}); - } - } -`; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/Popover.module.css b/packages/plasma-new-hope/src/components/_beta/Popover/Popover.module.css new file mode 100644 index 00000000000..c999cc02270 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/Popover/Popover.module.css @@ -0,0 +1,116 @@ +.root { + border-radius: var(--plasma-popover-border-radius); + outline: none; + --plasma_private-focus-border-radius: var(--plasma-popover-border-radius); + --plasma_private-focus-outline-offset: -0.125rem; +} + +.wrapper { + position: relative; + width: 100%; + height: 100%; + box-sizing: border-box; + padding: var(--plasma-popover-padding); + border-radius: var(--plasma-popover-border-radius); + background: var(--plasma-popover-background-color); + box-shadow: var(--plasma-popover-box-shadow); + filter: var(--plasma-popover-drop-shadow, none); +} + +.closeButton { + position: absolute; + top: var(--plasma-popover-icon-offset); + right: var(--plasma-popover-icon-offset); + padding: 0; + margin: 0; + border: none; + background: none; + cursor: pointer; + line-height: 0; + color: var(--plasma-popover-icon-color); + + --plasma_private-focus-outline-offset: 0.125rem; +} + +.closeButton:hover { + color: var(--plasma-popover-icon-color-hover); +} + +.closeButton:active { + color: var(--plasma-popover-icon-color-active); +} + +.closeIcon { + display: inline-flex; + width: var(--plasma-popover-close-icon-size, 1.5rem); + height: var(--plasma-popover-close-icon-size, 1.5rem); + flex: 0 0 var(--plasma-popover-close-icon-size, 1.5rem); +} + +.tail { + position: absolute; + pointer-events: none; +} + +.tail[data-side='top'], +.tail[data-side='bottom'] { + width: var(--plasma-popover-tail-width); + height: var(--plasma-popover-tail-height); +} + +.tail[data-side='left'], +.tail[data-side='right'] { + width: var(--plasma-popover-tail-height); + height: var(--plasma-popover-tail-width); +} + +.tail[data-side='top'] { + top: 100%; +} + +.tail[data-side='right'] { + right: 100%; +} + +.tail[data-side='bottom'] { + bottom: 100%; +} + +.tail[data-side='left'] { + left: 100%; +} + +.tail::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: var(--plasma-popover-tail-width); + height: var(--plasma-popover-tail-height); + background: var(--plasma-popover-background-color); + clip-path: shape( + from 100% 100%, + line to 0% 100%, + curve to 50% 0% with calc(25% - var(--plasma-popover-tail-side-curvature) * 1.24939) + calc(50% - var(--plasma-popover-tail-side-curvature) * 3.90435), + curve to 100% 100% with calc(75% + var(--plasma-popover-tail-side-curvature) * 1.24939) + calc(50% - var(--plasma-popover-tail-side-curvature) * 3.90435), + close + ); +} + +.tail[data-side='top']::before { + transform: translate(-50%, -50%) rotate(180deg); +} + +.tail[data-side='right']::before { + transform: translate(-50%, -50%) rotate(-90deg); +} + +.tail[data-side='bottom']::before { + transform: translate(-50%, -50%); +} + +.tail[data-side='left']::before { + transform: translate(-50%, -50%) rotate(90deg); +} diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/Popover.styles.ts b/packages/plasma-new-hope/src/components/_beta/Popover/Popover.styles.ts deleted file mode 100644 index 7debad8256e..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/Popover/Popover.styles.ts +++ /dev/null @@ -1,82 +0,0 @@ -import styled, { css } from 'styled-components'; - -import { tokens } from './Popover.tokens'; - -export const base = css` - border-radius: var(${tokens.borderRadius}); - outline: none; -`; - -export const Wrapper = styled.div` - position: relative; - background: var(${tokens.backgroundColor}); - padding: var(${tokens.padding}); - border-radius: var(${tokens.borderRadius}); - box-shadow: var(${tokens.boxShadow}); - filter: var(${tokens.dropShadow}, none); - width: 100%; - height: 100%; - box-sizing: border-box; -`; - -export const CloseButton = styled.button` - position: absolute; - top: var(${tokens.iconOffset}); - right: var(${tokens.iconOffset}); - padding: 0; - margin: 0; - border: none; - background: none; - cursor: pointer; - line-height: 0; - color: var(${tokens.iconColor}); - - &:hover { - color: var(${tokens.iconColorHover}); - } - - &:active { - color: var(${tokens.iconColorActive}); - } -`; - -export const Tail = styled.div<{ side: 'top' | 'right' | 'bottom' | 'left' }>` - position: absolute; - pointer-events: none; - width: ${({ side }) => - side === 'left' || side === 'right' ? `var(${tokens.tailHeight})` : `var(${tokens.tailWidth})`}; - height: ${({ side }) => - side === 'left' || side === 'right' ? `var(${tokens.tailWidth})` : `var(${tokens.tailHeight})`}; - - top: ${({ side }) => (side === 'top' ? '100%' : 'auto')}; - right: ${({ side }) => (side === 'right' ? '100%' : 'auto')}; - bottom: ${({ side }) => (side === 'bottom' ? '100%' : 'auto')}; - left: ${({ side }) => (side === 'left' ? '100%' : 'auto')}; - - &::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: var(${tokens.tailWidth}); - height: var(${tokens.tailHeight}); - background: var(${tokens.backgroundColor}); - transform: translate(-50%, -50%) - ${({ side }) => - ({ - top: 'rotate(180deg)', - right: 'rotate(-90deg)', - bottom: 'rotate(0deg)', - left: 'rotate(90deg)', - }[side])}; - clip-path: shape( - from 100% 100%, - line to 0% 100%, - curve to 50% 0% with calc(25% - var(${tokens.tailSideCurvature}) * 1.24939) - calc(50% - var(${tokens.tailSideCurvature}) * 3.90435), - curve to 100% 100% with calc(75% + var(${tokens.tailSideCurvature}) * 1.24939) - calc(50% - var(${tokens.tailSideCurvature}) * 3.90435), - close - ); - } -`; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/Popover.tsx b/packages/plasma-new-hope/src/components/_beta/Popover/Popover.tsx index e0127a066ca..3ea6b700510 100644 --- a/packages/plasma-new-hope/src/components/_beta/Popover/Popover.tsx +++ b/packages/plasma-new-hope/src/components/_beta/Popover/Popover.tsx @@ -1,5 +1,4 @@ import React, { forwardRef, useState, useRef } from 'react'; -import type { RootProps } from 'src/engines/types'; import cls from 'classnames'; import { useFloating, @@ -19,206 +18,182 @@ import { autoUpdate, limitShift, } from '@floating-ui/react'; -import { css } from 'styled-components'; -import { IconClose } from '../../_Icon'; -import { Resizable } from '../../_Resizable'; -import { Slot } from '../../_Slot/Slot'; +import addFocusMixin from '../mixins/addFocus.module.css'; +import { Slot } from '../utils/Slot'; -import { sizeToIconSize, matchPlacements, getFloatingPortalProps, useTailStyle } from './utils'; +import { Resizable } from './Resizable'; +import { ARROW_PADDING, matchPlacements, getFloatingPortalProps, useTailStyle } from './utils'; import { classes } from './Popover.tokens'; -import { base, CloseButton, Wrapper, Tail } from './Popover.styles'; import type { PopoverProps } from './Popover.types'; - -/* Ширина хвостика */ -export const ARROW_WIDTH = 20; -/* Высота хвостика */ -export const ARROW_HEIGHT = 8; -/* SVG хвостика */ -export const ARROW_POLYGON = 'M20 20L0 20C8.88889 20.0001 10 12.5714 10 12C10 12.5714 11.3273 20.006 20 20Z'; -/* Отступ хвостика по краям (чтобы избежать коллизии со скругленными углами) */ -export const ARROW_PADDING = 16; - -export const popoverRoot = (Root: RootProps>) => - forwardRef( - ( - { - appearance = 'closeNone', - children, - target, - opened: outerOpened, - defaultOpened = false, - trigger = 'click', - placement = 'bottom', - hasTail = true, - flip: outsideFlip = false, - shift: outsideShift = false, - offset: outerOffset = 0, - outsideClick = true, - resizable = false, - onResizeStart, - onResizeEnd, - onToggle, - delayOpen = 0, - delayClose = 0, - zIndex = 1000, - className, - style, - size, - view, - portal, - ...rest - }, - outerRootRef, - ) => { - const [innerOpened, setInnerOpened] = useState(defaultOpened); - - const opened = outerOpened ?? innerOpened; - - const arrowRef = useRef(null); - - const handleToggle = (opened: boolean) => { - setInnerOpened(opened); - - if (onToggle) { - onToggle(opened); - } - }; - - const { - refs, - floatingStyles, - context, - middlewareData, - placement: calculatedPlacement, - isPositioned, - } = useFloating({ - whileElementsMounted: autoUpdate, - placement, - open: opened, - onOpenChange: handleToggle, - middleware: [ - outsideShift && - shift({ - limiter: limitShift(), - }), - outsideFlip && flip(), - hasTail && arrow({ element: arrowRef, padding: ARROW_PADDING }), - offset( - ({ placement: currentPlacement }) => { - if (!hasTail) { - return outerOffset; - } - - const side = currentPlacement.split('-')[0]; - const { width = 0, height = 0 } = arrowRef.current?.getBoundingClientRect() ?? {}; - const tailOffset = side === 'top' || side === 'bottom' ? height : width; - - return tailOffset + outerOffset; - }, - [outerOffset, hasTail], - ), - ], - }); - - const click = useClick(context, { - enabled: trigger === 'click' || matchMedia('(hover: none)').matches, - }); - const focus = useFocus(context, { enabled: trigger === 'focus' }); - const dismiss = useDismiss(context, { - enabled: true, - outsidePress: outsideClick, - }); - const role = useRole(context); - const hover = useHover(context, { - mouseOnly: true, - enabled: trigger === 'hover', - handleClose: safePolygon({ - requireIntent: false, - }), - delay: { - open: delayOpen, - close: delayClose, - }, - }); - - const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, role, click, hover, focus]); - - const { side, tailStyle } = useTailStyle(calculatedPlacement, middlewareData, ARROW_PADDING); - - return ( - <> - - {target} - - - {opened && ( - - - - - - {hasTail && ( - - - - - - )} - - ); +import styles from './Popover.module.css'; + +const CloseIcon = () => ( + +); + +export const Popover = forwardRef((props, ref) => { + const { + appearance = 'default', + children, + target, + opened: outerOpened, + defaultOpened = false, + trigger = 'click', + placement = 'bottom', + hasTail = true, + flip: outsideFlip = false, + shift: outsideShift = false, + offset: outerOffset = 0, + outsideClick = true, + resizable = false, + onResizeStart, + onResizeEnd, + onToggle, + delayOpen = 0, + delayClose = 0, + zIndex = 1000, + portal, + // @ts-ignore + _configClassName, + ...rest + } = props; + + const [innerOpened, setInnerOpened] = useState(defaultOpened); + + const opened = outerOpened ?? innerOpened; + + const arrowRef = useRef(null); + + const handleToggle = (nextOpened: boolean) => { + setInnerOpened(nextOpened); + + if (onToggle) { + onToggle(nextOpened); + } + }; + + const { refs, floatingStyles, context, middlewareData, placement: calculatedPlacement, isPositioned } = useFloating( + { + whileElementsMounted: autoUpdate, + placement, + open: opened, + onOpenChange: handleToggle, + middleware: [ + outsideShift && + shift({ + limiter: limitShift(), + }), + outsideFlip && flip(), + hasTail && arrow({ element: arrowRef, padding: ARROW_PADDING }), + offset( + ({ placement: currentPlacement }) => { + if (!hasTail) { + return outerOffset; + } + + const side = currentPlacement.split('-')[0]; + const { width = 0, height = 0 } = arrowRef.current?.getBoundingClientRect() ?? {}; + const tailOffset = side === 'top' || side === 'bottom' ? height : width; + + return tailOffset + outerOffset; + }, + [outerOffset, hasTail], + ), + ], }, ); -export const popoverConfig = { - name: 'Popover', - tag: 'div', - layout: popoverRoot, - base, - variations: { - view: { - css: css``, - }, - size: { - css: css``, + const click = useClick(context, { + enabled: trigger === 'click' || matchMedia('(hover: none)').matches, + }); + const focus = useFocus(context, { enabled: trigger === 'focus' }); + const dismiss = useDismiss(context, { + enabled: true, + outsidePress: outsideClick, + }); + const role = useRole(context); + const hover = useHover(context, { + mouseOnly: true, + enabled: trigger === 'hover', + handleClose: safePolygon({ + requireIntent: false, + }), + delay: { + open: delayOpen, + close: delayClose, }, - }, - defaults: { - view: 'default', - size: 'm', - }, -}; + }); + + const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, role, click, hover, focus]); + + const { side, tailStyle } = useTailStyle(calculatedPlacement, middlewareData, ARROW_PADDING); + + return ( + <> + + {target} + + + {opened && ( + + +
+ +
+ {hasTail && ( + + +
+ + + )} + + ); +}); diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/Popover.types.ts b/packages/plasma-new-hope/src/components/_beta/Popover/Popover.types.ts index 2d4aef39013..c05c67045af 100644 --- a/packages/plasma-new-hope/src/components/_beta/Popover/Popover.types.ts +++ b/packages/plasma-new-hope/src/components/_beta/Popover/Popover.types.ts @@ -1,6 +1,6 @@ import type { HTMLAttributes, ReactNode, ReactElement } from 'react'; -import { ResizableProps } from '../../_Resizable'; +import type { ResizableProps } from './Resizable.types'; export type Placement = | 'top' @@ -20,9 +20,9 @@ export type BasicPopoverProps = { /** * Стиль для UI конфигурации * Влияет на выбор предустановленного набора токенов - * @default closeNone + * @default default */ - appearance?: 'closeNone' | 'closeInner'; + appearance?: 'default' | 'closeInner'; /** * Контент всплывающего окна. */ @@ -115,15 +115,6 @@ export type BasicPopoverProps = { * @default Без использования portal всплывающее окно рендерится перед . */ portal?: string | React.RefObject; - - /** - * Вид компонента. - */ - view?: string; - /** - * Размер компонента. - */ - size?: string; }; export type PopoverProps = HTMLAttributes & BasicPopoverProps; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.module.css b/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.module.css new file mode 100644 index 00000000000..c0cff1935cf --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.module.css @@ -0,0 +1,48 @@ +.containerNoSelect { + user-select: none; + -webkit-user-select: none; +} + +.resizeIcon { + display: inline-flex; + width: 1.5rem; + height: 1.5rem; + flex: 0 0 1.5rem; + color: var(--text-secondary); +} + +.resizeIcon[data-size='xs'] { + width: 1rem; + height: 1rem; + flex-basis: 1rem; +} + +.resizeIcon[data-size='m'] { + width: 2.25rem; + height: 2.25rem; + flex-basis: 2.25rem; +} + +.resizeIcon:hover { + color: var(--text-secondary-hover); +} + +.resizeIcon:active { + color: var(--text-secondary-active); +} + +.topRightIcon { + transform: rotate(-90deg); +} + +.bottomRightIcon { + transform: rotate(0); +} + +.bottomLeftIcon { + transform: rotate(90deg); +} + +.topLeftIcon { + transform: rotate(180deg); +} diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.tsx b/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.tsx new file mode 100644 index 00000000000..d06a2fecf1b --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.tsx @@ -0,0 +1,195 @@ +import React, { useRef } from 'react'; +import type { FC, PropsWithChildren } from 'react'; +import cls from 'classnames'; +import { Resizable as ReResizable } from 're-resizable'; +import type { Resizable as ResizableInstance } from 're-resizable'; + +import type { ResizableOptions, ResizablePlacement, ResizableProps, ResizeDirections } from './Resizable.types'; +import styles from './Resizable.module.css'; + +const publicClasses = { + container: 'resizable-container', + topRightIcon: 'resizable-top-right-icon', + bottomRightIcon: 'resizable-bottom-right-icon', + bottomLeftIcon: 'resizable-bottom-left-icon', + topLeftIcon: 'resizable-top-left-icon', + handleWrapper: 'resizable-handle-wrapper', + containerNoSelect: 'resizable-container-no-select', +}; + +const getResizeDirections = (directions?: ResizeDirections) => { + if (!directions) { + return { + top: true, + right: true, + bottom: true, + left: true, + topRight: true, + bottomRight: true, + bottomLeft: true, + topLeft: true, + }; + } + + return { + top: directions.includes('top'), + right: directions.includes('right'), + bottom: directions.includes('bottom'), + left: directions.includes('left'), + topRight: directions.includes('top-right'), + bottomRight: directions.includes('bottom-right'), + bottomLeft: directions.includes('bottom-left'), + topLeft: directions.includes('top-left'), + }; +}; + +const getResizeRatio = (placement?: ResizablePlacement): [number, number] => { + if (placement === 'center') { + return [2, 2]; + } + + if (placement === 'top' || placement === 'bottom') { + return [2, 1]; + } + + if (placement === 'left' || placement === 'right') { + return [1, 2]; + } + + return [1, 1]; +}; + +const handleStyles = { + topRight: { + width: 'auto', + height: 'auto', + lineHeight: '0', + top: '0', + right: '0', + transform: 'translate(50%, -50%)', + }, + bottomRight: { + width: 'auto', + height: 'auto', + lineHeight: '0', + right: '0', + bottom: '0', + transform: 'translate(50%, 50%)', + }, + bottomLeft: { + width: 'auto', + height: 'auto', + lineHeight: '0', + bottom: '0', + left: '0', + transform: 'translate(-50%, 50%)', + }, + topLeft: { + width: 'auto', + height: 'auto', + lineHeight: '0', + top: '0', + left: '0', + transform: 'translate(-50%, -50%)', + }, +}; + +type ResizeIconProps = { + position: 'topRight' | 'bottomRight' | 'bottomLeft' | 'topLeft'; + size?: 'xs' | 's' | 'm'; +}; + +const iconClasses = { + topRight: [styles.topRightIcon, publicClasses.topRightIcon], + bottomRight: [styles.bottomRightIcon, publicClasses.bottomRightIcon], + bottomLeft: [styles.bottomLeftIcon, publicClasses.bottomLeftIcon], + topLeft: [styles.topLeftIcon, publicClasses.topLeftIcon], +}; + +const ResizeIcon = ({ position, size = 's' }: ResizeIconProps) => ( + +); + +export const Resizable: FC> = ({ + children, + resizable: outerResizable, + placement, + onResizeStart, + onResizeEnd, +}) => { + const resizableContainer = useRef(null); + const resizable = typeof outerResizable === 'boolean' ? { disabled: !outerResizable } : outerResizable; + + const toggleNoSelect = () => { + const element = resizableContainer.current?.resizable; + + element?.classList.toggle(styles.containerNoSelect); + element?.classList.toggle(publicClasses.containerNoSelect); + }; + + if (!resizable || resizable.disabled) { + return <>{children}; + } + + const getIcon = (position: ResizeIconProps['position'], options: ResizableOptions) => { + const positionName = { + topRight: 'top-right', + bottomRight: 'bottom-right', + bottomLeft: 'bottom-left', + topLeft: 'top-left', + }[position] as 'top-right' | 'bottom-right' | 'bottom-left' | 'top-left'; + + if (options.hiddenIcons?.includes(positionName)) { + return undefined; + } + + return <>{options.icons?.[position] || }; + }; + + return ( + { + toggleNoSelect(); + onResizeStart?.(resizableContainer); + }} + onResizeStop={() => { + toggleNoSelect(); + onResizeEnd?.(resizableContainer); + }} + handleComponent={{ + topRight: getIcon('topRight', resizable), + bottomRight: getIcon('bottomRight', resizable), + bottomLeft: getIcon('bottomLeft', resizable), + topLeft: getIcon('topLeft', resizable), + }} + className={publicClasses.container} + handleStyles={handleStyles} + handleWrapperClass={publicClasses.handleWrapper} + > + {children} + + ); +}; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.types.ts b/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.types.ts new file mode 100644 index 00000000000..a99eb854cd3 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/Popover/Resizable.types.ts @@ -0,0 +1,41 @@ +import type { ReactNode, RefObject } from 'react'; +import type { Resizable as ResizableInstance } from 're-resizable'; + +export type ResizablePlacement = + | 'auto' + | 'center' + | 'top' + | 'bottom' + | 'right' + | 'left' + | 'top-right' + | 'top-left' + | 'bottom-right' + | 'bottom-left'; + +export type ResizeDirections = Exclude[]; + +export type ResizableOptions = { + disabled?: boolean; + directions?: ResizeDirections; + defaultSize?: { width?: number; height?: number }; + minWidth?: number; + minHeight?: number; + maxWidth?: number; + maxHeight?: number; + icons?: { + topRight?: ReactNode; + bottomRight?: ReactNode; + bottomLeft?: ReactNode; + topLeft?: ReactNode; + }; + iconSize?: 'xs' | 's' | 'm'; + hiddenIcons?: Array<'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'>; +}; + +export type ResizableProps = { + placement?: ResizablePlacement; + resizable?: boolean | ResizableOptions; + onResizeStart?: (resizableContainer?: RefObject) => void; + onResizeEnd?: (resizableContainer?: RefObject) => void; +}; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/index.ts b/packages/plasma-new-hope/src/components/_beta/Popover/index.ts index 4f2ece79fd2..9a4a6f72855 100644 --- a/packages/plasma-new-hope/src/components/_beta/Popover/index.ts +++ b/packages/plasma-new-hope/src/components/_beta/Popover/index.ts @@ -1,4 +1,3 @@ -export { popoverRoot as _beta_popoverRoot, popoverConfig as _beta_popoverConfig } from './Popover'; -export { classes as _beta_popoverClasses, tokens as _beta_popoverTokens } from './Popover.tokens'; +export { Popover } from './Popover'; -export type { PopoverProps as _beta_PopoverProps } from './Popover.types'; +export type { BasicPopoverProps, Placement, PopoverProps } from './Popover.types'; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/utils/constants.ts b/packages/plasma-new-hope/src/components/_beta/Popover/utils/constants.ts new file mode 100644 index 00000000000..5ecb2d7d4cf --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/Popover/utils/constants.ts @@ -0,0 +1,2 @@ +/* Отступ хвостика по краям (чтобы избежать коллизии со скругленными углами) */ +export const ARROW_PADDING = 16; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/utils/index.ts b/packages/plasma-new-hope/src/components/_beta/Popover/utils/index.ts index 12fbe4dd77e..32e1fe97097 100644 --- a/packages/plasma-new-hope/src/components/_beta/Popover/utils/index.ts +++ b/packages/plasma-new-hope/src/components/_beta/Popover/utils/index.ts @@ -1,4 +1,4 @@ -export * from './sizeToIconSize'; +export * from './constants'; export * from './matchPlacements'; export * from './getFloatingPortalProps'; export * from './useTailStyle'; diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/utils/matchPlacements.ts b/packages/plasma-new-hope/src/components/_beta/Popover/utils/matchPlacements.ts index f4a50a5e642..1b32cdf205e 100644 --- a/packages/plasma-new-hope/src/components/_beta/Popover/utils/matchPlacements.ts +++ b/packages/plasma-new-hope/src/components/_beta/Popover/utils/matchPlacements.ts @@ -1,5 +1,5 @@ -import { Placement as ResizablePlacement } from '../../../_Resizable/Resizable.types'; -import { PopoverProps } from '../Popover.types'; +import type { PopoverProps } from '../Popover.types'; +import type { ResizablePlacement } from '../Resizable.types'; export const matchPlacements = (placement: PopoverProps['placement']): ResizablePlacement => { switch (placement) { diff --git a/packages/plasma-new-hope/src/components/_beta/Popover/utils/sizeToIconSize.ts b/packages/plasma-new-hope/src/components/_beta/Popover/utils/sizeToIconSize.ts deleted file mode 100644 index 4380c171e19..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/Popover/utils/sizeToIconSize.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const sizeToIconSize = (size?: string) => { - return size === 's' ? 'xs' : 's'; -}; diff --git a/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.module.css b/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.module.css new file mode 100644 index 00000000000..195841852f1 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.module.css @@ -0,0 +1,98 @@ +.root { + border-radius: var(--plasma-tooltip-border-radius); +} + +.wrapper { + display: flex; + align-items: center; + position: relative; + gap: var(--plasma-tooltip-gap); + width: 100%; + height: 100%; + box-sizing: border-box; + padding: var(--plasma-tooltip-padding); + border-radius: var(--plasma-tooltip-border-radius); + background: var(--plasma-tooltip-background-color); + box-shadow: var(--plasma-tooltip-box-shadow); + filter: var(--plasma-tooltip-drop-shadow, none); + color: var(--plasma-tooltip-color); + font-family: var(--plasma-tooltip-font-family); + font-size: var(--plasma-tooltip-font-size); + font-style: var(--plasma-tooltip-font-style); + font-weight: var(--plasma-tooltip-font-weight); + letter-spacing: var(--plasma-tooltip-letter-spacing); + line-height: var(--plasma-tooltip-lineheight); +} + +.iconWrapper { + flex: none; + line-height: 0; +} + +.tail { + position: absolute; + pointer-events: none; +} + +.tail[data-side='top'], +.tail[data-side='bottom'] { + width: var(--plasma-tooltip-tail-width); + height: var(--plasma-tooltip-tail-height); +} + +.tail[data-side='left'], +.tail[data-side='right'] { + width: var(--plasma-tooltip-tail-height); + height: var(--plasma-tooltip-tail-width); +} + +.tail[data-side='top'] { + top: 100%; +} + +.tail[data-side='right'] { + right: 100%; +} + +.tail[data-side='bottom'] { + bottom: 100%; +} + +.tail[data-side='left'] { + left: 100%; +} + +.tail::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: var(--plasma-tooltip-tail-width); + height: var(--plasma-tooltip-tail-height); + background: var(--plasma-tooltip-background-color); + clip-path: shape( + from 100% 100%, + line to 0% 100%, + curve to 50% 0% with calc(25% - var(--plasma-tooltip-tail-side-curvature) * 1.24939) + calc(50% - var(--plasma-tooltip-tail-side-curvature) * 3.90435), + curve to 100% 100% with calc(75% + var(--plasma-tooltip-tail-side-curvature) * 1.24939) + calc(50% - var(--plasma-tooltip-tail-side-curvature) * 3.90435), + close + ); +} + +.tail[data-side='top']::before { + transform: translate(-50%, -50%) rotate(180deg); +} + +.tail[data-side='right']::before { + transform: translate(-50%, -50%) rotate(-90deg); +} + +.tail[data-side='bottom']::before { + transform: translate(-50%, -50%); +} + +.tail[data-side='left']::before { + transform: translate(-50%, -50%) rotate(90deg); +} diff --git a/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.styles.ts b/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.styles.ts deleted file mode 100644 index 0fd51a8b623..00000000000 --- a/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.styles.ts +++ /dev/null @@ -1,75 +0,0 @@ -import styled, { css } from 'styled-components'; - -import { tokens } from './Tooltip.tokens'; - -export const base = css` - border-radius: var(${tokens.borderRadius}); -`; - -export const Wrapper = styled.div` - display: flex; - align-items: center; - position: relative; - gap: var(${tokens.gap}); - background: var(${tokens.backgroundColor}); - padding: var(${tokens.padding}); - border-radius: var(${tokens.borderRadius}); - box-shadow: var(${tokens.boxShadow}); - filter: var(${tokens.dropShadow}, none); - width: 100%; - height: 100%; - box-sizing: border-box; - color: var(${tokens.color}); - font-family: var(${tokens.fontFamily}); - font-size: var(${tokens.fontSize}); - font-style: var(${tokens.fontStyle}); - font-weight: var(${tokens.fontWeight}); - letter-spacing: var(${tokens.letterSpacing}); - line-height: var(${tokens.lineHeight}); -`; - -export const IconWrapper = styled.div` - flex: none; - line-height: 0; -`; - -export const Tail = styled.div<{ side: 'top' | 'right' | 'bottom' | 'left' }>` - position: absolute; - pointer-events: none; - width: ${({ side }) => - side === 'left' || side === 'right' ? `var(${tokens.tailHeight})` : `var(${tokens.tailWidth})`}; - height: ${({ side }) => - side === 'left' || side === 'right' ? `var(${tokens.tailWidth})` : `var(${tokens.tailHeight})`}; - - top: ${({ side }) => (side === 'top' ? '100%' : 'auto')}; - right: ${({ side }) => (side === 'right' ? '100%' : 'auto')}; - bottom: ${({ side }) => (side === 'bottom' ? '100%' : 'auto')}; - left: ${({ side }) => (side === 'left' ? '100%' : 'auto')}; - - &::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: var(${tokens.tailWidth}); - height: var(${tokens.tailHeight}); - background: var(${tokens.backgroundColor}); - transform: translate(-50%, -50%) - ${({ side }) => - ({ - top: 'rotate(180deg)', - right: 'rotate(-90deg)', - bottom: 'rotate(0deg)', - left: 'rotate(90deg)', - }[side])}; - clip-path: shape( - from 100% 100%, - line to 0% 100%, - curve to 50% 0% with calc(25% - var(${tokens.tailSideCurvature}) * 1.24939) - calc(50% - var(${tokens.tailSideCurvature}) * 3.90435), - curve to 100% 100% with calc(75% + var(${tokens.tailSideCurvature}) * 1.24939) - calc(50% - var(${tokens.tailSideCurvature}) * 3.90435), - close - ); - } -`; diff --git a/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.tsx b/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.tsx index 34c08683c96..ab288614806 100644 --- a/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.tsx +++ b/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.tsx @@ -1,5 +1,4 @@ import React, { forwardRef, useState, useRef } from 'react'; -import type { RootProps } from 'src/engines/types'; import cls from 'classnames'; import { useFloating, @@ -18,163 +17,136 @@ import { autoUpdate, limitShift, } from '@floating-ui/react'; -import { css } from 'styled-components'; -import { Slot } from '../../_Slot/Slot'; -import { ARROW_PADDING } from '../Popover/Popover'; -import { getFloatingPortalProps, useTailStyle } from '../Popover/utils'; +import { ARROW_PADDING, getFloatingPortalProps, useTailStyle } from '../Popover/utils'; +import { Slot } from '../utils/Slot'; import { classes } from './Tooltip.tokens'; -import { base, Wrapper, IconWrapper, Tail } from './Tooltip.styles'; import type { TooltipProps } from './Tooltip.types'; - -export const tooltipRoot = (Root: RootProps>) => - forwardRef( - ( - { - children, - target, - iconSlot, - trigger = 'click', - placement = 'bottom', - hasTail = true, - flip: outsideFlip = false, - shift: outsideShift = false, - offset: outerOffset = 0, - delayOpen = 0, - delayClose = 0, - zIndex = 1000, - className, - style, - size, - view, - portal, - ...rest - }, - outerRootRef, - ) => { - const [opened, setOpened] = useState(false); - - const arrowRef = useRef(null); - - const handleToggle = (opened: boolean) => { - setOpened(opened); - }; - - const { - refs, - floatingStyles, - context, - middlewareData, - placement: calculatedPlacement, - isPositioned, - } = useFloating({ - whileElementsMounted: autoUpdate, - placement, - open: opened, - onOpenChange: handleToggle, - middleware: [ - outsideShift && - shift({ - limiter: limitShift(), - }), - outsideFlip && flip(), - hasTail && arrow({ element: arrowRef, padding: ARROW_PADDING }), - offset( - ({ placement: currentPlacement }) => { - if (!hasTail) { - return outerOffset; - } - - const side = currentPlacement.split('-')[0]; - const { width = 0, height = 0 } = arrowRef.current?.getBoundingClientRect() ?? {}; - const tailOffset = side === 'top' || side === 'bottom' ? height : width; - - return tailOffset + outerOffset; - }, - [outerOffset, hasTail], - ), - ], - }); - - const click = useClick(context, { - enabled: trigger === 'click' || matchMedia('(hover: none)').matches, - }); - const focus = useFocus(context, { enabled: trigger === 'focus' }); - const dismiss = useDismiss(context, { - enabled: true, - outsidePress: true, - }); - const role = useRole(context); - const hover = useHover(context, { - mouseOnly: true, - enabled: trigger === 'hover', - handleClose: safePolygon({ - requireIntent: false, - }), - delay: { - open: delayOpen, - close: delayClose, - }, - }); - - const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, role, click, hover, focus]); - - const { side, tailStyle } = useTailStyle(calculatedPlacement, middlewareData, ARROW_PADDING); - - return ( - <> - - {target} - - - {opened && ( - - - - {iconSlot && {iconSlot}} - - {children} - - {hasTail && ( - - - - )} - - ); +import styles from './Tooltip.module.css'; + +export const Tooltip = forwardRef((props, ref) => { + const { + children, + target, + iconSlot, + trigger = 'click', + placement = 'bottom', + hasTail = true, + flip: outsideFlip = false, + shift: outsideShift = false, + offset: outerOffset = 0, + delayOpen = 0, + delayClose = 0, + zIndex = 1000, + portal, + // @ts-ignore + _configClassName, + ...rest + } = props; + + const [opened, setOpened] = useState(false); + + const arrowRef = useRef(null); + + const handleToggle = (nextOpened: boolean) => { + setOpened(nextOpened); + }; + + const { refs, floatingStyles, context, middlewareData, placement: calculatedPlacement, isPositioned } = useFloating( + { + whileElementsMounted: autoUpdate, + placement, + open: opened, + onOpenChange: handleToggle, + middleware: [ + outsideShift && + shift({ + limiter: limitShift(), + }), + outsideFlip && flip(), + hasTail && arrow({ element: arrowRef, padding: ARROW_PADDING }), + offset( + ({ placement: currentPlacement }) => { + if (!hasTail) { + return outerOffset; + } + + const side = currentPlacement.split('-')[0]; + const { width = 0, height = 0 } = arrowRef.current?.getBoundingClientRect() ?? {}; + const tailOffset = side === 'top' || side === 'bottom' ? height : width; + + return tailOffset + outerOffset; + }, + [outerOffset, hasTail], + ), + ], }, ); -export const tooltipConfig = { - name: 'Tooltip', - tag: 'div', - layout: tooltipRoot, - base, - variations: { - view: { - css: css``, - }, - size: { - css: css``, + const click = useClick(context, { + enabled: trigger === 'click' || trigger === 'hover', + ignoreMouse: trigger === 'hover', + }); + const focus = useFocus(context, { enabled: trigger === 'focus' }); + const dismiss = useDismiss(context, { + enabled: true, + outsidePress: true, + }); + const role = useRole(context); + const hover = useHover(context, { + mouseOnly: true, + enabled: trigger === 'hover', + handleClose: safePolygon({ + requireIntent: false, + }), + delay: { + open: delayOpen, + close: delayClose, }, - }, - defaults: { - view: 'default', - size: 'm', - }, -}; + }); + + const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, role, click, hover, focus]); + + const { side, tailStyle } = useTailStyle(calculatedPlacement, middlewareData, ARROW_PADDING); + + return ( + <> + + {target} + + + {opened && ( + +
+
+ {iconSlot &&
{iconSlot}
} + + {children} + + {hasTail && ( + +
+ + )} + + ); +}); diff --git a/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.types.ts b/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.types.ts index 519fddcc2a8..d857a6fac28 100644 --- a/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.types.ts +++ b/packages/plasma-new-hope/src/components/_beta/Tooltip/Tooltip.types.ts @@ -68,15 +68,6 @@ export type BasicTooltipProps = { * @default Без использования portal всплывающее окно рендерится перед . */ portal?: string | React.RefObject; - - /** - * Вид компонента. - */ - view?: string; - /** - * Размер компонента. - */ - size?: string; }; export type TooltipProps = Omit, 'children'> & BasicTooltipProps; diff --git a/packages/plasma-new-hope/src/components/_beta/Tooltip/index.ts b/packages/plasma-new-hope/src/components/_beta/Tooltip/index.ts index bf49937f6ef..31619fd2eee 100644 --- a/packages/plasma-new-hope/src/components/_beta/Tooltip/index.ts +++ b/packages/plasma-new-hope/src/components/_beta/Tooltip/index.ts @@ -1,4 +1,3 @@ -export { tooltipRoot as _beta_tooltipRoot, tooltipConfig as _beta_tooltipConfig } from './Tooltip'; -export { classes as _beta_tooltipClasses, tokens as _beta_tooltipTokens } from './Tooltip.tokens'; +export { Tooltip } from './Tooltip'; -export type { TooltipProps as _beta_TooltipProps } from './Tooltip.types'; +export type { BasicTooltipProps, TooltipProps } from './Tooltip.types'; diff --git a/packages/plasma-new-hope/src/components/_beta/css-modules.d.ts b/packages/plasma-new-hope/src/components/_beta/css-modules.d.ts new file mode 100644 index 00000000000..e7f258a4668 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/css-modules.d.ts @@ -0,0 +1,5 @@ +declare module '*.module.css' { + const classes: Readonly>; + + export default classes; +} diff --git a/packages/plasma-new-hope/src/components/_beta/mixins/addFocus.module.css b/packages/plasma-new-hope/src/components/_beta/mixins/addFocus.module.css new file mode 100644 index 00000000000..80d6694f467 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/mixins/addFocus.module.css @@ -0,0 +1,22 @@ +.focus:focus-visible { + outline: none; +} + +.focus::before { + content: ''; + position: absolute; + inset: 0; + z-index: 1; + border-radius: var(--plasma_private-focus-border-radius, 0); + outline: var(--plasma_private-focus-outline-size, 0.0625rem) solid transparent; + outline-offset: var(--plasma_private-focus-outline-offset, 0.125rem); + transition: outline-color 0.2s ease-in-out; + pointer-events: none; +} + +.focus:focus-visible::before { + outline-color: var( + --plasma_private-focus-outline-color, + var(--plasma-colors-button-focused, var(--surface-accent)) + ); +} diff --git a/packages/plasma-new-hope/src/components/_beta/tsconfig.json b/packages/plasma-new-hope/src/components/_beta/tsconfig.json new file mode 100644 index 00000000000..e0172118eb9 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/beta/types", + "rootDir": "../.." + }, + "include": ["."], + "exclude": ["./**/*.stories.tsx", "./**/*.component-test.tsx"] +} diff --git a/packages/plasma-new-hope/src/components/_beta/utils/Slot.tsx b/packages/plasma-new-hope/src/components/_beta/utils/Slot.tsx new file mode 100644 index 00000000000..fd8c43ea173 --- /dev/null +++ b/packages/plasma-new-hope/src/components/_beta/utils/Slot.tsx @@ -0,0 +1,49 @@ +import React, { forwardRef, isValidElement, cloneElement } from 'react'; + +const mergeRefs = (...refs: Array | undefined>) => (value: unknown) => { + refs.forEach((ref) => { + if (typeof ref === 'function') { + ref(value); + } else if (ref) { + (ref as React.MutableRefObject).current = value; + } + }); +}; + +const mergeHandlers = (childHandler?: (...args: unknown[]) => void, slotHandler?: (...args: unknown[]) => void) => ( + ...args: unknown[] +) => { + childHandler?.(...args); + slotHandler?.(...args); +}; + +export const Slot = forwardRef>(({ children, ...slotProps }, forwardedRef) => { + if (!isValidElement>(children)) { + return null; + } + + const childProps = children.props; + const mergedProps: Record = { ...slotProps }; + + Object.keys(slotProps).forEach((key) => { + if (/^on[A-Z]/.test(key)) { + mergedProps[key] = mergeHandlers( + childProps[key] as ((...args: unknown[]) => void) | undefined, + slotProps[key] as ((...args: unknown[]) => void) | undefined, + ); + } + }); + + if (childProps.className || slotProps.className) { + mergedProps.className = [slotProps.className, childProps.className].filter(Boolean).join(' '); + } + + if (childProps.style || slotProps.style) { + mergedProps.style = { ...(slotProps.style as object), ...(childProps.style as object) }; + } + + const childRef = (children as React.ReactElement & { ref?: React.Ref }).ref; + mergedProps.ref = mergeRefs(childRef, forwardedRef); + + return cloneElement(children, mergedProps); +}); diff --git a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.config.ts b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.config.ts index dd600559cd5..f4f1771c41d 100644 --- a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.config.ts +++ b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.config.ts @@ -1,5 +1,6 @@ -import { css } from 'styled-components'; -import { _beta_embeddedButtonTokens as tokens } from 'src/components/_beta/EmbeddedButton'; +import disabledStyles from './config/Disabled.module.css'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; export const config = { defaults: { @@ -7,93 +8,10 @@ export const config = { size: 'm', }, variations: { - view: { - default: css` - ${tokens.color}: var(--text-primary); - ${tokens.colorHover}: var(--text-primary-hover); - ${tokens.colorActive}: var(--text-primary-active); - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: var(--text-primary); - ${tokens.focusColor}: var(--surface-accent); - ${tokens.loadingIconOpacity}: 0.06; - `, - secondary: css` - ${tokens.color}: var(--text-secondary); - ${tokens.colorHover}: var(--text-secondary-hover); - ${tokens.colorActive}: var(--text-secondary-active); - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: var(--text-secondary); - ${tokens.focusColor}: var(--surface-accent); - ${tokens.loadingIconOpacity}: 0.06; - `, - accent: css` - ${tokens.color}: var(--text-accent); - ${tokens.colorHover}: var(--text-accent-hover); - ${tokens.colorActive}: var(--text-accent-active); - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: var(--text-accent); - ${tokens.focusColor}: var(--surface-accent); - ${tokens.loadingIconOpacity}: 0.06; - `, - positive: css` - ${tokens.color}: var(--text-positive); - ${tokens.colorHover}: var(--text-positive-hover); - ${tokens.colorActive}: var(--text-positive-active); - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: var(--text-positive); - ${tokens.focusColor}: var(--surface-accent); - ${tokens.loadingIconOpacity}: 0.06; - `, - warning: css` - ${tokens.color}: var(--text-warning); - ${tokens.colorHover}: var(--text-warning-hover); - ${tokens.colorActive}: var(--text-warning-active); - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: var(--text-warning); - ${tokens.focusColor}: var(--surface-accent); - ${tokens.loadingIconOpacity}: 0.06; - `, - negative: css` - ${tokens.color}: var(--text-negative); - ${tokens.colorHover}: var(--text-negative-hover); - ${tokens.colorActive}: var(--text-negative-active); - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: var(--text-negative); - ${tokens.focusColor}: var(--surface-accent); - ${tokens.loadingIconOpacity}: 0.06; - `, - info: css` - ${tokens.color}: var(--text-info); - ${tokens.colorHover}: var(--text-info-hover); - ${tokens.colorActive}: var(--text-info-active); - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: var(--text-info); - ${tokens.focusColor}: var(--surface-accent); - ${tokens.loadingIconOpacity}: 0.06; - `, - }, - size: { - l: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.spinnerSize}: 2.25rem; - `, - m: css` - ${tokens.borderRadius}: 0.625rem; - ${tokens.spinnerSize}: 1.5rem; - `, - s: css` - ${tokens.borderRadius}: 0.5rem; - ${tokens.spinnerSize}: 1rem; - `, - xs: css` - ${tokens.borderRadius}: 0.375rem; - ${tokens.spinnerSize}: 0.75rem; - `, - }, + view: viewStyles, + size: sizeStyles, disabled: { - true: css` - ${tokens.disabledOpacity}: 0.4; - `, + true: disabledStyles.disabled, }, }, }; diff --git a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.ts b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.ts deleted file mode 100644 index 5663408ccac..00000000000 --- a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { _beta_embeddedButtonConfig } from 'src/components/_beta/EmbeddedButton'; -import { component, mergeConfig } from 'src/engines'; - -import { config } from './EmbeddedButton.config'; - -const mergedConfig = mergeConfig(_beta_embeddedButtonConfig, config); -export const EmbeddedButton = component(mergedConfig); diff --git a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.tsx b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.tsx new file mode 100644 index 00000000000..beabffdcf7f --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/EmbeddedButton.tsx @@ -0,0 +1,26 @@ +import React, { forwardRef } from 'react'; +import cls from 'classnames'; + +import { EmbeddedButton as CoreEmbeddedButton } from '../../../../components/_beta/EmbeddedButton'; +import type { EmbeddedButtonProps as CoreEmbeddedButtonProps } from '../../../../components/_beta/EmbeddedButton'; + +import disabledStyles from './config/Disabled.module.css'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; + +type EmbeddedButtonView = 'default' | 'secondary' | 'accent' | 'positive' | 'warning' | 'negative' | 'info'; +type EmbeddedButtonSize = 'l' | 'm' | 's' | 'xs'; + +type EmbeddedButtonProps = CoreEmbeddedButtonProps & { + view?: EmbeddedButtonView; + size?: EmbeddedButtonSize; +}; + +export const EmbeddedButton = forwardRef( + ({ view = 'default', size = 'm', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size], rest.disabled && disabledStyles.disabled); + + // @ts-expect-error _configClassName is an internal runtime property. + return ; + }, +); diff --git a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/Disabled.module.css b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/Disabled.module.css new file mode 100644 index 00000000000..e43dd3fca3b --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/Disabled.module.css @@ -0,0 +1,3 @@ +.disabled { + --plasma-embedded-button-disabled-opacity: 0.4; +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/Size.module.css b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/Size.module.css new file mode 100644 index 00000000000..f32385724ad --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/Size.module.css @@ -0,0 +1,19 @@ +.l { + --plasma-embedded-button-border-radius: 0.75rem; + --plasma-embedded-button-spinner-size: 2.25rem; +} + +.m { + --plasma-embedded-button-border-radius: 0.625rem; + --plasma-embedded-button-spinner-size: 1.5rem; +} + +.s { + --plasma-embedded-button-border-radius: 0.5rem; + --plasma-embedded-button-spinner-size: 1rem; +} + +.xs { + --plasma-embedded-button-border-radius: 0.375rem; + --plasma-embedded-button-spinner-size: 0.75rem; +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/View.module.css b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/View.module.css new file mode 100644 index 00000000000..ec493767fc6 --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/EmbeddedButton/config/View.module.css @@ -0,0 +1,69 @@ +.default { + --plasma-embedded-button-color: var(--text-primary); + --plasma-embedded-button-color-hover: var(--text-primary-hover); + --plasma-embedded-button-color-active: var(--text-primary-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-primary); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.secondary { + --plasma-embedded-button-color: var(--text-secondary); + --plasma-embedded-button-color-hover: var(--text-secondary-hover); + --plasma-embedded-button-color-active: var(--text-secondary-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-secondary); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.accent { + --plasma-embedded-button-color: var(--text-accent); + --plasma-embedded-button-color-hover: var(--text-accent-hover); + --plasma-embedded-button-color-active: var(--text-accent-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-accent); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.positive { + --plasma-embedded-button-color: var(--text-positive); + --plasma-embedded-button-color-hover: var(--text-positive-hover); + --plasma-embedded-button-color-active: var(--text-positive-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-positive); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.warning { + --plasma-embedded-button-color: var(--text-warning); + --plasma-embedded-button-color-hover: var(--text-warning-hover); + --plasma-embedded-button-color-active: var(--text-warning-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-warning); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.negative { + --plasma-embedded-button-color: var(--text-negative); + --plasma-embedded-button-color-hover: var(--text-negative-hover); + --plasma-embedded-button-color-active: var(--text-negative-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-negative); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.info { + --plasma-embedded-button-color: var(--text-info); + --plasma-embedded-button-color-hover: var(--text-info-hover); + --plasma-embedded-button-color-active: var(--text-info-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-info); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.closeInner.config.ts b/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.closeInner.config.ts deleted file mode 100644 index 8297638395d..00000000000 --- a/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.closeInner.config.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { css } from 'styled-components'; -import { _beta_popoverTokens as tokens } from 'src/components/_beta/Popover'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: var(--surface-solid-card); - ${tokens.boxShadow}: var(--shadow-down-soft-m); - ${tokens.iconColor}: var(--text-secondary); - ${tokens.iconColorHover}: var(--text-secondary-hover); - ${tokens.iconColorActive}: var(--text-secondary-active); - `, - accent: css` - ${tokens.backgroundColor}: var(--surface-accent); - ${tokens.boxShadow}: var(--shadow-down-soft-m); - ${tokens.iconColor}: var(--on-dark-text-secondary); - ${tokens.iconColorHover}: var(--on-dark-text-secondary-hover); - ${tokens.iconColorActive}: var(--on-dark-text-secondary-active); - `, - }, - size: { - l: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem; - ${tokens.iconOffset}: 0.75rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - m: css` - ${tokens.borderRadius}: 0.875rem; - ${tokens.padding}: 0.625rem; - ${tokens.iconOffset}: 0.625rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.padding}: 0.5rem; - ${tokens.iconOffset}: 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.closeNone.config.ts b/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.closeNone.config.ts deleted file mode 100644 index 21ba2353fdf..00000000000 --- a/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.closeNone.config.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { css } from 'styled-components'; -import { _beta_popoverTokens as tokens } from 'src/components/_beta/Popover'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: var(--surface-solid-card); - ${tokens.boxShadow}: var(--shadow-down-soft-m); - `, - accent: css` - ${tokens.backgroundColor}: var(--surface-accent); - ${tokens.boxShadow}: var(--shadow-down-soft-m); - `, - }, - size: { - l: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - m: css` - ${tokens.borderRadius}: 0.875rem; - ${tokens.padding}: 0.625rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.padding}: 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.stories.tsx b/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.stories.tsx index 004a191b126..e4127b54ee8 100644 --- a/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.stories.tsx +++ b/packages/plasma-new-hope/src/examples/components/_beta/Popover/Popover.stories.tsx @@ -11,7 +11,7 @@ import { Popover } from './Popover'; type StoryProps = ComponentProps; -const appearance = ['closeNone', 'closeInner']; +const appearance = ['default', 'closeInner']; const placements = [ 'top', 'top-start', @@ -106,7 +106,7 @@ const meta: Meta = { }, }, args: { - appearance: 'closeNone', + appearance: 'default', placement: 'bottom', trigger: 'click', defaultOpened: false, @@ -174,6 +174,7 @@ const StoryResizable = (args: StoryProps) => { resizableMaxWidth, resizableMaxHeight, resizableIconSize, + ...popoverProps } = args; React.useEffect(() => { @@ -201,6 +202,7 @@ const StoryResizable = (args: StoryProps) => { }} > Target} resizable={{ directions: resizableDirections, @@ -212,7 +214,6 @@ const StoryResizable = (args: StoryProps) => { maxHeight: resizableMaxHeight, iconSize: resizableIconSize, }} - {...args} >
; -export const Popover = createConditionalComponent({ - default: PopoverCloseNone, - closeInner: PopoverCloseInner, -}); +type DefaultAppearanceProps = { + appearance?: 'default'; + view?: 'default' | 'accent'; + size?: 'l' | 'm' | 's'; +}; + +type CloseInnerAppearanceProps = { + appearance: 'closeInner'; + view?: 'default' | 'accent'; + size?: 'l' | 'm' | 's'; +}; + +export type PopoverProps = BasePopoverProps & (DefaultAppearanceProps | CloseInnerAppearanceProps); + +export const Popover = forwardRef( + ({ appearance = 'default', view = 'default', size = 'm', ...rest }, ref) => { + const viewStyles = appearance === 'default' ? closeNoneViewStyles : closeInnerViewStyles; + const sizeStyles = appearance === 'default' ? closeNoneSizeStyles : closeInnerSizeStyles; + + return ( + + ); + }, +); diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseInnerSize.module.css b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseInnerSize.module.css new file mode 100644 index 00000000000..5ff85b522a8 --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseInnerSize.module.css @@ -0,0 +1,29 @@ +.l { + --plasma-popover-close-icon-size: 1.5rem; + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem; + --plasma-popover-icon-offset: 0.75rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.m { + --plasma-popover-close-icon-size: 1.5rem; + --plasma-popover-border-radius: 0.875rem; + --plasma-popover-padding: 0.625rem; + --plasma-popover-icon-offset: 0.625rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.s { + --plasma-popover-close-icon-size: 1rem; + --plasma-popover-border-radius: 0.75rem; + --plasma-popover-padding: 0.5rem; + --plasma-popover-icon-offset: 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseInnerView.module.css b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseInnerView.module.css new file mode 100644 index 00000000000..6d3461d021c --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseInnerView.module.css @@ -0,0 +1,15 @@ +.default { + --plasma-popover-background-color: var(--surface-solid-card); + --plasma-popover-box-shadow: var(--shadow-down-soft-m); + --plasma-popover-icon-color: var(--text-secondary); + --plasma-popover-icon-color-hover: var(--text-secondary-hover); + --plasma-popover-icon-color-active: var(--text-secondary-active); +} + +.accent { + --plasma-popover-background-color: var(--surface-accent); + --plasma-popover-box-shadow: var(--shadow-down-soft-m); + --plasma-popover-icon-color: var(--on-dark-text-secondary); + --plasma-popover-icon-color-hover: var(--on-dark-text-secondary-hover); + --plasma-popover-icon-color-active: var(--on-dark-text-secondary-active); +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseNoneSize.module.css b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseNoneSize.module.css new file mode 100644 index 00000000000..bc3dd55664f --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseNoneSize.module.css @@ -0,0 +1,23 @@ +.l { + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.m { + --plasma-popover-border-radius: 0.875rem; + --plasma-popover-padding: 0.625rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.s { + --plasma-popover-border-radius: 0.75rem; + --plasma-popover-padding: 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseNoneView.module.css b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseNoneView.module.css new file mode 100644 index 00000000000..093d78e99c6 --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/Popover/config/CloseNoneView.module.css @@ -0,0 +1,9 @@ +.default { + --plasma-popover-background-color: var(--surface-solid-card); + --plasma-popover-box-shadow: var(--shadow-down-soft-m); +} + +.accent { + --plasma-popover-background-color: var(--surface-accent); + --plasma-popover-box-shadow: var(--shadow-down-soft-m); +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.config.ts b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.config.ts deleted file mode 100644 index ebb22099de9..00000000000 --- a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.config.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { css } from 'styled-components'; -import { _beta_tooltipTokens as tokens } from 'src/components/_beta/Tooltip'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: var(--surface-solid-card); - ${tokens.boxShadow}: var(--shadow-down-soft-m); - ${tokens.color}: var(--text-primary); - `, - accent: css` - ${tokens.backgroundColor}: var(--surface-accent); - ${tokens.boxShadow}: var(--shadow-down-soft-m); - ${tokens.color}: var(--on-dark-text-primary); - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 0.625rem; - ${tokens.padding}: 0.625rem 0.875rem; - ${tokens.gap}: 0.375rem; - ${tokens.fontFamily}: var(--plasma-typo-body-s-font-family); - ${tokens.fontSize}: var(--plasma-typo-body-s-font-size); - ${tokens.fontStyle}: var(--plasma-typo-body-s-font-style); - ${tokens.fontWeight}: var(--plasma-typo-body-s-font-weight); - ${tokens.letterSpacing}: var(--plasma-typo-body-s-letter-spacing); - ${tokens.lineHeight}: var(--plasma-typo-body-s-line-height); - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.5rem; - ${tokens.padding}: 0.5rem 0.75rem; - ${tokens.gap}: 0.25rem; - ${tokens.fontFamily}: var(--plasma-typo-body-xs-font-family); - ${tokens.fontSize}: var(--plasma-typo-body-xs-font-size); - ${tokens.fontStyle}: var(--plasma-typo-body-xs-font-style); - ${tokens.fontWeight}: var(--plasma-typo-body-xs-font-weight); - ${tokens.letterSpacing}: var(--plasma-typo-body-xs-letter-spacing); - ${tokens.lineHeight}: var(--plasma-typo-body-xs-line-height); - ${tokens.tailWidth}: 14px; - ${tokens.tailHeight}: 6px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.stories.tsx b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.stories.tsx index 67333f36357..ea9c699d1bf 100644 --- a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.stories.tsx +++ b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.stories.tsx @@ -7,7 +7,9 @@ import { Button } from '../../Button/Button'; import { Tooltip } from './Tooltip'; -type StoryProps = ComponentProps; +type StoryProps = ComponentProps & { + hasIcon?: boolean; +}; const placements = [ 'top', @@ -108,7 +110,7 @@ const meta: Meta = { export default meta; -const StoryDefault = (args: StoryProps) => { +const StoryDefault = ({ hasIcon, ...tooltipProps }: StoryProps) => { React.useEffect(() => { window.scrollTo( (document.documentElement.scrollWidth - window.innerWidth) / 2, @@ -127,9 +129,9 @@ const StoryDefault = (args: StoryProps) => { }} > : undefined} + {...tooltipProps} + iconSlot={hasIcon ? : undefined} target={} - {...args} > Контент выпадающего окна diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.tsx b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.tsx index 038c23ad929..e1c386e8ba0 100644 --- a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.tsx +++ b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/Tooltip.tsx @@ -1,7 +1,21 @@ -import { _beta_tooltipConfig } from 'src/components/_beta/Tooltip'; -import { component, mergeConfig } from 'src/engines'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; -import { config } from './Tooltip.config'; +import { Tooltip as CoreTooltip } from '../../../../components/_beta/Tooltip'; +import type { TooltipProps as CoreTooltipProps } from '../../../../components/_beta/Tooltip'; -const mergedConfig = mergeConfig(_beta_tooltipConfig, config); -export const Tooltip = component(mergedConfig); +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; + +type TooltipView = 'default' | 'accent'; +type TooltipSize = 'm' | 's'; + +type TooltipProps = CoreTooltipProps & { + view?: TooltipView; + size?: TooltipSize; +}; + +export const Tooltip = forwardRef(({ view = 'default', size = 'm', ...rest }, ref) => { + // @ts-expect-error _configClassName is an internal runtime property. + return ; +}); diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/config/Size.module.css b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/config/Size.module.css new file mode 100644 index 00000000000..30e911443c4 --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/config/Size.module.css @@ -0,0 +1,29 @@ +.m { + --plasma-tooltip-border-radius: 0.625rem; + --plasma-tooltip-padding: 0.625rem 0.875rem; + --plasma-tooltip-gap: 0.375rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-s-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-s-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-s-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-s-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-s-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-s-line-height); + --plasma-tooltip-tail-width: 20px; + --plasma-tooltip-tail-height: 8px; + --plasma-tooltip-tail-side-curvature: -10%; +} + +.s { + --plasma-tooltip-border-radius: 0.5rem; + --plasma-tooltip-padding: 0.5rem 0.75rem; + --plasma-tooltip-gap: 0.25rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-xs-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-xs-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-xs-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-xs-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-xs-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-xs-line-height); + --plasma-tooltip-tail-width: 14px; + --plasma-tooltip-tail-height: 6px; + --plasma-tooltip-tail-side-curvature: -10%; +} diff --git a/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/config/View.module.css b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/config/View.module.css new file mode 100644 index 00000000000..dac85839385 --- /dev/null +++ b/packages/plasma-new-hope/src/examples/components/_beta/Tooltip/config/View.module.css @@ -0,0 +1,11 @@ +.default { + --plasma-tooltip-background-color: var(--surface-solid-card); + --plasma-tooltip-box-shadow: var(--shadow-down-soft-m); + --plasma-tooltip-color: var(--text-primary); +} + +.accent { + --plasma-tooltip-background-color: var(--surface-accent); + --plasma-tooltip-box-shadow: var(--shadow-down-soft-m); + --plasma-tooltip-color: var(--on-dark-text-primary); +} diff --git a/packages/plasma-new-hope/src/index.ts b/packages/plasma-new-hope/src/index.ts index 89d68ffb5f4..1bb9027e605 100644 --- a/packages/plasma-new-hope/src/index.ts +++ b/packages/plasma-new-hope/src/index.ts @@ -99,7 +99,3 @@ export * from './components/_ai/Answer'; export * from './components/_ai/Container'; export * from './components/_ai/Header'; export * from './components/_ai/UserMessage'; - -export * from './components/_beta/Popover'; -export * from './components/_beta/Tooltip'; -export * from './components/_beta/EmbeddedButton'; diff --git a/packages/sdds-cs/package.json b/packages/sdds-cs/package.json index 5bd96d90c7b..a71ce856f96 100644 --- a/packages/sdds-cs/package.json +++ b/packages/sdds-cs/package.json @@ -35,7 +35,8 @@ }, "dependencies": { "@salutejs/plasma-new-hope": "0.378.0", - "@salutejs/sdds-themes": "0.79.0" + "@salutejs/sdds-themes": "0.79.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", @@ -48,7 +49,10 @@ "@emotion/babel-plugin": "11.11.0", "@emotion/react": ">=11", "@emotion/styled": ">=11", + "@ironkinoko/rollup-plugin-styles": "^4.0.3", "@originjs/vite-plugin-commonjs": "1.0.3", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-node-resolve": "^15.1.0", "@salutejs/plasma-colors": "0.22.0", "@salutejs/plasma-core": "1.241.0", "@salutejs/plasma-cy-utils": "0.171.0", @@ -64,6 +68,7 @@ "default-browser-id": "2.0.0", "react": "18.2.0", "react-dom": "18.2.0", + "rollup": "^3.28.0", "styled-components": "5.3.1", "typescript-coverage-report": "0.7.0" }, @@ -73,11 +78,9 @@ "build:emotion": "rm -rf dist/emotion && npm run build:emotion:esm && npm run build:emotion:cjs", "build:emotion:cjs": "swc ./src --ignore \"src/components/_beta/**\" -d ./dist/emotion/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs", "build:emotion:esm": "swc ./src --ignore \"src/components/_beta/**\" -d ./dist/emotion/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6", - "build:beta": "rm -rf dist/beta && npm run build:beta:esm && npm run build:beta:cjs", - "build:beta:cjs": "swc ./src/components/_beta -d ./dist/beta/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs && mv dist/beta/cjs/components/_beta/* dist/beta/cjs && rimraf dist/beta/cjs/components", - "build:beta:esm": "swc ./src/components/_beta -d ./dist/beta/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6 && mv dist/beta/es/components/_beta/* dist/beta/es && rimraf dist/beta/es/components", + "build:beta": "rm -rf dist/beta && rollup -c rollup.beta.config.mjs", "postbuild": "npm run generate:typings", - "generate:typings": "rm -rf types && tsc && rm -rf dist/beta/types && tsc -p src/components/_beta/tsconfig.json", + "generate:typings": "tsc && tsc -p src/components/_beta/tsconfig.json", "storybook": "storybook dev -p ${PORT:-7007} -c .storybook", "storybook:build": "storybook build -c .storybook -o build-sb", "typescript-coverage": "npx typescript-coverage-report > /dev/null", @@ -88,5 +91,5 @@ "atLeast": 99.94 }, "contributors": ["salute.developers@gmail.com"], - "sideEffects": false + "sideEffects": ["*.css"] } diff --git a/packages/sdds-cs/rollup.beta.config.mjs b/packages/sdds-cs/rollup.beta.config.mjs new file mode 100644 index 00000000000..2305c2c3ef7 --- /dev/null +++ b/packages/sdds-cs/rollup.beta.config.mjs @@ -0,0 +1,131 @@ +import path from 'path'; +import { createHash } from 'crypto'; +import { fileURLToPath } from 'url'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { babel } from '@rollup/plugin-babel'; +import styles from '@ironkinoko/rollup-plugin-styles'; + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); +const betaSourceDir = path.resolve(dirname, 'src/components/_beta'); +const extractedCssModules = new Map(); + +export default { + input: { + index: path.join(betaSourceDir, 'index.ts'), + }, + treeshake: { + propertyReadSideEffects: false, + }, + output: [ + { + preserveModules: true, + dir: 'dist/beta/es', + format: 'es', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + }, + { + preserveModules: true, + dir: 'dist/beta/cjs', + format: 'cjs', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + interop: 'auto', + }, + ], + external: (id) => { + if (id.startsWith('regenerator-runtime') || id === 'tslib') { + return false; + } + + return !id.startsWith('.') && !path.isAbsolute(id); + }, + plugins: [ + nodeResolve({ + extensions: ['.tsx', '.ts'], + }), + styles({ + mode: 'extract', + modules: { + generateScopedName(localName, file, css) { + const relativePath = path.relative(betaSourceDir, file).split(path.sep).join('/'); + const componentName = relativePath.split('/')[0]; + const fileName = path.basename(file, '.module.css'); + const hash = createHash('sha256') + .update(`${relativePath}:${localName}:${css}`) + .digest('hex') + .slice(0, 8); + + return `${componentName}_${fileName}_${localName}__${hash}`; + }, + }, + onExtract({ name, css }) { + const moduleName = name.replace(/\.css$/, ''); + + if (moduleName.endsWith('.module.css')) { + extractedCssModules.set(moduleName, css); + } + + return false; + }, + }), + emitCssModulesPlugin(), + babel({ + babelHelpers: 'bundled', + extensions: ['.ts', '.tsx'], + presets: [ + ['@babel/preset-env', { modules: false }], + '@babel/preset-react', + '@babel/preset-typescript', + ], + plugins: [ + '@babel/plugin-transform-class-properties', + 'babel-plugin-annotate-pure-calls', + '@babel/plugin-transform-react-constant-elements', + ], + }), + ], +}; + +function emitCssModulesPlugin() { + return { + name: 'emitCssModulesPlugin', + generateBundle: { + order: 'post', + handler(options, bundle) { + Object.values(bundle).forEach((file) => { + if (file.type !== 'chunk' || !file.fileName.endsWith('.module.css.js')) { + return; + } + + const moduleName = file.fileName.replace(/\.js$/, ''); + const css = extractedCssModules.get(moduleName); + + if (css === undefined) { + this.error(`Processed CSS Module was not found for ${file.fileName}`); + } + + const cssFileName = file.fileName.replace(/\.module\.css\.js$/, '.css'); + const relativeCssPath = `./${path.posix.relative(path.posix.dirname(file.fileName), cssFileName)}`; + const importCss = + options.format === 'cjs' + ? `require('${relativeCssPath}');\n` + : `import '${relativeCssPath}';\n`; + + file.code = importCss + file.code; + + this.emitFile({ + type: 'asset', + fileName: cssFileName, + source: css, + }); + }); + }, + }, + }; +} diff --git a/packages/sdds-cs/src/components/_beta/Popover/Popover.closeInner.config.ts b/packages/sdds-cs/src/components/_beta/Popover/Popover.closeInner.config.ts deleted file mode 100644 index bdc75d3d0c6..00000000000 --- a/packages/sdds-cs/src/components/_beta/Popover/Popover.closeInner.config.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - onDarkTextSecondary, - onDarkTextSecondaryActive, - onDarkTextSecondaryHover, - shadowDownHardM, - surfaceAccent, - surfaceSolidCard, - textSecondary, - textSecondaryActive, - textSecondaryHover, -} from '@salutejs/sdds-themes/tokens/sdds_cs'; -import { css, _beta_popoverTokens as tokens } from '@salutejs/plasma-new-hope/emotion'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${surfaceSolidCard}; - ${tokens.boxShadow}: ${shadowDownHardM}; - ${tokens.iconColor}: ${textSecondary}; - ${tokens.iconColorHover}: ${textSecondaryHover}; - ${tokens.iconColorActive}: ${textSecondaryActive}; - `, - info: css` - ${tokens.backgroundColor}: ${surfaceAccent}; - ${tokens.boxShadow}: ${shadowDownHardM}; - ${tokens.iconColor}: ${onDarkTextSecondary}; - ${tokens.iconColorHover}: ${onDarkTextSecondaryHover}; - ${tokens.iconColorActive}: ${onDarkTextSecondaryActive}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem 0.5rem 0.5rem 0.5rem; - ${tokens.iconOffset}: 0.625rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.padding}: 0.5rem 0.375rem 0.375rem 0.375rem; - ${tokens.iconOffset}: 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/sdds-cs/src/components/_beta/Popover/Popover.closeNone.config.ts b/packages/sdds-cs/src/components/_beta/Popover/Popover.closeNone.config.ts deleted file mode 100644 index ec7eef405b8..00000000000 --- a/packages/sdds-cs/src/components/_beta/Popover/Popover.closeNone.config.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { shadowDownHardM, surfaceAccent, surfaceSolidCard } from '@salutejs/sdds-themes/tokens/sdds_cs'; -import { css, _beta_popoverTokens as tokens } from '@salutejs/plasma-new-hope/emotion'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${surfaceSolidCard}; - ${tokens.boxShadow}: ${shadowDownHardM}; - `, - info: css` - ${tokens.backgroundColor}: ${surfaceAccent}; - ${tokens.boxShadow}: ${shadowDownHardM}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem 0.5rem 0.5rem 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.padding}: 0.5rem 0.375rem 0.375rem 0.375rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/sdds-cs/src/components/_beta/Popover/Popover.stories.tsx b/packages/sdds-cs/src/components/_beta/Popover/Popover.stories.tsx index 787f61479a3..d7100c34661 100644 --- a/packages/sdds-cs/src/components/_beta/Popover/Popover.stories.tsx +++ b/packages/sdds-cs/src/components/_beta/Popover/Popover.stories.tsx @@ -9,9 +9,19 @@ import { ViewContainer } from '../../ViewContainer'; import { Popover } from './Popover'; -type StoryProps = ComponentProps; +type ResizableOptions = Exclude['resizable'], boolean | undefined>; +type StoryProps = ComponentProps & { + resizableDirections?: ResizableOptions['directions']; + resizableHiddenIcons?: ResizableOptions['hiddenIcons']; + resizableDefaultSize?: ResizableOptions['defaultSize']; + resizableMinWidth?: ResizableOptions['minWidth']; + resizableMinHeight?: ResizableOptions['minHeight']; + resizableMaxWidth?: ResizableOptions['maxWidth']; + resizableMaxHeight?: ResizableOptions['maxHeight']; + resizableIconSize?: ResizableOptions['iconSize']; +}; -const appearance = ['closeNone', 'closeInner']; +const appearance = ['default', 'closeInner']; const placements = [ 'top', 'top-start', @@ -106,7 +116,7 @@ const meta: Meta = { }, }, args: { - appearance: 'closeNone', + appearance: 'default', placement: 'bottom', trigger: 'click', defaultOpened: false, @@ -142,9 +152,9 @@ const StoryDefault = (args: StoryProps) => { height: '400vh', }} > - Target} {...args}> + Target}> - + Title Description @@ -161,7 +171,7 @@ const StoryDefault = (args: StoryProps) => { }; export const Default: StoryObj = { - render: (args) => , + render: (args: StoryProps) => , }; const StoryResizable = (args: StoryProps) => { @@ -174,6 +184,7 @@ const StoryResizable = (args: StoryProps) => { resizableMaxWidth, resizableMaxHeight, resizableIconSize, + ...popoverProps } = args; React.useEffect(() => { @@ -201,7 +212,7 @@ const StoryResizable = (args: StoryProps) => { }} > Target} + {...popoverProps} resizable={{ directions: resizableDirections, hiddenIcons: resizableHiddenIcons, @@ -212,7 +223,7 @@ const StoryResizable = (args: StoryProps) => { maxHeight: resizableMaxHeight, iconSize: resizableIconSize, }} - {...args} + target={} >
= { resizableMinWidth: 300, resizableMinHeight: 300, }, - render: (args) => , + render: (args: StoryProps) => , }; diff --git a/packages/sdds-cs/src/components/_beta/Popover/Popover.tsx b/packages/sdds-cs/src/components/_beta/Popover/Popover.tsx index 45499607d8b..7c38e4a6ab7 100644 --- a/packages/sdds-cs/src/components/_beta/Popover/Popover.tsx +++ b/packages/sdds-cs/src/components/_beta/Popover/Popover.tsx @@ -1,20 +1,43 @@ -import { - _beta_popoverConfig, - component, - createConditionalComponent, - mergeConfig, -} from '@salutejs/plasma-new-hope/emotion'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Popover as CorePopover } from '@salutejs/plasma-new-hope/beta'; +import type { PopoverProps as CorePopoverProps } from '@salutejs/plasma-new-hope/beta'; -import { config as closeNoneConfig } from './Popover.closeNone.config'; -import { config as closeInnerConfig } from './Popover.closeInner.config'; +import closeInnerSizeStyles from './config/CloseInnerSize.module.css'; +import closeInnerViewStyles from './config/CloseInnerView.module.css'; +import closeNoneSizeStyles from './config/CloseNoneSize.module.css'; +import closeNoneViewStyles from './config/CloseNoneView.module.css'; -const mergedCloseNoneConfig = mergeConfig(_beta_popoverConfig, closeNoneConfig); -export const PopoverCloseNone = component(mergedCloseNoneConfig); +type BasePopoverProps = Omit; -const mergedCloseInnerConfig = mergeConfig(_beta_popoverConfig, closeInnerConfig); -export const PopoverCloseInner = component(mergedCloseInnerConfig); +type DefaultAppearanceProps = { + appearance?: 'default'; + view?: 'default' | 'info'; + size?: 'm' | 's'; +}; -export const Popover = createConditionalComponent({ - default: PopoverCloseNone, - closeInner: PopoverCloseInner, -}); +type CloseInnerAppearanceProps = { + appearance: 'closeInner'; + view?: 'default' | 'info'; + size?: 'm' | 's'; +}; + +export type PopoverProps = BasePopoverProps & (DefaultAppearanceProps | CloseInnerAppearanceProps); + +export const Popover = forwardRef( + ({ appearance = 'default', view = 'default', size = 'm', ...rest }, ref) => { + const viewStyles = appearance === 'default' ? closeNoneViewStyles : closeInnerViewStyles; + const sizeStyles = appearance === 'default' ? closeNoneSizeStyles : closeInnerSizeStyles; + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + return ( + + ); + }, +); diff --git a/packages/sdds-cs/src/components/_beta/Popover/config/CloseInnerSize.module.css b/packages/sdds-cs/src/components/_beta/Popover/config/CloseInnerSize.module.css new file mode 100644 index 00000000000..f4ec16a194e --- /dev/null +++ b/packages/sdds-cs/src/components/_beta/Popover/config/CloseInnerSize.module.css @@ -0,0 +1,19 @@ +.m { + --plasma-popover-close-icon-size: 1.5rem; + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem 0.5rem 0.5rem; + --plasma-popover-icon-offset: 0.625rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.s { + --plasma-popover-close-icon-size: 1rem; + --plasma-popover-border-radius: 0.75rem; + --plasma-popover-padding: 0.5rem 0.375rem 0.375rem; + --plasma-popover-icon-offset: 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} diff --git a/packages/sdds-cs/src/components/_beta/Popover/config/CloseInnerView.module.css b/packages/sdds-cs/src/components/_beta/Popover/config/CloseInnerView.module.css new file mode 100644 index 00000000000..27526bcdc99 --- /dev/null +++ b/packages/sdds-cs/src/components/_beta/Popover/config/CloseInnerView.module.css @@ -0,0 +1,15 @@ +.default { + --plasma-popover-background-color: var(--surface-solid-card); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); + --plasma-popover-icon-color: var(--text-secondary); + --plasma-popover-icon-color-hover: var(--text-secondary-hover); + --plasma-popover-icon-color-active: var(--text-secondary-active); +} + +.info { + --plasma-popover-background-color: var(--surface-accent); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); + --plasma-popover-icon-color: var(--on-dark-text-secondary); + --plasma-popover-icon-color-hover: var(--on-dark-text-secondary-hover); + --plasma-popover-icon-color-active: var(--on-dark-text-secondary-active); +} diff --git a/packages/sdds-cs/src/components/_beta/Popover/config/CloseNoneSize.module.css b/packages/sdds-cs/src/components/_beta/Popover/config/CloseNoneSize.module.css new file mode 100644 index 00000000000..474c367b04d --- /dev/null +++ b/packages/sdds-cs/src/components/_beta/Popover/config/CloseNoneSize.module.css @@ -0,0 +1,15 @@ +.m { + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem 0.5rem 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.s { + --plasma-popover-border-radius: 0.75rem; + --plasma-popover-padding: 0.5rem 0.375rem 0.375rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} diff --git a/packages/sdds-cs/src/components/_beta/Popover/config/CloseNoneView.module.css b/packages/sdds-cs/src/components/_beta/Popover/config/CloseNoneView.module.css new file mode 100644 index 00000000000..4ca25dd8b88 --- /dev/null +++ b/packages/sdds-cs/src/components/_beta/Popover/config/CloseNoneView.module.css @@ -0,0 +1,9 @@ +.default { + --plasma-popover-background-color: var(--surface-solid-card); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); +} + +.info { + --plasma-popover-background-color: var(--surface-accent); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); +} diff --git a/packages/sdds-cs/src/components/_beta/Popover/index.ts b/packages/sdds-cs/src/components/_beta/Popover/index.ts index 6e5a6364810..2a955281c77 100644 --- a/packages/sdds-cs/src/components/_beta/Popover/index.ts +++ b/packages/sdds-cs/src/components/_beta/Popover/index.ts @@ -1 +1,2 @@ export { Popover } from './Popover'; +export type { PopoverProps } from './Popover'; diff --git a/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.config.ts b/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.config.ts deleted file mode 100644 index f763e428072..00000000000 --- a/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.config.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { - bodyS, - bodyXS, - inverseSurfaceSolidCard, - inverseTextPrimary, - onDarkSurfaceSolidSecondary, - shadowDownHardS, -} from '@salutejs/sdds-themes/tokens/sdds_cs'; -import { css, _beta_tooltipTokens as tokens } from '@salutejs/plasma-new-hope/emotion'; - -export const config = { - defaults: { - view: 'default', - size: 's', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${inverseSurfaceSolidCard}; - ${tokens.boxShadow}: ${shadowDownHardS}; - ${tokens.color}: ${inverseTextPrimary}; - `, - secondary: css` - ${tokens.backgroundColor}: ${onDarkSurfaceSolidSecondary}; - ${tokens.boxShadow}: ${shadowDownHardS}; - ${tokens.color}: ${inverseTextPrimary}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 0.5rem; - ${tokens.padding}: 0.5rem 0.75rem; - ${tokens.gap}: 0.25rem; - ${tokens.fontFamily}: ${bodyS.fontFamily}; - ${tokens.fontSize}: ${bodyS.fontSize}; - ${tokens.fontStyle}: ${bodyS.fontStyle}; - ${tokens.fontWeight}: ${bodyS.fontWeight}; - ${tokens.letterSpacing}: ${bodyS.letterSpacing}; - ${tokens.lineHeight}: ${bodyS.lineHeight}; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.5rem; - ${tokens.padding}: 0.5rem 0.75rem; - ${tokens.gap}: 0.25rem; - ${tokens.fontFamily}: ${bodyXS.fontFamily}; - ${tokens.fontSize}: ${bodyXS.fontSize}; - ${tokens.fontStyle}: ${bodyXS.fontStyle}; - ${tokens.fontWeight}: ${bodyXS.fontWeight}; - ${tokens.letterSpacing}: ${bodyXS.letterSpacing}; - ${tokens.lineHeight}: ${bodyXS.lineHeight}; - ${tokens.tailWidth}: 14px; - ${tokens.tailHeight}: 6px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.stories.tsx b/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.stories.tsx index c5c45bbeea4..3a435f95a5a 100644 --- a/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.stories.tsx +++ b/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.stories.tsx @@ -1,15 +1,15 @@ import * as React from 'react'; import type { ComponentProps } from 'react'; import type { StoryObj, Meta } from '@storybook/react-vite'; -import { getConfigVariations } from '@salutejs/plasma-sb-utils'; import { IconPlasma } from '@salutejs/plasma-icons'; import { Button } from '../../Button'; import { Tooltip } from './Tooltip'; -import { config } from './Tooltip.config'; -type StoryProps = ComponentProps; +type StoryProps = ComponentProps & { + hasIcon?: boolean; +}; const placements = [ 'top', @@ -27,7 +27,8 @@ const placements = [ ]; const trigger = ['click', 'hover', 'focus']; -const { views } = getConfigVariations(config); +const views = ['default', 'secondary']; +const sizes = ['m', 's']; const meta: Meta = { title: '_Beta/Overlay/Tooltip', @@ -81,6 +82,12 @@ const meta: Meta = { type: 'select', }, }, + size: { + options: sizes, + control: { + type: 'select', + }, + }, hasIcon: { control: { type: 'boolean', @@ -97,13 +104,14 @@ const meta: Meta = { delayOpen: 0, delayClose: 0, view: 'default', + size: 's', hasIcon: false, }, }; export default meta; -const StoryDefault = (args: StoryProps) => { +const StoryDefault = ({ hasIcon, ...tooltipProps }: StoryProps) => { React.useEffect(() => { window.scrollTo( (document.documentElement.scrollWidth - window.innerWidth) / 2, @@ -122,9 +130,9 @@ const StoryDefault = (args: StoryProps) => { }} > : undefined} + {...tooltipProps} + iconSlot={hasIcon ? : undefined} target={} - {...args} > Контент выпадающего окна @@ -133,5 +141,5 @@ const StoryDefault = (args: StoryProps) => { }; export const Default: StoryObj = { - render: (args) => , + render: (args: StoryProps) => , }; diff --git a/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.tsx b/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.tsx index d01b6f103a2..55a31d7d263 100644 --- a/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.tsx +++ b/packages/sdds-cs/src/components/_beta/Tooltip/Tooltip.tsx @@ -1,6 +1,22 @@ -import { _beta_tooltipConfig, component, mergeConfig } from '@salutejs/plasma-new-hope/emotion'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Tooltip as CoreTooltip } from '@salutejs/plasma-new-hope/beta'; +import type { TooltipProps as CoreTooltipProps } from '@salutejs/plasma-new-hope/beta'; -import { config } from './Tooltip.config'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; -const mergedConfig = mergeConfig(_beta_tooltipConfig, config); -export const Tooltip = component(mergedConfig); +type TooltipView = 'default' | 'secondary'; +type TooltipSize = 'm' | 's'; + +export type TooltipProps = CoreTooltipProps & { + view?: TooltipView; + size?: TooltipSize; +}; + +export const Tooltip = forwardRef(({ view = 'default', size = 's', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + // @ts-expect-error _configClassName is an internal runtime property. + return ; +}); diff --git a/packages/sdds-cs/src/components/_beta/Tooltip/config/Size.module.css b/packages/sdds-cs/src/components/_beta/Tooltip/config/Size.module.css new file mode 100644 index 00000000000..19df3290184 --- /dev/null +++ b/packages/sdds-cs/src/components/_beta/Tooltip/config/Size.module.css @@ -0,0 +1,29 @@ +.m { + --plasma-tooltip-border-radius: 0.5rem; + --plasma-tooltip-padding: 0.5rem 0.75rem; + --plasma-tooltip-gap: 0.25rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-s-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-s-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-s-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-s-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-s-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-s-line-height); + --plasma-tooltip-tail-width: 20px; + --plasma-tooltip-tail-height: 8px; + --plasma-tooltip-tail-side-curvature: -10%; +} + +.s { + --plasma-tooltip-border-radius: 0.5rem; + --plasma-tooltip-padding: 0.5rem 0.75rem; + --plasma-tooltip-gap: 0.25rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-xs-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-xs-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-xs-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-xs-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-xs-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-xs-line-height); + --plasma-tooltip-tail-width: 14px; + --plasma-tooltip-tail-height: 6px; + --plasma-tooltip-tail-side-curvature: -10%; +} diff --git a/packages/sdds-cs/src/components/_beta/Tooltip/config/View.module.css b/packages/sdds-cs/src/components/_beta/Tooltip/config/View.module.css new file mode 100644 index 00000000000..d3948b8f580 --- /dev/null +++ b/packages/sdds-cs/src/components/_beta/Tooltip/config/View.module.css @@ -0,0 +1,11 @@ +.default { + --plasma-tooltip-background-color: var(--inverse-surface-solid-card); + --plasma-tooltip-box-shadow: var(--shadow-down-hard-s); + --plasma-tooltip-color: var(--inverse-text-primary); +} + +.secondary { + --plasma-tooltip-background-color: var(--on-dark-surface-solid-secondary); + --plasma-tooltip-box-shadow: var(--shadow-down-hard-s); + --plasma-tooltip-color: var(--inverse-text-primary); +} diff --git a/packages/sdds-cs/src/components/_beta/Tooltip/index.ts b/packages/sdds-cs/src/components/_beta/Tooltip/index.ts index b44d466fac2..27667e0037c 100644 --- a/packages/sdds-cs/src/components/_beta/Tooltip/index.ts +++ b/packages/sdds-cs/src/components/_beta/Tooltip/index.ts @@ -1 +1,2 @@ export { Tooltip } from './Tooltip'; +export type { TooltipProps } from './Tooltip'; diff --git a/packages/sdds-cs/src/components/_beta/css-modules.d.ts b/packages/sdds-cs/src/components/_beta/css-modules.d.ts new file mode 100644 index 00000000000..e7f258a4668 --- /dev/null +++ b/packages/sdds-cs/src/components/_beta/css-modules.d.ts @@ -0,0 +1,5 @@ +declare module '*.module.css' { + const classes: Readonly>; + + export default classes; +} diff --git a/packages/sdds-finai/package.json b/packages/sdds-finai/package.json index a88d4c9af60..0f27336defc 100644 --- a/packages/sdds-finai/package.json +++ b/packages/sdds-finai/package.json @@ -34,16 +34,6 @@ "import": "./dist/beta/es/index.js", "require": "./dist/beta/cjs/index.js", "types": "./dist/beta/types/index.d.ts" - }, - "./beta/css": { - "import": "./dist/beta/css/es/index.js", - "require": "./dist/beta/css/cjs/index.js", - "types": "./dist/beta/types/index.d.ts" - }, - "./beta/emotion": { - "import": "./dist/beta/emotion/es/index.js", - "require": "./dist/beta/emotion/cjs/index.js", - "types": "./dist/beta/types/index.d.ts" } }, "peerDependencies": { @@ -55,7 +45,8 @@ }, "dependencies": { "@salutejs/plasma-new-hope": "0.378.0", - "@salutejs/sdds-themes": "0.79.0" + "@salutejs/sdds-themes": "0.79.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", @@ -96,25 +87,21 @@ }, "scripts": { "prepare": "npm run build", - "build": "npm run build:styled-components && npm run build:css && npm run build:emotion", + "build": "npm run build:styled-components && npm run build:css && npm run build:emotion && npm run build:beta", "postbuild": "npm run generate:typings", "prebuild:css": "rm -rf src-css && ./scripts/copy-linaria-components.sh", - "build:css": "rm -rf dist/css dist/beta/css && rollup -c", + "build:css": "rm -rf dist/css && rollup -c", "postbuild:css": "rm -rf src-css", - "build:styled-components": "rm -rf dist/styled-components dist/beta/es dist/beta/cjs && npm run build:styled-components:esm && npm run build:styled-components:cjs && npm run build:beta", + "build:styled-components": "rm -rf dist/styled-components && npm run build:styled-components:esm && npm run build:styled-components:cjs", "build:styled-components:cjs": "swc ./src --ignore \"src/components/_beta/**\" -d ./dist/styled-components/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs", "build:styled-components:esm": "swc ./src --ignore \"src/components/_beta/**\" -d ./dist/styled-components/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6", - "prebuild:emotion": "rm -rf src-emotion src-beta-emotion && cp -R src src-emotion && rm -rf src-emotion/components/_beta && cp -R src/components/_beta src-beta-emotion && node ./scripts/replaceStyledComponentsToEmotion.js && node ./scripts/replaceStyledComponentsToEmotion.js src-beta-emotion", - "build:emotion": "rm -rf dist/emotion dist/beta/emotion && npm run build:emotion:esm && npm run build:emotion:cjs && npm run build:beta:emotion:esm && npm run build:beta:emotion:cjs", + "prebuild:emotion": "rm -rf src-emotion && cp -R src src-emotion && rm -rf src-emotion/components/_beta && node ./scripts/replaceStyledComponentsToEmotion.js", + "build:emotion": "rm -rf dist/emotion && npm run build:emotion:esm && npm run build:emotion:cjs", "build:emotion:cjs": "swc ./src-emotion -d ./dist/emotion/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs", "build:emotion:esm": "swc ./src-emotion -d ./dist/emotion/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6", - "build:beta:emotion:cjs": "swc ./src-beta-emotion -d ./dist/beta/emotion/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs", - "build:beta:emotion:esm": "swc ./src-beta-emotion -d ./dist/beta/emotion/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6", - "postbuild:emotion": "rm -rf src-emotion src-beta-emotion", - "build:beta": "rm -rf dist/beta/es dist/beta/cjs && npm run build:beta:esm && npm run build:beta:cjs", - "build:beta:cjs": "swc ./src/components/_beta -d ./dist/beta/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs && mv dist/beta/cjs/components/_beta/* dist/beta/cjs && rimraf dist/beta/cjs/components", - "build:beta:esm": "swc ./src/components/_beta -d ./dist/beta/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6 && mv dist/beta/es/components/_beta/* dist/beta/es && rimraf dist/beta/es/components", - "generate:typings": "rm -rf types && tsc && rm -rf dist/beta/types && tsc -p src/components/_beta/tsconfig.json", + "postbuild:emotion": "rm -rf src-emotion", + "build:beta": "rm -rf dist/beta && rollup -c rollup.beta.config.mjs", + "generate:typings": "tsc && tsc -p src/components/_beta/tsconfig.json", "storybook": "storybook dev -p ${PORT:-7007} -c .storybook", "storybook:draft": "IS_DRAFT=true storybook dev -p ${PORT:-7007} -c .storybook", "storybook:build:draft": "IS_DRAFT=true storybook build -c .storybook -o build-sb-draft", diff --git a/packages/sdds-finai/rollup.beta.config.mjs b/packages/sdds-finai/rollup.beta.config.mjs new file mode 100644 index 00000000000..0c263c7e3a9 --- /dev/null +++ b/packages/sdds-finai/rollup.beta.config.mjs @@ -0,0 +1,121 @@ +import path from 'path'; +import { createHash } from 'crypto'; +import { fileURLToPath } from 'url'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { babel } from '@rollup/plugin-babel'; +import styles from '@ironkinoko/rollup-plugin-styles'; + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); +const betaSourceDir = path.resolve(dirname, 'src/components/_beta'); +const extractedCssModules = new Map(); + +export default { + input: { + index: path.join(betaSourceDir, 'index.ts'), + }, + treeshake: { + propertyReadSideEffects: false, + }, + output: [ + { + preserveModules: true, + dir: 'dist/beta/es', + format: 'es', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + }, + { + preserveModules: true, + dir: 'dist/beta/cjs', + format: 'cjs', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + interop: 'auto', + }, + ], + external: (id) => { + if (id.startsWith('regenerator-runtime') || id === 'tslib') { + return false; + } + + return !id.startsWith('.') && !path.isAbsolute(id); + }, + plugins: [ + nodeResolve({ + extensions: ['.tsx', '.ts'], + }), + styles({ + mode: 'extract', + modules: { + generateScopedName(localName, file, css) { + const relativePath = path.relative(betaSourceDir, file).split(path.sep).join('/'); + const componentName = relativePath.split('/')[0]; + const fileName = path.basename(file, '.module.css'); + const hash = createHash('sha256') + .update(`${relativePath}:${localName}:${css}`) + .digest('hex') + .slice(0, 8); + + return `${componentName}_${fileName}_${localName}__${hash}`; + }, + }, + onExtract({ name, css }) { + const moduleName = name.replace(/\.css$/, ''); + + if (moduleName.endsWith('.module.css')) { + extractedCssModules.set(moduleName, css); + } + + return false; + }, + }), + emitCssModulesPlugin(), + babel({ + babelHelpers: 'bundled', + extensions: ['.ts', '.tsx'], + }), + ], +}; + +function emitCssModulesPlugin() { + return { + name: 'emitCssModulesPlugin', + generateBundle: { + order: 'post', + handler(options, bundle) { + Object.values(bundle).forEach((file) => { + if (file.type !== 'chunk' || !file.fileName.endsWith('.module.css.js')) { + return; + } + + const moduleName = file.fileName.replace(/\.js$/, ''); + const css = extractedCssModules.get(moduleName); + + if (css === undefined) { + this.error(`Processed CSS Module was not found for ${file.fileName}`); + } + + const cssFileName = file.fileName.replace(/\.module\.css\.js$/, '.css'); + const relativeCssPath = `./${path.posix.relative(path.posix.dirname(file.fileName), cssFileName)}`; + const importCss = + options.format === 'cjs' + ? `require('${relativeCssPath}');\n` + : `import '${relativeCssPath}';\n`; + + file.code = importCss + file.code; + + this.emitFile({ + type: 'asset', + fileName: cssFileName, + source: css, + }); + }); + }, + }, + }; +} diff --git a/packages/sdds-finai/rollup.config.mjs b/packages/sdds-finai/rollup.config.mjs index f34d89c0c0b..bc0d86bed53 100644 --- a/packages/sdds-finai/rollup.config.mjs +++ b/packages/sdds-finai/rollup.config.mjs @@ -78,7 +78,7 @@ const createConfig = (inputFile, outputDir) => ({ ], }); -export default [createConfig('index.ts', 'dist/css'), createConfig('beta.ts', 'dist/beta/css')]; +export default createConfig('index.ts', 'dist/css'); function importCssPlugin() { const filter = createFilter(['**/*.css']); diff --git a/packages/sdds-finai/scripts/copy-linaria-components.sh b/packages/sdds-finai/scripts/copy-linaria-components.sh index 7c08d77b550..a81b21f4d20 100755 --- a/packages/sdds-finai/scripts/copy-linaria-components.sh +++ b/packages/sdds-finai/scripts/copy-linaria-components.sh @@ -10,9 +10,6 @@ for component in $components; do grep -E "\<$component\>" src/index.ts >> src-css/index.ts done -cp -R src/components/_beta src-css/components/_beta -echo "export * from './components/_beta';" > src-css/beta.ts - # remove unused tests and stories find src-css/components \( -name '*.component-test.tsx' -o -name '*.stories.tsx' \) -delete diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.config.ts b/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.config.ts deleted file mode 100644 index 4e56f3f486f..00000000000 --- a/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.config.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { css, _beta_embeddedButtonTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { - surfaceAccent, - textAccent, - textAccentActive, - textAccentGradient, - textAccentHover, - textInfo, - textInfoActive, - textInfoHover, - textNegative, - textNegativeActive, - textNegativeHover, - textPositive, - textPositiveActive, - textPositiveHover, - textPrimary, - textPrimaryActive, - textPrimaryHover, - textSecondary, - textSecondaryActive, - textSecondaryHover, - textWarning, - textWarningActive, - textWarningHover, -} from '@salutejs/sdds-themes/tokens/sdds_finai'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.color}: ${textPrimary}; - ${tokens.colorHover}: ${textPrimaryHover}; - ${tokens.colorActive}: ${textPrimaryActive}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textPrimary}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - secondary: css` - ${tokens.color}: ${textSecondary}; - ${tokens.colorHover}: ${textSecondaryHover}; - ${tokens.colorActive}: ${textSecondaryActive}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textSecondary}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - accent: css` - ${tokens.color}: ${textAccent}; - ${tokens.colorHover}: ${textAccentHover}; - ${tokens.colorActive}: ${textAccentActive}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textAccent}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - positive: css` - ${tokens.color}: ${textPositive}; - ${tokens.colorHover}: ${textPositiveHover}; - ${tokens.colorActive}: ${textPositiveActive}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textPositive}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - warning: css` - ${tokens.color}: ${textWarning}; - ${tokens.colorHover}: ${textWarningHover}; - ${tokens.colorActive}: ${textWarningActive}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textWarning}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - negative: css` - ${tokens.color}: ${textNegative}; - ${tokens.colorHover}: ${textNegativeHover}; - ${tokens.colorActive}: ${textNegativeActive}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textNegative}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - info: css` - ${tokens.color}: ${textInfo}; - ${tokens.colorHover}: ${textInfoHover}; - ${tokens.colorActive}: ${textInfoActive}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textInfo}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - gradient: css` - ${tokens.color}: ${textAccentGradient}; - ${tokens.colorHover}: ${textAccentGradient}; - ${tokens.colorActive}: ${textAccentGradient}; - ${tokens.backgroundColor}: transparent; - ${tokens.spinnerColor}: ${textAccentGradient}; - ${tokens.focusColor}: ${surfaceAccent}; - ${tokens.loadingIconOpacity}: 0.06; - `, - }, - size: { - l: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.spinnerSize}: 2.25rem; - `, - m: css` - ${tokens.borderRadius}: 0.625rem; - ${tokens.spinnerSize}: 1.5rem; - `, - s: css` - ${tokens.borderRadius}: 0.5rem; - ${tokens.spinnerSize}: 1rem; - `, - xs: css` - ${tokens.borderRadius}: 0.375rem; - ${tokens.spinnerSize}: 0.75rem; - `, - }, - disabled: { - true: css` - ${tokens.disabledOpacity}: 0.4; - `, - }, - }, -}; diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.stories.tsx b/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.stories.tsx index 580ef4a0ad6..ec359364bba 100644 --- a/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.stories.tsx +++ b/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.stories.tsx @@ -1,23 +1,68 @@ import React from 'react'; import type { ComponentProps } from 'react'; -import type { Meta } from '@storybook/react-vite'; -import { getEmbeddedButtonStories } from '@salutejs/plasma-sb-utils'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { IconPlasma } from '@salutejs/plasma-icons'; +import { InSpacingDecorator } from '@salutejs/plasma-sb-utils'; import { EmbeddedButton } from './EmbeddedButton'; -import { config } from './EmbeddedButton.config'; -type EmbeddedButtonProps = ComponentProps; +type StoryProps = ComponentProps & { + buttonContainerWidth?: string; + buttonContainerHeight?: string; +}; -const { meta: META, Default } = getEmbeddedButtonStories({ - component: EmbeddedButton, - componentConfig: config, -}); +const views = ['default', 'secondary', 'accent', 'positive', 'warning', 'negative', 'info']; +const sizes = ['l', 'm', 's', 'xs']; +const positions = [ + 'center', + 'center-left', + 'center-right', + 'top', + 'top-left', + 'top-right', + 'bottom', + 'bottom-left', + 'bottom-right', +]; +const iconSizeMap = { + l: '2.25rem', + m: '1.5rem', + s: '1rem', + xs: '0.75rem', +}; -const meta: Meta = { - ...META, +const meta: Meta = { title: '_Beta/Data Entry/EmbeddedButton', + component: EmbeddedButton, + decorators: [InSpacingDecorator], + argTypes: { + view: { options: views, control: 'select' }, + size: { options: sizes, control: 'select' }, + position: { options: positions, control: 'select' }, + disabled: { control: 'boolean' }, + isLoading: { control: 'boolean' }, + buttonContainerWidth: { control: 'text', table: { category: 'example-related' } }, + buttonContainerHeight: { control: 'text', table: { category: 'example-related' } }, + }, + args: { + buttonContainerWidth: '10rem', + buttonContainerHeight: '10rem', + view: 'default', + size: 'm', + position: 'center', + disabled: false, + isLoading: false, + }, }; export default meta; -export { Default }; +export const Default: StoryObj = { + render: ({ buttonContainerWidth, buttonContainerHeight, size = 'm', ...rest }) => ( +
+ + + +
+ ), +}; diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.ts b/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.ts deleted file mode 100644 index 18a84ca13f6..00000000000 --- a/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { _beta_embeddedButtonConfig, component, mergeConfig } from '@salutejs/plasma-new-hope/styled-components'; - -import { config } from './EmbeddedButton.config'; - -const mergedConfig = mergeConfig(_beta_embeddedButtonConfig, config); -export const EmbeddedButton = component(mergedConfig); diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.tsx b/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.tsx new file mode 100644 index 00000000000..32945a850e0 --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/EmbeddedButton/EmbeddedButton.tsx @@ -0,0 +1,25 @@ +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { EmbeddedButton as CoreEmbeddedButton } from '@salutejs/plasma-new-hope/beta'; +import type { EmbeddedButtonProps as CoreEmbeddedButtonProps } from '@salutejs/plasma-new-hope/beta'; + +import disabledStyles from './config/Disabled.module.css'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; + +type EmbeddedButtonView = 'default' | 'secondary' | 'accent' | 'positive' | 'warning' | 'negative' | 'info'; +type EmbeddedButtonSize = 'l' | 'm' | 's' | 'xs'; + +export type EmbeddedButtonProps = CoreEmbeddedButtonProps & { + view?: EmbeddedButtonView; + size?: EmbeddedButtonSize; +}; + +export const EmbeddedButton = forwardRef( + ({ view = 'default', size = 'm', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size], rest.disabled && disabledStyles.disabled); + + // @ts-expect-error _configClassName is an internal runtime property. + return ; + }, +); diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/Disabled.module.css b/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/Disabled.module.css new file mode 100644 index 00000000000..e43dd3fca3b --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/Disabled.module.css @@ -0,0 +1,3 @@ +.disabled { + --plasma-embedded-button-disabled-opacity: 0.4; +} diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/Size.module.css b/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/Size.module.css new file mode 100644 index 00000000000..f32385724ad --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/Size.module.css @@ -0,0 +1,19 @@ +.l { + --plasma-embedded-button-border-radius: 0.75rem; + --plasma-embedded-button-spinner-size: 2.25rem; +} + +.m { + --plasma-embedded-button-border-radius: 0.625rem; + --plasma-embedded-button-spinner-size: 1.5rem; +} + +.s { + --plasma-embedded-button-border-radius: 0.5rem; + --plasma-embedded-button-spinner-size: 1rem; +} + +.xs { + --plasma-embedded-button-border-radius: 0.375rem; + --plasma-embedded-button-spinner-size: 0.75rem; +} diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/View.module.css b/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/View.module.css new file mode 100644 index 00000000000..7901ad477fc --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/EmbeddedButton/config/View.module.css @@ -0,0 +1,77 @@ +.default { --plasma-embedded-button-color: var(--text-primary); --plasma-embedded-button-color-hover: var(--text-primary-hover); + --plasma-embedded-button-color-active: var(--text-primary-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-primary); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.secondary { + --plasma-embedded-button-color: var(--text-secondary); + --plasma-embedded-button-color-hover: var(--text-secondary-hover); + --plasma-embedded-button-color-active: var(--text-secondary-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-secondary); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.accent { + --plasma-embedded-button-color: var(--text-accent); + --plasma-embedded-button-color-hover: var(--text-accent-hover); + --plasma-embedded-button-color-active: var(--text-accent-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-accent); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.positive { + --plasma-embedded-button-color: var(--text-positive); + --plasma-embedded-button-color-hover: var(--text-positive-hover); + --plasma-embedded-button-color-active: var(--text-positive-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-positive); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.warning { + --plasma-embedded-button-color: var(--text-warning); + --plasma-embedded-button-color-hover: var(--text-warning-hover); + --plasma-embedded-button-color-active: var(--text-warning-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-warning); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.negative { + --plasma-embedded-button-color: var(--text-negative); + --plasma-embedded-button-color-hover: var(--text-negative-hover); + --plasma-embedded-button-color-active: var(--text-negative-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-negative); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.info { + --plasma-embedded-button-color: var(--text-info); + --plasma-embedded-button-color-hover: var(--text-info-hover); + --plasma-embedded-button-color-active: var(--text-info-active); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-info); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} + +.gradient { + --plasma-embedded-button-color: var(--text-accent-gradient); + --plasma-embedded-button-color-hover: var(--text-accent-gradient); + --plasma-embedded-button-color-active: var(--text-accent-gradient); + --plasma-embedded-button-background-color: transparent; + --plasma-embedded-button-spinner-color: var(--text-accent-gradient); + --plasma-embedded-button-focus-color: var(--surface-accent); + --plasma-embedded-button-loading-icon-opacity: 0.06; +} diff --git a/packages/sdds-finai/src/components/_beta/EmbeddedButton/index.ts b/packages/sdds-finai/src/components/_beta/EmbeddedButton/index.ts index a9c95bc52e7..25560896945 100644 --- a/packages/sdds-finai/src/components/_beta/EmbeddedButton/index.ts +++ b/packages/sdds-finai/src/components/_beta/EmbeddedButton/index.ts @@ -1 +1,2 @@ export { EmbeddedButton } from './EmbeddedButton'; +export type { EmbeddedButtonProps } from './EmbeddedButton'; diff --git a/packages/sdds-finai/src/components/_beta/Popover/Popover.closeInner.config.ts b/packages/sdds-finai/src/components/_beta/Popover/Popover.closeInner.config.ts deleted file mode 100644 index 548765e35b5..00000000000 --- a/packages/sdds-finai/src/components/_beta/Popover/Popover.closeInner.config.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { css, _beta_popoverTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { - onDarkTextSecondary, - onDarkTextSecondaryActive, - onDarkTextSecondaryHover, - shadowDownHardM, - surfaceAccent, - surfaceSolidCard, - textSecondary, - textSecondaryActive, - textSecondaryHover, -} from '@salutejs/sdds-themes/tokens/sdds_finai'; - -export const config = { - defaults: { - view: 'action', - size: 'm', - }, - variations: { - view: { - action: css` - ${tokens.backgroundColor}: ${surfaceSolidCard}; - ${tokens.boxShadow}: ${shadowDownHardM}; - ${tokens.iconColor}: ${textSecondary}; - ${tokens.iconColorHover}: ${textSecondaryHover}; - ${tokens.iconColorActive}: ${textSecondaryActive}; - `, - info: css` - ${tokens.backgroundColor}: ${surfaceAccent}; - ${tokens.boxShadow}: ${shadowDownHardM}; - ${tokens.iconColor}: ${onDarkTextSecondary}; - ${tokens.iconColorHover}: ${onDarkTextSecondaryHover}; - ${tokens.iconColorActive}: ${onDarkTextSecondaryActive}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem 0.5rem 0.5rem 0.5rem; - ${tokens.iconOffset}: 0.625rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.padding}: 0.5rem 0.375rem 0.375rem 0.375rem; - ${tokens.iconOffset}: 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/sdds-finai/src/components/_beta/Popover/Popover.closeNone.config.ts b/packages/sdds-finai/src/components/_beta/Popover/Popover.closeNone.config.ts deleted file mode 100644 index a99c2babbdc..00000000000 --- a/packages/sdds-finai/src/components/_beta/Popover/Popover.closeNone.config.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { css, _beta_popoverTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { shadowDownHardM, surfaceAccent, surfaceSolidCard } from '@salutejs/sdds-themes/tokens/sdds_finai'; - -export const config = { - defaults: { - view: 'action', - size: 'm', - }, - variations: { - view: { - action: css` - ${tokens.backgroundColor}: ${surfaceSolidCard}; - ${tokens.boxShadow}: ${shadowDownHardM}; - `, - info: css` - ${tokens.backgroundColor}: ${surfaceAccent}; - ${tokens.boxShadow}: ${shadowDownHardM}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem 0.5rem 0.5rem 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.75rem; - ${tokens.padding}: 0.5rem 0.375rem 0.375rem 0.375rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/sdds-finai/src/components/_beta/Popover/Popover.stories.tsx b/packages/sdds-finai/src/components/_beta/Popover/Popover.stories.tsx index e4c8bfa1cda..9177bddea3f 100644 --- a/packages/sdds-finai/src/components/_beta/Popover/Popover.stories.tsx +++ b/packages/sdds-finai/src/components/_beta/Popover/Popover.stories.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import type { ComponentProps } from 'react'; import type { StoryObj, Meta } from '@storybook/react-vite'; -import { getConfigVariations } from '@salutejs/plasma-sb-utils'; import { Cell, CellTextbox, CellTextboxTitle, CellTextboxSubtitle } from '../../Cell'; import { Button } from '../../Button'; @@ -9,12 +8,22 @@ import { ButtonGroup } from '../../ButtonGroup'; import { ViewContainer } from '../../ViewContainer'; import { Popover } from './Popover'; -import { config } from './Popover.closeNone.config'; -type StoryProps = ComponentProps; +type ResizableOptions = Exclude['resizable'], boolean | undefined>; +type StoryProps = ComponentProps & { + resizableDirections?: ResizableOptions['directions']; + resizableHiddenIcons?: ResizableOptions['hiddenIcons']; + resizableDefaultSize?: ResizableOptions['defaultSize']; + resizableMinWidth?: ResizableOptions['minWidth']; + resizableMinHeight?: ResizableOptions['minHeight']; + resizableMaxWidth?: ResizableOptions['maxWidth']; + resizableMaxHeight?: ResizableOptions['maxHeight']; + resizableIconSize?: ResizableOptions['iconSize']; +}; -const { views, sizes } = getConfigVariations(config); -const appearance = ['closeNone', 'closeInner']; +const views = ['action', 'info']; +const sizes = ['m', 's']; +const appearance = ['default', 'closeInner']; const placements = [ 'top', 'top-start', @@ -107,7 +116,7 @@ const meta: Meta = { }, }, args: { - appearance: 'closeNone', + appearance: 'default', placement: 'bottom', trigger: 'click', defaultOpened: false, @@ -162,7 +171,7 @@ const StoryDefault = (args: StoryProps) => { }; export const Default: StoryObj = { - render: (args) => , + render: (args: StoryProps) => , }; const StoryResizable = (args: StoryProps) => { @@ -175,6 +184,7 @@ const StoryResizable = (args: StoryProps) => { resizableMaxWidth, resizableMaxHeight, resizableIconSize, + ...popoverProps } = args; React.useEffect(() => { @@ -202,6 +212,7 @@ const StoryResizable = (args: StoryProps) => { }} > { maxHeight: resizableMaxHeight, iconSize: resizableIconSize, }} - {...args} target={} >
= { resizableMinWidth: 300, resizableMinHeight: 300, }, - render: (args) => , + render: (args: StoryProps) => , }; diff --git a/packages/sdds-finai/src/components/_beta/Popover/Popover.tsx b/packages/sdds-finai/src/components/_beta/Popover/Popover.tsx index 72bf3c58a6a..4b31533fe35 100644 --- a/packages/sdds-finai/src/components/_beta/Popover/Popover.tsx +++ b/packages/sdds-finai/src/components/_beta/Popover/Popover.tsx @@ -1,20 +1,43 @@ -import { - _beta_popoverConfig, - component, - createConditionalComponent, - mergeConfig, -} from '@salutejs/plasma-new-hope/styled-components'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Popover as CorePopover } from '@salutejs/plasma-new-hope/beta'; +import type { PopoverProps as CorePopoverProps } from '@salutejs/plasma-new-hope/beta'; -import { config as closeNoneConfig } from './Popover.closeNone.config'; -import { config as closeInnerConfig } from './Popover.closeInner.config'; +import closeInnerSizeStyles from './config/CloseInnerSize.module.css'; +import closeInnerViewStyles from './config/CloseInnerView.module.css'; +import closeNoneSizeStyles from './config/CloseNoneSize.module.css'; +import closeNoneViewStyles from './config/CloseNoneView.module.css'; -const mergedCloseNoneConfig = mergeConfig(_beta_popoverConfig, closeNoneConfig); -export const PopoverCloseNone = component(mergedCloseNoneConfig); +type BasePopoverProps = Omit; -const mergedCloseInnerConfig = mergeConfig(_beta_popoverConfig, closeInnerConfig); -export const PopoverCloseInner = component(mergedCloseInnerConfig); +type DefaultAppearanceProps = { + appearance?: 'default'; + view?: 'action' | 'info'; + size?: 'm' | 's'; +}; -export const Popover = createConditionalComponent({ - default: PopoverCloseNone, - closeInner: PopoverCloseInner, -}); +type CloseInnerAppearanceProps = { + appearance: 'closeInner'; + view?: 'action' | 'info'; + size?: 'm' | 's'; +}; + +export type PopoverProps = BasePopoverProps & (DefaultAppearanceProps | CloseInnerAppearanceProps); + +export const Popover = forwardRef( + ({ appearance = 'default', view = 'action', size = 'm', ...rest }, ref) => { + const viewStyles = appearance === 'default' ? closeNoneViewStyles : closeInnerViewStyles; + const sizeStyles = appearance === 'default' ? closeNoneSizeStyles : closeInnerSizeStyles; + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + return ( + + ); + }, +); diff --git a/packages/sdds-finai/src/components/_beta/Popover/config/CloseInnerSize.module.css b/packages/sdds-finai/src/components/_beta/Popover/config/CloseInnerSize.module.css new file mode 100644 index 00000000000..f4ec16a194e --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/Popover/config/CloseInnerSize.module.css @@ -0,0 +1,19 @@ +.m { + --plasma-popover-close-icon-size: 1.5rem; + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem 0.5rem 0.5rem; + --plasma-popover-icon-offset: 0.625rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.s { + --plasma-popover-close-icon-size: 1rem; + --plasma-popover-border-radius: 0.75rem; + --plasma-popover-padding: 0.5rem 0.375rem 0.375rem; + --plasma-popover-icon-offset: 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} diff --git a/packages/sdds-finai/src/components/_beta/Popover/config/CloseInnerView.module.css b/packages/sdds-finai/src/components/_beta/Popover/config/CloseInnerView.module.css new file mode 100644 index 00000000000..d70ca8d3bc5 --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/Popover/config/CloseInnerView.module.css @@ -0,0 +1,15 @@ +.action { + --plasma-popover-background-color: var(--surface-solid-card); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); + --plasma-popover-icon-color: var(--text-secondary); + --plasma-popover-icon-color-hover: var(--text-secondary-hover); + --plasma-popover-icon-color-active: var(--text-secondary-active); +} + +.info { + --plasma-popover-background-color: var(--surface-accent); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); + --plasma-popover-icon-color: var(--on-dark-text-secondary); + --plasma-popover-icon-color-hover: var(--on-dark-text-secondary-hover); + --plasma-popover-icon-color-active: var(--on-dark-text-secondary-active); +} diff --git a/packages/sdds-finai/src/components/_beta/Popover/config/CloseNoneSize.module.css b/packages/sdds-finai/src/components/_beta/Popover/config/CloseNoneSize.module.css new file mode 100644 index 00000000000..474c367b04d --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/Popover/config/CloseNoneSize.module.css @@ -0,0 +1,15 @@ +.m { + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem 0.5rem 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} + +.s { + --plasma-popover-border-radius: 0.75rem; + --plasma-popover-padding: 0.5rem 0.375rem 0.375rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: -10%; +} diff --git a/packages/sdds-finai/src/components/_beta/Popover/config/CloseNoneView.module.css b/packages/sdds-finai/src/components/_beta/Popover/config/CloseNoneView.module.css new file mode 100644 index 00000000000..e03d1a880e7 --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/Popover/config/CloseNoneView.module.css @@ -0,0 +1,9 @@ +.action { + --plasma-popover-background-color: var(--surface-solid-card); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); +} + +.info { + --plasma-popover-background-color: var(--surface-accent); + --plasma-popover-box-shadow: var(--shadow-down-hard-m); +} diff --git a/packages/sdds-finai/src/components/_beta/Popover/index.ts b/packages/sdds-finai/src/components/_beta/Popover/index.ts index 6e5a6364810..2a955281c77 100644 --- a/packages/sdds-finai/src/components/_beta/Popover/index.ts +++ b/packages/sdds-finai/src/components/_beta/Popover/index.ts @@ -1 +1,2 @@ export { Popover } from './Popover'; +export type { PopoverProps } from './Popover'; diff --git a/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.config.ts b/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.config.ts deleted file mode 100644 index d67df20139c..00000000000 --- a/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.config.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { css, _beta_tooltipTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { - bodyS, - bodyXS, - inverseSurfaceSolidCardBrightness, - inverseTextPrimary, - shadowDownHardM, -} from '@salutejs/sdds-themes/tokens/sdds_finai'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${inverseSurfaceSolidCardBrightness}; - ${tokens.boxShadow}: ${shadowDownHardM}; - ${tokens.color}: ${inverseTextPrimary}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 0.625rem; - ${tokens.padding}: 0.75rem 0.875rem; - ${tokens.gap}: 0.375rem; - ${tokens.fontFamily}: ${bodyS.fontFamily}; - ${tokens.fontSize}: ${bodyS.fontSize}; - ${tokens.fontStyle}: ${bodyS.fontStyle}; - ${tokens.fontWeight}: ${bodyS.fontWeight}; - ${tokens.letterSpacing}: ${bodyS.letterSpacing}; - ${tokens.lineHeight}: ${bodyS.lineHeight}; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: -10%; - `, - s: css` - ${tokens.borderRadius}: 0.5rem; - ${tokens.padding}: 0.5rem 0.75rem; - ${tokens.gap}: 0.25rem; - ${tokens.fontFamily}: ${bodyXS.fontFamily}; - ${tokens.fontSize}: ${bodyXS.fontSize}; - ${tokens.fontStyle}: ${bodyXS.fontStyle}; - ${tokens.fontWeight}: ${bodyXS.fontWeight}; - ${tokens.letterSpacing}: ${bodyXS.letterSpacing}; - ${tokens.lineHeight}: ${bodyXS.lineHeight}; - ${tokens.tailWidth}: 14px; - ${tokens.tailHeight}: 6px; - ${tokens.tailSideCurvature}: -10%; - `, - }, - }, -}; diff --git a/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.stories.tsx b/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.stories.tsx index a9d32df29b1..dd8ce6531ef 100644 --- a/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.stories.tsx +++ b/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.stories.tsx @@ -7,7 +7,9 @@ import { Button } from '../../Button'; import { Tooltip } from './Tooltip'; -type StoryProps = ComponentProps; +type StoryProps = ComponentProps & { + hasIcon?: boolean; +}; const placements = [ 'top', @@ -108,7 +110,7 @@ const meta: Meta = { export default meta; -const StoryDefault = (args: StoryProps) => { +const StoryDefault = ({ hasIcon, ...tooltipProps }: StoryProps) => { React.useEffect(() => { window.scrollTo( (document.documentElement.scrollWidth - window.innerWidth) / 2, @@ -127,9 +129,9 @@ const StoryDefault = (args: StoryProps) => { }} > : undefined} + {...tooltipProps} + iconSlot={hasIcon ? : undefined} target={} - {...args} > Контент выпадающего окна diff --git a/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.tsx b/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.tsx index ed219dfa125..a2af7cebba5 100644 --- a/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.tsx +++ b/packages/sdds-finai/src/components/_beta/Tooltip/Tooltip.tsx @@ -1,6 +1,22 @@ -import { _beta_tooltipConfig, component, mergeConfig } from '@salutejs/plasma-new-hope/styled-components'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Tooltip as CoreTooltip } from '@salutejs/plasma-new-hope/beta'; +import type { TooltipProps as CoreTooltipProps } from '@salutejs/plasma-new-hope/beta'; -import { config } from './Tooltip.config'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; -const mergedConfig = mergeConfig(_beta_tooltipConfig, config); -export const Tooltip = component(mergedConfig); +type TooltipView = 'default'; +type TooltipSize = 'm' | 's'; + +export type TooltipProps = CoreTooltipProps & { + view?: TooltipView; + size?: TooltipSize; +}; + +export const Tooltip = forwardRef(({ view = 'default', size = 'm', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + // @ts-expect-error _configClassName is an internal runtime property. + return ; +}); diff --git a/packages/sdds-finai/src/components/_beta/Tooltip/config/Size.module.css b/packages/sdds-finai/src/components/_beta/Tooltip/config/Size.module.css new file mode 100644 index 00000000000..327e31834e4 --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/Tooltip/config/Size.module.css @@ -0,0 +1,29 @@ +.m { + --plasma-tooltip-border-radius: 0.625rem; + --plasma-tooltip-padding: 0.75rem 0.875rem; + --plasma-tooltip-gap: 0.375rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-s-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-s-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-s-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-s-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-s-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-s-line-height); + --plasma-tooltip-tail-width: 20px; + --plasma-tooltip-tail-height: 8px; + --plasma-tooltip-tail-side-curvature: -10%; +} + +.s { + --plasma-tooltip-border-radius: 0.5rem; + --plasma-tooltip-padding: 0.5rem 0.75rem; + --plasma-tooltip-gap: 0.25rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-xs-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-xs-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-xs-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-xs-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-xs-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-xs-line-height); + --plasma-tooltip-tail-width: 14px; + --plasma-tooltip-tail-height: 6px; + --plasma-tooltip-tail-side-curvature: -10%; +} diff --git a/packages/sdds-finai/src/components/_beta/Tooltip/config/View.module.css b/packages/sdds-finai/src/components/_beta/Tooltip/config/View.module.css new file mode 100644 index 00000000000..ba9359319b0 --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/Tooltip/config/View.module.css @@ -0,0 +1,5 @@ +.default { + --plasma-tooltip-background-color: var(--inverse-surface-solid-card-brightness); + --plasma-tooltip-box-shadow: var(--shadow-down-hard-m); + --plasma-tooltip-color: var(--inverse-text-primary); +} diff --git a/packages/sdds-finai/src/components/_beta/Tooltip/index.ts b/packages/sdds-finai/src/components/_beta/Tooltip/index.ts index b44d466fac2..27667e0037c 100644 --- a/packages/sdds-finai/src/components/_beta/Tooltip/index.ts +++ b/packages/sdds-finai/src/components/_beta/Tooltip/index.ts @@ -1 +1,2 @@ export { Tooltip } from './Tooltip'; +export type { TooltipProps } from './Tooltip'; diff --git a/packages/sdds-finai/src/components/_beta/css-modules.d.ts b/packages/sdds-finai/src/components/_beta/css-modules.d.ts new file mode 100644 index 00000000000..e7f258a4668 --- /dev/null +++ b/packages/sdds-finai/src/components/_beta/css-modules.d.ts @@ -0,0 +1,5 @@ +declare module '*.module.css' { + const classes: Readonly>; + + export default classes; +} diff --git a/packages/sdds-insol-next/package.json b/packages/sdds-insol-next/package.json index 541032577ab..3d96e56ab9e 100644 --- a/packages/sdds-insol-next/package.json +++ b/packages/sdds-insol-next/package.json @@ -38,7 +38,8 @@ }, "dependencies": { "@salutejs/plasma-new-hope": "0.378.0", - "@salutejs/sdds-themes": "0.79.0" + "@salutejs/sdds-themes": "0.79.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", @@ -82,12 +83,10 @@ "build:css": "rm -rf dist/css && rollup -c", "postbuild:css": "rm -rf src-css", "build:styled-components": "rm -rf dist/styled-components && npm run build:styled-components:esm && npm run build:styled-components:cjs", - "build:styled-components:cjs": "swc ./src -d ./dist/styled-components/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs", - "build:styled-components:esm": "swc ./src -d ./dist/styled-components/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6", - "prebuild:beta": "rm -rf src-css && ./scripts/copy-linaria-components.sh", - "build:beta": "rm -rf dist/beta/es dist/beta/cjs && BETA=true rollup -c", - "postbuild:beta": "rm -rf src-css", - "generate:typings": "rm -rf types && tsc && rm -rf dist/beta/types && tsc -p src/components/_beta/tsconfig.json", + "build:styled-components:cjs": "swc ./src --ignore \"src/components/_beta/**\" -d ./dist/styled-components/cjs --strip-leading-paths --config-file ../../swc.config.json -C module.type=commonjs", + "build:styled-components:esm": "swc ./src --ignore \"src/components/_beta/**\" -d ./dist/styled-components/es --strip-leading-paths --config-file ../../swc.config.json -C module.type=es6", + "build:beta": "rm -rf dist/beta && rollup -c rollup.beta.config.mjs", + "generate:typings": "tsc && tsc -p src/components/_beta/tsconfig.json", "storybook": "npm run storybook:sc", "storybook:sc": "USE_STYLED_COMPONENTS=true storybook dev -p ${PORT:-7002} -c .storybook", "storybook:build": "storybook build -c .storybook -o build-sb", diff --git a/packages/sdds-insol-next/rollup.beta.config.mjs b/packages/sdds-insol-next/rollup.beta.config.mjs new file mode 100644 index 00000000000..0c263c7e3a9 --- /dev/null +++ b/packages/sdds-insol-next/rollup.beta.config.mjs @@ -0,0 +1,121 @@ +import path from 'path'; +import { createHash } from 'crypto'; +import { fileURLToPath } from 'url'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { babel } from '@rollup/plugin-babel'; +import styles from '@ironkinoko/rollup-plugin-styles'; + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); +const betaSourceDir = path.resolve(dirname, 'src/components/_beta'); +const extractedCssModules = new Map(); + +export default { + input: { + index: path.join(betaSourceDir, 'index.ts'), + }, + treeshake: { + propertyReadSideEffects: false, + }, + output: [ + { + preserveModules: true, + dir: 'dist/beta/es', + format: 'es', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + }, + { + preserveModules: true, + dir: 'dist/beta/cjs', + format: 'cjs', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + interop: 'auto', + }, + ], + external: (id) => { + if (id.startsWith('regenerator-runtime') || id === 'tslib') { + return false; + } + + return !id.startsWith('.') && !path.isAbsolute(id); + }, + plugins: [ + nodeResolve({ + extensions: ['.tsx', '.ts'], + }), + styles({ + mode: 'extract', + modules: { + generateScopedName(localName, file, css) { + const relativePath = path.relative(betaSourceDir, file).split(path.sep).join('/'); + const componentName = relativePath.split('/')[0]; + const fileName = path.basename(file, '.module.css'); + const hash = createHash('sha256') + .update(`${relativePath}:${localName}:${css}`) + .digest('hex') + .slice(0, 8); + + return `${componentName}_${fileName}_${localName}__${hash}`; + }, + }, + onExtract({ name, css }) { + const moduleName = name.replace(/\.css$/, ''); + + if (moduleName.endsWith('.module.css')) { + extractedCssModules.set(moduleName, css); + } + + return false; + }, + }), + emitCssModulesPlugin(), + babel({ + babelHelpers: 'bundled', + extensions: ['.ts', '.tsx'], + }), + ], +}; + +function emitCssModulesPlugin() { + return { + name: 'emitCssModulesPlugin', + generateBundle: { + order: 'post', + handler(options, bundle) { + Object.values(bundle).forEach((file) => { + if (file.type !== 'chunk' || !file.fileName.endsWith('.module.css.js')) { + return; + } + + const moduleName = file.fileName.replace(/\.js$/, ''); + const css = extractedCssModules.get(moduleName); + + if (css === undefined) { + this.error(`Processed CSS Module was not found for ${file.fileName}`); + } + + const cssFileName = file.fileName.replace(/\.module\.css\.js$/, '.css'); + const relativeCssPath = `./${path.posix.relative(path.posix.dirname(file.fileName), cssFileName)}`; + const importCss = + options.format === 'cjs' + ? `require('${relativeCssPath}');\n` + : `import '${relativeCssPath}';\n`; + + file.code = importCss + file.code; + + this.emitFile({ + type: 'asset', + fileName: cssFileName, + source: css, + }); + }); + }, + }, + }; +} diff --git a/packages/sdds-insol-next/rollup.config.mjs b/packages/sdds-insol-next/rollup.config.mjs index 29246bbe3da..5951eb4e4fd 100644 --- a/packages/sdds-insol-next/rollup.config.mjs +++ b/packages/sdds-insol-next/rollup.config.mjs @@ -8,9 +8,8 @@ import styles from '@ironkinoko/rollup-plugin-styles'; const inputDir = 'src-css'; const require = createRequire(import.meta.url); -const isBeta = process.env.BETA === 'true'; -const input = isBeta ? path.join(inputDir, 'components/_beta/index.ts') : path.join(inputDir, 'index.ts'); -const outputDir = isBeta ? 'dist/beta' : 'dist/css'; +const input = path.join(inputDir, 'index.ts'); +const outputDir = 'dist/css'; export default { input, diff --git a/packages/sdds-insol-next/scripts/copy-linaria-components.sh b/packages/sdds-insol-next/scripts/copy-linaria-components.sh index 28c2f5e9d01..ee0e9b16a20 100755 --- a/packages/sdds-insol-next/scripts/copy-linaria-components.sh +++ b/packages/sdds-insol-next/scripts/copy-linaria-components.sh @@ -1,15 +1,15 @@ #!/usr/bin/env bash # Example: Calendar -components=$(grep -R plasma-new-hope src/components | cut -d / -f 3 | sort -u) +components=$(grep -R plasma-new-hope src/components | cut -d / -f 3 | grep -v '^_beta$' | sort -u) mkdir -p src-css/components/ -touch src-css/index.ts -touch src-css/index.d.ts +: > src-css/index.ts +: > src-css/index.d.ts for component in $components; do cp -R src/components/$component src-css/components/; grep -E "\<$component\>" src/index.ts >> src-css/index.ts - echo "export * from '../components/$component';" >> css/index.d.ts; + echo "export * from '../components/$component';" >> src-css/index.d.ts; done; diff --git a/packages/sdds-insol-next/src/components/_beta/Popover/Popover.config.ts b/packages/sdds-insol-next/src/components/_beta/Popover/Popover.config.ts deleted file mode 100644 index 1fb42873d23..00000000000 --- a/packages/sdds-insol-next/src/components/_beta/Popover/Popover.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { css, _beta_popoverTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { surfaceSolidTertiary } from '@salutejs-ds/sdds_sbcom/theme/tokens'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${surfaceSolidTertiary}; - ${tokens.boxShadow}: none; - ${tokens.dropShadow}: drop-shadow(0px 4px 12px rgba(0, 0, 0, 0.16)) - drop-shadow(0px 1px 4px rgba(0, 0, 0, 0.08)); - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem 0.5rem 0.5rem 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: 0%; - `, - }, - }, -}; diff --git a/packages/sdds-insol-next/src/components/_beta/Popover/Popover.stories.tsx b/packages/sdds-insol-next/src/components/_beta/Popover/Popover.stories.tsx index c7dc0bf283f..f5f987d9e5b 100644 --- a/packages/sdds-insol-next/src/components/_beta/Popover/Popover.stories.tsx +++ b/packages/sdds-insol-next/src/components/_beta/Popover/Popover.stories.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import type { ComponentProps } from 'react'; import type { StoryObj, Meta } from '@storybook/react-vite'; -import { getConfigVariations } from '@salutejs/plasma-sb-utils'; import { Cell, CellTextbox, CellTextboxTitle, CellTextboxSubtitle } from '../../Cell'; import { Button } from '../../Button'; @@ -9,11 +8,21 @@ import { ButtonGroup } from '../../ButtonGroup'; import { ViewContainer } from '../../ViewContainer'; import { Popover } from './Popover'; -import { config } from './Popover.config'; -type StoryProps = ComponentProps; +type ResizableOptions = Exclude['resizable'], boolean | undefined>; +type StoryProps = ComponentProps & { + resizableDirections?: ResizableOptions['directions']; + resizableHiddenIcons?: ResizableOptions['hiddenIcons']; + resizableDefaultSize?: ResizableOptions['defaultSize']; + resizableMinWidth?: ResizableOptions['minWidth']; + resizableMinHeight?: ResizableOptions['minHeight']; + resizableMaxWidth?: ResizableOptions['maxWidth']; + resizableMaxHeight?: ResizableOptions['maxHeight']; + resizableIconSize?: ResizableOptions['iconSize']; +}; -const { views, sizes } = getConfigVariations(config); +const views = ['default']; +const sizes = ['m']; const placements = [ 'top', 'top-start', @@ -154,7 +163,7 @@ const StoryDefault = (args: StoryProps) => { }; export const Default: StoryObj = { - render: (args) => , + render: (args: StoryProps) => , }; const StoryResizable = (args: StoryProps) => { @@ -167,6 +176,7 @@ const StoryResizable = (args: StoryProps) => { resizableMaxWidth, resizableMaxHeight, resizableIconSize, + ...popoverProps } = args; React.useEffect(() => { @@ -194,6 +204,7 @@ const StoryResizable = (args: StoryProps) => { }} > { maxHeight: resizableMaxHeight, iconSize: resizableIconSize, }} - {...args} target={} >
= { resizableMinWidth: 300, resizableMinHeight: 300, }, - render: (args) => , + render: (args: StoryProps) => , }; diff --git a/packages/sdds-insol-next/src/components/_beta/Popover/Popover.tsx b/packages/sdds-insol-next/src/components/_beta/Popover/Popover.tsx index 0dbe210b791..48ef1d7ce81 100644 --- a/packages/sdds-insol-next/src/components/_beta/Popover/Popover.tsx +++ b/packages/sdds-insol-next/src/components/_beta/Popover/Popover.tsx @@ -1,6 +1,26 @@ -import { _beta_popoverConfig, component, mergeConfig } from '@salutejs/plasma-new-hope/styled-components'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Popover as CorePopover } from '@salutejs/plasma-new-hope/beta'; +import type { PopoverProps as CorePopoverProps } from '@salutejs/plasma-new-hope/beta'; -import { config } from './Popover.config'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; -const mergedConfig = mergeConfig(_beta_popoverConfig, config); -export const Popover = component(mergedConfig); +export type PopoverProps = Omit & { + view?: 'default'; + size?: 'm'; +}; + +export const Popover = forwardRef(({ view = 'default', size = 'm', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + return ( + + ); +}); diff --git a/packages/sdds-insol-next/src/components/_beta/Popover/config/Size.module.css b/packages/sdds-insol-next/src/components/_beta/Popover/config/Size.module.css new file mode 100644 index 00000000000..53002ebf718 --- /dev/null +++ b/packages/sdds-insol-next/src/components/_beta/Popover/config/Size.module.css @@ -0,0 +1,7 @@ +.m { + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem 0.5rem 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: 0%; +} diff --git a/packages/sdds-insol-next/src/components/_beta/Popover/config/View.module.css b/packages/sdds-insol-next/src/components/_beta/Popover/config/View.module.css new file mode 100644 index 00000000000..13509b0538e --- /dev/null +++ b/packages/sdds-insol-next/src/components/_beta/Popover/config/View.module.css @@ -0,0 +1,6 @@ +.default { + --plasma-popover-background-color: var(--surface-solid-tertiary); + --plasma-popover-box-shadow: none; + --plasma-popover-drop-shadow: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.16)) + drop-shadow(0 1px 4px rgba(0, 0, 0, 0.08)); +} diff --git a/packages/sdds-insol-next/src/components/_beta/Popover/index.ts b/packages/sdds-insol-next/src/components/_beta/Popover/index.ts index 6e5a6364810..2a955281c77 100644 --- a/packages/sdds-insol-next/src/components/_beta/Popover/index.ts +++ b/packages/sdds-insol-next/src/components/_beta/Popover/index.ts @@ -1 +1,2 @@ export { Popover } from './Popover'; +export type { PopoverProps } from './Popover'; diff --git a/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.config.ts b/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.config.ts deleted file mode 100644 index fa635074b93..00000000000 --- a/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.config.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { css, _beta_tooltipTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { bodyS, surfaceSolidCardBrightness, textPrimary } from '@salutejs/sdds-themes/tokens/sdds_insol_next'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${surfaceSolidCardBrightness}; - ${tokens.boxShadow}: none; - ${tokens.dropShadow}: drop-shadow(0px 4px 12px rgba(0, 0, 0, 0.16)) - drop-shadow(0px 1px 4px rgba(0, 0, 0, 0.08)); - ${tokens.color}: ${textPrimary}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 0.625rem; - ${tokens.padding}: 0.6875rem 0.875rem; - ${tokens.gap}: 0.375rem; - ${tokens.fontFamily}: ${bodyS.fontFamily}; - ${tokens.fontSize}: ${bodyS.fontSize}; - ${tokens.fontStyle}: ${bodyS.fontStyle}; - ${tokens.fontWeight}: ${bodyS.fontWeight}; - ${tokens.letterSpacing}: ${bodyS.letterSpacing}; - ${tokens.lineHeight}: ${bodyS.lineHeight}; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: 0%; - `, - }, - }, -}; diff --git a/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.stories.tsx b/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.stories.tsx index a9d32df29b1..4dd2e3c452d 100644 --- a/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.stories.tsx +++ b/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.stories.tsx @@ -7,7 +7,9 @@ import { Button } from '../../Button'; import { Tooltip } from './Tooltip'; -type StoryProps = ComponentProps; +type StoryProps = ComponentProps & { + hasIcon?: boolean; +}; const placements = [ 'top', @@ -25,7 +27,7 @@ const placements = [ ]; const trigger = ['click', 'hover', 'focus']; const view = ['default']; -const size = ['m', 's']; +const size = ['m']; const meta: Meta = { title: '_Beta/Overlay/Tooltip', @@ -108,7 +110,7 @@ const meta: Meta = { export default meta; -const StoryDefault = (args: StoryProps) => { +const StoryDefault = ({ hasIcon, ...tooltipProps }: StoryProps) => { React.useEffect(() => { window.scrollTo( (document.documentElement.scrollWidth - window.innerWidth) / 2, @@ -127,9 +129,9 @@ const StoryDefault = (args: StoryProps) => { }} > : undefined} + {...tooltipProps} + iconSlot={hasIcon ? : undefined} target={} - {...args} > Контент выпадающего окна @@ -138,5 +140,5 @@ const StoryDefault = (args: StoryProps) => { }; export const Default: StoryObj = { - render: (args) => , + render: (args: StoryProps) => , }; diff --git a/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.tsx b/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.tsx index ed219dfa125..da53060d4f5 100644 --- a/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.tsx +++ b/packages/sdds-insol-next/src/components/_beta/Tooltip/Tooltip.tsx @@ -1,6 +1,22 @@ -import { _beta_tooltipConfig, component, mergeConfig } from '@salutejs/plasma-new-hope/styled-components'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Tooltip as CoreTooltip } from '@salutejs/plasma-new-hope/beta'; +import type { TooltipProps as CoreTooltipProps } from '@salutejs/plasma-new-hope/beta'; -import { config } from './Tooltip.config'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; -const mergedConfig = mergeConfig(_beta_tooltipConfig, config); -export const Tooltip = component(mergedConfig); +type TooltipView = 'default'; +type TooltipSize = 'm'; + +export type TooltipProps = CoreTooltipProps & { + view?: TooltipView; + size?: TooltipSize; +}; + +export const Tooltip = forwardRef(({ view = 'default', size = 'm', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + // @ts-expect-error _configClassName is an internal runtime property. + return ; +}); diff --git a/packages/sdds-insol-next/src/components/_beta/Tooltip/config/Size.module.css b/packages/sdds-insol-next/src/components/_beta/Tooltip/config/Size.module.css new file mode 100644 index 00000000000..29cee187156 --- /dev/null +++ b/packages/sdds-insol-next/src/components/_beta/Tooltip/config/Size.module.css @@ -0,0 +1,14 @@ +.m { + --plasma-tooltip-border-radius: 0.625rem; + --plasma-tooltip-padding: 0.6875rem 0.875rem; + --plasma-tooltip-gap: 0.375rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-s-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-s-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-s-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-s-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-s-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-s-line-height); + --plasma-tooltip-tail-width: 20px; + --plasma-tooltip-tail-height: 8px; + --plasma-tooltip-tail-side-curvature: 0%; +} diff --git a/packages/sdds-insol-next/src/components/_beta/Tooltip/config/View.module.css b/packages/sdds-insol-next/src/components/_beta/Tooltip/config/View.module.css new file mode 100644 index 00000000000..c086f21bda1 --- /dev/null +++ b/packages/sdds-insol-next/src/components/_beta/Tooltip/config/View.module.css @@ -0,0 +1,7 @@ +.default { + --plasma-tooltip-background-color: var(--surface-solid-card-brightness); + --plasma-tooltip-box-shadow: none; + --plasma-tooltip-drop-shadow: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.16)) + drop-shadow(0 1px 4px rgba(0, 0, 0, 0.08)); + --plasma-tooltip-color: var(--text-primary); +} diff --git a/packages/sdds-insol-next/src/components/_beta/Tooltip/index.ts b/packages/sdds-insol-next/src/components/_beta/Tooltip/index.ts index b44d466fac2..27667e0037c 100644 --- a/packages/sdds-insol-next/src/components/_beta/Tooltip/index.ts +++ b/packages/sdds-insol-next/src/components/_beta/Tooltip/index.ts @@ -1 +1,2 @@ export { Tooltip } from './Tooltip'; +export type { TooltipProps } from './Tooltip'; diff --git a/packages/sdds-insol-next/src/components/_beta/css-modules.d.ts b/packages/sdds-insol-next/src/components/_beta/css-modules.d.ts new file mode 100644 index 00000000000..e7f258a4668 --- /dev/null +++ b/packages/sdds-insol-next/src/components/_beta/css-modules.d.ts @@ -0,0 +1,5 @@ +declare module '*.module.css' { + const classes: Readonly>; + + export default classes; +} diff --git a/packages/sdds-sbcom/package.json b/packages/sdds-sbcom/package.json index d4576f89e33..18f95fcea3a 100644 --- a/packages/sdds-sbcom/package.json +++ b/packages/sdds-sbcom/package.json @@ -33,7 +33,8 @@ }, "dependencies": { "@salutejs-ds/sdds_sbcom": "0.1.20", - "@salutejs/plasma-new-hope": "0.378.0" + "@salutejs/plasma-new-hope": "0.378.0", + "classnames": "2.5.1" }, "devDependencies": { "@babel/cli": "7.24.1", @@ -76,10 +77,8 @@ "prebuild:css": "rm -rf src-css && ./scripts/copy-linaria-components.sh", "build:css": "rm -rf dist/css && rollup -c", "postbuild:css": "rm -rf src-css", - "prebuild:beta": "rm -rf src-css && ./scripts/copy-linaria-components.sh", - "build:beta": "rm -rf dist/beta/es dist/beta/cjs && BETA=true rollup -c", - "postbuild:beta": "rm -rf src-css", - "generate:typings": "rm -rf types && tsc && rm -rf dist/beta/types && tsc -p src/components/_beta/tsconfig.json", + "build:beta": "rm -rf dist/beta && rollup -c rollup.beta.config.mjs", + "generate:typings": "tsc && tsc -p src/components/_beta/tsconfig.json", "storybook": "storybook dev -p ${PORT:-7002} -c .storybook", "storybook:build": "storybook build -c .storybook -o build-sb", "typescript-coverage": "npx typescript-coverage-report > /dev/null", diff --git a/packages/sdds-sbcom/rollup.beta.config.mjs b/packages/sdds-sbcom/rollup.beta.config.mjs new file mode 100644 index 00000000000..0c263c7e3a9 --- /dev/null +++ b/packages/sdds-sbcom/rollup.beta.config.mjs @@ -0,0 +1,121 @@ +import path from 'path'; +import { createHash } from 'crypto'; +import { fileURLToPath } from 'url'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { babel } from '@rollup/plugin-babel'; +import styles from '@ironkinoko/rollup-plugin-styles'; + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); +const betaSourceDir = path.resolve(dirname, 'src/components/_beta'); +const extractedCssModules = new Map(); + +export default { + input: { + index: path.join(betaSourceDir, 'index.ts'), + }, + treeshake: { + propertyReadSideEffects: false, + }, + output: [ + { + preserveModules: true, + dir: 'dist/beta/es', + format: 'es', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + }, + { + preserveModules: true, + dir: 'dist/beta/cjs', + format: 'cjs', + freeze: false, + esModule: true, + sourcemap: false, + exports: 'named', + interop: 'auto', + }, + ], + external: (id) => { + if (id.startsWith('regenerator-runtime') || id === 'tslib') { + return false; + } + + return !id.startsWith('.') && !path.isAbsolute(id); + }, + plugins: [ + nodeResolve({ + extensions: ['.tsx', '.ts'], + }), + styles({ + mode: 'extract', + modules: { + generateScopedName(localName, file, css) { + const relativePath = path.relative(betaSourceDir, file).split(path.sep).join('/'); + const componentName = relativePath.split('/')[0]; + const fileName = path.basename(file, '.module.css'); + const hash = createHash('sha256') + .update(`${relativePath}:${localName}:${css}`) + .digest('hex') + .slice(0, 8); + + return `${componentName}_${fileName}_${localName}__${hash}`; + }, + }, + onExtract({ name, css }) { + const moduleName = name.replace(/\.css$/, ''); + + if (moduleName.endsWith('.module.css')) { + extractedCssModules.set(moduleName, css); + } + + return false; + }, + }), + emitCssModulesPlugin(), + babel({ + babelHelpers: 'bundled', + extensions: ['.ts', '.tsx'], + }), + ], +}; + +function emitCssModulesPlugin() { + return { + name: 'emitCssModulesPlugin', + generateBundle: { + order: 'post', + handler(options, bundle) { + Object.values(bundle).forEach((file) => { + if (file.type !== 'chunk' || !file.fileName.endsWith('.module.css.js')) { + return; + } + + const moduleName = file.fileName.replace(/\.js$/, ''); + const css = extractedCssModules.get(moduleName); + + if (css === undefined) { + this.error(`Processed CSS Module was not found for ${file.fileName}`); + } + + const cssFileName = file.fileName.replace(/\.module\.css\.js$/, '.css'); + const relativeCssPath = `./${path.posix.relative(path.posix.dirname(file.fileName), cssFileName)}`; + const importCss = + options.format === 'cjs' + ? `require('${relativeCssPath}');\n` + : `import '${relativeCssPath}';\n`; + + file.code = importCss + file.code; + + this.emitFile({ + type: 'asset', + fileName: cssFileName, + source: css, + }); + }); + }, + }, + }; +} diff --git a/packages/sdds-sbcom/rollup.config.mjs b/packages/sdds-sbcom/rollup.config.mjs index 6b7445e5c4c..9a7c29309c2 100644 --- a/packages/sdds-sbcom/rollup.config.mjs +++ b/packages/sdds-sbcom/rollup.config.mjs @@ -12,9 +12,8 @@ import styles from "@ironkinoko/rollup-plugin-styles"; const inputDir = 'src-css'; const require = createRequire(import.meta.url) -const isBeta = process.env.BETA === 'true'; -const input = isBeta ? path.join(inputDir, 'components/_beta/index.ts') : path.join(inputDir, 'index.ts'); -const outputDir = isBeta ? 'dist/beta' : 'dist/css'; +const input = path.join(inputDir, 'index.ts'); +const outputDir = 'dist/css'; export default { input, diff --git a/packages/sdds-sbcom/scripts/copy-linaria-components.sh b/packages/sdds-sbcom/scripts/copy-linaria-components.sh index 4d2f16815cf..4631cab87a3 100755 --- a/packages/sdds-sbcom/scripts/copy-linaria-components.sh +++ b/packages/sdds-sbcom/scripts/copy-linaria-components.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Example: Calendar -components=$(grep -R plasma-new-hope src/components | cut -d / -f 3 | sort -u) +components=$(grep -R plasma-new-hope src/components | cut -d / -f 3 | grep -v '^_beta$' | sort -u) mkdir -p src-css/components/ touch src-css/index.ts diff --git a/packages/sdds-sbcom/src/components/_beta/Popover/Popover.config.ts b/packages/sdds-sbcom/src/components/_beta/Popover/Popover.config.ts deleted file mode 100644 index 1fb42873d23..00000000000 --- a/packages/sdds-sbcom/src/components/_beta/Popover/Popover.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { css, _beta_popoverTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { surfaceSolidTertiary } from '@salutejs-ds/sdds_sbcom/theme/tokens'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${surfaceSolidTertiary}; - ${tokens.boxShadow}: none; - ${tokens.dropShadow}: drop-shadow(0px 4px 12px rgba(0, 0, 0, 0.16)) - drop-shadow(0px 1px 4px rgba(0, 0, 0, 0.08)); - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 1rem; - ${tokens.padding}: 0.75rem 0.5rem 0.5rem 0.5rem; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: 0%; - `, - }, - }, -}; diff --git a/packages/sdds-sbcom/src/components/_beta/Popover/Popover.stories.tsx b/packages/sdds-sbcom/src/components/_beta/Popover/Popover.stories.tsx index c7dc0bf283f..10fddb3ff52 100644 --- a/packages/sdds-sbcom/src/components/_beta/Popover/Popover.stories.tsx +++ b/packages/sdds-sbcom/src/components/_beta/Popover/Popover.stories.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import type { ComponentProps } from 'react'; import type { StoryObj, Meta } from '@storybook/react-vite'; -import { getConfigVariations } from '@salutejs/plasma-sb-utils'; import { Cell, CellTextbox, CellTextboxTitle, CellTextboxSubtitle } from '../../Cell'; import { Button } from '../../Button'; @@ -9,11 +8,21 @@ import { ButtonGroup } from '../../ButtonGroup'; import { ViewContainer } from '../../ViewContainer'; import { Popover } from './Popover'; -import { config } from './Popover.config'; -type StoryProps = ComponentProps; +type ResizableOptions = Exclude['resizable'], boolean | undefined>; +type StoryProps = ComponentProps & { + resizableDirections?: ResizableOptions['directions']; + resizableHiddenIcons?: ResizableOptions['hiddenIcons']; + resizableDefaultSize?: ResizableOptions['defaultSize']; + resizableMinWidth?: ResizableOptions['minWidth']; + resizableMinHeight?: ResizableOptions['minHeight']; + resizableMaxWidth?: ResizableOptions['maxWidth']; + resizableMaxHeight?: ResizableOptions['maxHeight']; + resizableIconSize?: ResizableOptions['iconSize']; +}; -const { views, sizes } = getConfigVariations(config); +const views = ['default']; +const sizes = ['m']; const placements = [ 'top', 'top-start', @@ -142,8 +151,8 @@ const StoryDefault = (args: StoryProps) => { Title Description - - + + @@ -154,7 +163,7 @@ const StoryDefault = (args: StoryProps) => { }; export const Default: StoryObj = { - render: (args) => , + render: (args: StoryProps) => , }; const StoryResizable = (args: StoryProps) => { @@ -167,6 +176,7 @@ const StoryResizable = (args: StoryProps) => { resizableMaxWidth, resizableMaxHeight, resizableIconSize, + ...popoverProps } = args; React.useEffect(() => { @@ -194,6 +204,7 @@ const StoryResizable = (args: StoryProps) => { }} > { maxHeight: resizableMaxHeight, iconSize: resizableIconSize, }} - {...args} target={} >
= { resizableMinWidth: 300, resizableMinHeight: 300, }, - render: (args) => , + render: (args: StoryProps) => , }; diff --git a/packages/sdds-sbcom/src/components/_beta/Popover/Popover.tsx b/packages/sdds-sbcom/src/components/_beta/Popover/Popover.tsx index 0dbe210b791..48ef1d7ce81 100644 --- a/packages/sdds-sbcom/src/components/_beta/Popover/Popover.tsx +++ b/packages/sdds-sbcom/src/components/_beta/Popover/Popover.tsx @@ -1,6 +1,26 @@ -import { _beta_popoverConfig, component, mergeConfig } from '@salutejs/plasma-new-hope/styled-components'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Popover as CorePopover } from '@salutejs/plasma-new-hope/beta'; +import type { PopoverProps as CorePopoverProps } from '@salutejs/plasma-new-hope/beta'; -import { config } from './Popover.config'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; -const mergedConfig = mergeConfig(_beta_popoverConfig, config); -export const Popover = component(mergedConfig); +export type PopoverProps = Omit & { + view?: 'default'; + size?: 'm'; +}; + +export const Popover = forwardRef(({ view = 'default', size = 'm', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + return ( + + ); +}); diff --git a/packages/sdds-sbcom/src/components/_beta/Popover/config/Size.module.css b/packages/sdds-sbcom/src/components/_beta/Popover/config/Size.module.css new file mode 100644 index 00000000000..53002ebf718 --- /dev/null +++ b/packages/sdds-sbcom/src/components/_beta/Popover/config/Size.module.css @@ -0,0 +1,7 @@ +.m { + --plasma-popover-border-radius: 1rem; + --plasma-popover-padding: 0.75rem 0.5rem 0.5rem; + --plasma-popover-tail-width: 20px; + --plasma-popover-tail-height: 8px; + --plasma-popover-tail-side-curvature: 0%; +} diff --git a/packages/sdds-sbcom/src/components/_beta/Popover/config/View.module.css b/packages/sdds-sbcom/src/components/_beta/Popover/config/View.module.css new file mode 100644 index 00000000000..13509b0538e --- /dev/null +++ b/packages/sdds-sbcom/src/components/_beta/Popover/config/View.module.css @@ -0,0 +1,6 @@ +.default { + --plasma-popover-background-color: var(--surface-solid-tertiary); + --plasma-popover-box-shadow: none; + --plasma-popover-drop-shadow: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.16)) + drop-shadow(0 1px 4px rgba(0, 0, 0, 0.08)); +} diff --git a/packages/sdds-sbcom/src/components/_beta/Popover/index.ts b/packages/sdds-sbcom/src/components/_beta/Popover/index.ts index 6e5a6364810..2a955281c77 100644 --- a/packages/sdds-sbcom/src/components/_beta/Popover/index.ts +++ b/packages/sdds-sbcom/src/components/_beta/Popover/index.ts @@ -1 +1,2 @@ export { Popover } from './Popover'; +export type { PopoverProps } from './Popover'; diff --git a/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.config.ts b/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.config.ts deleted file mode 100644 index cf585e1edb4..00000000000 --- a/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.config.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { css, _beta_tooltipTokens as tokens } from '@salutejs/plasma-new-hope/styled-components'; -import { bodyS, surfaceSolidCardBrightness, textPrimary } from '@salutejs-ds/sdds_sbcom/theme/tokens'; - -export const config = { - defaults: { - view: 'default', - size: 'm', - }, - variations: { - view: { - default: css` - ${tokens.backgroundColor}: ${surfaceSolidCardBrightness}; - ${tokens.boxShadow}: none; - ${tokens.dropShadow}: drop-shadow(0px 4px 12px rgba(0, 0, 0, 0.16)) - drop-shadow(0px 1px 4px rgba(0, 0, 0, 0.08)); - ${tokens.color}: ${textPrimary}; - `, - }, - size: { - m: css` - ${tokens.borderRadius}: 0.625rem; - ${tokens.padding}: 0.6875rem 0.875rem; - ${tokens.gap}: 0.375rem; - ${tokens.fontFamily}: ${bodyS.fontFamily}; - ${tokens.fontSize}: ${bodyS.fontSize}; - ${tokens.fontStyle}: ${bodyS.fontStyle}; - ${tokens.fontWeight}: ${bodyS.fontWeight}; - ${tokens.letterSpacing}: ${bodyS.letterSpacing}; - ${tokens.lineHeight}: ${bodyS.lineHeight}; - ${tokens.tailWidth}: 20px; - ${tokens.tailHeight}: 8px; - ${tokens.tailSideCurvature}: 0%; - `, - }, - }, -}; diff --git a/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.stories.tsx b/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.stories.tsx index f7bb572b8cb..4dd2e3c452d 100644 --- a/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.stories.tsx +++ b/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.stories.tsx @@ -7,7 +7,9 @@ import { Button } from '../../Button'; import { Tooltip } from './Tooltip'; -type StoryProps = ComponentProps; +type StoryProps = ComponentProps & { + hasIcon?: boolean; +}; const placements = [ 'top', @@ -108,7 +110,7 @@ const meta: Meta = { export default meta; -const StoryDefault = (args: StoryProps) => { +const StoryDefault = ({ hasIcon, ...tooltipProps }: StoryProps) => { React.useEffect(() => { window.scrollTo( (document.documentElement.scrollWidth - window.innerWidth) / 2, @@ -127,9 +129,9 @@ const StoryDefault = (args: StoryProps) => { }} > : undefined} + {...tooltipProps} + iconSlot={hasIcon ? : undefined} target={} - {...args} > Контент выпадающего окна @@ -138,5 +140,5 @@ const StoryDefault = (args: StoryProps) => { }; export const Default: StoryObj = { - render: (args) => , + render: (args: StoryProps) => , }; diff --git a/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.tsx b/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.tsx index ed219dfa125..da53060d4f5 100644 --- a/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.tsx +++ b/packages/sdds-sbcom/src/components/_beta/Tooltip/Tooltip.tsx @@ -1,6 +1,22 @@ -import { _beta_tooltipConfig, component, mergeConfig } from '@salutejs/plasma-new-hope/styled-components'; +import React, { forwardRef } from 'react'; +import cls from 'classnames'; +import { Tooltip as CoreTooltip } from '@salutejs/plasma-new-hope/beta'; +import type { TooltipProps as CoreTooltipProps } from '@salutejs/plasma-new-hope/beta'; -import { config } from './Tooltip.config'; +import sizeStyles from './config/Size.module.css'; +import viewStyles from './config/View.module.css'; -const mergedConfig = mergeConfig(_beta_tooltipConfig, config); -export const Tooltip = component(mergedConfig); +type TooltipView = 'default'; +type TooltipSize = 'm'; + +export type TooltipProps = CoreTooltipProps & { + view?: TooltipView; + size?: TooltipSize; +}; + +export const Tooltip = forwardRef(({ view = 'default', size = 'm', ...rest }, ref) => { + const configClassName = cls(viewStyles[view], sizeStyles[size]); + + // @ts-expect-error _configClassName is an internal runtime property. + return ; +}); diff --git a/packages/sdds-sbcom/src/components/_beta/Tooltip/config/Size.module.css b/packages/sdds-sbcom/src/components/_beta/Tooltip/config/Size.module.css new file mode 100644 index 00000000000..29cee187156 --- /dev/null +++ b/packages/sdds-sbcom/src/components/_beta/Tooltip/config/Size.module.css @@ -0,0 +1,14 @@ +.m { + --plasma-tooltip-border-radius: 0.625rem; + --plasma-tooltip-padding: 0.6875rem 0.875rem; + --plasma-tooltip-gap: 0.375rem; + --plasma-tooltip-font-family: var(--plasma-typo-body-s-font-family); + --plasma-tooltip-font-size: var(--plasma-typo-body-s-font-size); + --plasma-tooltip-font-style: var(--plasma-typo-body-s-font-style); + --plasma-tooltip-font-weight: var(--plasma-typo-body-s-font-weight); + --plasma-tooltip-letter-spacing: var(--plasma-typo-body-s-letter-spacing); + --plasma-tooltip-lineheight: var(--plasma-typo-body-s-line-height); + --plasma-tooltip-tail-width: 20px; + --plasma-tooltip-tail-height: 8px; + --plasma-tooltip-tail-side-curvature: 0%; +} diff --git a/packages/sdds-sbcom/src/components/_beta/Tooltip/config/View.module.css b/packages/sdds-sbcom/src/components/_beta/Tooltip/config/View.module.css new file mode 100644 index 00000000000..c086f21bda1 --- /dev/null +++ b/packages/sdds-sbcom/src/components/_beta/Tooltip/config/View.module.css @@ -0,0 +1,7 @@ +.default { + --plasma-tooltip-background-color: var(--surface-solid-card-brightness); + --plasma-tooltip-box-shadow: none; + --plasma-tooltip-drop-shadow: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.16)) + drop-shadow(0 1px 4px rgba(0, 0, 0, 0.08)); + --plasma-tooltip-color: var(--text-primary); +} diff --git a/packages/sdds-sbcom/src/components/_beta/Tooltip/index.ts b/packages/sdds-sbcom/src/components/_beta/Tooltip/index.ts index b44d466fac2..27667e0037c 100644 --- a/packages/sdds-sbcom/src/components/_beta/Tooltip/index.ts +++ b/packages/sdds-sbcom/src/components/_beta/Tooltip/index.ts @@ -1 +1,2 @@ export { Tooltip } from './Tooltip'; +export type { TooltipProps } from './Tooltip'; diff --git a/packages/sdds-sbcom/src/components/_beta/css-modules.d.ts b/packages/sdds-sbcom/src/components/_beta/css-modules.d.ts new file mode 100644 index 00000000000..e7f258a4668 --- /dev/null +++ b/packages/sdds-sbcom/src/components/_beta/css-modules.d.ts @@ -0,0 +1,5 @@ +declare module '*.module.css' { + const classes: Readonly>; + + export default classes; +}