@sole-ui/react 0.0.0-stage → 0.2.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 (161) hide show
  1. package/README.md +98 -2
  2. package/dist/components/shell/app-frame.d.ts +14 -0
  3. package/dist/components/shell/app-frame.js +8 -0
  4. package/dist/components/shell/command-palette.d.ts +32 -0
  5. package/dist/components/shell/command-palette.js +30 -0
  6. package/dist/components/shell/index.d.ts +4 -0
  7. package/dist/components/shell/index.js +4 -0
  8. package/dist/components/shell/page.d.ts +25 -0
  9. package/dist/components/shell/page.js +22 -0
  10. package/dist/components/shell/sidebar.d.ts +81 -0
  11. package/dist/components/shell/sidebar.js +113 -0
  12. package/dist/components/sole/avatar.d.ts +19 -0
  13. package/dist/components/sole/avatar.js +37 -0
  14. package/dist/components/sole/banner.d.ts +24 -0
  15. package/dist/components/sole/banner.js +27 -0
  16. package/dist/components/sole/column-header.d.ts +15 -0
  17. package/dist/components/sole/column-header.js +15 -0
  18. package/dist/components/sole/copy-field.d.ts +10 -0
  19. package/dist/components/sole/copy-field.js +32 -0
  20. package/dist/components/sole/count-badge.d.ts +8 -0
  21. package/dist/components/sole/count-badge.js +8 -0
  22. package/dist/components/sole/field.d.ts +24 -0
  23. package/dist/components/sole/field.js +27 -0
  24. package/dist/components/sole/filters.d.ts +33 -0
  25. package/dist/components/sole/filters.js +48 -0
  26. package/dist/components/sole/index.d.ts +17 -0
  27. package/dist/components/sole/index.js +17 -0
  28. package/dist/components/sole/kbd.d.ts +7 -0
  29. package/dist/components/sole/kbd.js +14 -0
  30. package/dist/components/sole/label-tag.d.ts +18 -0
  31. package/dist/components/sole/label-tag.js +17 -0
  32. package/dist/components/sole/layout.d.ts +54 -0
  33. package/dist/components/sole/layout.js +48 -0
  34. package/dist/components/sole/logo.d.ts +13 -0
  35. package/dist/components/sole/logo.js +17 -0
  36. package/dist/components/sole/nav.d.ts +22 -0
  37. package/dist/components/sole/nav.js +32 -0
  38. package/dist/components/sole/person-chip.d.ts +8 -0
  39. package/dist/components/sole/person-chip.js +19 -0
  40. package/dist/components/sole/person-header.d.ts +21 -0
  41. package/dist/components/sole/person-header.js +22 -0
  42. package/dist/components/sole/pill.d.ts +9 -0
  43. package/dist/components/sole/pill.js +14 -0
  44. package/dist/components/sole/states.d.ts +48 -0
  45. package/dist/components/sole/states.js +53 -0
  46. package/dist/components/sole/table.d.ts +23 -0
  47. package/dist/components/sole/table.js +32 -0
  48. package/dist/components/ui/alert-dialog.d.ts +27 -0
  49. package/dist/components/ui/alert-dialog.js +33 -0
  50. package/dist/components/ui/badge.d.ts +11 -0
  51. package/dist/components/ui/badge.js +30 -0
  52. package/dist/components/ui/button.d.ts +13 -0
  53. package/dist/components/ui/button.js +49 -0
  54. package/dist/components/ui/calendar.d.ts +9 -0
  55. package/dist/components/ui/calendar.js +79 -0
  56. package/dist/components/ui/checkbox.d.ts +4 -0
  57. package/dist/components/ui/checkbox.js +11 -0
  58. package/dist/components/ui/command.d.ts +90 -0
  59. package/dist/components/ui/command.js +36 -0
  60. package/dist/components/ui/dialog.d.ts +18 -0
  61. package/dist/components/ui/dialog.js +33 -0
  62. package/dist/components/ui/dropdown-menu.d.ts +25 -0
  63. package/dist/components/ui/dropdown-menu.js +42 -0
  64. package/dist/components/ui/index.d.ts +23 -0
  65. package/dist/components/ui/index.js +23 -0
  66. package/dist/components/ui/input.d.ts +3 -0
  67. package/dist/components/ui/input.js +12 -0
  68. package/dist/components/ui/label.d.ts +4 -0
  69. package/dist/components/ui/label.js +10 -0
  70. package/dist/components/ui/popover.d.ts +10 -0
  71. package/dist/components/ui/popover.js +22 -0
  72. package/dist/components/ui/scroll-area.d.ts +5 -0
  73. package/dist/components/ui/scroll-area.js +14 -0
  74. package/dist/components/ui/select.d.ts +15 -0
  75. package/dist/components/ui/select.js +30 -0
  76. package/dist/components/ui/separator.d.ts +4 -0
  77. package/dist/components/ui/separator.js +10 -0
  78. package/dist/components/ui/sheet.d.ts +14 -0
  79. package/dist/components/ui/sheet.js +35 -0
  80. package/dist/components/ui/skeleton.d.ts +3 -0
  81. package/dist/components/ui/skeleton.js +10 -0
  82. package/dist/components/ui/sonner.d.ts +5 -0
  83. package/dist/components/ui/sonner.js +63 -0
  84. package/dist/components/ui/switch.d.ts +6 -0
  85. package/dist/components/ui/switch.js +10 -0
  86. package/dist/components/ui/tabs.d.ts +7 -0
  87. package/dist/components/ui/tabs.js +24 -0
  88. package/dist/components/ui/textarea.d.ts +3 -0
  89. package/dist/components/ui/textarea.js +9 -0
  90. package/dist/components/ui/toggle-group.d.ts +14 -0
  91. package/dist/components/ui/toggle-group.js +24 -0
  92. package/dist/components/ui/toggle.d.ts +12 -0
  93. package/dist/components/ui/toggle.js +28 -0
  94. package/dist/components/ui/tooltip.d.ts +7 -0
  95. package/dist/components/ui/tooltip.js +18 -0
  96. package/dist/hq/activity-line.d.ts +21 -0
  97. package/dist/hq/activity-line.js +26 -0
  98. package/dist/hq/board-card.d.ts +12 -0
  99. package/dist/hq/board-card.js +21 -0
  100. package/dist/hq/board-chip.d.ts +12 -0
  101. package/dist/hq/board-chip.js +20 -0
  102. package/dist/hq/checklist-item.d.ts +14 -0
  103. package/dist/hq/checklist-item.js +13 -0
  104. package/dist/hq/comment.d.ts +26 -0
  105. package/dist/hq/comment.js +15 -0
  106. package/dist/hq/due-chip.d.ts +11 -0
  107. package/dist/hq/due-chip.js +25 -0
  108. package/dist/hq/group-header.d.ts +27 -0
  109. package/dist/hq/group-header.js +22 -0
  110. package/dist/hq/inbox-row.d.ts +22 -0
  111. package/dist/hq/inbox-row.js +13 -0
  112. package/dist/hq/index.d.ts +21 -0
  113. package/dist/hq/index.js +21 -0
  114. package/dist/hq/link-row.d.ts +13 -0
  115. package/dist/hq/link-row.js +13 -0
  116. package/dist/hq/mention-chip.d.ts +23 -0
  117. package/dist/hq/mention-chip.js +28 -0
  118. package/dist/hq/page-row.d.ts +26 -0
  119. package/dist/hq/page-row.js +30 -0
  120. package/dist/hq/priority-icon.d.ts +9 -0
  121. package/dist/hq/priority-icon.js +23 -0
  122. package/dist/hq/property-type-icon.d.ts +7 -0
  123. package/dist/hq/property-type-icon.js +22 -0
  124. package/dist/hq/recent-item.d.ts +11 -0
  125. package/dist/hq/recent-item.js +12 -0
  126. package/dist/hq/review-badge.d.ts +37 -0
  127. package/dist/hq/review-badge.js +77 -0
  128. package/dist/hq/state-icon.d.ts +12 -0
  129. package/dist/hq/state-icon.js +41 -0
  130. package/dist/hq/state-pill.d.ts +9 -0
  131. package/dist/hq/state-pill.js +18 -0
  132. package/dist/hq/sticky.d.ts +13 -0
  133. package/dist/hq/sticky.js +22 -0
  134. package/dist/hq/template-card.d.ts +10 -0
  135. package/dist/hq/template-card.js +9 -0
  136. package/dist/hq/types.d.ts +49 -0
  137. package/dist/hq/types.js +7 -0
  138. package/dist/hq/work-item-row.d.ts +16 -0
  139. package/dist/hq/work-item-row.js +23 -0
  140. package/dist/index.d.ts +13 -0
  141. package/dist/index.js +12 -0
  142. package/dist/lib/cn.d.ts +2 -0
  143. package/dist/lib/cn.js +15 -0
  144. package/dist/lib/colour.d.ts +8 -0
  145. package/dist/lib/colour.js +28 -0
  146. package/dist/lib/dates.d.ts +62 -0
  147. package/dist/lib/dates.js +182 -0
  148. package/dist/lib/hue.d.ts +3 -0
  149. package/dist/lib/hue.js +1 -0
  150. package/dist/lib/person.d.ts +16 -0
  151. package/dist/lib/person.js +17 -0
  152. package/dist/lib/platform.d.ts +4 -0
  153. package/dist/lib/platform.js +12 -0
  154. package/dist/lib/sole-provider.d.ts +35 -0
  155. package/dist/lib/sole-provider.js +52 -0
  156. package/dist/styles.css +64 -0
  157. package/dist/tokens.css +231 -0
  158. package/dist/tokens.generated.d.ts +219 -0
  159. package/dist/tokens.generated.js +679 -0
  160. package/dist/tokens.json +677 -0
  161. package/package.json +82 -4
@@ -0,0 +1,14 @@
1
+ import * as React from 'react';
2
+ import type { VariantProps } from 'class-variance-authority';
3
+ import { ToggleGroup as ToggleGroupPrimitive } from 'radix-ui';
4
+ declare const ToggleGroup: React.ForwardRefExoticComponent<((Omit<ToggleGroupPrimitive.ToggleGroupMultipleProps & React.RefAttributes<HTMLDivElement>, "ref"> | Omit<ToggleGroupPrimitive.ToggleGroupSingleProps & React.RefAttributes<HTMLDivElement>, "ref">) & VariantProps<(props?: ({
5
+ variant?: "default" | "outline" | null | undefined;
6
+ size?: "default" | "lg" | "sm" | null | undefined;
7
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string> & {
8
+ spacing?: number;
9
+ }) & React.RefAttributes<HTMLDivElement>>;
10
+ declare const ToggleGroupItem: React.ForwardRefExoticComponent<Omit<ToggleGroupPrimitive.ToggleGroupItemProps & React.RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
11
+ variant?: "default" | "outline" | null | undefined;
12
+ size?: "default" | "lg" | "sm" | null | undefined;
13
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string> & React.RefAttributes<HTMLButtonElement>>;
14
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { ToggleGroup as ToggleGroupPrimitive } from 'radix-ui';
5
+ import { cn } from '../../lib/cn.js';
6
+ import { toggleVariants } from './toggle.js';
7
+ const ToggleGroupContext = React.createContext({
8
+ size: 'default',
9
+ variant: 'default',
10
+ spacing: 0,
11
+ });
12
+ const ToggleGroup = React.forwardRef(function ToggleGroup({ className, variant, size, spacing = 0, children, ...props }, ref) {
13
+ return (_jsx(ToggleGroupPrimitive.Root, { ref: ref, "data-slot": "toggle-group", "data-variant": variant, "data-size": size, "data-spacing": spacing, style: { '--gap': spacing }, className: cn('group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs', className), ...props, children: _jsx(ToggleGroupContext.Provider, { value: { variant, size, spacing }, children: children }) }));
14
+ });
15
+ ToggleGroup.displayName = 'ToggleGroup';
16
+ const ToggleGroupItem = React.forwardRef(function ToggleGroupItem({ className, children, variant, size, ...props }, ref) {
17
+ const context = React.useContext(ToggleGroupContext);
18
+ return (_jsx(ToggleGroupPrimitive.Item, { ref: ref, "data-slot": "toggle-group-item", "data-variant": context.variant || variant, "data-size": context.size || size, "data-spacing": context.spacing, className: cn(toggleVariants({
19
+ variant: context.variant || variant,
20
+ size: context.size || size,
21
+ }), 'w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10', 'data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l', className), ...props, children: children }));
22
+ });
23
+ ToggleGroupItem.displayName = 'ToggleGroupItem';
24
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import type { VariantProps } from 'class-variance-authority';
3
+ import { Toggle as TogglePrimitive } from 'radix-ui';
4
+ declare const toggleVariants: (props?: ({
5
+ variant?: "default" | "outline" | null | undefined;
6
+ size?: "default" | "lg" | "sm" | null | undefined;
7
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
+ declare const Toggle: React.ForwardRefExoticComponent<Omit<TogglePrimitive.ToggleProps & React.RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
9
+ variant?: "default" | "outline" | null | undefined;
10
+ size?: "default" | "lg" | "sm" | null | undefined;
11
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string> & React.RefAttributes<HTMLButtonElement>>;
12
+ export { Toggle, toggleVariants };
@@ -0,0 +1,28 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { cva } from 'class-variance-authority';
5
+ import { Toggle as TogglePrimitive } from 'radix-ui';
6
+ import { cn } from '../../lib/cn.js';
7
+ const toggleVariants = cva("inline-flex items-center justify-center gap-2 rounded-md text-body font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:shadow-[var(--focus-ring)] disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
8
+ variants: {
9
+ variant: {
10
+ default: 'bg-transparent',
11
+ outline: 'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground',
12
+ },
13
+ size: {
14
+ default: 'h-9 min-w-9 px-2',
15
+ sm: 'h-8 min-w-8 px-1.5',
16
+ lg: 'h-10 min-w-10 px-2.5',
17
+ },
18
+ },
19
+ defaultVariants: {
20
+ variant: 'default',
21
+ size: 'default',
22
+ },
23
+ });
24
+ const Toggle = React.forwardRef(function Toggle({ className, variant, size, ...props }, ref) {
25
+ return (_jsx(TogglePrimitive.Root, { ref: ref, "data-slot": "toggle", className: cn(toggleVariants({ variant, size, className })), ...props }));
26
+ });
27
+ Toggle.displayName = 'Toggle';
28
+ export { Toggle, toggleVariants };
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ import { Tooltip as TooltipPrimitive } from 'radix-ui';
3
+ declare function TooltipProvider({ delayDuration, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>): React.JSX.Element;
4
+ declare function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>): React.JSX.Element;
5
+ declare const TooltipTrigger: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
6
+ declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
7
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { Tooltip as TooltipPrimitive } from 'radix-ui';
5
+ import { cn } from '../../lib/cn.js';
6
+ // Renders no element, so it takes no ref. SoleProvider already wraps the app in one;
7
+ // use this only for a part of the page that needs a different delay.
8
+ function TooltipProvider({ delayDuration = 400, ...props }) {
9
+ return _jsx(TooltipPrimitive.Provider, { "data-slot": "tooltip-provider", delayDuration: delayDuration, ...props });
10
+ }
11
+ function Tooltip({ ...props }) {
12
+ return _jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props });
13
+ }
14
+ const TooltipTrigger = React.forwardRef((props, ref) => _jsx(TooltipPrimitive.Trigger, { ref: ref, "data-slot": "tooltip-trigger", ...props }));
15
+ TooltipTrigger.displayName = 'TooltipTrigger';
16
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, children, ...props }, ref) => (_jsx(TooltipPrimitive.Portal, { children: _jsxs(TooltipPrimitive.Content, { ref: ref, "data-slot": "tooltip-content", sideOffset: sideOffset, className: cn('z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-[7px] bg-tooltip px-[9px] py-[5px] text-label text-balance text-tooltip-foreground fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95', className), ...props, children: [children, _jsx(TooltipPrimitive.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-tooltip fill-tooltip" })] }) })));
17
+ TooltipContent.displayName = 'TooltipContent';
18
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import type { Timestamp } from '../lib/dates.ts';
3
+ import type { SolePerson } from '../lib/person.ts';
4
+ /** The kind of change, which picks the icon. */
5
+ export type ActivityKind = 'created' | 'state' | 'assignee' | 'label' | 'due' | 'comment' | 'link' | 'delete' | 'edit' | 'property';
6
+ export interface ActivityLineProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
7
+ /**
8
+ * Who made the change. The sentence already names them, so nothing is drawn for it; the id is kept on the
9
+ * line as `data-actor` for tests and hooks. `null` is a former member.
10
+ */
11
+ actor?: SolePerson | null;
12
+ /** Picks the icon. Defaults to a plain edit. */
13
+ kind?: ActivityKind;
14
+ /** When it happened. */
15
+ at: Timestamp;
16
+ /** Overrides the provider's clock. */
17
+ now?: Date;
18
+ /** The sentence, "Ava moved this from Todo to Done". */
19
+ children: React.ReactNode;
20
+ }
21
+ export declare const ActivityLine: React.ForwardRefExoticComponent<ActivityLineProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ArrowLeftRight, CalendarClock, CirclePlus, Link2, MessageSquare, Pencil, SlidersHorizontal, Tag, Trash2, UserPlus } from 'lucide-react';
4
+ import * as React from 'react';
5
+ import { cn } from '../lib/cn.js';
6
+ import { formatFullTimestamp, formatRelative } from '../lib/dates.js';
7
+ import { useNow, useSole } from '../lib/sole-provider.js';
8
+ const ICONS = {
9
+ created: CirclePlus,
10
+ state: ArrowLeftRight,
11
+ assignee: UserPlus,
12
+ label: Tag,
13
+ due: CalendarClock,
14
+ comment: MessageSquare,
15
+ link: Link2,
16
+ delete: Trash2,
17
+ edit: Pencil,
18
+ property: SlidersHorizontal,
19
+ };
20
+ export const ActivityLine = React.forwardRef(function ActivityLine({ actor, kind = 'edit', at, now, children, className, ...props }, ref) {
21
+ const tick = useNow();
22
+ const { timeZone } = useSole();
23
+ const Icon = ICONS[kind];
24
+ return (_jsxs("div", { ref: ref, "data-actor": actor?.id, className: cn('flex min-h-8 items-center gap-2.5 text-label font-normal text-muted-foreground', className), ...props, children: [_jsx(Icon, { size: 14, strokeWidth: 1.8, "aria-hidden": "true", className: "shrink-0 text-subtle-foreground" }), _jsx("span", { className: "min-w-0 flex-1", children: children }), _jsx("time", { dateTime: at, title: formatFullTimestamp(at, timeZone), className: "tnum shrink-0 text-subtle-foreground", children: formatRelative(at, now ?? tick, timeZone) })] }));
25
+ });
26
+ ActivityLine.displayName = 'ActivityLine';
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import type { DateOnly } from '../lib/dates.ts';
3
+ import type { WorkItemSummary } from './types.ts';
4
+ export interface BoardCardProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
5
+ item: WorkItemSummary;
6
+ /** Defaults to today on the provider's clock. */
7
+ today?: DateOnly;
8
+ /** Open somewhere other than the full page, e.g. the side sheet. Cmd-click still opens the page. */
9
+ onOpen?: (item: WorkItemSummary) => void;
10
+ dragging?: boolean;
11
+ }
12
+ export declare const BoardCard: React.ForwardRefExoticComponent<BoardCardProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,21 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { AvatarStack } from '../components/sole/avatar.js';
5
+ import { LabelTags } from '../components/sole/label-tag.js';
6
+ import { cn } from '../lib/cn.js';
7
+ import { SoleLink } from '../lib/sole-provider.js';
8
+ import { DueChip } from './due-chip.js';
9
+ import { PriorityIcon } from './priority-icon.js';
10
+ export const BoardCard = React.forwardRef(function BoardCard({ item, today, onOpen, dragging = false, className, ...rest }, ref) {
11
+ const onClick = onOpen
12
+ ? (e) => {
13
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0)
14
+ return;
15
+ e.preventDefault();
16
+ onOpen(item);
17
+ }
18
+ : undefined;
19
+ return (_jsxs("div", { ref: ref, "data-board-card": item.key, className: cn('flex min-h-16 flex-col rounded-lg border border-border bg-card px-3 py-[9px] text-card-foreground shadow-sm transition-shadow duration-[120ms]', dragging && 'shadow-lg ring-1 ring-brand', className), ...rest, children: [_jsxs("div", { className: "flex h-4 items-center gap-2", children: [_jsx("span", { className: "tnum text-label text-subtle-foreground", children: item.key }), _jsx(PriorityIcon, { priority: item.priority, className: "ml-auto" })] }), _jsx(SoleLink, { href: item.href, onClick: onClick, className: cn('mt-[7px] line-clamp-3 text-body font-medium outline-none hover:underline focus-visible:underline', item.state?.group === 'completed' && 'text-muted-foreground', item.state?.group === 'cancelled' && 'text-subtle-foreground line-through'), children: item.title }), (item.labels.length > 0 || item.dueDate || item.assignees.length > 0) && (_jsxs("div", { className: "mt-2 flex min-w-0 items-center gap-1.5", children: [_jsx(LabelTags, { labels: item.labels }), _jsx(DueChip, { due: item.dueDate, today: today, done: item.isDone }), _jsx(AvatarStack, { people: item.assignees, className: "ml-auto" })] }))] }));
20
+ });
21
+ BoardCard.displayName = 'BoardCard';
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import type { BoardSummary } from './types.ts';
3
+ export interface BoardEmojiProps extends React.ComponentPropsWithoutRef<'span'> {
4
+ board: Pick<BoardSummary, 'emoji'>;
5
+ }
6
+ export declare const BoardEmoji: React.ForwardRefExoticComponent<BoardEmojiProps & React.RefAttributes<HTMLSpanElement>>;
7
+ export interface BoardChipProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'children'> {
8
+ board: BoardSummary;
9
+ /** Where the board opens. With it the chip is a link; without it, plain text. */
10
+ href?: string;
11
+ }
12
+ export declare const BoardChip: React.ForwardRefExoticComponent<BoardChipProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { cn } from '../lib/cn.js';
5
+ import { SoleLink } from '../lib/sole-provider.js';
6
+ export const BoardEmoji = React.forwardRef(function BoardEmoji({ board, className, ...props }, ref) {
7
+ return (_jsx("span", { ...props, ref: ref, "aria-hidden": "true", className: cn('inline-flex w-4 shrink-0 justify-center text-[14px] leading-none', className), children: board.emoji || '📁' }));
8
+ });
9
+ BoardEmoji.displayName = 'BoardEmoji';
10
+ export const BoardChip = React.forwardRef(function BoardChip({ board, href, className, ...props }, ref) {
11
+ const classes = cn('inline-flex h-[22px] max-w-48 shrink-0 items-center gap-1.5 rounded-md bg-neutral-soft px-2 text-label text-neutral-text', className);
12
+ const inner = (_jsxs(_Fragment, { children: [_jsx(BoardEmoji, { board: board, className: "text-[12px]" }), _jsx("span", { className: "truncate", children: board.name })] }));
13
+ if (!href) {
14
+ return (_jsx("span", { ...props, ref: ref, className: classes, children: inner }));
15
+ }
16
+ // The span props are the anchor's too, apart from the handlers' element type, so they are spread as a link's.
17
+ const linkProps = props;
18
+ return (_jsx(SoleLink, { ...linkProps, ref: ref, href: href, className: cn(classes, 'hover:bg-sidebar-hover focus-visible:shadow-[var(--focus-ring)] focus-visible:outline-none'), children: inner }));
19
+ });
20
+ BoardChip.displayName = 'BoardChip';
@@ -0,0 +1,14 @@
1
+ import * as React from 'react';
2
+ export interface ChecklistItemProps extends Omit<React.ComponentPropsWithoutRef<'label'>, 'children'> {
3
+ checked: boolean;
4
+ onCheckedChange?: (checked: boolean) => void;
5
+ disabled?: boolean;
6
+ children: React.ReactNode;
7
+ /** read: 16/26 as in a description. body: 13/20 for denser lists. */
8
+ size?: 'read' | 'body';
9
+ }
10
+ /**
11
+ * Checklist item (50.6): a 16px checkbox and the line at the reading size; a done line
12
+ * turns the subtle grey. The editor draws its task items the same way (editor.css).
13
+ */
14
+ export declare const ChecklistItem: React.ForwardRefExoticComponent<ChecklistItemProps & React.RefAttributes<HTMLLabelElement>>;
@@ -0,0 +1,13 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { Checkbox } from '../components/ui/checkbox.js';
5
+ import { cn } from '../lib/cn.js';
6
+ /**
7
+ * Checklist item (50.6): a 16px checkbox and the line at the reading size; a done line
8
+ * turns the subtle grey. The editor draws its task items the same way (editor.css).
9
+ */
10
+ export const ChecklistItem = React.forwardRef(function ChecklistItem({ checked, onCheckedChange, disabled, children, size = 'read', className, ...props }, ref) {
11
+ return (_jsxs("label", { ref: ref, className: cn('flex min-w-0 items-start gap-2.5', size === 'read' ? 'text-read' : 'text-body', className), ...props, children: [_jsx(Checkbox, { checked: checked, disabled: disabled, onCheckedChange: (v) => onCheckedChange?.(v === true), className: cn('shrink-0', size === 'read' ? 'mt-[5px]' : 'mt-0.5') }), _jsx("span", { className: cn('min-w-0', checked ? 'text-subtle-foreground' : 'text-foreground'), children: children })] }));
12
+ });
13
+ ChecklistItem.displayName = 'ChecklistItem';
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+ import type { Timestamp } from '../lib/dates.ts';
3
+ import type { SolePerson } from '../lib/person.ts';
4
+ export interface CommentProps extends Omit<React.ComponentPropsWithoutRef<'article'>, 'children'> {
5
+ /** Who wrote it. `null` is a former member. */
6
+ author: SolePerson | null | undefined;
7
+ /**
8
+ * Who really wrote it, when a bot posted it for someone: "Ava (from the Dialer)". The name reads as the label and the
9
+ * avatar stays the bot's, so it is plain that it came through the Dialer.
10
+ */
11
+ label?: string | null;
12
+ createdAt: Timestamp;
13
+ edited?: boolean;
14
+ resolved?: boolean;
15
+ /** Page comments: the body at 14/20. */
16
+ reading?: boolean;
17
+ /** Overrides the provider's clock. */
18
+ now?: Date;
19
+ /** The viewer's time zone for the stamp. Defaults to the provider's. */
20
+ tz?: string;
21
+ /** Edit, Delete: shown on hover at the end of the header. */
22
+ actions?: React.ReactNode;
23
+ /** The rendered body. */
24
+ children: React.ReactNode;
25
+ }
26
+ export declare const Comment: React.ForwardRefExoticComponent<CommentProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { Avatar } from '../components/sole/avatar.js';
5
+ import { cn } from '../lib/cn.js';
6
+ import { formatDayTime, formatFullTimestamp } from '../lib/dates.js';
7
+ import { personName } from '../lib/person.js';
8
+ import { useNow, useSole } from '../lib/sole-provider.js';
9
+ export const Comment = React.forwardRef(function Comment({ author, label, createdAt, edited = false, resolved = false, reading = false, now, tz, actions, children, className, ...props }, ref) {
10
+ const tick = useNow();
11
+ const { timeZone } = useSole();
12
+ const zone = tz ?? timeZone;
13
+ return (_jsxs("article", { ref: ref, className: cn('group/comment flex min-w-0 gap-2.5', resolved && 'opacity-60', className), ...props, children: [_jsx(Avatar, { person: author, size: 24 }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("header", { className: "flex min-h-4 flex-wrap items-center gap-x-2 [&>*]:leading-4", children: [_jsx("span", { className: cn('text-body leading-4 font-semibold text-foreground', !author && 'text-subtle-foreground'), children: label?.trim() || personName(author) }), _jsx("time", { dateTime: createdAt, title: formatFullTimestamp(createdAt, zone), className: "tnum text-label font-normal text-subtle-foreground", children: formatDayTime(createdAt, now ?? tick, zone) }), edited && _jsx("span", { className: "text-label font-normal text-subtle-foreground", children: "edited" }), resolved && _jsx("span", { className: "text-label text-success-text", children: "Resolved" }), actions && (_jsx("span", { className: "ml-auto flex items-center gap-3 self-center opacity-0 transition-opacity duration-[120ms] group-hover/comment:opacity-100 focus-within:opacity-100", children: actions }))] }), _jsx("div", { className: cn('text-foreground', reading ? 'mt-1 text-[14px] leading-5' : 'mt-[3px] text-body'), children: children })] })] }));
14
+ });
15
+ Comment.displayName = 'Comment';
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ import type { DateOnly } from '../lib/dates.ts';
3
+ export interface DueChipProps extends React.ComponentPropsWithoutRef<'span'> {
4
+ /** Nothing is drawn without a date. */
5
+ due: DateOnly | null;
6
+ /** Defaults to today on the provider's clock. */
7
+ today?: DateOnly;
8
+ /** Completed or cancelled. */
9
+ done?: boolean;
10
+ }
11
+ export declare const DueChip: React.ForwardRefExoticComponent<DueChipProps & React.RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { CalendarClock } from 'lucide-react';
4
+ import * as React from 'react';
5
+ import { cn } from '../lib/cn.js';
6
+ import { dueChip } from '../lib/dates.js';
7
+ import { useToday } from '../lib/sole-provider.js';
8
+ // The due-date chip (brand-and-ux 5.10). Solid red is reserved for an open item past
9
+ // its due date and nothing else. Later dates and done items are plain text.
10
+ const TONES = {
11
+ overdue: 'h-[22px] rounded-md border border-transparent bg-overdue px-2 text-overdue-foreground',
12
+ today: 'h-[22px] rounded-md border border-danger-border bg-danger-soft px-2 text-danger-text',
13
+ soon: 'h-[22px] rounded-md border border-transparent bg-neutral-soft px-2 text-neutral-text',
14
+ plain: 'text-subtle-foreground',
15
+ done: 'text-subtle-foreground',
16
+ };
17
+ export const DueChip = React.forwardRef(function DueChip({ due, today, done = false, className, ...props }, ref) {
18
+ const current = useToday();
19
+ if (!due)
20
+ return null;
21
+ const chip = dueChip(due, today ?? current, done);
22
+ const boxed = chip.tone === 'overdue' || chip.tone === 'today' || chip.tone === 'soon';
23
+ return (_jsxs("span", { ...props, ref: ref, "data-due": chip.tone, title: chip.title, "aria-label": chip.ariaLabel, className: cn('tnum inline-flex shrink-0 items-center gap-[5px] text-label whitespace-nowrap', TONES[chip.tone], className), children: [boxed && _jsx(CalendarClock, { size: 12, strokeWidth: 1.8, "aria-hidden": "true" }), chip.label] }));
24
+ });
25
+ DueChip.displayName = 'DueChip';
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ import type { StateGroup } from './types.ts';
3
+ export interface GroupHeaderProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
4
+ name: string;
5
+ count?: number;
6
+ /** For `state` headers: which icon to show. */
7
+ group?: StateGroup;
8
+ variant?: 'state' | 'micro';
9
+ /** `danger` is for the Overdue bucket only. */
10
+ tone?: 'default' | 'danger';
11
+ /** Shows the "+" button on hover. */
12
+ onAdd?: () => void;
13
+ collapsed?: boolean;
14
+ /** Shows the chevron that hides and shows the group. */
15
+ onToggle?: () => void;
16
+ }
17
+ export declare const GroupHeader: React.ForwardRefExoticComponent<GroupHeaderProps & React.RefAttributes<HTMLDivElement>>;
18
+ export interface GroupLabelProps extends React.ComponentPropsWithoutRef<'div'> {
19
+ count?: number;
20
+ /** `danger` is for the Overdue bucket only. */
21
+ tone?: 'default' | 'danger';
22
+ }
23
+ /**
24
+ * Group label (40.1 Inbox "TODAY", 30.1 Home "OVERDUE 1"): 11/600 uppercase on the
25
+ * bottom of a 32px band, so it sits close to the rows it heads.
26
+ */
27
+ export declare const GroupLabel: React.ForwardRefExoticComponent<GroupLabelProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronDown, Plus } from 'lucide-react';
4
+ import * as React from 'react';
5
+ import { Button } from '../components/ui/button.js';
6
+ import { cn } from '../lib/cn.js';
7
+ import { StateIcon } from './state-icon.js';
8
+ export const GroupHeader = React.forwardRef(function GroupHeader({ name, count, group, variant = 'state', tone = 'default', onAdd, collapsed, onToggle, className, ...props }, ref) {
9
+ if (variant === 'micro') {
10
+ return (_jsx(GroupLabel, { ...props, ref: ref, count: count, tone: tone, className: className, children: name }));
11
+ }
12
+ return (_jsxs("div", { ...props, ref: ref, className: cn('group/header flex h-8 items-center gap-2 bg-muted px-3', className), children: [onToggle && (_jsx("button", { type: "button", onClick: onToggle, "aria-expanded": !collapsed, "aria-label": collapsed ? `Show ${name}` : `Hide ${name}`, className: "-ml-1 -mr-[3px] inline-flex size-5 items-center justify-center rounded-sm text-subtle-foreground hover:text-foreground focus-visible:shadow-[var(--focus-ring)] focus-visible:outline-none", children: _jsx(ChevronDown, { size: 14, className: cn('transition-transform duration-200', collapsed && '-rotate-90'), "aria-hidden": "true" }) })), group && _jsx(StateIcon, { group: group, decorative: true }), _jsx("h3", { className: "text-body font-semibold text-foreground", children: name }), count !== undefined && _jsx("span", { className: "tnum text-label text-subtle-foreground", children: count }), onAdd && (_jsx(Button, { variant: "ghost", size: "icon-xs", onClick: onAdd, "aria-label": `New work item in ${name}`, title: `New work item in ${name}`, className: "ml-auto opacity-0 group-hover/header:opacity-100 focus-visible:opacity-100", children: _jsx(Plus, { "aria-hidden": "true" }) }))] }));
13
+ });
14
+ GroupHeader.displayName = 'GroupHeader';
15
+ /**
16
+ * Group label (40.1 Inbox "TODAY", 30.1 Home "OVERDUE 1"): 11/600 uppercase on the
17
+ * bottom of a 32px band, so it sits close to the rows it heads.
18
+ */
19
+ export const GroupLabel = React.forwardRef(function GroupLabel({ children, count, tone = 'default', className, ...props }, ref) {
20
+ return (_jsxs("div", { ...props, ref: ref, className: cn('flex h-8 items-end gap-2 px-3 pb-1', className), children: [_jsx("h3", { className: cn('text-micro', tone === 'danger' ? 'text-danger-text' : 'text-subtle-foreground'), children: children }), count !== undefined && _jsx("span", { className: "tnum text-label leading-4 font-normal text-subtle-foreground", children: count })] }));
21
+ });
22
+ GroupLabel.displayName = 'GroupLabel';
@@ -0,0 +1,22 @@
1
+ import * as React from 'react';
2
+ import type { Timestamp } from '../lib/dates.ts';
3
+ import type { SolePerson } from '../lib/person.ts';
4
+ import type { SoleLinkProps } from '../lib/sole-provider.tsx';
5
+ export interface InboxRowProps extends Omit<SoleLinkProps, 'children' | 'title'> {
6
+ /** Who did it. `null` draws the plain "?" avatar of a former member. */
7
+ actor: SolePerson | null | undefined;
8
+ /** The sentence: "Ava Thompson assigned this to you". */
9
+ summary: React.ReactNode;
10
+ /** Second line: the item or page title. Comment rows can quote the comment. */
11
+ detail: React.ReactNode;
12
+ /** When it happened. Shown as relative time, with the full stamp on hover. */
13
+ at: Timestamp;
14
+ /** Draws the blue dot and tells screen readers. */
15
+ unread?: boolean;
16
+ selected?: boolean;
17
+ /** Kept on the row as `data-inbox-row`, for keyboard movement and tests. */
18
+ notificationId?: string;
19
+ /** Overrides the provider's clock. */
20
+ now?: Date;
21
+ }
22
+ export declare const InboxRow: React.ForwardRefExoticComponent<InboxRowProps & React.RefAttributes<HTMLAnchorElement>>;
@@ -0,0 +1,13 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { Avatar } from '../components/sole/avatar.js';
5
+ import { cn } from '../lib/cn.js';
6
+ import { formatFullTimestamp, formatRelative } from '../lib/dates.js';
7
+ import { SoleLink, useNow, useSole } from '../lib/sole-provider.js';
8
+ export const InboxRow = React.forwardRef(function InboxRow({ actor, summary, detail, at, unread = false, selected = false, notificationId, now, className, ...props }, ref) {
9
+ const tick = useNow();
10
+ const { timeZone } = useSole();
11
+ return (_jsxs(SoleLink, { ref: ref, "data-inbox-row": notificationId ?? '', "data-unread": unread || undefined, className: cn('flex min-h-[56px] items-center gap-2.5 border-b border-hairline py-2 pr-4 pl-3 outline-none transition-colors duration-[120ms] hover:bg-row-hover focus-visible:shadow-[inset_0_0_0_2px_var(--brand)]', selected && 'bg-accent hover:bg-accent', className), ...props, children: [_jsx("span", { "aria-hidden": "true", className: cn('size-2 shrink-0 rounded-full', unread ? 'bg-brand' : 'bg-transparent') }), _jsx("span", { className: "sr-only", children: unread ? 'Unread. ' : '' }), _jsx(Avatar, { person: actor, size: 24 }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-body text-muted-foreground", children: summary }), _jsx("span", { className: "truncate text-body font-medium text-foreground", children: detail })] }), _jsx("time", { dateTime: at, title: formatFullTimestamp(at, timeZone), className: "tnum shrink-0 text-label font-normal text-subtle-foreground", children: formatRelative(at, now ?? tick, timeZone) })] }));
12
+ });
13
+ InboxRow.displayName = 'InboxRow';
@@ -0,0 +1,21 @@
1
+ export * from './activity-line.tsx';
2
+ export * from './board-card.tsx';
3
+ export * from './board-chip.tsx';
4
+ export * from './checklist-item.tsx';
5
+ export * from './comment.tsx';
6
+ export * from './due-chip.tsx';
7
+ export * from './group-header.tsx';
8
+ export * from './inbox-row.tsx';
9
+ export * from './link-row.tsx';
10
+ export * from './mention-chip.tsx';
11
+ export * from './page-row.tsx';
12
+ export * from './priority-icon.tsx';
13
+ export * from './property-type-icon.tsx';
14
+ export * from './recent-item.tsx';
15
+ export * from './review-badge.tsx';
16
+ export * from './state-icon.tsx';
17
+ export * from './state-pill.tsx';
18
+ export * from './sticky.tsx';
19
+ export * from './template-card.tsx';
20
+ export * from './types.ts';
21
+ export * from './work-item-row.tsx';
@@ -0,0 +1,21 @@
1
+ export * from './activity-line.js';
2
+ export * from './board-card.js';
3
+ export * from './board-chip.js';
4
+ export * from './checklist-item.js';
5
+ export * from './comment.js';
6
+ export * from './due-chip.js';
7
+ export * from './group-header.js';
8
+ export * from './inbox-row.js';
9
+ export * from './link-row.js';
10
+ export * from './mention-chip.js';
11
+ export * from './page-row.js';
12
+ export * from './priority-icon.js';
13
+ export * from './property-type-icon.js';
14
+ export * from './recent-item.js';
15
+ export * from './review-badge.js';
16
+ export * from './state-icon.js';
17
+ export * from './state-pill.js';
18
+ export * from './sticky.js';
19
+ export * from './template-card.js';
20
+ export * from './types.js';
21
+ export * from './work-item-row.js';
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ export interface LinkRowProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title'> {
3
+ /** An `http` address opens in a new tab; anything else goes through the provider's link. */
4
+ href: string;
5
+ title: React.ReactNode;
6
+ /** "#pricing · Noah Patel · 24 Sep". */
7
+ meta?: React.ReactNode;
8
+ actions?: React.ReactNode;
9
+ /** In place of the link glyph; 16px, subtle, decorative. */
10
+ icon?: React.ReactNode;
11
+ }
12
+ /** Link row (50.6 Links): 36px box, a link icon, the title as a link, then the meta. */
13
+ export declare const LinkRow: React.ForwardRefExoticComponent<LinkRowProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,13 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Link2 } from 'lucide-react';
4
+ import * as React from 'react';
5
+ import { cn } from '../lib/cn.js';
6
+ import { SoleLink } from '../lib/sole-provider.js';
7
+ /** Link row (50.6 Links): 36px box, a link icon, the title as a link, then the meta. */
8
+ export const LinkRow = React.forwardRef(function LinkRow({ href, title, meta, actions, icon, className, ...props }, ref) {
9
+ const external = /^https?:\/\//.test(href);
10
+ const linkClass = 'min-w-0 shrink truncate text-body font-medium text-link outline-none hover:underline focus-visible:underline';
11
+ return (_jsxs("div", { ref: ref, className: cn('group/link flex h-9 min-w-0 items-center gap-2 rounded-lg border border-border bg-card px-2', className), ...props, children: [icon ?? _jsx(Link2, { size: 16, strokeWidth: 1.8, "aria-hidden": "true", className: "shrink-0 text-subtle-foreground" }), external ? (_jsx("a", { href: href, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: title })) : (_jsx(SoleLink, { href: href, className: linkClass, children: title })), meta && _jsx("span", { className: "ml-1 min-w-0 flex-1 truncate text-label font-normal text-subtle-foreground", children: meta }), actions && _jsx("span", { className: "ml-auto flex shrink-0 items-center gap-1 opacity-0 group-hover/link:opacity-100 focus-within:opacity-100", children: actions })] }));
12
+ });
13
+ LinkRow.displayName = 'LinkRow';
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+ import type { SolePerson } from '../lib/person.ts';
3
+ export interface MentionChipProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'children'> {
4
+ /** The person, when known, for the current name and the avatar colour. */
5
+ person?: SolePerson | null;
6
+ /** The name stored in the document, used when the person is not loaded. */
7
+ label?: string;
8
+ }
9
+ /**
10
+ * Mention chip: how an @mention reads in any rendered text. The 16px avatar and the name
11
+ * in blue on the accent fill; 22px, but set in the line without making it taller.
12
+ */
13
+ export declare const MentionChip: React.ForwardRefExoticComponent<MentionChipProps & React.RefAttributes<HTMLSpanElement>>;
14
+ export interface CitationChipProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'children'> {
15
+ /** The source number: 2 reads "[2]" in the answer and is named "Source 2". */
16
+ n: number;
17
+ /** Makes the chip a link. */
18
+ href?: string;
19
+ /** Makes the chip a button, or runs beside the link. */
20
+ onClick?: () => void;
21
+ }
22
+ /** Citation chip: [2] in an Ask answer, a 16px square, 10/600 on the muted fill. A link, a button or plain, by what it is given. */
23
+ export declare const CitationChip: React.ForwardRefExoticComponent<CitationChipProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,28 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { Avatar } from '../components/sole/avatar.js';
5
+ import { cn } from '../lib/cn.js';
6
+ import { FORMER_MEMBER, personName } from '../lib/person.js';
7
+ /**
8
+ * Mention chip: how an @mention reads in any rendered text. The 16px avatar and the name
9
+ * in blue on the accent fill; 22px, but set in the line without making it taller.
10
+ */
11
+ export const MentionChip = React.forwardRef(function MentionChip({ person, label, className, ...props }, ref) {
12
+ const name = person ? personName(person) : label || FORMER_MEMBER;
13
+ return (_jsxs("span", { ref: ref, "data-mention": person?.id ?? '', className: cn('mx-px -my-px inline-flex h-[22px] max-w-full items-center gap-1 rounded-md bg-accent pr-1.5 pl-[3px] align-middle text-[0.8125rem] leading-none font-medium whitespace-nowrap text-accent-foreground', className), ...props, children: [person ? _jsx(Avatar, { person: person, size: 16 }) : _jsx("span", { "aria-hidden": "true", children: "@" }), _jsx("span", { className: "truncate", children: name })] }));
14
+ });
15
+ MentionChip.displayName = 'MentionChip';
16
+ /** Citation chip: [2] in an Ask answer, a 16px square, 10/600 on the muted fill. A link, a button or plain, by what it is given. */
17
+ export const CitationChip = React.forwardRef(function CitationChip({ n, href, onClick, className, ...props }, ref) {
18
+ const classes = cn('mx-0.5 inline-flex size-4 items-center justify-center rounded-sm bg-muted align-[1px] text-[10px] leading-none font-semibold text-muted-foreground tnum', (href || onClick) && 'outline-none hover:bg-accent hover:text-accent-foreground focus-visible:shadow-[var(--focus-ring)]', className);
19
+ const label = `Source ${n}`;
20
+ if (href) {
21
+ return (_jsx("a", { ref: ref, href: href, onClick: onClick, "aria-label": label, className: classes, ...props, children: n }));
22
+ }
23
+ if (onClick) {
24
+ return (_jsx("button", { ref: ref, type: "button", onClick: onClick, "aria-label": label, className: classes, ...props, children: n }));
25
+ }
26
+ return (_jsx("span", { ref: ref, "aria-label": label, className: classes, ...props, children: n }));
27
+ });
28
+ CitationChip.displayName = 'CitationChip';
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+ import type { DateOnly, Timestamp } from '../lib/dates.ts';
3
+ import type { SolePerson } from '../lib/person.ts';
4
+ export interface PageRowProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title' | 'children'> {
5
+ /** Where the page opens. The title is the link, stretched over the whole row. */
6
+ href: string;
7
+ title: string;
8
+ isPrivate?: boolean;
9
+ reviewDue: DateOnly | null;
10
+ /** "Knowledge", when the list mixes spaces (80.2 Pages they own, 02.7). */
11
+ spaceName?: string | null;
12
+ folderName?: string | null;
13
+ tags?: Array<{
14
+ id: string;
15
+ name: string;
16
+ }>;
17
+ commentCount?: number;
18
+ owner: SolePerson | null;
19
+ collaborators?: SolePerson[];
20
+ updatedAt: Timestamp;
21
+ /** Defaults to today on the provider's clock. */
22
+ today?: DateOnly;
23
+ /** The row's overflow menu, shown on hover. */
24
+ actions?: React.ReactNode;
25
+ }
26
+ export declare const PageRow: React.ForwardRefExoticComponent<PageRowProps & React.RefAttributes<HTMLDivElement>>;