From 93e46e535560a558646c253e506605659b6a50f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=9A=D1=80=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 13 Jan 2026 18:20:38 +0300 Subject: [PATCH 1/9] feat(v1-components): UiSelect, UiMenuItem components added * UiMenuItem, UiSelectTrigger, UiSelectPopper on host - can be used to create alternative UiSelect if needed * UiSelect, UiSelectOption, UiSelectOptionGroup on remote --- .../assets/stylesheets/motion.less | 1 + .../assets/stylesheets/typography.less | 9 + .../src/common/components/menu.ts | 30 ++ .../src/common/components/select.ts | 111 ++++++ packages/v1-components/src/host.ts | 6 +- .../src/host/components/menu/UiMenuItem.vue | 161 +++++++++ .../host/components/menu/UiMenuItem.vue.d.ts | 9 + .../host/components/menu/UiMenuItemGroup.vue | 42 +++ .../components/menu/UiMenuItemGroup.vue.d.ts | 6 + .../src/host/components/menu/menu.less | 204 +++++++++++ .../src/host/components/popper/UiPopper.vue | 5 + .../host/components/select/UiSelectPopper.vue | 206 +++++++++++ .../components/select/UiSelectPopper.vue.d.ts | 14 + .../components/select/UiSelectTrigger.vue | 279 +++++++++++++++ .../select/UiSelectTrigger.vue.d.ts | 13 + .../src/host/components/select/i18n.ts | 13 + .../host/components/select/i18n/en-GB.json | 7 + .../host/components/select/i18n/es-ES.json | 7 + .../host/components/select/i18n/ru-RU.json | 7 + .../src/host/components/select/injection.ts | 34 ++ .../src/host/components/select/select.less | 124 +++++++ .../src/host/components/textbox/textbox.less | 18 +- packages/v1-components/src/remote.ts | 2 + .../src/remote/components/menu.ts | 38 ++ .../src/remote/components/select/UiSelect.vue | 338 ++++++++++++++++++ .../components/select/UiSelectOption.vue | 223 ++++++++++++ .../components/select/UiSelectOptionGroup.vue | 156 ++++++++ .../select/UiSelectOptionGroupHeader.vue | 26 ++ .../src/remote/components/select/index.ts | 3 + .../src/remote/components/select/parts.ts | 78 ++++ packages/v1-components/storybook/endpoint.ts | 107 ++++++ .../storybook/stories/UiMenuItem.example.vue | 88 +++++ .../storybook/stories/UiMenuItem.mdx | 44 +++ .../storybook/stories/UiMenuItem.stories.ts | 60 ++++ .../storybook/stories/UiSelect.mdx | 3 + .../storybook/stories/UiSelect.remote.ts | 73 ++++ .../storybook/stories/UiSelect.stories.ts | 120 +++++++ .../v1-components/storybook/tsconfig.json | 6 +- 38 files changed, 2667 insertions(+), 4 deletions(-) create mode 100644 packages/v1-components/assets/stylesheets/motion.less create mode 100644 packages/v1-components/src/common/components/menu.ts create mode 100644 packages/v1-components/src/common/components/select.ts create mode 100644 packages/v1-components/src/host/components/menu/UiMenuItem.vue create mode 100644 packages/v1-components/src/host/components/menu/UiMenuItem.vue.d.ts create mode 100644 packages/v1-components/src/host/components/menu/UiMenuItemGroup.vue create mode 100644 packages/v1-components/src/host/components/menu/UiMenuItemGroup.vue.d.ts create mode 100644 packages/v1-components/src/host/components/menu/menu.less create mode 100644 packages/v1-components/src/host/components/select/UiSelectPopper.vue create mode 100644 packages/v1-components/src/host/components/select/UiSelectPopper.vue.d.ts create mode 100644 packages/v1-components/src/host/components/select/UiSelectTrigger.vue create mode 100644 packages/v1-components/src/host/components/select/UiSelectTrigger.vue.d.ts create mode 100644 packages/v1-components/src/host/components/select/i18n.ts create mode 100644 packages/v1-components/src/host/components/select/i18n/en-GB.json create mode 100644 packages/v1-components/src/host/components/select/i18n/es-ES.json create mode 100644 packages/v1-components/src/host/components/select/i18n/ru-RU.json create mode 100644 packages/v1-components/src/host/components/select/injection.ts create mode 100644 packages/v1-components/src/host/components/select/select.less create mode 100644 packages/v1-components/src/remote/components/menu.ts create mode 100644 packages/v1-components/src/remote/components/select/UiSelect.vue create mode 100644 packages/v1-components/src/remote/components/select/UiSelectOption.vue create mode 100644 packages/v1-components/src/remote/components/select/UiSelectOptionGroup.vue create mode 100644 packages/v1-components/src/remote/components/select/UiSelectOptionGroupHeader.vue create mode 100644 packages/v1-components/src/remote/components/select/index.ts create mode 100644 packages/v1-components/src/remote/components/select/parts.ts create mode 100644 packages/v1-components/storybook/endpoint.ts create mode 100644 packages/v1-components/storybook/stories/UiMenuItem.example.vue create mode 100644 packages/v1-components/storybook/stories/UiMenuItem.mdx create mode 100644 packages/v1-components/storybook/stories/UiMenuItem.stories.ts create mode 100644 packages/v1-components/storybook/stories/UiSelect.mdx create mode 100644 packages/v1-components/storybook/stories/UiSelect.remote.ts create mode 100644 packages/v1-components/storybook/stories/UiSelect.stories.ts diff --git a/packages/v1-components/assets/stylesheets/motion.less b/packages/v1-components/assets/stylesheets/motion.less new file mode 100644 index 00000000..30866886 --- /dev/null +++ b/packages/v1-components/assets/stylesheets/motion.less @@ -0,0 +1 @@ +@transition: 0.25s ease; \ No newline at end of file diff --git a/packages/v1-components/assets/stylesheets/typography.less b/packages/v1-components/assets/stylesheets/typography.less index 2ff34301..0f835c38 100644 --- a/packages/v1-components/assets/stylesheets/typography.less +++ b/packages/v1-components/assets/stylesheets/typography.less @@ -8,6 +8,9 @@ @font-size-small: 14px; @font-size-tiny: 12px; +@font-weight-accent: 500; +@font-weight-normal: 400; + @line-height-h1: 44px; @line-height-h2: 32px; @line-height-h3: 32px; @@ -42,3 +45,9 @@ .text-tiny (@lh: (14/12)) { .text(400, @font-size-tiny, @lh); } .text-tiny-accent (@lh: (14/12)) { .text(500, @font-size-tiny, @lh); } + +.ellipsis () { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/packages/v1-components/src/common/components/menu.ts b/packages/v1-components/src/common/components/menu.ts new file mode 100644 index 00000000..af7a3166 --- /dev/null +++ b/packages/v1-components/src/common/components/menu.ts @@ -0,0 +1,30 @@ +export enum SIZE { + XS = 'xs', + SM = 'sm', + MD = 'md', + LG = 'lg', +} + +export type UiMenuItemProperties = { + description?: string; + counter?: string | number | null; + accent?: boolean; + active?: boolean; + danger?: boolean; + ticker?: boolean; + simple?: boolean; + size?: `${SIZE}`; + disabled?: boolean; +} + +type StyleDeclaration = CSSStyleDeclaration & { + '--delta-width': string +} + +export const deltaTransition = (el: HTMLElement): Partial => { + const delta = el.scrollWidth - el.clientWidth + return delta !== 0 ? { + '--delta-width': `-${delta}px`, + animationDuration: `${delta * 15}ms`, + } : {} +} diff --git a/packages/v1-components/src/common/components/select.ts b/packages/v1-components/src/common/components/select.ts new file mode 100644 index 00000000..5b63cfb0 --- /dev/null +++ b/packages/v1-components/src/common/components/select.ts @@ -0,0 +1,111 @@ +import type { Alignment } from '@floating-ui/dom' +import type { PlacementOptions } from '@/common/components/popper' +import type { Side } from '@floating-ui/dom' +import type { Trigger } from '@/common/components/popper' +import type { TriggerSchema } from '@/common/components/popper' +import type { UiPopperProperties } from '@/common/components/popper' + +export enum SIZE { + XS = 'xs', + SM = 'sm', + XL = 'xl', +} + +export enum PLACEMENT { + TOP = 'top', + TOP_START = 'top-start', + TOP_END = 'top-end', + BOTTOM = 'bottom', + BOTTOM_START = 'bottom-start', + BOTTOM_END = 'bottom-end', + LEFT = 'left', + LEFT_START = 'left-start', +} + +export type Option = { + id: string; + value: unknown; + label: string; + isMatched (): boolean; +} + +export type UiSelectTriggerProperties = { + value?: unknown|unknown[]; + clearable?: boolean; + filter?: string; + invalid?: boolean; + multiple?: boolean; + opened?: boolean; + expanded?: boolean; + placeholder?: string; + readonly?: boolean; + disabled?: boolean; + onlyPlaceholder?: boolean; + inputSize?: SIZE | `${SIZE}`; +} + +export type UiSelectTriggerMethods = { + open (): void; + close (): void; + onClick (): void; + onInput (event: Event): void; + onFocus (event: Event): void; + onBlur (event: Event): void; + onClear (event: MouseEvent): void; +} + +export type UiSelectPopperProperties = { + opened?: boolean; + targetTriggers?: Trigger[] | TriggerSchema; + popperTriggers?: Trigger[] | TriggerSchema; + popperFitTrigger?: boolean; + placement?: Side | `${Side}-${Alignment}` | PlacementOptions; + popperClass?: string; + popperOptions?: Omit; + disabled?: boolean; + readonly?: boolean; + multiple?: boolean; + ticker?: boolean; +} + +export type UiSelectPopperMethods = { + autoScroll (): void; + updateWidth (): void; +} + +export type UiSelectOptionProperties = { + value: unknown | unknown[]; + label: string; + description?: string; + disabled?: boolean; + selected?: boolean; + multiple?: boolean; + active?: boolean; + size?: SIZE | `${SIZE}`; + counter?: string | number | null; + accent?: boolean; +} + +const escapeSpecialSymbols = (text: string): string => text.replace( + /([\\^$.*+?()[\]{}|=!<>:-])/g, + '\\$1' +) + +/** + * @param text Текст, в котором ищем слово + * @param term Подсвечиваемое слово + * @param style Стиль подсветки + * @return Исходный текст со вставками span тегов в местах, где встречается слово term + */ +export const highlight = (text: string, term: string, style: string): string => text.replace( + new RegExp(`(${escapeSpecialSymbols(term)})`, 'gi'), + `$1` +) + +let counter = 0 + +/** + * @param prefix + * @return Идентификатор, уникальный в рамках генерируемой функцией последовательности + */ +export const uid = (prefix = 'ui-v1-select') => `${prefix}-${++counter}` diff --git a/packages/v1-components/src/host.ts b/packages/v1-components/src/host.ts index 999a17f7..53e464d3 100644 --- a/packages/v1-components/src/host.ts +++ b/packages/v1-components/src/host.ts @@ -8,20 +8,24 @@ export { default as UiError } from '@/host/components/error/UiError.vue' export { default as UiImage } from '@/host/components/image/UiImage.vue' export { default as UiLink } from '@/host/components/link/UiLink.vue' export { default as UiLoader } from '@/host/components/loader/UiLoader.vue' +export { default as UiMenuItem } from '@/host/components/menu/UiMenuItem.vue' +export { default as UiMenuItemGroup } from '@/host/components/menu/UiMenuItemGroup.vue' export { default as UiModalSidebar } from '@/host/components/modal-sidebar/UiModalSidebar.vue' export { default as UiModalWindow } from '@/host/components/modal-window/UiModalWindow.vue' export { default as UiModalWindowSurface } from '@/host/components/modal-window/UiModalWindowSurface.vue' export { default as UiPopper } from '@/host/components/popper/UiPopper.vue' export { default as UiPopperConnector } from '@/host/components/popper/UiPopperConnector.vue' export { default as UiPopperTarget } from '@/host/components/popper/UiPopperTarget.vue' -export { default as UiTooltip } from '@/host/components/tooltip/UiTooltip.vue' export { default as UiRadio } from '@/host/components/radio/UiRadio.vue' export { default as UiScrollBox } from '@/host/components/scroll-box/UiScrollBox.vue' +export { default as UiSelectPopper } from '@/host/components/select/UiSelectPopper.vue' +export { default as UiSelectTrigger } from '@/host/components/select/UiSelectTrigger.vue' export { default as UiTag } from '@/host/components/tag/UiTag.vue' export { default as UiTextbox } from '@/host/components/textbox/UiTextbox.vue' export { default as UiToolbar } from '@/host/components/toolbar/UiToolbar.vue' export { default as UiToolbarButton } from '@/host/components/toolbar/UiToolbarButton.vue' export { default as UiToolbarLink } from '@/host/components/toolbar/UiToolbarLink.vue' +export { default as UiTooltip } from '@/host/components/tooltip/UiTooltip.vue' export { default as UiTransition } from '@/host/components/transition/UiTransition.vue' export { default as UiYandexMap } from '@/host/components/yandex-map/UiYandexMap.vue' diff --git a/packages/v1-components/src/host/components/menu/UiMenuItem.vue b/packages/v1-components/src/host/components/menu/UiMenuItem.vue new file mode 100644 index 00000000..18ba0b8c --- /dev/null +++ b/packages/v1-components/src/host/components/menu/UiMenuItem.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/packages/v1-components/storybook/stories/UiMenuItem.mdx b/packages/v1-components/storybook/stories/UiMenuItem.mdx new file mode 100644 index 00000000..82f13187 --- /dev/null +++ b/packages/v1-components/storybook/stories/UiMenuItem.mdx @@ -0,0 +1,44 @@ +import ToReact from '../ToReact.ts' + +import UiMenuItem from './UiMenuItem.example.vue' + +# UiMenuItem + +Используется для отображения элемента выпадающего списка (меню) + +## Механика работы +Содержит основной текст, может содержать иконку слева, справа или дополнительный текст + +## Только основной текст (Дефолтный слот) + + + +## Жирный текст со счетчиком справа + + + +## Основной текст и описание + + + +## Слот для аватара + + + +## Слот для аватара и слот для description + + + +## Иконка слева + + + +## Иконка справа + + +## Иконки слева и справа + + +## Уменьшенный размер (size="sm") + + diff --git a/packages/v1-components/storybook/stories/UiMenuItem.stories.ts b/packages/v1-components/storybook/stories/UiMenuItem.stories.ts new file mode 100644 index 00000000..8048b079 --- /dev/null +++ b/packages/v1-components/storybook/stories/UiMenuItem.stories.ts @@ -0,0 +1,60 @@ +import type { Meta, StoryObj} from '@storybook/vue3' + +import UiMenuItem from '@/host/components/menu/UiMenuItem.vue' + +import page from './UiMenuItem.mdx' + +import { SIZE } from '@/common/components/menu' + +const meta = { + id: 'UiMenuItem', + + title: 'Components/UiMenuItem', + + component: UiMenuItem, + + argTypes: { + size: { + options: Object.values(SIZE), + }, + + counter: { + control: { type: 'number' }, + }, + }, + + render: (args) => ({ + components: { + UiMenuItem, + }, + + setup: () => ({ args }), + + template: ` + + Audrey Robertson + + `, + }), + + parameters: { + docs: { page }, + layout: 'centered', + }, +} satisfies Meta + +// noinspection JSUnusedGlobalSymbols +export default meta + +type Story = StoryObj + +export const Sandbox: Story = { + args: { + size: 'md', + description: '', + counter: 0, + accent: true, + active: false, + danger: false, + }, +} \ No newline at end of file diff --git a/packages/v1-components/storybook/stories/UiSelect.mdx b/packages/v1-components/storybook/stories/UiSelect.mdx new file mode 100644 index 00000000..5bd29ccf --- /dev/null +++ b/packages/v1-components/storybook/stories/UiSelect.mdx @@ -0,0 +1,3 @@ +# UiSelect + +test \ No newline at end of file diff --git a/packages/v1-components/storybook/stories/UiSelect.remote.ts b/packages/v1-components/storybook/stories/UiSelect.remote.ts new file mode 100644 index 00000000..f86e3c9e --- /dev/null +++ b/packages/v1-components/storybook/stories/UiSelect.remote.ts @@ -0,0 +1,73 @@ +import { UiSelect } from '../../src/remote/components/select' +import { UiSelectOption } from '../../src/remote/components/select' + +import { createComponentEndpoint } from '../endpoint' +import { h } from 'vue' + +import IconNotification from '../../assets/sprites/alerts/notifications.svg' +import IconWarning from '../../assets/sprites/alerts/warning.svg' +import IconError from '../../assets/sprites/alerts/error-outlined.svg' + +type UiSelectProps = InstanceType['$props'] + +createComponentEndpoint({ + async run (createApp, root, props) { + const app = createApp({ + setup ( ) { + return () => h(UiSelect, { + ...props, + equalsFn: (a: unknown, b: unknown) => a === b, + },{ + default: () => + [ + 'Kyle Simmmons', + 'Eduardo Henry', + 'Philip Williamson', + 'Max Miles', + 'Caroline Allen', + 'Joanne Thompson Joanne Thompson Joanne Thompson Thompson Thompson', + 'DAD', + ].map(t => + h(UiSelectOption, { + value: t, + label: t, + }, { + 'leading-icon': ({ selected }: { selected: boolean }) => { + if (selected) { + return h(IconWarning, { + class: 'ui-v1-select-option__checkmark-icon', + 'aria-hidden': 'true', + }) + } + + return null + }, + + 'trailing-icon': ({ selected }: { selected: boolean }) => { + if (selected) { + return h(IconNotification, { + class: 'ui-v1-select-option__checkmark-icon', + 'aria-hidden': 'true', + }) + } + + if (props.multiple) { + return h(IconError, { + class: 'ui-v1-select-option__add-icon', + 'aria-hidden': 'true', + }) + } + + return null + }, + }) + ), + }) + }, + }) + + app.mount(root) + + return () => app.unmount() + }, +}, self as unknown as Worker) diff --git a/packages/v1-components/storybook/stories/UiSelect.stories.ts b/packages/v1-components/storybook/stories/UiSelect.stories.ts new file mode 100644 index 00000000..c18d07dc --- /dev/null +++ b/packages/v1-components/storybook/stories/UiSelect.stories.ts @@ -0,0 +1,120 @@ +import type { Callable } from '../endpoint' +import type { Lifecycle } from '../endpoint' +import type { Meta } from '@storybook/vue3' +import type { StoryObj } from '@storybook/vue3' + +import UiMenuItem from '@/host/components/menu/UiMenuItem.vue' +import UiMenuItemGroup from '@/host/components/menu/UiMenuItemGroup.vue' +import UiPopperConnector from '@/host/components/popper/UiPopperConnector.vue' +import UiSelectPopper from '@/host/components/select/UiSelectPopper.vue' +import UiSelectTrigger from '@/host/components/select/UiSelectTrigger.vue' + +import { UiSelect } from '../../src/remote/components/select' + +import { HostedTree } from '@omnicajs/vue-remote/host' +import { createEndpoint } from '@remote-ui/rpc' +import { createProvider } from '@omnicajs/vue-remote/host' +import { createReceiver } from '@omnicajs/vue-remote/host' +import { watch } from 'vue' + +import page from './UiSelect.mdx' + +import { SIZE } from '@/common/components/select' +import { PLACEMENT } from '@/common/components/select' + +const provider = createProvider({ + UiMenuItem, + UiMenuItemGroup, + UiPopperConnector, + UiSelectPopper, + UiSelectTrigger, +}) +const receiver = createReceiver() + +const meta = { + title: 'Components/UiSelect', + + component: UiSelect, + + argTypes: { + id: { control: false }, + value: { control: false }, + expanded: { control: 'boolean' }, + clearable: { control: 'boolean' }, + placeholder: { control: 'text' }, + filterable: { control: 'boolean' }, + invalid: { control: 'boolean' }, + onlyPlaceholder: { control: 'boolean' }, + readonly: { control: 'boolean' }, + disabled: { control: 'boolean' }, + multiple: { control: 'boolean' }, + ticker: { control: 'boolean' }, + + inputSize: { + options: Object.values(SIZE), + }, + + placement: { + options: Object.values(PLACEMENT), + }, + + popperFitTrigger: { control: 'boolean' }, + popperClass: { control: 'text' }, + popperOptions: { control: false }, + targetTriggers: { control: false }, + popperTriggers: { control: false }, + }, + + render: (args) => ({ + components: { + HostedTree, + UiMenuItem, + UiMenuItemGroup, + UiPopperConnector, + UiSelectPopper, + UiSelectTrigger, + }, + + setup () { + const worker = new Worker(new URL('./UiSelect.remote.ts', import.meta.url), { type: 'module'}) + + const endpoint = createEndpoint(worker) + + endpoint.call.run(receiver.receive, args) + + watch(args, (newArgs) => { + endpoint.call.setProps(newArgs) + }) + + return { + args, + provider, + receiver, + } + }, + + template: ` + + `, + }), + + parameters: { + docs: { page }, + layout: 'centered', + }, +} satisfies Meta + +// noinspection JSUnusedGlobalSymbols +export default meta + +type Story = StoryObj; + +export const Sandbox: Story = { + args: { + placeholder: 'test123', + ticker: false, + disabled: false, + multiple: false, + filterable: false, + }, +} diff --git a/packages/v1-components/storybook/tsconfig.json b/packages/v1-components/storybook/tsconfig.json index 856762ce..4862b74a 100644 --- a/packages/v1-components/storybook/tsconfig.json +++ b/packages/v1-components/storybook/tsconfig.json @@ -2,6 +2,10 @@ "extends": "../tsconfig.json", "include": [ "storybook/**/*.stories.ts", - "storybook/**/*.vue" + "storybook/**/*.vue", + "stories/**/*.ts", + "stories/**/*.vue", + "stories/**/*.mdx", + "./../shims-*.d.ts", ] } From 55cdfaed1bcafbfd2bfac73988aa131f77434f9e Mon Sep 17 00:00:00 2001 From: Kirill Zaytsev Date: Wed, 11 Feb 2026 20:05:59 +0400 Subject: [PATCH 2/9] style: Eslint rules update --- eslint.config.js | 72 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 73e4e7f3..66b3830f 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -15,6 +15,9 @@ export default [ }, }, rules: { + 'brace-style': ['error', '1tbs', { + allowSingleLine: true, + }], 'comma-dangle': ['error', { arrays: 'always-multiline', exports: 'always-multiline', @@ -22,13 +25,43 @@ export default [ imports: 'always-multiline', objects: 'always-multiline', }], + 'eqeqeq': ['error', 'always'], 'indent': ['error', 2, { - 'ignoreComments': true, - 'SwitchCase': 1, + ignoreComments: true, + SwitchCase: 1, + }], + 'keyword-spacing': ['error', { + before: true, + after: true, + overrides: { + catch: { before: true, after: true }, + }, }], + 'linebreak-style': [2, 'unix'], + 'no-debugger': 'error', + 'no-empty': 'off', + 'no-multiple-empty-lines': ['error', { + max: 1, + maxBOF: 0, + maxEOF: 0, + }], + 'no-new-wrappers': 'error', + 'no-prototype-builtins': 'error', + 'no-shadow-restricted-names': 'error', + 'no-throw-literal': 'error', + 'no-trailing-spaces': ['error'], + 'no-unsafe-optional-chaining': 'off', + 'no-useless-escape': 'off', + 'object-curly-spacing': ['error', 'always'], + 'padded-blocks': ['error', 'never'], 'quotes': ['error', 'single'], 'semi': ['error', 'never'], + 'space-infix-ops': ['error', { 'int32Hint': false }], + '@typescript-eslint/consistent-type-imports': ['error', { + prefer: 'type-imports', + fixStyle: 'separate-type-imports', + }], '@typescript-eslint/naming-convention': 'off', }, }, @@ -41,10 +74,41 @@ export default [ parserOptions: { parser: pluginTs.parser }, }, rules: { - 'vue/html-indent': ['error', 4], + 'vue/attributes-order': 'error', + 'vue/component-definition-name-casing': ['error', 'PascalCase'], + 'vue/component-name-in-template-casing': ['error', 'PascalCase'], + 'vue/first-attribute-linebreak': 'error', + 'vue/html-closing-bracket-newline': ['error', { + multiline: 'always', + singleline: 'never', + }], + 'vue/html-closing-bracket-spacing': 'error', + 'vue/html-indent': ['error', 4, { + attribute: 1, + closeBracket: 0, + alignAttributesVertically: true, + ignores: [], + }], + 'vue/html-self-closing': ['error', { + html: { + component: 'always', + normal: 'always', + void: 'always', + }, + math: 'always', + svg: 'always', + }], + 'vue/no-required-prop-with-default': 'error', + 'vue/max-attributes-per-line': ['error', { + singleline: 4, + multiline: { + max: 1, + }, + }], + 'vue/one-component-per-file': 'off', 'indent': ['error', 2, { ignoreComments: true, SwitchCase: 1 }], }, }, { ignores: ['dist/*'] }, { ignores: ['**/dist/*'] }, -] \ No newline at end of file +] From 0f4905090198670592c2be5df6ece7221a944dbb Mon Sep 17 00:00:00 2001 From: Kirill Zaytsev Date: Wed, 11 Feb 2026 20:16:34 +0400 Subject: [PATCH 3/9] style: Applied updated eslint rules --- index.d.ts | 2 +- .../src/common/components/tag.ts | 2 +- .../v1-components/src/common/predicate.ts | 2 +- .../src/host/components/avatar/injection.ts | 2 +- .../host/components/checkbox/UiCheckbox.vue | 2 +- .../components/copy-button/UiCopyButton.vue | 2 +- .../src/host/components/date/UiDate.vue.d.ts | 1 - .../src/host/components/image/UiImage.vue | 2 +- .../src/host/components/menu/UiMenuItem.vue | 2 +- .../components/menu/UiMenuItemGroup.vue.d.ts | 1 - .../src/host/components/modal/layer.ts | 30 ++++++++--------- .../host/components/popper/UiPopper.vue.d.ts | 2 +- .../src/host/components/popper/composables.ts | 2 +- .../src/host/components/radio/UiRadio.vue | 2 +- .../host/components/select/UiSelectPopper.vue | 8 ++--- .../components/select/UiSelectPopper.vue.d.ts | 2 +- .../components/tooltip/UiTooltip.vue.d.ts | 2 +- .../src/remote/components/menu.ts | 2 +- .../src/remote/components/modal-sidebar.ts | 2 +- .../src/remote/components/select/UiSelect.vue | 2 -- .../components/select/UiSelectOption.vue | 32 +++++++++---------- .../src/remote/components/yandex-map.ts | 2 +- packages/v1-components/storybook/endpoint.ts | 7 ++-- .../storybook/stories/UiLink.stories.ts | 2 +- .../storybook/stories/UiMenuItem.stories.ts | 2 +- .../stories/UiModalWindow.stories.ts | 8 ++--- .../storybook/stories/UiSelect.stories.ts | 2 +- packages/v1-contexts/src/common/order/card.ts | 2 +- packages/v1-contexts/src/common/settings.ts | 2 +- .../tests/__util__/createAccessor.ts | 2 +- src/composables.ts | 2 +- tests/__util__/createAccessor.ts | 2 +- 32 files changed, 65 insertions(+), 72 deletions(-) diff --git a/index.d.ts b/index.d.ts index ada78497..f72ff0f6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -9,7 +9,7 @@ import type { RemoteCallable, } from '@remote-ui/rpc' -import { +import type { ContextAccessor, ContextSchema, CustomFieldKind, diff --git a/packages/v1-components/src/common/components/tag.ts b/packages/v1-components/src/common/components/tag.ts index 0ab249af..c268ecaa 100644 --- a/packages/v1-components/src/common/components/tag.ts +++ b/packages/v1-components/src/common/components/tag.ts @@ -22,7 +22,7 @@ type StyleDeclaration = CSSStyleDeclaration & { export function deltaTransition(el: HTMLElement): Partial { const delta = el.scrollWidth - el.clientWidth const animationDuration = `${((el.scrollWidth / el.clientWidth) * 2).toFixed(2)}s` - + return delta !== 0 ? { '--delta-width': `-${delta}px`, animationDuration, diff --git a/packages/v1-components/src/common/predicate.ts b/packages/v1-components/src/common/predicate.ts index d1ac1edd..eebd2cd5 100644 --- a/packages/v1-components/src/common/predicate.ts +++ b/packages/v1-components/src/common/predicate.ts @@ -13,6 +13,6 @@ export const isURL = (href: string, loose = true): boolean => { ].some(href => isURL(href, false)) } - return false + return false } } diff --git a/packages/v1-components/src/host/components/avatar/injection.ts b/packages/v1-components/src/host/components/avatar/injection.ts index 9f5d9173..5cd51990 100644 --- a/packages/v1-components/src/host/components/avatar/injection.ts +++ b/packages/v1-components/src/host/components/avatar/injection.ts @@ -3,6 +3,6 @@ import type { ComputedRef, } from 'vue' -import { SIZE } from '@/common/components/avatar' +import type { SIZE } from '@/common/components/avatar' export const AvatarSizeKey = Symbol('UiAvatarSize') as InjectionKey> diff --git a/packages/v1-components/src/host/components/checkbox/UiCheckbox.vue b/packages/v1-components/src/host/components/checkbox/UiCheckbox.vue index d0e47545..fb50bb4b 100644 --- a/packages/v1-components/src/host/components/checkbox/UiCheckbox.vue +++ b/packages/v1-components/src/host/components/checkbox/UiCheckbox.vue @@ -20,7 +20,7 @@ type="checkbox" class="ui-v1-checkbox__input" @change="onChange" - > + /> + /> diff --git a/packages/v1-components/src/host/components/date/UiDate.vue.d.ts b/packages/v1-components/src/host/components/date/UiDate.vue.d.ts index d820a997..31fce10f 100644 --- a/packages/v1-components/src/host/components/date/UiDate.vue.d.ts +++ b/packages/v1-components/src/host/components/date/UiDate.vue.d.ts @@ -9,4 +9,3 @@ declare const UiDate: DefineComponent< > export default UiDate - diff --git a/packages/v1-components/src/host/components/image/UiImage.vue b/packages/v1-components/src/host/components/image/UiImage.vue index 790650dd..57630075 100644 --- a/packages/v1-components/src/host/components/image/UiImage.vue +++ b/packages/v1-components/src/host/components/image/UiImage.vue @@ -3,7 +3,7 @@ :alt="alt" :src="url" v-bind="$attrs" - > + /> -