fix(ui): native inputs/checkboxes, QR fallback, focus + report modal cleanup
- N23 RoomServerACL: raw text input -> folds Input; raw checkbox -> folds Checkbox
- N24 PolicyListViewer: raw room-id input -> folds Input (Critical variant on error)
- N25 ExportRoomHistory: raw <input type="date"> x2 -> folds Input
- N26 RoomShareInvite: QR <img> gets loading="lazy" + onError fallback card
("QR code unavailable") instead of a broken-image icon
- N27 GifPicker: FocusTrap returnFocusOnDeactivate:false (matches EmojiBoard)
- N76 Report modals: drop redundant Cancel button (dismiss via header x /
click-outside, like MessageReportItem)
- N5 ReadReceiptAvatars: hover/focus moved to co-located css :hover/:focus-visible
(removed JS onMouseEnter/Leave .style mutation)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+7
-7
@@ -309,7 +309,7 @@ This document tracks identified bugs, edge cases, and architectural discrepancie
|
||||
|
||||
| # | Area | File | Lines | Issue | Native Pattern |
|
||||
| :-- | :------------------------- | :---------------------------------------- | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| N5 | Read Receipts | `ReadReceiptAvatars.tsx` | 62–137 | Trigger button is raw `<button>` with `onMouseEnter`/`onMouseLeave` JS style mutation for hover state | All interactive elements use `useHover` from `react-aria` and folds variant system for hover; direct `.style` mutation used nowhere else on buttons |
|
||||
| N5 | Read Receipts | `ReadReceiptAvatars.tsx` | 62–137 | Trigger button is raw `<button>` with `onMouseEnter`/`onMouseLeave` JS style mutation for hover state — **FIXED**: hover/focus emphasis moved to co-located `ReadReceiptAvatars.css.ts` (`:hover`/`:focus-visible`), no JS `.style` mutation | All interactive elements use `useHover` from `react-aria` and folds variant system for hover; direct `.style` mutation used nowhere else on buttons |
|
||||
| N6 | Read Receipts | `ReadReceiptAvatars.tsx` & `Message.tsx` | 32–56 / 268–283 | Two code paths open `EventReaders`: avatar-pill path uses `useModalStyle(360)` for mobile fullscreen; context-menu path (`MessageReadReceiptItem`) does not — on mobile the context menu path opens a fixed-size non-fullscreen modal for the same content | All modals that share a layout variant use `useModalStyle` consistently; `MessageReadReceiptItem` was not updated when `useModalStyle` was added |
|
||||
| N7 | Delivery Status | `Message.tsx` | 89–148 | `DeliveryStatus` renders Unicode glyphs (`⟳ ✓ ✕`) in a `<span>` with `fontSize: '10px'` instead of folds `<Icon>` components — **FIXED**: replaced with `Icons.Check/Cross/Send` via `<Icon size="100">` | `Icons.Check`, `Icons.Cross`, etc. are used for all other status glyphs; folds `Text` size tokens for all supplementary text |
|
||||
| N8 | GIF Picker | `GifPicker.tsx` | 83–124 | GIF picker container uses fully bespoke inline styles (`borderRadius: '12px'`, `boxShadow: '0 8px 32px rgba(0,0,0,0.4)'`, raw `rgba` border) — two separate style sets for TDS and non-TDS paths | `EmojiBoard` has no caller-applied container styling; folds components handle their own surface internally via design tokens |
|
||||
@@ -327,10 +327,10 @@ This document tracks identified bugs, edge cases, and architectural discrepancie
|
||||
| N20 | Notification Presets | `Notifications.tsx` | 57–107 | Gaming/Work/Sleep preset buttons are bare `<button>` elements with Lotus-specific CSS vars (`--border-interactive-normal`, `--bg-surface-low`) not defined in all themes | Grouped preset/action buttons elsewhere use folds `Chip variant="Primary/Secondary" outlined radii="Pill"` (e.g., Composer Toolbar toggles in `General.tsx:1100–1113`) |
|
||||
| N21 | Notification Sound Selects | `SystemNotification.tsx` | 111–305 | Message sound, invite sound, and quiet-hours time pickers are bare `<select>`/`<input type="time">` with `colorScheme: 'dark'` workaround | All other dropdowns in settings use the `Button`+`PopOut`+`Menu`+`MenuItem` folds pattern; the native select renders OS-styled on all platforms |
|
||||
| N22 | DM Preview Virtualizer | `RoomNavItem.tsx` / `Direct.tsx` | 608–627 / 232 | DM preview adds a second text row to each DM item, making it taller than 38px, but `useVirtualizer` in `Direct.tsx` still uses `estimateSize: () => 38` — causes layout jump/overlap on initial render | Non-DM rooms in Home.tsx also estimate 38px; DM items with a preview are now a different height, creating two visual densities in the same nav column |
|
||||
| N23 | RoomServerACL | `RoomServerACL.tsx` | 100–115 / 298–309 | Server-name text input is a raw `<input type="text">` with inline style object; "Allow IP literal addresses" is a raw `<input type="checkbox">` with `style={{ width: 16, height: 16 }}` | All other text/boolean controls in room settings use folds `Input` and `Checkbox` components (`RoomAddress.tsx:163`, `RoomAddress.tsx:330`) |
|
||||
| N24 | PolicyListViewer | `PolicyListViewer.tsx` | 245–264 | Room-ID add input is a raw `<input type="text">` with manually replicated folds token values | Native pattern: folds `<Input variant="Secondary" size="300" radii="300">` — no inline style needed |
|
||||
| N25 | ExportRoomHistory Inputs | `ExportRoomHistory.tsx` | 258–292 | Both date range pickers are raw `<input type="date">` with inline styles | Native pattern: folds `Input` component; `<input type="date">` renders OS-native date picker, unstyled relative to the rest of the settings panel |
|
||||
| N26 | RoomShareInvite QR | `RoomShareInvite.tsx` | 66–73 | QR code `<img>` has no `onError` handler and no loading state — broken-image placeholder shown when the external API is unreachable | Cinny avatar components and MediaGallery use `onError` handlers; this is the only settings element making a request to a third-party server with no graceful degradation |
|
||||
| N23 | RoomServerACL | `RoomServerACL.tsx` | 100–115 / 298–309 | Server-name text input is a raw `<input type="text">` with inline style object; "Allow IP literal addresses" is a raw `<input type="checkbox">` with `style={{ width: 16, height: 16 }}` — **FIXED**: text input → folds `<Input variant={error?'Critical':'Secondary'}>`; checkbox → folds `<Checkbox variant="Primary">` | All other text/boolean controls in room settings use folds `Input` and `Checkbox` components (`RoomAddress.tsx:163`, `RoomAddress.tsx:330`) |
|
||||
| N24 | PolicyListViewer | `PolicyListViewer.tsx` | 245–264 | Room-ID add input is a raw `<input type="text">` with manually replicated folds token values — **FIXED**: replaced with folds `<Input variant={error?'Critical':'Secondary'} size="400" radii="300">` | Native pattern: folds `<Input variant="Secondary" size="300" radii="300">` — no inline style needed |
|
||||
| N25 | ExportRoomHistory Inputs | `ExportRoomHistory.tsx` | 258–292 | Both date range pickers are raw `<input type="date">` with inline styles — **FIXED**: replaced with folds `<Input type="date" variant="Secondary" size="400" radii="300">` | Native pattern: folds `Input` component; `<input type="date">` renders OS-native date picker, unstyled relative to the rest of the settings panel |
|
||||
| N26 | RoomShareInvite QR | `RoomShareInvite.tsx` | 66–73 | QR code `<img>` has no `onError` handler and no loading state — broken-image placeholder shown when the external API is unreachable — **FIXED**: added `loading="lazy"` + `onError` that swaps to a folds "QR code unavailable" placeholder card | Cinny avatar components and MediaGallery use `onError` handlers; this is the only settings element making a request to a third-party server with no graceful degradation |
|
||||
|
||||
---
|
||||
|
||||
@@ -338,7 +338,7 @@ This document tracks identified bugs, edge cases, and architectural discrepancie
|
||||
|
||||
| # | Area | File | Lines | Issue | Native Pattern |
|
||||
| :------ | :--------------------------------- | :------------------------------------- | :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| N27 | GIF Picker | `GifPicker.tsx` | 103–110 | `FocusTrap` omits `returnFocusOnDeactivate: false` — focus returns to GIF button on dismiss instead of staying in the editor | `EmojiBoard` in `RoomInput.tsx:978` explicitly sets `returnFocusOnDeactivate={false}`; GIF picker dismiss behaviour is inconsistent with emoji picker |
|
||||
| N27 | GIF Picker | `GifPicker.tsx` | 103–110 | `FocusTrap` omits `returnFocusOnDeactivate: false` — focus returns to GIF button on dismiss instead of staying in the editor — **FIXED**: added `returnFocusOnDeactivate: false` (matches EmojiBoard) | `EmojiBoard` in `RoomInput.tsx:978` explicitly sets `returnFocusOnDeactivate={false}`; GIF picker dismiss behaviour is inconsistent with emoji picker |
|
||||
| N28 | Character Counter | `RoomInput.tsx` | 1159–1174 | Composer character counter rendered with `color: 'var(--tc-surface-low)'` and raw pixel padding — a CSS variable not used anywhere else in the codebase — **FIXED**: removed undefined var and raw opacity; now `<Text priority="300">` with `config.space.S100` padding | Use `color.*` folds tokens or `priority="300"` on a `Text` component |
|
||||
| N29 | PollCreator Modal | `PollCreator.tsx` | 103–116 | Modal root is `<Box as="form" role="dialog" aria-modal="true">` with manually assembled surface styles instead of folds `<Dialog variant="Surface">` | `MessageDeleteItem` and `MessageReportItem` in `Message.tsx:506,635` use `<Dialog variant="Surface">` inside `OverlayCenter > FocusTrap` |
|
||||
| N30 | Playback Speed Chip | `AudioContent.tsx` | 163–189 | Speed chip uses `variant="SurfaceVariant" radii="Pill"` while adjacent Play/Pause chip uses `variant="Secondary" radii="300"` — mismatched shape and variant within the same `leftControl` row — **FIXED**: changed speed chip to `variant="Secondary" radii="300"` | Controls grouped in the same row should share variant and radii |
|
||||
@@ -433,7 +433,7 @@ This document tracks identified bugs, edge cases, and architectural discrepancie
|
||||
| N73 | Pending Requests Header | `MembersDrawer.tsx` | 415–422 | "Pending Requests" section header is bare `<Text>` with inline padding instead of `className={css.MembersGroupLabel}` — **FIXED**: now uses `className={css.MembersGroupLabel}` like every other section header | Power-level group labels at lines 506–519 use `className={css.MembersGroupLabel}` for all other section headers in the same virtualizer list |
|
||||
| N74 | Emoji Prefix Span | `RoomNavItem.tsx` | 730–736 | Emoji prefix rendered as raw `<span style={{ fontSize: '1.15em', lineHeight: 1 }}>` inside a `<Text>` node — **FIXED**: removed the emoji-splitting span; the room name (including any leading emoji) now renders directly inside `<Text>` | All other nav item text uses folds `<Text size="Inherit">` or similar — no raw `<span>` with em-based font-size override exists elsewhere in the sidebar |
|
||||
| N75 | Room Name Override / Star Indicators | `RoomNavItem.tsx` | 741–757 | Pencil and star indicator icons are embedded inside the name `<Box as="span">`, giving them the same visual baseline as the room name text — **WON'T FIX (deliberate)**: an inline favorite-star / local-name marker adjacent to the name is a deliberate, common design (cf. Element/Slack pinned-name markers). Moving them to the far right would collide with the unread/notification indicators already there and risks layout regressions. Low value, real regression risk. | Native sidebar status indicators (unread count, notification mode icon) are placed to the far right of the item, never inside the name text span group |
|
||||
| N76 | Report Modals — Extra Cancel Button | `ReportRoomModal.tsx` / `ReportUserModal.tsx` | 189–191 / 195–197 | Both custom report modals include a "Cancel" `<Button>` in the footer row | Native `MessageReportItem` (`Message.tsx:675–691`) has no Cancel button — dismissal is via `×` header button or click-outside only |
|
||||
| N76 | Report Modals — Extra Cancel Button | `ReportRoomModal.tsx` / `ReportUserModal.tsx` | 189–191 / 195–197 | Both custom report modals include a "Cancel" `<Button>` in the footer row — **FIXED**: removed the Cancel button; dismissal is via the header `×` / click-outside, matching `MessageReportItem` | Native `MessageReportItem` (`Message.tsx:675–691`) has no Cancel button — dismissal is via `×` header button or click-outside only |
|
||||
| N77 | Search Filter Inline Lambdas | `SearchFilters.tsx` | 480, 625 | `SelectSenderButton` and `DateRangeButton` trigger chips use inline `onClick` arrow functions — **WON'T FIX (deliberate)**: purely a code-style nit with zero user-facing or behavioural impact. Inline arrow handlers are idiomatic React and used throughout this very file; extracting them yields no functional benefit. | `OrderButton` (line 58) and `SelectRoomButton` (line 195) both extract a named `const handleOpenMenu: MouseEventHandler<HTMLButtonElement>` handler — bypassing the type annotation in the inline form |
|
||||
| N78 | HasLink Chip Active Color | `SearchFilters.tsx` | 755 | `HasLink` active state uses `variant="Primary"` (blue); all boolean scope-toggle chips in the same bar use `variant="Success"` (green) with `outlined` — **FIXED**: changed to `variant={containsUrl ? 'Success' : 'SurfaceVariant'} outlined={!!containsUrl}` | `variant="Success" outlined` is the established active-state pattern for boolean toggles in the filter bar |
|
||||
| N79 | Server Notice Chip Radii | `RoomViewHeader.tsx` | 570 | `<Chip size="400" radii="Pill">` — `Pill` radii on a room-type label — **FIXED**: changed to `radii="300"` | Room/space type labels in lobby (`RoomItem.tsx:83`, `SpaceItem.tsx:63`) use `radii="300"`; `radii="Pill"` is for filter/tag chips only |
|
||||
|
||||
@@ -103,6 +103,7 @@ export function GifPicker({ apiKey, onSelect, requestClose }: GifPickerProps) {
|
||||
<FocusTrap
|
||||
focusTrapOptions={{
|
||||
initialFocus: false,
|
||||
returnFocusOnDeactivate: false,
|
||||
onDeactivate: requestClose,
|
||||
clickOutsideDeactivates: true,
|
||||
allowOutsideClick: true,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { config } from 'folds';
|
||||
|
||||
// Hover/focus emphasis driven by CSS rather than JS style mutation, matching
|
||||
// how every other interactive element in the app handles hover state.
|
||||
export const ReceiptTrigger = style({
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
padding: 0,
|
||||
marginLeft: 'auto',
|
||||
marginTop: config.space.S100,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: config.space.S100,
|
||||
opacity: config.opacity.P500,
|
||||
transition: 'opacity 150ms ease-in-out, transform 150ms ease-in-out',
|
||||
selectors: {
|
||||
'&:hover, &:focus-visible': {
|
||||
opacity: 1,
|
||||
transform: 'scale(1.04)',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -23,6 +23,7 @@ import { StackedAvatar } from '../stacked-avatar';
|
||||
import { EventReaders } from '../event-readers';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { useModalStyle } from '../../hooks/useModalStyle';
|
||||
import * as css from './ReadReceiptAvatars.css';
|
||||
|
||||
const MAX_DISPLAY = 5;
|
||||
|
||||
@@ -74,27 +75,7 @@ export function ReadReceiptAvatars({
|
||||
onClick={() => setOpen(true)}
|
||||
title={tooltipNames}
|
||||
aria-label={tooltipNames}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
padding: 0,
|
||||
marginLeft: 'auto',
|
||||
marginTop: '4px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '4px',
|
||||
opacity: 0.85,
|
||||
transition: 'opacity 0.15s, transform 0.15s',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.opacity = '1';
|
||||
e.currentTarget.style.transform = 'scale(1.04)';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.opacity = '0.85';
|
||||
e.currentTarget.style.transform = 'scale(1)';
|
||||
}}
|
||||
className={css.ReceiptTrigger}
|
||||
>
|
||||
{/* Pill wrapper ensures visibility on any wallpaper/background */}
|
||||
<span
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { Box, Button, config, Icon, Icons, Text } from 'folds';
|
||||
import { Box, Button, color, config, Icon, Icons, Text } from 'folds';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
||||
import { SettingTile } from '../../../components/setting-tile';
|
||||
@@ -12,6 +12,7 @@ export function RoomShareInvite() {
|
||||
const mx = useMatrixClient();
|
||||
const room = useRoom();
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [qrError, setQrError] = useState(false);
|
||||
|
||||
const domain = mx.getDomain() ?? undefined;
|
||||
const inviteUrl = getMatrixToRoom(room.roomId, domain ? [domain] : undefined);
|
||||
@@ -63,13 +64,35 @@ export function RoomShareInvite() {
|
||||
</Box>
|
||||
</Box>
|
||||
<Box justifyContent="Center">
|
||||
<img
|
||||
src={qrSrc}
|
||||
alt="QR code for room invite link"
|
||||
width={160}
|
||||
height={160}
|
||||
style={{ display: 'block', borderRadius: config.radii.R300 }}
|
||||
/>
|
||||
{qrError ? (
|
||||
<Box
|
||||
direction="Column"
|
||||
alignItems="Center"
|
||||
justifyContent="Center"
|
||||
gap="100"
|
||||
style={{
|
||||
width: 160,
|
||||
height: 160,
|
||||
borderRadius: config.radii.R300,
|
||||
background: color.SurfaceVariant.Container,
|
||||
}}
|
||||
>
|
||||
<Icon size="400" src={Icons.Warning} />
|
||||
<Text size="T200" priority="300" align="Center">
|
||||
QR code unavailable
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<img
|
||||
src={qrSrc}
|
||||
alt="QR code for room invite link"
|
||||
width={160}
|
||||
height={160}
|
||||
loading="lazy"
|
||||
onError={() => setQrError(true)}
|
||||
style={{ display: 'block', borderRadius: config.radii.R300 }}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</CutoutCard>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { Box, Button, Icon, IconButton, Icons, Scroll, Spinner, Text, config, color } from 'folds';
|
||||
import { Box, Button, Icon, IconButton, Icons, Input, Scroll, Spinner, Text } from 'folds';
|
||||
import { EventType } from 'matrix-js-sdk';
|
||||
import { Page, PageContent, PageHeader } from '../../components/page';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
@@ -255,40 +255,24 @@ ${msgRows}
|
||||
<Box gap="400" wrap="Wrap">
|
||||
<Box direction="Column" gap="100" style={{ flex: 1, minWidth: 160 }}>
|
||||
<Text size="T300">From</Text>
|
||||
<input
|
||||
<Input
|
||||
type="date"
|
||||
variant="Secondary"
|
||||
size="400"
|
||||
radii="300"
|
||||
value={fromDate}
|
||||
onChange={(e) => setFromDate(e.target.value)}
|
||||
style={{
|
||||
background: color.Surface.Container,
|
||||
color: color.Surface.OnContainer,
|
||||
border: `1px solid ${color.Surface.ContainerLine}`,
|
||||
borderRadius: config.radii.R300,
|
||||
padding: `${config.space.S200} ${config.space.S300}`,
|
||||
fontSize: 'inherit',
|
||||
fontFamily: 'inherit',
|
||||
width: '100%',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box direction="Column" gap="100" style={{ flex: 1, minWidth: 160 }}>
|
||||
<Text size="T300">To</Text>
|
||||
<input
|
||||
<Input
|
||||
type="date"
|
||||
variant="Secondary"
|
||||
size="400"
|
||||
radii="300"
|
||||
value={toDate}
|
||||
onChange={(e) => setToDate(e.target.value)}
|
||||
style={{
|
||||
background: color.Surface.Container,
|
||||
color: color.Surface.OnContainer,
|
||||
border: `1px solid ${color.Surface.ContainerLine}`,
|
||||
borderRadius: config.radii.R300,
|
||||
padding: `${config.space.S200} ${config.space.S300}`,
|
||||
fontSize: 'inherit',
|
||||
fontFamily: 'inherit',
|
||||
width: '100%',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import { Badge, Box, Button, Icon, IconButton, Icons, Scroll, Text, color, config } from 'folds';
|
||||
import {
|
||||
Badge,
|
||||
Box,
|
||||
Button,
|
||||
Icon,
|
||||
IconButton,
|
||||
Icons,
|
||||
Input,
|
||||
Scroll,
|
||||
Text,
|
||||
color,
|
||||
config,
|
||||
} from 'folds';
|
||||
import { EventTimeline, MatrixEvent, Room } from 'matrix-js-sdk';
|
||||
import { Page, PageContent, PageHeader } from '../../components/page';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
@@ -242,7 +254,7 @@ export function PolicyListViewer({ requestClose }: PolicyListViewerProps) {
|
||||
gap="300"
|
||||
>
|
||||
<Box gap="200" alignItems="Center">
|
||||
<input
|
||||
<Input
|
||||
ref={inputRef}
|
||||
value={roomIdInput}
|
||||
onChange={(e) => setRoomIdInput(e.target.value)}
|
||||
@@ -250,17 +262,10 @@ export function PolicyListViewer({ requestClose }: PolicyListViewerProps) {
|
||||
if (e.key === 'Enter') handleLoad();
|
||||
}}
|
||||
placeholder="!roomId:server or #alias:server"
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
padding: `${config.space.S200} ${config.space.S300}`,
|
||||
borderRadius: config.radii.R300,
|
||||
border: `1px solid ${error ? color.Critical.Main : color.Surface.ContainerLine}`,
|
||||
background: color.Surface.Container,
|
||||
color: color.Surface.OnContainer,
|
||||
fontSize: 'inherit',
|
||||
fontFamily: 'inherit',
|
||||
outline: 'none',
|
||||
}}
|
||||
variant={error ? 'Critical' : 'Secondary'}
|
||||
size="400"
|
||||
radii="300"
|
||||
style={{ flexGrow: 1 }}
|
||||
/>
|
||||
<Button
|
||||
onClick={handleLoad}
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import { Box, Button, Icon, IconButton, Icons, Scroll, Spinner, Text, color, config } from 'folds';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Icon,
|
||||
IconButton,
|
||||
Icons,
|
||||
Input,
|
||||
Scroll,
|
||||
Spinner,
|
||||
Text,
|
||||
color,
|
||||
config,
|
||||
} from 'folds';
|
||||
import { Page, PageContent, PageHeader } from '../../components/page';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useRoom } from '../../hooks/useRoom';
|
||||
@@ -97,22 +110,14 @@ function ServerList({ label, entries, canEdit, onAdd, onRemove }: ServerListProp
|
||||
|
||||
{canEdit && (
|
||||
<Box direction="Column" gap="100">
|
||||
<input
|
||||
<Input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
placeholder="e.g. *.example.com or badserver.org"
|
||||
onKeyDown={handleKeyDown}
|
||||
style={{
|
||||
background: color.Surface.Container,
|
||||
color: color.Surface.OnContainer,
|
||||
border: `1px solid ${error ? color.Critical.Main : color.Surface.ContainerLine}`,
|
||||
borderRadius: config.radii.R300,
|
||||
padding: `${config.space.S200} ${config.space.S300}`,
|
||||
fontSize: 'inherit',
|
||||
fontFamily: 'inherit',
|
||||
width: '100%',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
variant={error ? 'Critical' : 'Secondary'}
|
||||
size="400"
|
||||
radii="300"
|
||||
/>
|
||||
{error && (
|
||||
<Text size="T200" style={{ color: color.Critical.Main }}>
|
||||
@@ -295,18 +300,13 @@ export function RoomServerACL({ requestClose }: RoomServerACLProps) {
|
||||
gap="200"
|
||||
>
|
||||
<Box alignItems="Center" gap="300">
|
||||
<input
|
||||
type="checkbox"
|
||||
<Checkbox
|
||||
id="allow-ip-literals"
|
||||
checked={allowIpLiterals}
|
||||
disabled={!canEdit}
|
||||
onChange={(e) => setAllowIpLiterals(e.target.checked)}
|
||||
style={{
|
||||
width: 16,
|
||||
height: 16,
|
||||
flexShrink: 0,
|
||||
cursor: canEdit ? 'pointer' : 'default',
|
||||
}}
|
||||
onClick={() => setAllowIpLiterals(!allowIpLiterals)}
|
||||
size="300"
|
||||
variant="Primary"
|
||||
/>
|
||||
<Box direction="Column" gap="0">
|
||||
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
||||
|
||||
@@ -186,9 +186,6 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
|
||||
</Box>
|
||||
|
||||
<Box gap="200" justifyContent="End">
|
||||
<Button type="button" variant="Secondary" fill="None" radii="300" onClick={onClose}>
|
||||
<Text size="B400">Cancel</Text>
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="Critical"
|
||||
|
||||
@@ -192,9 +192,6 @@ export function ReportUserModal({ userId, onClose }: ReportUserModalProps) {
|
||||
</Box>
|
||||
|
||||
<Box gap="200" justifyContent="End">
|
||||
<Button type="button" variant="Secondary" fill="None" radii="300" onClick={onClose}>
|
||||
<Text size="B400">Cancel</Text>
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="Critical"
|
||||
|
||||
Reference in New Issue
Block a user