@stll/ui 0.66.0 → 0.68.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.
Files changed (70) hide show
  1. package/dist/calendar/day-calendar.js +2 -2
  2. package/dist/components/alert-dialog.js +1 -1
  3. package/dist/components/animated-preview.js +1 -1
  4. package/dist/components/application-rail.js +1 -1
  5. package/dist/components/button.js +2 -2
  6. package/dist/components/checkbox.js +2 -2
  7. package/dist/components/color-picker.js +4 -4
  8. package/dist/components/combobox.js +4 -4
  9. package/dist/components/command.js +3 -3
  10. package/dist/components/composer.js +1 -1
  11. package/dist/components/context-menu.d.ts +10 -1
  12. package/dist/components/context-menu.js +9 -2
  13. package/dist/components/court-filter.js +2 -2
  14. package/dist/components/date-picker-popover.js +3 -3
  15. package/dist/components/destructive-action-confirmation.js +1 -1
  16. package/dist/components/details-grid.js +1 -1
  17. package/dist/components/dialog.js +3 -3
  18. package/dist/components/document-identity-badge.js +1 -1
  19. package/dist/components/entity-actions.d.ts +34 -0
  20. package/dist/components/entity-actions.js +132 -0
  21. package/dist/components/file-input.js +1 -1
  22. package/dist/components/hex-color-picker.js +1 -1
  23. package/dist/components/horizontal-scroller.js +2 -2
  24. package/dist/components/identity-text.js +1 -1
  25. package/dist/components/inline-rename.js +1 -1
  26. package/dist/components/input-group.js +3 -3
  27. package/dist/components/input.js +2 -2
  28. package/dist/components/kbd.js +1 -1
  29. package/dist/components/matter-icon.js +1 -1
  30. package/dist/components/menu.js +2 -2
  31. package/dist/components/number-input.js +1 -1
  32. package/dist/components/outline-rail.js +4 -4
  33. package/dist/components/popover.js +1 -1
  34. package/dist/components/segmented-icon-toggle.js +1 -1
  35. package/dist/components/select.js +3 -3
  36. package/dist/components/sheet.js +2 -2
  37. package/dist/components/sheet.native.js +1 -1
  38. package/dist/components/sidebar.js +4 -4
  39. package/dist/components/split-button.js +1 -1
  40. package/dist/components/table.js +1 -1
  41. package/dist/components/tabs.js +1 -1
  42. package/dist/components/textarea.js +2 -2
  43. package/dist/components/toast.js +3 -3
  44. package/dist/components/tooltip.js +1 -1
  45. package/dist/components/truncated-text.js +2 -2
  46. package/dist/components/view-toolbar.d.ts +5 -1
  47. package/dist/components/view-toolbar.js +6 -2
  48. package/dist/components/workspace-shell.js +3 -3
  49. package/dist/data-table/table.js +1 -1
  50. package/dist/index.js +34 -34
  51. package/dist/inspector/chrome.js +1 -1
  52. package/dist/inspector/dock.js +1 -1
  53. package/dist/inspector/entity-tab.js +2 -2
  54. package/dist/inspector/facet-bar.js +4 -4
  55. package/dist/inspector/index.js +2 -2
  56. package/dist/kanban/card-shell.js +1 -1
  57. package/dist/kanban/cell-action.js +1 -1
  58. package/dist/kanban/column-band-header.js +1 -1
  59. package/dist/kanban/index.js +5 -5
  60. package/dist/kanban/sortable-interactions.js +2 -2
  61. package/dist/kanban/subgroup-board.js +4 -4
  62. package/dist/kanban/virtual-cell.js +2 -2
  63. package/dist/lib/native-context-menu.d.ts +24 -0
  64. package/dist/lib/native-context-menu.js +85 -0
  65. package/dist/review/review-author-avatar.js +1 -1
  66. package/dist/review/review-comment-card.js +2 -2
  67. package/dist/review/review-decision-actions.js +1 -1
  68. package/dist/review/review-out-of-date-notice.js +1 -1
  69. package/dist/styles/theme.css +23 -23
  70. package/package.json +14 -6
@@ -1,7 +1,7 @@
1
- import { cn } from "../lib/utils.js";
2
1
  import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "../components/tooltip.js";
3
- import { DAY_CALENDAR_SLOT_HEIGHT_PX, boundsHeight, extendRange, getDayBounds, getHourTicks, isRepeatedWallTime, layoutOverlaps, moveRange, offsetToTime, rangeFromDrag, slotAt, timeToOffset } from "./day-calendar.logic.js";
4
2
  import { getMatterColor, resolveMatterColor } from "../lib/matter-colors.js";
3
+ import { cn } from "../lib/utils.js";
4
+ import { DAY_CALENDAR_SLOT_HEIGHT_PX, boundsHeight, extendRange, getDayBounds, getHourTicks, isRepeatedWallTime, layoutOverlaps, moveRange, offsetToTime, rangeFromDrag, slotAt, timeToOffset } from "./day-calendar.logic.js";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useState } from "react";
7
7
  import { panic } from "better-result";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
3
2
  import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
4
3
  import { SAFE_AREA_OVERLAY_GUTTER_CLASS_NAME } from "../lib/safe-area.js";
4
+ import { cn } from "../lib/utils.js";
5
5
  import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
+ import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
2
3
  import { cn } from "../lib/utils.js";
3
4
  import { HoverCard as PreviewCard, HoverCardContent as PreviewCardPopup, HoverCardTrigger as PreviewCardTrigger } from "./preview-card.js";
4
- import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import * as React$1 from "react";
7
7
  // src/components/animated-preview.tsx
@@ -1,5 +1,5 @@
1
- import { cn } from "../lib/utils.js";
2
1
  import { TOOLBAR_ROW_HEIGHT } from "../inspector/layout-tokens.js";
2
+ import { cn } from "../lib/utils.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  // src/components/application-rail.tsx
5
5
  const APPLICATION_RAIL_WIDTH = "w-12";
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
3
- import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
4
2
  import { BUTTON_DISPOSITION, blockDisabledActivation, blockDisabledKeyActivation, resolveButtonDisposition } from "../lib/button-disposition.js";
5
3
  import { MENU_ROW_CLASS_NAME } from "../lib/menu-row.js";
6
4
  import { rendersNothing } from "../lib/renders-nothing.js";
5
+ import { cn } from "../lib/utils.js";
7
6
  import { BUTTON_PLAIN_VARIANT, BUTTON_VARIANT_TOKENS } from "./button.shared.js";
8
7
  import { Loader } from "./loader.js";
8
+ import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  import { Fragment as Fragment$1, isValidElement } from "react";
11
11
  import { mergeProps } from "@base-ui/react/merge-props";
@@ -4,11 +4,11 @@ import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { Checkbox as Checkbox$1 } from "@base-ui/react/checkbox";
5
5
  // src/components/checkbox.tsx
6
6
  const Checkbox = ({ className, ...props }) => /* @__PURE__ */ jsx(Checkbox$1.Root, {
7
- className: cn("border-input bg-background ring-ring focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-[4px] border shadow-xs/5 outline-none not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[3px] not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-2 focus-visible:ring-offset-1 data-disabled:opacity-64 sm:size-4 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none", className),
7
+ className: cn("border-input bg-background ring-ring focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-sm border shadow-xs/5 outline-none not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-sm)-1px)] not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-2 focus-visible:ring-offset-1 data-disabled:opacity-64 sm:size-4 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none", className),
8
8
  "data-slot": "checkbox",
9
9
  ...props,
10
10
  children: /* @__PURE__ */ jsx(Checkbox$1.Indicator, {
11
- className: "text-primary-foreground data-checked:bg-primary data-indeterminate:text-foreground absolute -inset-px flex items-center justify-center rounded-[4px] data-unchecked:hidden",
11
+ className: "text-primary-foreground data-checked:bg-primary data-indeterminate:text-foreground absolute -inset-px flex items-center justify-center rounded-sm data-unchecked:hidden",
12
12
  "data-slot": "checkbox-indicator",
13
13
  render: (indicatorProps, state) => /* @__PURE__ */ jsx("span", {
14
14
  ...indicatorProps,
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { CheckIcon, ChevronDownIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
3
  import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
4
+ import { cn } from "../lib/utils.js";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Suspense, lazy, useState } from "react";
7
7
  import { Popover } from "@base-ui/react/popover";
@@ -152,7 +152,7 @@ const CustomColorControls = ({ handleInputChange, handlePickerChange, inputHex,
152
152
  }),
153
153
  /* @__PURE__ */ jsx("input", {
154
154
  "aria-label": "Custom hex color",
155
- className: "border-input bg-background text-foreground text-2xs h-6 flex-1 rounded border px-1.5 font-mono outline-none",
155
+ className: "border-input bg-background text-foreground text-2xs h-6 flex-1 rounded-sm border px-1.5 font-mono outline-none",
156
156
  dir: "ltr",
157
157
  maxLength: 6,
158
158
  onChange: (event) => handleInputChange(event.target.value),
@@ -165,7 +165,7 @@ const CustomColorControls = ({ handleInputChange, handlePickerChange, inputHex,
165
165
  value: inputHex
166
166
  }),
167
167
  isValidHex(inputHex) && /* @__PURE__ */ jsx("span", {
168
- className: "border-border size-6 shrink-0 rounded border",
168
+ className: "border-border size-6 shrink-0 rounded-sm border",
169
169
  style: { backgroundColor: `#${inputHex}` }
170
170
  })
171
171
  ]
@@ -248,7 +248,7 @@ const ColorPickerContent = ({ value, onSelect, onClear, presets, columns, defaul
248
248
  onClear && /* @__PURE__ */ jsxs(Popover.Close, {
249
249
  render: /* @__PURE__ */ jsx("button", {
250
250
  "aria-label": "No color",
251
- className: "text-muted-foreground hover:bg-accent hover:text-accent-foreground text-2xs flex h-6 w-full items-center gap-1.5 rounded px-1",
251
+ className: "text-muted-foreground hover:bg-accent hover:text-accent-foreground text-2xs flex h-6 w-full items-center gap-1.5 rounded-sm px-1",
252
252
  onClick: onClear,
253
253
  type: "button"
254
254
  }),
@@ -1,12 +1,12 @@
1
1
  "use client";
2
- import { ChevronsUpDownIcon, XIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
- import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
5
- import { ScrollArea } from "./scroll-area.js";
6
2
  import { containedHandler } from "../hooks/use-contained-handler.js";
3
+ import { ChevronsUpDownIcon, XIcon } from "../icons.js";
7
4
  import { CONTROL_SIZE } from "../lib/control-size.js";
8
5
  import "../lib/field-trigger.js";
6
+ import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
7
+ import { cn } from "../lib/utils.js";
9
8
  import { Input } from "./input.js";
9
+ import { ScrollArea } from "./scroll-area.js";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
11
  import * as React$1 from "react";
12
12
  import { Combobox as Combobox$1 } from "@base-ui/react/combobox";
@@ -1,9 +1,9 @@
1
1
  "use client";
2
+ import { useContentDir } from "../hooks/use-content-dir.js";
2
3
  import { SearchIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
- import { MENU_ROW_CLASS_NAME } from "../lib/menu-row.js";
5
4
  import { CONTROL_SIZE } from "../lib/control-size.js";
6
- import { useContentDir } from "../hooks/use-content-dir.js";
5
+ import { MENU_ROW_CLASS_NAME } from "../lib/menu-row.js";
6
+ import { cn } from "../lib/utils.js";
7
7
  import { DialogContent as DialogPopup } from "./dialog.js";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Dialog } from "@base-ui/react/dialog";
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { ChevronDownIcon } from "../icons.js";
3
3
  import { cn } from "../lib/utils.js";
4
- import { DropdownMenu as Menu, DropdownMenuContent as MenuPopup, DropdownMenuRadioGroup as MenuRadioGroup, DropdownMenuRadioItem as MenuRadioItem, DropdownMenuTrigger as MenuTrigger } from "./menu.js";
5
4
  import { COMPOSER_BOX_ANONYMIZED_CLASS, COMPOSER_BOX_CLASS, COMPOSER_BOX_FOCUS_CLASS, COMPOSER_COMPACT_ROW_CLASS, COMPOSER_COMPACT_TEXT_CELL_CLASS, COMPOSER_CONTROL_BUTTON_SIZE, COMPOSER_LARGE_ACTION_ROW_CLASS, COMPOSER_LARGE_EDITOR_CLASS, COMPOSER_LARGE_TEXT_WELL_CLASS, COMPOSER_LEADING_GROUP_CLASS, COMPOSER_PICKER_TRIGGER_CLASS, COMPOSER_PLACEHOLDER_CLASS, COMPOSER_SEND_BUTTON_CLASS, COMPOSER_TEXT_CLASS } from "./composer-tokens.js";
5
+ import { DropdownMenu as Menu, DropdownMenuContent as MenuPopup, DropdownMenuRadioGroup as MenuRadioGroup, DropdownMenuRadioItem as MenuRadioItem, DropdownMenuTrigger as MenuTrigger } from "./menu.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  // src/components/composer.tsx
8
8
  /**
@@ -31,4 +31,13 @@ export type ContextMenuProps = {
31
31
  * Renders only the children when `actions` is empty so callers can
32
32
  * pass conditionally.
33
33
  */
34
- export declare const ContextMenu: ({ actions, children }: ContextMenuProps) => ReactNode;
34
+ export declare const ContextMenu: ({ actions, children }: ContextMenuProps) => ReactNode;
35
+ /**
36
+ * The items of one action list, inside a menu popup. `ContextMenu` and
37
+ * `EntityActions` (`@stll/ui/entity-actions`) both render their lists
38
+ * through it, so a right-click menu and an object's "…" menu built from
39
+ * the same list hold the same items.
40
+ */
41
+ export declare const ContextMenuActionItems: ({ actions }: {
42
+ actions: readonly ContextMenuAction[];
43
+ }) => import("react").JSX.Element;
@@ -23,9 +23,16 @@ const ContextMenu = ({ actions, children }) => {
23
23
  children
24
24
  }), /* @__PURE__ */ jsx(MenuPopup, {
25
25
  "data-slot": "context-menu-popup",
26
- children: actions.map((action) => /* @__PURE__ */ jsx(ContextMenuActionItem, { action }, action.label))
26
+ children: /* @__PURE__ */ jsx(ContextMenuActionItems, { actions })
27
27
  })] });
28
28
  };
29
+ /**
30
+ * The items of one action list, inside a menu popup. `ContextMenu` and
31
+ * `EntityActions` (`@stll/ui/entity-actions`) both render their lists
32
+ * through it, so a right-click menu and an object's "…" menu built from
33
+ * the same list hold the same items.
34
+ */
35
+ const ContextMenuActionItems = ({ actions }) => /* @__PURE__ */ jsx(Fragment, { children: actions.map((action) => /* @__PURE__ */ jsx(ContextMenuActionItem, { action }, action.label)) });
29
36
  const ContextMenuActionItem = ({ action }) => {
30
37
  const separator = action.separatorBefore ? /* @__PURE__ */ jsx(MenuSeparator, {}) : null;
31
38
  if (action.submenu) return /* @__PURE__ */ jsxs(Fragment, { children: [separator, /* @__PURE__ */ jsxs(MenuSub, { children: [/* @__PURE__ */ jsxs(MenuSubTrigger, { children: [action.icon, action.label] }), /* @__PURE__ */ jsx(MenuSubPopup, { children: action.submenu.map((sub) => /* @__PURE__ */ jsx(ContextMenuActionItem, { action: sub }, sub.label)) })] })] });
@@ -44,4 +51,4 @@ const ContextMenuActionItem = ({ action }) => {
44
51
  children: [action.icon, action.label]
45
52
  })] });
46
53
  };
47
- export { ContextMenu };
54
+ export { ContextMenu, ContextMenuActionItems };
@@ -2,10 +2,10 @@
2
2
  import { ChevronRightIcon } from "../icons.js";
3
3
  import { cn } from "../lib/utils.js";
4
4
  import { BidiText } from "./bidi-text.js";
5
- import { ScrollArea } from "./scroll-area.js";
6
- import { DirectionalIcon } from "./directional-icon.js";
7
5
  import { Checkbox } from "./checkbox.js";
6
+ import { DirectionalIcon } from "./directional-icon.js";
8
7
  import { Field, FieldLabel } from "./field.js";
8
+ import { ScrollArea } from "./scroll-area.js";
9
9
  import { SearchField } from "./search-field.js";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
11
  import { useId, useState } from "react";
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
  import { CalendarIcon, ChevronLeftIcon, ChevronRightIcon } from "../icons.js";
3
+ import { FIELD_TRIGGER_CLASS_NAME } from "../lib/field-trigger.js";
3
4
  import { cn } from "../lib/utils.js";
5
+ import { getLocaleWeekInfo, getWeekendDays } from "../lib/week.js";
4
6
  import { Button } from "./button.js";
7
+ import { DATE_PICKER_MODE, formatDateTimeValue, joinPickerTime, localDateFromTimestamp, millisecondsUntilNextLocalDate, parseDateTimeValue, resolveCalendarViewMonth, shiftCalendarDate } from "./date-picker-popover.logic.js";
5
8
  import { DirectionalIcon } from "./directional-icon.js";
6
- import { FIELD_TRIGGER_CLASS_NAME } from "../lib/field-trigger.js";
7
9
  import { Input } from "./input.js";
8
- import { getLocaleWeekInfo, getWeekendDays } from "../lib/week.js";
9
- import { DATE_PICKER_MODE, formatDateTimeValue, joinPickerTime, localDateFromTimestamp, millisecondsUntilNextLocalDate, parseDateTimeValue, resolveCalendarViewMonth, shiftCalendarDate } from "./date-picker-popover.logic.js";
10
10
  import { Popover, PopoverContent as PopoverPopup, PopoverTrigger } from "./popover.js";
11
11
  import { TimeField } from "./time-field.js";
12
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/utils.js";
3
- import { Input } from "./input.js";
4
3
  import { Field, FieldDescription, FieldLabel } from "./field.js";
4
+ import { Input } from "./input.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import * as React$1 from "react";
7
7
  // src/components/destructive-action-confirmation.tsx
@@ -1,5 +1,5 @@
1
- import { cn } from "../lib/utils.js";
2
1
  import { rendersNothing } from "../lib/renders-nothing.js";
2
+ import { cn } from "../lib/utils.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { createContext, useContext } from "react";
5
5
  // src/components/details-grid.tsx
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
  import { XIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
3
  import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
5
4
  import { SAFE_AREA_OVERLAY_GUTTER_CLASS_NAME } from "../lib/safe-area.js";
6
- import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
5
+ import { cn } from "../lib/utils.js";
7
6
  import { Button } from "./button.js";
8
- import { ScrollArea } from "./scroll-area.js";
9
7
  import { DialogFormContext, DialogFormState } from "./dialog-form-state.js";
8
+ import { ScrollArea } from "./scroll-area.js";
9
+ import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
11
  import { createContext, useContext, useRef, useState } from "react";
12
12
  import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
@@ -1,8 +1,8 @@
1
1
  import { FileTextIcon } from "../icons.js";
2
2
  import { cn } from "../lib/utils.js";
3
- import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
4
3
  import { CourtBadge } from "./court-badge.js";
5
4
  import { COURT_TIER_WEIGHT, caseNumberIdentityLabels, statuteIdentityLabels } from "./document-identity-badge.logic.js";
5
+ import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { panic } from "better-result";
8
8
  // src/components/document-identity-badge.tsx
@@ -0,0 +1,34 @@
1
+ import { ContextMenuAction } from "./context-menu.js";
2
+ import { ReactNode, Ref } from "react";
3
+ /** One action of an object: the same shape `ContextMenu` renders. */
4
+ export type EntityAction = ContextMenuAction;
5
+ export type EntityActionsProps = {
6
+ /** The object's actions, in menu order. An empty list still owns the
7
+ * object's right-click: the native menu stays, never a parent's menu. */
8
+ actions: readonly EntityAction[];
9
+ /** The object, which becomes the right-click target. It may render an
10
+ * `EntityActionsButton` anywhere inside. */
11
+ children: ReactNode;
12
+ /** A line above the actions in both menus, such as when a message was
13
+ * sent. It is a label, not an action. */
14
+ heading?: ReactNode;
15
+ /** The accessible name of the "…" button, e.g. "Actions". */
16
+ label: string;
17
+ };
18
+ /**
19
+ * An object's actions: the right-click menu over `children`, and the list
20
+ * an `EntityActionsButton` inside them opens.
21
+ */
22
+ export declare const EntityActions: ({ actions, children, heading, label }: EntityActionsProps) => import("react").JSX.Element;
23
+ export type EntityActionsButtonProps = {
24
+ /** Popup alignment against the button. */
25
+ align?: "center" | "end" | "start";
26
+ ref?: Ref<HTMLButtonElement>;
27
+ /** Popup side against the button. */
28
+ side?: "bottom" | "left" | "right" | "top";
29
+ };
30
+ /**
31
+ * The "…" button of the `EntityActions` around it. It opens the same list
32
+ * right-click opens, and renders nothing when the object has no actions.
33
+ */
34
+ export declare const EntityActionsButton: ({ align, ref, side }: EntityActionsButtonProps) => import("react").JSX.Element | null;
@@ -0,0 +1,132 @@
1
+ "use client";
2
+ import { EllipsisIcon } from "../icons.js";
3
+ import { nativeContextMenuReason } from "../lib/native-context-menu.js";
4
+ import { Button } from "./button.js";
5
+ import { ContextMenuActionItems } from "./context-menu.js";
6
+ import { DropdownMenu as Menu, DropdownMenuContent as MenuPopup, DropdownMenuGroup as MenuGroup, DropdownMenuLabel as MenuGroupLabel, DropdownMenuSeparator as MenuSeparator, DropdownMenuTrigger as MenuTrigger, MenuAnchor } from "./menu.js";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { createContext, use, useRef, useState } from "react";
9
+ import { panic } from "better-result";
10
+ // src/components/entity-actions.tsx
11
+ const EntityActionsContext = createContext(null);
12
+ const isContextMenuKey = (event) => event.key === "ContextMenu" || event.shiftKey && event.key === "F10";
13
+ const FOCUSABLE_SELECTOR = "a[href], button, input, select, textarea, [tabindex]:not([tabindex='-1'])";
14
+ /** The control focus returns to when the menu closes, inside the object. */
15
+ const focusReturnTarget = (container, target) => {
16
+ if (!(target instanceof Element)) return null;
17
+ const focusable = target.closest(FOCUSABLE_SELECTOR);
18
+ return focusable !== null && container.contains(focusable) ? focusable : null;
19
+ };
20
+ /**
21
+ * Right-clicks (and context-menu keys) an object already answered for. The
22
+ * innermost object owns the event even when it has no actions and leaves it
23
+ * to the native menu, so the objects around it never open theirs. A marker
24
+ * rather than `stopPropagation`: the native menu, and listeners further up
25
+ * such as the desktop webview's policy, still see the event.
26
+ */
27
+ const ownedEvents = /* @__PURE__ */ new WeakSet();
28
+ /** Claims the event for this object; false when an inner object owns it. */
29
+ const claimEvent = (event) => {
30
+ if (ownedEvents.has(event)) return false;
31
+ ownedEvents.add(event);
32
+ return true;
33
+ };
34
+ const EntityActionItems = ({ actions, heading }) => /* @__PURE__ */ jsxs(Fragment, { children: [heading !== void 0 && heading !== null && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuGroup, { children: /* @__PURE__ */ jsx(MenuGroupLabel, {
35
+ className: "font-normal",
36
+ children: heading
37
+ }) }), /* @__PURE__ */ jsx(MenuSeparator, {})] }), /* @__PURE__ */ jsx(ContextMenuActionItems, { actions })] });
38
+ /**
39
+ * An object's actions: the right-click menu over `children`, and the list
40
+ * an `EntityActionsButton` inside them opens.
41
+ */
42
+ const EntityActions = ({ actions, children, heading, label }) => {
43
+ const [open, setOpen] = useState(false);
44
+ const [anchor, setAnchor] = useState(null);
45
+ const returnFocus = useRef(null);
46
+ const context = {
47
+ actions,
48
+ heading,
49
+ label
50
+ };
51
+ const hasActions = actions.length > 0;
52
+ const openAt = (event, anchorRect) => {
53
+ event.preventDefault();
54
+ event.stopPropagation();
55
+ returnFocus.current = focusReturnTarget(event.currentTarget, event.target);
56
+ setAnchor(anchorRect);
57
+ setOpen(true);
58
+ };
59
+ const handleContextMenu = (event) => {
60
+ if (event.defaultPrevented || !(event.target instanceof Node) || !event.currentTarget.contains(event.target) || !claimEvent(event.nativeEvent)) return;
61
+ if (!hasActions || nativeContextMenuReason(event) !== null) return;
62
+ const { clientX: x, clientY: y } = event;
63
+ openAt(event, { getBoundingClientRect: () => new DOMRect(x, y, 0, 0) });
64
+ };
65
+ const handleKeyDown = (event) => {
66
+ const target = event.target;
67
+ if (event.defaultPrevented || !isContextMenuKey(event) || !(target instanceof Element) || !event.currentTarget.contains(target) || !claimEvent(event.nativeEvent)) return;
68
+ if (!hasActions || nativeContextMenuReason({
69
+ shiftKey: false,
70
+ target
71
+ }) !== null) return;
72
+ openAt(event, { getBoundingClientRect: () => target.getBoundingClientRect() });
73
+ };
74
+ return /* @__PURE__ */ jsxs(EntityActionsContext, {
75
+ value: context,
76
+ children: [/* @__PURE__ */ jsx("div", {
77
+ className: "contents",
78
+ "data-context-menu-target": "",
79
+ "data-slot": "entity-actions",
80
+ onContextMenu: handleContextMenu,
81
+ onKeyDown: handleKeyDown,
82
+ role: "presentation",
83
+ children
84
+ }), hasActions && /* @__PURE__ */ jsxs(Menu, {
85
+ onOpenChange: (nextOpen) => {
86
+ setOpen(nextOpen);
87
+ if (!nextOpen) setAnchor(null);
88
+ },
89
+ open,
90
+ children: [/* @__PURE__ */ jsx(MenuAnchor, {}), /* @__PURE__ */ jsx(MenuPopup, {
91
+ anchor: anchor ?? void 0,
92
+ "data-slot": "entity-actions-context-popup",
93
+ finalFocus: () => returnFocus.current ?? false,
94
+ children: /* @__PURE__ */ jsx(EntityActionItems, {
95
+ actions,
96
+ heading
97
+ })
98
+ })]
99
+ })]
100
+ });
101
+ };
102
+ /**
103
+ * The "…" button of the `EntityActions` around it. It opens the same list
104
+ * right-click opens, and renders nothing when the object has no actions.
105
+ */
106
+ const EntityActionsButton = ({ align = "end", ref, side = "bottom" }) => {
107
+ const context = use(EntityActionsContext);
108
+ if (context === null) panic("EntityActionsButton renders inside EntityActions, which owns the list it opens");
109
+ if (context.actions.length === 0) return null;
110
+ return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
111
+ ref,
112
+ render: /* @__PURE__ */ jsx(Button, {
113
+ "aria-label": context.label,
114
+ className: "size-6",
115
+ size: "icon-xs",
116
+ variant: "muted",
117
+ children: /* @__PURE__ */ jsx(EllipsisIcon, {
118
+ "aria-hidden": "true",
119
+ className: "size-3.5"
120
+ })
121
+ })
122
+ }), /* @__PURE__ */ jsx(MenuPopup, {
123
+ align,
124
+ "data-slot": "entity-actions-button-popup",
125
+ side,
126
+ children: /* @__PURE__ */ jsx(EntityActionItems, {
127
+ actions: context.actions,
128
+ heading: context.heading
129
+ })
130
+ })] });
131
+ };
132
+ export { EntityActions, EntityActionsButton };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { UploadIcon } from "../icons.js";
3
+ import { openFilePicker } from "../lib/file-picker.js";
3
4
  import { cn } from "../lib/utils.js";
4
5
  import { Button } from "./button.js";
5
- import { openFilePicker } from "../lib/file-picker.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { useId } from "react";
8
8
  // src/components/file-input.tsx
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
3
2
  import { containedHandler } from "../hooks/use-contained-handler.js";
4
3
  import { useLatest } from "../hooks/use-latest.js";
4
+ import { cn } from "../lib/utils.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useCallback, useEffect, useRef, useState } from "react";
7
7
  // src/components/hex-color-picker.tsx
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { ChevronLeftIcon, ChevronRightIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
2
  import { containedEventHandler } from "../hooks/use-contained-handler.js";
3
+ import { ChevronLeftIcon, ChevronRightIcon } from "../icons.js";
5
4
  import { SCROLL_EDGE_FADE_CLASS, writeScrollEdgeFade } from "../lib/scroll-edge-fade.js";
5
+ import { cn } from "../lib/utils.js";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { useCallback, useState } from "react";
8
8
  // src/components/horizontal-scroller.tsx
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/utils.js";
3
- import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
4
3
  import { withoutDirectionalControls } from "./bidi-text.js";
4
+ import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useCallback, useId, useState } from "react";
7
7
  // src/components/identity-text.tsx
@@ -1,5 +1,5 @@
1
- import { cn } from "../lib/utils.js";
2
1
  import { contentDir, isStructuredInputType } from "../hooks/use-content-dir.js";
2
+ import { cn } from "../lib/utils.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { useCallback, useImperativeHandle, useRef } from "react";
5
5
  import { panic } from "better-result";
@@ -11,7 +11,7 @@ const InputGroup = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
11
11
  role: "group",
12
12
  ...props
13
13
  });
14
- const inputGroupAddonVariants = cva("flex h-auto cursor-text items-center justify-center gap-2 leading-none select-none [&_svg]:-mx-0.5 in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 not-has-[button]:**:[svg:not([class*='opacity-'])]:opacity-80 [&>kbd]:rounded-[calc(var(--radius)-5px)]", {
14
+ const inputGroupAddonVariants = cva("flex h-auto cursor-text items-center justify-center gap-2 leading-none select-none [&_svg]:-mx-0.5 in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 not-has-[button]:**:[svg:not([class*='opacity-'])]:opacity-80 [&>kbd]:rounded-sm", {
15
15
  defaultVariants: { align: "inline-start" },
16
16
  variants: { align: {
17
17
  "block-end": "order-last w-full justify-start px-[calc(--spacing(3)-1px)] pb-[calc(--spacing(3)-1px)] [.border-t]:pt-[calc(--spacing(3)-1px)] [[data-size=sm]+&]:px-[calc(--spacing(2.5)-1px)]",
@@ -25,8 +25,8 @@ const InputGroupAddon = ({ className, align = "inline-start", ...props }) => /*
25
25
  "data-align": align,
26
26
  "data-slot": "input-group-addon",
27
27
  onMouseDown: (e) => {
28
- const { target } = e;
29
- if (!(target instanceof Element)) return;
28
+ const { currentTarget, target } = e;
29
+ if (!(target instanceof Element) || !currentTarget.contains(target)) return;
30
30
  if (target.closest("button, a, input, select, textarea, [role='button'], [role='combobox'], [role='listbox'], [data-slot='select-trigger']")) return;
31
31
  e.preventDefault();
32
32
  const parent = e.currentTarget.parentElement;
@@ -1,8 +1,8 @@
1
1
  "use client";
2
+ import { isStructuredInputType, useContentDir } from "../hooks/use-content-dir.js";
2
3
  import { SearchIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
4
  import { CONTROL_SIZE } from "../lib/control-size.js";
5
- import { isStructuredInputType, useContentDir } from "../hooks/use-content-dir.js";
5
+ import { cn } from "../lib/utils.js";
6
6
  import { INLINE_FIELD_CLASS_NAME, INPUT_ELEMENT_CLASS_NAME, INPUT_SIZE_CLASS_NAMES } from "./input-control.js";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Input as Input$1 } from "@base-ui/react/input";
@@ -26,7 +26,7 @@ const Kbd = ({ className, children, keys, variant = "cap", ...props }) => {
26
26
  });
27
27
  };
28
28
  const KBD_VARIANT_CLASS_NAME = {
29
- cap: "border-border bg-muted text-muted-foreground text-2xs h-5 min-w-5 rounded border px-1",
29
+ cap: "border-border bg-muted text-muted-foreground text-2xs h-5 min-w-5 rounded-sm border px-1",
30
30
  plain: "text-foreground-label text-xs tracking-widest"
31
31
  };
32
32
  const KEY_LABELS = {
@@ -1,6 +1,6 @@
1
1
  import { LayersIcon } from "../icons.js";
2
- import { cn } from "../lib/utils.js";
3
2
  import { resolveMatterColor } from "../lib/matter-colors.js";
3
+ import { cn } from "../lib/utils.js";
4
4
  import { ALL_MATTERS_STACK } from "./matter-icon.shared.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  // src/components/matter-icon.tsx
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { ChevronRightIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
3
  import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
4
+ import { cn } from "../lib/utils.js";
5
+ import { DirectionalIcon } from "./directional-icon.js";
5
6
  import { Kbd } from "./kbd.js";
6
7
  import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
7
- import { DirectionalIcon } from "./directional-icon.js";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Menu as Menu$1 } from "@base-ui/react/menu";
10
10
  // src/components/menu.tsx
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
3
2
  import { CONTROL_SIZE } from "../lib/control-size.js";
3
+ import { cn } from "../lib/utils.js";
4
4
  import { INPUT_CONTROL_CLASS_NAME, INPUT_ELEMENT_CLASS_NAME, INPUT_SIZE_CLASS_NAMES } from "./input-control.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { NumberField } from "@base-ui/react/number-field";
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
  import { ChevronRightIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
- import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
5
- import { ScrollArea } from "./scroll-area.js";
6
- import { DirectionalIcon } from "./directional-icon.js";
7
3
  import "../lib/panel-inset.js";
4
+ import { cn } from "../lib/utils.js";
8
5
  import { ReviewAuthorAvatar } from "../review/review-author-avatar.js";
6
+ import { DirectionalIcon } from "./directional-icon.js";
9
7
  import { reconcileOutlineItems, retainOutlineIdSet } from "./outline-rail.logic.js";
8
+ import { ScrollArea } from "./scroll-area.js";
9
+ import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { memo, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
12
12
  import { Temporal } from "temporal-polyfill/full";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
3
2
  import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
4
3
  import { CONTENT_SIZED_POSITIONER_CLASS_NAME, IN_FLOW_POPUP_CLASS_NAME } from "../lib/positioner-sizing.js";
4
+ import { cn } from "../lib/utils.js";
5
5
  import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { Popover as Popover$1 } from "@base-ui/react/popover";
@@ -19,7 +19,7 @@ const SegmentedIconToggle = ({ value, options, onChange, size = "compact" }) =>
19
19
  const Icon = option.icon;
20
20
  return /* @__PURE__ */ jsx(ToggleGroupItem, {
21
21
  "aria-label": option.label,
22
- className: cn("h-6 w-7 rounded-[4px] sm:h-6", size === "touch" && "[@media(any-pointer:coarse)]:h-11 [@media(any-pointer:coarse)]:w-11"),
22
+ className: cn("h-6 w-7 rounded-sm sm:h-6", size === "touch" && "[@media(any-pointer:coarse)]:h-11 [@media(any-pointer:coarse)]:w-11"),
23
23
  "data-control-value": option.value,
24
24
  size: "icon-xs",
25
25
  value: option.value,
@@ -1,10 +1,10 @@
1
1
  "use client";
2
+ import { useLatest } from "../hooks/use-latest.js";
2
3
  import { ChevronDownIcon, ChevronUpIcon, ChevronsUpDownIcon } from "../icons.js";
3
- import { cn } from "../lib/utils.js";
4
- import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
5
4
  import { CONTROL_SIZE } from "../lib/control-size.js";
6
5
  import { FIELD_TRIGGER_CLASS_NAME } from "../lib/field-trigger.js";
7
- import { useLatest } from "../hooks/use-latest.js";
6
+ import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
7
+ import { cn } from "../lib/utils.js";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
  import * as React$1 from "react";
10
10
  import { Select as Select$1 } from "@base-ui/react/select";