Merge branch 'develop' of https://codeberg.org/mkljczk/pl-fe into develop
Some checks failed
pl-api CI / Test for pl-api formatting (22.x) (push) Has been cancelled
pl-fe CI / Test and upload artifacts (22.x) (push) Has been cancelled
pl-hooks CI / Test for a successful build (22.x) (push) Has been cancelled
pl-fe CI / deploy (push) Has been cancelled

This commit is contained in:
2026-02-03 23:45:27 +00:00
13 changed files with 434 additions and 326 deletions

View File

@ -966,7 +966,10 @@ const getFeatures = (instance: Instance) => {
* @see GET /api/v2/notifications/:group_key/accounts
* @see GET /api/v2/notifications/unread_count
*/
groupedNotifications: instance.api_versions.mastodon >= 2,
groupedNotifications: any([
instance.api_versions.mastodon >= 2,
v.software === HOLLO && gte(v.version, '0.7.0'),
]),
/**
* Groups.

View File

@ -44,15 +44,15 @@
"@fontsource/noto-sans-javanese": "^5.2.8",
"@fontsource/roboto-mono": "^5.2.8",
"@fontsource/tajawal": "^5.2.7",
"@lexical/code": "^0.38.2",
"@lexical/hashtag": "^0.38.2",
"@lexical/link": "^0.38.2",
"@lexical/list": "^0.38.2",
"@lexical/markdown": "^0.38.2",
"@lexical/react": "^0.38.2",
"@lexical/rich-text": "^0.38.2",
"@lexical/selection": "^0.38.2",
"@lexical/utils": "^0.38.2",
"@lexical/code": "^0.39.0",
"@lexical/hashtag": "^0.39.0",
"@lexical/link": "^0.39.0",
"@lexical/list": "^0.39.0",
"@lexical/markdown": "^0.39.0",
"@lexical/react": "^0.39.0",
"@lexical/rich-text": "^0.39.0",
"@lexical/selection": "^0.39.0",
"@lexical/utils": "^0.39.0",
"@mkljczk/url-purify": "^0.0.5",
"@phosphor-icons/core": "^2.1.1",
"@reach/combobox": "^0.18.0",
@ -100,7 +100,7 @@
"intl-pluralrules": "^2.0.1",
"isomorphic-dompurify": "^2.35.0",
"leaflet": "^1.8.0",
"lexical": "^0.38.2",
"lexical": "^0.39.0",
"line-awesome": "^1.3.0",
"localforage": "^1.10.0",
"lodash": "^4.17.23",

View File

@ -777,7 +777,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
<div className='mt-6 flex w-full justify-end sm:pb-1'>
<HStack space={2} className='mt-10' justifyContent='end' wrap>
<SubscriptionButton account={account} />
{(ownAccount && account.id !== ownAccount.id) && <SubscriptionButton account={account} />}
{renderMessageButton()}
{renderShareButton()}

View File

@ -1,4 +1,5 @@
import { useNavigate } from '@tanstack/react-router';
import clsx from 'clsx';
import React, { useMemo } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
@ -6,12 +7,10 @@ import DropdownMenu from 'pl-fe/components/dropdown-menu';
import { ParsedContent } from 'pl-fe/components/parsed-content';
import RelativeTimestamp from 'pl-fe/components/relative-timestamp';
import Avatar from 'pl-fe/components/ui/avatar';
import HStack from 'pl-fe/components/ui/hstack';
import IconButton from 'pl-fe/components/ui/icon-button';
import Stack from 'pl-fe/components/ui/stack';
import Text from 'pl-fe/components/ui/text';
import VerificationBadge from 'pl-fe/components/verification-badge';
import { useChatContext } from 'pl-fe/contexts/chat-context';
import Emojify from 'pl-fe/features/emoji/emojify';
import { useFeatures } from 'pl-fe/hooks/use-features';
import { useRelationshipQuery } from 'pl-fe/queries/accounts/use-relationship';
import { useChatActions } from 'pl-fe/queries/chats';
@ -81,70 +80,58 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
key={chat.id}
onClick={() => onClick(chat)}
onKeyDown={handleKeyDown}
className='group flex w-full flex-col rounded-lg px-2 py-3 hover:bg-gray-100 focus:shadow-inset-ring dark:hover:bg-gray-800'
className='⁂-chat-list-item'
data-testid='chat-list-item'
tabIndex={0}
>
<HStack alignItems='center' justifyContent='between' space={2} className='w-full'>
<HStack alignItems='center' space={2} className='overflow-hidden'>
<div>
<div className='⁂-chat-list-item__info'>
<Avatar
src={chat.account.avatar}
alt={chat.account.avatar_description}
size={40}
className='flex-none'
className='⁂-chat-list-item__avatar'
isCat={chat.account.is_cat}
username={chat.account.username}
/>
<Stack alignItems='start' className='overflow-hidden'>
<div className='flex w-full grow items-center space-x-1'>
<Text weight='bold' size='sm' align='left' truncate>{chat.account?.display_name || `@${chat.account.username}`}</Text>
<div className='⁂-chat-list-item__content'>
<div className='⁂-chat-list-item__name'>
<p>
<Emojify text={chat.account.display_name} emojis={chat.account.emojis} />
</p>
{chat.account?.verified && <VerificationBadge />}
</div>
{(isBlocked || isBlocking) ? (
<Text
align='left'
size='sm'
weight='medium'
theme='muted'
truncate
className='pointer-events-none h-5 w-full italic'
data-testid='chat-last-message'
>
{isBlocked
? <FormattedMessage id='chat_list_item.blocked_you' defaultMessage='This user has blocked you' />
: <FormattedMessage id='chat_list_item.blocking' defaultMessage='You have blocked this user' />}
</Text>
) : (
<>
{chat.last_message?.content && (
<Text
align='left'
size='sm'
weight='medium'
theme={chat.last_message.unread ? 'default' : 'muted'}
truncate
className='truncate-child pointer-events-none h-5 w-full'
data-testid='chat-last-message'
>
<ParsedContent html={chat.last_message?.content} emojis={chat.last_message.emojis} />
</Text>
)}
</>
)}
</Stack>
</HStack>
<p
className={clsx('⁂-chat-list-item__message', {
'⁂-chat-list-item__message--unread': !(isBlocked || isBlocking) && chat.last_message?.unread,
'⁂-chat-list-item__message--blocking': isBlocked || isBlocking,
})}
>
{isBlocked ? (
<FormattedMessage id='chat_list_item.blocked_you' defaultMessage='This user has blocked you' />
) : isBlocking ? (
<FormattedMessage id='chat_list_item.blocking' defaultMessage='You have blocked this user' />
) : (
chat.last_message?.content && (
<ParsedContent
html={chat.last_message?.content}
emojis={chat.last_message.emojis}
/>
)
)}
</p>
</div>
</div>
<HStack alignItems='center' space={2}>
<div className='⁂-chat-list-item__actions'>
{features.chatsDelete && (
<div className='max-w-0 overflow-hidden text-gray-600 hover:text-gray-100 group-hover:max-w-full'>
<div className='⁂-chat-list-item__menu'>
<DropdownMenu items={menu}>
<IconButton
src={require('@phosphor-icons/core/regular/dots-three.svg')}
title={intl.formatMessage(messages.settings)}
className='text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500'
iconClassName='h-4 w-4'
/>
</DropdownMenu>
</div>
@ -154,7 +141,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
<>
{chat.last_message.unread && (
<div
className='size-2 rounded-full bg-secondary-500'
className='⁂-chat-list-item__unread'
data-testid='chat-unread-indicator'
/>
)}
@ -168,8 +155,8 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
/>
</>
)}
</HStack>
</HStack>
</div>
</div>
</div>
);
};

View File

@ -4,9 +4,7 @@ import { FormattedMessage } from 'react-intl';
import { useAccount } from 'pl-fe/api/hooks/accounts/use-account';
import { ParsedContent } from 'pl-fe/components/parsed-content';
import Avatar from 'pl-fe/components/ui/avatar';
import HStack from 'pl-fe/components/ui/hstack';
import Stack from 'pl-fe/components/ui/stack';
import Text from 'pl-fe/components/ui/text';
import Emojify from 'pl-fe/features/emoji/emojify';
import { useInstance } from 'pl-fe/hooks/use-instance';
import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config';
import { useShoutboxMessages } from 'pl-fe/stores/shoutbox';
@ -37,43 +35,33 @@ const ChatListShoutbox: React.FC<IChatListShoutboxInterface> = ({ onClick }) =>
key='shoutbox'
onClick={() => onClick('shoutbox')}
onKeyDown={handleKeyDown}
className='group flex w-full flex-col rounded-lg px-2 py-3 hover:bg-gray-100 focus:shadow-inset-ring dark:hover:bg-gray-800'
className='⁂-chat-list-item ⁂-chat-list-item--shoutbox'
data-testid='chat-list-item'
tabIndex={0}
>
<HStack alignItems='center' justifyContent='between' space={2} className='w-full'>
<HStack alignItems='center' space={2} className='overflow-hidden'>
<Avatar src={logo} alt='' size={40} className='flex-none' />
<Stack alignItems='start' className='overflow-hidden'>
<div className='flex w-full grow items-center space-x-1'>
<Text weight='bold' size='sm' align='left' truncate>
<FormattedMessage id='chat_list_item_shoutbox' defaultMessage='{instance} shoutbox' values={{ instance: instance.title }} />
</Text>
</div>
<div>
<Avatar src={logo} alt='' size={40} className='flex-none' />
<div className='⁂-chat-list-item__content'>
<div className='⁂-chat-list-item__name'>
<p>
<FormattedMessage id='chat_list_item_shoutbox' defaultMessage='{instance} shoutbox' values={{ instance: instance.title }} />
</p>
</div>
{lastMessage && (
<>
<Text
align='left'
size='sm'
weight='medium'
theme='muted'
truncate
className='truncate-child pointer-events-none h-5 w-full'
>
{lastMessageAuthor && (
<Text weight='bold' size='sm' align='left' theme='muted' truncate tag='span'>
{lastMessageAuthor.display_name || `@${lastMessageAuthor.username}`}:
{' '}
</Text>
)}
<ParsedContent html={lastMessage.text} />
</Text>
</>
)}
</Stack>
</HStack>
</HStack>
{lastMessage && (
<>
<p className='⁂-chat-list-item__message'>
{lastMessageAuthor && (
<span className='⁂-chat-list-item__message__author'>
<Emojify text={lastMessageAuthor.display_name} emojis={lastMessageAuthor.emojis} />{': '}
</span>
)}
<ParsedContent html={lastMessage.text} />
</p>
</>
)}
</div>
</div>
</div>
);
};

View File

@ -52,42 +52,31 @@ const ChatList: React.FC<IChatList> = ({ onClickChat, useWindowScroll = false })
};
return (
<div className='relative h-full'>
<PullToRefresh onRefresh={handleRefresh}>
<Virtuoso
atTopStateChange={(atTop) => setNearTop(atTop)}
atBottomStateChange={(atBottom) => setNearBottom(atBottom)}
useWindowScroll={useWindowScroll}
data={allChats}
endReached={handleLoadMore}
itemContent={(_index, chat) => (
<div className='px-2'>
{chat === 'shoutbox' ? <ChatListShoutbox onClick={onClickChat} /> : <ChatListItem chat={chat} onClick={onClickChat} />}
</div>
)}
components={{
ScrollSeekPlaceholder: () => <PlaceholderChat />,
Footer: () => hasNextPage ? <Spinner withText={false} /> : null,
EmptyPlaceholder: renderEmpty,
}}
/>
</PullToRefresh>
<>
<div
className={clsx('pointer-events-none absolute inset-x-0 flex justify-center rounded-t-lg bg-gradient-to-b from-white to-transparent pb-12 pt-8 transition-opacity duration-500 black:from-black dark:from-gray-900', {
'opacity-0': isNearTop,
'opacity-100 black:opacity-50': !isNearTop,
})}
/>
<div
className={clsx('pointer-events-none absolute inset-x-0 bottom-0 flex justify-center rounded-b-lg bg-gradient-to-t from-white to-transparent pb-8 pt-12 transition-opacity duration-500 black:from-black dark:from-gray-900', {
'opacity-0': isNearBottom,
'opacity-100 black:opacity-50': !isNearBottom,
})}
/>
</>
</div>
<PullToRefresh
onRefresh={handleRefresh}
className={clsx({
'⁂-chat-widget__list--near-top': isNearTop,
'⁂-chat-widget__list--near-bottom': isNearBottom,
})}
>
<Virtuoso
atTopStateChange={(atTop) => setNearTop(atTop)}
atBottomStateChange={(atBottom) => setNearBottom(atBottom)}
useWindowScroll={useWindowScroll}
data={allChats}
endReached={handleLoadMore}
itemContent={(_index, chat) => (
<div className='px-2'>
{chat === 'shoutbox' ? <ChatListShoutbox onClick={onClickChat} /> : <ChatListItem chat={chat} onClick={onClickChat} />}
</div>
)}
components={{
ScrollSeekPlaceholder: () => <PlaceholderChat />,
Footer: () => hasNextPage ? <Spinner withText={false} /> : null,
EmptyPlaceholder: renderEmpty,
}}
/>
</PullToRefresh>
);
};

View File

@ -178,11 +178,11 @@ const EditEvent: React.FC<IEditEvent> = ({ statusId }) => {
labelText={<FormattedMessage id='compose_event.fields.banner_label' defaultMessage='Event banner' />}
hintText={<FormattedMessage id='compose_event.fields.banner_hint' defaultMessage='PNG, GIF or JPG. Landscape format is preferred.' />}
>
<div className='dark:sm:shadow-inset relative flex h-24 items-center justify-center overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-white sm:h-32 sm:shadow'>
<div className='⁂-edit-event__banner__container'>
{banner ? (
<>
<img className='size-full object-cover' src={banner.url} alt='' />
<IconButton className='absolute right-2 top-2' src={require('@phosphor-icons/core/regular/x.svg')} onClick={handleClearBanner} />
<img src={banner.url} alt='' />
<IconButton src={require('@phosphor-icons/core/regular/x.svg')} onClick={handleClearBanner} />
</>
) : (
<UploadButton disabled={isUploading} onSelectFile={handleFiles} />
@ -206,8 +206,7 @@ const EditEvent: React.FC<IEditEvent> = ({ statusId }) => {
<ContentTypeButton composeId={composeId} />
<ComposeEditor
key={String(isDisabled)}
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 black:bg-black dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500 sm:text-sm'
placeholderClassName='pt-2'
placeholderClassName='⁂-compose-form__editor__placeholder'
composeId={composeId}
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
handleSubmit={handleSubmit}

View File

@ -200,12 +200,7 @@ const ComposeEditor = React.forwardRef<LexicalEditor, IComposeEditor>(({
</div>
}
placeholder={(
<div
className={clsx(
'pointer-events-none absolute top-0 select-none text-[1rem] text-gray-600 dark:placeholder:text-gray-600',
placeholderClassName,
)}
>
<div className={placeholderClassName}>
{textareaPlaceholder}
</div>
)}

View File

@ -21,7 +21,7 @@ const SharePage: React.FC = () => {
if (text) {
dispatch(openComposeWithText('compose-modal', text));
}
});
}, []);
return null;
};

View File

@ -95,6 +95,28 @@
gap: 1rem;
height: 100%;
flex-grow: 1;
> div {
&::before,
&::after {
@apply pointer-events-none absolute inset-x-0 flex justify-center from-white to-transparent pb-12 pt-8 transition-opacity duration-500 black:from-black dark:from-gray-900 opacity-100 black:opacity-50;
content: '';
z-index: 2;
}
&::before {
@apply top-0 rounded-t-lg bg-gradient-to-b;
}
&::after {
@apply bottom-0 rounded-b-lg bg-gradient-to-t;
}
&.-chat-widget__list--near-top::before,
&.-chat-widget__list--near-bottom::after {
@apply opacity-0 black:opacity-0;
}
}
}
&__blankslate {
@ -126,4 +148,85 @@
@include mixins.button($theme: primary);
}
}
}
.-chat-list-item {
@apply flex w-full flex-col rounded-lg px-2 py-3 hover:bg-gray-100 focus:shadow-inset-ring dark:hover:bg-gray-800;
> div {
@apply flex items-center justify-between gap-2 w-full;
}
&--shoutbox > div {
@apply justify-normal;
}
&__info {
@apply flex items-center gap-2 overflow-hidden;
}
&__avatar {
@apply flex-none;
}
&__content {
@apply flex flex-col items-start overflow-hidden;
}
&__name {
@apply flex w-full grow items-center space-x-1;
p {
@include mixins.text($weight: bold, $size: sm, $align: left, $truncate: true);
}
}
&__message {
@include mixins.text($theme: muted, $size: sm, $align: left, $truncate: true);
@apply truncate-child pointer-events-none h-5 w-full;
&--unread {
@apply text-gray-900 dark:text-gray-100;
}
&:not(&--blocking) > * {
@apply truncate;
}
&__author {
@include mixins.text($weight: bold, $size: sm, $align: left, $theme: muted, $truncate: true);
}
}
&__actions {
@apply flex items-center gap-2;
}
&__menu {
@apply max-w-0 overflow-hidden text-gray-600 hover:text-gray-100;
.-icon-button {
@apply text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500;
svg {
@apply h-4 w-4;
}
}
}
&:hover .-chat-list-item__menu {
@apply max-w-full;
}
&__unread {
@apply size-2 rounded-full bg-secondary-500;
}
&__timestamp {
@include mixins.text($theme: muted, $size: xs, $align: right, $truncate: true);
}
&__unread + &__timestamp {
@apply text-gray-900 dark:text-gray-100;
}
}

View File

@ -30,6 +30,11 @@
background-color: transparent !important;
}
&__editor__placeholder {
@apply pointer-events-none absolute top-0 select-none text-[1rem] text-gray-600 dark:placeholder:text-gray-600;
visibility: visible !important;
}
&:not(&--transparent) &__editor {
@apply rounded-md border-gray-400 px-3 py-2 ring-2 focus-within:border-primary-500 focus-within:ring-primary-500 dark:border-gray-800 dark:ring-gray-800 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500;

View File

@ -15,6 +15,51 @@
height: 1rem;
}
}
&__banner__container {
@apply dark:sm:shadow-inset relative flex h-24 items-center justify-center overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-white sm:h-32 sm:shadow;
img {
height: 100%;
width: 100%;
object-fit: cover;
}
.-icon-button {
position: absolute;
top: 0.5rem;
right: 0.5rem;
}
}
.lexical {
display: block;
width: 100%;
border-radius: 0.375rem;
border: 1px solid rgb(var(--color-gray-400));
background-color: rgb(var(--color-white));
padding: 0.5rem 0.75rem;
font-size: 0.9375rem;
color: rgb(var(--color-gray-900));
outline: 1px solid transparent;
@apply placeholder:text-gray-600 focus-within:border-primary-500 black:bg-black dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 sm:text-sm;
&:focus-within {
outline-color: rgb(var(--color-primary-500));
}
&:is(.dark *) {
outline-color: rgb(var(--color-gray-800));
&:focus-within {
outline-color: rgb(var(--color-primary-500));
}
}
}
.-compose-form__editor__placeholder {
@apply pt-2;
}
}
.-event-map-modal {

354
pnpm-lock.yaml generated
View File

@ -134,32 +134,32 @@ importers:
specifier: ^5.2.7
version: 5.2.7
'@lexical/code':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@lexical/hashtag':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@lexical/link':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@lexical/list':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@lexical/markdown':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@lexical/react':
specifier: ^0.38.2
version: 0.38.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(yjs@13.6.27)
specifier: ^0.39.0
version: 0.39.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(yjs@13.6.27)
'@lexical/rich-text':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@lexical/selection':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@lexical/utils':
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
'@mkljczk/url-purify':
specifier: ^0.0.5
version: 0.0.5
@ -302,8 +302,8 @@ importers:
specifier: ^1.8.0
version: 1.9.4
lexical:
specifier: ^0.38.2
version: 0.38.2
specifier: ^0.39.0
version: 0.39.0
line-awesome:
specifier: ^1.3.0
version: 1.3.0
@ -1219,10 +1219,6 @@ packages:
resolution: {integrity: sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==}
engines: {node: '>=6.9.0'}
'@babel/runtime@7.28.4':
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
engines: {node: '>=6.9.0'}
'@babel/runtime@7.28.6':
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
engines: {node: '>=6.9.0'}
@ -1858,77 +1854,77 @@ packages:
'@keyv/serialize@1.1.0':
resolution: {integrity: sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g==}
'@lexical/clipboard@0.38.2':
resolution: {integrity: sha512-dDShUplCu8/o6BB9ousr3uFZ9bltR+HtleF/Tl8FXFNPpZ4AXhbLKUoJuucRuIr+zqT7RxEv/3M6pk/HEoE6NQ==}
'@lexical/clipboard@0.39.0':
resolution: {integrity: sha512-ylrHy8M+I5EH4utwqivslugqQhvgLTz9VEJdrb2RjbhKQEXwMcqKCRWh6cRfkYx64onE2YQE0nRIdzHhExEpLQ==}
'@lexical/code@0.38.2':
resolution: {integrity: sha512-wpqgbmPsfi/+8SYP0zI2kml09fGPRhzO5litR9DIbbSGvcbawMbRNcKLO81DaTbsJRnBJiQvbBBBJAwZKRqgBw==}
'@lexical/code@0.39.0':
resolution: {integrity: sha512-3tqFOOzP5Z9nRkZPHZYmIyLXd28gMMrlAD3k2zxiH5vGnAqiYTezR24CpRDw1BaF2c8vCgY/9CNobZzjXivpIA==}
'@lexical/devtools-core@0.38.2':
resolution: {integrity: sha512-hlN0q7taHNzG47xKynQLCAFEPOL8l6IP79C2M18/FE1+htqNP35q4rWhYhsptGlKo4me4PtiME7mskvr7T4yqA==}
'@lexical/devtools-core@0.39.0':
resolution: {integrity: sha512-2ET2nFeRhcc2YMrn184wxoEOTLl3UOlugi8ozuZFa6F4UDMXPq7nZRhiQNgYzhE6Z7NLMFrcmghvx652JbEowg==}
peerDependencies:
react: '>=17.x'
react-dom: '>=17.x'
'@lexical/dragon@0.38.2':
resolution: {integrity: sha512-riOhgo+l4oN50RnLGhcqeUokVlMZRc+NDrxRNs2lyKSUdC4vAhAmAVUHDqYPyb4K4ZSw4ebZ3j8hI2zO4O3BbA==}
'@lexical/dragon@0.39.0':
resolution: {integrity: sha512-JkcBAYPZGzfs29gtkePeJG9US1uwKW6PkUt8G4QZkMTt4QMDnadqXauFE+30rbpvRdeNcR7s+/jOuRHd5SurDQ==}
'@lexical/extension@0.38.2':
resolution: {integrity: sha512-qbUNxEVjAC0kxp7hEMTzktj0/51SyJoIJWK6Gm790b4yNBq82fEPkksfuLkRg9VQUteD0RT1Nkjy8pho8nNamw==}
'@lexical/extension@0.39.0':
resolution: {integrity: sha512-mp/WcF8E53FWPiUHgHQz382J7u7C4+cELYNkC00dKaymf8NhS6M65Y8tyDikNGNUcLXSzaluwK0HkiKjTYGhVQ==}
'@lexical/hashtag@0.38.2':
resolution: {integrity: sha512-jNI4Pv+plth39bjOeeQegMypkjDmoMWBMZtV0lCynBpkkPFlfMnyL9uzW/IxkZnX8LXWSw5mbWk07nqOUNTCrA==}
'@lexical/hashtag@0.39.0':
resolution: {integrity: sha512-CFLNB74a607nC2GGcjKNPbo/ZnehnR3zz9+S5bfUg5dblSGKdCfxHiyr2cDwHY3dfOTu+qtimfh2Zqxz4dfghA==}
'@lexical/history@0.38.2':
resolution: {integrity: sha512-QWPwoVDMe/oJ0+TFhy78TDi7TWU/8bcDRFUNk1nWgbq7+2m+5MMoj90LmOFwakQHnCVovgba2qj+atZrab1dsQ==}
'@lexical/history@0.39.0':
resolution: {integrity: sha512-kuctleDime0tRDxQNDW8i5d6D/ys5Npp2yoCBmdKS8HfS/jz7uPumfZcX7wvUvNAEVExh+bY9IxqIexyGkNUtA==}
'@lexical/html@0.38.2':
resolution: {integrity: sha512-pC5AV+07bmHistRwgG3NJzBMlIzSdxYO6rJU4eBNzyR4becdiLsI4iuv+aY7PhfSv+SCs7QJ9oc4i5caq48Pkg==}
'@lexical/html@0.39.0':
resolution: {integrity: sha512-7VLWP5DpzBg3kKctpNK6PbhymKAtU6NAnKieopCfCIWlMW+EqpldteiIXGqSqrMRK0JWTmF1gKgr9nnQyOOsXw==}
'@lexical/link@0.38.2':
resolution: {integrity: sha512-UOKTyYqrdCR9+7GmH6ZVqJTmqYefKGMUHMGljyGks+OjOGZAQs78S1QgcPEqltDy+SSdPSYK7wAo6gjxZfEq9g==}
'@lexical/link@0.39.0':
resolution: {integrity: sha512-L1jSF2BVRHDqIQbKYFcQt3CqtVIphRA3QAW2VooYPNlKeaAb/yfFS+C60GX1cj96b0rMlHKrNC17ik2aEBZKLQ==}
'@lexical/list@0.38.2':
resolution: {integrity: sha512-OQm9TzatlMrDZGxMxbozZEHzMJhKxAbH1TOnOGyFfzpfjbnFK2y8oLeVsfQZfZRmiqQS4Qc/rpFnRP2Ax5dsbA==}
'@lexical/list@0.39.0':
resolution: {integrity: sha512-mxgSxUrakTCHtC+gF30BChQBJTsCMiMgfC2H5VvhcFwXMgsKE/aK9+a+C/sSvvzCmPXqzYsuAcGkJcrY3e5xlw==}
'@lexical/mark@0.38.2':
resolution: {integrity: sha512-U+8KGwc3cP5DxSs15HfkP2YZJDs5wMbWQAwpGqep9bKphgxUgjPViKhdi+PxIt2QEzk7WcoZWUsK1d2ty/vSmg==}
'@lexical/mark@0.39.0':
resolution: {integrity: sha512-wVs5498dWYOQ07FAHaFW6oYgNG3moBargf6es7+gHPzjlaoZ6Hd8sbvJtlT8F2RRlw+U+kUh4s8SjFuMSEJp0w==}
'@lexical/markdown@0.38.2':
resolution: {integrity: sha512-ykQJ9KUpCs1+Ak6ZhQMP6Slai4/CxfLEGg/rSHNVGbcd7OaH/ICtZN5jOmIe9ExfXMWy1o8PyMu+oAM3+AWFgA==}
'@lexical/markdown@0.39.0':
resolution: {integrity: sha512-mPaKH2FSwRwU2bDbMiMtdOridaEvSLU3Q5l7bqYE+TW799C/1EEtiv4xSkI01SjV9YOxNf24VNOipAMymPueKA==}
'@lexical/offset@0.38.2':
resolution: {integrity: sha512-uDky2palcY+gE6WTv6q2umm2ioTUnVqcaWlEcchP6A310rI08n6rbpmkaLSIh3mT2GJQN2QcN2x0ct5BQmKIpA==}
'@lexical/offset@0.39.0':
resolution: {integrity: sha512-8p+16AgFsG8ecZVQlFO6TQ+zHHHg7LKPNdm9BkklkJux41Y1+9rlPO12Mgbi4x2Hy2pRA8Gd/Su3hySGqEEVlA==}
'@lexical/overflow@0.38.2':
resolution: {integrity: sha512-f6vkTf+YZF0EuKvUK3goh4jrnF+Z0koiNMO+7rhSMLooc5IlD/4XXix4ZLiIktUWq4BhO84b82qtrO+6oPUxtw==}
'@lexical/overflow@0.39.0':
resolution: {integrity: sha512-BLtF4MNDrTNQFgryw6MPWh2Fj4GMjqC/6p9bbnZ9fdwMWKGSbsSNcK9PLlBwg3IzEK3XiibFDHUbsETwUd/bfw==}
'@lexical/plain-text@0.38.2':
resolution: {integrity: sha512-xRYNHJJFCbaQgr0uErW8Im2Phv1nWHIT4VSoAlBYqLuVGZBD4p61dqheBwqXWlGGJFk+MY5C5URLiMicgpol7A==}
'@lexical/plain-text@0.39.0':
resolution: {integrity: sha512-Ep0PGF7GlBNgiJJh/DBEPLt1WXyHUb7bCYZ4MUbD31AiJdG0p5a/g9dVTUr4QtNlCIXBCZjuatHyp6e2mzMacg==}
'@lexical/react@0.38.2':
resolution: {integrity: sha512-M3z3MkWyw3Msg4Hojr5TnO4TzL71NVPVNGoavESjdgJbTdv1ezcQqjE4feq+qs7H9jytZeuK8wsEOJfSPmNd8w==}
'@lexical/react@0.39.0':
resolution: {integrity: sha512-6ySVb5xv99GIkVzio4qqOBxkPgOSSeFAB4o9bVqtg72JbCoEKZPnWq5VVurGe1uiRJM8jvqTseM9mo2zTvUfXQ==}
peerDependencies:
react: '>=17.x'
react-dom: '>=17.x'
'@lexical/rich-text@0.38.2':
resolution: {integrity: sha512-eFjeOT7YnDZYpty7Zlwlct0UxUSaYu53uLYG+Prs3NoKzsfEK7e7nYsy/BbQFfk5HoM1pYuYxFR2iIX62+YHGw==}
'@lexical/rich-text@0.39.0':
resolution: {integrity: sha512-UoSgRi09nLP/mmD3ijdZycr9icnqlb761rzHC1gicuPDdTu0ruxAFbGanSE2h36ihSu0IUHwkpf4gBpgPPqWBw==}
'@lexical/selection@0.38.2':
resolution: {integrity: sha512-eMFiWlBH6bEX9U9sMJ6PXPxVXTrihQfFeiIlWLuTpEIDF2HRz7Uo1KFRC/yN6q0DQaj7d9NZYA6Mei5DoQuz5w==}
'@lexical/selection@0.39.0':
resolution: {integrity: sha512-j0cgNuTKDCdf/4MzRnAUwEqG6C/WQp18k2WKmX5KIVZJlhnGIJmlgSBrxjo8AuZ16DIHxTm2XNB4cUDCgZNuPA==}
'@lexical/table@0.38.2':
resolution: {integrity: sha512-uu0i7yz0nbClmHOO5ZFsinRJE6vQnFz2YPblYHAlNigiBedhqMwSv5bedrzDq8nTTHwych3mC63tcyKIrM+I1g==}
'@lexical/table@0.39.0':
resolution: {integrity: sha512-1eH11kV4bJ0fufCYl8DpE19kHwqUI8Ev5CZwivfAtC3ntwyNkeEpjCc0pqeYYIWN/4rTZ5jgB3IJV4FntyfCzw==}
'@lexical/text@0.38.2':
resolution: {integrity: sha512-+juZxUugtC4T37aE3P0l4I9tsWbogDUnTI/mgYk4Ht9g+gLJnhQkzSA8chIyfTxbj5i0A8yWrUUSw+/xA7lKUQ==}
'@lexical/text@0.39.0':
resolution: {integrity: sha512-fcIgejtIgfMAkxio6BO1eLA2eb4oRIFoUVA2jAXdCaLVHrG/cizitbygPrgWnWd8nt1WlMuS4lxa0PJl7h7Lqg==}
'@lexical/utils@0.38.2':
resolution: {integrity: sha512-y+3rw15r4oAWIEXicUdNjfk8018dbKl7dWHqGHVEtqzAYefnEYdfD2FJ5KOTXfeoYfxi8yOW7FvzS4NZDi8Bfw==}
'@lexical/utils@0.39.0':
resolution: {integrity: sha512-8YChidpMJpwQc4nex29FKUeuZzC++QCS/Jt46lPuy1GS/BZQoPHFKQ5hyVvM9QVhc5CEs4WGNoaCZvZIVN8bQw==}
'@lexical/yjs@0.38.2':
resolution: {integrity: sha512-fg6ZHNrVQmy1AAxaTs8HrFbeNTJCaCoEDPi6pqypHQU3QVfqr4nq0L0EcHU/TRlR1CeduEPvZZIjUUxWTZ0u8g==}
'@lexical/yjs@0.39.0':
resolution: {integrity: sha512-peBrzIDoRWeyX9XTilKVdeJua6A+RZ24CG7lgGLEhmNSGCqpj9FqlC1Wtrul4wTSh85KlDeI1Nq30gnyeNKWYA==}
peerDependencies:
yjs: '>=13.5.22'
@ -4797,8 +4793,8 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
lexical@0.38.2:
resolution: {integrity: sha512-JJmfsG3c4gwBHzUGffbV7ifMNkKAWMCnYE3xJl87gty7hjyV5f3xq7eqTjP5HFYvO4XpjJvvWO2/djHp5S10tw==}
lexical@0.39.0:
resolution: {integrity: sha512-lpLv7MEJH5QDujEDlYqettL3ATVtNYjqyimzqgrm0RvCm3AO9WXSdsgTxuN7IAZRu88xkxCDeYubeUf4mNZVdg==}
lib0@0.2.117:
resolution: {integrity: sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==}
@ -7849,8 +7845,6 @@ snapshots:
'@babel/runtime@7.28.2': {}
'@babel/runtime@7.28.4': {}
'@babel/runtime@7.28.6': {}
'@babel/template@7.27.2':
@ -8383,165 +8377,165 @@ snapshots:
'@keyv/serialize@1.1.0': {}
'@lexical/clipboard@0.38.2':
'@lexical/clipboard@0.39.0':
dependencies:
'@lexical/html': 0.38.2
'@lexical/list': 0.38.2
'@lexical/selection': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/html': 0.39.0
'@lexical/list': 0.39.0
'@lexical/selection': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/code@0.38.2':
'@lexical/code@0.39.0':
dependencies:
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/utils': 0.39.0
lexical: 0.39.0
prismjs: 1.30.0
'@lexical/devtools-core@0.38.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
'@lexical/devtools-core@0.39.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@lexical/html': 0.38.2
'@lexical/link': 0.38.2
'@lexical/mark': 0.38.2
'@lexical/table': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/html': 0.39.0
'@lexical/link': 0.39.0
'@lexical/mark': 0.39.0
'@lexical/table': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
'@lexical/dragon@0.38.2':
'@lexical/dragon@0.39.0':
dependencies:
'@lexical/extension': 0.38.2
lexical: 0.38.2
'@lexical/extension': 0.39.0
lexical: 0.39.0
'@lexical/extension@0.38.2':
'@lexical/extension@0.39.0':
dependencies:
'@lexical/utils': 0.38.2
'@lexical/utils': 0.39.0
'@preact/signals-core': 1.12.1
lexical: 0.38.2
lexical: 0.39.0
'@lexical/hashtag@0.38.2':
'@lexical/hashtag@0.39.0':
dependencies:
'@lexical/text': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/text': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/history@0.38.2':
'@lexical/history@0.39.0':
dependencies:
'@lexical/extension': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/extension': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/html@0.38.2':
'@lexical/html@0.39.0':
dependencies:
'@lexical/selection': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/selection': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/link@0.38.2':
'@lexical/link@0.39.0':
dependencies:
'@lexical/extension': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/extension': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/list@0.38.2':
'@lexical/list@0.39.0':
dependencies:
'@lexical/extension': 0.38.2
'@lexical/selection': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/extension': 0.39.0
'@lexical/selection': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/mark@0.38.2':
'@lexical/mark@0.39.0':
dependencies:
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/markdown@0.38.2':
'@lexical/markdown@0.39.0':
dependencies:
'@lexical/code': 0.38.2
'@lexical/link': 0.38.2
'@lexical/list': 0.38.2
'@lexical/rich-text': 0.38.2
'@lexical/text': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/code': 0.39.0
'@lexical/link': 0.39.0
'@lexical/list': 0.39.0
'@lexical/rich-text': 0.39.0
'@lexical/text': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/offset@0.38.2':
'@lexical/offset@0.39.0':
dependencies:
lexical: 0.38.2
lexical: 0.39.0
'@lexical/overflow@0.38.2':
'@lexical/overflow@0.39.0':
dependencies:
lexical: 0.38.2
lexical: 0.39.0
'@lexical/plain-text@0.38.2':
'@lexical/plain-text@0.39.0':
dependencies:
'@lexical/clipboard': 0.38.2
'@lexical/dragon': 0.38.2
'@lexical/selection': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/clipboard': 0.39.0
'@lexical/dragon': 0.39.0
'@lexical/selection': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/react@0.38.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(yjs@13.6.27)':
'@lexical/react@0.39.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(yjs@13.6.27)':
dependencies:
'@floating-ui/react': 0.27.16(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@lexical/devtools-core': 0.38.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@lexical/dragon': 0.38.2
'@lexical/extension': 0.38.2
'@lexical/hashtag': 0.38.2
'@lexical/history': 0.38.2
'@lexical/link': 0.38.2
'@lexical/list': 0.38.2
'@lexical/mark': 0.38.2
'@lexical/markdown': 0.38.2
'@lexical/overflow': 0.38.2
'@lexical/plain-text': 0.38.2
'@lexical/rich-text': 0.38.2
'@lexical/table': 0.38.2
'@lexical/text': 0.38.2
'@lexical/utils': 0.38.2
'@lexical/yjs': 0.38.2(yjs@13.6.27)
lexical: 0.38.2
'@lexical/devtools-core': 0.39.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@lexical/dragon': 0.39.0
'@lexical/extension': 0.39.0
'@lexical/hashtag': 0.39.0
'@lexical/history': 0.39.0
'@lexical/link': 0.39.0
'@lexical/list': 0.39.0
'@lexical/mark': 0.39.0
'@lexical/markdown': 0.39.0
'@lexical/overflow': 0.39.0
'@lexical/plain-text': 0.39.0
'@lexical/rich-text': 0.39.0
'@lexical/table': 0.39.0
'@lexical/text': 0.39.0
'@lexical/utils': 0.39.0
'@lexical/yjs': 0.39.0(yjs@13.6.27)
lexical: 0.39.0
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
react-error-boundary: 6.0.0(react@19.2.3)
transitivePeerDependencies:
- yjs
'@lexical/rich-text@0.38.2':
'@lexical/rich-text@0.39.0':
dependencies:
'@lexical/clipboard': 0.38.2
'@lexical/dragon': 0.38.2
'@lexical/selection': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/clipboard': 0.39.0
'@lexical/dragon': 0.39.0
'@lexical/selection': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/selection@0.38.2':
'@lexical/selection@0.39.0':
dependencies:
lexical: 0.38.2
lexical: 0.39.0
'@lexical/table@0.38.2':
'@lexical/table@0.39.0':
dependencies:
'@lexical/clipboard': 0.38.2
'@lexical/extension': 0.38.2
'@lexical/utils': 0.38.2
lexical: 0.38.2
'@lexical/clipboard': 0.39.0
'@lexical/extension': 0.39.0
'@lexical/utils': 0.39.0
lexical: 0.39.0
'@lexical/text@0.38.2':
'@lexical/text@0.39.0':
dependencies:
lexical: 0.38.2
lexical: 0.39.0
'@lexical/utils@0.38.2':
'@lexical/utils@0.39.0':
dependencies:
'@lexical/list': 0.38.2
'@lexical/selection': 0.38.2
'@lexical/table': 0.38.2
lexical: 0.38.2
'@lexical/list': 0.39.0
'@lexical/selection': 0.39.0
'@lexical/table': 0.39.0
lexical: 0.39.0
'@lexical/yjs@0.38.2(yjs@13.6.27)':
'@lexical/yjs@0.39.0(yjs@13.6.27)':
dependencies:
'@lexical/offset': 0.38.2
'@lexical/selection': 0.38.2
lexical: 0.38.2
'@lexical/offset': 0.39.0
'@lexical/selection': 0.39.0
lexical: 0.39.0
yjs: 13.6.27
'@material/material-color-utilities@0.3.0': {}
@ -11986,7 +11980,7 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
lexical@0.38.2: {}
lexical@0.39.0: {}
lib0@0.2.117:
dependencies:
@ -12740,7 +12734,7 @@ snapshots:
react-error-boundary@6.0.0(react@19.2.3):
dependencies:
'@babel/runtime': 7.28.4
'@babel/runtime': 7.28.6
react: 19.2.3
react-event-listener@0.6.6(react@19.2.3):