@sesamehr/react-design-system 3.4.0 → 3.5.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 (68) hide show
  1. package/dist/Button/index.d.ts +1 -1
  2. package/dist/Display/AiTag/AiTag.d.ts +33 -0
  3. package/dist/Display/AiTag/index.d.ts +21 -0
  4. package/dist/Display/Avatar/index.d.ts +2 -2
  5. package/dist/Display/Badge/index.d.ts +1 -1
  6. package/dist/Display/BrandLogo/BrandLogo.d.ts +53 -0
  7. package/dist/Display/BrandLogo/brandLogoArt.d.ts +29 -0
  8. package/dist/Display/BrandLogo/index.d.ts +17 -0
  9. package/dist/Display/FileCard/FileCard.d.ts +102 -41
  10. package/dist/Display/FileCard/index.d.ts +31 -0
  11. package/dist/Display/ImageAttachment/ImageAttachment.d.ts +58 -0
  12. package/dist/Display/ImageAttachment/index.d.ts +2 -0
  13. package/dist/Display/LinkPreview/LinkPreview.d.ts +65 -0
  14. package/dist/Display/LinkPreview/index.d.ts +1 -0
  15. package/dist/Display/LocationAttachment/LocationAttachment.d.ts +71 -0
  16. package/dist/Display/LocationAttachment/index.d.ts +1 -0
  17. package/dist/Display/VideoAttachment/VideoAttachment.d.ts +78 -0
  18. package/dist/Display/VideoAttachment/index.d.ts +1 -0
  19. package/dist/Display/VoiceMessage/VoiceMessage.d.ts +103 -0
  20. package/dist/Display/VoiceMessage/index.d.ts +2 -0
  21. package/dist/Display/VoiceMessage/toWaveformPeaks.d.ts +58 -0
  22. package/dist/Display/VoiceMessage/useVoiceWaveform.d.ts +90 -0
  23. package/dist/Feedback/Dialog/Dialog.d.ts +13 -1
  24. package/dist/Feedback/Dialog/DialogOverlay.d.ts +12 -1
  25. package/dist/Feedback/Drawer/Drawer.d.ts +68 -0
  26. package/dist/Feedback/Drawer/DrawerBody.d.ts +18 -0
  27. package/dist/Feedback/Drawer/DrawerContent.d.ts +36 -0
  28. package/dist/Feedback/Drawer/DrawerDescription.d.ts +10 -0
  29. package/dist/Feedback/Drawer/DrawerExpand.d.ts +23 -0
  30. package/dist/Feedback/Drawer/DrawerTitle.d.ts +13 -0
  31. package/dist/Feedback/Drawer/index.d.ts +7 -0
  32. package/dist/Feedback/Drawer/useDrawer.d.ts +30 -0
  33. package/dist/Feedback/Progress/index.d.ts +1 -1
  34. package/dist/Forms/Inputs/AiSearch/AiSearch.d.ts +67 -0
  35. package/dist/Forms/Inputs/AiSearch/AiSearchAsk.d.ts +34 -0
  36. package/dist/Forms/Inputs/AiSearch/AiSearchPanel.d.ts +50 -0
  37. package/dist/Forms/Inputs/AiSearch/AiSearchSend.d.ts +30 -0
  38. package/dist/Forms/Inputs/AiSearch/AiSearchShortcut.d.ts +23 -0
  39. package/dist/Forms/Inputs/AiSearch/AiSearchSuggestion.d.ts +27 -0
  40. package/dist/Forms/Inputs/AiSearch/index.d.ts +6 -0
  41. package/dist/Forms/Inputs/AiSearch/useAiSearch.d.ts +37 -0
  42. package/dist/Forms/Inputs/TimePicker/TimePicker.d.ts +64 -0
  43. package/dist/Forms/Inputs/TimePicker/TimePickerField.d.ts +35 -0
  44. package/dist/Forms/Inputs/TimePicker/TimePickerList.d.ts +23 -0
  45. package/dist/Forms/Inputs/TimePicker/TimePickerWheel.d.ts +26 -0
  46. package/dist/Forms/Inputs/TimePicker/TimePickerWheelColumn.d.ts +23 -0
  47. package/dist/Forms/Inputs/TimePicker/index.d.ts +6 -0
  48. package/dist/Forms/Inputs/TimePicker/time.d.ts +41 -0
  49. package/dist/Forms/Inputs/TimePicker/useTimeField.d.ts +62 -0
  50. package/dist/Forms/Inputs/TimePicker/useTimeList.d.ts +53 -0
  51. package/dist/Forms/Inputs/TimePicker/useTimePicker.d.ts +35 -0
  52. package/dist/Forms/Inputs/TimePicker/useWheelColumn.d.ts +71 -0
  53. package/dist/Forms/Inputs/index.d.ts +1 -0
  54. package/dist/Navigation/Tabs/Tabs.d.ts +18 -0
  55. package/dist/Navigation/Tabs/TabsContent.d.ts +7 -0
  56. package/dist/Navigation/Tabs/TabsList.d.ts +10 -0
  57. package/dist/Navigation/Tabs/TabsTrigger.d.ts +20 -0
  58. package/dist/Navigation/Tabs/index.d.ts +4 -0
  59. package/dist/internal/AttachmentMedia/AttachmentMedia.d.ts +38 -0
  60. package/dist/internal/AttachmentMedia/index.d.ts +36 -0
  61. package/dist/internal/index.d.ts +1 -0
  62. package/dist/main.d.ts +12 -2
  63. package/dist/react-design-system.css +1 -1
  64. package/dist/react-design-system.js +12581 -10218
  65. package/dist/react-design-system.umd.cjs +108 -74
  66. package/package.json +3 -2
  67. package/src/assets/styles/theme-v3.css +99 -2
  68. package/src/assets/styles/theme-v3.test.ts +5 -5
@@ -1,7 +1,7 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  export { Button, type ButtonProps } from './Button.tsx';
3
3
  export declare const buttonVariants: (props?: ({
4
- variant?: "link" | "default" | "destructive" | "success" | "outline" | "secondary" | "ghost" | null | undefined;
4
+ variant?: "link" | "default" | "destructive" | "success" | "outline" | "secondary" | "ghost" | "ai" | null | undefined;
5
5
  size?: "icon" | "2xs" | "xs" | "sm" | "md" | "lg" | null | undefined;
6
6
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
7
  export type ButtonVariants = VariantProps<typeof buttonVariants>;
@@ -0,0 +1,33 @@
1
+ import { AiTagVariants } from './index.ts';
2
+ /**
3
+ * `color` has to be omitted before it is redeclared: React's `HTMLAttributes`
4
+ * carries HTML's deprecated presentational `color` attribute as `string`, and
5
+ * the variant union will not widen to it.
6
+ */
7
+ export interface AiTagProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'> {
8
+ /**
9
+ * Whether this is the AI marker itself (`ai`, the two-hue gradient) or the
10
+ * quiet grey version for a surface that is already about AI.
11
+ */
12
+ color?: AiTagVariants['color'];
13
+ /** A line around nothing, or a filled surface. */
14
+ variant?: AiTagVariants['variant'];
15
+ /** 20px with 12px type, or 28px with 14px type. */
16
+ size?: AiTagVariants['size'];
17
+ dataTestid: string;
18
+ }
19
+ /**
20
+ * Says that what it sits next to came from Sesame AI.
21
+ *
22
+ * Built on `OxTag`'s shape rather than on a primitive, which is also what
23
+ * shadcn would have given: its `Badge` is a `<span>` with a variant map and no
24
+ * behaviour, because there is no behaviour here to get wrong. The AI marker is
25
+ * not interactive, takes no click and is not a tab stop — if pressing it should
26
+ * do something, that is an `OxChip`.
27
+ *
28
+ * The glyph goes in `children` carrying `data-slot="icon"`, the way `OxTag`
29
+ * takes one, and is not shipped inside with a prop to hide it. Figma spells the
30
+ * same axis as a `Show icon` boolean, and writing the icon or not writing it is
31
+ * the one spelling of that axis which needs no prop and cannot be got wrong.
32
+ */
33
+ export declare const AiTag: import('react').ForwardRefExoticComponent<AiTagProps & import('react').RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,21 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ export { AiTag, type AiTagProps } from './AiTag.tsx';
3
+ /**
4
+ * The marker that says a piece of content came from Sesame AI.
5
+ *
6
+ * Two axes, and they are not the same axis twice. `color` is *whether this is
7
+ * the AI marker at all*: `ai` paints the two-hue gradient nothing else in the
8
+ * system uses, `muted` is the same pill in grey for when the surrounding UI is
9
+ * already about AI and a second gradient would only shout. `variant` is how
10
+ * loudly either one is painted — a line around nothing, or a filled surface.
11
+ *
12
+ * The design calls the second axis `Style`; it is `variant` here because a prop
13
+ * named `style` would eat the caller's inline styles. `OxTag` renamed it for
14
+ * the same reason.
15
+ */
16
+ export declare const aiTagVariants: (props?: ({
17
+ color?: "ai" | "muted" | null | undefined;
18
+ variant?: "filled" | "outline" | null | undefined;
19
+ size?: "sm" | "md" | null | undefined;
20
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
21
+ export type AiTagVariants = VariantProps<typeof aiTagVariants>;
@@ -23,12 +23,12 @@ export { useAvatarBullet } from './hooks/useAvatarBullet.ts';
23
23
  */
24
24
  export declare const avatarSquareVariants: (props?: ({
25
25
  size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
26
- tone?: "neutral" | "brand" | null | undefined;
26
+ tone?: "brand" | "neutral" | null | undefined;
27
27
  disabled?: boolean | null | undefined;
28
28
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
29
29
  export declare const avatarRoundedVariants: (props?: ({
30
30
  size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
31
- tone?: "neutral" | "brand" | null | undefined;
31
+ tone?: "brand" | "neutral" | null | undefined;
32
32
  disabled?: boolean | null | undefined;
33
33
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
34
34
  export type AvatarSquareVariants = VariantProps<typeof avatarSquareVariants>;
@@ -12,6 +12,6 @@ export { Badge, type BadgeProps } from './Badge.tsx';
12
12
  */
13
13
  export declare const badgeVariants: (props?: ({
14
14
  size?: "sm" | "md" | "lg" | null | undefined;
15
- color?: "error" | "neutral" | "brand" | null | undefined;
15
+ color?: "brand" | "error" | "neutral" | null | undefined;
16
16
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
17
17
  export type BadgeVariants = VariantProps<typeof badgeVariants>;
@@ -0,0 +1,53 @@
1
+ import { BrandLogoVariants } from './index.ts';
2
+ /**
3
+ * `color` has to be omitted before it is redeclared: React's `SVGAttributes`
4
+ * carries SVG's presentational `color` attribute as `string`, and the variant
5
+ * union will not widen to it.
6
+ */
7
+ export interface BrandLogoProps extends Omit<React.SVGAttributes<SVGSVGElement>, 'color' | 'type'> {
8
+ /**
9
+ * The symbol with the wordmark beside it, or the symbol on its own — which
10
+ * is what a collapsed sidebar and a favicon-sized slot want.
11
+ */
12
+ type?: BrandLogoVariants['type'];
13
+ /**
14
+ * The ink: `dark` for a light background, `light` for a dark one. Not a
15
+ * dark-mode switch — see the note below.
16
+ */
17
+ color?: BrandLogoVariants['color'];
18
+ /** 32px tall, or 88px. The width follows the art. */
19
+ size?: BrandLogoVariants['size'];
20
+ dataTestid: string;
21
+ }
22
+ /**
23
+ * The Sesame logo.
24
+ *
25
+ * **It uses primitive colours on purpose, and this is the note that stops
26
+ * someone "fixing" it.** `dark` is `brand-500` and `light` is `white`, read
27
+ * straight off the primitive ramp rather than through `--brand` or
28
+ * `--foreground`. A semantic token is a promise that the value may be
29
+ * re-pointed — by a theme, by dark mode, by a consumer overriding
30
+ * `--ox-color-brand-500`'s semantic layer — and a logo is the one thing in the
31
+ * system that must not move when any of that happens. It is the brand, not a
32
+ * surface painted in brand colours. `@sesame/orxata-icons` is the only other
33
+ * sanctioned exception, for the same reason.
34
+ *
35
+ * So: the two colours here are *not* a dark-mode pair. `color` says what the
36
+ * logo is sitting on, not what the theme is — `light` is the white logo for a
37
+ * navy header, and it stays white in light mode.
38
+ *
39
+ * No primitive underneath, and nothing to borrow: shadcn has no logo and
40
+ * neither does Radix. There is no state, no keyboard and no coordination, so
41
+ * there is nothing for a headless primitive to hold — it is one `<svg>`.
42
+ *
43
+ * `role="img"` with no name by default, which is deliberate. A logo in a
44
+ * sidebar header beside the word "Sesame" is decoration and naming it twice is
45
+ * noise; a logo that *is* the link home needs the name on the link, not on the
46
+ * art. Where it is genuinely the only thing identifying the page, `children`
47
+ * becomes an SVG `<title>`:
48
+ *
49
+ * ```tsx
50
+ * <OxBrandLogo dataTestid="logo">{t('brand.name')}</OxBrandLogo>
51
+ * ```
52
+ */
53
+ export declare const BrandLogo: import('react').ForwardRefExoticComponent<BrandLogoProps & import('react').RefAttributes<SVGSVGElement>>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The Sesame logo, as the v3 board draws it.
3
+ *
4
+ * Path data rather than an asset file, and it lives beside the component rather
5
+ * than in `@sesame/orxata-icons`, for two reasons. The icons package renders an
6
+ * asset as `innerHTML` of an `<i>` and its one Sesame brand file is still the
7
+ * v2 mark — green accent, navy hexagon — so using it would ship the old logo;
8
+ * and adding v3 art there would tie this component to an icons release. Here it
9
+ * is versioned with the component that draws it.
10
+ *
11
+ * Every path is `fill="currentColor"` at render time. The board paints all of
12
+ * them with one colour per variant, so one `color` is all the markup needs —
13
+ * see the component for why that is worth saying out loud.
14
+ *
15
+ * Composed from the vector groups Figma exports, each placed with the offset
16
+ * the group has inside its variant frame. Regenerated rather than edited: the
17
+ * numbers are measurements, and a hand-nudged logo is a wrong logo.
18
+ */
19
+ export interface BrandLogoArt {
20
+ viewBox: string;
21
+ groups: {
22
+ transform: string;
23
+ paths: string[];
24
+ }[];
25
+ }
26
+ /** Symbol plus the "sesame" wordmark: 113.6 x 32, which is 3.55:1. */
27
+ export declare const BRAND_LOGO_FULL: BrandLogoArt;
28
+ /** The symbol on its own, square. */
29
+ export declare const BRAND_LOGO_MARK: BrandLogoArt;
@@ -0,0 +1,17 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ export { BrandLogo, type BrandLogoProps } from './BrandLogo.tsx';
3
+ export { type BrandLogoArt } from './brandLogoArt.ts';
4
+ /**
5
+ * The Sesame logo.
6
+ *
7
+ * `type` picks the art and `color` picks the ink. There is no `variant` axis,
8
+ * which is where this differs from every other component in the package — see
9
+ * the note in `BrandLogo.tsx` about the board's `Style` axis, which draws the
10
+ * same two colours either way.
11
+ */
12
+ export declare const brandLogoVariants: (props?: ({
13
+ type?: "mark" | "full" | null | undefined;
14
+ color?: "dark" | "light" | null | undefined;
15
+ size?: "md" | "lg" | null | undefined;
16
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
17
+ export type BrandLogoVariants = VariantProps<typeof brandLogoVariants>;
@@ -1,30 +1,72 @@
1
+ import { FileCardVariants } from './index.ts';
1
2
  /**
2
- * One attached file as a row. Mirrors `@sesame/orxata-core` FileCard.
3
+ * One attached file as a row: a type badge, the file's name, a second line of
4
+ * detail, somewhere for the caller to put what you can do to it, and an
5
+ * optional bar across the bottom while it moves.
3
6
  *
4
- * Built on `Card` rather than redrawing the shell. The radius, the border and
5
- * the white surface are already a component, and the only reason this file has
6
- * a stylesheet at all is the row inside it. `flat` is the card the design
7
- * draws: border, no lift — `Card`'s `flat` keeps the outline and drops only the
8
- * shadow and the glass.
7
+ * Mirrors `@sesame/orxata-core` FileCard.
9
8
  *
10
- * ### Why `name` and `meta` are props and the other two are nodes
9
+ * ### Figma draws this on two pages and they are one component
11
10
  *
12
- * Sameness is the product for the text, exactly as in `AvatarDetails`: every
13
- * file row we ship is two lines at the same sizes and weights, and a node is
14
- * where that guarantee goes to die — the first caller to put a link, a badge or
15
- * a third line in it ends the point of having the component. `meta` is
16
- * deliberately not called `size`: what the second line says is the
17
- * application's business ("1,56 MB", "PDF · yesterday", "Uploaded by Ana"), and
18
- * naming it after one of those would be a lie the day someone passes another.
11
+ * `File card` is the file you already have — display and download. `File item`
12
+ * is the row inside `File upload` while it arrives, with `State = Loading |
13
+ * Uploaded | Hover | Error`. They are the same row: the same `_File / Type`
14
+ * badge, the same name over the same meta line, the same box. What differs is
15
+ * which control sits on the right — a download in one, a retry or a remove in
16
+ * the other — and that is already a slot.
19
17
  *
20
- * The glyph and the action are the opposite case. Mapping an extension to an
21
- * icon is application knowledge — there are hundreds of extensions and we know
22
- * none of them — so `icon` takes a node and falls back to a generic file glyph,
23
- * which is the one honest thing a design system can draw. And `action` takes a
24
- * node because *which* action is not ours either: download, delete, share,
25
- * retry, or nothing at all. It also settles the accessible name, which we
26
- * cannot supply since the design system ships no strings — whatever the caller
27
- * puts there brings its own, and `IconButton` refuses to render without one.
18
+ * So there is no `OxFileItem` and there is not going to be one. The test for
19
+ * splitting a component here is logic, state or context interaction, and the
20
+ * upload side has none of the three: the progress is a number that becomes a
21
+ * width, the error is a class, and everything else that changes is slot
22
+ * content. A second component would wrap this one, add classes and forward a
23
+ * slot, which is the shape the architecture rules name as premature
24
+ * abstraction.
25
+ *
26
+ * ### The text is slots, which is a reversal
27
+ *
28
+ * The name and the second line used to be **strings** here, argued for on the
29
+ * grounds that sameness is the product and a node is where that guarantee
30
+ * dies. It was the wrong trade. Content in props is the pattern
31
+ * composition-over-configuration exists to stop, and the guarantee it was
32
+ * buying is held by the stylesheet anyway — the two lines are sized and
33
+ * coloured here whatever goes in them. Keeping them as strings also spent two
34
+ * of five on content at the exact moment the board needed three for `type`,
35
+ * `surface` and `state`.
36
+ *
37
+ * `children` is the name; `meta` is the second line, and it is called that
38
+ * rather than `size` because what belongs there is the application's business —
39
+ * `PDF · 230 KB` on the board, but `Uploading… 60 %` on the upload one and
40
+ * `Uploaded by Ana` in a list.
41
+ *
42
+ * ### `type` is the colour; the badge's content is still yours
43
+ *
44
+ * Mapping a file to a glyph is application knowledge — there are hundreds of
45
+ * extensions and the set is open — which is why the badge has a slot. The
46
+ * board closes the *colour* at five named types and binds a token to each,
47
+ * which is a design decision and therefore ours. Which of the five `.odt`,
48
+ * `.numbers` or `.pages` belongs to is not.
49
+ *
50
+ * So the two split cleanly: `type` picks the ramp, `icon` carries what is
51
+ * printed on it. The board prints a three-letter abbreviation — `PDF`, `DOC`,
52
+ * `XLS`, `PPT` — and those come from the caller, because this package ships no
53
+ * strings and because the generic badge has no abbreviation to ship (Figma
54
+ * draws `ZIP` there, which is an example of a generic file and not the name of
55
+ * one). Pass nothing and the badge keeps the ramp and falls back to a plain
56
+ * file glyph, which is the one honest default. A sixth file type nobody has
57
+ * asked us for is `--ox-file-card-glyph-background` on the root.
58
+ *
59
+ * ### The bar is drawn here rather than being an `OxProgress`
60
+ *
61
+ * `OxProgress` is an 8px pill with a rounded fill on a `secondary` track. This
62
+ * is a 3px hairline flush against the bottom edge, square, and on `brand` it
63
+ * swaps both of its colours for `chat-user-media` and `brand-foreground`.
64
+ * Reaching for the component would mean overriding every declaration it has
65
+ * from outside, where the two module classes weigh the same — so which
66
+ * stylesheet the bundler emitted first would decide what the bar looked like.
67
+ * Two elements and `role="progressbar"` cost less and cannot lose that race.
68
+ * The bar names itself after the file, via the id on the name, so a screen
69
+ * reader says the file and not just a percentage.
28
70
  *
29
71
  * ### What it deliberately does not do
30
72
  *
@@ -32,33 +74,52 @@
32
74
  * `width`, and that figure belongs to the screen it was drawn on, not to the
33
75
  * component: a card that hardcodes its own width cannot sit in a grid, a
34
76
  * sidebar or a flexible column, and the parent owns external layout. It fills
35
- * what it is given. The 72px height stays, because that one is internal — a
36
- * list of these has to have rows of equal height, and long names truncate
37
- * rather than growing the row.
77
+ * what it is given. The height stays, because that one is internal — a list of
78
+ * these has to have rows of equal height, and long names truncate rather than
79
+ * grow the row.
38
80
  *
39
- * **The root is not a button.** It already contains an interactive control, and
40
- * a button inside a button is invalid HTML; making the root activate would also
41
- * mean inventing a focus and keyboard contract the design has nothing to say
42
- * about. A caller who wants the whole row to do something wraps it, or puts a
43
- * link in `action`.
81
+ * **The root is not a button.** It already contains an interactive control,
82
+ * and a button inside a button is invalid HTML; making the root activate would
83
+ * also mean inventing a focus and keyboard contract the design has nothing to
84
+ * say about. A caller who wants the whole row to do something wraps it, or
85
+ * puts a link in `action`. The hover tint the upload board draws is on the row
86
+ * all the same, because the row is what the pointer is over whichever of those
87
+ * two the caller chose.
44
88
  */
45
- export interface FileCardProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title'> {
46
- /** The file's name. Truncates rather than wrapping — the row is a fixed height. */
47
- name: string;
89
+ export interface FileCardProps extends React.ComponentPropsWithoutRef<'div'> {
90
+ /**
91
+ * Which of the five colour ramps the badge wears. Not which extension the
92
+ * file has — that mapping is yours, and the badge's content is a slot.
93
+ */
94
+ type?: FileCardVariants['type'];
95
+ /**
96
+ * Which side of a chat bubble this sits in: `brand` inside the reader's own
97
+ * message, `default` anywhere else. The same axis the attachments carry.
98
+ */
99
+ surface?: FileCardVariants['surface'];
100
+ /**
101
+ * `error` repaints the border and the meta line. Loading and uploaded are
102
+ * not states here — they are what you put in `meta` and `action`.
103
+ */
104
+ state?: FileCardVariants['state'];
105
+ /**
106
+ * How far along, 0 to 100. Present at all means the bar is drawn; omit it
107
+ * and there is no bar and no `progressbar` role.
108
+ */
109
+ progress?: number;
48
110
  /**
49
- * The second line: whatever the app knows about the file. Size in the
50
- * design, but a type, a date or an author read just as well. Omit it and the
51
- * row is one line.
111
+ * The second line: a type and a size, a progress reading, or the reason an
112
+ * upload failed. Omit it and the row is one line.
52
113
  */
53
- meta?: string;
114
+ meta?: React.ReactNode;
54
115
  /**
55
- * The glyph in the ring. Defaults to a generic file — mapping an extension to
56
- * an icon is the application's knowledge, not ours.
116
+ * What is printed on the badge — the board uses a three-letter
117
+ * abbreviation. Left empty it falls back to a generic file glyph.
57
118
  */
58
119
  icon?: React.ReactNode;
59
120
  /**
60
- * The one thing you can do to this file. Nothing by default; whatever you put
61
- * here brings its own accessible name.
121
+ * What you can do to this file. Whatever you put here brings its own
122
+ * accessible name.
62
123
  */
63
124
  action?: React.ReactNode;
64
125
  dataTestid: string;
@@ -1 +1,32 @@
1
+ import { VariantProps } from 'class-variance-authority';
1
2
  export { FileCard, type FileCardProps } from './FileCard.tsx';
3
+ /**
4
+ * Three axes, and each of them is a thing the component draws rather than a
5
+ * thing the caller writes.
6
+ *
7
+ * `type` is the colour of the badge, not the text in it. The v3 board closes
8
+ * the set at five — PDF, Word, Excel, PowerPoint and a generic — and pins a
9
+ * colour to each (`file-pdf`, `file-word`, `file-excel`, `file-powerpoint`,
10
+ * `file-generic`). Which of the five a `.numbers` or an `.odt` belongs to is
11
+ * still the application's call; see the note in `FileCard.tsx`.
12
+ *
13
+ * `surface` is Figma's axis of the same name, with the same two values every
14
+ * chat attachment carries. The Vue original types it as the attachments'
15
+ * shared `AttachmentSurface`; this package has no `internal/AttachmentMedia`
16
+ * yet, so the prop reads the union off this cva instead — the same two values,
17
+ * to be re-pointed when the attachments port lands.
18
+ *
19
+ * `state` is two values where Figma's `File item` board draws four, and the
20
+ * other two are not missing — they are somewhere else. `Loading` and
21
+ * `Uploaded` differ only in what sits in the `action` slot and what the `meta`
22
+ * slot says, both of which are the caller's content; `Hover` is a tint, which
23
+ * is `:hover`. `Error` is the one state that is neither: it repaints the
24
+ * card's own border and its own meta line, and nothing a caller passes in
25
+ * could reach either.
26
+ */
27
+ export declare const fileCardVariants: (props?: ({
28
+ type?: "pdf" | "word" | "excel" | "powerpoint" | "file" | null | undefined;
29
+ surface?: "default" | "brand" | null | undefined;
30
+ state?: "default" | "error" | null | undefined;
31
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
32
+ export type FileCardVariants = VariantProps<typeof fileCardVariants>;
@@ -0,0 +1,58 @@
1
+ import { AttachmentImage, AttachmentSurface } from '../../internal/AttachmentMedia/index.ts';
2
+ /**
3
+ * The pictures attached to a chat message: one across the bubble, or a 2×2
4
+ * grid with a count on the last cell.
5
+ * Mirrors `@sesame/orxata-core` ImageAttachment.
6
+ *
7
+ * No primitive underneath. shadcn has nothing in this shape and neither does
8
+ * Radix — a grid of image buttons has no roving focus, no selection and no
9
+ * open state to coordinate, so there is nothing for a headless primitive to
10
+ * hold. Each cell is a plain `<button>` in document order, which is what Radix
11
+ * would have rendered anyway.
12
+ *
13
+ * ### `Type` is not a prop, because the content already decides it
14
+ *
15
+ * Figma's axis holds `Image` and `Gallery`, and its own usage board says when
16
+ * each applies: one picture is `Image`, two or more is `Gallery`, and from the
17
+ * fifth the last cell carries `+N`. All three are counts, so `images.length`
18
+ * answers them and a prop would only let a caller contradict it. `More count`
19
+ * goes the same way: it is `images.length - 4`, so pass every picture you have
20
+ * and at most four are ever rendered.
21
+ *
22
+ * ### Each cell is a button
23
+ *
24
+ * The behaviour board puts the viewer behind a click and asks for keyboard
25
+ * access, and unlike `FileCard` — whose root refuses to be a control because it
26
+ * *contains* one — there is nothing interactive in here to nest. A gallery's
27
+ * cells could not be wrapped from outside either: the component renders them.
28
+ * So `onOpen` carries the index, and `images[index]` is the picture to show.
29
+ *
30
+ * ### The `+N` cell is still its own picture
31
+ *
32
+ * It is the fourth image under a scrim, not a separate control, so its
33
+ * accessible name is that image's `alt` and the count is `aria-hidden`
34
+ * decoration on top. The accessibility board asks instead for an aria-label
35
+ * reading "see N more images" — which this package cannot supply, because it
36
+ * ships no strings of its own and has no catalogue to add one to. Opening the
37
+ * viewer at the fourth picture reaches the rest from there.
38
+ */
39
+ export interface ImageAttachmentProps extends React.ComponentPropsWithoutRef<'div'> {
40
+ /**
41
+ * Every picture attached, in order. One renders across the bubble; two or
42
+ * more render as a grid of up to four, and the rest become the `+N`.
43
+ */
44
+ images: AttachmentImage[];
45
+ /**
46
+ * Which side of the bubble this sits in: `brand` inside the reader's own
47
+ * message, `default` inside anyone else's.
48
+ */
49
+ surface?: AttachmentSurface;
50
+ /**
51
+ * A picture was activated. The index is into `images`, so the last cell of a
52
+ * clipped gallery still reports `3` and the viewer reaches the rest from
53
+ * there. Ports the Vue `@open` emit.
54
+ */
55
+ onOpen?: (index: number) => void;
56
+ dataTestid: string;
57
+ }
58
+ export declare const ImageAttachment: import('react').ForwardRefExoticComponent<ImageAttachmentProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,2 @@
1
+ export { ImageAttachment, type ImageAttachmentProps, } from './ImageAttachment.tsx';
2
+ export type { AttachmentImage, AttachmentSurface, } from '../../internal/AttachmentMedia/index.ts';
@@ -0,0 +1,65 @@
1
+ import { ReactNode } from 'react';
2
+ import { AttachmentImage, AttachmentSurface } from '../../internal/AttachmentMedia/index.ts';
3
+ /**
4
+ * A URL shared in a chat, unfurled: the page's image, its domain, its title and
5
+ * an extract.
6
+ * Mirrors `@sesame/orxata-core` LinkPreview.
7
+ *
8
+ * No primitive underneath. shadcn has no link card and Radix has none either —
9
+ * the whole thing is one `<a>`, which is what Radix's `Primitive` would have
10
+ * rendered, and there is no state, no keyboard contract and no composition for
11
+ * a headless primitive to hold. The image, its tint and the `Surface` axis come
12
+ * from `AttachmentMedia`, shared with the other four attachments.
13
+ *
14
+ * ### The card is one link, named by its title
15
+ *
16
+ * The accessibility board asks for exactly that, and the domain and the extract
17
+ * are inside the `<a>` too — so `aria-labelledby` points the link's name at the
18
+ * title and leaves the other two as text a reader still reaches. Without it the
19
+ * name would be all three lines read out as one sentence.
20
+ *
21
+ * `children` is therefore the title, and it is the one piece of content this
22
+ * component cannot do without: an empty one leaves the link with no accessible
23
+ * name at all.
24
+ *
25
+ * The board also asks the card to announce that it opens in a new tab. The
26
+ * `target` and the `rel` are here; the wording is not, because this package
27
+ * ships no strings and has no catalogue to add one to.
28
+ *
29
+ * ### Three nodes and not three strings
30
+ *
31
+ * `title` and `description` are names the composition rule does not allow as
32
+ * props, and a domain beside them as a plain string prop would be the same
33
+ * component taking its text two different ways. So all three are `ReactNode` —
34
+ * which is also what lets a caller put a `<time>`, a mark or an abbreviation in
35
+ * one, and what makes the sibling attachments consistent:
36
+ * `OxVideoAttachment`'s duration is a node for the same reason.
37
+ *
38
+ * ### Without an image the header is simply gone
39
+ *
40
+ * The usage board's rule, and it needs no flag: `image` is optional and the
41
+ * media is conditional on it, which leaves the text block alone in the card
42
+ * rather than an empty grey band above it. That is the one place this differs
43
+ * from `OxVideoAttachment`, where the tint *is* the placeholder.
44
+ */
45
+ export interface LinkPreviewProps extends React.ComponentPropsWithoutRef<'a'> {
46
+ /** Where the link goes. Opened in a new tab, as the behaviour board asks. */
47
+ href: string;
48
+ /**
49
+ * The page's image. Omitted — or absent from the page — leaves the card as
50
+ * its text block, which is the usage board's "no image" pattern. The boards
51
+ * call it decoration, so pass `alt: ''` unless it carries meaning of its own.
52
+ */
53
+ image?: AttachmentImage;
54
+ /**
55
+ * Which side of the bubble this sits in: `brand` inside the reader's own
56
+ * message, `default` inside anyone else's.
57
+ */
58
+ surface?: AttachmentSurface;
59
+ /** The domain of the shared URL, beside a globe glyph. Ports `#domain`. */
60
+ domain?: ReactNode;
61
+ /** An extract from the page. Two lines, then an ellipsis. Ports `#description`. */
62
+ description?: ReactNode;
63
+ dataTestid: string;
64
+ }
65
+ export declare const LinkPreview: import('react').ForwardRefExoticComponent<LinkPreviewProps & import('react').RefAttributes<HTMLAnchorElement>>;
@@ -0,0 +1 @@
1
+ export { LinkPreview, type LinkPreviewProps } from './LinkPreview.tsx';
@@ -0,0 +1,71 @@
1
+ import { ReactNode } from 'react';
2
+ import { AttachmentImage, AttachmentSurface } from '../../internal/AttachmentMedia/index.ts';
3
+ /**
4
+ * A place shared in a chat: a map band, the place's name and its address.
5
+ * Mirrors `@sesame/orxata-core` LocationAttachment.
6
+ *
7
+ * No primitive underneath, and here there was never a candidate — shadcn has
8
+ * no map card, Radix has no map anything, and the whole component is one `<a>`
9
+ * with no state, no keyboard contract beyond a link's own and nothing to
10
+ * coordinate. `AttachmentMedia` supplies the band, its tint and the `Surface`
11
+ * axis, shared with the other four attachments.
12
+ *
13
+ * ### The map is a prop, and the pin is what shows without one
14
+ *
15
+ * A prop rather than a node, on two counts. `OxImageAttachment`,
16
+ * `OxVideoAttachment` and `OxLinkPreview` all take their picture as an
17
+ * `image?: AttachmentImage`, and a node here would make one of the four odd for
18
+ * no gain a caller could use. And what the board draws in the band is a static
19
+ * map render — a URL, the same kind of thing as the `href` beside it, not
20
+ * arbitrary markup.
21
+ *
22
+ * The image **replaces** the pin rather than sitting under it, because the
23
+ * board's anatomy calls part one "map (placeholder)" with the pin inside it:
24
+ * the pin is what stands in for a map that is not there. So it is
25
+ * `AttachmentMedia`'s `placeholder`, which is also what makes it the
26
+ * failed-to-load state for free.
27
+ *
28
+ * Without an image the band is decoration: `AttachmentMedia` marks a
29
+ * placeholder it cannot name `aria-hidden`, which is the accessibility board's
30
+ * "the map is decorative". With one, the `alt` decides — and `''` is the right
31
+ * answer for a map of an address the line below already spells out.
32
+ *
33
+ * ### One link, named by what is in it
34
+ *
35
+ * Activating it opens the device's map application, which is an `href` — a
36
+ * `geo:` URI or a maps URL, the application's choice. The place and the address
37
+ * both sit inside the `<a>`, so the link's accessible name is the two of them,
38
+ * which is what the accessibility board asks for bar its "Location:" prefix.
39
+ * That prefix is a string, and this package ships none.
40
+ *
41
+ * Unlike `OxLinkPreview` there is no `aria-labelledby` here: that one has three
42
+ * lines and a board saying the name is the title alone, while this one has two
43
+ * and a board saying the name is both.
44
+ *
45
+ * ### Place and address are nodes
46
+ *
47
+ * The same reason as the siblings: `OxLinkPreview` carries a title and a
48
+ * description, names the composition rule does not allow as props, so the
49
+ * family takes its text as nodes rather than two different ways.
50
+ */
51
+ export interface LocationAttachmentProps extends React.ComponentPropsWithoutRef<'a'> {
52
+ /**
53
+ * Where the card goes — a `geo:` URI or a maps URL. Which one, and whether it
54
+ * carries coordinates or a query, is the application's knowledge.
55
+ */
56
+ href: string;
57
+ /**
58
+ * The static map of the place. It replaces the pin, which is the placeholder
59
+ * it stands in for; omitted — or failed to load — leaves the pin on the tint.
60
+ */
61
+ image?: AttachmentImage;
62
+ /**
63
+ * Which side of the bubble this sits in: `brand` inside the reader's own
64
+ * message, `default` inside anyone else's.
65
+ */
66
+ surface?: AttachmentSurface;
67
+ /** The full address. One line, then an ellipsis. Ports the `#address` slot. */
68
+ address?: ReactNode;
69
+ dataTestid: string;
70
+ }
71
+ export declare const LocationAttachment: import('react').ForwardRefExoticComponent<LocationAttachmentProps & import('react').RefAttributes<HTMLAnchorElement>>;
@@ -0,0 +1 @@
1
+ export { LocationAttachment, type LocationAttachmentProps, } from './LocationAttachment.tsx';