/** @jsxImportSource react */ import { useMemo, useRef, useState, type CSSProperties, type KeyboardEvent, type RefObject } from "react"; import { Box, Input, Text, Textarea, editableTextContextMenuItems, useRendererHost, useUiCapabilities } from "../../../../ui"; import { TextAttributes, type InputRenderable } from "../../../../ui"; import { useShortcut } from "../../../../react/input"; import { blendHex, type ThemeColors } from "../../../../theme/colors"; import { contrastRatio } from "../../../../theme/color-utils"; import { useThemeColors } from "../../../../theme/theme-context"; import { isDetailBackNavigationKey } from "../../../../utils/back-navigation"; import { WEB_CELL_HEIGHT, WEB_CELL_WIDTH } from "../../../../theme/font-scale"; import type { ButtonProps } from "../../../../components/ui/button"; import type { CheckboxProps } from "../../../../components/ui/checkbox"; import type { TextFieldProps } from "../../../../components/ui/fields"; import type { DialogFrameProps } from "../../../../components/ui/frame"; import type { MessageComposerProps } from "../../../../components/ui/message-composer"; import type { PageStackViewProps } from "../../../../components/ui/page-stack-view"; import { StackHeaderContext, type StackHeaderSlot } from "./stack-header"; import { releasePointerFocus } from "../host/focus-scope"; import { WebIcon, WebIconButton } from "./icons"; import { NestedPaneTabs } from "../../../../components/layout/pane/header-tabs"; import type { SegmentedControlProps } from "../../../../components/ui/toggle"; import { CONTROL_RADIUS, buttonPalette, controlBorderColor, controlShadow, panelBorder, panelFill, } from "./control-styles"; export { WebListView } from "./list-view"; export function WebButton({ label, displayLabel, children, expanded, onPress, variant = "secondary", disabled = false, active = false, shortcut, width, height, compact = false, flush = false, stopPropagation = false, title, }: ButtonProps) { const colors = useThemeColors(); const palette = buttonPalette({ variant, active, disabled }, colors); return ( ); } function checkboxAccentColor(colors: ThemeColors): string { const base = colors.borderFocused; const nativeCheckmark = "#ffffff"; const candidates = [ blendHex(base, colors.selected, 0.55), blendHex(base, colors.selected, 0.65), blendHex(base, "#000000", 0.45), blendHex(base, "#000000", 0.52), base, ]; return candidates.find((candidate) => ( contrastRatio(candidate, nativeCheckmark) >= 4.5 && contrastRatio(candidate, colors.panel) >= 2.2 )) ?? candidates[1]!; } function checkboxCheckImage(): string { const svg = ``; return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`; } /** * The one checkbox square on the desktop: the kit Checkbox, query-bar toggles * and multi-select menu items all draw it through this style. */ export function checkboxBoxStyle( colors: ThemeColors, { checked, active = false, size = 14 }: { checked: boolean; active?: boolean; size?: number }, ): CSSProperties { const accentColor = checkboxAccentColor(colors); return { appearance: "none", WebkitAppearance: "none", display: "inline-block", width: size, height: size, margin: 0, backgroundColor: checked ? accentColor : panelFill(colors), backgroundImage: checked ? checkboxCheckImage() : undefined, backgroundPosition: "center", backgroundRepeat: "no-repeat", backgroundSize: `${size - 2}px ${size - 2}px`, border: `1px solid ${checked ? accentColor : controlBorderColor(active, false, colors)}`, borderRadius: size >= 14 ? 4 : 3, boxShadow: active ? `0 0 0 2px ${blendHex(colors.bg, colors.borderFocused, 0.28)}, inset 0 1px 0 rgba(255,255,255,0.16)` : "inset 0 1px 0 rgba(255,255,255,0.10)", boxSizing: "border-box", flexShrink: 0, verticalAlign: "middle", }; } /** A checkbox square for a control that owns its own click (a menu row, a bar toggle). */ export function CheckboxBox({ checked, size = 12 }: { checked: boolean; size?: number }) { const colors = useThemeColors(); return