@tensor_1/react 2.24.0 → 2.26.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
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { RefObject, ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, AriaAttributes, HTMLAttributes, TextareaHTMLAttributes, SelectHTMLAttributes, AnchorHTMLAttributes, MouseEvent, DetailsHTMLAttributes, TdHTMLAttributes, TableHTMLAttributes, ThHTMLAttributes } from 'react';
2
+ import { RefObject, ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, AriaAttributes, HTMLAttributes, Ref, TextareaHTMLAttributes, SelectHTMLAttributes, AnchorHTMLAttributes, MouseEvent, DetailsHTMLAttributes, TdHTMLAttributes, TableHTMLAttributes, ThHTMLAttributes } from 'react';
3
3
  import { P as Placement } from './overlay-position-CEGSz6Z2.cjs';
4
4
  export { A as Align, a as PositionOptions, b as PositionResult, R as Rect, S as Side, c as Size, d as computePosition } from './overlay-position-CEGSz6Z2.cjs';
5
5
 
@@ -250,6 +250,108 @@ interface ComboboxProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>
250
250
  /** Searchable single-select combobox with keyboard navigation and no framework dependencies. */
251
251
  declare function Combobox({ options, value, defaultValue, onValueChange, label, placeholder, emptyLabel, name, disabled, className, ...props }: ComboboxProps): react.JSX.Element;
252
252
 
253
+ /** One result row. */
254
+ interface SearchSuggestOption {
255
+ /** Stable id, returned by `onSelect`. */
256
+ id: string;
257
+ /** The result's name. Matched letters are emphasised. */
258
+ title: string;
259
+ /** Where the result lives, outermost first (a breadcrumb). Middle crumbs truncate first. */
260
+ meta?: readonly string[];
261
+ /** One or two lines of context, clamped at two lines. Matched letters are emphasised. */
262
+ description?: string;
263
+ /** Optional leading glyph (decorative). */
264
+ icon?: ReactNode;
265
+ }
266
+ /** A labelled action inside the list (the footer row, the heading action). */
267
+ interface SearchSuggestAction {
268
+ /** Visible text of the action. */
269
+ label: string;
270
+ /** Runs when the action is chosen. */
271
+ onSelect: () => void;
272
+ }
273
+ /** Props of {@link SearchSuggest}. */
274
+ interface SearchSuggestProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'onSelect' | 'title' | 'defaultValue'> {
275
+ /** The text in the field (controlled). */
276
+ value: string;
277
+ /** Called on every edit, and with an empty string when the field is cleared. */
278
+ onValueChange: (value: string) => void;
279
+ /** The suggestions to show, best first. The consumer filters; this component only renders. */
280
+ options: readonly SearchSuggestOption[];
281
+ /** Called when a row is chosen by click or Enter. The list closes afterwards. */
282
+ onSelect: (id: string, option: SearchSuggestOption) => void;
283
+ /** Accessible name of the field (there is no visible label; the placeholder is not a label). */
284
+ label: string;
285
+ placeholder?: string;
286
+ /** Text to emphasise in rows. Defaults to `value`. */
287
+ highlight?: string;
288
+ /** A title above the options, e.g. "Recently opened". */
289
+ heading?: string;
290
+ /** A small action next to the heading, e.g. "Clear". */
291
+ headingAction?: SearchSuggestAction;
292
+ /** A last row after the options, e.g. "Show all 23 results". Reachable by arrow keys. */
293
+ footer?: SearchSuggestAction;
294
+ /** The field is fetching suggestions: a spinner shows in the field and, with no options yet, in the list. */
295
+ loading?: boolean;
296
+ /** Announced while loading, and shown in the list when it has no rows yet. */
297
+ loadingLabel?: string;
298
+ /** Shown when the field has text, nothing is loading and there are no options. */
299
+ empty?: ReactNode;
300
+ /** Shown instead of the empty state when suggestions could not be loaded. */
301
+ error?: ReactNode;
302
+ /** A keyboard hint shown in the empty, unfocused field, e.g. "/". */
303
+ shortcutHint?: string;
304
+ /** Accessible name of the clear button (default "Clear search"). */
305
+ clearLabel?: string;
306
+ /** A polite announcement, e.g. "8 results". Rendered in a visually hidden live region. */
307
+ status?: string;
308
+ /** `lg` for a page-level search (hubs, start pages); `md` for a field in a toolbar or header. */
309
+ size?: 'md' | 'lg';
310
+ /** Controlled open state of the suggestion list (optional). */
311
+ open?: boolean;
312
+ /** Called when the list opens or closes. */
313
+ onOpenChange?: (open: boolean) => void;
314
+ /**
315
+ * `absolute` (default) places the list under the field inside its own box. `fixed` floats it on
316
+ * the viewport, so a clipping ancestor (`overflow: hidden` toolbars and headers) cannot cut it off;
317
+ * it follows the field on scroll and resize and flips above it when there is no room below.
318
+ */
319
+ strategy?: 'absolute' | 'fixed';
320
+ /** Focus the field from outside (e.g. a "/" shortcut). */
321
+ inputRef?: Ref<HTMLInputElement | null>;
322
+ /** Focus the field on mount. */
323
+ autoFocus?: boolean;
324
+ /** Form field name of the input. */
325
+ name?: string;
326
+ }
327
+ /**
328
+ * A search field with a suggestion list underneath: the "search and jump" pattern of Windows
329
+ * Settings, Android Settings and most docs sites. Each row shows a name, where it lives and a line
330
+ * of context. ARIA combobox pattern: focus stays in the field, arrow keys move the active row
331
+ * (`aria-activedescendant`), Enter opens it (the first row when none is active), Escape closes the
332
+ * list and a second Escape clears the text.
333
+ */
334
+ declare function SearchSuggest({ value, onValueChange, options, onSelect, label, placeholder, highlight, heading, headingAction, footer, loading, loadingLabel, empty, error, shortcutHint, clearLabel, status, size, open: openProp, strategy, onOpenChange, inputRef, autoFocus, name, className, onBlur, ...props }: SearchSuggestProps): react.JSX.Element;
335
+
336
+ /** One run of a result's text, emphasised or not. */
337
+ interface SearchSegment {
338
+ text: string;
339
+ match: boolean;
340
+ }
341
+ /** Text folded for matching, with a map back to the original characters. */
342
+ interface FoldedText {
343
+ /** The folded text: lower case, diacritics stripped, ß → ss. */
344
+ text: string;
345
+ /** For each index of `text`, the start index of the original character it came from. */
346
+ source: number[];
347
+ /** For each index of `text`, the end index (exclusive) of that original character. */
348
+ sourceEnd: number[];
349
+ }
350
+ /** Fold `text` for matching and keep a map back to the original indices. */
351
+ declare function foldForSearch(text: string): FoldedText;
352
+ /** Split `text` into matched and unmatched segments for `query`. */
353
+ declare function searchSegments(text: string, query: string): SearchSegment[];
354
+
253
355
  interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
254
356
  invalid?: boolean;
255
357
  }
@@ -289,11 +391,19 @@ interface FieldProps {
289
391
  error?: string;
290
392
  success?: string;
291
393
  required?: boolean;
394
+ /**
395
+ * Plain-text help behind a ? button after the label (before the required marker). Blank
396
+ * lines separate paragraphs; empty, whitespace-only or `null` renders no button. Needs `label`.
397
+ * Keep format or validation instructions in `hint`, where they stay visible.
398
+ */
399
+ help?: string | null;
400
+ /** Accessible name of the ? button. Default `"About: <label>"`; pass a localised one. */
401
+ helpLabel?: string;
292
402
  children: ReactNode;
293
403
  className?: string;
294
404
  htmlFor?: string;
295
405
  }
296
- declare function Field({ label, hint, error, success, required, children, className, htmlFor }: FieldProps): react.JSX.Element;
406
+ declare function Field({ label, hint, error, success, required, help, helpLabel, children, className, htmlFor }: FieldProps): react.JSX.Element;
297
407
 
298
408
  interface ModalProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
299
409
  open: boolean;
@@ -343,11 +453,17 @@ interface DrawerProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
343
453
  closeLabel?: string;
344
454
  open: boolean;
345
455
  onClose?: () => void;
456
+ /**
457
+ * A click on the dimmed backdrop calls `onClose`, like Escape and the close button
458
+ * (TENSOR HAR-547). Pass `false` on a drawer that holds unsaved form input, so a stray click
459
+ * can't discard it; Escape and the close button still close. Default `true`.
460
+ */
461
+ dismissOnBackdrop?: boolean;
346
462
  title?: ReactNode;
347
463
  children?: ReactNode;
348
464
  footer?: ReactNode;
349
465
  }
350
- declare function Drawer({ open, onClose, title, children, footer, closeLabel, className, ...rest }: DrawerProps): react.JSX.Element;
466
+ declare function Drawer({ open, onClose, dismissOnBackdrop, title, children, footer, closeLabel, className, onClick, ...rest }: DrawerProps): react.JSX.Element;
351
467
 
352
468
  interface PeekProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
353
469
  /** TENSOR RX-125 (UIX-04): translatable; English default. */
@@ -372,11 +488,18 @@ interface CardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
372
488
  /** Element for the title — pick a real heading to slot the card into the page outline (UIX-A11Y-4). Default `div` keeps legacy rendering. */
373
489
  titleAs?: 'h2' | 'h3' | 'h4' | 'div';
374
490
  subtitle?: ReactNode;
491
+ /**
492
+ * Plain-text help behind a ? button after the title. Blank lines separate paragraphs;
493
+ * empty, whitespace-only or `null` renders no button.
494
+ */
495
+ help?: string | null;
496
+ /** Accessible name of the ? button. Default `"About: <title>"` when title is text; pass a localised one. */
497
+ helpLabel?: string;
375
498
  headerAction?: ReactNode;
376
499
  footer?: ReactNode;
377
500
  children?: ReactNode;
378
501
  }
379
- declare function Card({ title, titleAs: TitleTag, subtitle, headerAction, footer, children, className, ...props }: CardProps): react.JSX.Element;
502
+ declare function Card({ title, titleAs: TitleTag, subtitle, help, helpLabel, headerAction, footer, children, className, ...props }: CardProps): react.JSX.Element;
380
503
  interface CardLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'title'> {
381
504
  title?: ReactNode;
382
505
  subtitle?: ReactNode;
@@ -408,14 +531,21 @@ interface PageHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
408
531
  as?: 'h1' | 'h2';
409
532
  /** Supporting copy under the title. */
410
533
  subtitle?: ReactNode;
534
+ /**
535
+ * Plain-text help behind a ? button right after the title. Blank lines separate paragraphs;
536
+ * empty, whitespace-only or `null` renders no button.
537
+ */
538
+ help?: string | null;
539
+ /** Accessible name of the ? button. Default `"About: <title>"` when title is text; pass a localised one. */
540
+ helpLabel?: string;
411
541
  /** Right-aligned action area (buttons, menus). */
412
542
  actions?: ReactNode;
413
543
  }
414
544
  /**
415
- * Page header — eyebrow / title / subtitle + actions row, over `.uix-page-header`.
545
+ * Page header — eyebrow / title (+ optional `help` ?) / subtitle + actions row, over `.uix-page-header`.
416
546
  * The hairline + breathing room below come from the component CSS.
417
547
  */
418
- declare function PageHeader({ eyebrow, title, subtitle, actions, as: TitleTag, className, ...props }: PageHeaderProps): react.JSX.Element;
548
+ declare function PageHeader({ eyebrow, title, subtitle, help, helpLabel, actions, as: TitleTag, className, ...props }: PageHeaderProps): react.JSX.Element;
419
549
 
420
550
  interface DetailLayoutProps extends HTMLAttributes<HTMLDivElement> {
421
551
  /** The narrow trailing column (record meta, side panels). */
@@ -1017,6 +1147,30 @@ interface TooltipProps extends HTMLAttributes<HTMLSpanElement> {
1017
1147
  */
1018
1148
  declare function Tooltip({ label, placement, className, children, ...props }: TooltipProps): react.JSX.Element;
1019
1149
 
1150
+ interface InfoTipProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'content' | 'children'> {
1151
+ /**
1152
+ * Help text, rendered as plain text (never HTML). A blank line starts a new paragraph.
1153
+ * Empty or whitespace-only text renders nothing, so a missing help string needs no guard.
1154
+ */
1155
+ content: string;
1156
+ /** Accessible name of the ? button, e.g. "About: Incidents". The consumer localises it. */
1157
+ label: string;
1158
+ /** Preferred panel placement. Default `'bottom-start'`. */
1159
+ placement?: Placement;
1160
+ }
1161
+ /**
1162
+ * A small ? that explains a page, section or field. It is a fixed 9 px glyph, superscript at
1163
+ * the top right of the text it follows (25 px hit area). The panel opens on hover (after a short delay), on
1164
+ * keyboard focus, and on click or tap; a click keeps it open until a second click, Esc or a
1165
+ * click outside. Esc returns focus to the button. The panel is plain text in
1166
+ * the top layer (kit `Popover`, `popover="manual"`, so opening it never closes another popover)
1167
+ * and is the button's `aria-describedby`, so the text is announced on focus.
1168
+ *
1169
+ * Do not put it inside a `<label>`, a heading or a link: `Field`, `PageHeader`, `Card` and
1170
+ * `SectionHead` place it beside those through their `help` prop.
1171
+ */
1172
+ declare function InfoTip({ content, ...props }: InfoTipProps): react.JSX.Element | null;
1173
+
1020
1174
  type StateVariant = 'section' | 'inline' | 'drawer' | 'page' | 'full-page';
1021
1175
  interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
1022
1176
  icon?: ReactNode;
@@ -1733,11 +1887,18 @@ interface SectionHeadProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'>
1733
1887
  title: ReactNode;
1734
1888
  /** id for the `<h2>`, for `aria-labelledby` wiring on the enclosing section. */
1735
1889
  titleId?: string;
1890
+ /**
1891
+ * Plain-text help behind a ? button after the title. Blank lines separate paragraphs;
1892
+ * empty, whitespace-only or `null` renders no button.
1893
+ */
1894
+ help?: string | null;
1895
+ /** Accessible name of the ? button. Default `"About: <title>"` when title is text; pass a localised one. */
1896
+ helpLabel?: string;
1736
1897
  /** Right-aligned slot — a `.uix-section-link` anchor, a button, a pill. */
1737
1898
  action?: ReactNode;
1738
1899
  }
1739
- /** Section head — title row with an optional trailing action (`.uix-section-head`). */
1740
- declare function SectionHead({ title, titleId, action, className, ...props }: SectionHeadProps): react.JSX.Element;
1900
+ /** Section head — title row (+ optional `help` ?) with an optional trailing action (`.uix-section-head`). */
1901
+ declare function SectionHead({ title, titleId, help, helpLabel, action, className, ...props }: SectionHeadProps): react.JSX.Element;
1741
1902
  interface NoticeQueueProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1742
1903
  /** Leading icon slot. */
1743
1904
  icon?: ReactNode;
@@ -2759,4 +2920,4 @@ declare function hsvToHex(value: HsvColor): string;
2759
2920
  declare function contrastRatio(background: string, foreground: string): number | undefined;
2760
2921
  declare function meetsContrast(background: string, foreground: string, minimum?: number): boolean;
2761
2922
 
2762
- export { type AccessStateProps, Alert, type AlertProps, type AlertTone, AppShell, type AppShellProps, type AppliedBrandProfileSnapshot, type AsyncOperationState, AsyncOperationStatus, type AsyncOperationStatusProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type BoundedRelationshipGraph, type BrandProfile, BrandProfileEditor, type BrandProfileEditorLabels, type BrandProfileEditorProps, type BrandProfileLogo, type BrandProfileTypography, BrandProfiles, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, BuilderCanvas, type BuilderCanvasItem, type BuilderCanvasLabels, type BuilderCanvasProps, type BuilderPaletteItem, BulkBar, type BulkBarProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type CalendarDay, Card, CardLink, type CardLinkProps, type CardProps, CellStrong, CellSub, Checkbox, type CheckboxProps, CollapsibleSection, type CollapsibleSectionProps, ColorPicker, type ColorPickerLabels, type ColorPickerProps, type ColumnFilter, Combobox, type ComboboxOption, type ComboboxProps, CommandGroup, type CommandGroupProps, CommandItem, type CommandItemProps, CommandPalette, type CommandPaletteProps, Comment, type CommentProps, Comments, type CommentsProps, Composer, ComposerBar, type ComposerBarProps, type ComposerProps, ConfirmDialog, type ConfirmDialogProps, ContentList, ContentListItem, type ContentListItemProps, type ContentListProps, CopyButton, type CopyButtonProps, DEFAULT_BRAND_PROFILE_EDITOR_LABELS, DEFAULT_BUILDER_CANVAS_LABELS, DEFAULT_COLOR_PICKER_LABELS, DEFAULT_DATE_RANGE_PICKER_LABELS, DEFAULT_DIFF_VIEWER_LABELS, DEFAULT_MATCH_REVIEW_LABELS, DEFAULT_PAGINATION_LABELS, DEFAULT_RELATIONSHIP_GRAPH_LABELS, DEFAULT_RULE_BUILDER_LABELS, DEFAULT_SAVE_STATUS_LABELS, DEFAULT_SCHEDULING_CALENDAR_LABELS, DateRangePicker, type DateRangePickerLabels, type DateRangePickerProps, type DateRangeValue, DescriptionItem, type DescriptionItemProps, DescriptionList, type DescriptionListItem, type DescriptionListProps, DetailLayout, type DetailLayoutProps, DetailPage, type DetailPageLinkProps, type DetailPageMetric, type DetailPageProps, type DetailPageTab, type DiffEntry, type DiffKind, type DiffResolution, type DiffSummary, DiffViewer, type DiffViewerLabels, type DiffViewerProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, EventRow, type EventRowProps, ExpandToggle, type ExpandToggleProps, FeaturedRundown, FeaturedRundownItem, type FeaturedRundownItemProps, type FeaturedRundownProps, FeaturedStage, type FeaturedStageProps, Field, type FieldProps, type FilterKind, type FilterOp, type FilterOption, FilterPopover, type FilterPopoverProps, FilteredEmptyState, type FlatNode, Flow, FlowNode, type FlowNodeProps, type FlowNodeState, type FlowProps, type FlowVariant, ForbiddenState, Highlighted, type HighlightedProps, type HsvColor, Inbox, InboxDetail, type InboxDetailProps, InboxItem, type InboxItemProps, InboxList, type InboxListProps, type InboxProps, Input, InputGroup, type InputGroupProps, type InputProps, type JsonPrimitive, type JsonValue, Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanMoveDirection, type KanbanProps, Label, type LabelProps, type LayeredColumn, type LayeredEdgeClassification, type LayeredEdgeKind, type LayeredItem, type LayeredLayout, type LayeredLayoutOptions, type LayeredNavigationKey, LicensePositionBar, type LicensePositionBarProps, List, ListItem, type ListItemProps, type ListProps, LoadingState, type LoadingStateProps, Mark, type MarkProps, type MatchBulkResult, MatchReview, type MatchReviewAction, type MatchReviewCandidate, type MatchReviewField, type MatchReviewLabels, type MatchReviewProps, Meter, type MeterProps, type MeterTone, MetricInput, type MetricInputProps, Modal, type ModalProps, type NavFavouriteItem, NavFavourites, type NavFavouritesLabels, type NavFavouritesProps, NavGroup, type NavGroupProps, NavItem, type NavItemProps, NewsLead, type NewsLeadProps, NotFoundState, Note, type NoteProps, type NoteTone, NoticeQueue, type NoticeQueueProps, PageHeader, type PageHeaderProps, PageIntro, type PageIntroProps, Pagination, type PaginationLabels, type PaginationProps, Peek, type PeekProps, type PillTone, type PillTreatment, Pipeline, type PipelineProps, PipelineStage, type PipelineStageProps, type PipelineStageState, Placement, Popover, type PopoverProps, type PositionedRelationshipNode, type Primitive, Progress, type ProgressProps, PromptDialog, type PromptDialogProps, Prose, type ProseProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, type RelatedLinkItem, RelatedLinks, type RelatedLinksProps, RelationshipGraph, type RelationshipGraphArrow, type RelationshipGraphCluster, type RelationshipGraphEdge, type RelationshipGraphLabels, type RelationshipGraphLegendItem, type RelationshipGraphNode, type RelationshipGraphProps, RelativeTime, type RelativeTimeFormatContext, type RelativeTimeProps, type RelativeTimeUnit, type RelativeTimeValue, ResourceGrid, type ResourceGridProps, type RgbColor, type RoutedEdge, type Row, RowAction, type RowActionProps, RowActions, type RowActionsProps, type RuleAction, type RuleActionDefinition, RuleBuilder, type RuleBuilderLabels, type RuleBuilderProps, type RuleCondition, type RuleDefinition, type RuleFieldDefinition, type RuleGroup, type RuleOperatorDefinition, type RuleValidationIssue, type RuleValueEditorProps, SaveStatus, type SaveStatusLabels, type SaveStatusProps, type SaveStatusState, type SavedViewItem, SavedViewMenu, type SavedViewMenuProps, type SavedViewSection, SchedulingCalendar, type SchedulingCalendarEntry, type SchedulingCalendarLabels, type SchedulingCalendarOverlay, type SchedulingCalendarProps, type SchedulingCalendarView, type SchedulingEntryState, type SchedulingOverlayKind, SectionHead, type SectionHeadProps, type Segment, Segmented, SegmentedOption, type SegmentedOptionProps, type SegmentedProps, Select, type SelectAllState, type SelectProps, type ShellNav, Sidebar, type SidebarProps, SidebarSection, type SidebarSectionProps, Skeleton, type SkeletonProps, type SortDir, type SortDirection, type SortKey, Spinner, type SpinnerProps, StarButton, type StarButtonProps, Stat, StatLine, type StatLineItem, type StatLineProps, type StatProps, type StatTrend, type StateVariant, StatusPill, type StatusPillProps, StatusRow, type StatusRowProps, SubNavItem, type SubNavItemProps, Switch, type SwitchProps, Tab, TabPanel, type TabPanelProps, type TabProps, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Tabs, type TabsProps, Td, type TdProps, Textarea, type TextareaProps, Th, type ThProps, Timeline, TimelineItem, type TimelineItemProps, type TimelineProps, Toast, type ToastProps, type ToastTone, Toaster, type ToasterProps, ToggleRow, type ToggleRowProps, Tooltip, type TooltipProps, Tr, type TrProps, Tree, type TreeLike, type TreeNavAction, type TreeNodeData, type TreeNodeProps, type TreeProps, type UseAnchoredPositionOptions, type UseTableOptions, type UseTableResult, type UseVirtualRowsOptions, type UseVirtualRowsResult, UserChip, type UserChipProps, ViewMenu, type ViewMenuColumn, type ViewMenuColumnLabels, type ViewMenuProps, type ViewState, type VirtualWindow, type ZonedDateSpan, addCalendarDays, addCalendarMonths, appendRuleNode, applyBrandProfile, applyFilters, boundRelationshipGraph, buildMonthGrid, buildThreeWayDiff, clampMetricValue, clampWidth, classifyLayeredEdges, clusterIdFor, contrastRatio, cx, enumerateDateSpan, filterComboboxOptions, findRuleNodeDepth, flattenTree, hexToRgb, highlightSegments, hsvToHex, hsvToRgb, isDateInRange, isDateUnavailable, isRuleGroup, layeredNeighbor, layoutLayeredGraph, layoutRelationshipGraph, mapRuleGroup, matchFilter, meetsContrast, mergePinned, moveRuleNode, multiSort, nextSortDir, normalizeHex, parseDateValue, parseMetricValue, parseView, relationshipNeighbors, relativeTimeValue, removeRuleNode, reorder, restoreBrandProfile, rgbToHex, rgbToHsv, ruleDepth, searchRows, selectAllState, selectRangeDate, serializeView, shouldVirtualize, startOfMonth, stepMetricValue, summarizeDiff, summarizeRule, toDateKey, toggleId, togglePage, toggleSort, traverseRelationshipNode, treeNav, useAnchoredPosition, useDialog, useTable, useVirtualRows, validateRuleDefinition, virtualWindow, wrapEdgeLabel, zonedDateKey, zonedDateSpan };
2923
+ export { type AccessStateProps, Alert, type AlertProps, type AlertTone, AppShell, type AppShellProps, type AppliedBrandProfileSnapshot, type AsyncOperationState, AsyncOperationStatus, type AsyncOperationStatusProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type BoundedRelationshipGraph, type BrandProfile, BrandProfileEditor, type BrandProfileEditorLabels, type BrandProfileEditorProps, type BrandProfileLogo, type BrandProfileTypography, BrandProfiles, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, BuilderCanvas, type BuilderCanvasItem, type BuilderCanvasLabels, type BuilderCanvasProps, type BuilderPaletteItem, BulkBar, type BulkBarProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type CalendarDay, Card, CardLink, type CardLinkProps, type CardProps, CellStrong, CellSub, Checkbox, type CheckboxProps, CollapsibleSection, type CollapsibleSectionProps, ColorPicker, type ColorPickerLabels, type ColorPickerProps, type ColumnFilter, Combobox, type ComboboxOption, type ComboboxProps, CommandGroup, type CommandGroupProps, CommandItem, type CommandItemProps, CommandPalette, type CommandPaletteProps, Comment, type CommentProps, Comments, type CommentsProps, Composer, ComposerBar, type ComposerBarProps, type ComposerProps, ConfirmDialog, type ConfirmDialogProps, ContentList, ContentListItem, type ContentListItemProps, type ContentListProps, CopyButton, type CopyButtonProps, DEFAULT_BRAND_PROFILE_EDITOR_LABELS, DEFAULT_BUILDER_CANVAS_LABELS, DEFAULT_COLOR_PICKER_LABELS, DEFAULT_DATE_RANGE_PICKER_LABELS, DEFAULT_DIFF_VIEWER_LABELS, DEFAULT_MATCH_REVIEW_LABELS, DEFAULT_PAGINATION_LABELS, DEFAULT_RELATIONSHIP_GRAPH_LABELS, DEFAULT_RULE_BUILDER_LABELS, DEFAULT_SAVE_STATUS_LABELS, DEFAULT_SCHEDULING_CALENDAR_LABELS, DateRangePicker, type DateRangePickerLabels, type DateRangePickerProps, type DateRangeValue, DescriptionItem, type DescriptionItemProps, DescriptionList, type DescriptionListItem, type DescriptionListProps, DetailLayout, type DetailLayoutProps, DetailPage, type DetailPageLinkProps, type DetailPageMetric, type DetailPageProps, type DetailPageTab, type DiffEntry, type DiffKind, type DiffResolution, type DiffSummary, DiffViewer, type DiffViewerLabels, type DiffViewerProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, EventRow, type EventRowProps, ExpandToggle, type ExpandToggleProps, FeaturedRundown, FeaturedRundownItem, type FeaturedRundownItemProps, type FeaturedRundownProps, FeaturedStage, type FeaturedStageProps, Field, type FieldProps, type FilterKind, type FilterOp, type FilterOption, FilterPopover, type FilterPopoverProps, FilteredEmptyState, type FlatNode, Flow, FlowNode, type FlowNodeProps, type FlowNodeState, type FlowProps, type FlowVariant, type FoldedText, ForbiddenState, Highlighted, type HighlightedProps, type HsvColor, Inbox, InboxDetail, type InboxDetailProps, InboxItem, type InboxItemProps, InboxList, type InboxListProps, type InboxProps, InfoTip, type InfoTipProps, Input, InputGroup, type InputGroupProps, type InputProps, type JsonPrimitive, type JsonValue, Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanMoveDirection, type KanbanProps, Label, type LabelProps, type LayeredColumn, type LayeredEdgeClassification, type LayeredEdgeKind, type LayeredItem, type LayeredLayout, type LayeredLayoutOptions, type LayeredNavigationKey, LicensePositionBar, type LicensePositionBarProps, List, ListItem, type ListItemProps, type ListProps, LoadingState, type LoadingStateProps, Mark, type MarkProps, type MatchBulkResult, MatchReview, type MatchReviewAction, type MatchReviewCandidate, type MatchReviewField, type MatchReviewLabels, type MatchReviewProps, Meter, type MeterProps, type MeterTone, MetricInput, type MetricInputProps, Modal, type ModalProps, type NavFavouriteItem, NavFavourites, type NavFavouritesLabels, type NavFavouritesProps, NavGroup, type NavGroupProps, NavItem, type NavItemProps, NewsLead, type NewsLeadProps, NotFoundState, Note, type NoteProps, type NoteTone, NoticeQueue, type NoticeQueueProps, PageHeader, type PageHeaderProps, PageIntro, type PageIntroProps, Pagination, type PaginationLabels, type PaginationProps, Peek, type PeekProps, type PillTone, type PillTreatment, Pipeline, type PipelineProps, PipelineStage, type PipelineStageProps, type PipelineStageState, Placement, Popover, type PopoverProps, type PositionedRelationshipNode, type Primitive, Progress, type ProgressProps, PromptDialog, type PromptDialogProps, Prose, type ProseProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, type RelatedLinkItem, RelatedLinks, type RelatedLinksProps, RelationshipGraph, type RelationshipGraphArrow, type RelationshipGraphCluster, type RelationshipGraphEdge, type RelationshipGraphLabels, type RelationshipGraphLegendItem, type RelationshipGraphNode, type RelationshipGraphProps, RelativeTime, type RelativeTimeFormatContext, type RelativeTimeProps, type RelativeTimeUnit, type RelativeTimeValue, ResourceGrid, type ResourceGridProps, type RgbColor, type RoutedEdge, type Row, RowAction, type RowActionProps, RowActions, type RowActionsProps, type RuleAction, type RuleActionDefinition, RuleBuilder, type RuleBuilderLabels, type RuleBuilderProps, type RuleCondition, type RuleDefinition, type RuleFieldDefinition, type RuleGroup, type RuleOperatorDefinition, type RuleValidationIssue, type RuleValueEditorProps, SaveStatus, type SaveStatusLabels, type SaveStatusProps, type SaveStatusState, type SavedViewItem, SavedViewMenu, type SavedViewMenuProps, type SavedViewSection, SchedulingCalendar, type SchedulingCalendarEntry, type SchedulingCalendarLabels, type SchedulingCalendarOverlay, type SchedulingCalendarProps, type SchedulingCalendarView, type SchedulingEntryState, type SchedulingOverlayKind, type SearchSegment, SearchSuggest, type SearchSuggestAction, type SearchSuggestOption, type SearchSuggestProps, SectionHead, type SectionHeadProps, type Segment, Segmented, SegmentedOption, type SegmentedOptionProps, type SegmentedProps, Select, type SelectAllState, type SelectProps, type ShellNav, Sidebar, type SidebarProps, SidebarSection, type SidebarSectionProps, Skeleton, type SkeletonProps, type SortDir, type SortDirection, type SortKey, Spinner, type SpinnerProps, StarButton, type StarButtonProps, Stat, StatLine, type StatLineItem, type StatLineProps, type StatProps, type StatTrend, type StateVariant, StatusPill, type StatusPillProps, StatusRow, type StatusRowProps, SubNavItem, type SubNavItemProps, Switch, type SwitchProps, Tab, TabPanel, type TabPanelProps, type TabProps, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Tabs, type TabsProps, Td, type TdProps, Textarea, type TextareaProps, Th, type ThProps, Timeline, TimelineItem, type TimelineItemProps, type TimelineProps, Toast, type ToastProps, type ToastTone, Toaster, type ToasterProps, ToggleRow, type ToggleRowProps, Tooltip, type TooltipProps, Tr, type TrProps, Tree, type TreeLike, type TreeNavAction, type TreeNodeData, type TreeNodeProps, type TreeProps, type UseAnchoredPositionOptions, type UseTableOptions, type UseTableResult, type UseVirtualRowsOptions, type UseVirtualRowsResult, UserChip, type UserChipProps, ViewMenu, type ViewMenuColumn, type ViewMenuColumnLabels, type ViewMenuProps, type ViewState, type VirtualWindow, type ZonedDateSpan, addCalendarDays, addCalendarMonths, appendRuleNode, applyBrandProfile, applyFilters, boundRelationshipGraph, buildMonthGrid, buildThreeWayDiff, clampMetricValue, clampWidth, classifyLayeredEdges, clusterIdFor, contrastRatio, cx, enumerateDateSpan, filterComboboxOptions, findRuleNodeDepth, flattenTree, foldForSearch, hexToRgb, highlightSegments, hsvToHex, hsvToRgb, isDateInRange, isDateUnavailable, isRuleGroup, layeredNeighbor, layoutLayeredGraph, layoutRelationshipGraph, mapRuleGroup, matchFilter, meetsContrast, mergePinned, moveRuleNode, multiSort, nextSortDir, normalizeHex, parseDateValue, parseMetricValue, parseView, relationshipNeighbors, relativeTimeValue, removeRuleNode, reorder, restoreBrandProfile, rgbToHex, rgbToHsv, ruleDepth, searchRows, searchSegments, selectAllState, selectRangeDate, serializeView, shouldVirtualize, startOfMonth, stepMetricValue, summarizeDiff, summarizeRule, toDateKey, toggleId, togglePage, toggleSort, traverseRelationshipNode, treeNav, useAnchoredPosition, useDialog, useTable, useVirtualRows, validateRuleDefinition, virtualWindow, wrapEdgeLabel, zonedDateKey, zonedDateSpan };
package/dist/index.d.ts CHANGED
@@ -8,6 +8,8 @@ export { Button, ButtonGroup, ButtonGroupProps, ButtonProps } from './components
8
8
  export { Input, InputGroup, InputGroupProps, InputProps } from './components/Input.js';
9
9
  export { Combobox, ComboboxProps } from './components/Combobox.js';
10
10
  export { ComboboxOption, filterComboboxOptions } from './combobox-model.js';
11
+ export { SearchSuggest, SearchSuggestAction, SearchSuggestOption, SearchSuggestProps } from './components/SearchSuggest.js';
12
+ export { FoldedText, SearchSegment, foldForSearch, searchSegments } from './search-suggest-model.js';
11
13
  export { Textarea, TextareaProps } from './components/Textarea.js';
12
14
  export { Select, SelectProps } from './components/Select.js';
13
15
  export { Checkbox, CheckboxProps } from './components/Checkbox.js';
@@ -45,6 +47,7 @@ export { Progress, ProgressProps } from './components/Progress.js';
45
47
  export { Meter, MeterProps, MeterTone } from './components/Meter.js';
46
48
  export { Stat, StatProps, StatTrend } from './components/Stat.js';
47
49
  export { Tooltip, TooltipProps } from './components/Tooltip.js';
50
+ export { InfoTip, InfoTipProps } from './components/InfoTip.js';
48
51
  export { AccessStateProps, EmptyState, EmptyStateProps, ErrorState, ErrorStateProps, FilteredEmptyState, ForbiddenState, LoadingState, LoadingStateProps, NotFoundState, Skeleton, SkeletonProps, StateVariant } from './components/States.js';
49
52
  export { RelativeTime, RelativeTimeFormatContext, RelativeTimeProps } from './components/RelativeTime.js';
50
53
  export { RelativeTimeUnit, RelativeTimeValue, parseDateValue, relativeTimeValue } from './relative-time-model.js';
package/dist/index.js CHANGED
@@ -8,6 +8,8 @@ import { Button, ButtonGroup } from "./components/Button.js";
8
8
  import { Input, InputGroup } from "./components/Input.js";
9
9
  import { Combobox } from "./components/Combobox.js";
10
10
  import { filterComboboxOptions } from "./combobox-model.js";
11
+ import { SearchSuggest } from "./components/SearchSuggest.js";
12
+ import { searchSegments, foldForSearch } from "./search-suggest-model.js";
11
13
  import { Textarea } from "./components/Textarea.js";
12
14
  import { Select } from "./components/Select.js";
13
15
  import { Checkbox } from "./components/Checkbox.js";
@@ -59,6 +61,7 @@ import { Progress } from "./components/Progress.js";
59
61
  import { Meter } from "./components/Meter.js";
60
62
  import { Stat } from "./components/Stat.js";
61
63
  import { Tooltip } from "./components/Tooltip.js";
64
+ import { InfoTip } from "./components/InfoTip.js";
62
65
  import { EmptyState, ErrorState, ForbiddenState, NotFoundState, FilteredEmptyState, Skeleton, LoadingState } from "./components/States.js";
63
66
  import { RelativeTime } from "./components/RelativeTime.js";
64
67
  import { parseDateValue, relativeTimeValue } from "./relative-time-model.js";
@@ -202,6 +205,7 @@ export {
202
205
  InboxDetail,
203
206
  InboxItem,
204
207
  InboxList,
208
+ InfoTip,
205
209
  Input,
206
210
  InputGroup,
207
211
  Kanban,
@@ -246,6 +250,7 @@ export {
246
250
  SaveStatus,
247
251
  SavedViewMenu,
248
252
  SchedulingCalendar,
253
+ SearchSuggest,
249
254
  SectionHead,
250
255
  Segmented,
251
256
  SegmentedOption,
@@ -296,6 +301,7 @@ export {
296
301
  filterComboboxOptions,
297
302
  findRuleNodeDepth,
298
303
  flattenTree,
304
+ foldForSearch,
299
305
  hexToRgb,
300
306
  hsvToHex,
301
307
  hsvToRgb,
@@ -318,6 +324,7 @@ export {
318
324
  rgbToHex,
319
325
  rgbToHsv,
320
326
  ruleDepth,
327
+ searchSegments,
321
328
  selectRangeDate,
322
329
  startOfMonth,
323
330
  stepMetricValue,
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ /** Blank lines (any whitespace between two line breaks) separate paragraphs; empty paragraphs drop. */
4
+ declare const helpParagraphs: (content: unknown) => string[];
5
+ /** True when `help` would render an InfoTip, so a slot can skip its wrapper row. */
6
+ declare const hasHelp: (help: unknown) => help is string;
7
+ /** Default accessible name for a `help` slot: "About: <title>" for text titles. */
8
+ declare const helpLabelFor: (thing: ReactNode) => string;
9
+
10
+ export { hasHelp, helpLabelFor, helpParagraphs };
@@ -0,0 +1,8 @@
1
+ const helpParagraphs = (content) => typeof content === "string" ? content.replace(/\r\n?/g, "\n").split(/\n\s*\n/).map((p) => p.trim()).filter(Boolean) : [];
2
+ const hasHelp = (help) => helpParagraphs(help).length > 0;
3
+ const helpLabelFor = (thing) => typeof thing === "string" || typeof thing === "number" ? `About: ${thing}` : "More information";
4
+ export {
5
+ hasHelp,
6
+ helpLabelFor,
7
+ helpParagraphs
8
+ };
@@ -1674,6 +1674,7 @@ var DEFAULT_RICH_TEXT_LABELS = {
1674
1674
  image: "Image",
1675
1675
  imageUploading: "Uploading image\u2026",
1676
1676
  imageFailed: "The image could not be added.",
1677
+ imagesUnsupported: "Images can't be added here.",
1677
1678
  emoji: "Emoji",
1678
1679
  emojiSuggestions: "Emoji suggestions",
1679
1680
  undo: "Undo",
@@ -1685,8 +1686,9 @@ var DEFAULT_RICH_TEXT_LABELS = {
1685
1686
  var COMMON = ["bold", "italic", "strike", "code", "bulletList", "orderedList", "taskList", "blockquote", "codeBlock", "link", "emoji", "history", "source"];
1686
1687
  var PRESETS = {
1687
1688
  full: /* @__PURE__ */ new Set([...COMMON, "heading", "horizontalRule", "table", "image"]),
1688
- comment: new Set(COMMON),
1689
- template: /* @__PURE__ */ new Set([...COMMON, "heading", "horizontalRule", "table"])
1689
+ // Images in every preset once the consumer supplies onUploadImage (TENSOR HAR-749).
1690
+ comment: /* @__PURE__ */ new Set([...COMMON, "image"]),
1691
+ template: /* @__PURE__ */ new Set([...COMMON, "heading", "horizontalRule", "table", "image"])
1690
1692
  };
1691
1693
  var emojiSuggestionKey = new import_state.PluginKey("uixEmojiSuggestion");
1692
1694
  var SHORTCODE_RE = /:([a-zA-Z0-9_+-]+):$/;
@@ -1802,7 +1804,8 @@ function RichTextEditor(props) {
1802
1804
  minRows,
1803
1805
  className,
1804
1806
  onBlur,
1805
- emojiImageBaseUrl
1807
+ emojiImageBaseUrl,
1808
+ imagesUnavailableReason
1806
1809
  } = props;
1807
1810
  const emojiBase = (0, import_react7.useMemo)(() => normalizeEmojiImageBaseUrl(emojiImageBaseUrl), [emojiImageBaseUrl]);
1808
1811
  const renderEmoji = useEmojiRenderer(emojiImageBaseUrl);
@@ -1814,7 +1817,7 @@ function RichTextEditor(props) {
1814
1817
  const linkPopoverId = `${uid}-link`;
1815
1818
  const controls = PRESETS[features];
1816
1819
  const has = (control) => controls.has(control) && (control !== "emoji" || emoji) && (control !== "image" || !!onUploadImage);
1817
- const latest = (0, import_react7.useRef)({ onChange, onSubmitShortcut, onBlur, isSafeUrl, resolveImageSrc, onUploadImage, placeholder, imagesOn: false });
1820
+ const latest = (0, import_react7.useRef)({ onChange, onSubmitShortcut, onBlur, isSafeUrl, resolveImageSrc, onUploadImage, placeholder, imagesOn: false, imagesOffText: "" });
1818
1821
  latest.current = {
1819
1822
  onChange,
1820
1823
  onSubmitShortcut,
@@ -1823,7 +1826,8 @@ function RichTextEditor(props) {
1823
1826
  resolveImageSrc,
1824
1827
  onUploadImage,
1825
1828
  placeholder,
1826
- imagesOn: controls.has("image") && !!onUploadImage
1829
+ imagesOn: controls.has("image") && !!onUploadImage,
1830
+ imagesOffText: imagesUnavailableReason?.trim() || labels.imagesUnsupported
1827
1831
  };
1828
1832
  const lastValue = (0, import_react7.useRef)(value);
1829
1833
  const origin = (0, import_react7.useRef)(null);
@@ -2046,22 +2050,31 @@ function RichTextEditor(props) {
2046
2050
  shouldRerenderOnTransaction: false,
2047
2051
  editable: !disabled && !readOnly,
2048
2052
  editorProps: {
2053
+ // An image file pasted or dropped where images are off used to vanish silently; now the
2054
+ // status line says so (TENSOR HAR-749). A paste that also carries text is a text paste:
2055
+ // Excel, Word and Docs add a PNG rendering of the copied cells or text, which must not
2056
+ // replace (or block) the text itself.
2049
2057
  handlePaste: (_view, event) => {
2050
- const files = Array.from(event.clipboardData?.files ?? []).filter((f) => f.type.startsWith("image/"));
2051
- if (!files.length || !latest.current.imagesOn || !editorRef.current) return false;
2052
- files.forEach((file) => void uploadImage(editorRef.current, file));
2058
+ const data = event.clipboardData;
2059
+ const files = Array.from(data?.files ?? []).filter((f) => f.type.startsWith("image/"));
2060
+ if (!files.length || !editorRef.current || data?.getData("text/plain").trim()) return false;
2061
+ event.preventDefault();
2062
+ if (!latest.current.imagesOn) setStatus({ kind: "notice", text: latest.current.imagesOffText });
2063
+ else files.forEach((file) => void uploadImage(editorRef.current, file));
2053
2064
  return true;
2054
2065
  },
2055
2066
  handleDrop: (_view, event) => {
2056
2067
  const files = Array.from(event.dataTransfer?.files ?? []).filter((f) => f.type.startsWith("image/"));
2057
- if (!files.length || !latest.current.imagesOn || !editorRef.current) return false;
2068
+ if (!files.length || !editorRef.current) return false;
2058
2069
  event.preventDefault();
2059
- files.forEach((file) => void uploadImage(editorRef.current, file));
2070
+ if (!latest.current.imagesOn) setStatus({ kind: "notice", text: latest.current.imagesOffText });
2071
+ else files.forEach((file) => void uploadImage(editorRef.current, file));
2060
2072
  return true;
2061
2073
  }
2062
2074
  },
2063
2075
  onCreate: ({ editor: ed }) => load(ed, lastValue.current),
2064
2076
  onUpdate: ({ editor: ed }) => {
2077
+ setStatus((s) => s?.kind === "notice" ? null : s);
2065
2078
  if (!origin.current) return;
2066
2079
  emit(writeMarkdown(ed.getJSON(), origin.current, managerOf(ed)));
2067
2080
  },
@@ -38,6 +38,8 @@ interface RichTextLabels {
38
38
  image: string;
39
39
  imageUploading: string;
40
40
  imageFailed: string;
41
+ /** Shown when an image is pasted or dropped where images are off (default for `imagesUnavailableReason`). */
42
+ imagesUnsupported: string;
41
43
  emoji: string;
42
44
  /** Accessible name of the `:shortcode` suggestion list. */
43
45
  emojiSuggestions: string;
@@ -64,11 +66,17 @@ interface RichTextEditorProps {
64
66
  features?: RichTextFeatures;
65
67
  /** Heading levels the toolbar and input rules offer. Default `[1, 2, 3]`. */
66
68
  headingLevels?: ReadonlyArray<RichTextHeadingLevel>;
67
- /** Enables the image button (preset `full`), and image paste/drop. */
69
+ /** Enables image paste/drop and the toolbar image button, in every preset. */
68
70
  onUploadImage?: (file: File) => Promise<{
69
71
  src: string;
70
72
  alt: string;
71
73
  }>;
74
+ /**
75
+ * Shown in the status line when an image is pasted or dropped while images are off (no
76
+ * `onUploadImage`), e.g. "Attach files to the incident instead.". Nothing is inserted.
77
+ * Default: the `imagesUnsupported` label.
78
+ */
79
+ imagesUnavailableReason?: string;
72
80
  /** Link policy. Default: http(s), mailto and same-app paths. */
73
81
  isSafeUrl?: (url: string) => boolean;
74
82
  /** Image policy: the URL to display, or `null` to show the image as a link chip. */
@@ -0,0 +1,20 @@
1
+ /** One run of a result's text, emphasised or not. */
2
+ interface SearchSegment {
3
+ text: string;
4
+ match: boolean;
5
+ }
6
+ /** Text folded for matching, with a map back to the original characters. */
7
+ interface FoldedText {
8
+ /** The folded text: lower case, diacritics stripped, ß → ss. */
9
+ text: string;
10
+ /** For each index of `text`, the start index of the original character it came from. */
11
+ source: number[];
12
+ /** For each index of `text`, the end index (exclusive) of that original character. */
13
+ sourceEnd: number[];
14
+ }
15
+ /** Fold `text` for matching and keep a map back to the original indices. */
16
+ declare function foldForSearch(text: string): FoldedText;
17
+ /** Split `text` into matched and unmatched segments for `query`. */
18
+ declare function searchSegments(text: string, query: string): SearchSegment[];
19
+
20
+ export { type FoldedText, type SearchSegment, foldForSearch, searchSegments };
@@ -0,0 +1,74 @@
1
+ const COMBINING_MARK = /\p{M}/u;
2
+ function foldForSearch(text) {
3
+ let folded = "";
4
+ const source = [];
5
+ const sourceEnd = [];
6
+ let index = 0;
7
+ for (const char of text) {
8
+ const base = char === "\xDF" || char === "\u1E9E" ? "ss" : char.toLowerCase().normalize("NFD");
9
+ for (const part of base) {
10
+ if (COMBINING_MARK.test(part)) continue;
11
+ folded += part;
12
+ for (let i = 0; i < part.length; i += 1) {
13
+ source.push(index);
14
+ sourceEnd.push(index + char.length);
15
+ }
16
+ }
17
+ index += char.length;
18
+ }
19
+ return { text: folded, source, sourceEnd };
20
+ }
21
+ const isWordStart = (text, at) => at === 0 || /[\s\-_/.,:;()[\]'"›>·|]/u.test(text[at - 1] ?? "");
22
+ function foldedRanges(haystack, query) {
23
+ const whole = query.trim();
24
+ if (!whole) return [];
25
+ const out = [];
26
+ let from = haystack.indexOf(whole);
27
+ if (from !== -1) {
28
+ while (from !== -1) {
29
+ out.push([from, from + whole.length]);
30
+ from = haystack.indexOf(whole, from + whole.length);
31
+ }
32
+ return out;
33
+ }
34
+ for (const token of whole.split(/\s+/)) {
35
+ for (let at = haystack.indexOf(token); at !== -1; at = haystack.indexOf(token, at + 1)) {
36
+ if (isWordStart(haystack, at)) out.push([at, at + token.length]);
37
+ }
38
+ }
39
+ return out;
40
+ }
41
+ function merge(ranges) {
42
+ const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
43
+ const out = [];
44
+ for (const range of sorted) {
45
+ const last = out[out.length - 1];
46
+ if (last && range[0] <= last[1]) last[1] = Math.max(last[1], range[1]);
47
+ else out.push([range[0], range[1]]);
48
+ }
49
+ return out;
50
+ }
51
+ function searchSegments(text, query) {
52
+ const foldedQuery = foldForSearch(query).text;
53
+ if (!text || !foldedQuery.trim()) return [{ text, match: false }];
54
+ const folded = foldForSearch(text);
55
+ const ranges = merge(
56
+ foldedRanges(folded.text, foldedQuery).map(
57
+ ([start, end]) => [folded.source[start] ?? 0, folded.sourceEnd[end - 1] ?? text.length]
58
+ )
59
+ );
60
+ if (ranges.length === 0) return [{ text, match: false }];
61
+ const out = [];
62
+ let cursor = 0;
63
+ for (const [start, end] of ranges) {
64
+ if (start > cursor) out.push({ text: text.slice(cursor, start), match: false });
65
+ out.push({ text: text.slice(start, end), match: true });
66
+ cursor = end;
67
+ }
68
+ if (cursor < text.length) out.push({ text: text.slice(cursor), match: false });
69
+ return out;
70
+ }
71
+ export {
72
+ foldForSearch,
73
+ searchSegments
74
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tensor_1/react",
3
- "version": "2.24.0",
3
+ "version": "2.26.0",
4
4
  "description": "Thin React wrappers over the UIx v2 CSS component library.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",