@flytedan/flytebot-design-system 0.55.3 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1269,6 +1269,13 @@ interface FilterFieldMultiSelect extends FilterFieldBase {
1269
1269
  * empty token list, and tokens are de-duplicated before the call. */
1270
1270
  resolve?: (tokens: string[]) => Promise<FilterResolveResult>;
1271
1271
  placeholder?: string;
1272
+ /** What the panel says when the field has nothing to pick at all: its option list
1273
+ * (`options`, or what `loadOptions` returns for the empty query) is empty and nothing
1274
+ * has been typed, e.g. "No contact lists yet." It replaces the generic "No matches",
1275
+ * which would wrongly suggest a search came up short. The field stays in the Filter
1276
+ * menu and the text is announced through the panel's status region. Once the user types
1277
+ * and nothing matches, "No matches" still shows. Omit it for the generic text. */
1278
+ emptyText?: string;
1272
1279
  /** Placeholder for the paste textarea, when `resolve` is given. Falls back to `placeholder`. */
1273
1280
  pastePlaceholder?: string;
1274
1281
  /** Restrict which operators this field's toggle offers, e.g. `["in"]` for a dimension
@@ -1798,14 +1805,24 @@ interface SortMenuField {
1798
1805
  /** Numeric fields read "lowest/highest first" instead of "A to Z". */
1799
1806
  numeric?: boolean;
1800
1807
  }
1801
- interface SortMenuProps extends React.HTMLAttributes<HTMLSpanElement> {
1808
+ type SortDirection = "asc" | "desc";
1809
+ /** One sort key and its direction. A sort is an ordered list of these, most significant first. */
1810
+ interface SortEntry {
1811
+ key: string;
1812
+ dir: SortDirection;
1813
+ }
1814
+ interface SortMenuProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "onChange"> {
1802
1815
  fields: SortMenuField[];
1803
- /** Current sort, straight from the endpoint's response envelope. */
1804
- sort?: {
1805
- key: string;
1806
- dir: "asc" | "desc";
1807
- } | null;
1808
- onSort?: (key: string, dir: "asc" | "desc") => void;
1816
+ /** The current sort, most significant key first, straight from the endpoint's response
1817
+ * envelope. Empty (the default) reads "Unsorted". A single-key sort is a list of one. */
1818
+ sort?: SortEntry[];
1819
+ /** Called with the complete new sort whenever the user changes it. The menu never holds
1820
+ * the list itself: the host applies this, and `sort` comes back. */
1821
+ onSortChange?: (sort: SortEntry[]) => void;
1822
+ /** Sort by several keys at once: the panel lists the active keys in order, each with a
1823
+ * direction flip, move earlier/later and remove, and every unused field offers an add.
1824
+ * Off (the default), the sort is one key: choosing a direction on a field replaces it. */
1825
+ multiple?: boolean;
1809
1826
  /** Which edge the popover aligns to. Default "right". */
1810
1827
  align?: "left" | "right";
1811
1828
  /** Trigger button height, same scale as every other control in the kit (Button,
@@ -1828,10 +1845,14 @@ interface SortMenuProps extends React.HTMLAttributes<HTMLSpanElement> {
1828
1845
  * text fields "A to Z" — while both use the same arrow pair, because varying the icon by
1829
1846
  * type encodes a distinction nobody asked for and reads as inconsistency.
1830
1847
  *
1831
- * Purely presentational: reports intent through onSort(key, dir) and never holds sort
1848
+ * The sort is an ordered list of keys. By default it holds one; with `multiple` the user
1849
+ * builds a list (first key wins, later keys break its ties) and can flip, reorder and
1850
+ * remove each entry.
1851
+ *
1852
+ * Purely presentational: reports intent through onSortChange(list) and never holds sort
1832
1853
  * state, so it stays honest against a real endpoint.
1833
1854
  */
1834
- declare function SortMenu({ fields, sort, onSort, align, size, className, ...rest }: SortMenuProps): React.JSX.Element;
1855
+ declare function SortMenu({ fields, sort, onSortChange, multiple, align, size, className, ...rest }: SortMenuProps): React.JSX.Element;
1835
1856
 
1836
1857
  interface Step {
1837
1858
  id: string;
@@ -5055,4 +5076,4 @@ declare function CornerStackPortal({ slot, children }: {
5055
5076
  children?: React.ReactNode;
5056
5077
  }): React.ReactPortal | null;
5057
5078
 
5058
- export { AccountMenu, type AccountMenuLink, type AccountMenuProps, AgentChatPanel, type AgentChatPanelProps, AnchoredPopover, type AnchoredPopoverProps, AnimNum, type AnimNumProps, ApiSpecBrowser, type ApiSpecBrowserProps, type AppEntry, AppShell, type AppShellProps, AppSwitcher, type AppSwitcherProps, AppearanceMenu, type AppearanceMenuProps, type AppearancePrefs, type AppearanceStore, type AppearanceStoreOptions, type Attachment, Avatar, type AvatarProps, AvatarStack, type AvatarStackProps, Badge, type BadgeProps, Banner, type BannerProps, type BannerTone, BarList, type BarListProps, type BarListRow, BudgetReallocator, type BudgetReallocatorProps, Button, type ButtonProps, CHANNELS, CHANNEL_WEIGHTS, CHAT_UNAVAILABLE, COPIED_FEEDBACK_MS, Calendar, type CalendarProps, Card, CardGrid, type CardGridProps, type CardProps, CardRow, type CardRowProps, ChannelContribution, type ChannelContributionChannel, type ChannelContributionProps, ChannelMeta, type ChannelMetaRecord, ChannelTag, type ChannelTagProps, ChannelWeightOf, type ChatAdapter, ChatComposer, type ChatComposerProps, type ChatEngine, type ChatEngineOptions, ChatKit, type ChatMessage, type ChatRenderContext, ChatSessionBar, type ChatSessionBarProps, ChatTranscript, type ChatTranscriptProps, ChatTurn, type ChatTurnProps, Checkbox, type CheckboxProps, type Citation, Citations, type CitationsProps, Clamp, type ClampProps, ClockFace, type ClockFaceProps, CodeBlock, type CodeBlockProps, CodeEditor, type CodeEditorDiagnostic, type CodeEditorProps, Collapsible, type CollapsibleProps, ComingSoon, type ComingSoonProps, type ContextUsage, CornerStackPortal, type CornerStackSlot, type CreateVersionStoreOptions, CsiBadge, type CsiBadgeProps, CsiHero, type CsiHeroProps, CsiMeter, type CsiMeterProps, DEFAULT_PREFS, DEFAULT_STORAGE_KEY, DEFAULT_TOAST_DURATION_MS, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, type DemoSessionControls, DemoSessionProvider, type DeviceSession, DiffBlock, type DiffBlockProps, DonutChart, type DonutChartProps, type DonutSegment, Drawer, type DrawerProps, Dropzone, DropzoneKit, type DropzoneProps, ENTITY_ROW_METRIC_WIDTH, type EditorTrigger, EmptyState, type EmptyStateProps, type EndpointSpec, EntityRow, type EntityRowAction, type EntityRowContent, type EntityRowMetric, EntityRowMetrics, type EntityRowMetricsProps, type EntityRowProps, FILE_VIEWER_CSV_ROW_LIMIT, FILE_VIEWER_TEXT_LIMIT, FeatureGate, type FeatureGateProps, type FeatureStatus, FileBrowser, type FileBrowserFile, type FileBrowserFolder, type FileBrowserPermissions, type FileBrowserProps, FileChip, type FileChipProps, FileGrid, type FileGridProps, FileKit, FilePickButton, type FilePickButtonProps, type FileRejection, FileStrip, type FileStripProps, FileTile, type FileTileProps, type FileUploadHandler, FileViewer, type FileViewerProps, FilterBar, type FilterBarProps, type FilterDateValue, type FilterField, type FilterFieldDate, type FilterFieldMultiSelect, type FilterFieldOption, type FilterFieldRange, type FilterFieldSelect, type FilterFieldText, type FilterMultiSelectValue, type FilterOperator, type FilterRangeValue, type FilterResolveMatch, type FilterResolveResult, type FilterValidation, type FilterValue, Flag$1 as Flag, type FlagExplanation, type FlagProps, FlytedeskBrand, type FlytedeskBrandProps, FlytedeskMark, type FlytedeskMarkProps, FormatEta, FunnelChart, type FunnelChartProps, type FunnelStep, Gate, GatePending, type GatePendingProps, type GateProps, IMPORTANCE_LEVELS, IconButton, type IconButtonProps, type ImportanceLevel, type ImportanceLevelId, ImportanceTag, type ImportanceTagProps, type ImportanceTokens, Input, type InputProps, type Job, type JobAction, type JobCardStatus, type JobStatus, JobTray, type JobTrayProps, Json, KeyHint, type KeyHintProps, LAYER_STEP, type ListEnvelope, LoadingRegion, type LoadingRegionProps, Markdown, MarkdownEditor, type MarkdownEditorHandle, type MarkdownEditorProps, MarkdownInline, type MarkdownProps, type MentionSource, Menu, MenuButton, type MenuButtonProps, type MenuItem, type MenuProps, MessageBody, type MessageBodyProps, type MessageGroup, Meter, type MeterProps, type MeterSegment, type MeterSegmentInput, MixGap, type MixGapProps, type MixGapRow, MockJobKit, type MockJobStatus, Modal, type ModalProps, ModeSwitch, type ModeSwitchProps, type Model, ModelControls, type ModelControlsProps, NumberInput, type NumberInputProps, OVERLAY_CEILING, POPOVER_BODY_MIN, type Packet, PacketCard, type PacketCardProps, type PacketSchema, type Pager, Pagination, type PaginationProps, PermissionDenied, type PermissionDeniedProps, type PermissionGroup, PermissionHint, type PermissionItem, type Phase, type PhaseStatus, PhasedProgress, type PhasedProgressProps, type Placement, type PollOptions, Popover, type PopoverProps, type PreferenceCriterion, PreferenceMeter, type PreferenceMeterProps, type ProfileFieldDef, type ProfileFieldType, type ProfileNotificationDef, ProfilePage, type ProfilePageProps, ProgressBar, type ProgressBarProps, QueryKit, type QueuedTurn, QuotaRow, type QuotaRowProps, ROOT_STEP, Radio, type RadioProps, RangeSlider, type RangeSliderProps, RelativeTime, type RelativeTimeProps, type RoadmapItem, type RoadmapResult, RoadmapTimeline, type RoadmapTimelineProps, type Role, RunActions, type RunActionsProps, type RunConfig, RuntimeKit, type RuntimeSummary, SaturationDistribution, type SaturationDistributionCampus, type SaturationDistributionProps, ScoreMeter, type ScoreMeterProps, ScreenHead, type ScreenHeadProps, SearchField, type SearchFieldProps, SegmentedControl, type SegmentedControlProps, SegmentedMeter, type SegmentedMeterProps, Select, type SelectOption, type SelectProps, type SendMessageResult, type ServerTable, type Session, type SessionContextValue, type Flag as SessionFlag, SessionKit, SessionProvider, type SessionProviderProps, type SessionRole, SessionScreen, type SessionScreenKind, type SessionScreenProps, type SessionStats, type SessionUser, SidebarNav, type SidebarNavItem, type SidebarNavProps, Skeleton, type SkeletonProps, SkeletonText, type SkeletonTextProps, type SlashCommand, Slider, type SliderProps, SortMenu, type SortMenuField, type SortMenuProps, type SpecModule, Spinner, type SpinnerProps, type StackedLayer, type StackedLayerOptions, StackedLayerProvider, StatTile, type StatTileProps, type Step, StepList, type StepListProps, type StreamHandlers, type Suggestion, SurroundSound, type SurroundSoundProps, Switch, type SwitchProps, type TableQuery, Tabs, type TabsProps, Tag, type TagProps, TestModeBar, type TestModeBarProps, type TextScale, Textarea, type TextareaProps, type ThemeMode, ThinkingBlock, type ThinkingBlockProps, type ThreadSummary, TimePicker, type TimePickerProps, Toast, type ToastApi, type ToastOptions, type ToastProps, ToastProvider, Tooltip, type TooltipProps, Topbar, type TopbarProps, TranscriptKit, TransferList, type TransferListProps, type TransferListSide, type TransferListSideProps, TrendChart, type TrendChartProps, type TrendSeries, type UsageLimit, UseFeatureStatus, type UseResponsiveRailOptions, type UseResponsiveRailResult, UseRuntimeMode, type UseServerTableOptions, type User, VIRTUAL_LIST_BUFFER_ROWS, VIRTUAL_LIST_ROW_GAP, type VersionRecord, type VersionStore, VirtualList, type VirtualListProps, type VirtualLoadedBand, type VirtualWindow, type VoiceHandler, __resetLayerStackForTests, acceptMatches, anyOfFilter, applyPrefs, channelWeightOf, computeNeedMore, computeVirtualWindow, copyToClipboard, createLocalStorageAppearanceStore, createVersionStore, eqFilter, extensionOf, extractClipboardFiles, filterFiles, formatAbsolute, formatBytes, formatClock, formatDocumentTitle, formatDuration, formatEta, formatRelative, groupMessages, hasModifier, iconForMime, importanceLevel, importanceTokens, installFlytedeskFavicon, isImage, isSystemMessage, isWithinLayerTree, jobBucket, languageLabel, loadPrefs, markdownToText, meterFormats, modifierLabel, parseDelimited, pastedTextName, pluralizeUnit, preferenceScore, preferenceSegments, rangeFilter, resolveTheme, revokeAttachment, savePrefs, toAttachment, tokenize, useAppearancePrefs, useChatEngine, useCopyToClipboard, useCornerStackSlot, useDocumentTitle, useFeatureStatus, useLayerZIndex, usePopoverPosition, useResponsiveRail, useRuntimeMode, useServerTable, useSessionContext, useStackedLayer, useStagedFiles, useToast, validateFilterValue, visibleMessages };
5079
+ export { AccountMenu, type AccountMenuLink, type AccountMenuProps, AgentChatPanel, type AgentChatPanelProps, AnchoredPopover, type AnchoredPopoverProps, AnimNum, type AnimNumProps, ApiSpecBrowser, type ApiSpecBrowserProps, type AppEntry, AppShell, type AppShellProps, AppSwitcher, type AppSwitcherProps, AppearanceMenu, type AppearanceMenuProps, type AppearancePrefs, type AppearanceStore, type AppearanceStoreOptions, type Attachment, Avatar, type AvatarProps, AvatarStack, type AvatarStackProps, Badge, type BadgeProps, Banner, type BannerProps, type BannerTone, BarList, type BarListProps, type BarListRow, BudgetReallocator, type BudgetReallocatorProps, Button, type ButtonProps, CHANNELS, CHANNEL_WEIGHTS, CHAT_UNAVAILABLE, COPIED_FEEDBACK_MS, Calendar, type CalendarProps, Card, CardGrid, type CardGridProps, type CardProps, CardRow, type CardRowProps, ChannelContribution, type ChannelContributionChannel, type ChannelContributionProps, ChannelMeta, type ChannelMetaRecord, ChannelTag, type ChannelTagProps, ChannelWeightOf, type ChatAdapter, ChatComposer, type ChatComposerProps, type ChatEngine, type ChatEngineOptions, ChatKit, type ChatMessage, type ChatRenderContext, ChatSessionBar, type ChatSessionBarProps, ChatTranscript, type ChatTranscriptProps, ChatTurn, type ChatTurnProps, Checkbox, type CheckboxProps, type Citation, Citations, type CitationsProps, Clamp, type ClampProps, ClockFace, type ClockFaceProps, CodeBlock, type CodeBlockProps, CodeEditor, type CodeEditorDiagnostic, type CodeEditorProps, Collapsible, type CollapsibleProps, ComingSoon, type ComingSoonProps, type ContextUsage, CornerStackPortal, type CornerStackSlot, type CreateVersionStoreOptions, CsiBadge, type CsiBadgeProps, CsiHero, type CsiHeroProps, CsiMeter, type CsiMeterProps, DEFAULT_PREFS, DEFAULT_STORAGE_KEY, DEFAULT_TOAST_DURATION_MS, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, type DemoSessionControls, DemoSessionProvider, type DeviceSession, DiffBlock, type DiffBlockProps, DonutChart, type DonutChartProps, type DonutSegment, Drawer, type DrawerProps, Dropzone, DropzoneKit, type DropzoneProps, ENTITY_ROW_METRIC_WIDTH, type EditorTrigger, EmptyState, type EmptyStateProps, type EndpointSpec, EntityRow, type EntityRowAction, type EntityRowContent, type EntityRowMetric, EntityRowMetrics, type EntityRowMetricsProps, type EntityRowProps, FILE_VIEWER_CSV_ROW_LIMIT, FILE_VIEWER_TEXT_LIMIT, FeatureGate, type FeatureGateProps, type FeatureStatus, FileBrowser, type FileBrowserFile, type FileBrowserFolder, type FileBrowserPermissions, type FileBrowserProps, FileChip, type FileChipProps, FileGrid, type FileGridProps, FileKit, FilePickButton, type FilePickButtonProps, type FileRejection, FileStrip, type FileStripProps, FileTile, type FileTileProps, type FileUploadHandler, FileViewer, type FileViewerProps, FilterBar, type FilterBarProps, type FilterDateValue, type FilterField, type FilterFieldDate, type FilterFieldMultiSelect, type FilterFieldOption, type FilterFieldRange, type FilterFieldSelect, type FilterFieldText, type FilterMultiSelectValue, type FilterOperator, type FilterRangeValue, type FilterResolveMatch, type FilterResolveResult, type FilterValidation, type FilterValue, Flag$1 as Flag, type FlagExplanation, type FlagProps, FlytedeskBrand, type FlytedeskBrandProps, FlytedeskMark, type FlytedeskMarkProps, FormatEta, FunnelChart, type FunnelChartProps, type FunnelStep, Gate, GatePending, type GatePendingProps, type GateProps, IMPORTANCE_LEVELS, IconButton, type IconButtonProps, type ImportanceLevel, type ImportanceLevelId, ImportanceTag, type ImportanceTagProps, type ImportanceTokens, Input, type InputProps, type Job, type JobAction, type JobCardStatus, type JobStatus, JobTray, type JobTrayProps, Json, KeyHint, type KeyHintProps, LAYER_STEP, type ListEnvelope, LoadingRegion, type LoadingRegionProps, Markdown, MarkdownEditor, type MarkdownEditorHandle, type MarkdownEditorProps, MarkdownInline, type MarkdownProps, type MentionSource, Menu, MenuButton, type MenuButtonProps, type MenuItem, type MenuProps, MessageBody, type MessageBodyProps, type MessageGroup, Meter, type MeterProps, type MeterSegment, type MeterSegmentInput, MixGap, type MixGapProps, type MixGapRow, MockJobKit, type MockJobStatus, Modal, type ModalProps, ModeSwitch, type ModeSwitchProps, type Model, ModelControls, type ModelControlsProps, NumberInput, type NumberInputProps, OVERLAY_CEILING, POPOVER_BODY_MIN, type Packet, PacketCard, type PacketCardProps, type PacketSchema, type Pager, Pagination, type PaginationProps, PermissionDenied, type PermissionDeniedProps, type PermissionGroup, PermissionHint, type PermissionItem, type Phase, type PhaseStatus, PhasedProgress, type PhasedProgressProps, type Placement, type PollOptions, Popover, type PopoverProps, type PreferenceCriterion, PreferenceMeter, type PreferenceMeterProps, type ProfileFieldDef, type ProfileFieldType, type ProfileNotificationDef, ProfilePage, type ProfilePageProps, ProgressBar, type ProgressBarProps, QueryKit, type QueuedTurn, QuotaRow, type QuotaRowProps, ROOT_STEP, Radio, type RadioProps, RangeSlider, type RangeSliderProps, RelativeTime, type RelativeTimeProps, type RoadmapItem, type RoadmapResult, RoadmapTimeline, type RoadmapTimelineProps, type Role, RunActions, type RunActionsProps, type RunConfig, RuntimeKit, type RuntimeSummary, SaturationDistribution, type SaturationDistributionCampus, type SaturationDistributionProps, ScoreMeter, type ScoreMeterProps, ScreenHead, type ScreenHeadProps, SearchField, type SearchFieldProps, SegmentedControl, type SegmentedControlProps, SegmentedMeter, type SegmentedMeterProps, Select, type SelectOption, type SelectProps, type SendMessageResult, type ServerTable, type Session, type SessionContextValue, type Flag as SessionFlag, SessionKit, SessionProvider, type SessionProviderProps, type SessionRole, SessionScreen, type SessionScreenKind, type SessionScreenProps, type SessionStats, type SessionUser, SidebarNav, type SidebarNavItem, type SidebarNavProps, Skeleton, type SkeletonProps, SkeletonText, type SkeletonTextProps, type SlashCommand, Slider, type SliderProps, type SortDirection, type SortEntry, SortMenu, type SortMenuField, type SortMenuProps, type SpecModule, Spinner, type SpinnerProps, type StackedLayer, type StackedLayerOptions, StackedLayerProvider, StatTile, type StatTileProps, type Step, StepList, type StepListProps, type StreamHandlers, type Suggestion, SurroundSound, type SurroundSoundProps, Switch, type SwitchProps, type TableQuery, Tabs, type TabsProps, Tag, type TagProps, TestModeBar, type TestModeBarProps, type TextScale, Textarea, type TextareaProps, type ThemeMode, ThinkingBlock, type ThinkingBlockProps, type ThreadSummary, TimePicker, type TimePickerProps, Toast, type ToastApi, type ToastOptions, type ToastProps, ToastProvider, Tooltip, type TooltipProps, Topbar, type TopbarProps, TranscriptKit, TransferList, type TransferListProps, type TransferListSide, type TransferListSideProps, TrendChart, type TrendChartProps, type TrendSeries, type UsageLimit, UseFeatureStatus, type UseResponsiveRailOptions, type UseResponsiveRailResult, UseRuntimeMode, type UseServerTableOptions, type User, VIRTUAL_LIST_BUFFER_ROWS, VIRTUAL_LIST_ROW_GAP, type VersionRecord, type VersionStore, VirtualList, type VirtualListProps, type VirtualLoadedBand, type VirtualWindow, type VoiceHandler, __resetLayerStackForTests, acceptMatches, anyOfFilter, applyPrefs, channelWeightOf, computeNeedMore, computeVirtualWindow, copyToClipboard, createLocalStorageAppearanceStore, createVersionStore, eqFilter, extensionOf, extractClipboardFiles, filterFiles, formatAbsolute, formatBytes, formatClock, formatDocumentTitle, formatDuration, formatEta, formatRelative, groupMessages, hasModifier, iconForMime, importanceLevel, importanceTokens, installFlytedeskFavicon, isImage, isSystemMessage, isWithinLayerTree, jobBucket, languageLabel, loadPrefs, markdownToText, meterFormats, modifierLabel, parseDelimited, pastedTextName, pluralizeUnit, preferenceScore, preferenceSegments, rangeFilter, resolveTheme, revokeAttachment, savePrefs, toAttachment, tokenize, useAppearancePrefs, useChatEngine, useCopyToClipboard, useCornerStackSlot, useDocumentTitle, useFeatureStatus, useLayerZIndex, usePopoverPosition, useResponsiveRail, useRuntimeMode, useServerTable, useSessionContext, useStackedLayer, useStagedFiles, useToast, validateFilterValue, visibleMessages };
package/dist/index.d.ts CHANGED
@@ -1269,6 +1269,13 @@ interface FilterFieldMultiSelect extends FilterFieldBase {
1269
1269
  * empty token list, and tokens are de-duplicated before the call. */
1270
1270
  resolve?: (tokens: string[]) => Promise<FilterResolveResult>;
1271
1271
  placeholder?: string;
1272
+ /** What the panel says when the field has nothing to pick at all: its option list
1273
+ * (`options`, or what `loadOptions` returns for the empty query) is empty and nothing
1274
+ * has been typed, e.g. "No contact lists yet." It replaces the generic "No matches",
1275
+ * which would wrongly suggest a search came up short. The field stays in the Filter
1276
+ * menu and the text is announced through the panel's status region. Once the user types
1277
+ * and nothing matches, "No matches" still shows. Omit it for the generic text. */
1278
+ emptyText?: string;
1272
1279
  /** Placeholder for the paste textarea, when `resolve` is given. Falls back to `placeholder`. */
1273
1280
  pastePlaceholder?: string;
1274
1281
  /** Restrict which operators this field's toggle offers, e.g. `["in"]` for a dimension
@@ -1798,14 +1805,24 @@ interface SortMenuField {
1798
1805
  /** Numeric fields read "lowest/highest first" instead of "A to Z". */
1799
1806
  numeric?: boolean;
1800
1807
  }
1801
- interface SortMenuProps extends React.HTMLAttributes<HTMLSpanElement> {
1808
+ type SortDirection = "asc" | "desc";
1809
+ /** One sort key and its direction. A sort is an ordered list of these, most significant first. */
1810
+ interface SortEntry {
1811
+ key: string;
1812
+ dir: SortDirection;
1813
+ }
1814
+ interface SortMenuProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "onChange"> {
1802
1815
  fields: SortMenuField[];
1803
- /** Current sort, straight from the endpoint's response envelope. */
1804
- sort?: {
1805
- key: string;
1806
- dir: "asc" | "desc";
1807
- } | null;
1808
- onSort?: (key: string, dir: "asc" | "desc") => void;
1816
+ /** The current sort, most significant key first, straight from the endpoint's response
1817
+ * envelope. Empty (the default) reads "Unsorted". A single-key sort is a list of one. */
1818
+ sort?: SortEntry[];
1819
+ /** Called with the complete new sort whenever the user changes it. The menu never holds
1820
+ * the list itself: the host applies this, and `sort` comes back. */
1821
+ onSortChange?: (sort: SortEntry[]) => void;
1822
+ /** Sort by several keys at once: the panel lists the active keys in order, each with a
1823
+ * direction flip, move earlier/later and remove, and every unused field offers an add.
1824
+ * Off (the default), the sort is one key: choosing a direction on a field replaces it. */
1825
+ multiple?: boolean;
1809
1826
  /** Which edge the popover aligns to. Default "right". */
1810
1827
  align?: "left" | "right";
1811
1828
  /** Trigger button height, same scale as every other control in the kit (Button,
@@ -1828,10 +1845,14 @@ interface SortMenuProps extends React.HTMLAttributes<HTMLSpanElement> {
1828
1845
  * text fields "A to Z" — while both use the same arrow pair, because varying the icon by
1829
1846
  * type encodes a distinction nobody asked for and reads as inconsistency.
1830
1847
  *
1831
- * Purely presentational: reports intent through onSort(key, dir) and never holds sort
1848
+ * The sort is an ordered list of keys. By default it holds one; with `multiple` the user
1849
+ * builds a list (first key wins, later keys break its ties) and can flip, reorder and
1850
+ * remove each entry.
1851
+ *
1852
+ * Purely presentational: reports intent through onSortChange(list) and never holds sort
1832
1853
  * state, so it stays honest against a real endpoint.
1833
1854
  */
1834
- declare function SortMenu({ fields, sort, onSort, align, size, className, ...rest }: SortMenuProps): React.JSX.Element;
1855
+ declare function SortMenu({ fields, sort, onSortChange, multiple, align, size, className, ...rest }: SortMenuProps): React.JSX.Element;
1835
1856
 
1836
1857
  interface Step {
1837
1858
  id: string;
@@ -5055,4 +5076,4 @@ declare function CornerStackPortal({ slot, children }: {
5055
5076
  children?: React.ReactNode;
5056
5077
  }): React.ReactPortal | null;
5057
5078
 
5058
- export { AccountMenu, type AccountMenuLink, type AccountMenuProps, AgentChatPanel, type AgentChatPanelProps, AnchoredPopover, type AnchoredPopoverProps, AnimNum, type AnimNumProps, ApiSpecBrowser, type ApiSpecBrowserProps, type AppEntry, AppShell, type AppShellProps, AppSwitcher, type AppSwitcherProps, AppearanceMenu, type AppearanceMenuProps, type AppearancePrefs, type AppearanceStore, type AppearanceStoreOptions, type Attachment, Avatar, type AvatarProps, AvatarStack, type AvatarStackProps, Badge, type BadgeProps, Banner, type BannerProps, type BannerTone, BarList, type BarListProps, type BarListRow, BudgetReallocator, type BudgetReallocatorProps, Button, type ButtonProps, CHANNELS, CHANNEL_WEIGHTS, CHAT_UNAVAILABLE, COPIED_FEEDBACK_MS, Calendar, type CalendarProps, Card, CardGrid, type CardGridProps, type CardProps, CardRow, type CardRowProps, ChannelContribution, type ChannelContributionChannel, type ChannelContributionProps, ChannelMeta, type ChannelMetaRecord, ChannelTag, type ChannelTagProps, ChannelWeightOf, type ChatAdapter, ChatComposer, type ChatComposerProps, type ChatEngine, type ChatEngineOptions, ChatKit, type ChatMessage, type ChatRenderContext, ChatSessionBar, type ChatSessionBarProps, ChatTranscript, type ChatTranscriptProps, ChatTurn, type ChatTurnProps, Checkbox, type CheckboxProps, type Citation, Citations, type CitationsProps, Clamp, type ClampProps, ClockFace, type ClockFaceProps, CodeBlock, type CodeBlockProps, CodeEditor, type CodeEditorDiagnostic, type CodeEditorProps, Collapsible, type CollapsibleProps, ComingSoon, type ComingSoonProps, type ContextUsage, CornerStackPortal, type CornerStackSlot, type CreateVersionStoreOptions, CsiBadge, type CsiBadgeProps, CsiHero, type CsiHeroProps, CsiMeter, type CsiMeterProps, DEFAULT_PREFS, DEFAULT_STORAGE_KEY, DEFAULT_TOAST_DURATION_MS, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, type DemoSessionControls, DemoSessionProvider, type DeviceSession, DiffBlock, type DiffBlockProps, DonutChart, type DonutChartProps, type DonutSegment, Drawer, type DrawerProps, Dropzone, DropzoneKit, type DropzoneProps, ENTITY_ROW_METRIC_WIDTH, type EditorTrigger, EmptyState, type EmptyStateProps, type EndpointSpec, EntityRow, type EntityRowAction, type EntityRowContent, type EntityRowMetric, EntityRowMetrics, type EntityRowMetricsProps, type EntityRowProps, FILE_VIEWER_CSV_ROW_LIMIT, FILE_VIEWER_TEXT_LIMIT, FeatureGate, type FeatureGateProps, type FeatureStatus, FileBrowser, type FileBrowserFile, type FileBrowserFolder, type FileBrowserPermissions, type FileBrowserProps, FileChip, type FileChipProps, FileGrid, type FileGridProps, FileKit, FilePickButton, type FilePickButtonProps, type FileRejection, FileStrip, type FileStripProps, FileTile, type FileTileProps, type FileUploadHandler, FileViewer, type FileViewerProps, FilterBar, type FilterBarProps, type FilterDateValue, type FilterField, type FilterFieldDate, type FilterFieldMultiSelect, type FilterFieldOption, type FilterFieldRange, type FilterFieldSelect, type FilterFieldText, type FilterMultiSelectValue, type FilterOperator, type FilterRangeValue, type FilterResolveMatch, type FilterResolveResult, type FilterValidation, type FilterValue, Flag$1 as Flag, type FlagExplanation, type FlagProps, FlytedeskBrand, type FlytedeskBrandProps, FlytedeskMark, type FlytedeskMarkProps, FormatEta, FunnelChart, type FunnelChartProps, type FunnelStep, Gate, GatePending, type GatePendingProps, type GateProps, IMPORTANCE_LEVELS, IconButton, type IconButtonProps, type ImportanceLevel, type ImportanceLevelId, ImportanceTag, type ImportanceTagProps, type ImportanceTokens, Input, type InputProps, type Job, type JobAction, type JobCardStatus, type JobStatus, JobTray, type JobTrayProps, Json, KeyHint, type KeyHintProps, LAYER_STEP, type ListEnvelope, LoadingRegion, type LoadingRegionProps, Markdown, MarkdownEditor, type MarkdownEditorHandle, type MarkdownEditorProps, MarkdownInline, type MarkdownProps, type MentionSource, Menu, MenuButton, type MenuButtonProps, type MenuItem, type MenuProps, MessageBody, type MessageBodyProps, type MessageGroup, Meter, type MeterProps, type MeterSegment, type MeterSegmentInput, MixGap, type MixGapProps, type MixGapRow, MockJobKit, type MockJobStatus, Modal, type ModalProps, ModeSwitch, type ModeSwitchProps, type Model, ModelControls, type ModelControlsProps, NumberInput, type NumberInputProps, OVERLAY_CEILING, POPOVER_BODY_MIN, type Packet, PacketCard, type PacketCardProps, type PacketSchema, type Pager, Pagination, type PaginationProps, PermissionDenied, type PermissionDeniedProps, type PermissionGroup, PermissionHint, type PermissionItem, type Phase, type PhaseStatus, PhasedProgress, type PhasedProgressProps, type Placement, type PollOptions, Popover, type PopoverProps, type PreferenceCriterion, PreferenceMeter, type PreferenceMeterProps, type ProfileFieldDef, type ProfileFieldType, type ProfileNotificationDef, ProfilePage, type ProfilePageProps, ProgressBar, type ProgressBarProps, QueryKit, type QueuedTurn, QuotaRow, type QuotaRowProps, ROOT_STEP, Radio, type RadioProps, RangeSlider, type RangeSliderProps, RelativeTime, type RelativeTimeProps, type RoadmapItem, type RoadmapResult, RoadmapTimeline, type RoadmapTimelineProps, type Role, RunActions, type RunActionsProps, type RunConfig, RuntimeKit, type RuntimeSummary, SaturationDistribution, type SaturationDistributionCampus, type SaturationDistributionProps, ScoreMeter, type ScoreMeterProps, ScreenHead, type ScreenHeadProps, SearchField, type SearchFieldProps, SegmentedControl, type SegmentedControlProps, SegmentedMeter, type SegmentedMeterProps, Select, type SelectOption, type SelectProps, type SendMessageResult, type ServerTable, type Session, type SessionContextValue, type Flag as SessionFlag, SessionKit, SessionProvider, type SessionProviderProps, type SessionRole, SessionScreen, type SessionScreenKind, type SessionScreenProps, type SessionStats, type SessionUser, SidebarNav, type SidebarNavItem, type SidebarNavProps, Skeleton, type SkeletonProps, SkeletonText, type SkeletonTextProps, type SlashCommand, Slider, type SliderProps, SortMenu, type SortMenuField, type SortMenuProps, type SpecModule, Spinner, type SpinnerProps, type StackedLayer, type StackedLayerOptions, StackedLayerProvider, StatTile, type StatTileProps, type Step, StepList, type StepListProps, type StreamHandlers, type Suggestion, SurroundSound, type SurroundSoundProps, Switch, type SwitchProps, type TableQuery, Tabs, type TabsProps, Tag, type TagProps, TestModeBar, type TestModeBarProps, type TextScale, Textarea, type TextareaProps, type ThemeMode, ThinkingBlock, type ThinkingBlockProps, type ThreadSummary, TimePicker, type TimePickerProps, Toast, type ToastApi, type ToastOptions, type ToastProps, ToastProvider, Tooltip, type TooltipProps, Topbar, type TopbarProps, TranscriptKit, TransferList, type TransferListProps, type TransferListSide, type TransferListSideProps, TrendChart, type TrendChartProps, type TrendSeries, type UsageLimit, UseFeatureStatus, type UseResponsiveRailOptions, type UseResponsiveRailResult, UseRuntimeMode, type UseServerTableOptions, type User, VIRTUAL_LIST_BUFFER_ROWS, VIRTUAL_LIST_ROW_GAP, type VersionRecord, type VersionStore, VirtualList, type VirtualListProps, type VirtualLoadedBand, type VirtualWindow, type VoiceHandler, __resetLayerStackForTests, acceptMatches, anyOfFilter, applyPrefs, channelWeightOf, computeNeedMore, computeVirtualWindow, copyToClipboard, createLocalStorageAppearanceStore, createVersionStore, eqFilter, extensionOf, extractClipboardFiles, filterFiles, formatAbsolute, formatBytes, formatClock, formatDocumentTitle, formatDuration, formatEta, formatRelative, groupMessages, hasModifier, iconForMime, importanceLevel, importanceTokens, installFlytedeskFavicon, isImage, isSystemMessage, isWithinLayerTree, jobBucket, languageLabel, loadPrefs, markdownToText, meterFormats, modifierLabel, parseDelimited, pastedTextName, pluralizeUnit, preferenceScore, preferenceSegments, rangeFilter, resolveTheme, revokeAttachment, savePrefs, toAttachment, tokenize, useAppearancePrefs, useChatEngine, useCopyToClipboard, useCornerStackSlot, useDocumentTitle, useFeatureStatus, useLayerZIndex, usePopoverPosition, useResponsiveRail, useRuntimeMode, useServerTable, useSessionContext, useStackedLayer, useStagedFiles, useToast, validateFilterValue, visibleMessages };
5079
+ export { AccountMenu, type AccountMenuLink, type AccountMenuProps, AgentChatPanel, type AgentChatPanelProps, AnchoredPopover, type AnchoredPopoverProps, AnimNum, type AnimNumProps, ApiSpecBrowser, type ApiSpecBrowserProps, type AppEntry, AppShell, type AppShellProps, AppSwitcher, type AppSwitcherProps, AppearanceMenu, type AppearanceMenuProps, type AppearancePrefs, type AppearanceStore, type AppearanceStoreOptions, type Attachment, Avatar, type AvatarProps, AvatarStack, type AvatarStackProps, Badge, type BadgeProps, Banner, type BannerProps, type BannerTone, BarList, type BarListProps, type BarListRow, BudgetReallocator, type BudgetReallocatorProps, Button, type ButtonProps, CHANNELS, CHANNEL_WEIGHTS, CHAT_UNAVAILABLE, COPIED_FEEDBACK_MS, Calendar, type CalendarProps, Card, CardGrid, type CardGridProps, type CardProps, CardRow, type CardRowProps, ChannelContribution, type ChannelContributionChannel, type ChannelContributionProps, ChannelMeta, type ChannelMetaRecord, ChannelTag, type ChannelTagProps, ChannelWeightOf, type ChatAdapter, ChatComposer, type ChatComposerProps, type ChatEngine, type ChatEngineOptions, ChatKit, type ChatMessage, type ChatRenderContext, ChatSessionBar, type ChatSessionBarProps, ChatTranscript, type ChatTranscriptProps, ChatTurn, type ChatTurnProps, Checkbox, type CheckboxProps, type Citation, Citations, type CitationsProps, Clamp, type ClampProps, ClockFace, type ClockFaceProps, CodeBlock, type CodeBlockProps, CodeEditor, type CodeEditorDiagnostic, type CodeEditorProps, Collapsible, type CollapsibleProps, ComingSoon, type ComingSoonProps, type ContextUsage, CornerStackPortal, type CornerStackSlot, type CreateVersionStoreOptions, CsiBadge, type CsiBadgeProps, CsiHero, type CsiHeroProps, CsiMeter, type CsiMeterProps, DEFAULT_PREFS, DEFAULT_STORAGE_KEY, DEFAULT_TOAST_DURATION_MS, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, type DemoSessionControls, DemoSessionProvider, type DeviceSession, DiffBlock, type DiffBlockProps, DonutChart, type DonutChartProps, type DonutSegment, Drawer, type DrawerProps, Dropzone, DropzoneKit, type DropzoneProps, ENTITY_ROW_METRIC_WIDTH, type EditorTrigger, EmptyState, type EmptyStateProps, type EndpointSpec, EntityRow, type EntityRowAction, type EntityRowContent, type EntityRowMetric, EntityRowMetrics, type EntityRowMetricsProps, type EntityRowProps, FILE_VIEWER_CSV_ROW_LIMIT, FILE_VIEWER_TEXT_LIMIT, FeatureGate, type FeatureGateProps, type FeatureStatus, FileBrowser, type FileBrowserFile, type FileBrowserFolder, type FileBrowserPermissions, type FileBrowserProps, FileChip, type FileChipProps, FileGrid, type FileGridProps, FileKit, FilePickButton, type FilePickButtonProps, type FileRejection, FileStrip, type FileStripProps, FileTile, type FileTileProps, type FileUploadHandler, FileViewer, type FileViewerProps, FilterBar, type FilterBarProps, type FilterDateValue, type FilterField, type FilterFieldDate, type FilterFieldMultiSelect, type FilterFieldOption, type FilterFieldRange, type FilterFieldSelect, type FilterFieldText, type FilterMultiSelectValue, type FilterOperator, type FilterRangeValue, type FilterResolveMatch, type FilterResolveResult, type FilterValidation, type FilterValue, Flag$1 as Flag, type FlagExplanation, type FlagProps, FlytedeskBrand, type FlytedeskBrandProps, FlytedeskMark, type FlytedeskMarkProps, FormatEta, FunnelChart, type FunnelChartProps, type FunnelStep, Gate, GatePending, type GatePendingProps, type GateProps, IMPORTANCE_LEVELS, IconButton, type IconButtonProps, type ImportanceLevel, type ImportanceLevelId, ImportanceTag, type ImportanceTagProps, type ImportanceTokens, Input, type InputProps, type Job, type JobAction, type JobCardStatus, type JobStatus, JobTray, type JobTrayProps, Json, KeyHint, type KeyHintProps, LAYER_STEP, type ListEnvelope, LoadingRegion, type LoadingRegionProps, Markdown, MarkdownEditor, type MarkdownEditorHandle, type MarkdownEditorProps, MarkdownInline, type MarkdownProps, type MentionSource, Menu, MenuButton, type MenuButtonProps, type MenuItem, type MenuProps, MessageBody, type MessageBodyProps, type MessageGroup, Meter, type MeterProps, type MeterSegment, type MeterSegmentInput, MixGap, type MixGapProps, type MixGapRow, MockJobKit, type MockJobStatus, Modal, type ModalProps, ModeSwitch, type ModeSwitchProps, type Model, ModelControls, type ModelControlsProps, NumberInput, type NumberInputProps, OVERLAY_CEILING, POPOVER_BODY_MIN, type Packet, PacketCard, type PacketCardProps, type PacketSchema, type Pager, Pagination, type PaginationProps, PermissionDenied, type PermissionDeniedProps, type PermissionGroup, PermissionHint, type PermissionItem, type Phase, type PhaseStatus, PhasedProgress, type PhasedProgressProps, type Placement, type PollOptions, Popover, type PopoverProps, type PreferenceCriterion, PreferenceMeter, type PreferenceMeterProps, type ProfileFieldDef, type ProfileFieldType, type ProfileNotificationDef, ProfilePage, type ProfilePageProps, ProgressBar, type ProgressBarProps, QueryKit, type QueuedTurn, QuotaRow, type QuotaRowProps, ROOT_STEP, Radio, type RadioProps, RangeSlider, type RangeSliderProps, RelativeTime, type RelativeTimeProps, type RoadmapItem, type RoadmapResult, RoadmapTimeline, type RoadmapTimelineProps, type Role, RunActions, type RunActionsProps, type RunConfig, RuntimeKit, type RuntimeSummary, SaturationDistribution, type SaturationDistributionCampus, type SaturationDistributionProps, ScoreMeter, type ScoreMeterProps, ScreenHead, type ScreenHeadProps, SearchField, type SearchFieldProps, SegmentedControl, type SegmentedControlProps, SegmentedMeter, type SegmentedMeterProps, Select, type SelectOption, type SelectProps, type SendMessageResult, type ServerTable, type Session, type SessionContextValue, type Flag as SessionFlag, SessionKit, SessionProvider, type SessionProviderProps, type SessionRole, SessionScreen, type SessionScreenKind, type SessionScreenProps, type SessionStats, type SessionUser, SidebarNav, type SidebarNavItem, type SidebarNavProps, Skeleton, type SkeletonProps, SkeletonText, type SkeletonTextProps, type SlashCommand, Slider, type SliderProps, type SortDirection, type SortEntry, SortMenu, type SortMenuField, type SortMenuProps, type SpecModule, Spinner, type SpinnerProps, type StackedLayer, type StackedLayerOptions, StackedLayerProvider, StatTile, type StatTileProps, type Step, StepList, type StepListProps, type StreamHandlers, type Suggestion, SurroundSound, type SurroundSoundProps, Switch, type SwitchProps, type TableQuery, Tabs, type TabsProps, Tag, type TagProps, TestModeBar, type TestModeBarProps, type TextScale, Textarea, type TextareaProps, type ThemeMode, ThinkingBlock, type ThinkingBlockProps, type ThreadSummary, TimePicker, type TimePickerProps, Toast, type ToastApi, type ToastOptions, type ToastProps, ToastProvider, Tooltip, type TooltipProps, Topbar, type TopbarProps, TranscriptKit, TransferList, type TransferListProps, type TransferListSide, type TransferListSideProps, TrendChart, type TrendChartProps, type TrendSeries, type UsageLimit, UseFeatureStatus, type UseResponsiveRailOptions, type UseResponsiveRailResult, UseRuntimeMode, type UseServerTableOptions, type User, VIRTUAL_LIST_BUFFER_ROWS, VIRTUAL_LIST_ROW_GAP, type VersionRecord, type VersionStore, VirtualList, type VirtualListProps, type VirtualLoadedBand, type VirtualWindow, type VoiceHandler, __resetLayerStackForTests, acceptMatches, anyOfFilter, applyPrefs, channelWeightOf, computeNeedMore, computeVirtualWindow, copyToClipboard, createLocalStorageAppearanceStore, createVersionStore, eqFilter, extensionOf, extractClipboardFiles, filterFiles, formatAbsolute, formatBytes, formatClock, formatDocumentTitle, formatDuration, formatEta, formatRelative, groupMessages, hasModifier, iconForMime, importanceLevel, importanceTokens, installFlytedeskFavicon, isImage, isSystemMessage, isWithinLayerTree, jobBucket, languageLabel, loadPrefs, markdownToText, meterFormats, modifierLabel, parseDelimited, pastedTextName, pluralizeUnit, preferenceScore, preferenceSegments, rangeFilter, resolveTheme, revokeAttachment, savePrefs, toAttachment, tokenize, useAppearancePrefs, useChatEngine, useCopyToClipboard, useCornerStackSlot, useDocumentTitle, useFeatureStatus, useLayerZIndex, usePopoverPosition, useResponsiveRail, useRuntimeMode, useServerTable, useSessionContext, useStackedLayer, useStagedFiles, useToast, validateFilterValue, visibleMessages };
package/dist/index.js CHANGED
@@ -3913,7 +3913,7 @@ function MultiSelectPanel({
3913
3913
  nav.setActive(0);
3914
3914
  }, [query, options.length]);
3915
3915
  const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
3916
- const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
3916
+ const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? query === "" && field.emptyText || "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
3917
3917
  const [pasteText, setPasteText] = React29.useState("");
3918
3918
  const [pasteLoading, setPasteLoading] = React29.useState(false);
3919
3919
  const [unmatchedTokens, setUnmatchedTokens] = React29.useState([]);
@@ -5427,53 +5427,156 @@ function InlinePanelSurface({ panel, align = "right", ...popover }) {
5427
5427
  }
5428
5428
 
5429
5429
  // src/components/data/SortMenu.tsx
5430
- import { jsx as jsx57, jsxs as jsxs49 } from "react/jsx-runtime";
5431
- function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
5430
+ import { Fragment as Fragment11, jsx as jsx57, jsxs as jsxs49 } from "react/jsx-runtime";
5431
+ var directionWord = (field, dir) => dir === "asc" ? field.numeric ? "lowest first" : "A to Z" : field.numeric ? "highest first" : "Z to A";
5432
+ function moved(sort, from, to) {
5433
+ const next = [...sort];
5434
+ const [entry] = next.splice(from, 1);
5435
+ next.splice(to, 0, entry);
5436
+ return next;
5437
+ }
5438
+ function SortMenu({
5439
+ fields = [],
5440
+ sort = [],
5441
+ onSortChange,
5442
+ multiple = false,
5443
+ align = "right",
5444
+ size = "md",
5445
+ className = "",
5446
+ ...rest
5447
+ }) {
5432
5448
  const panel = useInlinePanel();
5433
5449
  const { open: open2, setOpen, ref } = panel;
5434
- const cur = fields.find((f) => f.key === (sort && sort.key));
5435
- const dir = sort && sort.dir;
5436
- const arrow = (f, d) => {
5437
- const on = cur && cur.key === f.key && dir === d;
5438
- const label = d === "asc" ? f.numeric ? "lowest first" : "A to Z" : f.numeric ? "highest first" : "Z to A";
5439
- return /* @__PURE__ */ jsx57(
5440
- "button",
5450
+ const change = (next) => onSortChange && onSortChange(next);
5451
+ const fieldOf = (key) => fields.find((f) => f.key === key);
5452
+ const active = sort.filter((entry) => fieldOf(entry.key));
5453
+ const first = active[0];
5454
+ const firstField = first && fieldOf(first.key);
5455
+ const triggerLabel = firstField ? firstField.label + (active.length > 1 ? " +" + (active.length - 1) : "") : "Unsorted";
5456
+ const triggerTitle = active.map((entry) => {
5457
+ const field = fieldOf(entry.key);
5458
+ return field.label + " " + directionWord(field, entry.dir);
5459
+ }).join(", then ");
5460
+ const arrow = (field, dir, on, onClick) => /* @__PURE__ */ jsx57(
5461
+ "button",
5462
+ {
5463
+ type: "button",
5464
+ "aria-label": field.label + ", " + directionWord(field, dir),
5465
+ "aria-pressed": on,
5466
+ onClick,
5467
+ style: {
5468
+ display: "grid",
5469
+ placeItems: "center",
5470
+ width: 26,
5471
+ height: 26,
5472
+ borderRadius: 6,
5473
+ cursor: "pointer",
5474
+ flex: "none",
5475
+ border: "1px solid " + (on ? "var(--brand)" : "var(--border)"),
5476
+ background: on ? "var(--brand)" : "var(--surface)",
5477
+ color: on ? "#fff" : "var(--text-muted)"
5478
+ },
5479
+ children: /* @__PURE__ */ jsx57("i", { className: "ph ph-arrow-" + (dir === "asc" ? "up" : "down"), style: { fontSize: 13 } })
5480
+ }
5481
+ );
5482
+ const rowStyle = (highlight) => ({
5483
+ gap: 8,
5484
+ padding: "4px 8px",
5485
+ borderRadius: 7,
5486
+ background: highlight ? "var(--surface-brand)" : "transparent"
5487
+ });
5488
+ const labelStyle = (highlight) => ({
5489
+ flex: 1,
5490
+ minWidth: 0,
5491
+ fontWeight: highlight ? 700 : 500,
5492
+ color: highlight ? "var(--text-on-surface-brand)" : "var(--text)"
5493
+ });
5494
+ const singleBody = fields.map((f) => {
5495
+ const on = !!first && first.key === f.key;
5496
+ return /* @__PURE__ */ jsxs49("span", { className: "fd-row", style: rowStyle(on), children: [
5497
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: labelStyle(on), children: f.label }),
5498
+ arrow(f, "asc", on && first.dir === "asc", () => change([{ key: f.key, dir: "asc" }])),
5499
+ arrow(f, "desc", on && first.dir === "desc", () => change([{ key: f.key, dir: "desc" }]))
5500
+ ] }, f.key);
5501
+ });
5502
+ const unused = fields.filter((f) => !active.some((entry) => entry.key === f.key));
5503
+ const multipleBody = /* @__PURE__ */ jsxs49(Fragment11, { children: [
5504
+ /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Sorted by" }),
5505
+ active.length === 0 ? /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", style: { padding: "4px 8px" }, children: "Unsorted" }) : /* @__PURE__ */ jsx57("ol", { className: "fd-stack", style: { gap: 2, margin: 0, padding: 0, listStyle: "none" }, "aria-label": "Sort order", children: active.map((entry, index) => {
5506
+ const f = fieldOf(entry.key);
5507
+ const flipped = entry.dir === "asc" ? "desc" : "asc";
5508
+ return /* @__PURE__ */ jsxs49("li", { className: "fd-row", style: rowStyle(false), children: [
5509
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", "aria-hidden": "true", style: { width: 14, flex: "none" }, children: index + 1 }),
5510
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: labelStyle(false), children: f.label }),
5511
+ /* @__PURE__ */ jsx57(
5512
+ IconButton,
5513
+ {
5514
+ size: "sm",
5515
+ variant: "outline",
5516
+ icon: entry.dir === "asc" ? "arrow-up" : "arrow-down",
5517
+ label: f.label + ", " + directionWord(f, entry.dir) + ". Switch to " + directionWord(f, flipped),
5518
+ onClick: () => change(active.map((e) => e.key === entry.key ? { key: e.key, dir: flipped } : e))
5519
+ }
5520
+ ),
5521
+ /* @__PURE__ */ jsx57(
5522
+ IconButton,
5523
+ {
5524
+ size: "sm",
5525
+ icon: "caret-up",
5526
+ label: "Sort " + f.label + " earlier",
5527
+ disabled: index === 0,
5528
+ onClick: () => change(moved(active, index, index - 1))
5529
+ }
5530
+ ),
5531
+ /* @__PURE__ */ jsx57(
5532
+ IconButton,
5533
+ {
5534
+ size: "sm",
5535
+ icon: "caret-down",
5536
+ label: "Sort " + f.label + " later",
5537
+ disabled: index === active.length - 1,
5538
+ onClick: () => change(moved(active, index, index + 1))
5539
+ }
5540
+ ),
5541
+ /* @__PURE__ */ jsx57(
5542
+ IconButton,
5543
+ {
5544
+ size: "sm",
5545
+ icon: "x",
5546
+ label: "Remove " + f.label + " from the sort",
5547
+ onClick: () => change(active.filter((e) => e.key !== entry.key))
5548
+ }
5549
+ )
5550
+ ] }, entry.key);
5551
+ }) }),
5552
+ unused.length > 0 ? /* @__PURE__ */ jsxs49(Fragment11, { children: [
5553
+ /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", style: { padding: "10px 8px 6px" }, children: "Add a sort" }),
5554
+ unused.map((f) => /* @__PURE__ */ jsxs49("span", { className: "fd-row", style: rowStyle(false), children: [
5555
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: labelStyle(false), children: f.label }),
5556
+ arrow(f, "asc", false, () => change([...active, { key: f.key, dir: "asc" }])),
5557
+ arrow(f, "desc", false, () => change([...active, { key: f.key, dir: "desc" }]))
5558
+ ] }, f.key))
5559
+ ] }) : null
5560
+ ] });
5561
+ return /* @__PURE__ */ jsxs49("span", { className, style: { display: "inline-flex", minWidth: 0 }, ref, ...rest, children: [
5562
+ /* @__PURE__ */ jsxs49(
5563
+ Button,
5441
5564
  {
5442
- type: "button",
5443
- "aria-label": f.label + ", " + label,
5444
- "aria-pressed": on,
5445
- onClick: () => onSort && onSort(f.key, d),
5446
- style: {
5447
- display: "grid",
5448
- placeItems: "center",
5449
- width: 26,
5450
- height: 26,
5451
- borderRadius: 6,
5452
- cursor: "pointer",
5453
- border: "1px solid " + (on ? "var(--brand)" : "var(--border)"),
5454
- background: on ? "var(--brand)" : "var(--surface)",
5455
- color: on ? "#fff" : "var(--text-muted)"
5456
- },
5457
- children: /* @__PURE__ */ jsx57("i", { className: "ph ph-arrow-" + (d === "asc" ? "up" : "down"), style: { fontSize: 13 } })
5565
+ size,
5566
+ variant: "secondary",
5567
+ icon: first && first.dir === "asc" ? "sort-ascending" : "sort-descending",
5568
+ title: triggerTitle || void 0,
5569
+ onClick: () => setOpen(!open2),
5570
+ children: [
5571
+ triggerLabel,
5572
+ /* @__PURE__ */ jsx57("i", { className: "ph ph-" + (first && first.dir === "asc" ? "arrow-up" : "arrow-down"), style: { fontSize: 12, marginLeft: 6, opacity: 0.75 } })
5573
+ ]
5458
5574
  }
5459
- );
5460
- };
5461
- return /* @__PURE__ */ jsxs49("span", { className, style: { display: "inline-flex" }, ref, ...rest, children: [
5462
- /* @__PURE__ */ jsxs49(Button, { size, variant: "secondary", icon: dir === "asc" ? "sort-ascending" : "sort-descending", onClick: () => setOpen(!open2), children: [
5463
- cur ? cur.label : "Unsorted",
5464
- /* @__PURE__ */ jsx57("i", { className: "ph ph-" + (dir === "asc" ? "arrow-up" : "arrow-down"), style: { fontSize: 12, marginLeft: 6, opacity: 0.75 } })
5465
- ] }),
5466
- /* @__PURE__ */ jsx57(InlinePanelSurface, { panel, align, offset: 6, width: 280, label: "Sort by", children: /* @__PURE__ */ jsxs49("span", { className: "fd-stack", style: { gap: 2, padding: 8 }, children: [
5575
+ ),
5576
+ /* @__PURE__ */ jsx57(InlinePanelSurface, { panel, align, offset: 6, width: multiple ? 340 : 280, label: "Sort by", children: /* @__PURE__ */ jsx57("span", { className: "fd-stack", style: { gap: 2, padding: 8 }, children: multiple ? multipleBody : /* @__PURE__ */ jsxs49(Fragment11, { children: [
5467
5577
  /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Sort by" }),
5468
- fields.map((f) => {
5469
- const active = cur && cur.key === f.key;
5470
- return /* @__PURE__ */ jsxs49("span", { className: "fd-row", style: { gap: 8, padding: "4px 8px", borderRadius: 7, background: active ? "var(--surface-brand)" : "transparent" }, children: [
5471
- /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { flex: 1, fontWeight: active ? 700 : 500, color: active ? "var(--text-on-surface-brand)" : "var(--text)" }, children: f.label }),
5472
- arrow(f, "asc"),
5473
- arrow(f, "desc")
5474
- ] }, f.key);
5475
- })
5476
- ] }) })
5578
+ singleBody
5579
+ ] }) }) })
5477
5580
  ] });
5478
5581
  }
5479
5582
 
@@ -6011,7 +6114,7 @@ function TransferList({
6011
6114
  cfg.header ? /* @__PURE__ */ jsx63("div", { className: "fd-tlist-header", children: cfg.header }) : null,
6012
6115
  /* @__PURE__ */ jsxs54("span", { className: "fd-row", style: { gap: 8 }, children: [
6013
6116
  /* @__PURE__ */ jsx63(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
6014
- /* @__PURE__ */ jsx63(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
6117
+ /* @__PURE__ */ jsx63(SortMenu, { fields: cfg.sortFields, sort: cfg.sort ? [cfg.sort] : [], onSortChange: (next) => next[0] && cfg.onSort(next[0].key, next[0].dir), align: side === "left" ? "left" : "right" })
6015
6118
  ] }),
6016
6119
  /* @__PURE__ */ jsx63(
6017
6120
  VirtualList,
@@ -7734,7 +7837,7 @@ function useSessionContext() {
7734
7837
  }
7735
7838
 
7736
7839
  // src/components/platform/AccountMenu.tsx
7737
- import { Fragment as Fragment16, jsx as jsx75, jsxs as jsxs66 } from "react/jsx-runtime";
7840
+ import { Fragment as Fragment17, jsx as jsx75, jsxs as jsxs66 } from "react/jsx-runtime";
7738
7841
  var DEFAULT_LINKS = [];
7739
7842
  var DEFAULT_GROUPS = [];
7740
7843
  function Item({ item, onPick }) {
@@ -7796,7 +7899,7 @@ function AccountMenu({
7796
7899
  }
7797
7900
  };
7798
7901
  const showSwitcher = allowUserSwitch && !!demo;
7799
- return /* @__PURE__ */ jsxs66(Fragment16, { children: [
7902
+ return /* @__PURE__ */ jsxs66(Fragment17, { children: [
7800
7903
  /* @__PURE__ */ jsxs66(
7801
7904
  "button",
7802
7905
  {
@@ -8554,7 +8657,7 @@ function ProfilePage({
8554
8657
 
8555
8658
  // src/components/platform/SessionScreen.tsx
8556
8659
  import * as React55 from "react";
8557
- import { Fragment as Fragment19, jsx as jsx80, jsxs as jsxs71 } from "react/jsx-runtime";
8660
+ import { Fragment as Fragment20, jsx as jsx80, jsxs as jsxs71 } from "react/jsx-runtime";
8558
8661
  var COPY = {
8559
8662
  "signing-in": { busy: "Signing you in\u2026" },
8560
8663
  "session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
@@ -8582,7 +8685,7 @@ function SessionScreen({ kind, error, onRetry, productName }) {
8582
8685
  /* @__PURE__ */ jsx80("div", { className: "fd-session-screen-stripe" }),
8583
8686
  /* @__PURE__ */ jsx80(Card, { children: /* @__PURE__ */ jsxs71("div", { className: "fd-session-screen-body", children: [
8584
8687
  /* @__PURE__ */ jsx80("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
8585
- /* @__PURE__ */ jsx80("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ jsxs71(Fragment19, { children: [
8688
+ /* @__PURE__ */ jsx80("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ jsxs71(Fragment20, { children: [
8586
8689
  /* @__PURE__ */ jsx80("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
8587
8690
  /* @__PURE__ */ jsx80("p", { className: "fd-body fd-session-screen-message", children: announced })
8588
8691
  ] }) : null }),
@@ -10609,7 +10712,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10609
10712
  // src/components/platform/ComingSoon.tsx
10610
10713
  import * as React59 from "react";
10611
10714
  import { createPortal as createPortal6 } from "react-dom";
10612
- import { Fragment as Fragment21, jsx as jsx82, jsxs as jsxs73 } from "react/jsx-runtime";
10715
+ import { Fragment as Fragment22, jsx as jsx82, jsxs as jsxs73 } from "react/jsx-runtime";
10613
10716
  var BYPASS_STORE = "fd.soon.bypass.v1";
10614
10717
  function readBypassed() {
10615
10718
  try {
@@ -10639,7 +10742,7 @@ function useBypass(key) {
10639
10742
  return [on, set];
10640
10743
  }
10641
10744
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
10642
- return /* @__PURE__ */ jsxs73(Fragment21, { children: [
10745
+ return /* @__PURE__ */ jsxs73(Fragment22, { children: [
10643
10746
  /* @__PURE__ */ jsxs73("span", { className: "fd-soon-badge", children: [
10644
10747
  /* @__PURE__ */ jsx82("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
10645
10748
  label
@@ -11029,7 +11132,7 @@ function PermissionHint({ perm, children }) {
11029
11132
  }
11030
11133
 
11031
11134
  // src/components/platform/ModeSwitch.tsx
11032
- import { Fragment as Fragment22, jsx as jsx84, jsxs as jsxs75 } from "react/jsx-runtime";
11135
+ import { Fragment as Fragment23, jsx as jsx84, jsxs as jsxs75 } from "react/jsx-runtime";
11033
11136
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
11034
11137
  const mode2 = useRuntimeMode();
11035
11138
  const panel = useInlinePanel();
@@ -11084,7 +11187,7 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11084
11187
  s.total,
11085
11188
  " features complete"
11086
11189
  ] }),
11087
- onOpenSpec ? /* @__PURE__ */ jsxs75(Fragment22, { children: [
11190
+ onOpenSpec ? /* @__PURE__ */ jsxs75(Fragment23, { children: [
11088
11191
  /* @__PURE__ */ jsx84("span", { style: { flex: 1 } }),
11089
11192
  /* @__PURE__ */ jsxs75("button", { type: "button", className: "fd-soon-link", onClick: () => {
11090
11193
  setOpen(false);
@@ -11276,7 +11379,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11276
11379
 
11277
11380
  // src/components/planner/MixGap.tsx
11278
11381
  import * as React60 from "react";
11279
- import { Fragment as Fragment23, jsx as jsx87, jsxs as jsxs78 } from "react/jsx-runtime";
11382
+ import { Fragment as Fragment24, jsx as jsx87, jsxs as jsxs78 } from "react/jsx-runtime";
11280
11383
  var MIX_GAP_LAYOUT = {
11281
11384
  trackHeight: 30,
11282
11385
  barHeight: 20,
@@ -11320,7 +11423,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11320
11423
  onMouseLeave: () => setHover(null),
11321
11424
  children: [
11322
11425
  /* @__PURE__ */ jsx87("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx87(ChannelTag, { channel: r.channel, size: "sm" }) }),
11323
- /* @__PURE__ */ jsx87("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx87("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ jsxs78(Fragment23, { children: [
11426
+ /* @__PURE__ */ jsx87("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx87("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ jsxs78(Fragment24, { children: [
11324
11427
  /* @__PURE__ */ jsx87("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
11325
11428
  /* @__PURE__ */ jsx87("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
11326
11429
  /* @__PURE__ */ jsxs78("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
@@ -11434,7 +11537,7 @@ function ChannelContribution({
11434
11537
 
11435
11538
  // src/components/planner/BudgetReallocator.tsx
11436
11539
  import * as React61 from "react";
11437
- import { Fragment as Fragment24, jsx as jsx89, jsxs as jsxs80 } from "react/jsx-runtime";
11540
+ import { Fragment as Fragment25, jsx as jsx89, jsxs as jsxs80 } from "react/jsx-runtime";
11438
11541
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
11439
11542
  function BudgetReallocator({
11440
11543
  campus,
@@ -11498,7 +11601,7 @@ function BudgetReallocator({
11498
11601
  /* @__PURE__ */ jsxs80("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
11499
11602
  /* @__PURE__ */ jsx89("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
11500
11603
  /* @__PURE__ */ jsx89(CsiBadge, { band: nowBand, crp, size: "medium" }),
11501
- dirty ? /* @__PURE__ */ jsxs80(Fragment24, { children: [
11604
+ dirty ? /* @__PURE__ */ jsxs80(Fragment25, { children: [
11502
11605
  /* @__PURE__ */ jsx89("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
11503
11606
  /* @__PURE__ */ jsx89(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
11504
11607
  ] }) : null
@@ -13437,7 +13540,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13437
13540
 
13438
13541
  // src/components/files/FileBrowser.tsx
13439
13542
  import * as React70 from "react";
13440
- import { Fragment as Fragment28, jsx as jsx99, jsxs as jsxs90 } from "react/jsx-runtime";
13543
+ import { Fragment as Fragment29, jsx as jsx99, jsxs as jsxs90 } from "react/jsx-runtime";
13441
13544
  function childrenOf(folders, parentId) {
13442
13545
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
13443
13546
  }
@@ -13736,7 +13839,7 @@ function FileBrowser({
13736
13839
  ] }),
13737
13840
  /* @__PURE__ */ jsxs90("span", { className: "fd-fb-actions", children: [
13738
13841
  canCreateFolder ? /* @__PURE__ */ jsx99(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
13739
- canUpload ? /* @__PURE__ */ jsxs90(Fragment28, { children: [
13842
+ canUpload ? /* @__PURE__ */ jsxs90(Fragment29, { children: [
13740
13843
  /* @__PURE__ */ jsx99(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
13741
13844
  /* @__PURE__ */ jsx99(
13742
13845
  "input",
@@ -13803,7 +13906,7 @@ function FileBrowser({
13803
13906
  draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
13804
13907
  isDropTarget: canMove,
13805
13908
  onDropPayload: (p) => moveIntoFolder(p, f.id),
13806
- actions: /* @__PURE__ */ jsxs90(Fragment28, { children: [
13909
+ actions: /* @__PURE__ */ jsxs90(Fragment29, { children: [
13807
13910
  canRenameFolder ? /* @__PURE__ */ jsx99(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
13808
13911
  canMove ? /* @__PURE__ */ jsx99(
13809
13912
  FolderPickerMenu,
@@ -13826,7 +13929,7 @@ function FileBrowser({
13826
13929
  meta: file.size ? formatBytes(file.size) : void 0,
13827
13930
  onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
13828
13931
  draggableId: canMove ? { kind: "file", id: file.id } : void 0,
13829
- actions: /* @__PURE__ */ jsxs90(Fragment28, { children: [
13932
+ actions: /* @__PURE__ */ jsxs90(Fragment29, { children: [
13830
13933
  canMove ? /* @__PURE__ */ jsx99(
13831
13934
  FolderPickerMenu,
13832
13935
  {
@@ -13844,7 +13947,7 @@ function FileBrowser({
13844
13947
  }
13845
13948
  ) })
13846
13949
  ] }),
13847
- /* @__PURE__ */ jsx99(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ jsxs90(Fragment28, { children: [
13950
+ /* @__PURE__ */ jsx99(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ jsxs90(Fragment29, { children: [
13848
13951
  /* @__PURE__ */ jsx99(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
13849
13952
  /* @__PURE__ */ jsx99(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
13850
13953
  ] }), children: /* @__PURE__ */ jsx99(
@@ -13861,7 +13964,7 @@ function FileBrowser({
13861
13964
  autoFocus: true
13862
13965
  }
13863
13966
  ) }),
13864
- /* @__PURE__ */ jsx99(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ jsxs90(Fragment28, { children: [
13967
+ /* @__PURE__ */ jsx99(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ jsxs90(Fragment29, { children: [
13865
13968
  /* @__PURE__ */ jsx99(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
13866
13969
  /* @__PURE__ */ jsx99(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
13867
13970
  ] }), children: /* @__PURE__ */ jsx99(
@@ -13885,7 +13988,7 @@ function FileBrowser({
13885
13988
  title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
13886
13989
  description: "This can't be undone. The folder must be empty.",
13887
13990
  onClose: () => setDeleteTarget(null),
13888
- footer: /* @__PURE__ */ jsxs90(Fragment28, { children: [
13991
+ footer: /* @__PURE__ */ jsxs90(Fragment29, { children: [
13889
13992
  /* @__PURE__ */ jsx99(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
13890
13993
  /* @__PURE__ */ jsx99(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
13891
13994
  ] })