@olddevs/ui 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/dist/components/actions/Toggle.d.ts.map +1 -1
- package/dist/components/actions/Toggle.js +1 -1
- package/dist/components/actions/Toggle.js.map +1 -1
- package/dist/components/actions/Truncate.d.ts.map +1 -1
- package/dist/components/actions/Truncate.js +2 -2
- package/dist/components/actions/Truncate.js.map +1 -1
- package/dist/components/app-shell/MobileTabBar.d.ts.map +1 -1
- package/dist/components/app-shell/MobileTabBar.js +1 -1
- package/dist/components/app-shell/MobileTabBar.js.map +1 -1
- package/dist/components/app-shell/NavItem.d.ts.map +1 -1
- package/dist/components/app-shell/NavItem.js +3 -1
- package/dist/components/app-shell/NavItem.js.map +1 -1
- package/dist/components/content/AvatarGroup.d.ts.map +1 -1
- package/dist/components/content/AvatarGroup.js +2 -1
- package/dist/components/content/AvatarGroup.js.map +1 -1
- package/dist/components/content/Table.d.ts.map +1 -1
- package/dist/components/content/Table.js +2 -1
- package/dist/components/content/Table.js.map +1 -1
- package/dist/components/content/VirtualGrid.d.ts.map +1 -1
- package/dist/components/content/VirtualGrid.js +4 -1
- package/dist/components/content/VirtualGrid.js.map +1 -1
- package/dist/components/inputs/Checkbox.d.ts.map +1 -1
- package/dist/components/inputs/Checkbox.js +3 -0
- package/dist/components/inputs/Checkbox.js.map +1 -1
- package/dist/components/inputs/CheckboxCard.d.ts.map +1 -1
- package/dist/components/inputs/CheckboxCard.js +2 -2
- package/dist/components/inputs/CheckboxCard.js.map +1 -1
- package/dist/components/inputs/RadioGroup.d.ts.map +1 -1
- package/dist/components/inputs/RadioGroup.js +5 -3
- package/dist/components/inputs/RadioGroup.js.map +1 -1
- package/dist/components/inputs/Select.d.ts.map +1 -1
- package/dist/components/inputs/Select.js +6 -6
- package/dist/components/inputs/Select.js.map +1 -1
- package/dist/components/inputs/Slider.d.ts.map +1 -1
- package/dist/components/inputs/Slider.js +2 -2
- package/dist/components/inputs/Slider.js.map +1 -1
- package/dist/components/navigation/Accordion.d.ts.map +1 -1
- package/dist/components/navigation/Accordion.js +1 -1
- package/dist/components/navigation/Accordion.js.map +1 -1
- package/dist/components/navigation/MegaMenu.d.ts +156 -0
- package/dist/components/navigation/MegaMenu.d.ts.map +1 -0
- package/dist/components/navigation/MegaMenu.js +512 -0
- package/dist/components/navigation/MegaMenu.js.map +1 -0
- package/dist/components/navigation/TreeView.d.ts.map +1 -1
- package/dist/components/navigation/TreeView.js +6 -3
- package/dist/components/navigation/TreeView.js.map +1 -1
- package/dist/components/navigation/useMenuAim.d.ts +41 -0
- package/dist/components/navigation/useMenuAim.d.ts.map +1 -0
- package/dist/components/navigation/useMenuAim.js +114 -0
- package/dist/components/navigation/useMenuAim.js.map +1 -0
- package/dist/components/overlays/Menu.d.ts +19 -1
- package/dist/components/overlays/Menu.d.ts.map +1 -1
- package/dist/components/overlays/Menu.js +16 -4
- package/dist/components/overlays/Menu.js.map +1 -1
- package/dist/editor/RichTextEditor.d.ts.map +1 -1
- package/dist/editor/RichTextEditor.js +4 -2
- package/dist/editor/RichTextEditor.js.map +1 -1
- package/dist/editor/features/table/TableMenuButton.js +1 -1
- package/dist/editor/features/table/TableMenuButton.js.map +1 -1
- package/dist/editor/styles/prose.d.ts +7 -0
- package/dist/editor/styles/prose.d.ts.map +1 -1
- package/dist/editor/styles/prose.js +1 -1
- package/dist/editor/styles/prose.js.map +1 -1
- package/dist/editor/ui/BlockHandle.js +1 -1
- package/dist/editor/ui/BlockHandle.js.map +1 -1
- package/dist/editor/ui/FormatMenus.d.ts.map +1 -1
- package/dist/editor/ui/FormatMenus.js +3 -2
- package/dist/editor/ui/FormatMenus.js.map +1 -1
- package/dist/{editor/hooks → hooks}/useSubmenuPlacement.d.ts +14 -1
- package/dist/hooks/useSubmenuPlacement.d.ts.map +1 -0
- package/dist/hooks/useSubmenuPlacement.js +10 -0
- package/dist/hooks/useSubmenuPlacement.js.map +1 -0
- package/dist/i18n/defaults.d.ts.map +1 -1
- package/dist/i18n/defaults.js +3 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/messages.d.ts +8 -0
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/choice-card.d.ts +13 -0
- package/dist/lib/choice-card.d.ts.map +1 -1
- package/dist/lib/choice-card.js +2 -0
- package/dist/lib/choice-card.js.map +1 -1
- package/dist/locales/ru.d.ts.map +1 -1
- package/dist/locales/ru.js +3 -0
- package/dist/locales/ru.js.map +1 -1
- package/docs/api/messages.md +6 -0
- package/docs/components/app-shell/mobile-tab-bar.en.md +3 -3
- package/docs/components/app-shell/mobile-tab-bar.md +2 -2
- package/docs/components/app-shell/side-nav.en.md +7 -3
- package/docs/components/app-shell/side-nav.md +6 -2
- package/docs/components/index.en.md +2 -1
- package/docs/components/index.md +1 -0
- package/docs/components/inputs/form.en.md +2 -2
- package/docs/components/inputs/form.md +1 -1
- package/docs/components/inputs/rich-text-editor.en.md +2 -2
- package/docs/components/inputs/rich-text-editor.md +1 -1
- package/docs/components/navigation/mega-menu.en.md +273 -0
- package/docs/components/navigation/mega-menu.md +258 -0
- package/docs/components/overlays/menu.en.md +22 -4
- package/docs/components/overlays/menu.md +20 -4
- package/docs/getting-started.en.md +5 -5
- package/docs/getting-started.md +4 -4
- package/docs/glossary.en.md +6 -1
- package/docs/glossary.md +5 -0
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/src/components/actions/Toggle.tsx +10 -3
- package/src/components/actions/Truncate.tsx +5 -3
- package/src/components/app-shell/MobileTabBar.tsx +9 -1
- package/src/components/app-shell/NavItem.tsx +6 -1
- package/src/components/content/AvatarGroup.tsx +6 -2
- package/src/components/content/Table.tsx +15 -3
- package/src/components/content/VirtualGrid.tsx +11 -1
- package/src/components/inputs/Checkbox.tsx +5 -0
- package/src/components/inputs/CheckboxCard.tsx +2 -0
- package/src/components/inputs/RadioGroup.tsx +10 -1
- package/src/components/inputs/Select.tsx +113 -106
- package/src/components/inputs/Slider.tsx +6 -2
- package/src/components/navigation/Accordion.tsx +4 -1
- package/src/components/navigation/MegaMenu.tsx +1223 -0
- package/src/components/navigation/TreeView.tsx +70 -49
- package/src/components/navigation/useMenuAim.ts +202 -0
- package/src/components/overlays/Menu.tsx +47 -4
- package/src/editor/RichTextEditor.tsx +6 -3
- package/src/editor/features/table/TableMenuButton.tsx +1 -1
- package/src/editor/styles/prose.ts +1 -1
- package/src/editor/ui/BlockHandle.tsx +1 -1
- package/src/editor/ui/FormatMenus.tsx +17 -2
- package/src/{editor/hooks → hooks}/useSubmenuPlacement.ts +18 -15
- package/src/i18n/defaults.ts +4 -0
- package/src/i18n/messages.ts +9 -0
- package/src/index.ts +17 -0
- package/src/lib/choice-card.ts +17 -0
- package/src/locales/ru.ts +4 -0
- package/dist/editor/hooks/useSubmenuPlacement.d.ts.map +0 -1
- package/dist/editor/hooks/useSubmenuPlacement.js +0 -20
- package/dist/editor/hooks/useSubmenuPlacement.js.map +0 -1
|
@@ -509,7 +509,17 @@ export function VirtualGrid({
|
|
|
509
509
|
className="focus-visible:outline-accent-strong rounded-xl focus-visible:outline-2 focus-visible:outline-offset-2"
|
|
510
510
|
>
|
|
511
511
|
{/* `gridcell` у react-aria — `display: contents`: высоту держит обёртка. */}
|
|
512
|
-
|
|
512
|
+
{/* Обёртка — сетка из одной строки, а не блок с `min-height`: процентная высота
|
|
513
|
+
вложенного узла (`h-full`) от `min-height` не считается и схлопывается до
|
|
514
|
+
содержимого, а от строки сетки — считается. `items-start` оставляет ячейку без
|
|
515
|
+
`h-full` её естественной высоты. */}
|
|
516
|
+
<div
|
|
517
|
+
className="grid h-full grid-cols-1 items-start"
|
|
518
|
+
style={{
|
|
519
|
+
minHeight: minItemHeight,
|
|
520
|
+
gridTemplateRows: `minmax(${minItemHeight}px, 1fr)`,
|
|
521
|
+
}}
|
|
522
|
+
>
|
|
513
523
|
{item.contextMenu != null ? (
|
|
514
524
|
<CellContextMenu
|
|
515
525
|
menu={item.contextMenu}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "react";
|
|
11
11
|
import { CheckboxButton, CheckboxField, Text } from "react-aria-components";
|
|
12
12
|
import { CheckIcon, MinusIcon } from "../../icons.js";
|
|
13
|
+
import { DIMMED_IN_DISABLED_FIELDSET } from "../../lib/choice-card.js";
|
|
13
14
|
import { cn } from "../../lib/cn.js";
|
|
14
15
|
import { hasContent } from "../../lib/empty.js";
|
|
15
16
|
import { STATE_BORDER, TONE_TOKENS, type Size, type Tone } from "../../lib/variants.js";
|
|
@@ -239,6 +240,10 @@ export const Checkbox = forwardRef<HTMLDivElement, CheckboxProps>(function Check
|
|
|
239
240
|
className={
|
|
240
241
|
"hover:bg-bg-2 relative flex w-fit cursor-pointer items-center gap-2 rounded-sm px-1 py-0.5 " +
|
|
241
242
|
"transition-colors disabled:cursor-default disabled:opacity-50 " +
|
|
243
|
+
// `disabled:` ловит только собственный `isDisabled`; выключенный предок-
|
|
244
|
+
// `fieldset` — см. `DIMMED_IN_DISABLED_FIELDSET`.
|
|
245
|
+
DIMMED_IN_DISABLED_FIELDSET +
|
|
246
|
+
" " +
|
|
242
247
|
"before:absolute before:inset-x-0 before:bottom-full before:h-0.5 before:content-[''] after:absolute after:inset-x-0 after:top-full after:h-0.5 after:content-['']"
|
|
243
248
|
}
|
|
244
249
|
>
|
|
@@ -6,6 +6,7 @@ import { CheckIcon, MinusIcon } from "../../icons.js";
|
|
|
6
6
|
import { cn } from "../../lib/cn.js";
|
|
7
7
|
import {
|
|
8
8
|
CHOICE_CARD_BASE,
|
|
9
|
+
CHOICE_CARD_DIMMED_IN_DISABLED_FIELDSET,
|
|
9
10
|
CHOICE_CARD_FOCUS_RING,
|
|
10
11
|
CHOICE_CARD_IDLE_BORDER,
|
|
11
12
|
CHOICE_CARD_INVALID_BORDER,
|
|
@@ -82,6 +83,7 @@ export const CheckboxCard: CheckboxCardComponent = forwardRef<
|
|
|
82
83
|
? CHOICE_CARD_SELECTED_BORDER[tone]
|
|
83
84
|
: CHOICE_CARD_IDLE_BORDER,
|
|
84
85
|
isDisabled ? "opacity-50" : "hover:bg-bg-3",
|
|
86
|
+
CHOICE_CARD_DIMMED_IN_DISABLED_FIELDSET,
|
|
85
87
|
orientation === "horizontal" && CHOICE_CARD_ROW,
|
|
86
88
|
className
|
|
87
89
|
)
|
|
@@ -14,6 +14,8 @@ import { hasContent } from "../../lib/empty.js";
|
|
|
14
14
|
import { ChoiceCardBody } from "./ChoiceCardBody.js";
|
|
15
15
|
import {
|
|
16
16
|
CHOICE_CARD_BASE,
|
|
17
|
+
DIMMED_IN_DISABLED_FIELDSET,
|
|
18
|
+
CHOICE_CARD_DIMMED_IN_DISABLED_FIELDSET,
|
|
17
19
|
CHOICE_CARD_FOCUS_RING,
|
|
18
20
|
CHOICE_CARD_IDLE_BORDER,
|
|
19
21
|
CHOICE_CARD_INVALID_BORDER,
|
|
@@ -214,6 +216,7 @@ export const Radio = forwardRef<HTMLDivElement, RadioProps>(function Radio(
|
|
|
214
216
|
? CHOICE_CARD_SELECTED_BORDER[tone]
|
|
215
217
|
: CHOICE_CARD_IDLE_BORDER,
|
|
216
218
|
isDisabled ? "opacity-50" : "hover:bg-bg-3",
|
|
219
|
+
CHOICE_CARD_DIMMED_IN_DISABLED_FIELDSET,
|
|
217
220
|
orientation === "horizontal" && CHOICE_CARD_ROW,
|
|
218
221
|
className
|
|
219
222
|
)
|
|
@@ -247,7 +250,13 @@ export const Radio = forwardRef<HTMLDivElement, RadioProps>(function Radio(
|
|
|
247
250
|
isDisabled={disabled}
|
|
248
251
|
className={cn("flex flex-col", className)}
|
|
249
252
|
>
|
|
250
|
-
<RadioButton
|
|
253
|
+
<RadioButton
|
|
254
|
+
className={
|
|
255
|
+
"hover:bg-bg-2 flex w-fit cursor-pointer items-center gap-2 rounded-sm px-1 py-0.5 transition-colors " +
|
|
256
|
+
"disabled:cursor-default disabled:opacity-50 " +
|
|
257
|
+
DIMMED_IN_DISABLED_FIELDSET
|
|
258
|
+
}
|
|
259
|
+
>
|
|
251
260
|
{({ isSelected, isInvalid, isFocusVisible }) => (
|
|
252
261
|
<>
|
|
253
262
|
<RadioBox selected={isSelected} invalid={isInvalid} focusVisible={isFocusVisible} />
|
|
@@ -15,7 +15,7 @@ import { LISTBOX_ITEM_CLASS } from "../../lib/menu.js";
|
|
|
15
15
|
import { FIELD_CLEAR_CLASS } from "../../lib/field.js";
|
|
16
16
|
import { useMessages } from "../../i18n/useMessages.js";
|
|
17
17
|
import { CheckIcon, CloseIcon, SelectIcon } from "../../icons.js";
|
|
18
|
-
import { Popover, PopoverContent, PopoverTrigger } from "../overlays/Popover.js";
|
|
18
|
+
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../overlays/Popover.js";
|
|
19
19
|
import { VisuallyHidden } from "../content/VisuallyHidden.js";
|
|
20
20
|
|
|
21
21
|
/** Минимум, который список требует от элемента. Остальные поля — ваши. */
|
|
@@ -502,41 +502,47 @@ export function Select<T extends SelectItem>(props: SelectProps<T>) {
|
|
|
502
502
|
Кольцо фокуса рисуется на псевдоэлементе, а не на кнопке: обводить надо
|
|
503
503
|
пилюлю целиком, иначе она у`же собственного контура.
|
|
504
504
|
*/}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
505
|
+
{/*
|
|
506
|
+
Якорь панели — вся пилюля, а не кнопка-триггер внутри неё: кнопка отступает
|
|
507
|
+
от нижней кромки на рамку и `py-[7px]`, и панель с `sideOffset` в 4px
|
|
508
|
+
заходила на пилюлю вместо зазора.
|
|
509
|
+
*/}
|
|
510
|
+
<PopoverAnchor asChild>
|
|
511
|
+
<span
|
|
512
|
+
className={cn(
|
|
513
|
+
"relative inline-flex items-center gap-2 rounded-full border px-3 py-[7px]",
|
|
514
|
+
// `leading-5` задаёт высоту, а не наследует её: строчный бокс в 20px
|
|
515
|
+
// плюс отступы дают ровно 36 — рост `Button` размера `md`, рядом с
|
|
516
|
+
// которым пилюля и стоит в панели фильтров. С отступами формы
|
|
517
|
+
// (`py-2.5` от потребителя) те же 20 дают 42 — рост `TextControl`
|
|
518
|
+
// и `NumberInput` (см. `lib/field.ts`).
|
|
519
|
+
//
|
|
520
|
+
// Картинка выбранного значения тоже 20, и это условие, а не совпадение:
|
|
521
|
+
// содержимое выше строчного бокса растягивало бы триггер. Пока она
|
|
522
|
+
// была 22, пилюля с картинкой вырастала до 38, а триггер формы — до 44,
|
|
523
|
+
// и контрол расходился и с соседним полем, и сам с собой в пустом
|
|
524
|
+
// состоянии.
|
|
525
|
+
// `transition-colors`, а не `transition-all`: на этом боксе меняются
|
|
526
|
+
// только рамка, фон и цвет подписи — по ветке `hasSelection`. `all`
|
|
527
|
+
// обещал переход всему, чего на пилюле нет, и заодно тому, что
|
|
528
|
+
// потребитель пришлёт через `triggerClassName`. Заменено в волне 27
|
|
529
|
+
// при ревизии движения: класс выглядел перемещающим, а перемещать
|
|
530
|
+
// здесь нечего.
|
|
531
|
+
"text-[13px] leading-5 font-semibold transition-colors",
|
|
532
|
+
hasSelection && highlightSelected
|
|
533
|
+
? "border-accent-strong bg-accent-soft text-fg-0"
|
|
534
|
+
: "border-line-soft text-fg-1 hover:border-line hover:bg-bg-2 bg-transparent",
|
|
535
|
+
// Выбранное значение читается тёмным даже без акцентной подсветки:
|
|
536
|
+
// подпись — это содержимое контрола, а не подсказка.
|
|
537
|
+
hasSelection && !highlightSelected && "text-fg-0",
|
|
538
|
+
// Гаснет ПИЛЮЛЯ, а не кнопка внутри неё: рамка и фон нарисованы здесь,
|
|
539
|
+
// и приглушённая подпись рядом с яркой рамкой выглядела бы сбоем
|
|
540
|
+
// отрисовки, а не выключенным полем.
|
|
541
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
542
|
+
triggerClassName
|
|
543
|
+
)}
|
|
544
|
+
>
|
|
545
|
+
{/*
|
|
540
546
|
Подпись видна только скринридеру и стоит ВНЕ кнопки: внутри неё она
|
|
541
547
|
попала бы в содержимое, то есть прочиталась бы дважды — один раз как
|
|
542
548
|
имя, второй как значение.
|
|
@@ -544,46 +550,46 @@ export function Select<T extends SelectItem>(props: SelectProps<T>) {
|
|
|
544
550
|
`elementType="span"`: по умолчанию react-aria рисует `<div>`, а здесь
|
|
545
551
|
он оказался бы внутри строчной пилюли.
|
|
546
552
|
*/}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
553
|
+
{ariaLabel && !ariaLabelledBy ? (
|
|
554
|
+
<VisuallyHidden elementType="span" id={labelId}>
|
|
555
|
+
{ariaLabel}
|
|
556
|
+
</VisuallyHidden>
|
|
557
|
+
) : null}
|
|
558
|
+
|
|
559
|
+
<PopoverTrigger asChild>
|
|
560
|
+
<button
|
|
561
|
+
type="button"
|
|
562
|
+
disabled={disabled}
|
|
563
|
+
aria-haspopup="listbox"
|
|
564
|
+
aria-expanded={open && !disabled}
|
|
565
|
+
aria-labelledby={labelledBy ? `${labelledBy} ${valueId}` : undefined}
|
|
566
|
+
aria-describedby={describedBy}
|
|
567
|
+
className={cn(
|
|
568
|
+
// `grow` + `justify-between`: когда потребитель растягивает пилюлю
|
|
569
|
+
// (`w-full`, `min-w`), кнопка занимает всю ширину, и его
|
|
570
|
+
// `justify-between` разводит иконку и подпись — как было до выноса.
|
|
571
|
+
// На пилюле по размеру содержимого свободного места нет, и оба
|
|
572
|
+
// класса ничего не меняют.
|
|
573
|
+
"inline-flex min-w-0 grow cursor-pointer items-center justify-between gap-2 text-left",
|
|
574
|
+
"disabled:cursor-not-allowed",
|
|
575
|
+
"after:absolute after:inset-0 after:rounded-[inherit]",
|
|
576
|
+
"focus-visible:after:outline-accent-strong focus-visible:after:outline-2 focus-visible:after:outline-offset-2",
|
|
577
|
+
// Место под крестик — на кнопке, а не на пилюле: пилюля уже несёт
|
|
578
|
+
// отступы потребителя, и добавка к ним сместила бы рамку.
|
|
579
|
+
hasSelection && clearable && !disabled && "pr-6"
|
|
580
|
+
)}
|
|
581
|
+
>
|
|
582
|
+
{/*
|
|
577
583
|
Содержимое собрано в одну группу, а не выложено соседями кнопки.
|
|
578
584
|
Иначе `justify-between` разводит по краям именно их: в пилюле по
|
|
579
585
|
ширине содержимого это незаметно, а в широком триггере (`w-full`
|
|
580
586
|
в форме) картинка прилипает к левому краю, подпись — к правому,
|
|
581
587
|
и между ними дыра во всю строку.
|
|
582
588
|
*/}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
589
|
+
{selected ? (
|
|
590
|
+
<span id={valueId} className="inline-flex min-w-0 items-center gap-2">
|
|
591
|
+
{renderMedia?.(selected, 20)}
|
|
592
|
+
{/*
|
|
587
593
|
Ширина подписи ограничена переменной, а не жёстким числом.
|
|
588
594
|
В пилюле фильтра предел нужен: она растёт по содержимому, и
|
|
589
595
|
«Абстрактные градиенты» растолкали бы соседние фильтры. В
|
|
@@ -592,10 +598,10 @@ export function Select<T extends SelectItem>(props: SelectProps<T>) {
|
|
|
592
598
|
Снимается это классом на триггере:
|
|
593
599
|
`triggerClassName="[--select-label-max:none]"`.
|
|
594
600
|
*/}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
601
|
+
<span className={LABEL_CLASS}>{selected.label}</span>
|
|
602
|
+
</span>
|
|
603
|
+
) : hasSelection && props.multiple ? (
|
|
604
|
+
/*
|
|
599
605
|
Счётчик — СТРОГО за множественным выбором.
|
|
600
606
|
|
|
601
607
|
Ветка ловила и одиночный `Select`, у которого значение есть, а
|
|
@@ -605,13 +611,13 @@ export function Select<T extends SelectItem>(props: SelectProps<T>) {
|
|
|
605
611
|
нечего. Одиночный случай уходит теперь в ветку ниже и
|
|
606
612
|
показывает сам ключ, как это делает `captionOf` в `TreeSelect`.
|
|
607
613
|
*/
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
614
|
+
<span id={valueId} className={LABEL_CLASS}>
|
|
615
|
+
{countLabel
|
|
616
|
+
? countLabel(selectedIds.length)
|
|
617
|
+
: `${placeholder}: ${selectedIds.length}`}
|
|
618
|
+
</span>
|
|
619
|
+
) : hasSelection ? (
|
|
620
|
+
/*
|
|
615
621
|
Одиночный выбор, которому не нашлось элемента.
|
|
616
622
|
|
|
617
623
|
Ключ ЧЕСТНЕЕ плейсхолдера, когда он человекочитаем
|
|
@@ -622,36 +628,37 @@ export function Select<T extends SelectItem>(props: SelectProps<T>) {
|
|
|
622
628
|
умолчанию показывается ключ, как это делает `captionOf` в
|
|
623
629
|
`TreeSelect`.
|
|
624
630
|
*/
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
631
|
+
<span id={valueId} className={LABEL_CLASS}>
|
|
632
|
+
{missingLabel ? missingLabel(selectedIds[0]!) : selectedIds[0]}
|
|
633
|
+
</span>
|
|
634
|
+
) : (
|
|
635
|
+
/*
|
|
630
636
|
`id` значения стоит на КОРНЕ КАЖДОЙ ветки, а не на общей обёртке
|
|
631
637
|
вокруг них: обёртка — лишний бокс во флексе триггера, и она
|
|
632
638
|
сместила бы содержимое там, где менять его никто не просил.
|
|
633
639
|
*/
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
640
|
+
<span id={valueId} className="inline-flex min-w-0 items-center gap-2">
|
|
641
|
+
<span aria-hidden className="inline-flex shrink-0 items-center opacity-60">
|
|
642
|
+
{icon ?? <SelectIcon size={14} />}
|
|
643
|
+
</span>
|
|
644
|
+
<span className="truncate">{placeholder}</span>
|
|
637
645
|
</span>
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
</span>
|
|
646
|
+
)}
|
|
647
|
+
</button>
|
|
648
|
+
</PopoverTrigger>
|
|
649
|
+
|
|
650
|
+
{hasSelection && clearable && !disabled ? (
|
|
651
|
+
<button
|
|
652
|
+
type="button"
|
|
653
|
+
aria-label={clearLabel ?? messages.common.clear}
|
|
654
|
+
onClick={clear}
|
|
655
|
+
className={FIELD_CLEAR_CLASS}
|
|
656
|
+
>
|
|
657
|
+
<CloseIcon size={10} aria-hidden />
|
|
658
|
+
</button>
|
|
659
|
+
) : null}
|
|
660
|
+
</span>
|
|
661
|
+
</PopoverAnchor>
|
|
655
662
|
|
|
656
663
|
<PopoverContent
|
|
657
664
|
className={cn("w-[260px]", contentClassName)}
|
|
@@ -64,15 +64,19 @@ export type RangeSliderProps = SliderLookProps &
|
|
|
64
64
|
`State=disabled` в Figma. `disabled:` здесь срабатывает на `data-disabled`,
|
|
65
65
|
который react-aria ставит на корень. Раньше вида не было вовсе —
|
|
66
66
|
отличался только курсор над бегунком.
|
|
67
|
+
|
|
68
|
+
`has-[input:disabled]:` — для ползунка внутри `<fieldset disabled>` (так `Form` с
|
|
69
|
+
`pending` гасит поля): react-aria о таком предке не знает и `data-disabled`
|
|
70
|
+
на корне не ставит, а нативное состояние видит только скрытый `input` бегунка.
|
|
67
71
|
*/
|
|
68
|
-
const DIMMED_WHEN_DISABLED = "disabled:opacity-50";
|
|
72
|
+
const DIMMED_WHEN_DISABLED = "disabled:opacity-50 has-[input:disabled]:opacity-50";
|
|
69
73
|
const ROOT_CLASS = `flex w-full flex-col gap-2 ${DIMMED_WHEN_DISABLED}`;
|
|
70
74
|
const TRACK_CLASS = "bg-bg-3 relative h-1.5 w-full rounded-full";
|
|
71
75
|
const FILL_CLASS = "bg-accent absolute h-full rounded-full";
|
|
72
76
|
const THUMB_BASE_CLASS =
|
|
73
77
|
"border-accent bg-bg-1 size-4 cursor-grab rounded-full border-2 shadow-[var(--shadow-1)] transition-shadow " +
|
|
74
78
|
"dragging:cursor-grabbing focus-visible:outline-accent-strong focus-visible:outline-2 focus-visible:outline-offset-2 " +
|
|
75
|
-
"disabled:cursor-not-allowed";
|
|
79
|
+
"disabled:cursor-not-allowed has-[input:disabled]:cursor-not-allowed";
|
|
76
80
|
// Вдоль оси бегунок ставит react-aria (`left` или `top`), поперёк — мы.
|
|
77
81
|
const THUMB_CLASS = `${THUMB_BASE_CLASS} top-1/2`;
|
|
78
82
|
|
|
@@ -91,7 +91,10 @@ export function AccordionItem({ id, title, disabled, className, children }: Acco
|
|
|
91
91
|
/>
|
|
92
92
|
</AriaButton>
|
|
93
93
|
</AriaHeading>
|
|
94
|
-
|
|
94
|
+
{/* Отступ только у раскрытой панели: свёрнутая остаётся в потоке, и её `pb-3` добавлял 12px. */}
|
|
95
|
+
<DisclosurePanel className={cn("text-fg-1 text-sm", isExpanded && "pb-3")}>
|
|
96
|
+
{children}
|
|
97
|
+
</DisclosurePanel>
|
|
95
98
|
</>
|
|
96
99
|
)}
|
|
97
100
|
</Disclosure>
|