diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fdda9ec380..69bf6b5507 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -914,6 +914,9 @@ importers: semcore/dropdown: dependencies: + '@semcore/notice': + specifier: ^17.2.2 + version: link:../notice '@semcore/typography': specifier: ^17.2.1 version: link:../typography @@ -1508,6 +1511,10 @@ importers: version: link:../../tools/testing-utils semcore/pills: + dependencies: + '@semcore/typography': + specifier: ^17.2.1 + version: link:../typography devDependencies: '@semcore/badge': specifier: workspace:* @@ -19556,7 +19563,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.17 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@9.20.3)(jsdom@22.1.0)(lightningcss@1.31.1)(sass@1.100.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.8.3) + vitest: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@9.20.3)(jsdom@22.1.0)(lightningcss@1.31.1)(sass@1.100.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.48.0)(yaml@2.8.3) '@vitest/utils@3.2.4': dependencies: diff --git a/semcore/base-trigger/src/style/base-trigger.shadow.css b/semcore/base-trigger/src/style/base-trigger.shadow.css index 2046743fc6..f23c8ddc87 100644 --- a/semcore/base-trigger/src/style/base-trigger.shadow.css +++ b/semcore/base-trigger/src/style/base-trigger.shadow.css @@ -8,7 +8,6 @@ SBaseTrigger { white-space: nowrap; user-select: none; box-sizing: border-box; - padding: 0; margin: 0; box-shadow: none; text-decoration: none; @@ -19,12 +18,15 @@ SBaseTrigger { font-family: inherit; cursor: pointer; - background: var(--intergalactic-bg-primary-neutral, oklch(1 0 0)); /* TODO: --intergalactic-control-select-trigger-normal */ + background: var(--intergalactic-control-select-trigger-normal, oklch(1 0 0)); font-weight: var(--intergalactic-regular, 400); border: 1px solid var(--intergalactic-border-primary, oklch(0.137 0.026 175.7 / 0.161)); color: var(--intergalactic-text-primary, oklch(0.1 0.03 137 / 0.899)); + border-radius: var(--intergalactic-control-rounded, 6px); + padding: 0 var(--intergalactic-spacing-content-inset-inline, 12px); + &::-moz-focus-inner { border: none; padding: 0; @@ -40,13 +42,13 @@ SBaseTrigger { } &:hover { - background-color: var(--intergalactic-bg-primary-neutral-hover, oklch(0.98 0.001 180)); /* TODO: --intergalactic-control-select-trigger-hover */ + background-color: var(--intergalactic-control-select-trigger-hover, oklch(0.98 0.001 180)); } &:active, &[active] { border-color: var(--intergalactic-border-info-active, oklch(0.7 0.131 275.2)); - background-color: var(--intergalactic-bg-primary-neutral, oklch(1 0 0)); /* TODO: --intergalactic-control-select-trigger-active */ + background-color: var(--intergalactic-control-select-trigger-active, oklch(1 0 0)); } } @@ -61,6 +63,7 @@ SInner { display: inline-flex; align-items: center; justify-content: center; + gap: var(--intergalactic-spacing-content-gap-medium, 6px); height: 100%; width: 100%; } @@ -68,11 +71,9 @@ SInner { SText { display: inline; /* disable-tokens-validator */ - padding: 1px 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; - line-height: var(--intergalactic-lh-200, 142%); flex-grow: 1; text-align: left; } @@ -83,57 +84,25 @@ SAddon { justify-content: center; flex-shrink: 0; pointer-events: none; -} -SBaseAddon { - width: 12px; - height: 12px; + &:only-child { + margin-left: calc(-1 * var(--intergalactic-spacing-1x, 4px)); + margin-right: calc(-1 * var(--intergalactic-spacing-1x, 4px)); + } } SBaseTrigger[size='m'] { min-width: var(--intergalactic-form-control-m, 32px); height: var(--intergalactic-form-control-m, 32px); - border-radius: var(--intergalactic-control-rounded, 6px); - padding: 0 var(--intergalactic-spacing-2x, 8px); font-size: var(--intergalactic-fs-200, 14px); - - & SAddon { - &:not(:only-child):first-child { - margin-right: var(--intergalactic-spacing-2x, 8px); - } - - &:not(:only-child):last-child { - margin-left: var(--intergalactic-spacing-2x, 8px); - } - - &:only-child { - margin-left: calc(-1 * var(--intergalactic-spacing-1x, 4px)); - margin-right: calc(-1 * var(--intergalactic-spacing-1x, 4px)); - } - } + line-height: var(--intergalactic-lh-200, 142%); } SBaseTrigger[size='l'] { min-width: var(--intergalactic-form-control-l, 44px); height: var(--intergalactic-form-control-l, 44px); - border-radius: var(--intergalactic-control-rounded, 6px); - padding: 0 var(--intergalactic-spacing-3x, 12px); font-size: var(--intergalactic-fs-300, 16px); - - & SAddon { - &:not(:only-child):first-child { - margin-right: var(--intergalactic-spacing-2x, 8px); - } - - &:not(:only-child):last-child { - margin-left: var(--intergalactic-spacing-2x, 8px); - } - - &:only-child { - margin-left: calc(-1 * var(--intergalactic-spacing-1x, 4px)); - margin-right: calc(-1 * var(--intergalactic-spacing-1x, 4px)); - } - } + line-height: var(--intergalactic-lh-300, 150%); } SBaseTrigger[neighborLocation='right'] { diff --git a/semcore/base-trigger/src/style/button-trigger.shadow.css b/semcore/base-trigger/src/style/button-trigger.shadow.css index 29b3fb18e8..f31559c95a 100644 --- a/semcore/base-trigger/src/style/button-trigger.shadow.css +++ b/semcore/base-trigger/src/style/button-trigger.shadow.css @@ -1,8 +1,11 @@ SButtonAddon { - width: 12px; - height: 12px; + width: var(--intergalactic-spacing-3x, 12px); + height: var(--intergalactic-spacing-3x, 12px); + color: var(--intergalactic-icon-non-interactive, oklch(0.094 0.024 153.9 / 0.503)); + position: relative; + left: var(--intergalactic-spacing-05x, 2px); } SButtonTriggerSpin { - fill: var(--intergalactic-icon-primary-neutral, oklch(0.092 0.024 152.2 / 0.526)); + fill: var(--intergalactic-icon-non-interactive, oklch(0.094 0.024 153.9 / 0.503)); } diff --git a/semcore/data-table/__tests__/data-table-states.browser-test.tsx-snapshots/-visual-Limited-mode-Verify-limited-state-for-table-with-accordion-keyboard-and-mouse-interactions-1-webkit-linux.png b/semcore/data-table/__tests__/data-table-states.browser-test.tsx-snapshots/-visual-Limited-mode-Verify-limited-state-for-table-with-accordion-keyboard-and-mouse-interactions-1-webkit-linux.png index 9455cfbbf8..ee307a4080 100644 Binary files a/semcore/data-table/__tests__/data-table-states.browser-test.tsx-snapshots/-visual-Limited-mode-Verify-limited-state-for-table-with-accordion-keyboard-and-mouse-interactions-1-webkit-linux.png and b/semcore/data-table/__tests__/data-table-states.browser-test.tsx-snapshots/-visual-Limited-mode-Verify-limited-state-for-table-with-accordion-keyboard-and-mouse-interactions-1-webkit-linux.png differ diff --git a/semcore/drag-and-drop/src/style/drag-and-drop.shadow.css b/semcore/drag-and-drop/src/style/drag-and-drop.shadow.css index a53b2a6d45..ee3585dc48 100644 --- a/semcore/drag-and-drop/src/style/drag-and-drop.shadow.css +++ b/semcore/drag-and-drop/src/style/drag-and-drop.shadow.css @@ -98,7 +98,7 @@ SDropZone[dropPreview] { SDropZone[dark][dropPreview] { - background-color: var(--intergalactic-bg-primary-invert-active, oklch(0.4 0.004 140)); + background-color: var(--intergalactic-bg-primary-invert-active, oklch(0.36 0.005 140)); } SDraggable[keyboardDragging] { diff --git a/semcore/dropdown-menu/src/DropdownMenu.jsx b/semcore/dropdown-menu/src/DropdownMenu.jsx index 8c3b7498fe..7ea55290a5 100644 --- a/semcore/dropdown-menu/src/DropdownMenu.jsx +++ b/semcore/dropdown-menu/src/DropdownMenu.jsx @@ -570,6 +570,7 @@ const DropdownMenu = createComponent( Item: [Item, { Addon, Content: ItemContent, Text: ItemContentText, Hint: ItemHint }], Group: Dropdown.Group, StatusItem: Dropdown.StatusItem, + Notice: Dropdown.Notice, }, { parent: [Dropdown], diff --git a/semcore/dropdown-menu/src/index.d.ts b/semcore/dropdown-menu/src/index.d.ts index 85260d57c9..49d2d68739 100644 --- a/semcore/dropdown-menu/src/index.d.ts +++ b/semcore/dropdown-menu/src/index.d.ts @@ -154,8 +154,8 @@ declare const DropdownMenu: Intergalactic.Component< }; Group: typeof Dropdown.Group; - StatusItem: StatusItemComponent; + Notice: DropdownNoticeComponent; VirtualList: typeof VirtualList; diff --git a/semcore/dropdown-menu/src/style/dropdown-menu.shadow.css b/semcore/dropdown-menu/src/style/dropdown-menu.shadow.css index 6f3453c496..1b13ef106e 100644 --- a/semcore/dropdown-menu/src/style/dropdown-menu.shadow.css +++ b/semcore/dropdown-menu/src/style/dropdown-menu.shadow.css @@ -1,5 +1,5 @@ SDropdownMenuList { - max-height: 240px; + max-height: 246px; padding: var(--intergalactic-spacing-1x, 4px) 0; position: relative; min-height: 26px; @@ -29,6 +29,10 @@ SDropdownMenuList { } } +SDropdownMenuList[size='l'] { + max-height: 306px; +} + SDropdownMenuItemContainer { SItemContent:focus-visible { outline: none; @@ -42,11 +46,13 @@ SDropdownMenuItemContainer[nesting-trigger] { SDropdownMenuItemAddon, SItemContentText { display: inline-flex; /* todo: Brauer Ilia - why? should be changed to inline/inline-block for SItemContentText */ - margin-left: var(--intergalactic-spacing-1x, 4px); - margin-right: var(--intergalactic-spacing-1x, 4px); + + margin-left: var(--intergalactic-spacing-content-gap-small, 4px); + margin-right: var(--intergalactic-spacing-content-gap-small, 4px); &:first-child { margin-left: 0; + margin-right: var(--intergalactic-spacing-content-gap-medium, 6px); } &:last-child { diff --git a/semcore/dropdown/package.json b/semcore/dropdown/package.json index 25446d3b97..6d1302a961 100644 --- a/semcore/dropdown/package.json +++ b/semcore/dropdown/package.json @@ -17,7 +17,8 @@ "require": "./lib/cjs/index.js" }, "dependencies": { - "@semcore/typography": "^17.2.1" + "@semcore/typography": "^17.2.1", + "@semcore/notice": "^17.2.2" }, "peerDependencies": { "@semcore/base-components": "^17.2.1" diff --git a/semcore/dropdown/src/Dropdown.jsx b/semcore/dropdown/src/Dropdown.jsx index 942cbe801c..5a5aed417b 100644 --- a/semcore/dropdown/src/Dropdown.jsx +++ b/semcore/dropdown/src/Dropdown.jsx @@ -7,6 +7,7 @@ import { hasFocusableIn } from '@semcore/core/lib/utils/use/useFocusLock'; import React from 'react'; import { DropdownItem } from './DropdownItem'; +import { DropdownNotice } from './Notice'; import { StatusItem } from './StatusItem'; import style from './style/dropdown.shadow.css'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; @@ -212,6 +213,7 @@ const Dropdown = createComponent( Item: DropdownItem, Group: DropdownGroup, StatusItem, + Notice: DropdownNotice, }, { parent: Popper, diff --git a/semcore/dropdown/src/Notice.tsx b/semcore/dropdown/src/Notice.tsx new file mode 100644 index 0000000000..b057cf9a5d --- /dev/null +++ b/semcore/dropdown/src/Notice.tsx @@ -0,0 +1,25 @@ +import { Component, createComponent, Root, sstyled } from '@semcore/core'; +import Notice, { type NSNotice } from '@semcore/notice'; +import React from 'react'; + +import style from './style/dropdownNotice.shadow.css'; + +class DropdownNoticeRoot extends Component { + static displayName = 'Notice'; + static style = style; + + render() { + const { styles } = this.asProps; + const SDropdownNotice = Root; + return sstyled(styles)(); + } +} + +export const DropdownNotice = createComponent(DropdownNoticeRoot, { + Label: Notice.Label, + Title: Notice.Title, + Text: Notice.Text, + Actions: Notice.Actions, + Content: Notice.Content, + Close: Notice.Close, +}, { parent: Notice }); diff --git a/semcore/dropdown/src/StatusItem.tsx b/semcore/dropdown/src/StatusItem.tsx index e207d31def..6836081fa4 100644 --- a/semcore/dropdown/src/StatusItem.tsx +++ b/semcore/dropdown/src/StatusItem.tsx @@ -38,7 +38,8 @@ class StatusItemRoot extends Component< render={Text} tag='div' key='StatusItem' - p={size === 'l' ? 3 : 2} + px={3} + py={size === 'l' ? 3 : 2} use:size={size === 'l' ? 300 : 200} use='secondary' > diff --git a/semcore/dropdown/src/index.d.ts b/semcore/dropdown/src/index.d.ts index 244a66abad..41115001fe 100644 --- a/semcore/dropdown/src/index.d.ts +++ b/semcore/dropdown/src/index.d.ts @@ -7,6 +7,8 @@ import type { Box, BoxProps, PopperPopperProps, } from '@semcore/base-components'; import type { Intergalactic, PropGetterFn } from '@semcore/core'; +import type { NSNotice } from '@semcore/notice'; +import type Notice from '@semcore/notice'; import type React from 'react'; export type DropdownProps = PopperProps & { @@ -71,6 +73,9 @@ export type DropdownStatusItemProps = { export type StatusItemComponent = Intergalactic.Component<'div', DropdownStatusItemProps>; +export type DropdownNoticeProps = NSNotice.Props; +export type DropdownNoticeComponent = Intergalactic.Component; + declare const Dropdown: Intergalactic.Component< 'div', DropdownProps, @@ -87,6 +92,7 @@ declare const Dropdown: Intergalactic.Component< Item: Intergalactic.Component; Group: Intergalactic.Component<'div', DropdownGroupProps>; StatusItem: StatusItemComponent; + DropdownNotice: DropdownNoticeComponent; }; export default Dropdown; diff --git a/semcore/dropdown/src/style/dropdown.shadow.css b/semcore/dropdown/src/style/dropdown.shadow.css index eef34c1d96..05bc6eeaf8 100644 --- a/semcore/dropdown/src/style/dropdown.shadow.css +++ b/semcore/dropdown/src/style/dropdown.shadow.css @@ -14,13 +14,13 @@ SDropdownPopper { text-decoration: none; box-sizing: border-box; cursor: pointer; - width: 100%; text-align: left; line-height: normal; outline: none; } - + SDropdownItem:not(button) { + width: 100%; color: var(--intergalactic-text-primary, oklch(0.1 0.03 137 / 0.899)); &:hover { @@ -28,6 +28,11 @@ SDropdownPopper { } } + SDropdownItem[size='l'] SDropdownItem:is(button) { + width: var(--intergalactic-spacing-6x, 24px); + height: var(--intergalactic-spacing-6x, 24px); + } + SDropdownItem[isMenuItemCheckbox] { &::before, @@ -36,7 +41,7 @@ SDropdownPopper { position: absolute; border: 1px solid; border-radius: var(--intergalactic-addon-rounded, 4px); - box-sizing: content-box; + box-sizing: border-box; } &::before { @@ -51,13 +56,20 @@ SDropdownPopper { background-position: center center; background-color: var(--intergalactic-control-primary-info, oklch(0.23 0.01 140)); border-color: var(--intergalactic-control-primary-info, oklch(0.23 0.01 140)); - background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNyIgdmlld0JveD0iMCAwIDEwIDciIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik04LjI1IDFMNCA1LjI1TDEuNzUgMyIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+Cg=='); + } + + &[selected][size='m']::after { + background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTAiIHZpZXdCb3g9IjAgMCAxMiAxMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAuMzEwNyAyLjE2NzkxTDQuNjQ2NDUgNy44MzIxMkwxLjY4OTM0IDQuODc1MDEiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZT0id2hpdGUiLz48L3N2Zz4='); + } + + &[selected][size='l']::after { + background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTIiIHZpZXdCb3g9IjAgMCAxNCAxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIuNCAyLjQ1MjIxTDUuMzA0NCA5LjU0NzgyTDEuNjAwMDEgNS44NDM0MyIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvc3ZnPg=='); } } SDropdownItem[selected]:not(SDropdownItem[isMenuItemCheckbox]) { background-color: var(--intergalactic-dropdown-menu-item-selected, oklch(0.525 0.265 263 / 0.077)); - box-shadow: 2px 0px 0px 0px var(--intergalactic-control-primary-info, oklch(0.23 0.01 140)) inset; /* TODO: --intergalactic-dropdown-menu-item-selected-border */ + box-shadow: 2px 0px 0px 0px var(--intergalactic-dropdown-menu-item-selected-box-shadow, oklch(0.23 0.01 140)) inset; &:hover { background-color: var(--intergalactic-dropdown-menu-item-selected-hover, oklch(0.52 0.268 263.2 / 0.191)); @@ -87,18 +99,19 @@ SDropdownPopper { SDropdownItem[size='l'] { font-size: var(--intergalactic-fs-300, 16px); line-height: var(--intergalactic-lh-300, 150%); - padding: var(--intergalactic-spacing-2x, 8px) var(--intergalactic-spacing-3x, 12px); - min-height: 40px; + padding: var(--intergalactic-spacing-2x, 8px) var(--intergalactic-spacing-content-inset-inline, 12px); + min-height: var(--intergalactic-spacing-10x, 40px); &[isMenuItemCheckbox] { - padding-left: calc(var(--intergalactic-spacing-3x, 12px) * 2 + 16px + 2px); /* padding*2 (parent item and from checkbox to content) + checkboxWidth + border*2 */ + padding-left: calc(var(--intergalactic-spacing-content-inset-inline, 12px) + var(--intergalactic-spacing-5x, 20px) + var(--intergalactic-spacing-content-gap-large, 8px)); + /* padding before + checkbox + padding after */ &::before, &::after { - width: 20px; - height: 20px; - top: calc(var(--intergalactic-spacing-2x, 8px) - 1px); - left: var(--intergalactic-spacing-3x, 12px); + width: var(--intergalactic-spacing-5x, 20px); + height: var(--intergalactic-spacing-5x, 20px); + top: calc(var(--intergalactic-spacing-2x, 8px) + var(--intergalactic-spacing-05x, 2px)); + left: var(--intergalactic-spacing-content-inset-inline, 12px); } } } @@ -106,18 +119,19 @@ SDropdownPopper { SDropdownItem[size='m'] { font-size: var(--intergalactic-fs-200, 14px); line-height: var(--intergalactic-lh-200, 142%); - padding: calc(var(--intergalactic-spacing-1x, 4px) + var(--intergalactic-spacing-05x, 2px)) var(--intergalactic-spacing-2x, 8px); - min-height: 32px; + padding: calc(var(--intergalactic-spacing-1x, 4px) + var(--intergalactic-spacing-05x, 2px)) var(--intergalactic-spacing-content-inset-inline, 12px); + min-height: var(--intergalactic-form-control-m, 32px); &[isMenuItemCheckbox] { - padding-left: calc(var(--intergalactic-spacing-2x, 8px) * 2 + 16px + 2px); /* padding*2 (parent item and from checkbox to content) + checkboxWidth + border*2 */ + padding-left: calc(var(--intergalactic-spacing-content-inset-inline, 12px) + var(--intergalactic-spacing-4x, 16px) + var(--intergalactic-spacing-content-gap-medium, 6px)); + /* padding before + checkbox + padding after */ &::before, &::after { - width: 16px; - height: 16px; - top: calc(var(--intergalactic-spacing-2x, 8px) - 1px); - left: var(--intergalactic-spacing-2x, 8px); + width: var(--intergalactic-spacing-4x, 16px); + height: var(--intergalactic-spacing-4x, 16px); + top: var(--intergalactic-spacing-2x, 8px); + left: var(--intergalactic-spacing-content-inset-inline, 12px); } } } diff --git a/semcore/dropdown/src/style/dropdownNotice.shadow.css b/semcore/dropdown/src/style/dropdownNotice.shadow.css new file mode 100644 index 0000000000..ee1173fdd7 --- /dev/null +++ b/semcore/dropdown/src/style/dropdownNotice.shadow.css @@ -0,0 +1,9 @@ +SDropdownNotice { + padding-top: var(--intergalactic-spacing-content-inset-inline, 12px); + padding-bottom: var(--intergalactic-spacing-content-inset-inline, 12px); + border-left: none; + border-right: none; + border-bottom: none; + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/semcore/feature-popover/src/style/feature-popover.shadow.css b/semcore/feature-popover/src/style/feature-popover.shadow.css index 4df66ad267..ada19867ce 100644 --- a/semcore/feature-popover/src/style/feature-popover.shadow.css +++ b/semcore/feature-popover/src/style/feature-popover.shadow.css @@ -13,7 +13,7 @@ SFeaturePopover { color: var(--intergalactic-text-primary, oklch(0.1 0.03 137 / 0.899)); /* TODO: --intergalactic-feature-popover-text */ } &[theme='neutral'] { - background-color: var(--intergalactic-feature-popover-bg-neutral, oklch(0.23 0.01 140)); /* TODO: --intergalactic-feature-popover-bg-neutral */ + background-color: var(--intergalactic-feature-popover-bg-neutral, oklch(0.21 0.01 140)); /* TODO: --intergalactic-feature-popover-bg-neutral */ color: var(--intergalactic-text-primary-invert, oklch(0.999 0.001 180 / 0.949)); /* TODO: --intergalactic-feature-popover-text-invert */ } } diff --git a/semcore/input-tags/src/style/input-tag.shadow.css b/semcore/input-tags/src/style/input-tag.shadow.css index 08af38ed01..bb2b4daaf8 100644 --- a/semcore/input-tags/src/style/input-tag.shadow.css +++ b/semcore/input-tags/src/style/input-tag.shadow.css @@ -43,7 +43,7 @@ SInputTags>div[data-ui-name='ScrollArea.Bar'][orientation='vertical'] { SInputTags[size='m'] { min-height: var(--intergalactic-form-control-m, 32px); height: auto; - padding: 0 calc(var(--intergalactic-spacing-1x, 4px) + var(--intergalactic-spacing-05x, 2px)) 0 var(--intergalactic-spacing-1x, 4px); + padding: 0 calc(var(--intergalactic-spacing-2x, 8px) + var(--intergalactic-spacing-05x, 2px)) 0 var(--intergalactic-spacing-2x, 8px); } SInputTags[size='l'] { diff --git a/semcore/notice-bubble/src/style/notice-bubble.shadow.css b/semcore/notice-bubble/src/style/notice-bubble.shadow.css index 37f7a248b5..52de3e8f9c 100644 --- a/semcore/notice-bubble/src/style/notice-bubble.shadow.css +++ b/semcore/notice-bubble/src/style/notice-bubble.shadow.css @@ -12,7 +12,7 @@ SView { gap: var(--intergalactic-spacing-2x, 8px); &[type='info'] { - background: var(--intergalactic-bg-primary-invert, oklch(0.23 0.01 140)); /* TODO: --intergalactic-notice-bubble-bg-info */ + background: var(--intergalactic-bg-primary-invert, oklch(0.21 0.01 140)); /* TODO: --intergalactic-notice-bubble-bg-info */ } &[type='warning'] { diff --git a/semcore/pills/package.json b/semcore/pills/package.json index 9d1c9fe4b4..a5357d7f4b 100644 --- a/semcore/pills/package.json +++ b/semcore/pills/package.json @@ -16,6 +16,9 @@ "import": "./lib/esm/index.mjs", "require": "./lib/cjs/index.js" }, + "dependencies": { + "@semcore/typography": "^17.2.1" + }, "peerDependencies": { "@semcore/base-components": "^17.2.1" }, diff --git a/semcore/pills/src/Pills.tsx b/semcore/pills/src/Pills.tsx index 458ca5e28b..de7598dbe6 100644 --- a/semcore/pills/src/Pills.tsx +++ b/semcore/pills/src/Pills.tsx @@ -1,15 +1,21 @@ -import { NeighborLocation, Box, useNeighborLocationDetect } from '@semcore/base-components'; +import { Box } from '@semcore/base-components'; import type { Intergalactic } from '@semcore/core'; import { createComponent, Component, sstyled, Root } from '@semcore/core'; import addonTextChildren from '@semcore/core/lib/utils/addonTextChildren'; +import canUseDOM from '@semcore/core/lib/utils/canUseDOM'; import a11yEnhance from '@semcore/core/lib/utils/enhances/a11yEnhance'; +import trottle from '@semcore/core/lib/utils/rafTrottle'; +import { Text as SemcoreText } from '@semcore/typography'; import React from 'react'; import type { NSPills } from './Pills.type'; import style from './style/pills.shadow.css'; +const TRANSITION_SLOW_THRESHOLD = 1; + +type RootProps = Intergalactic.InternalTypings.InferComponentProps; class RootPills extends Component< - Intergalactic.InternalTypings.InferComponentProps, + RootProps, typeof RootPills.enhance, NSPills.Handlers, {}, @@ -18,7 +24,7 @@ class RootPills extends Component< > { static displayName = 'Pills'; static style = style; - static defaultProps = ({ behavior }: Intergalactic.InternalTypings.InferComponentProps) => ({ + static defaultProps = ({ behavior }: RootProps) => ({ size: 'm', defaultValue: null, behavior: behavior ?? 'auto', @@ -26,6 +32,15 @@ class RootPills extends Component< itemValues: Array = []; + lastSelectedIndex: number | null = null; + currentSelectedIndex: number | null = null; + + rootRef: React.MutableRefObject = React.createRef(); + pills: Array = []; + segmentIndicatorRef: React.MutableRefObject = React.createRef(); + + ro: ResizeObserver | null = null; + static enhance = [a11yEnhance({ onNeighborChange: (neighborElement, props) => { if (neighborElement) { @@ -42,12 +57,60 @@ class RootPills extends Component< }, })] as const; + constructor(props: RootProps) { + super(props); + if (canUseDOM()) { + this.ro = new ResizeObserver(trottle(() => this.updateSegmentIndicator())); + } + } + uncontrolledProps() { return { value: null, }; } + componentDidUpdate() { + this.updateSegmentIndicator(); + } + + componentDidMount() { + this.updateSegmentIndicator(); + + if (!this.ro) return; + + for (const pill of this.pills) { + this.ro.observe(pill); + } + } + + updateSegmentIndicator() { + if (this.currentSelectedIndex === null) return; + + const root = this.rootRef?.current; + const pill = this.pills[this.currentSelectedIndex]; + const indicator = this.segmentIndicatorRef?.current; + + if (!pill || !root || !indicator) return; + + const pillRect = pill.getBoundingClientRect(); + const rootRect = root.getBoundingClientRect(); + + const speed = this.lastSelectedIndex === null + ? '--transition-slow' + : Math.abs(this.currentSelectedIndex - this.lastSelectedIndex) > TRANSITION_SLOW_THRESHOLD + ? '--transition-slow' + : '--transition-fast'; + const left = pillRect.left - rootRect.left; + const width = pillRect.width; + const height = pillRect.height; + + indicator.style.setProperty('--global-speed', `var(${speed})`); + indicator.style.setProperty('--global-left', `${left}px`); + indicator.style.setProperty('--global-width', `${width}px`); + indicator.style.setProperty('--global-height', `${height}px`); + } + bindHandlerClick = (value: NSPills.Pill.Props['value']) => (e: React.MouseEvent) => { this.handlers.value(value, e); }; @@ -65,6 +128,11 @@ class RootPills extends Component< this.itemValues[index] = props.value; + if (isSelected) { + this.lastSelectedIndex = this.currentSelectedIndex; + this.currentSelectedIndex = index; + } + return { index: index, size, @@ -74,12 +142,18 @@ class RootPills extends Component< tabIndex: isSelected ? 0 : -1, onClick: this.bindHandlerClick(props.value), onKeyDown: this.bindHandleKeyDown(props.value), + ref: (node: HTMLButtonElement | null) => { + if (node === null) return; + + this.pills[index] = node; + }, }; } render() { const SPills = Root; - const { Children, styles, controlsLength, disabled, behavior, value } = this.asProps; + const SSegmentIndicator = Box; + const { Children, styles, disabled, behavior, value } = this.asProps; return sstyled(styles)( - - - + + , ); } @@ -98,8 +176,9 @@ class RootPills extends Component< function Pill(props: Intergalactic.InternalTypings.InferChildComponentProps) { const SPill = Root; - const { Children, styles, addonLeft, addonRight, selected, disabled, index, behavior } = props; - const neighborLocation = useNeighborLocationDetect(index); + const SPillContainer = Box; + const SPillSeparator = Box; + const { Children, styles, addonLeft, addonRight, selected, disabled, behavior, size } = props; const roleAreaProps = { 'role': behavior === 'auto' ? 'radio' : 'tab', @@ -108,25 +187,31 @@ function Pill(props: Intergalactic.InternalTypings.InferChildComponentProps - {addonLeft ? : null} - {addonTextChildren(Children, Pills.Item.Text, Pills.Item.Addon)} - {addonRight ? : null} - , + + + {addonLeft ? : null} + {addonTextChildren(Children, Pills.Item.Text, Pills.Item.Addon)} + {addonRight ? : null} + + + , ); } function Text(props: Intergalactic.InternalTypings.InferComponentProps) { const SText = Root; - return sstyled(props.styles)(); + return sstyled(props.styles)(); } function Addon(props: Intergalactic.InternalTypings.InferComponentProps) { diff --git a/semcore/pills/src/Pills.type.ts b/semcore/pills/src/Pills.type.ts index 8638f22305..5cd693a938 100644 --- a/semcore/pills/src/Pills.type.ts +++ b/semcore/pills/src/Pills.type.ts @@ -1,11 +1,12 @@ -import type { Box, BoxProps, NeighborItemProps, NeighborLocationProps } from '@semcore/base-components'; +import type { Box, BoxProps, NeighborItemProps } from '@semcore/base-components'; import type { PropGetterFn, Intergalactic } from '@semcore/core'; +import type { NSText } from '@semcore/typography'; import type React from 'react'; declare namespace NSPills { // TODO: It looks like the value isn't accurate. Revise and align it with the component's logic. type Value = string | number | boolean | null; - type Props = NeighborLocationProps & BoxProps & { + type Props = BoxProps & { /** Pills size */ size?: 'l' | 'm'; /** Disabled state */ @@ -55,7 +56,7 @@ declare namespace NSPills { addonRight?: React.ElementType; }; namespace Text { - type Component = typeof Box; + type Component = NSText.Component; } namespace Addon { type Component = typeof Box; diff --git a/semcore/pills/src/style/pills.shadow.css b/semcore/pills/src/style/pills.shadow.css index 127459adff..3d6056be64 100644 --- a/semcore/pills/src/style/pills.shadow.css +++ b/semcore/pills/src/style/pills.shadow.css @@ -1,156 +1,160 @@ SPills { + position: relative; display: inline-flex; - align-items: center; - justify-content: center; - isolation: isolate; - border-radius: var(--intergalactic-control-rounded, 6px); /* TODO: --intergalactic-pills-rounded */ + padding: var(--intergalactic-spacing-05x, 2px); + min-height: var(--intergalactic-form-control-m, 32px); + border-radius: var(--intergalactic-pills-rounded, 6px); + background: var(--intergalactic-control-pills-bg-normal, oklch(0.176 0.033 175.7 / 0.07)); + box-sizing: border-box; - SPill[selected] { - background: var(--intergalactic-control-secondary-info, oklch(0.527 0.264 262.9 / 0.039)); /* TODO: --intergalactic-control-pills-bg-selected */ - border-color: var(--intergalactic-border-info-active, oklch(0.7 0.131 275.2)); /* TODO: --intergalactic-box-shadow-pills-item-selected */ - z-index: 3; - } - SPill:focus-visible, SPill[selected] { - z-index: 3; + &[size='l'] { + min-height: var(--intergalactic-form-control-l, 44px); } - SPill:hover, SPill:active { - z-index: 2; + /* + TODO: switch to anchor realisation when layout changes will be supported by FF and Safari. + As of now JS fallback is used. + */ + /* &:has(SPill[aria-checked='true'], SPill[aria-selected='true']) { + SPill[aria-checked='true'], SPill[aria-selected='true'] { + anchor-name: --active-segment; + } + } */ + + SPillContainer { + &:last-of-type { + SPillSeparator { + display: none; + } + } } + + --transition-fast: + left calc(var(--intergalactic-duration-extra-fast, 100) * 1ms) var(--intergalactic-timing-fast, cubic-bezier(0.5, 0, 0, 1.26)), + width calc(var(--intergalactic-duration-extra-fast, 100) * 1ms) var(--intergalactic-timing-fast, cubic-bezier(0.5, 0, 0, 1.26)), + top calc(var(--intergalactic-duration-extra-fast, 100) * 1ms) var(--intergalactic-timing-fast, cubic-bezier(0.5, 0, 0, 1.26)), + height calc(var(--intergalactic-duration-extra-fast, 100) * 1ms) var(--intergalactic-timing-fast, cubic-bezier(0.5, 0, 0, 1.26)); + + --transition-slow: + left calc(var(--intergalactic-duration-medium, 300) * 1ms) var(--intergalactic-timing-medium, cubic-bezier(0.5, 0, 0, 1.13)), + width calc(var(--intergalactic-duration-medium, 300) * 1ms) var(--intergalactic-timing-medium, cubic-bezier(0.5, 0, 0, 1.13)), + top calc(var(--intergalactic-duration-medium, 300) * 1ms) var(--intergalactic-timing-medium, cubic-bezier(0.5, 0, 0, 1.13)), + height calc(var(--intergalactic-duration-medium, 300) * 1ms) var(--intergalactic-timing-medium, cubic-bezier(0.5, 0, 0, 1.13)); } SPill { - display: inline-flex; - align-items: center; - justify-content: center; - line-height: normal; position: relative; - touch-action: manipulation; - white-space: nowrap; - user-select: none; - box-sizing: border-box; - padding: 0; - margin: 0; - box-shadow: none; - text-decoration: none; - -webkit-tap-highlight-color: transparent; - overflow: visible; - text-align: center; - vertical-align: middle; - font-family: inherit; + cursor: pointer; - background: var(--intergalactic-bg-primary-neutral, oklch(1 0 0)); /* TODO: --intergalactic-control-pills-bg-normal */ - border: 1px solid var(--intergalactic-border-primary, oklch(0.137 0.026 175.7 / 0.161)); /* TODO: --intergalactic-control-pills-border */ - border-radius: var(--intergalactic-control-rounded, 6px); /* TODO: --intergalactic-pills-rounded */ - &::-moz-focus-inner { - border: none; - padding: 0; - } + display: inline-flex; + justify-content: center; + align-items: center; + gap: var(--intergalactic-spacing-content-gap-medium, 6px); - &:active { - outline: 0; - text-decoration: none; - } + min-width: 28px; + padding: 0 var(--intergalactic-spacing-content-inset-inline, 12px); + + border-style: solid; + border-color: transparent; + border-width: 1px 3px; + border-radius: var(--intergalactic-rounded-small, 4px); + + background-color: transparent; &:hover { - background: var(--intergalactic-bg-primary-neutral-hover, oklch(0.98 0.001 180)); /* TODO: --intergalactic-control-pills-bg-hover */ + &[aria-checked='false'], + &[aria-selected='false'] { + :after { + content: ''; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: var(--intergalactic-rounded-small, 4px); + background: var(--intergalactic-control-pills-bg-hover, oklch(0.176 0.033 175.7 / 0.07)); + } + } } -} -SPill[disabled] { - cursor: default; - /* Disable link interactions */ - pointer-events: none; + &[disabled] { + cursor: default; + pointer-events: none; - &>* { - opacity: var(--intergalactic-disabled-opacity, 0.4); + &>* { + opacity: var(--intergalactic-disabled-opacity, 0.4); + } } -} -SText { - color: var(--intergalactic-text-primary, oklch(0.1 0.03 137 / 0.899)); - display: inline-flex; + &[size='l'] { + min-width: 40px; + } } -SAddon { - color: var(--intergalactic-text-secondary, oklch(0.088 0.026 147.7 / 0.583)); +SPillContainer { display: inline-flex; - align-items: center; - justify-content: center; -} - -SPill[size='m'] { - height: var(--intergalactic-form-control-m, 32px); - min-width: var(--intergalactic-form-control-m, 32px); - font-size: var(--intergalactic-fs-200, 14px); - - & SText { - margin-left: var(--intergalactic-spacing-2x, 8px); - margin-right: var(--intergalactic-spacing-2x, 8px); - } - - & SAddon { - &:not(:only-child):first-child { - margin-left: var(--intergalactic-spacing-2x, 8px); - } - &:not(:only-child):last-child { - margin-right: var(--intergalactic-spacing-2x, 8px); - } - - &:only-child { - margin-left: var(--intergalactic-spacing-2x, 8px); - margin-right: var(--intergalactic-spacing-2x, 8px); + &:has(SPill[aria-checked='true'], SPill[aria-selected='true']) { + SPillSeparator { + background-color: transparent; } } -} - -SPill[size='l'] { - height: var(--intergalactic-form-control-l, 44px); - min-width: var(--intergalactic-form-control-l, 44px); - font-size: var(--intergalactic-fs-300, 16px); - & SText { - margin-left: var(--intergalactic-spacing-2x, 8px); - margin-right: var(--intergalactic-spacing-2x, 8px); - - &:only-child { - margin-left: var(--intergalactic-spacing-3x, 12px); - margin-right: var(--intergalactic-spacing-3x, 12px); + &:has(+ SPillContainer SPill[aria-checked='true'], +SPillContainer SPill[aria-selected='true']) { + SPillSeparator { + background-color: transparent; } } +} - & SAddon { - &:not(:only-child):first-child { - margin-left: var(--intergalactic-spacing-3x, 12px); - } +SPillSeparator { + align-self: center; - &:not(:only-child):last-child { - margin-right: var(--intergalactic-spacing-3x, 12px); - } + width: 1px; + height: 18px; + background-color: var(--intergalactic-control-pills-border, oklch(0.137 0.026 175.7 / 0.161)); - &:only-child { - margin-left: var(--intergalactic-spacing-3x, 12px); - margin-right: var(--intergalactic-spacing-3x, 12px); - } + &[size='l'] { + height: 24px; } } -SPill[neighborLocation='right'] { - border-top-right-radius: 0; - border-bottom-right-radius: 0; +SSegmentIndicator { + position: absolute; + + /* + TODO: switch to anchor realisation when layout changes will be supported by FF and Safari. + As of now JS fallback is used. + */ + /* position-anchor:--active-segment; */ + /*left:anchor(left);*/ + /*width:anchor-size(width);*/ + /*height:anchor-size(height);*/ + left: var(--global-left); + width: var(--global-width); + height: var(--global-height); + transition: var(--global-speed); + + background: var(--intergalactic-control-pills-bg-selected, oklch(1 0 0)); + box-shadow: 0 0 1px 0 rgba(0, 21, 16, 0.07), 0 1px 3px 0 rgba(0, 21, 16, 0.07); + border-radius: var(--intergalactic-pills-rounded, 6px); } -SPill[neighborLocation='both'] { - border-radius: 0; - /* disable-tokens-validator */ - margin-left: -1px; +SText { + color: var(--intergalactic-text-primary, oklch(0.1 0.03 137 / 0.899)); } -SPill[neighborLocation='left'] { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - /* disable-tokens-validator */ - margin-left: -1px; +SAddon { + color: var(--intergalactic-text-secondary, oklch(0.088 0.026 147.7 / 0.583)); + display: inline-flex; + align-items: center; + justify-content: center; } + +@media (prefers-reduced-motion) { + SSegmentIndicator { + transition: none; + } +} \ No newline at end of file diff --git a/semcore/select/src/Select.jsx b/semcore/select/src/Select.jsx index d48b1d4e7b..660b30f9c6 100644 --- a/semcore/select/src/Select.jsx +++ b/semcore/select/src/Select.jsx @@ -510,6 +510,7 @@ const Select = createComponent( Divider, InputSearch: [InputSearchWrapper, InputSearch._______childrenComponents], Input: [InputSearchWrapper, InputSearch._______childrenComponents], + Notice: Dropdown.Notice, }, { parent: DropdownMenu, context: selectContext }, ); diff --git a/semcore/select/src/index.d.ts b/semcore/select/src/index.d.ts index 27e01b7ec6..da089a1152 100644 --- a/semcore/select/src/index.d.ts +++ b/semcore/select/src/index.d.ts @@ -3,7 +3,7 @@ import type { ButtonTrigger, BaseTriggerProps, ButtonTriggerProps, LinkTriggerPr import type { PropGetterFn, Intergalactic } from '@semcore/core'; import type Divider from '@semcore/divider'; import type Dropdown from '@semcore/dropdown'; -import type { StatusItemComponent } from '@semcore/dropdown'; +import type { StatusItemComponent, DropdownNoticeComponent } from '@semcore/dropdown'; import type { DropdownMenuContext, DropdownMenuItemProps, @@ -162,6 +162,7 @@ declare const Select: IntergalacticSelectComponent & { Divider: typeof Divider; InputSearch: typeof InputSearch; Input: typeof InputSearch; + Notice: DropdownNoticeComponent; }; declare const wrapSelect: ( diff --git a/semcore/select/src/style/input-search.shadow.css b/semcore/select/src/style/input-search.shadow.css index 14db18dac4..92de2e78aa 100644 --- a/semcore/select/src/style/input-search.shadow.css +++ b/semcore/select/src/style/input-search.shadow.css @@ -1,9 +1,11 @@ -SInputSearch[size='m'] { - height: 32px; +SInputSearch[size='l'] { + height: var(--intergalactic-form-control-l, 44px); } SSearchClear { - padding: 0 var(--intergalactic-spacing-2x, 8px); + padding: 0 var(--intergalactic-spacing-05x, 2px); + margin-left: var(--intergalactic-spacing-05x, 2px); + margin-right: var(--intergalactic-spacing-content-gap-medium, 6px); } SSearchClear[hide] { diff --git a/semcore/select/src/style/select.shadow.css b/semcore/select/src/style/select.shadow.css index 04cae287a4..1cc6a3f102 100644 --- a/semcore/select/src/style/select.shadow.css +++ b/semcore/select/src/style/select.shadow.css @@ -1,6 +1,6 @@ SOptionCheckbox { margin-top: var(--intergalactic-spacing-05x, 2px); - margin-right: var(--intergalactic-spacing-2x, 8px); + margin-right: var(--intergalactic-spacing-content-gap-medium, 6px); margin-bottom: auto; position: relative; flex-shrink: 0; @@ -12,14 +12,13 @@ SOptionCheckbox { left: 0; right: 0; bottom: 0; - background: var(--intergalactic-bg-primary-neutral, oklch(1 0 0)); - border: 1px solid; + background: var(--intergalactic-control-checkbox-bg-normal, oklch(1 0 0)); + border: 1px solid var(--intergalactic-control-checkbox-border, oklch(0.137 0.026 175.7 / 0.161)); border-radius: var(--intergalactic-addon-rounded, 4px); - border-color: var(--intergalactic-border-primary, oklch(0.137 0.026 175.7 / 0.161)); } - width: 16px; - height: 16px; + width: var(--intergalactic-spacing-4x, 16px); + height: var(--intergalactic-spacing-4x, 16px); } SOptionCheckbox::after { @@ -35,26 +34,27 @@ SOptionCheckbox::after { } SOptionCheckbox[selected]::after { - background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNyIgdmlld0JveD0iMCAwIDEwIDciIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik04LjI1IDFMNCA1LjI1TDEuNzUgMyIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+Cg=='); + background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTAiIHZpZXdCb3g9IjAgMCAxMiAxMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAuMzEwNyAyLjE2NzkxTDQuNjQ2NDUgNy44MzIxMkwxLjY4OTM0IDQuODc1MDEiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZT0id2hpdGUiLz48L3N2Zz4='); } SOptionCheckbox[size='l'] { - width: 20px; - height: 20px; + width: var(--intergalactic-spacing-5x, 20px); + height: var(--intergalactic-spacing-5x, 20px); + margin-right: var(--intergalactic-spacing-content-gap-large, 8px); } SOptionCheckbox[size='l'][selected]::after { - background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOSIgdmlld0JveD0iMCAwIDEyIDkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xMSAxLjVMNC43NSA3Ljc1TDEgNCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+Cg=='); + background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTIiIHZpZXdCb3g9IjAgMCAxNCAxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIuNCAyLjQ1MjIxTDUuMzA0NCA5LjU0NzgyTDEuNjAwMDEgNS44NDM0MyIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvc3ZnPg=='); } SOptionCheckbox[selected]:before { - background-color: var(--intergalactic-control-primary-info, oklch(0.23 0.01 140)); /* TODO: --intergalactic-control-checkbox-bg-selected */ - border-color: var(--intergalactic-control-primary-info, oklch(0.23 0.01 140)); /* TODO: --intergalactic-control-checkbox-bg-selected */ + background-color: var(--intergalactic-control-checkbox-bg-selected, oklch(0.23 0.01 140)); + border-color: var(--intergalactic-control-checkbox-bg-selected, oklch(0.23 0.01 140)); } SOptionCheckbox[indeterminate]:before { - background-color: var(--intergalactic-control-primary-info, oklch(0.23 0.01 140)); /* TODO: --intergalactic-control-checkbox-bg-selected */ - border-color: var(--intergalactic-control-primary-info, oklch(0.23 0.01 140)); /* TODO: --intergalactic-control-checkbox-bg-selected */ + background-color: var(--intergalactic-control-checkbox-bg-selected, oklch(0.23 0.01 140)); + border-color: var(--intergalactic-control-checkbox-bg-selected, oklch(0.23 0.01 140)); } SOptionCheckbox[theme]:before { @@ -76,7 +76,7 @@ SOptionCheckbox[selected] { } SOptionCheckbox[indeterminate]:after { - background-color: #ffffff; /* TODO: --gray-white */ + background-color: var(--intergalactic-control-checkbox-checkmark, oklch(1 0 0)); background-image: none; margin: auto; /* disable-tokens-validator */ @@ -84,11 +84,13 @@ SOptionCheckbox[indeterminate]:after { } SOptionCheckbox[indeterminate][size='l']:after { - width: 12px; - height: 2px; + width: var(--intergalactic-spacing-3x, 12px); + /* disable-tokens-validator */ + height: 1.5px; /* TODO: --intergalactic-icon-stroke-width (?) */ } SOptionCheckbox[indeterminate][size='m']:after { - width: 8px; - height: 2px; + width: var(--intergalactic-spacing-2x, 8px); + /* disable-tokens-validator */ + height: 1.5px; /* TODO: --intergalactic-icon-stroke-width (?) */ } diff --git a/semcore/switch/src/style/switch.shadow.css b/semcore/switch/src/style/switch.shadow.css index aaaabf42aa..7d8fd5c423 100644 --- a/semcore/switch/src/style/switch.shadow.css +++ b/semcore/switch/src/style/switch.shadow.css @@ -76,7 +76,7 @@ SSwitch[disabled] { } SToggle { - background: var(--intergalactic-control-switch-bg, oklch(0.88 0.002 175.6)); /* TODO: --intergalactic-control-switch-bg */ + background: var(--intergalactic-control-switch-bg, oklch(0.176 0.033 175.7 / 0.07)); /* TODO: --intergalactic-control-switch-bg */ position: relative; color: var(--intergalactic-icon-secondary-neutral, oklch(0.104 0.023 162.3 / 0.385)); cursor: pointer; diff --git a/semcore/tag/src/style/tag.shadow.css b/semcore/tag/src/style/tag.shadow.css index e951c4c3cc..6f464c9c53 100644 --- a/semcore/tag/src/style/tag.shadow.css +++ b/semcore/tag/src/style/tag.shadow.css @@ -45,12 +45,12 @@ STagContainerClose { align-items: center; justify-content: center; vertical-align: middle; - border: 1px solid var(--intergalactic-bg-primary-neutral, oklch(1 0 0)); /* TODO: --intergalactic-tag-primary-border */ + border: 1px solid var(--intergalactic-tag-primary-border, oklch(1 0 0)); box-sizing: border-box; - background-color: var(--intergalactic-bg-primary-neutral, oklch(1 0 0)); /* TODO: --intergalactic-tag-primary-bg-normal */ + background-color: var(--intergalactic-tag-primary-bg-normal, oklch(1 0 0)); border-radius: var(--intergalactic-tag-rounded, 24px); - padding-left: var(--intergalactic-spacing-1x, 4px); - padding-right: var(--intergalactic-spacing-1x, 4px); + padding-left: var(--intergalactic-spacing-content-gap-small, 4px); + padding-right: var(--intergalactic-spacing-content-gap-small, 4px); font-family: inherit; font-weight: var(--intergalactic-medium, 500); color: var(--tag-color); @@ -135,7 +135,7 @@ STag[size="xl"], STagContainerClose[size="xl"] { height: 40px; min-width: 40px; - padding: 0 var(--intergalactic-spacing-2x, 8px); + padding: 0 var(--intergalactic-spacing-content-gap-large, 8px); & SText { font-size: var(--intergalactic-fs-300, 16px); @@ -167,62 +167,96 @@ STagContainer[theme="primary"] SAddon { } STag[theme="secondary"], -STagContainerClose[theme="secondary"], -STag[theme="additional"], -STagContainerClose[theme="additional"] { - /* chenge to ...? secondary: change to --intergalactic-tag-secondary-border; additional: change to --intergalactic-tag-additional-bg-normal */ - &::before { - opacity: 0.01; +STagContainerClose[theme="secondary"] { + color: var(--intergalactic-tag-secondary-text, #6a6c6a); + background-color: var(--intergalactic-tag-secondary-bg-normal, #ffffff); + border-color: var(--intergalactic-tag-secondary-border, oklch(0.176 0.033 175.7 / 0.07)); + + &::before, + &::after { + display: none; } &[interactiveView]:hover, &[interactiveView]:active, &[active] { - &:before { - opacity: 0.1; - } + background-color: var(--intergalactic-tag-secondary-bg-hover-active, #f4f5f5); } } -STag[theme="secondary"], -STagContainerClose[theme="secondary"], STag[theme="additional"], -STagContainerClose[theme="additional"], -STag[theme="secondary-invert"], -STagContainerClose[theme="secondary-invert"], -STag[theme="additional-invert"], -STagContainerClose[theme="additional-invert"] { +STagContainerClose[theme="additional"] { + color: var(--intergalactic-tag-additional-text, #6a6c6a); + background-color: var(--intergalactic-tag-additional-bg-normal, oklch(1 0 0)); + border-color: var(--intergalactic-tag-additional-border, oklch(0.137 0.026 175.7 / 0.161)); + border-style: dashed; + + &::before, &::after { - opacity: 0.5; + display: none; + } + + &[interactiveView]:hover, + &[interactiveView]:active, + &[active] { + background-color: var(--intergalactic-tag-additional-bg-hover-active, oklch(0.98 0.001 180)); } } STag[theme="primary-invert"], STagContainerClose[theme="primary-invert"] { - background-color: var( - --intergalactic-tag-primary-white-normal, - oklch(1 0 0) - ); - color: var(--intergalactic-text-primary-invert, oklch(0.999 0.001 180 / 0.949)); + background-color: var(--intergalactic-tag-primary-bg-invert-normal, oklch(0.965 0.065 140 / 0.1)); + color: var(--intergalactic-tag-primary-text-invert, #ffffff); + border-color: transparent; + + &[interactiveView]:hover, + &[interactiveView]:active, + &[active] { + background-color: var(--intergalactic-tag-primary-bg-invert-hover-active, oklch(0.986 0.025 140 / 0.203)); + } } STag[theme="secondary-invert"], -STagContainerClose[theme="secondary-invert"], +STagContainerClose[theme="secondary-invert"] { + background-color: var(--intergalactic-tag-secondary-bg-invert-normal, transparent); + color: var(--intergalactic-tag-secondary-text-invert, oklch(0.997 0.004 165.9 / 0.684)); + border-color: var(--intergalactic-tag-secondary-border-invert, oklch(0.974 0.047 140 / 0.136)); + + &::before, + &::after { + display: none; + } + + &[interactiveView]:hover, + &[interactiveView]:active, + &[active] { + background-color: var(--intergalactic-tag-secondary-bg-invert-hover-active, oklch(0.98 0.036 140 / 0.164)); + } +} + STag[theme="additional-invert"], STagContainerClose[theme="additional-invert"] { - color: var(--intergalactic-text-primary-invert, oklch(0.999 0.001 180 / 0.949)); /* TODO:--intergalactic-tag-secondary-white-text */ -} + background-color: var(--intergalactic-tag-additional-bg-invert-normal, transparent); + color: var(--intergalactic-tag-additional-text-invert, oklch(0.997 0.004 165.9 / 0.684)); + border-color: var(--intergalactic-tag-additional-border-invert, oklch(0.995 0.008 147.4 / 0.391)); + border-style: dashed; -STag[theme="additional"] { + &::before, &::after { - border-style: dashed; + display: none; + } + + &[interactiveView]:hover, + &[interactiveView]:active, + &[active] { + background-color: var(--intergalactic-tag-additional-bg-invert-hover-active, oklch(0.98 0.036 140 / 0.164)); } } SText { display: flex; - padding-left: var(--intergalactic-spacing-1x, 4px); - padding-right: var(--intergalactic-spacing-1x, 4px); + padding-left: var(--intergalactic-spacing-content-gap-small, 4px); + padding-right: var(--intergalactic-spacing-content-gap-small, 4px); position: relative; } @@ -258,6 +292,20 @@ STagContainer { align-items: center; justify-content: center; + STag[theme="secondary"]:not(:last-child), + STag[theme="additional"]:not(:last-child), + STag[theme="secondary-invert"]:not(:last-child), + STag[theme="additional-invert"]:not(:last-child) { + border-right: 0; + } + + STagContainerClose[theme="secondary"], + STagContainerClose[theme="additional"], + STagContainerClose[theme="secondary-invert"], + STagContainerClose[theme="additional-invert"] { + border-left: 0; + } + STag, SAddon { &:not(:last-child) { @@ -319,7 +367,7 @@ STagContainer { svg { padding-left: 0; - padding-right: var(--intergalactic-spacing-1x, 4px); + padding-right: var(--intergalactic-spacing-content-gap-small, 4px); } svg path { @@ -333,8 +381,8 @@ STagContainer { STagContainerClose[size="xl"] { svg { - padding-left: var(--intergalactic-spacing-1x, 4px); - padding-right: var(--intergalactic-spacing-2x, 8px); + padding-left: var(--intergalactic-spacing-content-gap-small, 4px); + padding-right: var(--intergalactic-spacing-content-gap-large, 8px); } } } diff --git a/semcore/tooltip/src/style/tooltip.shadow.css b/semcore/tooltip/src/style/tooltip.shadow.css index 6a2e50be7c..0ea8195334 100644 --- a/semcore/tooltip/src/style/tooltip.shadow.css +++ b/semcore/tooltip/src/style/tooltip.shadow.css @@ -21,8 +21,8 @@ STooltip { STooltip[theme='invert'] { color: var(--intergalactic-text-primary-invert, oklch(0.999 0.001 180 / 0.949)); /* TODO: --intergalactic-tooltip-text-invert */ - background-color: var(--intergalactic-tooltip-invert, oklch(0.23 0.01 140)); /* TODO: --intergalactic-tooltip-bg-invert */ - border: 1px solid var(--intergalactic-border-tooltip-invert, oklch(0.995 0.008 145.9 / 0.369)); /* TODO: --intergalactic-tooltip-border-invert */ + background-color: var(--intergalactic-tooltip-invert, oklch(0.21 0.01 140)); /* TODO: --intergalactic-tooltip-bg-invert */ + border: 1px solid var(--intergalactic-border-tooltip-invert, oklch(0.974 0.047 140 / 0.136)); /* TODO: --intergalactic-tooltip-border-invert */ } STooltip[theme='warning'] { @@ -52,10 +52,10 @@ SArrow { } SArrow[theme='invert'] { - border-color: var(--intergalactic-border-tooltip-invert, oklch(0.995 0.008 145.9 / 0.369)); /* TODO: --intergalactic-tooltip-border-invert */ + border-color: var(--intergalactic-border-tooltip-invert, oklch(0.974 0.047 140 / 0.136)); /* TODO: --intergalactic-tooltip-border-invert */ &::before { - border-color: var(--intergalactic-tooltip-invert, oklch(0.23 0.01 140)); /* TODO: --intergalactic-tooltip-bg-invert */ + border-color: var(--intergalactic-tooltip-invert, oklch(0.21 0.01 140)); /* TODO: --intergalactic-tooltip-bg-invert */ } } diff --git a/semcore/wizard/src/style/wizard.shadow.css b/semcore/wizard/src/style/wizard.shadow.css index fd0f1bfc37..d5deaf02b4 100644 --- a/semcore/wizard/src/style/wizard.shadow.css +++ b/semcore/wizard/src/style/wizard.shadow.css @@ -7,7 +7,7 @@ SWizard { } SSidebar { - background: var(--intergalactic-control-primary-advertising, oklch(0.23 0.01 140)); /* TODO: --intergalactic-wizard-sidebar-bg */ + background: var(--intergalactic-control-primary-advertising, oklch(0.21 0.01 140)); /* TODO: --intergalactic-wizard-sidebar-bg */ color: var(--intergalactic-text-primary-invert, oklch(0.999 0.001 180 / 0.949)); /* TODO: --intergalactic-wizard-sidebar-text-primary */ font-weight: var(--intergalactic-bold, 700); font-size: var(--intergalactic-fs-300, 16px); @@ -38,11 +38,11 @@ SSidebar { } &:hover { - background: var(--intergalactic-control-primary-advertising-hover, oklch(0.36 0.005 140)); /* TODO: --intergalactic-wizard-sidebar-control-hover */ + background: var(--intergalactic-control-primary-advertising-hover, oklch(0.32 0.007 140)); /* TODO: --intergalactic-wizard-sidebar-control-hover */ z-index: 2; } &[active] { - background: var(--intergalactic-control-primary-advertising-active, oklch(0.4 0.004 140)); /* TODO: --intergalactic-wizard-sidebar-control-active */ + background: var(--intergalactic-control-primary-advertising-active, oklch(0.36 0.005 140)); /* TODO: --intergalactic-wizard-sidebar-control-active */ } &:disabled, &[disabled] { @@ -63,7 +63,7 @@ SSidebar { overflow: auto; } &[active]:hover SStepDescription { - background: var(--intergalactic-control-primary-advertising-active, oklch(0.4 0.004 140)); /* TODO: --intergalactic-wizard-sidebar-control-active */ + background: var(--intergalactic-control-primary-advertising-active, oklch(0.36 0.005 140)); /* TODO: --intergalactic-wizard-sidebar-control-active */ } } } diff --git a/stories/components/dropdown-menu/advanced/examples/modal-in-dd-notice.tsx b/stories/components/dropdown-menu/advanced/examples/modal-in-dd-notice.tsx index f7783bc87f..2294c8796f 100644 --- a/stories/components/dropdown-menu/advanced/examples/modal-in-dd-notice.tsx +++ b/stories/components/dropdown-menu/advanced/examples/modal-in-dd-notice.tsx @@ -2,7 +2,6 @@ import FileExportM from '@semcore/icon/FileExport/m'; import Button from '@semcore/ui/button'; import DropdownMenu from '@semcore/ui/dropdown-menu'; import Modal from '@semcore/ui/modal'; -import Notice from '@semcore/ui/notice'; import SpinContainer from '@semcore/ui/spin-container'; import { Text } from '@semcore/ui/typography'; import React from 'react'; @@ -41,13 +40,13 @@ const Demo = () => { CSV CSV Semicolon - - + + - - + + diff --git a/stories/components/dropdown-menu/docs/examples/dropdown-menu.tsx b/stories/components/dropdown-menu/docs/examples/dropdown-menu.tsx index 4fb272c579..925d34ac6f 100644 --- a/stories/components/dropdown-menu/docs/examples/dropdown-menu.tsx +++ b/stories/components/dropdown-menu/docs/examples/dropdown-menu.tsx @@ -37,18 +37,11 @@ const Demo = () => { CSV CSV Semicolon - - + Export failed @@ -59,8 +52,8 @@ const Demo = () => { feedback@semrush.com - - + + diff --git a/stories/components/dropdown-menu/docs/examples/item_actions.tsx b/stories/components/dropdown-menu/docs/examples/item_actions.tsx index 100ae946be..0e741c018a 100644 --- a/stories/components/dropdown-menu/docs/examples/item_actions.tsx +++ b/stories/components/dropdown-menu/docs/examples/item_actions.tsx @@ -20,7 +20,7 @@ const Demo = () => { Menu item 3 - + @@ -32,7 +32,7 @@ const Demo = () => { placement='right-start' interaction={DropdownMenu.nestedMenuInteraction} timeout={[0, 300]} - offset={[-11, 12]} + offset={[-11, 17]} > Menu item 4 diff --git a/stories/components/dropdown-menu/docs/examples/nested.tsx b/stories/components/dropdown-menu/docs/examples/nested.tsx index ee2aad100d..fd4fd34f32 100644 --- a/stories/components/dropdown-menu/docs/examples/nested.tsx +++ b/stories/components/dropdown-menu/docs/examples/nested.tsx @@ -1,9 +1,12 @@ import ChevronRightIcon from '@semcore/icon/ChevronRight/m'; import Button from '@semcore/ui/button'; -import DropdownMenu from '@semcore/ui/dropdown-menu'; +import DropdownMenu, { type DropdownMenuProps } from '@semcore/ui/dropdown-menu'; import React from 'react'; const Demo = () => { + const nestedOffset: DropdownMenuProps['offset'] = [-11, 17]; + const nestedTimeout: DropdownMenuProps['timeout'] = [0, 300]; + return ( Explore nested menus @@ -15,8 +18,8 @@ const Demo = () => { Item 4 @@ -27,8 +30,8 @@ const Demo = () => { Item 4.1 @@ -48,8 +51,8 @@ const Demo = () => { Item 4.2 @@ -63,8 +66,8 @@ const Demo = () => { Item 4.2.1 diff --git a/stories/components/dropdown-menu/docs/examples/nested_with_focusable.tsx b/stories/components/dropdown-menu/docs/examples/nested_with_focusable.tsx index e7e9399eba..99304aa703 100644 --- a/stories/components/dropdown-menu/docs/examples/nested_with_focusable.tsx +++ b/stories/components/dropdown-menu/docs/examples/nested_with_focusable.tsx @@ -22,7 +22,7 @@ const Demo = () => { placement='right-start' interaction={DropdownMenu.nestedMenuInteraction} timeout={[0, 300]} - offset={[-11, 12]} + offset={[-11, 17]} > {item} @@ -35,7 +35,7 @@ const Demo = () => { Item 4.1.3 - + diff --git a/stories/components/input-tags/tests/examples/all-sizes.tsx b/stories/components/input-tags/tests/examples/all-sizes.tsx new file mode 100644 index 0000000000..66dc057ba6 --- /dev/null +++ b/stories/components/input-tags/tests/examples/all-sizes.tsx @@ -0,0 +1,37 @@ +import { Flex } from '@semcore/ui/base-components'; +import InputTags from '@semcore/ui/input-tags'; +import React from 'react'; + +const TAGS = ['Facebook', 'Instagram']; + +export default function AllSizes() { + const [tagsM, setTagsM] = React.useState(TAGS); + const [tagsL, setTagsL] = React.useState(TAGS); + + return ( + + + {tagsM.map((tag) => ( + + {tag} + setTagsM((current) => current.filter((item) => item !== tag))} + /> + + ))} + + + + {tagsL.map((tag) => ( + + {tag} + setTagsL((current) => current.filter((item) => item !== tag))} + /> + + ))} + + + + ); +} diff --git a/stories/components/input-tags/tests/input-tags.stories.tsx b/stories/components/input-tags/tests/input-tags.stories.tsx index dc7d0dc76b..4f3d6a333b 100644 --- a/stories/components/input-tags/tests/input-tags.stories.tsx +++ b/stories/components/input-tags/tests/input-tags.stories.tsx @@ -1,6 +1,7 @@ import InputTags from '@semcore/ui/input-tags'; import type { Meta, StoryObj } from '@storybook/react-vite'; +import AllSizesExample from './examples/all-sizes'; import EnteringAndEditingTagsExample, { defaultProps as enteringAndEditingTagsProps } from './examples/entering_and_editing_tags'; import TagsWithAddonsExample, { defaultPropsEmail } from './examples/tags-with-addons'; @@ -11,6 +12,11 @@ const meta: Meta = { export default meta; +export const AllSizes: StoryObj = { + name: 'All sizes', + render: AllSizesExample, +}; + export const EnteringAndEditingTags: StoryObj = { render: EnteringAndEditingTagsExample, argTypes: { diff --git a/stories/components/select/docs/examples/dropdownmenu_customization.tsx b/stories/components/select/docs/examples/dropdownmenu_customization.tsx index 46780811bf..e3f968007e 100644 --- a/stories/components/select/docs/examples/dropdownmenu_customization.tsx +++ b/stories/components/select/docs/examples/dropdownmenu_customization.tsx @@ -8,12 +8,6 @@ const options = Array(12) .fill('') .map((_, index) => `Option ${index}`); -const noticeStyle = { - border: 'none', - borderRadius: `0 0 var(--intergalactic-rounded-medium, 6px) var(--intergalactic-rounded-medium, 6px)`, - padding: 'var(--intergalactic-spacing-3x, 12px) var(--intergalactic-spacing-2x, 8px)', -}; - const Demo = () => ( @@ -22,16 +16,16 @@ const Demo = () => ( diff --git a/stories/components/select/docs/examples/options_filtering.tsx b/stories/components/select/docs/examples/options_filtering.tsx index 8535d4f571..80992b3229 100644 --- a/stories/components/select/docs/examples/options_filtering.tsx +++ b/stories/components/select/docs/examples/options_filtering.tsx @@ -26,7 +26,7 @@ const Demo = () => { onChange={setFilter} /> {options.length > 0 && ( - + {options.map(({ value, label }) => ( {label} diff --git a/stories/components/select/docs/examples/trigger_customization_deep.tsx b/stories/components/select/docs/examples/trigger_customization_deep.tsx index e818922a92..90ab78a9db 100644 --- a/stories/components/select/docs/examples/trigger_customization_deep.tsx +++ b/stories/components/select/docs/examples/trigger_customization_deep.tsx @@ -26,8 +26,12 @@ const Demo = () => { {flags.map((value) => ( - - {formatName(iso2Name[value])} + + + + + {formatName(iso2Name[value])} + ))} diff --git a/stories/components/select/tests/Select.stories.tsx b/stories/components/select/tests/Select.stories.tsx index 167ea265fe..5c632710ed 100644 --- a/stories/components/select/tests/Select.stories.tsx +++ b/stories/components/select/tests/Select.stories.tsx @@ -101,6 +101,14 @@ export const BasicPropsAndTriggerAddons: StoryObj = { showTriggerText: { control: { type: 'boolean' }, }, + + // option addon props + showOptionLeftAddon: { + control: { type: 'boolean' }, + }, + showOptionRightAddon: { + control: { type: 'boolean' }, + }, }, args: BasicProps, }; diff --git a/stories/components/select/tests/examples/basic_props_and_trigger_addons.tsx b/stories/components/select/tests/examples/basic_props_and_trigger_addons.tsx index 37fed7c4c5..360cf0956d 100644 --- a/stories/components/select/tests/examples/basic_props_and_trigger_addons.tsx +++ b/stories/components/select/tests/examples/basic_props_and_trigger_addons.tsx @@ -32,6 +32,10 @@ export type SelectBasicProps = Omit< showTriggerText?: boolean; triggerText?: string; size?: 'm' | 'l'; + + // option addon props + showOptionLeftAddon?: boolean; + showOptionRightAddon?: boolean; }; const Demo = (props: SelectBasicProps) => { @@ -63,6 +67,10 @@ const Demo = (props: SelectBasicProps) => { triggerText = 'Trigger', showTriggerText = false, + // option addon + showOptionLeftAddon = false, + showOptionRightAddon = false, + ...restProps } = props; @@ -74,7 +82,7 @@ const Demo = (props: SelectBasicProps) => { children: `Option ${index}`, })); - const hasCustomTrigger = showLeftAddon || showRightAddon || showTriggerText; + const hasCustomTriggerOrOption = showLeftAddon || showRightAddon || showTriggerText || showOptionLeftAddon || showOptionRightAddon; const [value, setValue] = React.useState(multiselect ? [] : null); React.useEffect(() => { @@ -93,7 +101,7 @@ const Demo = (props: SelectBasicProps) => { {labelText} )} - {hasCustomTrigger + {hasCustomTriggerOrOption ? (