@botiverse/raft-ui 0.83.0 → 0.84.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 (47) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/dist/components/app-link-card/app-link-card.mjs +19 -37
  3. package/dist/components/banner/banner.mjs +15 -2
  4. package/dist/components/drag/drag.recipe.mjs +1 -1
  5. package/dist/components/fit-toolbar/fit-toolbar.d.mts +63 -8
  6. package/dist/components/fit-toolbar/fit-toolbar.mjs +310 -43
  7. package/dist/components/fit-toolbar/fit-toolbar.recipe.mjs +21 -7
  8. package/dist/components/fit-toolbar/index.d.mts +2 -2
  9. package/dist/components/lightbox/index.d.mts +2 -2
  10. package/dist/components/lightbox/lightbox.d.mts +70 -4
  11. package/dist/components/lightbox/lightbox.mjs +285 -91
  12. package/dist/components/list-row/list-row.d.mts +14 -1
  13. package/dist/components/list-row/list-row.mjs +4 -2
  14. package/dist/components/list-row/list-row.recipe.d.mts +12 -0
  15. package/dist/components/list-row/list-row.recipe.mjs +19 -7
  16. package/dist/components/message-action-card/message-action-card-content.recipe.mjs +3 -3
  17. package/dist/components/message-action-card/message-action-card.mjs +7 -3
  18. package/dist/components/message-action-card/message-action-card.recipe.mjs +2 -6
  19. package/dist/components/message-embed/index.d.mts +2 -1
  20. package/dist/components/message-embed/message-embed.d.mts +8 -1
  21. package/dist/components/message-embed/message-embed.mjs +2 -2
  22. package/dist/components/message-embed/message-embed.recipe.d.mts +160 -0
  23. package/dist/components/message-embed/message-embed.recipe.mjs +49 -10
  24. package/dist/components/message-forwarded-bundle/message-forwarded-bundle.mjs +1 -0
  25. package/dist/components/message-forwarded-bundle/message-forwarded-bundle.recipe.mjs +1 -1
  26. package/dist/components/message-quoted-preview/message-quoted-preview.mjs +2 -0
  27. package/dist/components/message-replies/message-replies.mjs +1 -1
  28. package/dist/components/message-replies/message-replies.recipe.mjs +1 -1
  29. package/dist/components/popover/popover.d.mts +11 -2
  30. package/dist/components/popover/popover.mjs +51 -38
  31. package/dist/components/preview-card/preview-card.d.mts +5 -1
  32. package/dist/components/preview-card/preview-card.mjs +24 -27
  33. package/dist/components/save-status/save-status.d.mts +16 -9
  34. package/dist/components/save-status/save-status.mjs +19 -30
  35. package/dist/components/segmented-control/segmented-control.mjs +45 -8
  36. package/dist/components/task-board/task-board.d.mts +5 -0
  37. package/dist/components/task-board/task-board.mjs +8 -1
  38. package/dist/components/task-dnd/task-dnd.d.mts +10 -1
  39. package/dist/components/task-dnd/task-dnd.mjs +2 -1
  40. package/dist/components/toast/toast.mjs +2 -2
  41. package/dist/index.d.mts +2 -1
  42. package/dist/index.mjs +2 -1
  43. package/dist/lib/laid-out-children.mjs +32 -0
  44. package/dist/lib/stacked-actions.mjs +7 -4
  45. package/dist/wip.d.mts +4 -2
  46. package/dist/wip.mjs +3 -2
  47. package/package.json +1 -1
@@ -7,7 +7,6 @@ const listRow = tv({
7
7
  "group/list-row flex w-full min-w-0 items-center gap-3 py-3 text-left",
8
8
  "font-sans no-underline",
9
9
  "[--list-row-ink:var(--foreground)] [--list-row-ink-2:var(--foreground-muted)] [--list-row-ink-3:var(--foreground-hint)]",
10
- "[--list-row-status-space:0px]",
11
10
  "text-(--list-row-ink)",
12
11
  "not-disabled:not-aria-disabled:data-[tone=unread]:[--list-row-ink-2:var(--foreground)]",
13
12
  "not-disabled:not-aria-disabled:data-[tone=muted]:[--list-row-ink:var(--foreground-muted)]",
@@ -19,7 +18,7 @@ const listRow = tv({
19
18
  "aria-disabled:[--list-row-ink-2:var(--foreground-disabled)] aria-disabled:[--list-row-ink-3:var(--foreground-disabled)]"
20
19
  ],
21
20
  icon: ["flex shrink-0 items-center justify-center", "text-(--list-row-ink-3) [&>svg]:size-5 [&>svg]:shrink-0"],
22
- body: ["flex min-w-0 flex-1 flex-col gap-0.5", "-mb-(--list-row-status-space,0px)"],
21
+ body: ["flex min-w-0 flex-1 flex-col gap-0.5"],
23
22
  line: ["flex min-w-0 items-center gap-2"],
24
23
  title: [
25
24
  "min-w-0 flex-1 truncate",
@@ -35,17 +34,17 @@ const listRow = tv({
35
34
  variants: {
36
35
  variant: {
37
36
  default: { root: "min-h-16 pointer-coarse:min-h-14 pointer-coarse:py-2 [--list-row-rule-start:63px]" },
38
- plain: { root: [
39
- "py-(--settings-row-inset) pb-[calc(var(--settings-row-inset)+var(--list-row-status-space))]",
40
- "has-[>[data-slot=list-row-body]>[data-slot=save-status]]:[--list-row-status-space:calc(--spacing(1)+var(--text-footnote--line-height))]",
41
- "[--list-row-rule-start:16px]"
42
- ] },
37
+ plain: { root: ["py-(--settings-row-inset)", "[--list-row-rule-start:16px]"] },
43
38
  entry: { root: "" }
44
39
  },
45
40
  interactive: {
46
41
  true: {},
47
42
  false: {}
48
43
  },
44
+ attached: {
45
+ true: {},
46
+ false: {}
47
+ },
49
48
  cell: {
50
49
  false: { root: [
51
50
  "relative px-4",
@@ -67,6 +66,7 @@ const listRow = tv({
67
66
  compoundVariants: [
68
67
  {
69
68
  cell: false,
69
+ attached: false,
70
70
  variant: ["default", "plain"],
71
71
  class: { root: [
72
72
  "before:pointer-events-none before:absolute before:top-0 before:right-0 before:hidden",
@@ -74,6 +74,17 @@ const listRow = tv({
74
74
  "[[data-slot=list-row]+&]:before:block [li+li>&]:before:block"
75
75
  ] }
76
76
  },
77
+ {
78
+ variant: "plain",
79
+ attached: true,
80
+ class: { root: "pt-0" }
81
+ },
82
+ {
83
+ variant: "plain",
84
+ attached: true,
85
+ interactive: true,
86
+ class: { root: "min-h-control" }
87
+ },
77
88
  {
78
89
  cell: false,
79
90
  interactive: true,
@@ -92,6 +103,7 @@ const listRow = tv({
92
103
  defaultVariants: {
93
104
  variant: "default",
94
105
  interactive: true,
106
+ attached: false,
95
107
  cell: false,
96
108
  wrap: false
97
109
  }
@@ -1,7 +1,7 @@
1
1
  import { tv } from "../../lib/tv.mjs";
2
2
  //#region src/components/message-action-card/message-action-card-content.recipe.ts
3
3
  const messageActionCardContent = tv({ slots: {
4
- root: ["p-3", "flex flex-col gap-2 px-3 pt-0 pb-3"],
4
+ root: ["flex flex-col gap-2 pt-0"],
5
5
  panel: [
6
6
  "h-(--collapsible-panel-height) overflow-hidden",
7
7
  "transition-[height] duration-200 ease-out motion-reduce:transition-none",
@@ -44,8 +44,8 @@ const messageActionCardContent = tv({ slots: {
44
44
  "[&>svg]:mt-[calc((1lh-14px)/2)] [&>svg]:text-foreground-muted"
45
45
  ],
46
46
  completion: ["inline-flex items-center gap-1.5 text-footnote text-foreground-muted", "[&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-foreground"],
47
- actions: ["flex flex-wrap items-center justify-end", "mt-1 gap-2"],
48
- actionsNote: ["min-w-0 flex-1 basis-40", "text-footnote text-foreground-muted"]
47
+ actions: ["mt-1"],
48
+ actionsNote: ["min-w-0 basis-full", "text-footnote text-foreground-muted"]
49
49
  } });
50
50
  //#endregion
51
51
  export { messageActionCardContent };
@@ -1,5 +1,6 @@
1
1
  import { ScrollArea } from "../scroll-area/scroll-area.mjs";
2
2
  import { Badge } from "../badge/badge.mjs";
3
+ import { messageCard } from "../message-embed/message-embed.recipe.mjs";
3
4
  import { useLabelValueFit } from "../../lib/label-value-fit.mjs";
4
5
  import { MessageEmbed, MessageEmbedContent, MessageEmbedHeader } from "../message-embed/message-embed.mjs";
5
6
  import { messageActionCard } from "./message-action-card.recipe.mjs";
@@ -25,6 +26,7 @@ function MessageActionCard({ className, render, open, defaultOpen = true, onOpen
25
26
  defaultOpen,
26
27
  onOpenChange,
27
28
  render: /* @__PURE__ */ jsx(MessageEmbed, {
29
+ size: "item",
28
30
  className: root({ className }),
29
31
  render,
30
32
  ...props
@@ -36,7 +38,7 @@ function MessageActionCardContent({ className, render, ...props }) {
36
38
  return /* @__PURE__ */ jsx(Collapsible.Panel, {
37
39
  className: panel(),
38
40
  children: /* @__PURE__ */ jsx(MessageEmbedContent, {
39
- className: root({ className }),
41
+ className: messageCard().inset({ className: root({ className }) }),
40
42
  render,
41
43
  ...props
42
44
  })
@@ -129,8 +131,9 @@ function MessageActionCardCollapseTrigger({ className, ...props }) {
129
131
  }
130
132
  function MessageActionCardHeader({ className, render, ...props }) {
131
133
  const { header } = messageActionCard();
134
+ const { inset, heading } = messageCard();
132
135
  return /* @__PURE__ */ jsx(MessageEmbedHeader, {
133
- className: header({ className }),
136
+ className: inset({ className: heading({ className: header({ className }) }) }),
134
137
  render,
135
138
  ...props
136
139
  });
@@ -290,10 +293,11 @@ function MessageActionCardCompletion({ className, render, ...props }) {
290
293
  }
291
294
  function MessageActionCardActions({ className, render, ...props }) {
292
295
  const { actions } = messageActionCardContent();
296
+ const { actionRow } = messageCard();
293
297
  return useRender({
294
298
  defaultTagName: "div",
295
299
  render,
296
- props: mergeProps({ className: actions({ className }) }, props),
300
+ props: mergeProps({ className: actionRow({ className: actions({ className }) }) }, props),
297
301
  state: { slot: "message-action-card-actions" }
298
302
  });
299
303
  }
@@ -2,12 +2,8 @@ import { tv } from "../../lib/tv.mjs";
2
2
  //#region src/components/message-action-card/message-action-card.recipe.ts
3
3
  const messageActionCard = tv({
4
4
  slots: {
5
- root: ["w-full", "group/action-card mt-2 max-w-[440px]"],
6
- header: [
7
- "flex items-start",
8
- "gap-2 px-3 pt-3 pb-2 group-data-closed/action-card:pb-3",
9
- "text-subhead font-bold text-foreground"
10
- ],
5
+ root: ["group/action-card mt-2"],
6
+ header: ["flex items-start", "gap-2 pb-2 group-data-closed/action-card:pb-3"],
11
7
  headerIcon: [
12
8
  "flex shrink-0 items-center justify-center",
13
9
  "[&>svg]:shrink-0",
@@ -1,2 +1,3 @@
1
1
  import { MessageEmbed, MessageEmbedContent, MessageEmbedContentProps, MessageEmbedFooter, MessageEmbedFooterProps, MessageEmbedHeader, MessageEmbedHeaderProps, MessageEmbedProps } from "./message-embed.mjs";
2
- export { MessageEmbed, MessageEmbedContent, type MessageEmbedContentProps, MessageEmbedFooter, type MessageEmbedFooterProps, MessageEmbedHeader, type MessageEmbedHeaderProps, type MessageEmbedProps };
2
+ import { messageCard, messageEmbed } from "./message-embed.recipe.mjs";
3
+ export { MessageEmbed, MessageEmbedContent, type MessageEmbedContentProps, MessageEmbedFooter, type MessageEmbedFooterProps, MessageEmbedHeader, type MessageEmbedHeaderProps, type MessageEmbedProps, messageCard, messageEmbed };
@@ -1,7 +1,7 @@
1
1
  import { useRender } from "@base-ui/react/use-render";
2
2
  //#region src/components/message-embed/message-embed.d.ts
3
3
  type DivProps = useRender.ComponentProps<"div">;
4
- export declare function MessageEmbed({ interactive, className, render, ...props }: MessageEmbedProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
4
+ export declare function MessageEmbed({ interactive, size, className, render, ...props }: MessageEmbedProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
5
5
  export declare function MessageEmbedHeader({ className, render, ...props }: DivProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
6
6
  export declare function MessageEmbedContent({ className, render, ...props }: DivProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
7
7
  export declare function MessageEmbedFooter({ className, render, ...props }: DivProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
@@ -13,6 +13,13 @@ export type MessageEmbedProps = DivProps & {
13
13
  * @default false
14
14
  */
15
15
  interactive?: boolean;
16
+ /**
17
+ * The card's width, one of the two a card in a message has
18
+ * (cards-in-messages.md): `item` for a card that opens one thing, at most
19
+ * 400px and the message's width on a phone; `content` for a card that
20
+ * shows other messages, at most 560px. Unset, the card sets no width.
21
+ */
22
+ size?: "item" | "content";
16
23
  };
17
24
  export type MessageEmbedHeaderProps = DivProps;
18
25
  export type MessageEmbedContentProps = DivProps;
@@ -2,8 +2,8 @@ import { messageEmbed } from "./message-embed.recipe.mjs";
2
2
  import { mergeProps } from "@base-ui/react/merge-props";
3
3
  import { useRender } from "@base-ui/react/use-render";
4
4
  //#region src/components/message-embed/message-embed.tsx
5
- function MessageEmbed({ interactive = false, className, render, ...props }) {
6
- const { root } = messageEmbed();
5
+ function MessageEmbed({ interactive = false, size, className, render, ...props }) {
6
+ const { root } = messageEmbed({ size });
7
7
  const defaultProps = {
8
8
  "data-interactive": interactive ? "true" : void 0,
9
9
  className: root({ className })
@@ -0,0 +1,160 @@
1
+ //#region src/components/message-embed/message-embed.recipe.d.ts
2
+ export declare const messageEmbed: import("tailwind-variants/lite").TVReturnType<{
3
+ size: {
4
+ item: {
5
+ root: string[];
6
+ };
7
+ content: {
8
+ root: string[];
9
+ };
10
+ };
11
+ }, {
12
+ root: string[];
13
+ header: string[];
14
+ content: string[];
15
+ footer: string[];
16
+ }, undefined, {
17
+ size: {
18
+ item: {
19
+ root: string[];
20
+ };
21
+ content: {
22
+ root: string[];
23
+ };
24
+ };
25
+ }, {
26
+ root: string[];
27
+ header: string[];
28
+ content: string[];
29
+ footer: string[];
30
+ }, import("tailwind-variants/lite").TVReturnTypeLike<{
31
+ size: {
32
+ item: {
33
+ root: string[];
34
+ };
35
+ content: {
36
+ root: string[];
37
+ };
38
+ };
39
+ }, {
40
+ root: string[];
41
+ header: string[];
42
+ content: string[];
43
+ footer: string[];
44
+ }>>;
45
+ export declare const messageCard: import("tailwind-variants/lite").TVReturnType<{
46
+ [key: string]: {
47
+ [key: string]: {
48
+ actionGroup?: import("tailwind-variants/lite").ClassValue;
49
+ actionRow?: import("tailwind-variants/lite").ClassValue;
50
+ actions?: import("tailwind-variants/lite").ClassValue;
51
+ body?: import("tailwind-variants/lite").ClassValue;
52
+ eyebrow?: import("tailwind-variants/lite").ClassValue;
53
+ heading?: import("tailwind-variants/lite").ClassValue;
54
+ inset?: import("tailwind-variants/lite").ClassValue;
55
+ meta?: import("tailwind-variants/lite").ClassValue;
56
+ popover?: import("tailwind-variants/lite").ClassValue;
57
+ source?: import("tailwind-variants/lite").ClassValue;
58
+ sourceFooter?: import("tailwind-variants/lite").ClassValue;
59
+ sourceHost?: import("tailwind-variants/lite").ClassValue;
60
+ sourceHostText?: import("tailwind-variants/lite").ClassValue;
61
+ sourceIcon?: import("tailwind-variants/lite").ClassValue;
62
+ sourceName?: import("tailwind-variants/lite").ClassValue;
63
+ title?: import("tailwind-variants/lite").ClassValue;
64
+ } | import("tailwind-variants/lite").ClassValue;
65
+ };
66
+ } | {
67
+ [x: string]: {
68
+ [x: string]: {
69
+ actionGroup?: import("tailwind-variants/lite").ClassValue;
70
+ actionRow?: import("tailwind-variants/lite").ClassValue;
71
+ actions?: import("tailwind-variants/lite").ClassValue;
72
+ body?: import("tailwind-variants/lite").ClassValue;
73
+ eyebrow?: import("tailwind-variants/lite").ClassValue;
74
+ heading?: import("tailwind-variants/lite").ClassValue;
75
+ inset?: import("tailwind-variants/lite").ClassValue;
76
+ meta?: import("tailwind-variants/lite").ClassValue;
77
+ popover?: import("tailwind-variants/lite").ClassValue;
78
+ source?: import("tailwind-variants/lite").ClassValue;
79
+ sourceFooter?: import("tailwind-variants/lite").ClassValue;
80
+ sourceHost?: import("tailwind-variants/lite").ClassValue;
81
+ sourceHostText?: import("tailwind-variants/lite").ClassValue;
82
+ sourceIcon?: import("tailwind-variants/lite").ClassValue;
83
+ sourceName?: import("tailwind-variants/lite").ClassValue;
84
+ title?: import("tailwind-variants/lite").ClassValue;
85
+ } | import("tailwind-variants/lite").ClassValue;
86
+ };
87
+ } | {}, {
88
+ source: string[];
89
+ sourceIcon: string[];
90
+ sourceName: string[];
91
+ sourceHost: string[];
92
+ sourceHostText: string[];
93
+ sourceFooter: string[];
94
+ body: string[];
95
+ eyebrow: string[];
96
+ title: string[];
97
+ heading: string[];
98
+ meta: string[];
99
+ actions: string[];
100
+ actionRow: string[];
101
+ actionGroup: string[];
102
+ inset: string[];
103
+ popover: string[];
104
+ }, undefined, {
105
+ [key: string]: {
106
+ [key: string]: {
107
+ actionGroup?: import("tailwind-variants/lite").ClassValue;
108
+ actionRow?: import("tailwind-variants/lite").ClassValue;
109
+ actions?: import("tailwind-variants/lite").ClassValue;
110
+ body?: import("tailwind-variants/lite").ClassValue;
111
+ eyebrow?: import("tailwind-variants/lite").ClassValue;
112
+ heading?: import("tailwind-variants/lite").ClassValue;
113
+ inset?: import("tailwind-variants/lite").ClassValue;
114
+ meta?: import("tailwind-variants/lite").ClassValue;
115
+ popover?: import("tailwind-variants/lite").ClassValue;
116
+ source?: import("tailwind-variants/lite").ClassValue;
117
+ sourceFooter?: import("tailwind-variants/lite").ClassValue;
118
+ sourceHost?: import("tailwind-variants/lite").ClassValue;
119
+ sourceHostText?: import("tailwind-variants/lite").ClassValue;
120
+ sourceIcon?: import("tailwind-variants/lite").ClassValue;
121
+ sourceName?: import("tailwind-variants/lite").ClassValue;
122
+ title?: import("tailwind-variants/lite").ClassValue;
123
+ } | import("tailwind-variants/lite").ClassValue;
124
+ };
125
+ } | {}, {
126
+ source: string[];
127
+ sourceIcon: string[];
128
+ sourceName: string[];
129
+ sourceHost: string[];
130
+ sourceHostText: string[];
131
+ sourceFooter: string[];
132
+ body: string[];
133
+ eyebrow: string[];
134
+ title: string[];
135
+ heading: string[];
136
+ meta: string[];
137
+ actions: string[];
138
+ actionRow: string[];
139
+ actionGroup: string[];
140
+ inset: string[];
141
+ popover: string[];
142
+ }, import("tailwind-variants/lite").TVReturnTypeLike<unknown, {
143
+ source: string[];
144
+ sourceIcon: string[];
145
+ sourceName: string[];
146
+ sourceHost: string[];
147
+ sourceHostText: string[];
148
+ sourceFooter: string[];
149
+ body: string[];
150
+ eyebrow: string[];
151
+ title: string[];
152
+ heading: string[];
153
+ meta: string[];
154
+ actions: string[];
155
+ actionRow: string[];
156
+ actionGroup: string[];
157
+ inset: string[];
158
+ popover: string[];
159
+ }>>;
160
+ //#endregion
@@ -1,15 +1,54 @@
1
1
  import { tv } from "../../lib/tv.mjs";
2
2
  //#region src/components/message-embed/message-embed.recipe.ts
3
- const messageEmbed = tv({ slots: {
4
- root: [
5
- "group block min-w-0 text-left",
6
- "rounded-container border border-line-hairline bg-layer-card",
7
- "outline-none focus-visible:shadow-focus",
8
- "data-[interactive=true]:hover:overlay-subtle data-[interactive=true]:active:overlay-medium"
3
+ const messageEmbed = tv({
4
+ slots: {
5
+ root: [
6
+ "group block min-w-0 text-left",
7
+ "rounded-container border border-line-hairline bg-layer-card",
8
+ "outline-none focus-visible:shadow-focus",
9
+ "data-[interactive=true]:hover:overlay-subtle data-[interactive=true]:active:overlay-medium",
10
+ "not-data-[frame=bar]:*:data-[slot=message-embed-content]:first:rounded-t-[calc(var(--radius-container)-1px)] not-data-[frame=bar]:*:data-[slot=message-embed-content]:first:overflow-clip",
11
+ "not-data-[frame=bar]:*:data-[slot=message-embed-content]:last:rounded-b-[calc(var(--radius-container)-1px)] not-data-[frame=bar]:*:data-[slot=message-embed-content]:last:overflow-clip"
12
+ ],
13
+ header: ["min-w-0", "px-3 py-2"],
14
+ content: ["min-w-0"],
15
+ footer: ["min-w-0", "px-3 py-2"]
16
+ },
17
+ variants: { size: {
18
+ item: { root: ["w-full max-w-[400px] max-md:max-w-none"] },
19
+ content: { root: ["w-full max-w-[560px]"] }
20
+ } }
21
+ });
22
+ const messageCard = tv({ slots: {
23
+ source: [
24
+ "flex min-w-0 items-center gap-1.5",
25
+ "border-b border-line-hairline px-3 py-2",
26
+ "font-sans text-caption text-foreground-muted"
9
27
  ],
10
- header: ["min-w-0", "px-3 py-2"],
11
- content: ["min-w-0"],
12
- footer: ["min-w-0", "px-3 py-2"]
28
+ sourceIcon: ["inline-flex size-4 shrink-0 items-center justify-center", "*:size-full *:shrink-0 [&>img]:rounded-[2px] [&>img]:object-cover"],
29
+ sourceName: ["min-w-0 truncate", "font-semibold text-foreground"],
30
+ sourceHost: ["flex min-w-0 items-baseline", "before:shrink-0 before:pe-1.5 before:content-['·']"],
31
+ sourceHostText: ["min-w-0 truncate"],
32
+ sourceFooter: [
33
+ "m-0 truncate",
34
+ "border-t border-line-hairline px-3 py-2",
35
+ "font-sans text-caption text-foreground-muted"
36
+ ],
37
+ body: ["flex min-w-0 flex-col gap-1.5", "p-3"],
38
+ eyebrow: ["m-0 truncate", "font-mono text-mono-meta text-foreground-muted"],
39
+ title: [
40
+ "m-0 line-clamp-2",
41
+ "font-sans text-subhead font-bold text-foreground",
42
+ "[&_a]:rounded-[2px] [&_a]:decoration-[1.5px] [&_a]:underline-offset-[3px] [&_a]:hover:underline",
43
+ "[&_a]:outline-none [&_a]:focus-visible:shadow-focus"
44
+ ],
45
+ heading: ["font-sans text-subhead font-bold text-foreground"],
46
+ meta: ["flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", "m-0 font-sans text-callout text-foreground-muted"],
47
+ actions: ["flex flex-wrap items-center justify-end gap-2", "px-3 pb-3"],
48
+ actionRow: ["flex flex-wrap items-center justify-end gap-2"],
49
+ actionGroup: ["flex min-w-0 max-w-full flex-wrap items-center justify-end gap-2", "ms-auto"],
50
+ inset: ["p-3"],
51
+ popover: ["w-[400px] max-w-(--available-width)"]
13
52
  } });
14
53
  //#endregion
15
- export { messageEmbed };
54
+ export { messageCard, messageEmbed };
@@ -56,6 +56,7 @@ function MessageForwardedBundle({ className, fullWidth = false, render, ...props
56
56
  return /* @__PURE__ */ jsx(MessageForwardedBundleFoldContext.Provider, {
57
57
  value: fold,
58
58
  children: /* @__PURE__ */ jsx(MessageEmbed, {
59
+ size: fullWidth ? void 0 : "content",
59
60
  className: root({ className }),
60
61
  render,
61
62
  ...props
@@ -2,7 +2,7 @@ import { tv } from "../../lib/tv.mjs";
2
2
  //#region src/components/message-forwarded-bundle/message-forwarded-bundle.recipe.ts
3
3
  const messageForwardedBundle = tv({
4
4
  slots: {
5
- root: ["mt-1 max-w-[min(34rem,100%)]"],
5
+ root: ["mt-1"],
6
6
  header: ["flex flex-wrap items-center justify-between", "gap-2"],
7
7
  headerContent: ["flex min-w-0 items-center", "gap-2"],
8
8
  headerLabel: ["inline-flex shrink-0 items-center", "gap-1 text-footnote font-bold text-foreground-muted [&_svg]:size-3.5"],
@@ -7,6 +7,7 @@ import { useRender } from "@base-ui/react/use-render";
7
7
  function MessageQuotedPreview({ className, render, ...props }) {
8
8
  const { root } = messageQuotedPreview();
9
9
  return /* @__PURE__ */ jsx(MessageEmbed, {
10
+ "data-frame": "bar",
10
11
  className: root({ className }),
11
12
  render,
12
13
  ...props
@@ -126,6 +127,7 @@ function MessageQuotedPreviewAttachment({ className, render, ...props }) {
126
127
  function MessageQuotedPreviewLoading({ className, render, ...props }) {
127
128
  const { loading } = messageQuotedPreview();
128
129
  return /* @__PURE__ */ jsx(MessageEmbed, {
130
+ "data-frame": "bar",
129
131
  className: loading({ className }),
130
132
  render,
131
133
  ...props
@@ -6,7 +6,7 @@ import { useRender } from "@base-ui/react/use-render";
6
6
  //#region src/components/message-replies/message-replies.tsx
7
7
  function MessageReplies({ className, render, ...props }) {
8
8
  const { root } = messageReplies();
9
- const { root: embedRoot } = messageEmbed();
9
+ const { root: embedRoot } = messageEmbed({ size: "content" });
10
10
  const defaultProps = { className: embedRoot({ className: root({ className }) }) };
11
11
  return useRender({
12
12
  defaultTagName: "button",
@@ -4,7 +4,7 @@ const messageReplies = tv({ slots: {
4
4
  root: [
5
5
  "group/message-replies flex min-w-0 w-full flex-col text-left",
6
6
  "transition-colors focus-visible:keyboard:outline-1 focus-visible:keyboard:outline-line-strong",
7
- "mt-2 max-w-[480px] gap-1 rounded-container border-0 px-2.5 py-2",
7
+ "mt-2 gap-1 border-0 px-2.5 py-2",
8
8
  "bg-fill-muted text-foreground-muted hover:overlay-subtle active:overlay-medium",
9
9
  "focus-visible:outline-none focus-visible:shadow-focus"
10
10
  ],
@@ -13,8 +13,17 @@ export declare function PopoverPopup({ className, ...props }: PopoverPopupProps)
13
13
  export type PopoverContentProps = StyledProps<Popover.Popup.Props> & Pick<Popover.Positioner.Props, "align" | "alignOffset" | "anchor" | "arrowPadding" | "collisionAvoidance" | "collisionBoundary" | "collisionPadding" | "disableAnchorTracking" | "positionMethod" | "side" | "sideOffset" | "sticky"> & {
14
14
  container?: PopoverPortalProps["container"];
15
15
  portalProps?: PopoverPortalProps;
16
+ /**
17
+ * `item` for a popover about an app's item, such as the question before
18
+ * its link previews are shown: 400px, and `PopoverBody`, `PopoverTitle`
19
+ * and `PopoverActions` take a card's parts and 12px inset, like the item
20
+ * card (PreviewCard `size="item"`). Choose it by what the popover is
21
+ * about, not by its parts.
22
+ * @default "default"
23
+ */
24
+ size?: "default" | "item";
16
25
  };
17
- export declare function PopoverContent({ align, alignOffset, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking, positionMethod, side, sideOffset, sticky, container, portalProps, className, ...props }: PopoverContentProps): import("react").JSX.Element;
26
+ export declare function PopoverContent({ align, alignOffset, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking, positionMethod, side, sideOffset, sticky, container, portalProps, size, className, ...props }: PopoverContentProps): import("react").JSX.Element;
18
27
  export type PopoverViewportProps = StyledProps<Popover.Viewport.Props>;
19
28
  export declare function PopoverViewport({ className, ...props }: PopoverViewportProps): import("react").JSX.Element;
20
29
  export type PopoverHeaderProps = ComponentPropsWithRef<"div">;
@@ -32,7 +41,7 @@ export declare function PopoverArrow({ className, ...props }: PopoverArrowProps)
32
41
  export type PopoverBackdropProps = StyledProps<Popover.Backdrop.Props>;
33
42
  export declare function PopoverBackdrop({ className, ...props }: PopoverBackdropProps): import("react").JSX.Element;
34
43
  export type PopoverBodyProps = ComponentPropsWithRef<"div">;
35
- /** The panel's text: a `PopoverTitle` and a `PopoverDescription`, 16px in from its edges. */
44
+ /** The panel's text: a `PopoverTitle` and a `PopoverDescription`, 16px in from its edges (12px in a `size="item"` popover). */
36
45
  export declare function PopoverBody({ className, ...props }: PopoverBodyProps): import("react").JSX.Element;
37
46
  export type PopoverActionsProps = ComponentPropsWithRef<"div">;
38
47
  /** The panel's buttons, at its end, under `PopoverBody`: the way out first, then the confirm button. */
@@ -1,37 +1,46 @@
1
1
  import { tv } from "../../lib/tv.mjs";
2
2
  import { useThemeScopeProps } from "../../lib/theme/theme-scope.mjs";
3
3
  import { usePopupCollision } from "../../lib/frame-insets.mjs";
4
+ import { messageCard } from "../message-embed/message-embed.recipe.mjs";
5
+ import { createContext, useContext } from "react";
4
6
  import { jsx } from "react/jsx-runtime";
5
7
  import { Popover } from "@base-ui/react/popover";
6
8
  //#region src/components/popover/popover.tsx
7
- const popover = tv({ slots: {
8
- trigger: ["select-none"],
9
- positioner: ["isolate z-50 outline-none"],
10
- content: [
11
- "max-h-(--available-height) min-w-[220px] overflow-hidden",
12
- "outline-none",
13
- "rounded-container bg-layer-popover text-foreground",
14
- "shadow-float ring-1 ring-line-seam"
15
- ],
16
- header: ["flex items-center justify-between px-3", "min-h-11 gap-2 py-1.5 pr-1.5 pl-4"],
17
- body: ["flex min-w-0 flex-col gap-1.5", "px-4 pt-4 pb-3 last:pb-4"],
18
- actions: ["flex flex-wrap items-center justify-end gap-2", "px-4 pb-3 last:pb-4"],
19
- separator: ["border-t", "border-line-hairline"],
20
- title: ["m-0", "font-sans text-headline font-bold text-foreground"],
21
- description: ["m-0", "font-sans text-footnote text-foreground-muted"],
22
- close: [
23
- "inline-flex items-center justify-center",
24
- "outline-none transition-colors",
25
- "h-8 min-w-8 rounded-chip px-1.5",
26
- "font-sans text-footnote font-bold text-foreground",
27
- "hover:bg-fill-medium active:bg-fill-medium",
28
- "focus-visible:shadow-focus",
29
- "[&_svg]:size-4.5"
30
- ],
31
- arrow: ["size-2 rotate-45", "border-l border-t border-line-seam bg-layer-popover"],
32
- backdrop: ["fixed inset-0", "bg-transparent"],
33
- viewport: ["block"]
34
- } });
9
+ const popover = tv({
10
+ slots: {
11
+ trigger: ["select-none"],
12
+ positioner: ["isolate z-50 outline-none"],
13
+ content: [
14
+ "max-h-(--available-height) min-w-[220px] overflow-hidden",
15
+ "outline-none",
16
+ "rounded-container bg-layer-popover text-foreground",
17
+ "shadow-float ring-1 ring-line-seam"
18
+ ],
19
+ header: ["flex items-center justify-between px-3", "min-h-11 gap-2 py-1.5 pr-1.5 pl-4"],
20
+ body: ["flex min-w-0 flex-col gap-1.5", "px-4 pt-4 pb-3 last:pb-4"],
21
+ actions: ["flex flex-wrap items-center justify-end gap-2", "px-4 pb-3 last:pb-4"],
22
+ separator: ["border-t", "border-line-hairline"],
23
+ title: ["m-0", "font-sans text-headline font-bold text-foreground"],
24
+ description: ["m-0", "font-sans text-footnote text-foreground-muted"],
25
+ close: [
26
+ "inline-flex items-center justify-center",
27
+ "outline-none transition-colors",
28
+ "h-8 min-w-8 rounded-chip px-1.5",
29
+ "font-sans text-footnote font-bold text-foreground",
30
+ "hover:bg-fill-medium active:bg-fill-medium",
31
+ "focus-visible:shadow-focus",
32
+ "[&_svg]:size-4.5"
33
+ ],
34
+ arrow: ["size-2 rotate-45", "border-l border-t border-line-seam bg-layer-popover"],
35
+ backdrop: ["fixed inset-0", "bg-transparent"],
36
+ viewport: ["block"]
37
+ },
38
+ variants: { size: {
39
+ default: {},
40
+ item: { content: messageCard().popover() }
41
+ } }
42
+ });
43
+ const PopoverSizeContext = createContext("default");
35
44
  function Popover$1(props) {
36
45
  return /* @__PURE__ */ jsx(Popover.Root, {
37
46
  "data-slot": "popover",
@@ -67,8 +76,8 @@ function PopoverFramePositioner({ collisionBoundary, collisionPadding, container
67
76
  ...props
68
77
  });
69
78
  }
70
- function PopoverContent({ align = "start", alignOffset = 0, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking, positionMethod = "fixed", side = "bottom", sideOffset = 4, sticky, container, portalProps, className, ...props }) {
71
- const { positioner, content } = popover();
79
+ function PopoverContent({ align = "start", alignOffset = 0, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking, positionMethod = "fixed", side = "bottom", sideOffset = 4, sticky, container, portalProps, size = "default", className, ...props }) {
80
+ const { positioner, content } = popover({ size });
72
81
  const portalContainer = container !== void 0 ? container : portalProps?.container;
73
82
  return /* @__PURE__ */ jsx(PopoverPortal, {
74
83
  ...portalProps,
@@ -88,10 +97,14 @@ function PopoverContent({ align = "start", alignOffset = 0, anchor, arrowPadding
88
97
  sideOffset,
89
98
  sticky,
90
99
  className: positioner(),
91
- children: /* @__PURE__ */ jsx(Popover.Popup, {
92
- "data-slot": "popover-content",
93
- className: content({ className }),
94
- ...props
100
+ children: /* @__PURE__ */ jsx(PopoverSizeContext.Provider, {
101
+ value: size,
102
+ children: /* @__PURE__ */ jsx(Popover.Popup, {
103
+ "data-slot": "popover-content",
104
+ "data-size": size,
105
+ className: content({ className }),
106
+ ...props
107
+ })
95
108
  })
96
109
  })
97
110
  });
@@ -123,7 +136,7 @@ function PopoverSeparator({ className, ...props }) {
123
136
  });
124
137
  }
125
138
  function PopoverTitle({ className, ...props }) {
126
- const { title } = popover();
139
+ const title = useContext(PopoverSizeContext) === "item" ? messageCard().title : popover().title;
127
140
  return /* @__PURE__ */ jsx(Popover.Title, {
128
141
  "data-slot": "popover-title",
129
142
  className: title({ className }),
@@ -162,9 +175,9 @@ function PopoverBackdrop({ className, ...props }) {
162
175
  ...props
163
176
  });
164
177
  }
165
- /** The panel's text: a `PopoverTitle` and a `PopoverDescription`, 16px in from its edges. */
178
+ /** The panel's text: a `PopoverTitle` and a `PopoverDescription`, 16px in from its edges (12px in a `size="item"` popover). */
166
179
  function PopoverBody({ className, ...props }) {
167
- const { body } = popover();
180
+ const body = useContext(PopoverSizeContext) === "item" ? messageCard().body : popover().body;
168
181
  return /* @__PURE__ */ jsx("div", {
169
182
  "data-slot": "popover-body",
170
183
  className: body({ className }),
@@ -173,7 +186,7 @@ function PopoverBody({ className, ...props }) {
173
186
  }
174
187
  /** The panel's buttons, at its end, under `PopoverBody`: the way out first, then the confirm button. */
175
188
  function PopoverActions({ className, ...props }) {
176
- const { actions } = popover();
189
+ const actions = useContext(PopoverSizeContext) === "item" ? messageCard().actions : popover().actions;
177
190
  return /* @__PURE__ */ jsx("div", {
178
191
  "data-slot": "popover-actions",
179
192
  className: actions({ className }),