F: Improve buttons accessibility
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run

This commit is contained in:
Ivan 2025-03-20 11:33:42 +03:00
parent 575b7a29f2
commit e144d20f2d
57 changed files with 217 additions and 136 deletions

View File

@ -23,6 +23,7 @@ export function ToggleNavigation() {
onClick={toggleNoNavigation}
data-tooltip-id={globalIDs.tooltip}
data-tooltip-content={noNavigationAnimation ? 'Показать навигацию' : 'Скрыть навигацию'}
aria-label={noNavigationAnimation ? 'Показать навигацию' : 'Скрыть навигацию'}
>
{!noNavigationAnimation ? <IconPin size='0.75rem' /> : null}
{noNavigationAnimation ? <IconUnpin size='0.75rem' /> : null}
@ -35,6 +36,7 @@ export function ToggleNavigation() {
onClick={toggleDarkMode}
data-tooltip-id={globalIDs.tooltip}
data-tooltip-content={darkMode ? 'Тема: Темная' : 'Тема: Светлая'}
aria-label={darkMode ? 'Тема: Темная' : 'Тема: Светлая'}
>
{darkMode ? <IconDarkTheme size='0.75rem' /> : null}
{!darkMode ? <IconLightTheme size='0.75rem' /> : null}

View File

@ -85,27 +85,28 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
/>
<DropdownButton
text={darkMode ? 'Тема: Темная' : 'Тема: Светлая'}
icon={darkMode ? <IconDarkTheme size='1rem' /> : <IconLightTheme size='1rem' />}
title='Переключение темы оформления'
icon={darkMode ? <IconDarkTheme size='1rem' /> : <IconLightTheme size='1rem' />}
onClick={handleToggleDarkMode}
/>
<DropdownButton
text={showHelp ? 'Помощь: Вкл' : 'Помощь: Выкл'}
icon={showHelp ? <IconHelp size='1rem' /> : <IconHelpOff size='1rem' />}
title='Отображение иконок подсказок'
icon={showHelp ? <IconHelp size='1rem' /> : <IconHelpOff size='1rem' />}
onClick={toggleShowHelp}
/>
{user.is_staff ? (
<DropdownButton
text={adminMode ? 'Админ: Вкл' : 'Админ: Выкл'}
icon={adminMode ? <IconAdmin size='1rem' /> : <IconAdminOff size='1rem' />}
title='Работа в режиме администратора'
icon={adminMode ? <IconAdmin size='1rem' /> : <IconAdminOff size='1rem' />}
onClick={toggleAdminMode}
/>
) : null}
{user.is_staff ? (
<DropdownButton
text='REST API' //
title='Переход к backend API'
icon={<IconRESTapi size='1rem' />}
className='border-t'
onClick={gotoRestApi}
@ -114,6 +115,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
{user.is_staff ? (
<DropdownButton
text='База данных' //
title='Переход к администрированию базы данных'
icon={<IconDatabase size='1rem' />}
onClick={gotoAdmin}
/>
@ -121,6 +123,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
{user?.is_staff ? (
<DropdownButton
text='Иконки' //
title='Переход к странице иконок'
icon={<IconImage size='1rem' />}
onClick={gotoIcons}
/>
@ -128,6 +131,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
{user.is_staff ? (
<DropdownButton
text='Структура БД' //
title='Переход к странице структуры БД'
icon={<IconDBStructure size='1rem' />}
onClick={gotoDatabaseSchema}
className='border-b'
@ -135,6 +139,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
) : null}
<DropdownButton
text='Выйти...'
title='Выход из приложения'
className='font-semibold'
icon={<IconLogout size='1rem' />}
onClick={logoutAndRedirect}

View File

@ -38,7 +38,6 @@ export function Button({
return (
<button
type='button'
disabled={disabled ?? loading}
className={clsx(
'inline-flex gap-2 items-center justify-center',
'font-medium select-none disabled:cursor-auto',
@ -53,6 +52,8 @@ export function Button({
data-tooltip-html={titleHtml}
data-tooltip-content={title}
data-tooltip-hidden={hideTitle}
disabled={disabled ?? loading}
aria-label={!text ? title : undefined}
{...restProps}
>
{icon ? icon : null}

View File

@ -49,6 +49,7 @@ export function MiniButton({
data-tooltip-html={titleHtml}
data-tooltip-content={title}
data-tooltip-hidden={hideTitle}
aria-label={title}
{...restProps}
>
{icon}

View File

@ -46,6 +46,7 @@ export function DropdownButton({
data-tooltip-html={titleHtml}
data-tooltip-content={title}
data-tooltip-hidden={hideTitle}
aria-label={title}
{...restProps}
>
{icon ? icon : null}

View File

@ -55,12 +55,12 @@ export function CheckboxTristate({
cursor,
className
)}
disabled={disabled}
onClick={handleClick}
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
data-tooltip-html={titleHtml}
data-tooltip-content={title}
data-tooltip-hidden={hideTitle}
disabled={disabled}
{...restProps}
>
<div

View File

@ -54,12 +54,12 @@ export function Checkbox({
cursor,
className
)}
disabled={disabled}
onClick={handleClick}
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
data-tooltip-html={titleHtml}
data-tooltip-content={title}
data-tooltip-hidden={hideTitle}
disabled={disabled}
{...restProps}
>
<div

View File

@ -99,6 +99,7 @@ export function SelectTree<ItemType>({
>
{foldable.has(item) ? (
<MiniButton
aria-label={!folded.includes(item) ? 'Свернуть' : 'Развернуть'}
className={clsx('absolute left-1', !folded.includes(item) ? 'top-1.5' : 'top-1')}
noPadding
noHover

View File

@ -105,9 +105,9 @@ export function ModalForm({
) : null}
<MiniButton
noPadding
aria-label='Закрыть'
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
aria-label='Закрыть'
noPadding
icon={<IconClose size='1.25rem' />}
className='absolute z-pop top-2 right-2'
onClick={hideDialog}

View File

@ -49,9 +49,9 @@ export function ModalView({
) : null}
<MiniButton
noPadding
aria-label='Закрыть'
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
aria-label='Закрыть'
noPadding
icon={<IconClose size='1.25rem' />}
className='absolute z-pop top-2 right-2'
onClick={hideDialog}

View File

@ -14,7 +14,15 @@ interface TabLabelProps extends Omit<TabPropsImpl, 'children'>, Titled {
/**
* Displays a tab header with a label.
*/
export function TabLabel({ label, title, titleHtml, hideTitle, className, ...otherProps }: TabLabelProps) {
export function TabLabel({
label,
title,
titleHtml,
hideTitle,
className,
role = 'tab',
...otherProps
}: TabLabelProps) {
return (
<TabImpl
className={clsx(
@ -31,6 +39,7 @@ export function TabLabel({ label, title, titleHtml, hideTitle, className, ...oth
data-tooltip-html={titleHtml}
data-tooltip-content={title}
data-tooltip-hidden={hideTitle}
role={role}
{...otherProps}
>
{label}

View File

@ -50,6 +50,7 @@ export function ValueIcon({
...restProps
}: ValueIconProps) {
// TODO: use CSS instead of threshold
// TODO: do not add button if onClick is disabled
const isSmall = !smallThreshold || String(value).length < smallThreshold;
return (
<div
@ -66,7 +67,7 @@ export function ValueIcon({
data-tooltip-content={title}
data-tooltip-hidden={hideTitle}
>
<MiniButton noHover noPadding icon={icon} disabled={disabled} onClick={onClick} />
<MiniButton noHover noPadding icon={icon} onClick={onClick} disabled={disabled} />
<span id={id} className={clsx({ 'text-xs': !isSmall }, textClassName)}>
{value}
</span>

View File

@ -64,20 +64,20 @@ export function LoginPage() {
id='username'
autoComplete='username'
label='Логин или email'
{...register('username')}
autoFocus
allowEnter
spellCheck={false}
defaultValue={initialName}
{...register('username')}
error={errors.username}
/>
<TextInput
id='password'
{...register('password')}
type='password'
autoComplete='current-password'
label='Пароль'
allowEnter
{...register('password')}
error={errors.password}
/>

View File

@ -85,9 +85,9 @@ export function EditorLibraryItem({ schema, isAttachedToOSS }: EditorLibraryItem
<div className='flex flex-col'>
<div className='relative flex justify-stretch sm:mb-1 max-w-120 gap-3'>
<MiniButton
title='Открыть в библиотеке'
noHover
noPadding
title='Открыть в библиотеке'
icon={<IconFolderOpened size='1.25rem' className='icon-primary' />}
onClick={handleOpenLibrary}
/>

View File

@ -67,22 +67,22 @@ export function MenuRole({ isOwned, isEditor }: MenuRoleProps) {
text={labelUserRole(UserRole.EDITOR)}
title={describeUserRole(UserRole.EDITOR)}
icon={<IconRole role={UserRole.EDITOR} size='1rem' />}
disabled={!isOwned && !isEditor}
onClick={() => handleChangeMode(UserRole.EDITOR)}
disabled={!isOwned && !isEditor}
/>
<DropdownButton
text={labelUserRole(UserRole.OWNER)}
title={describeUserRole(UserRole.OWNER)}
icon={<IconRole role={UserRole.OWNER} size='1rem' />}
disabled={!isOwned}
onClick={() => handleChangeMode(UserRole.OWNER)}
disabled={!isOwned}
/>
<DropdownButton
text={labelUserRole(UserRole.ADMIN)}
title={describeUserRole(UserRole.ADMIN)}
icon={<IconRole role={UserRole.ADMIN} size='1rem' />}
disabled={!user.is_staff}
onClick={() => handleChangeMode(UserRole.ADMIN)}
disabled={!user.is_staff}
/>
</Dropdown>
</div>

View File

@ -30,8 +30,8 @@ export function MiniSelectorOSS({ items, onSelect, className, ...restProps }: Mi
return (
<div ref={ossMenu.ref} className={clsx('relative flex items-center', className)} {...restProps}>
<MiniButton
icon={<IconOSS size='1.25rem' className='icon-primary' />}
title='Операционные схемы'
icon={<IconOSS size='1.25rem' className='icon-primary' />}
hideTitle={ossMenu.isOpen}
onClick={onToggle}
/>
@ -40,9 +40,9 @@ export function MiniSelectorOSS({ items, onSelect, className, ...restProps }: Mi
<Label text='Список ОСС' className='border-b px-3 py-1' />
{items.map((reference, index) => (
<DropdownButton
className='min-w-20'
key={`${prefixes.oss_list}${index}`}
text={reference.alias}
className='min-w-20'
onClick={event => onSelect(event, reference)}
/>
))}

View File

@ -114,8 +114,8 @@ export function PickSchema({
/>
<div className='relative' ref={locationMenu.ref}>
<MiniButton
icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />}
title='Фильтр по расположению'
icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />}
className='mt-1'
onClick={() => locationMenu.toggle()}
/>

View File

@ -52,10 +52,10 @@ export function SelectLocationHead({
return (
<DropdownButton
key={`${prefixes.location_head_list}${index}`}
onClick={() => handleChange(head)}
title={describeLocationHead(head)}
icon={<IconLocationHead value={head} size='1rem' />}
text={labelLocationHead(head)}
title={describeLocationHead(head)}
onClick={() => handleChange(head)}
icon={<IconLocationHead value={head} size='1rem' />}
/>
);
})}

View File

@ -48,13 +48,14 @@ export function ToolbarItemAccess({
<Label text='Доступ' className='self-center select-none' />
<div className='ml-auto cc-icons'>
<SelectAccessPolicy
disabled={role <= UserRole.EDITOR || isProcessing || isAttachedToOSS}
value={policy}
onChange={handleSetAccessPolicy}
disabled={role <= UserRole.EDITOR || isProcessing || isAttachedToOSS}
/>
<MiniButton
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
aria-label='Переключатель отображения библиотеки'
icon={<IconItemVisibility value={visible} />}
onClick={toggleVisible}
disabled={role === UserRole.READER || isProcessing}
@ -62,6 +63,7 @@ export function ToolbarItemAccess({
<MiniButton
title={readOnly ? 'Изменение: запрещено' : 'Изменение: разрешено'}
aria-label='Переключатель режима изменения'
icon={
readOnly ? (
<IconImmutable size='1.25rem' className='text-sec-600' />

View File

@ -56,13 +56,15 @@ export function ToolbarItemCard({ className, schema, onSubmit, isMutable, delete
{isMutable || isModified ? (
<MiniButton
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
disabled={!canSave}
aria-label='Сохранить изменения'
icon={<IconSave size='1.25rem' className='icon-primary' />}
onClick={onSubmit}
disabled={!canSave}
/>
) : null}
<MiniButton
titleHtml={tooltipText.shareItem(schema.access_policy === AccessPolicy.PUBLIC)}
aria-label='Поделиться схемой'
icon={<IconShare size='1.25rem' className='icon-primary' />}
onClick={sharePage}
disabled={schema.access_policy !== AccessPolicy.PUBLIC}
@ -71,8 +73,8 @@ export function ToolbarItemCard({ className, schema, onSubmit, isMutable, delete
<MiniButton
title='Удалить схему'
icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={!isMutable || isProcessing || role < UserRole.OWNER}
onClick={deleteSchema}
disabled={!isMutable || isProcessing || role < UserRole.OWNER}
/>
) : null}
<BadgeHelp topic={HelpTopic.UI_RS_CARD} offset={4} />

View File

@ -95,6 +95,7 @@ export function DlgCloneLibraryItem() {
render={({ field }) => (
<MiniButton
title={field.value ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
aria-label='Переключатель отображения библиотеки'
icon={<IconItemVisibility value={field.value} />}
onClick={() => field.onChange(!field.value)}
/>

View File

@ -47,12 +47,12 @@ export function DlgEditEditors() {
<div className='self-center text-sm font-semibold'>
<span>Всего редакторов [{selected.length}]</span>
<MiniButton
noHover
title='Очистить список'
noHover
className='py-0 align-middle'
icon={<IconRemove size='1.5rem' className='icon-red' />}
disabled={selected.length === 0}
onClick={() => setSelected([])}
disabled={selected.length === 0}
/>
</div>

View File

@ -107,14 +107,15 @@ export function DlgEditVersions() {
<MiniButton
type='submit'
title={isValid ? 'Сохранить изменения' : errorMsg.versionTaken}
disabled={!isDirty || !isValid || isProcessing}
aria-label='Сохранить изменения'
icon={<IconSave size='1.25rem' className='icon-primary' />}
disabled={!isDirty || !isValid || isProcessing}
/>
<MiniButton
title='Сбросить несохраненные изменения'
disabled={!isDirty}
onClick={() => reset()}
icon={<IconReset size='1.25rem' className='icon-primary' />}
disabled={!isDirty}
/>
</div>
</form>

View File

@ -66,9 +66,9 @@ export function TableVersions({ processing, items, onDelete, selected, onSelect
className='align-middle'
noHover
noPadding
disabled={processing}
icon={<IconRemove size='1.25rem' className='icon-red' />}
onClick={event => handleDeleteVersion(event, props.row.original.id)}
disabled={processing}
/>
)
})

View File

@ -185,6 +185,7 @@ export function FormCreateItem() {
render={({ field }) => (
<MiniButton
title={field.value ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
aria-label='Переключатель отображения библиотеки'
icon={<IconItemVisibility value={field.value} />}
onClick={() => field.onChange(!field.value)}
/>

View File

@ -56,8 +56,8 @@ export function LibraryPage() {
<ToolbarSearch className='top-0 h-9' total={libraryItems.length} filtered={filtered.length} />
<div className='relative cc-fade-in flex'>
<MiniButton
className='absolute z-tooltip -top-8 right-6'
title='Выгрузить в формате CSV'
className='absolute z-tooltip -top-8 right-6'
icon={<IconCSV size='1.25rem' className='icon-green' />}
onClick={handleDownloadCSV}
/>

View File

@ -98,17 +98,20 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
<Dropdown isOpen={userMenu.isOpen}>
<DropdownButton
text='Я - Владелец'
title='Фильтровать схемы, в которых текущий пользователь является владельцем'
icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />}
onClick={toggleOwned}
/>
<DropdownButton
text='Я - Редактор'
title='Фильтровать схемы, в которых текущий пользователя является редактором'
icon={<IconEditor size='1.25rem' className={tripleToggleColor(isEditor)} />}
onClick={toggleEditor}
/>
<SelectUser
noBorder
aria-label='Выбор пользователя для фильтра по владельцу'
placeholder='Выберите владельца'
noBorder
className='min-w-60 text-sm mx-1 mb-1'
value={filterUser}
onChange={setFilterUser}
@ -155,13 +158,14 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
<Dropdown isOpen={headMenu.isOpen} stretchLeft>
<DropdownButton
title='Переключение в режим Проводник'
text='проводник...'
title='Переключение в режим Проводник'
icon={<IconFolderTree size='1rem' className='clr-text-controls' />}
onClick={handleToggleFolder}
/>
<DropdownButton
text='отображать все'
title='Очистить фильтр по расположению'
icon={<IconFolder size='1rem' className='clr-text-controls' />}
onClick={() => handleChange(null)}
/>
@ -169,9 +173,9 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
return (
<DropdownButton
key={`${prefixes.location_head_list}${index}`}
onClick={() => handleChange(head)}
title={describeLocationHead(head)}
text={labelLocationHead(head)}
title={describeLocationHead(head)}
onClick={() => handleChange(head)}
icon={<IconLocationHead value={head} size='1rem' />}
/>
);

View File

@ -35,11 +35,12 @@ export function useLibraryColumns() {
id: 'location',
header: () => (
<MiniButton
titleHtml='Переключение в режим Проводник'
aria-label='Переключатель режима Проводник'
noPadding
noHover
className='pl-2 max-h-4 -translate-y-0.5'
onClick={handleToggleFolder}
titleHtml='Переключение в режим Проводник'
icon={<IconFolderTree size='1.25rem' className='clr-text-controls' />}
/>
),

View File

@ -71,21 +71,23 @@ export function ViewSideLocation({ isVisible, onRenameLocation }: ViewSideLocati
<div className='cc-icons'>
{canRename ? (
<MiniButton
icon={<IconFolderEdit size='1.25rem' className='icon-primary' />}
titleHtml='<b>Редактирование пути</b><br/>Перемещаются только Ваши схемы<br/>в указанной папке (и подпапках)'
aria-label='Редактирование расположения'
icon={<IconFolderEdit size='1.25rem' className='icon-primary' />}
onClick={onRenameLocation}
/>
) : null}
{!!location ? (
<MiniButton
title={subfolders ? 'Вложенные папки: Вкл' : 'Вложенные папки: Выкл'}
aria-label='Переключатель отображения вложенных папок'
icon={<IconShowSubfolders value={subfolders} />}
onClick={toggleSubfolders}
/>
) : null}
<MiniButton
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
title='Переключение в режим Поиск'
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
onClick={toggleFolderMode}
/>
</div>

View File

@ -81,22 +81,22 @@ export function PickMultiOperation({ rows, items, value, onChange, className, ..
cell: props => (
<div className='flex gap-1 w-fit'>
<MiniButton
title='Удалить'
noHover
className='px-0'
title='Удалить'
icon={<IconRemove size='1rem' className='icon-red' />}
onClick={() => handleDelete(props.row.original.id)}
/>
<MiniButton
title='Переместить выше'
noHover
className='px-0'
title='Выше'
icon={<IconMoveUp size='1rem' className='icon-primary' />}
onClick={() => handleMoveUp(props.row.original.id)}
/>
<MiniButton
title='Переместить ниже'
noHover
title='Ниже'
className='px-0'
icon={<IconMoveDown size='1rem' className='icon-primary' />}
onClick={() => handleMoveDown(props.row.original.id)}

View File

@ -65,8 +65,8 @@ export function FormOSS() {
{...register('title')}
label='Полное название'
className='mb-3'
disabled={!isMutable}
error={errors.title}
disabled={!isMutable}
/>
<div className='relative flex justify-between gap-3 mb-3'>
<TextInput
@ -74,8 +74,8 @@ export function FormOSS() {
{...register('alias')}
label='Сокращение'
className='w-64'
disabled={!isMutable}
error={errors.alias}
disabled={!isMutable}
/>
<ToolbarItemAccess
className='absolute top-18 right-2'
@ -93,16 +93,16 @@ export function FormOSS() {
{...register('comment')}
label='Описание'
rows={3}
disabled={!isMutable || isProcessing}
error={errors.comment}
disabled={!isMutable || isProcessing}
/>
{isMutable || isModified ? (
<SubmitButton
text='Сохранить изменения'
className='self-center mt-4'
loading={isProcessing}
disabled={!isModified}
icon={<IconSave size='1.25rem' />}
disabled={!isModified}
/>
) : null}
</form>

View File

@ -178,17 +178,18 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
text='Редактировать'
title='Редактировать операцию'
icon={<IconEdit2 size='1rem' className='icon-primary' />}
disabled={!isMutable || isProcessing}
onClick={handleEditOperation}
disabled={!isMutable || isProcessing}
/>
{operation?.result ? (
<DropdownButton
text='Открыть схему'
titleHtml={prepareTooltip('Открыть привязанную КС', 'Двойной клик')}
aria-label='Открыть привязанную КС'
icon={<IconRSForm size='1rem' className='icon-green' />}
disabled={isProcessing}
onClick={handleOpenSchema}
disabled={isProcessing}
/>
) : null}
{isMutable && !operation?.result && operation?.arguments.length === 0 ? (
@ -196,8 +197,8 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
text='Создать схему'
title='Создать пустую схему'
icon={<IconNewRSForm size='1rem' className='icon-green' />}
disabled={isProcessing}
onClick={handleInputCreate}
disabled={isProcessing}
/>
) : null}
{isMutable && operation?.operation_type === OperationType.INPUT ? (
@ -205,8 +206,8 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
text={!operation?.result ? 'Загрузить схему' : 'Изменить схему'}
title='Выбрать схему для загрузки'
icon={<IconConnect size='1rem' className='icon-primary' />}
disabled={isProcessing}
onClick={handleEditSchema}
disabled={isProcessing}
/>
) : null}
{isMutable && !operation?.result && operation?.operation_type === OperationType.SYNTHESIS ? (
@ -217,9 +218,10 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
? 'Активировать операцию<br/>и получить синтезированную КС'
: 'Необходимо предоставить все аргументы'
}
aria-label='Активировать операцию и получить синтезированную КС'
icon={<IconExecute size='1rem' className='icon-green' />}
disabled={isProcessing || !readyForSynthesis}
onClick={handleOperationExecute}
disabled={isProcessing || !readyForSynthesis}
/>
) : null}
@ -227,17 +229,18 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
<DropdownButton
text='Конституенты'
titleHtml='Перенос конституент</br>между схемами'
aria-label='Перенос конституент между схемами'
icon={<IconChild size='1rem' className='icon-green' />}
disabled={isProcessing}
onClick={handleRelocateConstituents}
disabled={isProcessing}
/>
) : null}
<DropdownButton
text='Удалить операцию'
icon={<IconDestroy size='1rem' className='icon-red' />}
disabled={!isMutable || isProcessing || !operation || !canDelete(operation)}
onClick={handleDeleteOperation}
disabled={!isMutable || isProcessing || !operation || !canDelete(operation)}
/>
</Dropdown>
</div>

View File

@ -143,12 +143,13 @@ export function ToolbarOssGraph({
onClick={onResetPositions}
/>
<MiniButton
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
title='Сбросить вид'
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
onClick={handleFitView}
/>
<MiniButton
title={showGrid ? 'Скрыть сетку' : 'Отобразить сетку'}
aria-label='Переключатель отображения сетки'
icon={
showGrid ? (
<IconGrid size='1.25rem' className='icon-green' />
@ -160,6 +161,7 @@ export function ToolbarOssGraph({
/>
<MiniButton
title={edgeStraight ? 'Связи: прямые' : 'Связи: безье'}
aria-label='Переключатель формы связей'
icon={
edgeStraight ? (
<IconLineStraight size='1.25rem' className='icon-primary' />
@ -171,6 +173,7 @@ export function ToolbarOssGraph({
/>
<MiniButton
title={edgeAnimate ? 'Анимация: вкл' : 'Анимация: выкл'}
aria-label='Переключатель анимации связей'
icon={
edgeAnimate ? (
<IconAnimation size='1.25rem' className='icon-primary' />
@ -186,33 +189,37 @@ export function ToolbarOssGraph({
<div className='cc-icons'>
<MiniButton
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
aria-label='Сохранить изменения'
icon={<IconSave size='1.25rem' className='icon-primary' />}
disabled={isProcessing}
onClick={handleSavePositions}
disabled={isProcessing}
/>
<MiniButton
titleHtml={prepareTooltip('Новая операция', 'Ctrl + Q')}
aria-label='Новая операция'
icon={<IconNewItem size='1.25rem' className='icon-green' />}
disabled={isProcessing}
onClick={onCreate}
disabled={isProcessing}
/>
<MiniButton
title='Активировать операцию'
icon={<IconExecute size='1.25rem' className='icon-green' />}
disabled={isProcessing || selected.length !== 1 || !readyForSynthesis}
onClick={handleOperationExecute}
disabled={isProcessing || selected.length !== 1 || !readyForSynthesis}
/>
<MiniButton
titleHtml={prepareTooltip('Редактировать выбранную', 'Двойной клик')}
aria-label='Редактировать выбранную'
icon={<IconEdit2 size='1.25rem' className='icon-primary' />}
disabled={selected.length !== 1 || isProcessing}
onClick={handleEditOperation}
disabled={selected.length !== 1 || isProcessing}
/>
<MiniButton
titleHtml={prepareTooltip('Удалить выбранную', 'Delete')}
aria-label='Удалить выбранную'
icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={selected.length !== 1 || isProcessing || !selectedOperation || !canDelete(selectedOperation)}
onClick={onDelete}
disabled={selected.length !== 1 || isProcessing || !selectedOperation || !canDelete(selectedOperation)}
/>
</div>
) : null}

View File

@ -47,6 +47,7 @@ export function MenuEditOss() {
<DropdownButton
text='Конституенты'
titleHtml='Перенос конституент</br>между схемами'
aria-label='Перенос конституент между схемами'
icon={<IconChild size='1rem' className='icon-green' />}
disabled={isProcessing}
onClick={handleRelocate}

View File

@ -61,6 +61,7 @@ export function MenuMain() {
<Dropdown isOpen={schemaMenu.isOpen} margin='mt-3'>
<DropdownButton
text='Поделиться'
title='Скопировать ссылку в буфер обмена'
icon={<IconShare size='1rem' className='icon-primary' />}
onClick={handleShare}
/>
@ -74,8 +75,8 @@ export function MenuMain() {
<DropdownButton
text='Удалить схему'
icon={<IconDestroy size='1rem' className='icon-red' />}
disabled={isProcessing || role < UserRole.OWNER}
onClick={handleDelete}
disabled={isProcessing || role < UserRole.OWNER}
/>
) : null}

View File

@ -196,14 +196,14 @@ export function PickSubstitutions({
props.row.original.is_suggestion ? (
<div className='max-w-fit'>
<MiniButton
noHover
title='Принять предложение'
noHover
icon={<IconAccept size='1rem' className='icon-green' />}
onClick={() => handleAcceptSuggestion(props.row.original)}
/>
<MiniButton
noHover
title='Игнорировать предложение'
noHover
icon={<IconRemove size='1rem' className='icon-red' />}
onClick={() => handleDeclineSuggestion(props.row.original)}
/>
@ -211,8 +211,8 @@ export function PickSubstitutions({
) : (
<div className='max-w-fit'>
<MiniButton
noHover
title='Удалить'
noHover
icon={<IconRemove size='1rem' className='icon-red' />}
onClick={() => handleDeleteSubstitution(props.row.original)}
/>
@ -257,8 +257,8 @@ export function PickSubstitutions({
title='Добавить в таблицу отождествлений'
className='grow-0'
icon={<IconReplace size='1.5rem' className='icon-primary' />}
disabled={!leftCst || !rightCst || (leftCst === rightCst && !allowSelfSubstitution)}
onClick={addSubstitution}
disabled={!leftCst || !rightCst || (leftCst === rightCst && !allowSelfSubstitution)}
/>
</div>

View File

@ -46,54 +46,55 @@ export function ToolbarGraphSelection({
return (
<div className={clsx('cc-icons', className)} {...restProps}>
<MiniButton
titleHtml='Сбросить выделение'
title='Сбросить выделение'
icon={<IconReset size='1.25rem' className='icon-primary' />}
onClick={() => onChange([])}
disabled={emptySelection}
/>
<MiniButton
titleHtml='Выделить все влияющие'
title='Выделить все влияющие'
icon={<IconGraphCollapse size='1.25rem' className='icon-primary' />}
onClick={() => onChange([...selected, ...graph.expandAllInputs(selected)])}
disabled={emptySelection}
/>
<MiniButton
titleHtml='Выделить все зависимые'
title='Выделить все зависимые'
icon={<IconGraphExpand size='1.25rem' className='icon-primary' />}
onClick={() => onChange([...selected, ...graph.expandAllOutputs(selected)])}
disabled={emptySelection}
/>
<MiniButton
titleHtml='<b>Максимизация</b> <br/>дополнение выделения конституентами, <br/>зависимыми только от выделенных'
aria-label='Максимизация - дополнение выделения конституентами, зависимыми только от выделенных'
icon={<IconGraphMaximize size='1.25rem' className='icon-primary' />}
onClick={() => onChange(graph.maximizePart(selected))}
disabled={emptySelection}
/>
<MiniButton
titleHtml='Выделить поставщиков'
title='Выделить поставщиков'
icon={<IconGraphInputs size='1.25rem' className='icon-primary' />}
onClick={() => onChange([...selected, ...graph.expandInputs(selected)])}
disabled={emptySelection}
/>
<MiniButton
titleHtml='Выделить потребителей'
title='Выделить потребителей'
icon={<IconGraphOutputs size='1.25rem' className='icon-primary' />}
onClick={() => onChange([...selected, ...graph.expandOutputs(selected)])}
disabled={emptySelection}
/>
<MiniButton
titleHtml='Инвертировать'
title='Инвертировать'
icon={<IconGraphInverse size='1.25rem' className='icon-primary' />}
onClick={() => onChange([...graph.nodes.keys()].filter(item => !selected.includes(item)))}
/>
<MiniButton
titleHtml='Выделить ядро'
title='Выделить ядро'
icon={<IconGraphCore size='1.25rem' className='icon-primary' />}
onClick={handleSelectCore}
/>
{isOwned ? (
<MiniButton
titleHtml='Выделить собственные'
title='Выделить собственные'
icon={<IconPredecessor size='1.25rem' className='icon-primary' />}
onClick={handleSelectOwned}
/>

View File

@ -43,8 +43,20 @@ export function FormCreateCst({ schema }: FormCreateCstProps) {
return (
<>
<div className='flex items-center self-center gap-3'>
<SelectCstType id='dlg_cst_type' className='w-64' value={cst_type} onChange={handleTypeChange} />
<TextInput id='dlg_cst_alias' dense label='Имя' className='w-28' {...register('alias')} error={errors.alias} />
<SelectCstType
id='dlg_cst_type' //
className='w-64'
value={cst_type}
onChange={handleTypeChange}
/>
<TextInput
id='dlg_cst_alias' //
dense
label='Имя'
className='w-28'
{...register('alias')}
error={errors.alias}
/>
<BadgeHelp topic={HelpTopic.CC_CONSTITUENTA} offset={16} contentClass='sm:max-w-160' />
</div>

View File

@ -133,8 +133,8 @@ export function TabArguments() {
noHover
className='py-0'
icon={<IconAccept size='1.5rem' className='icon-green' />}
disabled={!argumentValue || !selectedArgument}
onClick={() => handleAssignArgument(selectedArgument!, argumentValue)}
disabled={!argumentValue || !selectedArgument}
/>
<MiniButton
title='Очистить поле'

View File

@ -143,18 +143,18 @@ export function DlgEditWordForms() {
/>
<div className='flex flex-col self-center gap-1'>
<MiniButton
noHover
title='Определить граммемы'
noHover
icon={<IconMoveRight size='1.25rem' className='icon-primary' />}
disabled={isProcessing || !inputText}
onClick={handleParse}
disabled={isProcessing || !inputText}
/>
<MiniButton
noHover
title='Генерировать словоформу'
noHover
icon={<IconMoveLeft size='1.25rem' className='icon-primary' />}
disabled={isProcessing || inputGrams.length == 0}
onClick={handleInflect}
disabled={isProcessing || inputGrams.length == 0}
/>
</div>
<SelectMultiGrammeme
@ -168,29 +168,29 @@ export function DlgEditWordForms() {
<div className='flex justify-between'>
<div className='cc-icons'>
<MiniButton
noHover
title='Внести словоформу'
noHover
icon={<IconAccept size='1.5rem' className='icon-green' />}
disabled={isProcessing || !inputText || inputGrams.length == 0}
onClick={handleAddForm}
disabled={isProcessing || !inputText || inputGrams.length == 0}
/>
<MiniButton
noHover
title='Генерировать стандартные словоформы'
noHover
icon={<IconMoveDown size='1.5rem' className='icon-primary' />}
disabled={isProcessing || !inputText}
onClick={handleGenerateLexeme}
disabled={isProcessing || !inputText}
/>
</div>
<div className='mt-3 mb-2 mx-auto text-sm font-semibold'>
<span>Заданные вручную словоформы [{forms.length}]</span>
<MiniButton
noHover
title='Сбросить все словоформы'
noHover
className='py-0 align-middle'
icon={<IconRemove size='1.5rem' className='icon-red' />}
disabled={isProcessing || forms.length === 0}
onClick={handleResetAll}
disabled={isProcessing || forms.length === 0}
/>
</div>
</div>

View File

@ -47,10 +47,10 @@ export function TableWordForms({ forms, setForms, onFormSelect }: TableWordForms
size: 0,
cell: props => (
<MiniButton
title='Удалить словоформу'
noHover
noPadding
className='align-middle'
title='Удалить словоформу'
icon={<IconRemove size='1.25rem' className='icon-red' />}
onClick={() => handleDeleteRow(props.row.index)}
/>

View File

@ -87,20 +87,20 @@ export function EditorConstituenta() {
<ToolbarConstituenta
className='cc-tab-tools right-1/2 translate-x-0 xs:right-4 xs:-translate-x-1/2 md:right-1/2 md:translate-x-0 cc-animate-position'
activeCst={activeCst}
disabled={disabled}
onSubmit={initiateSubmit}
onReset={() => setToggleReset(prev => !prev)}
disabled={disabled}
/>
<div className='mx-0 md:mx-auto pt-8 md:w-195 shrink-0 xs:pt-0'>
{activeCst ? (
<FormConstituenta
id={globalIDs.constituenta_editor}
disabled={disabled}
toggleReset={toggleReset}
activeCst={activeCst}
schema={schema}
onOpenEdit={navigateCst}
disabled={disabled}
/>
) : null}
</div>

View File

@ -136,7 +136,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
<form id={id} className='relative cc-column mt-1 px-6 py-1' onSubmit={event => void handleSubmit(onSubmit)(event)}>
{!disabled || isProcessing ? (
<MiniButton
title={isModified ? tooltipText.unsaved : `Редактировать словоформы термина`}
title={isModified ? tooltipText.unsaved : 'Редактировать словоформы термина'}
aria-label='Редактировать словоформы термина'
noHover
onClick={handleEditTermForms}
className='absolute z-pop top-0 left-[calc(7ch+4px)]'
@ -152,8 +153,9 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
</div>
{!disabled || isProcessing ? (
<MiniButton
noHover
title={isModified ? tooltipText.unsaved : 'Переименовать конституенту'}
aria-label='Переименовать конституенту'
noHover
onClick={handleRenameCst}
icon={<IconEdit size='1rem' className='icon-primary' />}
disabled={isModified}
@ -175,8 +177,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
value={field.value ?? ''}
initialValue={activeCst.term_raw}
resolved={activeCst.term_resolved}
disabled={disabled}
onChange={newValue => field.onChange(newValue)}
disabled={disabled}
/>
)}
/>
@ -214,12 +216,12 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
}
value={field.value ?? ''}
activeCst={activeCst}
disabled={disabled || activeCst.is_inherited}
toggleReset={toggleReset}
onChange={newValue => field.onChange(newValue)}
onChangeLocalParse={setLocalParse}
onOpenEdit={onOpenEdit}
onShowTypeGraph={handleTypeGraph}
disabled={disabled || activeCst.is_inherited}
/>
)}
/>
@ -240,8 +242,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
value={field.value ?? ''}
initialValue={activeCst.definition_raw}
resolved={activeCst.definition_resolved}
disabled={disabled}
onChange={newValue => field.onChange(newValue)}
disabled={disabled}
/>
)}
/>
@ -275,8 +277,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
<div className='relative mx-auto flex'>
<SubmitButton
text='Сохранить изменения'
disabled={disabled || !isModified}
icon={<IconSave size='1.25rem' />}
disabled={disabled || !isModified}
/>
<div className='absolute z-pop top-1/2 -translate-y-1/2 left-full cc-icons'>
{activeCst.has_inherited_children && !activeCst.is_inherited ? (

View File

@ -98,33 +98,35 @@ export function ToolbarConstituenta({
<>
<MiniButton
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
aria-label='Сохранить изменения'
icon={<IconSave size='1.25rem' className='icon-primary' />}
disabled={disabled || !isModified}
onClick={onSubmit}
disabled={disabled || !isModified}
/>
<MiniButton
title='Сбросить несохраненные изменения'
icon={<IconReset size='1.25rem' className='icon-primary' />}
disabled={disabled || !isModified}
onClick={onReset}
disabled={disabled || !isModified}
/>
<MiniButton
title='Создать конституенту после данной'
icon={<IconNewItem size='1.25rem' className='icon-green' />}
disabled={!isContentEditable || isProcessing}
onClick={() => (activeCst ? createCst(activeCst.cst_type, false) : createCstDefault())}
disabled={!isContentEditable || isProcessing}
/>
<MiniButton
titleHtml={isModified ? tooltipText.unsaved : prepareTooltip('Клонировать конституенту', 'Alt + V')}
aria-label='Клонировать конституенту'
icon={<IconClone size='1.25rem' className='icon-green' />}
disabled={disabled || isModified}
onClick={cloneCst}
disabled={disabled || isModified}
/>
<MiniButton
title='Удалить редактируемую конституенту'
disabled={disabled || !canDeleteSelected}
onClick={promptDeleteCst}
icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={disabled || !canDeleteSelected}
/>
</>
) : null}
@ -139,15 +141,17 @@ export function ToolbarConstituenta({
<>
<MiniButton
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
aria-label='Переместить вверх'
icon={<IconMoveUp size='1.25rem' className='icon-primary' />}
disabled={disabled || isModified || schema.items.length < 2}
onClick={moveUp}
disabled={disabled || isModified || schema.items.length < 2}
/>
<MiniButton
titleHtml={prepareTooltip('Переместить вниз', 'Alt + вниз')}
aria-label='Переместить вниз'
icon={<IconMoveDown size='1.25rem' className='icon-primary' />}
disabled={disabled || isModified || schema.items.length < 2}
onClick={moveDown}
disabled={disabled || isModified || schema.items.length < 2}
/>
</>
) : null}

View File

@ -157,9 +157,9 @@ export function EditorRSExpression({
<div className='relative cc-fade-in'>
<ToolbarRSExpression
className='absolute -top-2 right-0'
disabled={disabled}
showAST={handleShowAST}
showTypeGraph={onShowTypeGraph}
disabled={disabled}
/>
<StatusBar
@ -174,27 +174,27 @@ export function EditorRSExpression({
<RSInput
ref={rsInput}
value={value}
schema={schema}
minHeight='3.75rem'
maxHeight='8rem'
disabled={disabled}
onChange={handleChange}
onAnalyze={handleCheckExpression}
schema={schema}
onOpenEdit={onOpenEdit}
disabled={disabled}
{...restProps}
/>
<RSEditorControls
isOpen={showControls && (!disabled || (isProcessing && !activeCst.is_inherited))}
disabled={disabled}
onEdit={handleEdit}
disabled={disabled}
/>
<ParsingResult
isOpen={!!parseData && parseData.errors.length > 0}
data={parseData}
disabled={disabled}
onShowError={error => onShowError(error, parseData?.prefixLen ?? 0)}
disabled={disabled}
/>
</div>
);

View File

@ -108,9 +108,9 @@ export function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsP
key={`${prefixes.rsedit_btn}${hotkey}`}
text={text}
titleHtml={`<kbd>[${hotkey}]</kbd>`}
className='hidden xs:inline'
onInsert={onEdit}
disabled={disabled}
className='hidden xs:inline'
/>
))}

View File

@ -17,7 +17,6 @@ export function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps)
<button
type='button'
tabIndex={-1}
disabled={disabled}
onClick={() => onInsert(token)}
className={clsx(
'h-5 sm:h-6',
@ -30,6 +29,7 @@ export function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps)
)}
data-tooltip-id={globalIDs.tooltip}
data-tooltip-html={describeToken(token)}
disabled={disabled}
>
{label ? <span className='whitespace-nowrap'>{label}</span> : null}
</button>

View File

@ -78,8 +78,8 @@ export function FormRSForm() {
{...register('title')}
label='Полное название'
className='mb-3'
disabled={!isContentEditable}
error={errors.title}
disabled={!isContentEditable}
/>
<div className='flex justify-between gap-3 mb-3'>
<TextInput
@ -87,8 +87,8 @@ export function FormRSForm() {
{...register('alias')}
label='Сокращение'
className='w-64'
disabled={!isContentEditable}
error={errors.alias}
disabled={!isContentEditable}
/>
<div className='relative flex flex-col gap-2'>
<ToolbarVersioning
@ -122,16 +122,16 @@ export function FormRSForm() {
{...register('comment')}
label='Описание'
rows={3}
disabled={!isContentEditable || isProcessing}
error={errors.comment}
disabled={!isContentEditable || isProcessing}
/>
{isContentEditable || isDirty ? (
<SubmitButton
text='Сохранить изменения'
className='self-center mt-4'
loading={isProcessing}
disabled={!isDirty}
icon={<IconSave size='1.25rem' />}
disabled={!isDirty}
/>
) : null}
</form>

View File

@ -69,21 +69,23 @@ export function ToolbarVersioning({ blockReload, className }: ToolbarVersioningP
? 'Откатить к версии'
: 'Переключитесь на <br/>неактуальную версию'
}
disabled={isContentEditable || blockReload}
aria-label='Откатить к выбранной версии'
onClick={handleRestoreVersion}
icon={<IconUpload size='1.25rem' className='icon-red' />}
disabled={isContentEditable || blockReload}
/>
<MiniButton
titleHtml={isContentEditable ? 'Создать версию' : 'Переключитесь <br/>на актуальную версию'}
disabled={!isContentEditable}
aria-label={isContentEditable ? 'Создать версию' : 'Переключить на актуальную версию'}
onClick={handleCreateVersion}
icon={<IconNewVersion size='1.25rem' className='icon-green' />}
disabled={!isContentEditable}
/>
<MiniButton
title={schema.versions.length === 0 ? 'Список версий пуст' : 'Редактировать версии'}
disabled={schema.versions.length === 0}
onClick={handleEditVersions}
icon={<IconVersions size='1.25rem' className='icon-primary' />}
disabled={schema.versions.length === 0}
/>
</>
) : null}

View File

@ -55,29 +55,32 @@ export function ToolbarRSList({ className }: ToolbarRSListProps) {
) : null}
<MiniButton
titleHtml={prepareTooltip('Сбросить выделение', 'ESC')}
aria-label='Сбросить выделение'
icon={<IconReset size='1.25rem' className='icon-primary' />}
disabled={selected.length === 0}
onClick={deselectAll}
disabled={selected.length === 0}
/>
<MiniButton
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
aria-label='Переместить вверх'
icon={<IconMoveUp size='1.25rem' className='icon-primary' />}
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
onClick={moveUp}
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
/>
<MiniButton
titleHtml={prepareTooltip('Переместить вниз', 'Alt + вниз')}
aria-label='Переместить вниз'
icon={<IconMoveDown size='1.25rem' className='icon-primary' />}
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
onClick={moveDown}
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
/>
<div ref={insertMenu.ref} className='relative'>
<MiniButton
title='Добавить пустую конституенту'
hideTitle={insertMenu.isOpen}
icon={<IconOpenList size='1.25rem' className='icon-green' />}
disabled={isProcessing}
onClick={insertMenu.toggle}
disabled={isProcessing}
/>
<Dropdown isOpen={insertMenu.isOpen} className='-translate-x-1/2'>
{Object.values(CstType).map(typeStr => (
@ -93,21 +96,24 @@ export function ToolbarRSList({ className }: ToolbarRSListProps) {
</div>
<MiniButton
titleHtml={prepareTooltip('Добавить новую конституенту...', 'Alt + `')}
aria-label='Добавить новую конституенту'
icon={<IconNewItem size='1.25rem' className='icon-green' />}
disabled={isProcessing}
onClick={createCstDefault}
disabled={isProcessing}
/>
<MiniButton
titleHtml={prepareTooltip('Клонировать конституенту', 'Alt + V')}
aria-label='Клонировать конституенту'
icon={<IconClone size='1.25rem' className='icon-green' />}
disabled={isProcessing || selected.length !== 1}
onClick={cloneCst}
disabled={isProcessing || selected.length !== 1}
/>
<MiniButton
titleHtml={prepareTooltip('Удалить выбранные', 'Delete')}
aria-label='Удалить выбранные'
icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={isProcessing || !canDeleteSelected}
onClick={promptDeleteCst}
disabled={isProcessing || !canDeleteSelected}
/>
<BadgeHelp topic={HelpTopic.UI_RS_LIST} offset={5} />
</div>

View File

@ -44,7 +44,7 @@ export function ToolbarFocusedCst() {
</div>
<MiniButton
titleHtml='Сбросить фокус'
title='Сбросить фокус'
icon={<IconReset size='1.25rem' className='icon-primary' />}
onClick={resetSelection}
/>

View File

@ -99,8 +99,8 @@ export function ToolbarTermGraph() {
onClick={showParams}
/>
<MiniButton
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
title='Граф целиком'
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
onClick={handleFitView}
/>
<MiniButton
@ -129,16 +129,16 @@ export function ToolbarTermGraph() {
<MiniButton
title='Новая конституента'
icon={<IconNewItem size='1.25rem' className='icon-green' />}
disabled={isProcessing}
onClick={handleCreateCst}
disabled={isProcessing}
/>
) : null}
{isContentEditable ? (
<MiniButton
title='Удалить выбранные'
icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={!canDeleteSelected || isProcessing}
onClick={handleDeleteCst}
disabled={!canDeleteSelected || isProcessing}
/>
) : null}
<MiniButton

View File

@ -135,15 +135,16 @@ export function MenuEditSchema() {
text='Шаблоны'
title='Создать конституенту из шаблона'
icon={<IconTemplates size='1rem' className='icon-green' />}
disabled={!isContentEditable || isProcessing}
onClick={handleTemplates}
disabled={!isContentEditable || isProcessing}
/>
<DropdownButton
text='Встраивание'
titleHtml='Импортировать совокупность <br/>конституент из другой схемы'
aria-label='Импортировать совокупность конституент из другой схемы'
icon={<IconInlineSynthesis size='1rem' className='icon-green' />}
disabled={!isContentEditable || isProcessing}
onClick={handleInlineSynthesis}
disabled={!isContentEditable || isProcessing}
/>
<Divider margins='mx-3 my-1' />
@ -151,27 +152,31 @@ export function MenuEditSchema() {
<DropdownButton
text='Упорядочить список'
titleHtml='Упорядочить список, исходя из <br/>логики типов и связей конституент'
aria-label='Упорядочить список, исходя из логики типов и связей конституент'
icon={<IconSortList size='1rem' className='icon-primary' />}
disabled={!isContentEditable || isProcessing}
onClick={handleRestoreOrder}
disabled={!isContentEditable || isProcessing}
/>
<DropdownButton
text='Порядковые имена'
titleHtml='Присвоить порядковые имена <br/>и обновить выражения'
aria-label='Присвоить порядковые имена и обновить выражения'
icon={<IconGenerateNames size='1rem' className='icon-primary' />}
disabled={!isContentEditable || isProcessing}
onClick={handleReindex}
disabled={!isContentEditable || isProcessing}
/>
<DropdownButton
text='Порождение структуры'
titleHtml='Раскрыть структуру типизации <br/>выделенной конституенты'
aria-label='Раскрыть структуру типизации выделенной конституенты'
icon={<IconGenerateStructure size='1rem' className='icon-primary' />}
disabled={!isContentEditable || isProcessing || !activeCst || !canProduceStructure(activeCst)}
onClick={() => handleProduceStructure(activeCst)}
disabled={!isContentEditable || isProcessing || !activeCst || !canProduceStructure(activeCst)}
/>
<DropdownButton
text='Отождествление'
titleHtml='Заменить вхождения <br/>одной конституенты на другую'
aria-label='Заменить вхождения одной конституенты на другую'
icon={<IconReplace size='1rem' className='icon-red' />}
onClick={handleSubstituteCst}
disabled={!isContentEditable || isProcessing}

View File

@ -129,6 +129,7 @@ export function MenuMain() {
<DropdownButton
text='Поделиться'
titleHtml={tooltipText.shareItem(schema.access_policy === AccessPolicy.PUBLIC)}
aria-label='Скопировать ссылку в буфер обмена'
icon={<IconShare size='1rem' className='icon-primary' />}
onClick={handleShare}
disabled={schema.access_policy !== AccessPolicy.PUBLIC}

View File

@ -41,6 +41,7 @@ export function ConstituentsSearch({ dense }: ConstituentsSearchProps) {
<MiniButton
noHover
titleHtml={`Наследованные: <b>${includeInherited ? 'отображать' : 'скрывать'}</b>`}
aria-label={`Отображение наследованных: ${includeInherited ? 'отображать' : 'скрывать'}`}
icon={<IconChild size='1rem' className={includeInherited ? 'icon-primary' : 'clr-text-controls'} />}
className='h-fit self-center'
onClick={toggleInherited}

View File

@ -46,10 +46,10 @@ export function SelectGraphFilter({ value, dense, className, onChange, ...restPr
const source = value as DependencyMode;
return (
<DropdownButton
className={!dense ? 'w-72' : undefined}
key={`${prefixes.cst_source_list}${index}`}
onClick={() => handleChange(source)}
className={!dense ? 'w-72' : undefined}
icon={<IconDependencyMode value={source} size='1rem' />}
onClick={() => handleChange(source)}
>
{!dense ? (
<span>

View File

@ -45,10 +45,10 @@ export function SelectMatchMode({ value, dense, className, onChange, ...restProp
const matchMode = value as CstMatchMode;
return (
<DropdownButton
className={!dense ? 'w-80' : undefined}
key={`${prefixes.cst_source_list}${index}`}
onClick={() => handleChange(matchMode)}
className={!dense ? 'w-80' : undefined}
icon={<IconCstMatchMode value={matchMode} size='1rem' />}
onClick={() => handleChange(matchMode)}
>
{!dense ? (
<span>