@stackone/malachite 2.62.1 → 2.64.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 (42) hide show
  1. package/COMPONENTS.md +3 -0
  2. package/dist/assets/icons/caret_double_left.svg.js +6 -0
  3. package/dist/assets/icons/caret_double_left.svg.js.map +1 -0
  4. package/dist/assets/icons/caret_double_right.svg.js +6 -0
  5. package/dist/assets/icons/caret_double_right.svg.js.map +1 -0
  6. package/dist/components/Chat/ChatThread.js +1 -2
  7. package/dist/components/Chat/ChatThread.js.map +1 -1
  8. package/dist/components/CloseButton.js +76 -0
  9. package/dist/components/CloseButton.js.map +1 -0
  10. package/dist/components/CustomIcons/CaretDoubleLeftIcon.js +21 -0
  11. package/dist/components/CustomIcons/CaretDoubleLeftIcon.js.map +1 -0
  12. package/dist/components/CustomIcons/CaretDoubleRightIcon.js +21 -0
  13. package/dist/components/CustomIcons/CaretDoubleRightIcon.js.map +1 -0
  14. package/dist/components/CustomIcons/index.js +306 -300
  15. package/dist/components/CustomIcons/index.js.map +1 -1
  16. package/dist/components/DatePicker.js +36 -0
  17. package/dist/components/DatePicker.js.map +1 -0
  18. package/dist/components/DatePickerField.js +246 -0
  19. package/dist/components/DatePickerField.js.map +1 -0
  20. package/dist/components/DatePickerPanel.js +399 -0
  21. package/dist/components/DatePickerPanel.js.map +1 -0
  22. package/dist/components/DatePickerTrigger.js +68 -0
  23. package/dist/components/DatePickerTrigger.js.map +1 -0
  24. package/dist/components/DateRangePicker.js +43 -0
  25. package/dist/components/DateRangePicker.js.map +1 -0
  26. package/dist/components/SplitScreenLayout.js +21 -38
  27. package/dist/components/SplitScreenLayout.js.map +1 -1
  28. package/dist/components/dateMath.js +153 -0
  29. package/dist/components/dateMath.js.map +1 -0
  30. package/dist/components/datePickerStyles.js +46 -0
  31. package/dist/components/datePickerStyles.js.map +1 -0
  32. package/dist/components/focusRing.js +4 -3
  33. package/dist/components/focusRing.js.map +1 -1
  34. package/dist/components/useDatePickerDraft.js +126 -0
  35. package/dist/components/useDatePickerDraft.js.map +1 -0
  36. package/dist/index.d.ts +262 -101
  37. package/dist/index.js +433 -423
  38. package/dist/index.js.map +1 -1
  39. package/dist/tailwind.css.js +1 -1
  40. package/dist/theme.js +406 -359
  41. package/dist/theme.js.map +1 -1
  42. package/package.json +1 -1
package/COMPONENTS.md CHANGED
@@ -88,6 +88,8 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
88
88
  - **`SegmentedControl`** — A rounded track of mutually-exclusive options — the segmented “one of these” control. Owns the track background, the selected-thumb chrome and the `radiogroup` semantics, so consumers never hand-roll a track around `PillButton` (whose `default` variant tokens are tuned for standalone filter pills, not a sunken track). Single tab stop with arrow-key move-and-select; selection is conveyed via `aria-checked` and a foreground change, not background colour alone. An option `icon` sits before the label in a fixed 16px slot, and an option `badge` follows the label at whatever width it needs, for a mark such as a compact `Tag` naming a saving; it renders inside the segment button, so it must not be interactive. Restyle via the `segmentedControl` theme tokens. _Key props:_ `options` (`value`, `label`, `icon`, `badge`, `disabled`), `value`, `onChange`, `SegmentedControlSize` (`small` | `medium` | `large`), `fullWidth`, `disabled`, `aria-label`, `aria-labelledby`, `className`.
89
89
  - **`Toggle`** — On/off switch. Add `label` for a visible caption, and `variant` to give it standalone toolbar-filter chrome — pick the family it sits beside: `pill` matches the filter-bar inputs (`Search`, `MultiSelect`), `button` renders the whole control as an outline `Button` with the switch as its trailing icon. `bordered` is shorthand for `variant="pill"`. `tone="pending"` paints the checked track amber, for a switch whose change has not been written yet — pair it with a `SelectionBar` reporting the same diff. The unchecked track never changes: nothing is pending about a switch that is off. Forwards a ref to its root element, so it can anchor an `InlineConfirm`. _Key props:_ `checked`, `onChange`, `disabled`, `ToggleSize` (`small` | `medium`), `ToggleTone` (`default` | `pending`), `label`, `ToggleVariant` (`pill` | `button`), `bordered`, `aria-label`, `aria-labelledby`, `aria-describedby`, `id`.
90
90
  - **`Dropdown`** — Single-select dropdown. `DropdownSize` is `small` (28px) | `medium` (32px) | `large` (42px), matching Button; `fullWidth` fills the container instead of sizing to content, which is what a table cell or a toolbar slot needs — without it the field column sizes to its content, so a consumer has to compute a width; `width` fixes that width outright, the way `MultiSelect` does, for a toolbar lining the two up rather than letting each hug its own label — a narrower container still wins, since the width clamps to it; Until this release a `search` trigger could not go below the intrinsic width of its bare `input`, so a `width` under roughly 200px was ignored; it now shrinks with the rest. The open menu fills the trigger and left-aligns under it, as Figma draws every tier of `Dropdown Component - Standard`, so `width` sizes both — the menu is the width of the control that opened it and does not widen for a long option, which ellipsises instead, so a row of controls and their open menus stay on one set of edges; below 160px the menu keeps that floor rather than shrinking to a chip nobody can read, and `minWidth` raises that floor without widening the trigger — for a picker a column pins narrow whose options carry a subtitle the trigger never shows; `menuAlign="end"` lines a menu wider than its trigger up with the trigger's right edge instead, so a control at the right of a card opens its menu inwards rather than past the card; near a viewport edge it anchors to the trigger's other side before falling back to the viewport, so the two share an edge wherever one fits; `small` is the chip that sits beside a page title and rounds tighter (10px) than the taller sizes. These names each moved up a tier in 0.71 — the old `xsmall`/`small`/`medium` are now `small`/`medium`/`large`. Pass `value` for a controlled selection whose source of truth lives elsewhere (URL or app state): the trigger follows it without the consumer remounting via `key`, which used to discard focus mid-interaction. `defaultValue` keeps the uncontrolled behaviour. `clearable` adds a clear control to the trigger once something is selected and reports it as `onItemSelected(undefined)` — without it a selection cannot be undone, so filter bars had to invent a sentinel "any" item to carry that meaning. `requiredIndicator` switches the label between the library default of naming the optional fields, an `asterisk` on the required ones for designs drawn that way, and `none` for a field whose value is supplied rather than asked for — a locked control is still required, but a marker only sends the reader looking for something to fill in. Visual only: `aria-required` is set from `required` whichever is chosen. `showSubtitleInTrigger` promotes the selected item's `subtitle` into the closed trigger, on one line under the value, so the consequence of a choice stays on screen once the menu shuts — the trigger trades its fixed height for a floor and grows by that line, and either line too long for it ellipsises, with a single tooltip carrying whichever lines are cut off, value first. It does not combine with `search`, whose trigger is a single-line text input with nowhere to put a second line, so the type rejects the pair rather than letting a consumer ask for a subtitle and get none. `subtitleLayout` decides how a subtitle sits in the open menu: the default `inline` keeps it on the label's row after a divider, which suits a short qualifier, while `stacked` gives it its own line beneath the label — one line either way, ellipsised rather than wrapped, so inline a sentence-length subtitle is cut back to a few words. Every option row carries a tooltip for whatever it had to cut, across all three of label, subtitle and `rightSideText`, so nothing the row hides is unreadable. Passing `formControl` is enough to show validation on the same terms as `Input`, though only validation: the trigger still paints `value` or `defaultValue`, never the value the form holds. The resolver's message renders on its own line beneath the field in the destructive colour, politely announced, with `aria-invalid` and `aria-describedby` wired, while an explicit `helperText` keeps its own line above it and stays dimmed, and `error={false}` suppresses the resolver outright. An item's `subtitle` renders inline markdown in the option, trigger and tooltip, with links drawn but inert, since the option is itself the click target; a subtitle with no markdown syntax stays a plain text node. An item's `badge` (e.g. a `Tag`) sits at the right end of its option in the open menu, after any `rightSideText`, and never shows in the closed trigger or the search input; it does not shrink, and the option is still named by its label alone. _Key props:_ `DropdownItem[]` (items take `badge`), `DropdownSize`, `fullWidth`, `width`, `minWidth`, `menuAlign` (`start` | `end`), `value`, `defaultValue`, `label`, `search`, `showSubtitleInTrigger`, `subtitleLayout`, `clearable`, `required`, `requiredIndicator`, `error`, `helperText`, `loading`, `formControl`, `aria-label`, `aria-labelledby`, `id`.
91
+ - **`DatePicker`** — Picks one day, or one instant with `precision="minute"` or `"second"`, from Figma's calendar in a popover. Day precision commits on click; a time precision adds hour/minute(/second) columns and holds a draft until Apply, which Escape or an outside click discards. `timeZone="utc"` draws the UTC calendar day and suffixes times with "UTC" whatever the browser's zone, as the logs pages need. Values are `Date`s; ISO strings are accepted (a string without an offset, such as `2025-01-20` or `2025-01-20T10:00`, is read in `timeZone`), and a `formControl` field seeded with a string is written back as an ISO string. `min`/`max` bound the instant (days and times outside are disabled, as are month arrows and keyboard paging that would leave them; a value clamped up to `min` rounds up to the precision, so on `min`'s own day a day-precision value is `min` itself) and `isDateDisabled` rules out single days. The grid is an ARIA grid with a roving tab stop: arrows move by day and week, PageUp/PageDown by month (Shift for a year), Home/End to the week's ends, Enter or Space picks; every day of a range is `aria-selected`, and a hidden live line asks for the end date once the start is picked. The trigger sits on the 28/32/42 control ladder with Dropdown's chrome; `clearable` adds a clear control reported as `onChange(null)`. Colours come from `text`, `accent` and `card`, so a rebrand repaints the picker; the derived states (hover, outside-month text, selected fill, today ring, range band, pressed opacity) can each be overridden through the `datePicker` theme group (`applyTheme({ colors: { datePicker: { selectedBackground } } })`). _Key props:_ `value`, `defaultValue`, `onChange`, `precision` (`day` | `minute` | `second`), `minuteStep`, `timeZone` (`local` | `utc`), `weekStartsOn`, `min`, `max`, `isDateDisabled`, `presets`, `clearable`, `tag` (`{ label, type }` status beside the value), `tone` (`default` | `chosen` | `pending`, paint only), `placeholder`, `size`, `fullWidth`, `width`, `label`, `description`, `hint`, `tooltip`, `helperText`, `required`, `requiredIndicator`, `formControl`, `error`, `disabled`, `loading`, `id`, `aria-label`, `aria-labelledby`.
92
+ - **`DateRangePicker`** — `DatePicker`'s range form, with the same props and a `{ start, end }` value. The second click completes a day range; a click before the start restarts it. The end always covers the whole of its last unit (`23:59:59.999` for a picked day, the last millisecond of the picked minute or second), so a filter on the range keeps its final minutes. In a `formControl` field a cleared range writes `null`. With a time precision a Start/End switch picks which end the time columns edit, end times before the start are not offered, and Apply waits for both ends. `presets` list beside the calendar and apply at once; pass a function (`value: () => ({ start, end })`) for a relative preset such as "Past 1 hour", so it is measured when clicked rather than when the page loaded. _Key props:_ `value` / `defaultValue` (`{ start, end }`), `onChange`, `presets` (`DateRangePreset[]`), plus every `DatePicker` prop.
91
93
  - **`MultiSelect`** — Multi-select dropdown. `width` fixes the trigger, as `Dropdown` and `Search` take it, so a toolbar can put its controls on one width — and, as with those two, a container narrower than the value still wins; the menu fills the trigger and left-aligns under it, so that one prop sizes both; `minWidth` raises the 160px floor a narrow trigger falls back to. An option label too long for the menu ellipsises, and hovering it shows the full label — above the description in `hover` mode — as `Dropdown` does for its options. `requiredIndicator` follows the same three-way convention the single-select controls do, so a form choosing asterisks does not get "(Optional)" on one of its fields. _Key props:_ `MultiSelectOption[]`, `MultiSelectSize`, `width`, `minWidth`, `label`, `searchable`, `inlineSearch`, `chips`, `chipsRemovable`, `required`, `requiredIndicator`, `aria-label`, `aria-labelledby`, `id`.
92
94
  - **`FilterSearch`** — One search field that filters across several categories. Clicking lists the filters, each with its description and an example; picking one lists its values behind a `Filters > Name` breadcrumb, and typing before picking searches the values of every filter at once, tagging each match with the filter it belongs to. Select All / Deselect All act on whatever the query matches. Each filter becomes a chip (`Connector: Notion`, or `Connector: (Notion, Attio)`) that reopens its values when clicked; Backspace in an empty field removes the last one. Controlled: `onChange` gets the next selection and the `changes` that produced it, an empty `items` meaning the filter was removed, so a URL-backed selection writes back only what moved. Chips keep the order filters were added in even when `value` comes back reordered, and keep their labels while `filters` reloads. _Key props:_ `filters`, `value`, `onChange`, `onClear`, `onActiveFilterChange`, `placeholder`, `size`, `width`, `loading`, `disabled`, `clearable`, `maxVisibleChips`, `aria-label`, `aria-labelledby`, `id`.
93
95
  - **`QueryInput`** — A textbox with inline syntax colouring and a suggestion menu anchored to the caret. It carries no grammar of its own: the consumer parses the value, hands back `tokens` to colour and `suggestions` to offer, so the vocabulary lives in the consuming app rather than here. _Key props:_ `value`, `onChange`, `tokens`, `suggestions`, `activeRange`, `onAccept`, `onQueryContextChange`, `onSubmit`, `placeholder`, `size`, `disabled`, `loading`, `emptyMessage`, `className`, `style`, `aria-label`, `aria-labelledby`.
@@ -96,6 +98,7 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
96
98
  ## Buttons & actions
97
99
 
98
100
  - **`Button`** — Primary button. Variants: `filled`, `outline`, `surface` (outline's geometry on a ground of its own, for a control sitting on a tinted surface), `assistant` (the violet the assistant is named in — provenance, not a severity: it says who is being asked, not that anything is wrong), `destructive`, `success`, `warning`, `error`, `ghost`, `no-style`. Supports `iconOnly`, `loading`, `tooltip`. _Key props:_ `variant`, `size`, `icon`, `iconOnly`, `loading`, `disabled`, `fill`, `tooltip`.
101
+ - **`CloseButton`** — The bare X that dismisses a screen, panel or wizard: secondary at rest, primary on hover and keyboard focus, with no box or background at either. Use it instead of a `ghost` `Button` (which draws a hover box) or `no-style` (which has no disabled look). `surface="inverse"` is for a panel that stays dark in every theme, such as `SplitScreenLayout`’s, and reads the `closeButton` theme tokens. `loading` swaps the X for a spinner and sets `aria-busy`. Disabled and loading both use `aria-disabled` rather than `disabled`, so they ignore clicks but stay focusable and can still trigger a `Tooltip` explaining why. Named "Close" unless `aria-label` says otherwise. _Key props:_ `onClick`, `aria-label`, `size` (`small` 24px | `medium` 32px, 12px glyph), `surface` (`default` | `inverse`), `disabled`, `loading`.
99
102
  - **`PillButton`** — Pill-shaped button, often used for filters/toggleable chips. `shape="tab"` squares the top corners so a row of them reads as attached to whatever sits above — the controls under a chat composer. Pass `href` and an interactive, non-disabled pill renders a real anchor (cmd-click, copy-link) instead of navigating from `onClick`; a disabled or `interactive={false}` pill stays static, and an unsafe scheme such as `javascript:` is dropped. `target="_blank"` always carries `noopener noreferrer`. _Key props:_ `label`, `icon`, `trailingIcon`, `selected`, `disabled`, `interactive`, `size`, `variant`, `shape` (`pill` | `tab`), `onClick`, `href`, `target`, `rel`.
100
103
  - **`Link`** — Styled anchor/link text. _Key props:_ `LinkProps`.
101
104
  - **`InlineConfirm`** — A confirmation asked on the control that triggered it rather than in a modal, for a reversible bulk edit where a dialog would be heavier than the change it guards. Drawn to the design's chip: 33px tall, 12px radius, its confirm cell running to the pill's own edge between two rules. Reads its own `inlineConfirm` theme tokens — a shade off the `SelectionBar` it appears beside, by design. Carries a spinning glyph by default — its own, so it takes the pill's colour rather than the sheet's dimmed grey — standing for a change waiting on an answer; pass `icon={null}` to drop it or a node to replace it. Anchored placement is in viewport coordinates, so the chip must not sit inside an ancestor carrying `transform`, `filter` or `contain`. It takes focus on open so `Enter` confirms, dismisses on `Escape` (through the shared escape-layer stack, so the topmost overlay answers) or a click outside, and returns focus to whatever opened it. `role="alertdialog"` named by the message itself, so the confirm button is never announced bare. Only one can be open at a time: opening a second dismisses the first, so it is never ambiguous what Yes answers. Pass `anchorTo` (a ref to the control it answers for) and it pins itself to that control's left, follows it while the page or a sticky header scrolls, dismisses once it scrolls out of view, and treats clicks on it as inside — without which the same click would dismiss and reopen. Left unanchored it renders in flow for the consumer to place, and must then not sit in a container that clips overflow (`Table` header cells among them). Nothing renders while `open` is false, and its listeners are attached only while it is open. _Key props:_ `open`, `message`, `confirmLabel`, `onConfirm`, `onDismiss`, `anchorTo`, `icon`, `className`, `style`.
@@ -0,0 +1,6 @@
1
+ import * as t from "react";
2
+ const l = (e) => /* @__PURE__ */ t.createElement("svg", { width: 256, height: 256, viewBox: "0 0 256 256", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...e }, /* @__PURE__ */ t.createElement("path", { transform: "matrix(-1 0 0 1 256 0)", d: "M141.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L124.69,128,58.34,61.66A8,8,0,0,1,69.66,50.34l72,72A8,8,0,0,1,141.66,133.66Zm80-11.32-72-72a8,8,0,0,0-11.32,11.32L204.69,128l-66.35,66.34a8,8,0,0,0,11.32,11.32l72-72A8,8,0,0,0,221.66,122.34Z", fill: "currentColor" }));
3
+ export {
4
+ l as default
5
+ };
6
+ //# sourceMappingURL=caret_double_left.svg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caret_double_left.svg.js","sources":["../../../src/assets/icons/caret_double_left.svg?react"],"sourcesContent":["import * as React from \"react\";\nconst SvgCaretDoubleLeft = (props) => /* @__PURE__ */ React.createElement(\"svg\", { width: 256, height: 256, viewBox: \"0 0 256 256\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", ...props }, /* @__PURE__ */ React.createElement(\"path\", { transform: \"matrix(-1 0 0 1 256 0)\", d: \"M141.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L124.69,128,58.34,61.66A8,8,0,0,1,69.66,50.34l72,72A8,8,0,0,1,141.66,133.66Zm80-11.32-72-72a8,8,0,0,0-11.32,11.32L204.69,128l-66.35,66.34a8,8,0,0,0,11.32,11.32l72-72A8,8,0,0,0,221.66,122.34Z\", fill: \"currentColor\" }));\nexport default SvgCaretDoubleLeft;\n"],"names":["SvgCaretDoubleLeft","props","React"],"mappings":";AACK,MAACA,IAAqB,CAACC,MAA0B,gBAAAC,EAAM,cAAc,OAAO,EAAE,OAAO,KAAK,QAAQ,KAAK,SAAS,eAAe,MAAM,QAAQ,OAAO,8BAA8B,GAAGD,EAAK,GAAoB,gBAAAC,EAAM,cAAc,QAAQ,EAAE,WAAW,0BAA0B,GAAG,6OAA6O,MAAM,eAAc,CAAE,CAAC;"}
@@ -0,0 +1,6 @@
1
+ import * as e from "react";
2
+ const l = (t) => /* @__PURE__ */ e.createElement("svg", { width: 256, height: 256, viewBox: "0 0 256 256", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...t }, /* @__PURE__ */ e.createElement("path", { d: "M141.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L124.69,128,58.34,61.66A8,8,0,0,1,69.66,50.34l72,72A8,8,0,0,1,141.66,133.66Zm80-11.32-72-72a8,8,0,0,0-11.32,11.32L204.69,128l-66.35,66.34a8,8,0,0,0,11.32,11.32l72-72A8,8,0,0,0,221.66,122.34Z", fill: "currentColor" }));
3
+ export {
4
+ l as default
5
+ };
6
+ //# sourceMappingURL=caret_double_right.svg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caret_double_right.svg.js","sources":["../../../src/assets/icons/caret_double_right.svg?react"],"sourcesContent":["import * as React from \"react\";\nconst SvgCaretDoubleRight = (props) => /* @__PURE__ */ React.createElement(\"svg\", { width: 256, height: 256, viewBox: \"0 0 256 256\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", ...props }, /* @__PURE__ */ React.createElement(\"path\", { d: \"M141.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L124.69,128,58.34,61.66A8,8,0,0,1,69.66,50.34l72,72A8,8,0,0,1,141.66,133.66Zm80-11.32-72-72a8,8,0,0,0-11.32,11.32L204.69,128l-66.35,66.34a8,8,0,0,0,11.32,11.32l72-72A8,8,0,0,0,221.66,122.34Z\", fill: \"currentColor\" }));\nexport default SvgCaretDoubleRight;\n"],"names":["SvgCaretDoubleRight","props","React"],"mappings":";AACK,MAACA,IAAsB,CAACC,MAA0B,gBAAAC,EAAM,cAAc,OAAO,EAAE,OAAO,KAAK,QAAQ,KAAK,SAAS,eAAe,MAAM,QAAQ,OAAO,8BAA8B,GAAGD,EAAK,GAAoB,gBAAAC,EAAM,cAAc,QAAQ,EAAE,GAAG,6OAA6O,MAAM,eAAc,CAAE,CAAC;"}
@@ -40,8 +40,7 @@ const z = ({
40
40
  }
41
41
  ) }),
42
42
  !p && // Pinned to the side rather than centred over the newest message, which is
43
- // the thing a reader scrolled back to see. `-translate-y-1/2` is measured
44
- // working inside a shadow root (see the CardStrip arrow).
43
+ // the thing a reader scrolled back to see.
45
44
  /* @__PURE__ */ l("div", { className: "absolute right-3 top-1/2 -translate-y-1/2", children: /* @__PURE__ */ l(
46
45
  N,
47
46
  {
@@ -1 +1 @@
1
- {"version":3,"file":"ChatThread.js","sources":["../../../src/components/Chat/ChatThread.tsx"],"sourcesContent":["import React from 'react';\nimport Button from '../Button';\nimport CaretDownIcon from '../CustomIcons/CaretDownIcon';\nimport Typography from '../Typography';\nimport { useStickToBottom } from './stickToBottom';\n\nexport interface ChatThreadProps {\n children?: React.ReactNode;\n /** Names the transcript for assistive tech, e.g. \"Policy assistant conversation\". */\n 'aria-label'?: string;\n /** Shown, centred, while the transcript holds nothing. Ignored when `emptyContent` is\n * supplied. */\n emptyTitle?: string;\n /** The lines under the title. A node, because guidance is rarely one sentence. Ignored\n * when `emptyContent` is supplied. */\n emptyDescription?: React.ReactNode;\n /** Ignored when `emptyContent` is supplied. */\n emptyIcon?: React.ReactNode;\n /**\n * Replaces the `emptyTitle`/`emptyDescription`/`emptyIcon` composition. Renders\n * left-aligned at the bottom of the transcript, directly above the composer — an empty\n * conversation should read as ready to start, not as a decorated void.\n */\n emptyContent?: React.ReactNode;\n className?: string;\n}\n\n/**\n * The scrolling transcript. Owns scroll ownership and the pin-to-newest behaviour so a\n * consumer never wires a scroll listener of its own.\n *\n * `flex-1 min-h-0` is load-bearing: without the floor, WebKit shrinks an `overflow` child to\n * fit its content and scrolling silently moves to an ancestor.\n */\nconst ChatThread: React.FC<ChatThreadProps> = ({\n children,\n 'aria-label': ariaLabel,\n emptyTitle,\n emptyDescription,\n emptyIcon,\n emptyContent,\n className = '',\n}) => {\n const { scrollRef, contentRef, pinned, scrollToBottom } = useStickToBottom();\n\n // `toArray` rather than `count`: it drops the nulls a caller leaves behind when a\n // conditional turn renders nothing, which `count` would tally as content.\n const isEmpty = React.Children.toArray(children).length === 0;\n const isEmptyWithCustomContent = isEmpty && Boolean(emptyContent);\n const isEmptyWithLegacyState =\n isEmpty && !emptyContent && Boolean(emptyTitle || emptyDescription || emptyIcon);\n\n let contentClassName = 'flex flex-col gap-4 p-4';\n if (isEmptyWithCustomContent) {\n // `flex-1`, not `min-h-full`: a percentage height only resolves against a parent with\n // an explicit height, and the scroll div's height comes from flex resolution rather\n // than a set value, so the percentage silently fails to resolve and the content\n // collapses to the top. `flex-1` instead asks the (now flex) scroll div's own layout\n // for a real height, which `mt-auto` below can then push against.\n contentClassName = 'flex flex-1 flex-col p-4';\n } else if (isEmptyWithLegacyState) {\n contentClassName =\n 'flex min-h-full flex-col items-center justify-center gap-2 p-6 text-center';\n }\n\n return (\n <div className={`relative flex min-h-0 flex-1 flex-col ${className}`}>\n <div ref={scrollRef} className=\"flex min-h-0 flex-1 flex-col overflow-y-auto\">\n <div\n ref={contentRef}\n role=\"log\"\n aria-live=\"polite\"\n aria-label={ariaLabel}\n className={contentClassName}\n >\n {isEmptyWithCustomContent ? (\n // `margin-top: auto` consumes the free space the scroll div's flex\n // layout gives this (now `flex-1`) content box, pinning the block to\n // the bottom. `flex-direction: column-reverse` was the mock's own\n // approach, but it inverts scroll geometry that `useStickToBottom` and\n // the jump-to-latest control both rely on — this gets the same bottom\n // anchoring without touching either.\n <div className=\"mt-auto text-left\">{emptyContent}</div>\n ) : isEmptyWithLegacyState ? (\n <>\n {emptyIcon ? (\n <span className=\"text-[var(--malachite-text-dimmed)]\">\n {emptyIcon}\n </span>\n ) : null}\n {emptyTitle ? (\n <Typography.SecondaryText fontWeight=\"bold\">\n {emptyTitle}\n </Typography.SecondaryText>\n ) : null}\n {emptyDescription ? (\n <Typography.SecondaryText size=\"small\">\n {emptyDescription}\n </Typography.SecondaryText>\n ) : null}\n </>\n ) : (\n children\n )}\n </div>\n </div>\n {!pinned && (\n // Pinned to the side rather than centred over the newest message, which is\n // the thing a reader scrolled back to see. `-translate-y-1/2` is measured\n // working inside a shadow root (see the CardStrip arrow).\n <div className=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <Button\n variant=\"outline\"\n size=\"small\"\n iconOnly\n radius=\"xl\"\n // Inline, because no utility class can reach it: Tailwind's utilities\n // sit in `@layer utilities` while `.btn-outline`'s transparent\n // background is an unlayered rule, and unlayered wins. Without this\n // the transcript reads straight through the button.\n style={{\n backgroundColor: 'var(--malachite-card-background)',\n boxShadow: 'var(--malachite-shadow-md)',\n }}\n icon={<CaretDownIcon size={14} />}\n tooltip=\"Jump to latest\"\n aria-label=\"Jump to latest\"\n onClick={scrollToBottom}\n />\n </div>\n )}\n </div>\n );\n};\n\nexport default ChatThread;\nexport { ChatThread };\n"],"names":["ChatThread","children","ariaLabel","emptyTitle","emptyDescription","emptyIcon","emptyContent","className","scrollRef","contentRef","pinned","scrollToBottom","useStickToBottom","isEmpty","React","isEmptyWithCustomContent","isEmptyWithLegacyState","contentClassName","jsxs","jsx","Fragment","Typography","Button","CaretDownIcon"],"mappings":";;;;;;AAkCA,MAAMA,IAAwC,CAAC;AAAA,EAC3C,UAAAC;AAAA,EACA,cAAcC;AAAA,EACd,YAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC,IAAY;AAChB,MAAM;AACF,QAAM,EAAE,WAAAC,GAAW,YAAAC,GAAY,QAAAC,GAAQ,gBAAAC,EAAA,IAAmBC,EAAA,GAIpDC,IAAUC,EAAM,SAAS,QAAQb,CAAQ,EAAE,WAAW,GACtDc,IAA2BF,KAAW,EAAQP,GAC9CU,IACFH,KAAW,CAACP,KAAgB,GAAQH,KAAcC,KAAoBC;AAE1E,MAAIY,IAAmB;AACvB,SAAIF,IAMAE,IAAmB,6BACZD,MACPC,IACI,+EAIJ,gBAAAC,EAAC,OAAA,EAAI,WAAW,yCAAyCX,CAAS,IAC9D,UAAA;AAAA,IAAA,gBAAAY,EAAC,OAAA,EAAI,KAAKX,GAAW,WAAU,gDAC3B,UAAA,gBAAAW;AAAA,MAAC;AAAA,MAAA;AAAA,QACG,KAAKV;AAAA,QACL,MAAK;AAAA,QACL,aAAU;AAAA,QACV,cAAYP;AAAA,QACZ,WAAWe;AAAA,QAEV,UAAAF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAOG,gBAAAI,EAAC,OAAA,EAAI,WAAU,qBAAqB,UAAAb,EAAA,CAAa;AAAA,YACjDU,IACA,gBAAAE,EAAAE,GAAA,EACK,UAAA;AAAA,UAAAf,IACG,gBAAAc,EAAC,QAAA,EAAK,WAAU,uCACX,aACL,IACA;AAAA,UACHhB,sBACIkB,EAAW,eAAX,EAAyB,YAAW,QAChC,aACL,IACA;AAAA,UACHjB,sBACIiB,EAAW,eAAX,EAAyB,MAAK,SAC1B,aACL,IACA;AAAA,QAAA,EAAA,CACR,IAEApB;AAAA,MAAA;AAAA,IAAA,GAGZ;AAAA,IACC,CAACS;AAAA;AAAA;AAAA,IAIE,gBAAAS,EAAC,OAAA,EAAI,WAAU,6CACX,UAAA,gBAAAA;AAAA,MAACG;AAAA,MAAA;AAAA,QACG,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,UAAQ;AAAA,QACR,QAAO;AAAA,QAKP,OAAO;AAAA,UACH,iBAAiB;AAAA,UACjB,WAAW;AAAA,QAAA;AAAA,QAEf,MAAM,gBAAAH,EAACI,GAAA,EAAc,MAAM,GAAA,CAAI;AAAA,QAC/B,SAAQ;AAAA,QACR,cAAW;AAAA,QACX,SAASZ;AAAA,MAAA;AAAA,IAAA,EACb,CACJ;AAAA,EAAA,GAER;AAER;"}
1
+ {"version":3,"file":"ChatThread.js","sources":["../../../src/components/Chat/ChatThread.tsx"],"sourcesContent":["import React from 'react';\nimport Button from '../Button';\nimport CaretDownIcon from '../CustomIcons/CaretDownIcon';\nimport Typography from '../Typography';\nimport { useStickToBottom } from './stickToBottom';\n\nexport interface ChatThreadProps {\n children?: React.ReactNode;\n /** Names the transcript for assistive tech, e.g. \"Policy assistant conversation\". */\n 'aria-label'?: string;\n /** Shown, centred, while the transcript holds nothing. Ignored when `emptyContent` is\n * supplied. */\n emptyTitle?: string;\n /** The lines under the title. A node, because guidance is rarely one sentence. Ignored\n * when `emptyContent` is supplied. */\n emptyDescription?: React.ReactNode;\n /** Ignored when `emptyContent` is supplied. */\n emptyIcon?: React.ReactNode;\n /**\n * Replaces the `emptyTitle`/`emptyDescription`/`emptyIcon` composition. Renders\n * left-aligned at the bottom of the transcript, directly above the composer — an empty\n * conversation should read as ready to start, not as a decorated void.\n */\n emptyContent?: React.ReactNode;\n className?: string;\n}\n\n/**\n * The scrolling transcript. Owns scroll ownership and the pin-to-newest behaviour so a\n * consumer never wires a scroll listener of its own.\n *\n * `flex-1 min-h-0` is load-bearing: without the floor, WebKit shrinks an `overflow` child to\n * fit its content and scrolling silently moves to an ancestor.\n */\nconst ChatThread: React.FC<ChatThreadProps> = ({\n children,\n 'aria-label': ariaLabel,\n emptyTitle,\n emptyDescription,\n emptyIcon,\n emptyContent,\n className = '',\n}) => {\n const { scrollRef, contentRef, pinned, scrollToBottom } = useStickToBottom();\n\n // `toArray` rather than `count`: it drops the nulls a caller leaves behind when a\n // conditional turn renders nothing, which `count` would tally as content.\n const isEmpty = React.Children.toArray(children).length === 0;\n const isEmptyWithCustomContent = isEmpty && Boolean(emptyContent);\n const isEmptyWithLegacyState =\n isEmpty && !emptyContent && Boolean(emptyTitle || emptyDescription || emptyIcon);\n\n let contentClassName = 'flex flex-col gap-4 p-4';\n if (isEmptyWithCustomContent) {\n // `flex-1`, not `min-h-full`: a percentage height only resolves against a parent with\n // an explicit height, and the scroll div's height comes from flex resolution rather\n // than a set value, so the percentage silently fails to resolve and the content\n // collapses to the top. `flex-1` instead asks the (now flex) scroll div's own layout\n // for a real height, which `mt-auto` below can then push against.\n contentClassName = 'flex flex-1 flex-col p-4';\n } else if (isEmptyWithLegacyState) {\n contentClassName =\n 'flex min-h-full flex-col items-center justify-center gap-2 p-6 text-center';\n }\n\n return (\n <div className={`relative flex min-h-0 flex-1 flex-col ${className}`}>\n <div ref={scrollRef} className=\"flex min-h-0 flex-1 flex-col overflow-y-auto\">\n <div\n ref={contentRef}\n role=\"log\"\n aria-live=\"polite\"\n aria-label={ariaLabel}\n className={contentClassName}\n >\n {isEmptyWithCustomContent ? (\n // `margin-top: auto` consumes the free space the scroll div's flex\n // layout gives this (now `flex-1`) content box, pinning the block to\n // the bottom. `flex-direction: column-reverse` was the mock's own\n // approach, but it inverts scroll geometry that `useStickToBottom` and\n // the jump-to-latest control both rely on — this gets the same bottom\n // anchoring without touching either.\n <div className=\"mt-auto text-left\">{emptyContent}</div>\n ) : isEmptyWithLegacyState ? (\n <>\n {emptyIcon ? (\n <span className=\"text-[var(--malachite-text-dimmed)]\">\n {emptyIcon}\n </span>\n ) : null}\n {emptyTitle ? (\n <Typography.SecondaryText fontWeight=\"bold\">\n {emptyTitle}\n </Typography.SecondaryText>\n ) : null}\n {emptyDescription ? (\n <Typography.SecondaryText size=\"small\">\n {emptyDescription}\n </Typography.SecondaryText>\n ) : null}\n </>\n ) : (\n children\n )}\n </div>\n </div>\n {!pinned && (\n // Pinned to the side rather than centred over the newest message, which is\n // the thing a reader scrolled back to see.\n <div className=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <Button\n variant=\"outline\"\n size=\"small\"\n iconOnly\n radius=\"xl\"\n // Inline, because no utility class can reach it: Tailwind's utilities\n // sit in `@layer utilities` while `.btn-outline`'s transparent\n // background is an unlayered rule, and unlayered wins. Without this\n // the transcript reads straight through the button.\n style={{\n backgroundColor: 'var(--malachite-card-background)',\n boxShadow: 'var(--malachite-shadow-md)',\n }}\n icon={<CaretDownIcon size={14} />}\n tooltip=\"Jump to latest\"\n aria-label=\"Jump to latest\"\n onClick={scrollToBottom}\n />\n </div>\n )}\n </div>\n );\n};\n\nexport default ChatThread;\nexport { ChatThread };\n"],"names":["ChatThread","children","ariaLabel","emptyTitle","emptyDescription","emptyIcon","emptyContent","className","scrollRef","contentRef","pinned","scrollToBottom","useStickToBottom","isEmpty","React","isEmptyWithCustomContent","isEmptyWithLegacyState","contentClassName","jsxs","jsx","Fragment","Typography","Button","CaretDownIcon"],"mappings":";;;;;;AAkCA,MAAMA,IAAwC,CAAC;AAAA,EAC3C,UAAAC;AAAA,EACA,cAAcC;AAAA,EACd,YAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC,IAAY;AAChB,MAAM;AACF,QAAM,EAAE,WAAAC,GAAW,YAAAC,GAAY,QAAAC,GAAQ,gBAAAC,EAAA,IAAmBC,EAAA,GAIpDC,IAAUC,EAAM,SAAS,QAAQb,CAAQ,EAAE,WAAW,GACtDc,IAA2BF,KAAW,EAAQP,GAC9CU,IACFH,KAAW,CAACP,KAAgB,GAAQH,KAAcC,KAAoBC;AAE1E,MAAIY,IAAmB;AACvB,SAAIF,IAMAE,IAAmB,6BACZD,MACPC,IACI,+EAIJ,gBAAAC,EAAC,OAAA,EAAI,WAAW,yCAAyCX,CAAS,IAC9D,UAAA;AAAA,IAAA,gBAAAY,EAAC,OAAA,EAAI,KAAKX,GAAW,WAAU,gDAC3B,UAAA,gBAAAW;AAAA,MAAC;AAAA,MAAA;AAAA,QACG,KAAKV;AAAA,QACL,MAAK;AAAA,QACL,aAAU;AAAA,QACV,cAAYP;AAAA,QACZ,WAAWe;AAAA,QAEV,UAAAF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAOG,gBAAAI,EAAC,OAAA,EAAI,WAAU,qBAAqB,UAAAb,EAAA,CAAa;AAAA,YACjDU,IACA,gBAAAE,EAAAE,GAAA,EACK,UAAA;AAAA,UAAAf,IACG,gBAAAc,EAAC,QAAA,EAAK,WAAU,uCACX,aACL,IACA;AAAA,UACHhB,sBACIkB,EAAW,eAAX,EAAyB,YAAW,QAChC,aACL,IACA;AAAA,UACHjB,sBACIiB,EAAW,eAAX,EAAyB,MAAK,SAC1B,aACL,IACA;AAAA,QAAA,EAAA,CACR,IAEApB;AAAA,MAAA;AAAA,IAAA,GAGZ;AAAA,IACC,CAACS;AAAA;AAAA,IAGE,gBAAAS,EAAC,OAAA,EAAI,WAAU,6CACX,UAAA,gBAAAA;AAAA,MAACG;AAAA,MAAA;AAAA,QACG,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,UAAQ;AAAA,QACR,QAAO;AAAA,QAKP,OAAO;AAAA,UACH,iBAAiB;AAAA,UACjB,WAAW;AAAA,QAAA;AAAA,QAEf,MAAM,gBAAAH,EAACI,GAAA,EAAc,MAAM,GAAA,CAAI;AAAA,QAC/B,SAAQ;AAAA,QACR,cAAW;AAAA,QACX,SAASZ;AAAA,MAAA;AAAA,IAAA,EACb,CACJ;AAAA,EAAA,GAER;AAER;"}
@@ -0,0 +1,76 @@
1
+ import { jsx as l } from "react/jsx-runtime";
2
+ import { forwardRef as f } from "react";
3
+ import h from "./CustomIcons/DismissIcon.js";
4
+ import { FOCUS_RING_CLOSE_BUTTON_INVERSE as v, FOCUS_RING as p } from "./focusRing.js";
5
+ const x = {
6
+ small: { target: 24, glyph: 12 },
7
+ medium: { target: 32, glyph: 12 }
8
+ }, y = {
9
+ default: {
10
+ idle: "text-[var(--malachite-text-secondary,rgb(123,123,123))]",
11
+ interactive: "hover:text-[var(--malachite-text-primary,rgb(10,10,10))] focus-visible:text-[var(--malachite-text-primary,rgb(10,10,10))]",
12
+ disabled: "text-[var(--malachite-text-dimmed,rgb(161,161,161))]",
13
+ focusRing: p
14
+ },
15
+ inverse: {
16
+ idle: "text-[var(--malachite-close-button-inverse-foreground,rgba(255,255,255,0.7))]",
17
+ interactive: "hover:text-[var(--malachite-close-button-inverse-hover-foreground,rgb(255,255,255))] focus-visible:text-[var(--malachite-close-button-inverse-hover-foreground,rgb(255,255,255))]",
18
+ disabled: "text-[var(--malachite-close-button-inverse-disabled-foreground,rgba(255,255,255,0.35))]",
19
+ focusRing: v
20
+ }
21
+ }, S = (e, a) => {
22
+ const { idle: r, interactive: o, disabled: t, focusRing: i } = y[e];
23
+ return `${{
24
+ enabled: `${r} ${o} cursor-pointer`,
25
+ disabled: `${t} cursor-not-allowed`,
26
+ loading: `${r} cursor-progress`
27
+ }[a]} ${i}`;
28
+ }, C = "flex shrink-0 items-center justify-center rounded-md border-0 bg-transparent p-0 transition-colors", $ = (e) => {
29
+ e.preventDefault(), e.stopPropagation();
30
+ }, E = f(
31
+ ({
32
+ onClick: e,
33
+ "aria-label": a = "Close",
34
+ "aria-labelledby": r,
35
+ disabled: o = !1,
36
+ loading: t = !1,
37
+ size: i = "small",
38
+ surface: n = "default",
39
+ className: u = "",
40
+ ...m
41
+ }, g) => {
42
+ const { target: d, glyph: s } = x[i], c = o && "disabled" || t && "loading" || "enabled", b = c !== "enabled";
43
+ return /* @__PURE__ */ l(
44
+ "button",
45
+ {
46
+ ...m,
47
+ ref: g,
48
+ type: "button",
49
+ "aria-label": a,
50
+ "aria-labelledby": r,
51
+ "aria-disabled": b ? !0 : void 0,
52
+ "aria-busy": t ? !0 : void 0,
53
+ onClick: b ? $ : e,
54
+ className: `${C} ${S(n, c)} ${u}`,
55
+ style: { width: d, height: d },
56
+ children: t ? (
57
+ // Not `Spinner`: its smallest step is 14px inside a min-height wrapper.
58
+ /* @__PURE__ */ l(
59
+ "span",
60
+ {
61
+ "aria-hidden": !0,
62
+ className: "box-border shrink-0 animate-spin rounded-full border-2 border-solid border-current border-t-transparent motion-reduce:animate-none motion-reduce:border-t-current",
63
+ style: { width: s, height: s }
64
+ }
65
+ )
66
+ ) : /* @__PURE__ */ l(h, { size: s })
67
+ }
68
+ );
69
+ }
70
+ );
71
+ E.displayName = "CloseButton";
72
+ export {
73
+ E as CloseButton,
74
+ E as default
75
+ };
76
+ //# sourceMappingURL=CloseButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CloseButton.js","sources":["../../src/components/CloseButton.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport DismissIcon from './CustomIcons/DismissIcon';\nimport { FOCUS_RING, FOCUS_RING_CLOSE_BUTTON_INVERSE } from './focusRing';\n\nexport type CloseButtonSize = 'small' | 'medium';\n\n/** `inverse` is for a surface that stays dark in every theme, e.g. `SplitScreenLayout`'s panel. */\nexport type CloseButtonSurface = 'default' | 'inverse';\n\nexport interface CloseButtonProps\n extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n | 'children'\n | 'className'\n | 'style'\n | 'color'\n | 'type'\n | 'disabled'\n | 'onClick'\n | 'aria-label'\n | 'aria-disabled'\n | 'aria-busy'\n > {\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n /** Accessible name. Defaults to \"Close\"; name what closes when there are several. */\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n disabled?: boolean;\n /** Shows a spinner in place of the X, sets `aria-busy` and ignores clicks. */\n loading?: boolean;\n /** `small` is a 24px target, `medium` a 32px one. The glyph is 12px in both. */\n size?: CloseButtonSize;\n surface?: CloseButtonSurface;\n className?: string;\n}\n\nconst SIZE_PX: Record<CloseButtonSize, { target: number; glyph: number }> = {\n small: { target: 24, glyph: 12 },\n medium: { target: 32, glyph: 12 },\n};\n\nconst SURFACE_CLASSES: Record<\n CloseButtonSurface,\n { idle: string; interactive: string; disabled: string; focusRing: string }\n> = {\n default: {\n idle: 'text-[var(--malachite-text-secondary,rgb(123,123,123))]',\n interactive:\n 'hover:text-[var(--malachite-text-primary,rgb(10,10,10))] focus-visible:text-[var(--malachite-text-primary,rgb(10,10,10))]',\n disabled: 'text-[var(--malachite-text-dimmed,rgb(161,161,161))]',\n focusRing: FOCUS_RING,\n },\n inverse: {\n idle: 'text-[var(--malachite-close-button-inverse-foreground,rgba(255,255,255,0.7))]',\n interactive:\n 'hover:text-[var(--malachite-close-button-inverse-hover-foreground,rgb(255,255,255))] focus-visible:text-[var(--malachite-close-button-inverse-hover-foreground,rgb(255,255,255))]',\n disabled:\n 'text-[var(--malachite-close-button-inverse-disabled-foreground,rgba(255,255,255,0.35))]',\n focusRing: FOCUS_RING_CLOSE_BUTTON_INVERSE,\n },\n};\n\ntype CloseButtonState = 'enabled' | 'disabled' | 'loading';\n\nconst stateClassesOf = (surface: CloseButtonSurface, state: CloseButtonState): string => {\n const { idle, interactive, disabled, focusRing } = SURFACE_CLASSES[surface];\n const byState: Record<CloseButtonState, string> = {\n enabled: `${idle} ${interactive} cursor-pointer`,\n disabled: `${disabled} cursor-not-allowed`,\n loading: `${idle} cursor-progress`,\n };\n return `${byState[state]} ${focusRing}`;\n};\n\nconst BASE_CLASSES =\n 'flex shrink-0 items-center justify-center rounded-md border-0 bg-transparent p-0 transition-colors';\n\n// A click on an aria-disabled button still dispatches, so stop it before an ancestor's handler runs.\nconst swallowClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n};\n\n/** The bare X that dismisses a screen or panel: no box at rest or on hover. */\nconst CloseButton = forwardRef<HTMLButtonElement, CloseButtonProps>(\n (\n {\n onClick,\n 'aria-label': ariaLabel = 'Close',\n 'aria-labelledby': ariaLabelledBy,\n disabled = false,\n loading = false,\n size = 'small',\n surface = 'default',\n className = '',\n ...rest\n },\n ref,\n ) => {\n const { target, glyph } = SIZE_PX[size];\n const state: CloseButtonState =\n (disabled && 'disabled') || (loading && 'loading') || 'enabled';\n const inactive = state !== 'enabled';\n\n return (\n <button\n {...rest}\n ref={ref}\n type=\"button\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n // aria-disabled, not `disabled`: a disabled element gets no pointer events, so a\n // wrapping Tooltip could never explain it, and focus would drop to <body> mid-request.\n aria-disabled={inactive ? true : undefined}\n aria-busy={loading ? true : undefined}\n onClick={inactive ? swallowClick : onClick}\n className={`${BASE_CLASSES} ${stateClassesOf(surface, state)} ${className}`}\n style={{ width: target, height: target }}\n >\n {loading ? (\n // Not `Spinner`: its smallest step is 14px inside a min-height wrapper.\n <span\n aria-hidden\n className=\"box-border shrink-0 animate-spin rounded-full border-2 border-solid border-current border-t-transparent motion-reduce:animate-none motion-reduce:border-t-current\"\n style={{ width: glyph, height: glyph }}\n />\n ) : (\n <DismissIcon size={glyph} />\n )}\n </button>\n );\n },\n);\n\nCloseButton.displayName = 'CloseButton';\n\nexport default CloseButton;\nexport { CloseButton };\n"],"names":["SIZE_PX","SURFACE_CLASSES","FOCUS_RING","FOCUS_RING_CLOSE_BUTTON_INVERSE","stateClassesOf","surface","state","idle","interactive","disabled","focusRing","BASE_CLASSES","swallowClick","event","CloseButton","forwardRef","onClick","ariaLabel","ariaLabelledBy","loading","size","className","rest","ref","target","glyph","inactive","jsx","DismissIcon"],"mappings":";;;;AAoCA,MAAMA,IAAsE;AAAA,EACxE,OAAO,EAAE,QAAQ,IAAI,OAAO,GAAA;AAAA,EAC5B,QAAQ,EAAE,QAAQ,IAAI,OAAO,GAAA;AACjC,GAEMC,IAGF;AAAA,EACA,SAAS;AAAA,IACL,MAAM;AAAA,IACN,aACI;AAAA,IACJ,UAAU;AAAA,IACV,WAAWC;AAAA,EAAA;AAAA,EAEf,SAAS;AAAA,IACL,MAAM;AAAA,IACN,aACI;AAAA,IACJ,UACI;AAAA,IACJ,WAAWC;AAAA,EAAA;AAEnB,GAIMC,IAAiB,CAACC,GAA6BC,MAAoC;AACrF,QAAM,EAAE,MAAAC,GAAM,aAAAC,GAAa,UAAAC,GAAU,WAAAC,EAAA,IAAcT,EAAgBI,CAAO;AAM1E,SAAO,GAL2C;AAAA,IAC9C,SAAS,GAAGE,CAAI,IAAIC,CAAW;AAAA,IAC/B,UAAU,GAAGC,CAAQ;AAAA,IACrB,SAAS,GAAGF,CAAI;AAAA,EAAA,EAEFD,CAAK,CAAC,IAAII,CAAS;AACzC,GAEMC,IACF,sGAGEC,IAAe,CAACC,MAA+C;AACjE,EAAAA,EAAM,eAAA,GACNA,EAAM,gBAAA;AACV,GAGMC,IAAcC;AAAA,EAChB,CACI;AAAA,IACI,SAAAC;AAAA,IACA,cAAcC,IAAY;AAAA,IAC1B,mBAAmBC;AAAA,IACnB,UAAAT,IAAW;AAAA,IACX,SAAAU,IAAU;AAAA,IACV,MAAAC,IAAO;AAAA,IACP,SAAAf,IAAU;AAAA,IACV,WAAAgB,IAAY;AAAA,IACZ,GAAGC;AAAA,EAAA,GAEPC,MACC;AACD,UAAM,EAAE,QAAAC,GAAQ,OAAAC,MAAUzB,EAAQoB,CAAI,GAChCd,IACDG,KAAY,cAAgBU,KAAW,aAAc,WACpDO,IAAWpB,MAAU;AAE3B,WACI,gBAAAqB;AAAA,MAAC;AAAA,MAAA;AAAA,QACI,GAAGL;AAAA,QACJ,KAAAC;AAAA,QACA,MAAK;AAAA,QACL,cAAYN;AAAA,QACZ,mBAAiBC;AAAA,QAGjB,iBAAeQ,IAAW,KAAO;AAAA,QACjC,aAAWP,IAAU,KAAO;AAAA,QAC5B,SAASO,IAAWd,IAAeI;AAAA,QACnC,WAAW,GAAGL,CAAY,IAAIP,EAAeC,GAASC,CAAK,CAAC,IAAIe,CAAS;AAAA,QACzE,OAAO,EAAE,OAAOG,GAAQ,QAAQA,EAAA;AAAA,QAE/B,UAAAL;AAAA;AAAA,UAEG,gBAAAQ;AAAA,YAAC;AAAA,YAAA;AAAA,cACG,eAAW;AAAA,cACX,WAAU;AAAA,cACV,OAAO,EAAE,OAAOF,GAAO,QAAQA,EAAA;AAAA,YAAM;AAAA,UAAA;AAAA,YAGzC,gBAAAE,EAACC,GAAA,EAAY,MAAMH,EAAA,CAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAI1C;AACJ;AAEAX,EAAY,cAAc;"}
@@ -0,0 +1,21 @@
1
+ import { jsx as n } from "react/jsx-runtime";
2
+ import f from "../../assets/icons/caret_double_left.svg.js";
3
+ const c = ({
4
+ size: t = 16,
5
+ className: o = "",
6
+ style: r = {},
7
+ onClick: e
8
+ }) => {
9
+ const l = {
10
+ width: typeof t == "number" ? `${t}px` : t,
11
+ height: typeof t == "number" ? `${t}px` : t,
12
+ display: "inline-block",
13
+ fill: "currentColor",
14
+ ...r
15
+ };
16
+ return /* @__PURE__ */ n(f, { className: o, style: l, onClick: e });
17
+ };
18
+ export {
19
+ c as default
20
+ };
21
+ //# sourceMappingURL=CaretDoubleLeftIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CaretDoubleLeftIcon.js","sources":["../../../src/components/CustomIcons/CaretDoubleLeftIcon.tsx"],"sourcesContent":["import type { CSSProperties } from 'react';\nimport CaretDoubleLeftIconSvg from '../../assets/icons/caret_double_left.svg?react';\n\nexport interface IconProps {\n size?: number | string;\n className?: string;\n style?: CSSProperties;\n onClick?: () => void;\n}\n\nconst CaretDoubleLeftIcon: React.FC<IconProps> = ({\n size = 16,\n className = '',\n style = {},\n onClick,\n}) => {\n const iconStyle: CSSProperties = {\n width: typeof size === 'number' ? `${size}px` : size,\n height: typeof size === 'number' ? `${size}px` : size,\n display: 'inline-block',\n fill: 'currentColor',\n ...style,\n };\n\n return <CaretDoubleLeftIconSvg className={className} style={iconStyle} onClick={onClick} />;\n};\n\nexport default CaretDoubleLeftIcon;\n"],"names":["CaretDoubleLeftIcon","size","className","style","onClick","iconStyle","jsx","CaretDoubleLeftIconSvg"],"mappings":";;AAUA,MAAMA,IAA2C,CAAC;AAAA,EAC9C,MAAAC,IAAO;AAAA,EACP,WAAAC,IAAY;AAAA,EACZ,OAAAC,IAAQ,CAAA;AAAA,EACR,SAAAC;AACJ,MAAM;AACF,QAAMC,IAA2B;AAAA,IAC7B,OAAO,OAAOJ,KAAS,WAAW,GAAGA,CAAI,OAAOA;AAAA,IAChD,QAAQ,OAAOA,KAAS,WAAW,GAAGA,CAAI,OAAOA;AAAA,IACjD,SAAS;AAAA,IACT,MAAM;AAAA,IACN,GAAGE;AAAA,EAAA;AAGP,SAAO,gBAAAG,EAACC,GAAA,EAAuB,WAAAL,GAAsB,OAAOG,GAAW,SAAAD,GAAkB;AAC7F;"}
@@ -0,0 +1,21 @@
1
+ import { jsx as n } from "react/jsx-runtime";
2
+ import p from "../../assets/icons/caret_double_right.svg.js";
3
+ const f = ({
4
+ size: t = 16,
5
+ className: o = "",
6
+ style: r = {},
7
+ onClick: e
8
+ }) => {
9
+ const l = {
10
+ width: typeof t == "number" ? `${t}px` : t,
11
+ height: typeof t == "number" ? `${t}px` : t,
12
+ display: "inline-block",
13
+ fill: "currentColor",
14
+ ...r
15
+ };
16
+ return /* @__PURE__ */ n(p, { className: o, style: l, onClick: e });
17
+ };
18
+ export {
19
+ f as default
20
+ };
21
+ //# sourceMappingURL=CaretDoubleRightIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CaretDoubleRightIcon.js","sources":["../../../src/components/CustomIcons/CaretDoubleRightIcon.tsx"],"sourcesContent":["import type { CSSProperties } from 'react';\nimport CaretDoubleRightIconSvg from '../../assets/icons/caret_double_right.svg?react';\n\nexport interface IconProps {\n size?: number | string;\n className?: string;\n style?: CSSProperties;\n onClick?: () => void;\n}\n\nconst CaretDoubleRightIcon: React.FC<IconProps> = ({\n size = 16,\n className = '',\n style = {},\n onClick,\n}) => {\n const iconStyle: CSSProperties = {\n width: typeof size === 'number' ? `${size}px` : size,\n height: typeof size === 'number' ? `${size}px` : size,\n display: 'inline-block',\n fill: 'currentColor',\n ...style,\n };\n\n return <CaretDoubleRightIconSvg className={className} style={iconStyle} onClick={onClick} />;\n};\n\nexport default CaretDoubleRightIcon;\n"],"names":["CaretDoubleRightIcon","size","className","style","onClick","iconStyle","jsx","CaretDoubleRightIconSvg"],"mappings":";;AAUA,MAAMA,IAA4C,CAAC;AAAA,EAC/C,MAAAC,IAAO;AAAA,EACP,WAAAC,IAAY;AAAA,EACZ,OAAAC,IAAQ,CAAA;AAAA,EACR,SAAAC;AACJ,MAAM;AACF,QAAMC,IAA2B;AAAA,IAC7B,OAAO,OAAOJ,KAAS,WAAW,GAAGA,CAAI,OAAOA;AAAA,IAChD,QAAQ,OAAOA,KAAS,WAAW,GAAGA,CAAI,OAAOA;AAAA,IACjD,SAAS;AAAA,IACT,MAAM;AAAA,IACN,GAAGE;AAAA,EAAA;AAGP,SAAO,gBAAAG,EAACC,GAAA,EAAwB,WAAAL,GAAsB,OAAOG,GAAW,SAAAD,GAAkB;AAC9F;"}