tempest-react-sdk 0.74.0 → 0.76.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.
- package/README.md +3 -1
- package/dist/br/BrazilMap.module.cjs.map +1 -1
- package/dist/br/BrazilMap.module.js.map +1 -1
- package/dist/br/MunicipalitySearch.cjs +1 -1
- package/dist/br/MunicipalitySearch.cjs.map +1 -1
- package/dist/br/MunicipalitySearch.js +66 -48
- package/dist/br/MunicipalitySearch.js.map +1 -1
- package/dist/br/MunicipalitySearch.module.cjs +1 -1
- package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
- package/dist/br/MunicipalitySearch.module.js +4 -3
- package/dist/br/MunicipalitySearch.module.js.map +1 -1
- package/dist/br.d.ts +12 -0
- package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
- package/dist/components/AIChat/AIChat.module.js.map +1 -1
- package/dist/components/AppBar/AppBar.cjs +1 -1
- package/dist/components/AppBar/AppBar.cjs.map +1 -1
- package/dist/components/AppBar/AppBar.js +1 -0
- package/dist/components/AppBar/AppBar.js.map +1 -1
- package/dist/components/AppBar/AppBar.module.cjs +1 -1
- package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
- package/dist/components/AppBar/AppBar.module.js +12 -11
- package/dist/components/AppBar/AppBar.module.js.map +1 -1
- package/dist/components/Button/Button.module.cjs.map +1 -1
- package/dist/components/Button/Button.module.js.map +1 -1
- package/dist/components/Button/ButtonContent.cjs.map +1 -1
- package/dist/components/Button/ButtonContent.js.map +1 -1
- package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
- package/dist/components/Carousel/Carousel.module.js.map +1 -1
- package/dist/components/Chat/Chat.module.cjs.map +1 -1
- package/dist/components/Chat/Chat.module.js.map +1 -1
- package/dist/components/Combobox/Combobox.cjs +1 -1
- package/dist/components/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/Combobox/Combobox.js +18 -23
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Combobox/use-listbox-dismiss.cjs +2 -0
- package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -0
- package/dist/components/Combobox/use-listbox-dismiss.js +34 -0
- package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -0
- package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
- package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
- package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
- package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
- package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
- package/dist/components/ListTile/ListTile.module.js.map +1 -1
- package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
- package/dist/components/Markdown/Markdown.module.js.map +1 -1
- package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
- package/dist/components/Menubar/Menubar.module.js.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.cjs +1 -1
- package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.js +55 -54
- package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/components/Navbar/Navbar.cjs +1 -1
- package/dist/components/Navbar/Navbar.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.js +1 -0
- package/dist/components/Navbar/Navbar.js.map +1 -1
- package/dist/components/Navbar/Navbar.module.cjs +1 -1
- package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.module.js +9 -8
- package/dist/components/Navbar/Navbar.module.js.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
- package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
- package/dist/components/PinInput/PinInput.module.js.map +1 -1
- package/dist/components/SectionHeader/SectionHeader.cjs +1 -1
- package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -1
- package/dist/components/SectionHeader/SectionHeader.js +33 -25
- package/dist/components/SectionHeader/SectionHeader.js.map +1 -1
- package/dist/components/Tour/Tour.module.cjs.map +1 -1
- package/dist/components/Tour/Tour.module.js.map +1 -1
- package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
- package/dist/components/Transfer/Transfer.module.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
- package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
- package/dist/geo/TrajectoryMap.module.js.map +1 -1
- package/dist/icons/IconPicker.module.cjs.map +1 -1
- package/dist/icons/IconPicker.module.js.map +1 -1
- package/dist/neural.cjs +2 -0
- package/dist/neural.cjs.map +1 -0
- package/dist/neural.d.ts +110 -0
- package/dist/neural.js +48 -0
- package/dist/neural.js.map +1 -0
- package/dist/styles/actions.css +2 -2
- package/dist/styles/br.css +3 -3
- package/dist/styles/chat.css +5 -5
- package/dist/styles/component/AIChat.css +3 -3
- package/dist/styles/component/AppBar.css +1 -0
- package/dist/styles/component/BrazilMap.css +2 -2
- package/dist/styles/component/Button.css +1 -1
- package/dist/styles/component/Carousel.css +3 -3
- package/dist/styles/component/Chat.css +2 -2
- package/dist/styles/component/Dropzone.css +2 -1
- package/dist/styles/component/FilterBar.css +2 -2
- package/dist/styles/component/FloatingActionButton.css +1 -1
- package/dist/styles/component/IconPicker.css +1 -1
- package/dist/styles/component/ImageCropper.css +2 -2
- package/dist/styles/component/ListTile.css +1 -1
- package/dist/styles/component/Markdown.css +1 -1
- package/dist/styles/component/Menubar.css +1 -1
- package/dist/styles/component/MunicipalitySearch.css +1 -1
- package/dist/styles/component/Navbar.css +1 -0
- package/dist/styles/component/NavigationMenu.css +1 -1
- package/dist/styles/component/NavigationRail.css +1 -1
- package/dist/styles/component/NotificationCenter.css +3 -3
- package/dist/styles/component/PasswordInput.css +1 -1
- package/dist/styles/component/PinInput.css +1 -1
- package/dist/styles/component/Tour.css +2 -2
- package/dist/styles/component/TrajectoryMap.css +1 -1
- package/dist/styles/component/Transfer.css +2 -2
- package/dist/styles/component/VirtualTable.css +2 -2
- package/dist/styles/data.css +10 -10
- package/dist/styles/feedback.css +3 -3
- package/dist/styles/forms.css +6 -5
- package/dist/styles/geo.css +1 -1
- package/dist/styles/icons.css +1 -1
- package/dist/styles/inverse.css +225 -0
- package/dist/styles/navigation.css +8 -6
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.d.ts +130 -17
- package/dist/theme/create-theme.cjs +1 -1
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js +6 -1
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/inverse-render.cjs +1 -1
- package/dist/theme/inverse-render.cjs.map +1 -1
- package/dist/theme/inverse-render.js +1 -1
- package/dist/theme/inverse-render.js.map +1 -1
- package/dist/theme/inverse-restore.cjs +5 -0
- package/dist/theme/inverse-restore.cjs.map +1 -0
- package/dist/theme/inverse-restore.js +30 -0
- package/dist/theme/inverse-restore.js.map +1 -0
- package/dist/theme/inverse-surface.cjs +1 -1
- package/dist/theme/inverse-surface.cjs.map +1 -1
- package/dist/theme/inverse-surface.js +69 -72
- package/dist/theme/inverse-surface.js.map +1 -1
- package/package.json +11 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIChat.module.js","names":[],"sources":["../../../src/components/AIChat/AIChat.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n height: var(--tempest-ai-chat-height, 100%);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n flex: 0 0 auto;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n/*\n * The wrapper exists only so the jump-to-latest button can be positioned against\n * the scroll area without being scrolled away with it.\n */\n.threadWrapper {\n position: relative;\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n}\n\n/*\n * `min-width: 0` is load-bearing, not defensive.\n *\n * A flex item defaults to `min-width: auto`, which means \"at least as wide as my\n * content wants\". An answer carrying a wide table or a long line of SQL would make\n * the scroll area itself grow past the panel — and the table's own `overflow-x`\n * inside `Markdown` never gets a chance to kick in, because it is already as wide as\n * it asked to be. Zeroing the floor here is what pushes the overflow back down to\n * the table and the code block, where it scrolls in its own box.\n */\n.thread {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--tempest-space-5);\n min-width: 0;\n min-height: 0;\n padding: var(--tempest-space-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.thread:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -2px;\n}\n\n.jump {\n position: absolute;\n right: var(--tempest-space-4);\n bottom: var(--tempest-space-3);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n padding: 0;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n box-shadow: var(--tempest-shadow-md);\n cursor: pointer;\n}\n\n.jump:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n\n/* Same 44×44 hit-slop as the turn actions: 2rem is a small target for a thumb. */\n@media (pointer: coarse) {\n .jump::after {\n content: \"\";\n position: absolute;\n inset: -6px;\n }\n}\n\n/* --- turn ------------------------------------------------------------------ */\n\n/*\n * Turns, the thinking row, the suggestions and the composer all share one reading\n * column — `--tempest-ai-chat-width`, 48rem by default — centred in whatever width\n * the panel got.\n *\n * A capped column is the right answer from a phone up to a 1920 desktop: prose past\n * roughly 90 characters per line is measurably harder to track back to the start of\n * the next line, and letting an answer run the full width of a wide monitor makes it\n * worse, not more useful. It is deliberately a **knob** rather than a constant\n * because at 2560 and above the trade flips — a 768px ribbon in the middle of a\n * living-room screen is mostly empty room, and only the app knows how far away its\n * user is sitting. Widen it at the root: `--tempest-ai-chat-width: 72rem`.\n *\n * Type size is **not** solved here. Scaling the font for a TV is a decision for\n * `typography.css` and `density.css` — a component-local font ramp would fight the\n * tokens every app themes through.\n */\n.turn {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-2);\n min-width: 0;\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin-inline: auto;\n}\n\n/*\n * An assistant turn is full width with no bubble, a user turn is a narrow bubble\n * pushed to the end of the row.\n *\n * That asymmetry is the whole reading model of an LLM transcript: the answer is the\n * document being read, and wrapping it in a bubble would cap its width, fight the\n * code blocks and tables inside it, and make a long answer look like a shouted\n * message. The prompt is short and needs to be told apart at a glance, which a\n * bubble does better than anything else.\n */\n.userTurn {\n align-items: flex-end;\n}\n\n.systemTurn {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px dashed var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n\n.turnHeader {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n min-width: 0;\n}\n\n.avatar {\n display: inline-flex;\n flex: 0 0 auto;\n}\n\n.role {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-semibold);\n}\n\n/*\n * The role of a user turn is announced but not drawn: the bubble on the other side\n * already says who wrote it, and a \"Você\" label over every prompt is noise. Screen\n * readers still get it, because side and colour are not information for them.\n */\n.visuallyHiddenRole {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n border: 0;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/*\n * The meta row uses the muted token, not the subtle one.\n *\n * `--tempest-text-subtle` at `--tempest-text-2xs` measures **4.37:1** against\n * `--tempest-bg` in the dark theme — under the 4.5:1 floor for text. Measured in a\n * real browser; jsdom's `axe` turns `color-contrast` off because nothing is painted.\n * Size is what de-emphasises this row; colour still has to pass.\n */\n.model,\n.time {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.body {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.userTurn .body {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n max-width: min(85%, 36rem);\n}\n\n.plain {\n white-space: pre-wrap;\n}\n\n.markdownRoot {\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-relaxed);\n}\n\n/*\n * The caret rides the last block of the answer, so it sits at the end of the text\n * instead of on a line of its own.\n *\n * `::after` on the final child is inline content, which is exactly the behaviour\n * wanted: it flows after the last word and moves with it as more text arrives. When\n * the answer starts with a fenced block the caret lands inside the code area — which\n * is where the text is actually being appended, so it is still telling the truth.\n */\n.streamingBody > .markdownRoot > :last-child::after {\n content: \"▍\";\n margin-left: 0.125em;\n color: var(--tempest-primary);\n animation: caretBlink 1s steps(2, jump-none) infinite;\n}\n\n@keyframes caretBlink {\n to {\n opacity: 0.2;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .streamingBody > .markdownRoot > :last-child::after {\n animation: none;\n }\n}\n\n.dots {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n}\n\n.dots > span {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background-color: var(--tempest-text-subtle);\n animation: dotPulse 1.2s var(--tempest-ease-in-out) infinite;\n}\n\n.dots > span:nth-child(2) {\n animation-delay: 0.15s;\n}\n\n.dots > span:nth-child(3) {\n animation-delay: 0.3s;\n}\n\n@keyframes dotPulse {\n 0%,\n 60%,\n 100% {\n opacity: 0.25;\n }\n\n 30% {\n opacity: 1;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dots > span {\n animation: none;\n opacity: 0.6;\n }\n}\n\n.thinking {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin: 0 auto;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n\n/* --- reasoning ------------------------------------------------------------- */\n\n.reasoning {\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n}\n\n/*\n * Class plus attribute, so this beats `Collapsible`'s own single-class `.trigger`\n * rule whatever order the two modules land in the built stylesheet.\n */\n.reasoning button[aria-expanded] {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-medium);\n}\n\n.reasoning button[aria-expanded=\"true\"] .reasoningChevron {\n transform: rotate(90deg);\n}\n\n.reasoningChevron {\n flex: 0 0 auto;\n transition: transform var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .reasoningChevron {\n transition: none;\n }\n}\n\n.reasoningBody {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n line-height: var(--tempest-leading-relaxed);\n white-space: pre-wrap;\n}\n\n/* --- attachments ----------------------------------------------------------- */\n\n.attachments {\n display: flex;\n flex-wrap: wrap;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.attachment {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-2);\n max-width: 16rem;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n font-size: var(--tempest-text-xs);\n}\n\n.attachmentName {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.attachmentMeta {\n flex: 0 0 auto;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.thumb {\n display: block;\n width: 4rem;\n height: 4rem;\n border-radius: var(--tempest-radius-sm);\n object-fit: cover;\n}\n\n/* --- error ----------------------------------------------------------------- */\n\n.error {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-danger);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-danger-bg);\n color: var(--tempest-text);\n font-size: var(--tempest-text-sm);\n}\n\n.retry {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-danger);\n font: inherit;\n font-weight: var(--tempest-weight-medium);\n text-decoration: underline;\n cursor: pointer;\n}\n\n/* --- actions --------------------------------------------------------------- */\n\n.actions {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n opacity: 0;\n transition: opacity var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n/*\n * The row is revealed on hover and on keyboard focus, and is **always** visible\n * where there is no hover at all.\n *\n * Hiding a control behind `:hover` on a touch screen hides it for good — there is no\n * hover event to trigger it, and the first tap would land on whatever is underneath.\n */\n.turn:hover .actions,\n.actions:focus-within {\n opacity: 1;\n}\n\n@media (hover: none) {\n .actions {\n opacity: 1;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .actions {\n transition: none;\n }\n}\n\n/*\n * Two classes so the ghost styling wins over `CopyButton`'s own `.button` rule\n * regardless of the order the two CSS modules land in `styles.css`.\n */\n.actions .action {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-sm);\n background: none;\n color: var(--tempest-text-muted);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n/*\n * Touch hit-slop — grows the tap target to 44×44 on a coarse pointer without moving\n * a pixel of the visible button, the same trick `Button` uses for its icon-only\n * sizes.\n *\n * 28×28 clears the 24×24 floor of WCAG 2.5.8 but sits well under the 44×44 of 2.5.5,\n * and four of these sit side by side: on a phone, \"copy\" and \"thumbs down\" are two\n * thumb-widths apart. Padding the button instead would space the row out on desktop,\n * where the pointer is precise and the row should stay quiet.\n */\n@media (pointer: coarse) {\n .actions .action::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n .actions .action:hover {\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n }\n}\n\n.actions .action:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 1px;\n}\n\n.actions .action[data-copied],\n.actions .actionActive {\n background: none;\n color: var(--tempest-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .actions .action {\n transition: none;\n }\n}\n\n/* --- edit ------------------------------------------------------------------ */\n\n.editor {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-2);\n width: 100%;\n max-width: min(85%, 36rem);\n}\n\n.editField {\n width: 100%;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-primary);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: vertical;\n}\n\n.editField:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -1px;\n}\n\n.editActions {\n display: flex;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n}\n\n.ghost {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: transparent;\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n}\n\n.primary {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.primary:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n/* --- suggestions ----------------------------------------------------------- */\n\n.suggestions {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--tempest-space-2);\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin: auto auto 0;\n}\n\n.suggestionsTitle {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n\n.suggestion {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n text-align: left;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .suggestion:hover {\n background-color: var(--tempest-surface-2);\n }\n}\n\n.suggestion:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n\n/* --- composer -------------------------------------------------------------- */\n\n.composer {\n display: flex;\n flex: 0 0 auto;\n flex-direction: column;\n gap: var(--tempest-space-1);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-top: 1px solid var(--tempest-border);\n}\n\n/*\n * The field and the buttons share one bordered box, and the border is drawn here\n * rather than on the textarea: that is what makes the attach control and the send\n * button read as part of the prompt instead of a toolbar next to it.\n */\n.composerBox {\n display: flex;\n align-items: flex-end;\n gap: var(--tempest-space-2);\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin-inline: auto;\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n}\n\n.composerBox:focus-within {\n border-color: var(--tempest-primary);\n}\n\n.field {\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: none;\n}\n\n.field:focus-visible {\n outline: none;\n}\n\n.field:disabled {\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.composerActions {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.composerFooter {\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin-inline: auto;\n padding-inline: var(--tempest-space-2);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.send {\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.send:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n/*\n * Stop replaces send in the same slot, so the one button under the thumb is always\n * the one that does the thing you want next — send while idle, abort while the answer\n * is coming. Two buttons side by side would mean aiming at the right one mid-stream.\n */\n.stop {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.stopGlyph {\n display: inline-block;\n width: 0.625rem;\n height: 0.625rem;\n border-radius: 2px;\n background-color: currentColor;\n}\n\n@media (max-width: 480px) {\n .thread {\n gap: var(--tempest-space-4);\n padding: var(--tempest-space-3);\n }\n\n .userTurn .body,\n .editor {\n max-width: 100%;\n }\n\n .composer {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n }\n}\n"],"mappings":";"}
|
|
1
|
+
{"version":3,"file":"AIChat.module.js","names":[],"sources":["../../../src/components/AIChat/AIChat.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n height: var(--tempest-ai-chat-height, 100%);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n flex: 0 0 auto;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n/*\n * The wrapper exists only so the jump-to-latest button can be positioned against\n * the scroll area without being scrolled away with it.\n */\n.threadWrapper {\n position: relative;\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n}\n\n/*\n * `min-width: 0` is load-bearing, not defensive.\n *\n * A flex item defaults to `min-width: auto`, which means \"at least as wide as my\n * content wants\". An answer carrying a wide table or a long line of SQL would make\n * the scroll area itself grow past the panel — and the table's own `overflow-x`\n * inside `Markdown` never gets a chance to kick in, because it is already as wide as\n * it asked to be. Zeroing the floor here is what pushes the overflow back down to\n * the table and the code block, where it scrolls in its own box.\n */\n.thread {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--tempest-space-5);\n min-width: 0;\n min-height: 0;\n padding: var(--tempest-space-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.thread:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.jump {\n position: absolute;\n right: var(--tempest-space-4);\n bottom: var(--tempest-space-3);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n padding: 0;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n box-shadow: var(--tempest-shadow-md);\n cursor: pointer;\n}\n\n.jump:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n\n/* Same 44×44 hit-slop as the turn actions: 2rem is a small target for a thumb. */\n@media (pointer: coarse) {\n .jump::after {\n content: \"\";\n position: absolute;\n inset: -6px;\n }\n}\n\n/* --- turn ------------------------------------------------------------------ */\n\n/*\n * Turns, the thinking row, the suggestions and the composer all share one reading\n * column — `--tempest-ai-chat-width`, 48rem by default — centred in whatever width\n * the panel got.\n *\n * A capped column is the right answer from a phone up to a 1920 desktop: prose past\n * roughly 90 characters per line is measurably harder to track back to the start of\n * the next line, and letting an answer run the full width of a wide monitor makes it\n * worse, not more useful. It is deliberately a **knob** rather than a constant\n * because at 2560 and above the trade flips — a 768px ribbon in the middle of a\n * living-room screen is mostly empty room, and only the app knows how far away its\n * user is sitting. Widen it at the root: `--tempest-ai-chat-width: 72rem`.\n *\n * Type size is **not** solved here. Scaling the font for a TV is a decision for\n * `typography.css` and `density.css` — a component-local font ramp would fight the\n * tokens every app themes through.\n */\n.turn {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-2);\n min-width: 0;\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin-inline: auto;\n}\n\n/*\n * An assistant turn is full width with no bubble, a user turn is a narrow bubble\n * pushed to the end of the row.\n *\n * That asymmetry is the whole reading model of an LLM transcript: the answer is the\n * document being read, and wrapping it in a bubble would cap its width, fight the\n * code blocks and tables inside it, and make a long answer look like a shouted\n * message. The prompt is short and needs to be told apart at a glance, which a\n * bubble does better than anything else.\n */\n.userTurn {\n align-items: flex-end;\n}\n\n.systemTurn {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px dashed var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n\n.turnHeader {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n min-width: 0;\n}\n\n.avatar {\n display: inline-flex;\n flex: 0 0 auto;\n}\n\n.role {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-semibold);\n}\n\n/*\n * The role of a user turn is announced but not drawn: the bubble on the other side\n * already says who wrote it, and a \"Você\" label over every prompt is noise. Screen\n * readers still get it, because side and colour are not information for them.\n */\n.visuallyHiddenRole {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n border: 0;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/*\n * The meta row uses the muted token, not the subtle one.\n *\n * `--tempest-text-subtle` at `--tempest-text-2xs` measures **4.37:1** against\n * `--tempest-bg` in the dark theme — under the 4.5:1 floor for text. Measured in a\n * real browser; jsdom's `axe` turns `color-contrast` off because nothing is painted.\n * Size is what de-emphasises this row; colour still has to pass.\n */\n.model,\n.time {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.body {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.userTurn .body {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n max-width: min(85%, 36rem);\n}\n\n.plain {\n white-space: pre-wrap;\n}\n\n.markdownRoot {\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-relaxed);\n}\n\n/*\n * The caret rides the last block of the answer, so it sits at the end of the text\n * instead of on a line of its own.\n *\n * `::after` on the final child is inline content, which is exactly the behaviour\n * wanted: it flows after the last word and moves with it as more text arrives. When\n * the answer starts with a fenced block the caret lands inside the code area — which\n * is where the text is actually being appended, so it is still telling the truth.\n */\n.streamingBody > .markdownRoot > :last-child::after {\n content: \"▍\";\n margin-left: 0.125em;\n color: var(--tempest-primary);\n animation: caretBlink 1s steps(2, jump-none) infinite;\n}\n\n@keyframes caretBlink {\n to {\n opacity: 0.2;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .streamingBody > .markdownRoot > :last-child::after {\n animation: none;\n }\n}\n\n.dots {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n}\n\n.dots > span {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background-color: var(--tempest-text-subtle);\n animation: dotPulse 1.2s var(--tempest-ease-in-out) infinite;\n}\n\n.dots > span:nth-child(2) {\n animation-delay: 0.15s;\n}\n\n.dots > span:nth-child(3) {\n animation-delay: 0.3s;\n}\n\n@keyframes dotPulse {\n 0%,\n 60%,\n 100% {\n opacity: 0.25;\n }\n\n 30% {\n opacity: 1;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dots > span {\n animation: none;\n opacity: 0.6;\n }\n}\n\n.thinking {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin: 0 auto;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n\n/* --- reasoning ------------------------------------------------------------- */\n\n.reasoning {\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n}\n\n/*\n * Class plus attribute, so this beats `Collapsible`'s own single-class `.trigger`\n * rule whatever order the two modules land in the built stylesheet.\n */\n.reasoning button[aria-expanded] {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-medium);\n}\n\n.reasoning button[aria-expanded=\"true\"] .reasoningChevron {\n transform: rotate(90deg);\n}\n\n.reasoningChevron {\n flex: 0 0 auto;\n transition: transform var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .reasoningChevron {\n transition: none;\n }\n}\n\n.reasoningBody {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n line-height: var(--tempest-leading-relaxed);\n white-space: pre-wrap;\n}\n\n/* --- attachments ----------------------------------------------------------- */\n\n.attachments {\n display: flex;\n flex-wrap: wrap;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.attachment {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-2);\n max-width: 16rem;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n font-size: var(--tempest-text-xs);\n}\n\n.attachmentName {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.attachmentMeta {\n flex: 0 0 auto;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.thumb {\n display: block;\n width: 4rem;\n height: 4rem;\n border-radius: var(--tempest-radius-sm);\n object-fit: cover;\n}\n\n/* --- error ----------------------------------------------------------------- */\n\n.error {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-danger);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-danger-bg);\n color: var(--tempest-text);\n font-size: var(--tempest-text-sm);\n}\n\n.retry {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-danger);\n font: inherit;\n font-weight: var(--tempest-weight-medium);\n text-decoration: underline;\n cursor: pointer;\n}\n\n/* --- actions --------------------------------------------------------------- */\n\n.actions {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n opacity: 0;\n transition: opacity var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n/*\n * The row is revealed on hover and on keyboard focus, and is **always** visible\n * where there is no hover at all.\n *\n * Hiding a control behind `:hover` on a touch screen hides it for good — there is no\n * hover event to trigger it, and the first tap would land on whatever is underneath.\n */\n.turn:hover .actions,\n.actions:focus-within {\n opacity: 1;\n}\n\n@media (hover: none) {\n .actions {\n opacity: 1;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .actions {\n transition: none;\n }\n}\n\n/*\n * Two classes so the ghost styling wins over `CopyButton`'s own `.button` rule\n * regardless of the order the two CSS modules land in `styles.css`.\n */\n.actions .action {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-sm);\n background: none;\n color: var(--tempest-text-muted);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n/*\n * Touch hit-slop — grows the tap target to 44×44 on a coarse pointer without moving\n * a pixel of the visible button, the same trick `Button` uses for its icon-only\n * sizes.\n *\n * 28×28 clears the 24×24 floor of WCAG 2.5.8 but sits well under the 44×44 of 2.5.5,\n * and four of these sit side by side: on a phone, \"copy\" and \"thumbs down\" are two\n * thumb-widths apart. Padding the button instead would space the row out on desktop,\n * where the pointer is precise and the row should stay quiet.\n */\n@media (pointer: coarse) {\n .actions .action::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n .actions .action:hover {\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n }\n}\n\n.actions .action:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 1px;\n}\n\n.actions .action[data-copied],\n.actions .actionActive {\n background: none;\n color: var(--tempest-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .actions .action {\n transition: none;\n }\n}\n\n/* --- edit ------------------------------------------------------------------ */\n\n.editor {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-2);\n width: 100%;\n max-width: min(85%, 36rem);\n}\n\n.editField {\n width: 100%;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-primary);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: vertical;\n}\n\n.editField:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.editActions {\n display: flex;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n}\n\n.ghost {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: transparent;\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n cursor: pointer;\n}\n\n.primary {\n padding: var(--tempest-space-1) var(--tempest-space-3);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.primary:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n/* --- suggestions ----------------------------------------------------------- */\n\n.suggestions {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--tempest-space-2);\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin: auto auto 0;\n}\n\n.suggestionsTitle {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n\n.suggestion {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n text-align: left;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .suggestion:hover {\n background-color: var(--tempest-surface-2);\n }\n}\n\n.suggestion:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n\n/* --- composer -------------------------------------------------------------- */\n\n.composer {\n display: flex;\n flex: 0 0 auto;\n flex-direction: column;\n gap: var(--tempest-space-1);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-top: 1px solid var(--tempest-border);\n}\n\n/*\n * The field and the buttons share one bordered box, and the border is drawn here\n * rather than on the textarea: that is what makes the attach control and the send\n * button read as part of the prompt instead of a toolbar next to it.\n */\n.composerBox {\n display: flex;\n align-items: flex-end;\n gap: var(--tempest-space-2);\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin-inline: auto;\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n}\n\n.composerBox:focus-within {\n border-color: var(--tempest-primary);\n box-shadow: 0 0 0 var(--tempest-focus-ring-width) var(--tempest-focus-ring-color);\n}\n\n.field {\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: none;\n}\n\n.field:focus-visible {\n outline: none;\n}\n\n.field:disabled {\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.composerActions {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.composerFooter {\n max-width: var(--tempest-ai-chat-width, 48rem);\n width: 100%;\n margin-inline: auto;\n padding-inline: var(--tempest-space-2);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.send {\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.send:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n/*\n * Stop replaces send in the same slot, so the one button under the thumb is always\n * the one that does the thing you want next — send while idle, abort while the answer\n * is coming. Two buttons side by side would mean aiming at the right one mid-stream.\n */\n.stop {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.stopGlyph {\n display: inline-block;\n width: 0.625rem;\n height: 0.625rem;\n border-radius: 2px;\n background-color: currentColor;\n}\n\n@media (max-width: 480px) {\n .thread {\n gap: var(--tempest-space-4);\n padding: var(--tempest-space-3);\n }\n\n .userTurn .body,\n .editor {\n max-width: 100%;\n }\n\n .composer {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n }\n}\n"],"mappings":";"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../utils/cn.cjs"),t=require("./use-sticky-body-warning.cjs"),n=require("./AppBar.module.cjs");let r=require("react/jsx-runtime"),i=require("lucide-react");function a({title:a,leading:o,showBack:s=!1,onBack:c,backLabel:l=`Go back`,backIcon:u,brand:d,actions:f,centered:p=!1,sticky:m=!0,tone:h=`surface`,bordered:g=!0,safeArea:_=!0,className:v,...y}){t.useStickyBodyWarning(m);let b=c??(()=>window.history.back()),x=o??(0,r.jsxs)(r.Fragment,{children:[s&&(0,r.jsx)(`button`,{type:`button`,className:n.default.iconBtn,onClick:b,"aria-label":l,children:u??(0,r.jsx)(i.ArrowLeft,{size:22,"aria-hidden":`true`})}),d&&(0,r.jsx)(`span`,{className:n.default.brand,children:d})]});return(0,r.jsxs)(`header`,{className:e.cn(n.default.bar,n.default[h],p&&n.default.centered,m&&n.default.sticky,g&&n.default.bordered,_&&n.default.safeArea,v),...y,children:[(0,r.jsx)(`div`,{className:n.default.leading,children:x}),a!=null&&a!==``&&(0,r.jsx)(`h1`,{className:n.default.title,"aria-live":`polite`,children:a}),(0,r.jsx)(`div`,{className:n.default.actions,children:f})]})}exports.AppBar=a;
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("./use-sticky-body-warning.cjs"),n=require("./AppBar.module.cjs");let r=require("react/jsx-runtime"),i=require("lucide-react");function a({title:a,leading:o,showBack:s=!1,onBack:c,backLabel:l=`Go back`,backIcon:u,brand:d,actions:f,centered:p=!1,sticky:m=!0,tone:h=`surface`,bordered:g=!0,safeArea:_=!0,className:v,...y}){t.useStickyBodyWarning(m);let b=c??(()=>window.history.back()),x=o??(0,r.jsxs)(r.Fragment,{children:[s&&(0,r.jsx)(`button`,{type:`button`,className:n.default.iconBtn,onClick:b,"aria-label":l,children:u??(0,r.jsx)(i.ArrowLeft,{size:22,"aria-hidden":`true`})}),d&&(0,r.jsx)(`span`,{className:n.default.brand,children:d})]});return(0,r.jsxs)(`header`,{className:e.cn(n.default.bar,n.default[h],p&&n.default.centered,m&&n.default.sticky,g&&n.default.bordered,_&&n.default.safeArea,v),"data-tempest-tone":h===`inverse`?`inverse`:void 0,...y,children:[(0,r.jsx)(`div`,{className:n.default.leading,children:x}),a!=null&&a!==``&&(0,r.jsx)(`h1`,{className:n.default.title,"aria-live":`polite`,children:a}),(0,r.jsx)(`div`,{className:n.default.actions,children:f})]})}exports.AppBar=a;
|
|
2
2
|
//# sourceMappingURL=AppBar.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppBar.cjs","names":[],"sources":["../../../src/components/AppBar/AppBar.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a top bar is a slot layout: leading (leading,\n * showBack, onBack, backLabel, backIcon, brand), centre (title, centered) and\n * trailing (actions), plus the chrome it sits in (sticky, tone, bordered, safeArea).\n * Every one of those is a real decision an app makes per screen, and the alternative\n * to accepting them is the app rebuilding the bar around the parts it wanted to\n * change.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useStickyBodyWarning } from \"./use-sticky-body-warning\";\nimport styles from \"./AppBar.module.css\";\n\nexport type AppBarTone = \"surface\" | \"primary\" | \"transparent\";\n\nexport interface AppBarProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title — string or any node. Rendered as the bar's `<h1>`. */\n title?: ReactNode;\n /**\n * Replace the whole left slot. When set, the auto back button and `brand`\n * are ignored — you own the leading content.\n */\n leading?: ReactNode;\n /** Show a back button in the left slot. Ignored when `leading` is set. */\n showBack?: boolean;\n /**\n * Back-button handler. Defaults to `window.history.back()`. With a router,\n * pass `onBack={() => navigate(-1)}`.\n */\n onBack?: () => void;\n /** Accessible label for the back button. Default `\"Go back\"`. */\n backLabel?: string;\n /** Custom back icon. Default a left arrow. */\n backIcon?: ReactNode;\n /** Brand / logo node shown in the left slot (after the back button). */\n brand?: ReactNode;\n /** Right slot — action buttons / menu. One node or many. */\n actions?: ReactNode;\n /** Center the title (three-column grid). Default `false` (left-aligned). */\n centered?: boolean;\n /**\n * Stick to the top of the scroll container. Default `true`.\n *\n * The page has to leave the body out of the scrolling: `body { overflow-x:\n * hidden }` makes the body a scroll container and the bar scrolls away with\n * the content. Use `overflow-x: clip` on `html` and `body` instead — in\n * development the bar says so in the console when it detects it.\n */\n sticky?: boolean;\n
|
|
1
|
+
{"version":3,"file":"AppBar.cjs","names":[],"sources":["../../../src/components/AppBar/AppBar.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a top bar is a slot layout: leading (leading,\n * showBack, onBack, backLabel, backIcon, brand), centre (title, centered) and\n * trailing (actions), plus the chrome it sits in (sticky, tone, bordered, safeArea).\n * Every one of those is a real decision an app makes per screen, and the alternative\n * to accepting them is the app rebuilding the bar around the parts it wanted to\n * change.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useStickyBodyWarning } from \"./use-sticky-body-warning\";\nimport styles from \"./AppBar.module.css\";\n\n/**\n * Visual tone of an {@link AppBar}.\n *\n * - `\"surface\"` — the page's surface and text.\n * - `\"primary\"` — the brand fill (`--tempest-primary`) with\n * `--tempest-primary-foreground` ink. Only the bar's own text and back button\n * follow the fill: components in `actions` keep the page's tokens. Measured in\n * Chromium over the SDK's `#0066ff`, a primary `Button` inside it has the same\n * color as the bar (1:1) and its focus ring reads 1.41:1.\n * - `\"inverse\"` — the inverse surface: every color token inverted inside the bar,\n * so the components in it are measured against the fill. See\n * {@link AppBarProps.tone}.\n * - `\"transparent\"` — no background; the text inherits.\n */\nexport type AppBarTone = \"surface\" | \"primary\" | \"inverse\" | \"transparent\";\n\nexport interface AppBarProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title — string or any node. Rendered as the bar's `<h1>`. */\n title?: ReactNode;\n /**\n * Replace the whole left slot. When set, the auto back button and `brand`\n * are ignored — you own the leading content.\n */\n leading?: ReactNode;\n /** Show a back button in the left slot. Ignored when `leading` is set. */\n showBack?: boolean;\n /**\n * Back-button handler. Defaults to `window.history.back()`. With a router,\n * pass `onBack={() => navigate(-1)}`.\n */\n onBack?: () => void;\n /** Accessible label for the back button. Default `\"Go back\"`. */\n backLabel?: string;\n /** Custom back icon. Default a left arrow. */\n backIcon?: ReactNode;\n /** Brand / logo node shown in the left slot (after the back button). */\n brand?: ReactNode;\n /** Right slot — action buttons / menu. One node or many. */\n actions?: ReactNode;\n /** Center the title (three-column grid). Default `false` (left-aligned). */\n centered?: boolean;\n /**\n * Stick to the top of the scroll container. Default `true`.\n *\n * The page has to leave the body out of the scrolling: `body { overflow-x:\n * hidden }` makes the body a scroll container and the bar scrolls away with\n * the content. Use `overflow-x: clip` on `html` and `body` instead — in\n * development the bar says so in the console when it detects it.\n */\n sticky?: boolean;\n /**\n * Visual tone. Default `\"surface\"`.\n *\n * `\"inverse\"` writes `data-tempest-tone=\"inverse\"` and paints the bar with the\n * inverse surface's `--tempest-bg`, so the back button, the title and the\n * components in `actions` invert with it. The tokens are opt-in:\n * `tempest-react-sdk/styles/inverse.css` for the SDK's own blue, or\n * `createTheme({ primary, inverse: createInverseSurface })` for yours. With\n * neither loaded the bar falls back to the page's `--tempest-bg` and\n * `--tempest-text` — legible, not inverted.\n *\n * A separate tone rather than a change to `\"primary\"`, because the inverse\n * fill is not always the brand's `500`: for `#0066ff` it is the `800`\n * (`#042e75`), and turning `\"primary\"` into it would repaint every bar that\n * uses it today.\n */\n tone?: AppBarTone;\n /** Thin bottom border. Default `true`. */\n bordered?: boolean;\n /** Add `env(safe-area-inset-top)` padding (iOS notch / PWA). Default `true`. */\n safeArea?: boolean;\n}\n\n/**\n * Mobile-first top app bar for PWAs — leading (back / brand) + title +\n * trailing actions, sticky with safe-area padding out of the box.\n *\n * Consumers customise via tokens (`--tempest-*`) and slots; the SDK ships the\n * layout, sticky/safe-area behaviour, and accessible back button so apps don't\n * hand-roll one per screen. For a desktop three-slot nav use [[Navbar]].\n *\n * @example\n * // Detail screen with back + a trailing action\n * <AppBar\n * title=\"Profile\"\n * showBack\n * onBack={() => navigate(-1)}\n * actions={<IconButton icon={<Settings />} onClick={openSettings} />}\n * />\n *\n * @example\n * // Home screen — brand left, centered title disabled\n * <AppBar brand={<Logo />} actions={<UserMenu />} />\n */\nexport function AppBar({\n title,\n leading,\n showBack = false,\n onBack,\n backLabel = \"Go back\",\n backIcon,\n brand,\n actions,\n centered = false,\n sticky = true,\n tone = \"surface\",\n bordered = true,\n safeArea = true,\n className,\n ...props\n}: AppBarProps) {\n useStickyBodyWarning(sticky);\n\n const handleBack = onBack ?? (() => window.history.back());\n\n const leadingContent = leading ?? (\n <>\n {showBack && (\n <button\n type=\"button\"\n className={styles.iconBtn}\n onClick={handleBack}\n aria-label={backLabel}\n >\n {backIcon ?? <ArrowLeft size={22} aria-hidden=\"true\" />}\n </button>\n )}\n {brand && <span className={styles.brand}>{brand}</span>}\n </>\n );\n\n return (\n <header\n className={cn(\n styles.bar,\n styles[tone],\n centered && styles.centered,\n sticky && styles.sticky,\n bordered && styles.bordered,\n safeArea && styles.safeArea,\n className,\n )}\n data-tempest-tone={tone === \"inverse\" ? \"inverse\" : undefined}\n {...props}\n >\n <div className={styles.leading}>{leadingContent}</div>\n {title != null && title !== \"\" && (\n <h1 className={styles.title} aria-live=\"polite\">\n {title}\n </h1>\n )}\n <div className={styles.actions}>{actions}</div>\n </header>\n );\n}\n"],"mappings":"+KA4GA,SAAgB,EAAO,CACnB,QACA,UACA,WAAW,GACX,SACA,YAAY,UACZ,WACA,QACA,UACA,WAAW,GACX,SAAS,GACT,OAAO,UACP,WAAW,GACX,WAAW,GACX,YACA,GAAG,GACS,CACZ,EAAA,qBAAqB,CAAM,EAE3B,IAAM,EAAa,QAAiB,OAAO,QAAQ,KAAK,GAElD,EAAiB,IACnB,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,CACK,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,QAAS,EACT,aAAY,EAEX,SAAA,IAAY,EAAA,EAAA,IAAA,CAAC,EAAA,UAAD,CAAW,KAAM,GAAI,cAAY,MAAQ,CAAA,CAClD,CAAA,EAEX,IAAS,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAY,CAAA,CACxD,CAAA,CAAA,EAGN,OACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,UAAW,EAAA,GACP,EAAA,QAAO,IACP,EAAA,QAAO,GACP,GAAY,EAAA,QAAO,SACnB,GAAU,EAAA,QAAO,OACjB,GAAY,EAAA,QAAO,SACnB,GAAY,EAAA,QAAO,SACnB,CACJ,EACA,oBAAmB,IAAS,UAAY,UAAY,IAAA,GACpD,GAAI,EAXR,SAAA,EAaI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,SAAA,CAAoB,CAAA,EACpD,GAAS,MAAQ,IAAU,KACxB,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,MAAO,YAAU,SAClC,SAAA,CACD,CAAA,GAER,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,SAAA,CAAa,CAAA,CAC1C,GAEhB"}
|
|
@@ -21,6 +21,7 @@ function s({ title: s, leading: c, showBack: l = !1, onBack: u, backLabel: d = "
|
|
|
21
21
|
})] });
|
|
22
22
|
return /* @__PURE__ */ a("header", {
|
|
23
23
|
className: e(n.bar, n[_], h && n.centered, g && n.sticky, v && n.bordered, y && n.safeArea, b),
|
|
24
|
+
"data-tempest-tone": _ === "inverse" ? "inverse" : void 0,
|
|
24
25
|
...x,
|
|
25
26
|
children: [
|
|
26
27
|
/* @__PURE__ */ i("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppBar.js","names":[],"sources":["../../../src/components/AppBar/AppBar.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a top bar is a slot layout: leading (leading,\n * showBack, onBack, backLabel, backIcon, brand), centre (title, centered) and\n * trailing (actions), plus the chrome it sits in (sticky, tone, bordered, safeArea).\n * Every one of those is a real decision an app makes per screen, and the alternative\n * to accepting them is the app rebuilding the bar around the parts it wanted to\n * change.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useStickyBodyWarning } from \"./use-sticky-body-warning\";\nimport styles from \"./AppBar.module.css\";\n\nexport type AppBarTone = \"surface\" | \"primary\" | \"transparent\";\n\nexport interface AppBarProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title — string or any node. Rendered as the bar's `<h1>`. */\n title?: ReactNode;\n /**\n * Replace the whole left slot. When set, the auto back button and `brand`\n * are ignored — you own the leading content.\n */\n leading?: ReactNode;\n /** Show a back button in the left slot. Ignored when `leading` is set. */\n showBack?: boolean;\n /**\n * Back-button handler. Defaults to `window.history.back()`. With a router,\n * pass `onBack={() => navigate(-1)}`.\n */\n onBack?: () => void;\n /** Accessible label for the back button. Default `\"Go back\"`. */\n backLabel?: string;\n /** Custom back icon. Default a left arrow. */\n backIcon?: ReactNode;\n /** Brand / logo node shown in the left slot (after the back button). */\n brand?: ReactNode;\n /** Right slot — action buttons / menu. One node or many. */\n actions?: ReactNode;\n /** Center the title (three-column grid). Default `false` (left-aligned). */\n centered?: boolean;\n /**\n * Stick to the top of the scroll container. Default `true`.\n *\n * The page has to leave the body out of the scrolling: `body { overflow-x:\n * hidden }` makes the body a scroll container and the bar scrolls away with\n * the content. Use `overflow-x: clip` on `html` and `body` instead — in\n * development the bar says so in the console when it detects it.\n */\n sticky?: boolean;\n
|
|
1
|
+
{"version":3,"file":"AppBar.js","names":[],"sources":["../../../src/components/AppBar/AppBar.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a top bar is a slot layout: leading (leading,\n * showBack, onBack, backLabel, backIcon, brand), centre (title, centered) and\n * trailing (actions), plus the chrome it sits in (sticky, tone, bordered, safeArea).\n * Every one of those is a real decision an app makes per screen, and the alternative\n * to accepting them is the app rebuilding the bar around the parts it wanted to\n * change.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useStickyBodyWarning } from \"./use-sticky-body-warning\";\nimport styles from \"./AppBar.module.css\";\n\n/**\n * Visual tone of an {@link AppBar}.\n *\n * - `\"surface\"` — the page's surface and text.\n * - `\"primary\"` — the brand fill (`--tempest-primary`) with\n * `--tempest-primary-foreground` ink. Only the bar's own text and back button\n * follow the fill: components in `actions` keep the page's tokens. Measured in\n * Chromium over the SDK's `#0066ff`, a primary `Button` inside it has the same\n * color as the bar (1:1) and its focus ring reads 1.41:1.\n * - `\"inverse\"` — the inverse surface: every color token inverted inside the bar,\n * so the components in it are measured against the fill. See\n * {@link AppBarProps.tone}.\n * - `\"transparent\"` — no background; the text inherits.\n */\nexport type AppBarTone = \"surface\" | \"primary\" | \"inverse\" | \"transparent\";\n\nexport interface AppBarProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title — string or any node. Rendered as the bar's `<h1>`. */\n title?: ReactNode;\n /**\n * Replace the whole left slot. When set, the auto back button and `brand`\n * are ignored — you own the leading content.\n */\n leading?: ReactNode;\n /** Show a back button in the left slot. Ignored when `leading` is set. */\n showBack?: boolean;\n /**\n * Back-button handler. Defaults to `window.history.back()`. With a router,\n * pass `onBack={() => navigate(-1)}`.\n */\n onBack?: () => void;\n /** Accessible label for the back button. Default `\"Go back\"`. */\n backLabel?: string;\n /** Custom back icon. Default a left arrow. */\n backIcon?: ReactNode;\n /** Brand / logo node shown in the left slot (after the back button). */\n brand?: ReactNode;\n /** Right slot — action buttons / menu. One node or many. */\n actions?: ReactNode;\n /** Center the title (three-column grid). Default `false` (left-aligned). */\n centered?: boolean;\n /**\n * Stick to the top of the scroll container. Default `true`.\n *\n * The page has to leave the body out of the scrolling: `body { overflow-x:\n * hidden }` makes the body a scroll container and the bar scrolls away with\n * the content. Use `overflow-x: clip` on `html` and `body` instead — in\n * development the bar says so in the console when it detects it.\n */\n sticky?: boolean;\n /**\n * Visual tone. Default `\"surface\"`.\n *\n * `\"inverse\"` writes `data-tempest-tone=\"inverse\"` and paints the bar with the\n * inverse surface's `--tempest-bg`, so the back button, the title and the\n * components in `actions` invert with it. The tokens are opt-in:\n * `tempest-react-sdk/styles/inverse.css` for the SDK's own blue, or\n * `createTheme({ primary, inverse: createInverseSurface })` for yours. With\n * neither loaded the bar falls back to the page's `--tempest-bg` and\n * `--tempest-text` — legible, not inverted.\n *\n * A separate tone rather than a change to `\"primary\"`, because the inverse\n * fill is not always the brand's `500`: for `#0066ff` it is the `800`\n * (`#042e75`), and turning `\"primary\"` into it would repaint every bar that\n * uses it today.\n */\n tone?: AppBarTone;\n /** Thin bottom border. Default `true`. */\n bordered?: boolean;\n /** Add `env(safe-area-inset-top)` padding (iOS notch / PWA). Default `true`. */\n safeArea?: boolean;\n}\n\n/**\n * Mobile-first top app bar for PWAs — leading (back / brand) + title +\n * trailing actions, sticky with safe-area padding out of the box.\n *\n * Consumers customise via tokens (`--tempest-*`) and slots; the SDK ships the\n * layout, sticky/safe-area behaviour, and accessible back button so apps don't\n * hand-roll one per screen. For a desktop three-slot nav use [[Navbar]].\n *\n * @example\n * // Detail screen with back + a trailing action\n * <AppBar\n * title=\"Profile\"\n * showBack\n * onBack={() => navigate(-1)}\n * actions={<IconButton icon={<Settings />} onClick={openSettings} />}\n * />\n *\n * @example\n * // Home screen — brand left, centered title disabled\n * <AppBar brand={<Logo />} actions={<UserMenu />} />\n */\nexport function AppBar({\n title,\n leading,\n showBack = false,\n onBack,\n backLabel = \"Go back\",\n backIcon,\n brand,\n actions,\n centered = false,\n sticky = true,\n tone = \"surface\",\n bordered = true,\n safeArea = true,\n className,\n ...props\n}: AppBarProps) {\n useStickyBodyWarning(sticky);\n\n const handleBack = onBack ?? (() => window.history.back());\n\n const leadingContent = leading ?? (\n <>\n {showBack && (\n <button\n type=\"button\"\n className={styles.iconBtn}\n onClick={handleBack}\n aria-label={backLabel}\n >\n {backIcon ?? <ArrowLeft size={22} aria-hidden=\"true\" />}\n </button>\n )}\n {brand && <span className={styles.brand}>{brand}</span>}\n </>\n );\n\n return (\n <header\n className={cn(\n styles.bar,\n styles[tone],\n centered && styles.centered,\n sticky && styles.sticky,\n bordered && styles.bordered,\n safeArea && styles.safeArea,\n className,\n )}\n data-tempest-tone={tone === \"inverse\" ? \"inverse\" : undefined}\n {...props}\n >\n <div className={styles.leading}>{leadingContent}</div>\n {title != null && title !== \"\" && (\n <h1 className={styles.title} aria-live=\"polite\">\n {title}\n </h1>\n )}\n <div className={styles.actions}>{actions}</div>\n </header>\n );\n}\n"],"mappings":";;;;;;AA4GA,SAAgB,EAAO,EACnB,UACA,YACA,cAAW,IACX,WACA,eAAY,WACZ,aACA,UACA,YACA,cAAW,IACX,YAAS,IACT,UAAO,WACP,cAAW,IACX,cAAW,IACX,cACA,GAAG,KACS;CACZ,EAAqB,CAAM;CAE3B,IAAM,IAAa,YAAiB,OAAO,QAAQ,KAAK,IAElD,IAAiB,KACnB,kBAAA,GAAA,EAAA,UAAA,CACK,KACG,kBAAC,UAAD;EACI,MAAK;EACL,WAAW,EAAO;EAClB,SAAS;EACT,cAAY;EAEX,UAAA,KAAY,kBAAC,GAAD;GAAW,MAAM;GAAI,eAAY;EAAQ,CAAA;CAClD,CAAA,GAEX,KAAS,kBAAC,QAAD;EAAM,WAAW,EAAO;EAAQ,UAAA;CAAY,CAAA,CACxD,EAAA,CAAA;CAGN,OACI,kBAAC,UAAD;EACI,WAAW,EACP,EAAO,KACP,EAAO,IACP,KAAY,EAAO,UACnB,KAAU,EAAO,QACjB,KAAY,EAAO,UACnB,KAAY,EAAO,UACnB,CACJ;EACA,qBAAmB,MAAS,YAAY,YAAY,KAAA;EACpD,GAAI;EAXR,UAAA;GAaI,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAU,UAAA;GAAoB,CAAA;GACpD,KAAS,QAAQ,MAAU,MACxB,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAO,aAAU;IAClC,UAAA;GACD,CAAA;GAER,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAU,UAAA;GAAa,CAAA;EAC1C;;AAEhB"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
require("../../styles/component/AppBar.css");
|
|
2
|
-
var e=`tempest_bar_SHqWS`,t=`tempest_centered_S0CCw`,n=`tempest_surface_fusKb`,r=`tempest_primary_QcCyN`,i=`
|
|
2
|
+
var e=`tempest_bar_SHqWS`,t=`tempest_centered_S0CCw`,n=`tempest_surface_fusKb`,r=`tempest_primary_QcCyN`,i=`tempest_inverse_Icool`,a=`tempest_transparent_uGrsu`,o=`tempest_bordered_5M9FZ`,s=`tempest_sticky_DStUO`,c=`tempest_safeArea_Vo3Bi`,l=`tempest_leading_mXv-d`,u=`tempest_actions_x7tMx`,d=`tempest_title_qaMMQ`,f=`tempest_brand_xKt54`,p=`tempest_iconBtn_S-BTg`,m={bar:e,centered:t,surface:n,primary:r,inverse:i,transparent:a,bordered:o,sticky:s,safeArea:c,leading:l,actions:u,title:d,brand:f,iconBtn:p};exports.actions=u,exports.bar=e,exports.bordered=o,exports.brand=f,exports.centered=t,exports.default=m,exports.iconBtn=p,exports.inverse=i,exports.leading=l,exports.primary=r,exports.safeArea=c,exports.sticky=s,exports.surface=n,exports.title=d,exports.transparent=a;
|
|
3
3
|
//# sourceMappingURL=AppBar.module.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppBar.module.cjs","names":[],"sources":["../../../src/components/AppBar/AppBar.module.css"],"sourcesContent":[".bar {\n display: grid;\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--tempest-space-2);\n width: 100%;\n min-height: 56px;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n font-family: var(--tempest-font-sans);\n}\n\n/* Symmetric side columns so the title is truly centered. */\n.bar.centered {\n grid-template-columns: 1fr auto 1fr;\n}\n\n.bar.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.bar.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.bar.transparent {\n background: transparent;\n color: inherit;\n}\n\n.bar.bordered {\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.bar.sticky {\n position: sticky;\n top: 0;\n z-index: 30;\n}\n\n.bar.safeArea {\n padding-top: max(var(--tempest-space-3), env(safe-area-inset-top, 0px));\n}\n\n.leading {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n min-width: 0;\n}\n\n.actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-1);\n min-width: 0;\n}\n\n.title {\n margin: 0;\n min-width: 0;\n font-size: var(--tempest-text-xl);\n font-weight: var(--tempest-weight-bold);\n line-height: 1.2;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.bar.centered .title {\n text-align: center;\n}\n\n.brand {\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-bold);\n color: inherit;\n white-space: nowrap;\n}\n\n.iconBtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-full);\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n\n.iconBtn:hover {\n background: var(--tempest-surface-2);\n}\n\n.iconBtn:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n"],"mappings":";"}
|
|
1
|
+
{"version":3,"file":"AppBar.module.cjs","names":[],"sources":["../../../src/components/AppBar/AppBar.module.css"],"sourcesContent":[".bar {\n display: grid;\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--tempest-space-2);\n width: 100%;\n min-height: 56px;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n font-family: var(--tempest-font-sans);\n}\n\n/* Symmetric side columns so the title is truly centered. */\n.bar.centered {\n grid-template-columns: 1fr auto 1fr;\n}\n\n.bar.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.bar.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.bar.inverse {\n background: var(--tempest-bg);\n color: var(--tempest-text);\n}\n\n.bar.transparent {\n background: transparent;\n color: inherit;\n}\n\n.bar.bordered {\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.bar.sticky {\n position: sticky;\n top: 0;\n z-index: 30;\n}\n\n.bar.safeArea {\n padding-top: max(var(--tempest-space-3), env(safe-area-inset-top, 0px));\n}\n\n.leading {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n min-width: 0;\n}\n\n.actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-1);\n min-width: 0;\n}\n\n.title {\n margin: 0;\n min-width: 0;\n font-size: var(--tempest-text-xl);\n font-weight: var(--tempest-weight-bold);\n line-height: 1.2;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.bar.centered .title {\n text-align: center;\n}\n\n.brand {\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-bold);\n color: inherit;\n white-space: nowrap;\n}\n\n.iconBtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-full);\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n\n.iconBtn:hover {\n background: var(--tempest-surface-2);\n}\n\n.iconBtn:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n"],"mappings":";"}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import "../../styles/component/AppBar.css";
|
|
2
2
|
//#region src/components/AppBar/AppBar.module.css
|
|
3
|
-
var e = "tempest_bar_SHqWS", t = "tempest_centered_S0CCw", n = "tempest_surface_fusKb", r = "tempest_primary_QcCyN", i = "
|
|
3
|
+
var e = "tempest_bar_SHqWS", t = "tempest_centered_S0CCw", n = "tempest_surface_fusKb", r = "tempest_primary_QcCyN", i = "tempest_inverse_Icool", a = "tempest_transparent_uGrsu", o = "tempest_bordered_5M9FZ", s = "tempest_sticky_DStUO", c = "tempest_safeArea_Vo3Bi", l = "tempest_leading_mXv-d", u = "tempest_actions_x7tMx", d = "tempest_title_qaMMQ", f = "tempest_brand_xKt54", p = "tempest_iconBtn_S-BTg", m = {
|
|
4
4
|
bar: e,
|
|
5
5
|
centered: t,
|
|
6
6
|
surface: n,
|
|
7
7
|
primary: r,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
inverse: i,
|
|
9
|
+
transparent: a,
|
|
10
|
+
bordered: o,
|
|
11
|
+
sticky: s,
|
|
12
|
+
safeArea: c,
|
|
13
|
+
leading: l,
|
|
14
|
+
actions: u,
|
|
15
|
+
title: d,
|
|
16
|
+
brand: f,
|
|
17
|
+
iconBtn: p
|
|
17
18
|
};
|
|
18
19
|
//#endregion
|
|
19
|
-
export {
|
|
20
|
+
export { u as actions, e as bar, o as bordered, f as brand, t as centered, m as default, p as iconBtn, i as inverse, l as leading, r as primary, c as safeArea, s as sticky, n as surface, d as title, a as transparent };
|
|
20
21
|
|
|
21
22
|
//# sourceMappingURL=AppBar.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppBar.module.js","names":[],"sources":["../../../src/components/AppBar/AppBar.module.css"],"sourcesContent":[".bar {\n display: grid;\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--tempest-space-2);\n width: 100%;\n min-height: 56px;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n font-family: var(--tempest-font-sans);\n}\n\n/* Symmetric side columns so the title is truly centered. */\n.bar.centered {\n grid-template-columns: 1fr auto 1fr;\n}\n\n.bar.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.bar.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.bar.transparent {\n background: transparent;\n color: inherit;\n}\n\n.bar.bordered {\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.bar.sticky {\n position: sticky;\n top: 0;\n z-index: 30;\n}\n\n.bar.safeArea {\n padding-top: max(var(--tempest-space-3), env(safe-area-inset-top, 0px));\n}\n\n.leading {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n min-width: 0;\n}\n\n.actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-1);\n min-width: 0;\n}\n\n.title {\n margin: 0;\n min-width: 0;\n font-size: var(--tempest-text-xl);\n font-weight: var(--tempest-weight-bold);\n line-height: 1.2;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.bar.centered .title {\n text-align: center;\n}\n\n.brand {\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-bold);\n color: inherit;\n white-space: nowrap;\n}\n\n.iconBtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-full);\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n\n.iconBtn:hover {\n background: var(--tempest-surface-2);\n}\n\n.iconBtn:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n"],"mappings":";"}
|
|
1
|
+
{"version":3,"file":"AppBar.module.js","names":[],"sources":["../../../src/components/AppBar/AppBar.module.css"],"sourcesContent":[".bar {\n display: grid;\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--tempest-space-2);\n width: 100%;\n min-height: 56px;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n font-family: var(--tempest-font-sans);\n}\n\n/* Symmetric side columns so the title is truly centered. */\n.bar.centered {\n grid-template-columns: 1fr auto 1fr;\n}\n\n.bar.surface {\n background: var(--tempest-surface);\n color: var(--tempest-text);\n}\n\n.bar.primary {\n background: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.bar.inverse {\n background: var(--tempest-bg);\n color: var(--tempest-text);\n}\n\n.bar.transparent {\n background: transparent;\n color: inherit;\n}\n\n.bar.bordered {\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.bar.sticky {\n position: sticky;\n top: 0;\n z-index: 30;\n}\n\n.bar.safeArea {\n padding-top: max(var(--tempest-space-3), env(safe-area-inset-top, 0px));\n}\n\n.leading {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n min-width: 0;\n}\n\n.actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-1);\n min-width: 0;\n}\n\n.title {\n margin: 0;\n min-width: 0;\n font-size: var(--tempest-text-xl);\n font-weight: var(--tempest-weight-bold);\n line-height: 1.2;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.bar.centered .title {\n text-align: center;\n}\n\n.brand {\n font-size: var(--tempest-text-lg);\n font-weight: var(--tempest-weight-bold);\n color: inherit;\n white-space: nowrap;\n}\n\n.iconBtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-full);\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n\n.iconBtn:hover {\n background: var(--tempest-surface-2);\n}\n\n.iconBtn:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n"],"mappings":";"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.module.cjs","names":[],"sources":["../../../src/components/Button/Button.module.css"],"sourcesContent":[".button {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n border: 1px solid transparent;\n border-radius: var(--tempest-control-radius, var(--tempest-radius-md));\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-none);\n letter-spacing: var(--tempest-tracking-normal);\n color: var(--_tempest-button-fg);\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n transition: var(--tempest-transition-base);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n box-shadow: var(--tempest-shadow-sm);\n }\n}\n\n.button:active:not(:disabled, [aria-disabled=\"true\"]) {\n transform: translateY(1px);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:disabled,\n.button[aria-disabled=\"true\"] {\n opacity: 0.55;\n box-shadow: none;\n}\n\n.button[aria-disabled=\"true\"] {\n cursor: not-allowed;\n}\n\n/*\n * `<Button href>` and `<ButtonSlot>` around a link render an `<a>`, and an app's own link\n * rules reach it. `.button` is one class (0,1,0); `a:hover { color }` is (0,1,1) and\n * wins — the Vite React template ships exactly that rule, so in a fresh app a\n * primary link-button turned its label `#535bf2` on hover, over the primary fill.\n *\n * Each variant therefore sets its text colour as `--_tempest-button-fg` instead of\n * `color`, and this rule restates it on every link state at (0,2,1), above any\n * single-element link rule. The `link` variant's hover underline is (0,3,0) and\n * still applies.\n */\na.button:is(:link, :visited, :hover, :active, :focus, :not([href])) {\n color: var(--_tempest-button-fg);\n text-decoration: none;\n}\n\n/* ============================================================\n * Variants — solid (default), soft, outline, ghost\n * Status colors: primary, secondary (neutral), danger, success\n * ============================================================ */\n\n/* primary — solid filled */\n.primary {\n background-color: var(--tempest-primary);\n --_tempest-button-fg: var(--tempest-primary-foreground);\n}\n.primary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-hover);\n}\n.primary:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-active);\n}\n\n/* secondary — neutral surface */\n.secondary {\n background-color: var(--tempest-surface);\n --_tempest-button-fg: var(--tempest-text);\n border-color: var(--tempest-border);\n}\n.secondary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n border-color: var(--tempest-border-strong);\n}\n\n/* danger — solid red */\n.danger {\n background-color: var(--tempest-danger-solid);\n --_tempest-button-fg: var(--tempest-danger-on-solid);\n}\n.danger:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-danger-hover);\n}\n\n/* success — solid green */\n.success {\n background-color: var(--tempest-success-solid);\n --_tempest-button-fg: var(--tempest-success-on-solid);\n}\n.success:hover:not(:disabled, [aria-disabled=\"true\"]) {\n filter: brightness(0.92);\n}\n\n/* ghost — transparent, hover surface */\n.ghost {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-text);\n box-shadow: none;\n}\n.ghost:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface);\n box-shadow: none;\n}\n.ghost:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n box-shadow: none;\n}\n\n/* soft — tinted background, primary text */\n.soft {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n box-shadow: none;\n}\n.soft:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft-hover);\n}\n\n/* outline — bordered, transparent fill */\n.outline {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n border-color: var(--tempest-primary);\n box-shadow: none;\n}\n/*\n * The text colour has to move with the background.\n *\n * `.outline` sets its text to `var(--tempest-primary)` over a transparent background,\n * where it is fine. This rule tints the background to `--tempest-primary-soft` and,\n * without restating the colour, leaves the fill token sitting on the tint: **4.38:1 in\n * the light theme and 4.28:1 in dark**, both under the 4.5:1 floor for text — so the\n * label got harder to read at the exact moment the pointer was on it.\n *\n * `--tempest-primary-on-soft` is the token for this ground (6.18:1 / 8.72:1) and\n * `docs/styles.md` has documented the rule all along. A rule that changes only the\n * background of a coloured element is the shape of this bug; the other eight places in\n * the SDK that tint a background inherit `--tempest-text`, `--tempest-text-muted` or\n * `--tempest-primary-on-soft` and are fine.\n */\n.outline:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n}\n\n/* link — text-only, underline on hover */\n.link {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n box-shadow: none;\n padding-left: 0;\n padding-right: 0;\n border-radius: var(--tempest-radius-sm);\n}\n.link:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --_tempest-button-fg: var(--tempest-primary-hover);\n text-decoration: underline;\n background: none;\n box-shadow: none;\n}\n\n/* ============================================================\n * Sizes — token-driven, density-aware\n * ============================================================ */\n.xs {\n height: var(--tempest-control-height-xs);\n padding: 0 var(--tempest-control-padding-xs);\n font-size: var(--tempest-control-font-xs);\n}\n.sm {\n height: var(--tempest-control-height-sm);\n padding: 0 var(--tempest-control-padding-sm);\n font-size: var(--tempest-control-font-sm);\n}\n.md {\n height: var(--tempest-control-height-md);\n padding: 0 var(--tempest-control-padding-md);\n font-size: var(--tempest-control-font-md);\n}\n.lg {\n height: var(--tempest-control-height-lg);\n padding: 0 var(--tempest-control-padding-lg);\n font-size: var(--tempest-control-font-lg);\n}\n.xl {\n height: var(--tempest-control-height-xl);\n padding: 0 var(--tempest-control-padding-xl);\n font-size: var(--tempest-control-font-xl);\n}\n\n/* Square (icon-only) — width matches height */\n.iconOnly {\n position: relative;\n}\n.iconOnly.xs {\n width: var(--tempest-control-height-xs);\n padding: 0;\n}\n.iconOnly.sm {\n width: var(--tempest-control-height-sm);\n padding: 0;\n}\n.iconOnly.md {\n width: var(--tempest-control-height-md);\n padding: 0;\n}\n.iconOnly.lg {\n width: var(--tempest-control-height-lg);\n padding: 0;\n}\n.iconOnly.xl {\n width: var(--tempest-control-height-xl);\n padding: 0;\n}\n\n/* Touch hit-slop — extend tap target to a min 44×44 on coarse pointers\n * for the smallest icon-only sizes, without changing visual footprint. */\n@media (pointer: coarse) {\n .iconOnly.xs::after,\n .iconOnly.sm::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n }\n}\n\n/* Pill shape */\n.pill {\n border-radius: var(--tempest-radius-full);\n}\n\n.fullWidth {\n width: 100%;\n}\n\n/*\n * Lay out leftIcon + label + rightIcon as one centered, gapped row. Without\n * this the three are inline inside a single span (no gap, icon baseline-\n * aligned instead of centered), which reads as off-center — most visible on\n * fullWidth buttons where the label has room to drift.\n */\n.content {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n min-width: 0;\n}\n\n.loading .hiddenText {\n
|
|
1
|
+
{"version":3,"file":"Button.module.cjs","names":[],"sources":["../../../src/components/Button/Button.module.css"],"sourcesContent":[".button {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n border: 1px solid transparent;\n border-radius: var(--tempest-control-radius, var(--tempest-radius-md));\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-none);\n letter-spacing: var(--tempest-tracking-normal);\n color: var(--_tempest-button-fg);\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n transition: var(--tempest-transition-base);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n box-shadow: var(--tempest-shadow-sm);\n }\n}\n\n.button:active:not(:disabled, [aria-disabled=\"true\"]) {\n transform: translateY(1px);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:disabled,\n.button[aria-disabled=\"true\"] {\n opacity: 0.55;\n box-shadow: none;\n}\n\n.button[aria-disabled=\"true\"] {\n cursor: not-allowed;\n}\n\n/*\n * `<Button href>` and `<ButtonSlot>` around a link render an `<a>`, and an app's own link\n * rules reach it. `.button` is one class (0,1,0); `a:hover { color }` is (0,1,1) and\n * wins — the Vite React template ships exactly that rule, so in a fresh app a\n * primary link-button turned its label `#535bf2` on hover, over the primary fill.\n *\n * Each variant therefore sets its text colour as `--_tempest-button-fg` instead of\n * `color`, and this rule restates it on every link state at (0,2,1), above any\n * single-element link rule. The `link` variant's hover underline is (0,3,0) and\n * still applies.\n */\na.button:is(:link, :visited, :hover, :active, :focus, :not([href])) {\n color: var(--_tempest-button-fg);\n text-decoration: none;\n}\n\n/* ============================================================\n * Variants — solid (default), soft, outline, ghost\n * Status colors: primary, secondary (neutral), danger, success\n * ============================================================ */\n\n/* primary — solid filled */\n.primary {\n background-color: var(--tempest-primary);\n --_tempest-button-fg: var(--tempest-primary-foreground);\n}\n.primary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-hover);\n}\n.primary:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-active);\n}\n\n/* secondary — neutral surface */\n.secondary {\n background-color: var(--tempest-surface);\n --_tempest-button-fg: var(--tempest-text);\n border-color: var(--tempest-border);\n}\n.secondary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n border-color: var(--tempest-border-strong);\n}\n\n/* danger — solid red */\n.danger {\n background-color: var(--tempest-danger-solid);\n --_tempest-button-fg: var(--tempest-danger-on-solid);\n}\n.danger:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-danger-hover);\n}\n\n/* success — solid green */\n.success {\n background-color: var(--tempest-success-solid);\n --_tempest-button-fg: var(--tempest-success-on-solid);\n}\n.success:hover:not(:disabled, [aria-disabled=\"true\"]) {\n filter: brightness(0.92);\n}\n\n/* ghost — transparent, hover surface */\n.ghost {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-text);\n box-shadow: none;\n}\n.ghost:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface);\n box-shadow: none;\n}\n.ghost:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n box-shadow: none;\n}\n\n/* soft — tinted background, primary text */\n.soft {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n box-shadow: none;\n}\n.soft:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft-hover);\n}\n\n/* outline — bordered, transparent fill */\n.outline {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n border-color: var(--tempest-primary);\n box-shadow: none;\n}\n/*\n * The text colour has to move with the background.\n *\n * `.outline` sets its text to `var(--tempest-primary)` over a transparent background,\n * where it is fine. This rule tints the background to `--tempest-primary-soft` and,\n * without restating the colour, leaves the fill token sitting on the tint: **4.38:1 in\n * the light theme and 4.28:1 in dark**, both under the 4.5:1 floor for text — so the\n * label got harder to read at the exact moment the pointer was on it.\n *\n * `--tempest-primary-on-soft` is the token for this ground (6.18:1 / 8.72:1) and\n * `docs/styles.md` has documented the rule all along. A rule that changes only the\n * background of a coloured element is the shape of this bug; the other eight places in\n * the SDK that tint a background inherit `--tempest-text`, `--tempest-text-muted` or\n * `--tempest-primary-on-soft` and are fine.\n */\n.outline:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n}\n\n/* link — text-only, underline on hover */\n.link {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n box-shadow: none;\n padding-left: 0;\n padding-right: 0;\n border-radius: var(--tempest-radius-sm);\n}\n.link:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --_tempest-button-fg: var(--tempest-primary-hover);\n text-decoration: underline;\n background: none;\n box-shadow: none;\n}\n\n/* ============================================================\n * Sizes — token-driven, density-aware\n * ============================================================ */\n.xs {\n height: var(--tempest-control-height-xs);\n padding: 0 var(--tempest-control-padding-xs);\n font-size: var(--tempest-control-font-xs);\n}\n.sm {\n height: var(--tempest-control-height-sm);\n padding: 0 var(--tempest-control-padding-sm);\n font-size: var(--tempest-control-font-sm);\n}\n.md {\n height: var(--tempest-control-height-md);\n padding: 0 var(--tempest-control-padding-md);\n font-size: var(--tempest-control-font-md);\n}\n.lg {\n height: var(--tempest-control-height-lg);\n padding: 0 var(--tempest-control-padding-lg);\n font-size: var(--tempest-control-font-lg);\n}\n.xl {\n height: var(--tempest-control-height-xl);\n padding: 0 var(--tempest-control-padding-xl);\n font-size: var(--tempest-control-font-xl);\n}\n\n/* Square (icon-only) — width matches height */\n.iconOnly {\n position: relative;\n}\n.iconOnly.xs {\n width: var(--tempest-control-height-xs);\n padding: 0;\n}\n.iconOnly.sm {\n width: var(--tempest-control-height-sm);\n padding: 0;\n}\n.iconOnly.md {\n width: var(--tempest-control-height-md);\n padding: 0;\n}\n.iconOnly.lg {\n width: var(--tempest-control-height-lg);\n padding: 0;\n}\n.iconOnly.xl {\n width: var(--tempest-control-height-xl);\n padding: 0;\n}\n\n/* Touch hit-slop — extend tap target to a min 44×44 on coarse pointers\n * for the smallest icon-only sizes, without changing visual footprint. */\n@media (pointer: coarse) {\n .iconOnly.xs::after,\n .iconOnly.sm::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n }\n}\n\n/* Pill shape */\n.pill {\n border-radius: var(--tempest-radius-full);\n}\n\n.fullWidth {\n width: 100%;\n}\n\n/*\n * Lay out leftIcon + label + rightIcon as one centered, gapped row. Without\n * this the three are inline inside a single span (no gap, icon baseline-\n * aligned instead of centered), which reads as off-center — most visible on\n * fullWidth buttons where the label has room to drift.\n */\n.content {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n min-width: 0;\n}\n\n/*\n * Hide the label by paint only. `visibility: hidden` also drops it from the\n * accessibility tree, so a loading button lost its name (#416). `opacity: 0`\n * keeps the name and the width; `pointer-events: none` keeps the invisible\n * label out of hit-testing, as it was. Forced colors leaves `opacity` alone.\n */\n.loading .hiddenText {\n opacity: 0;\n pointer-events: none;\n}\n\n.spinner {\n position: absolute;\n animation: tempest-spin 0.8s linear infinite;\n}\n\n@keyframes tempest-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n"],"mappings":";"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.module.js","names":[],"sources":["../../../src/components/Button/Button.module.css"],"sourcesContent":[".button {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n border: 1px solid transparent;\n border-radius: var(--tempest-control-radius, var(--tempest-radius-md));\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-none);\n letter-spacing: var(--tempest-tracking-normal);\n color: var(--_tempest-button-fg);\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n transition: var(--tempest-transition-base);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n box-shadow: var(--tempest-shadow-sm);\n }\n}\n\n.button:active:not(:disabled, [aria-disabled=\"true\"]) {\n transform: translateY(1px);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:disabled,\n.button[aria-disabled=\"true\"] {\n opacity: 0.55;\n box-shadow: none;\n}\n\n.button[aria-disabled=\"true\"] {\n cursor: not-allowed;\n}\n\n/*\n * `<Button href>` and `<ButtonSlot>` around a link render an `<a>`, and an app's own link\n * rules reach it. `.button` is one class (0,1,0); `a:hover { color }` is (0,1,1) and\n * wins — the Vite React template ships exactly that rule, so in a fresh app a\n * primary link-button turned its label `#535bf2` on hover, over the primary fill.\n *\n * Each variant therefore sets its text colour as `--_tempest-button-fg` instead of\n * `color`, and this rule restates it on every link state at (0,2,1), above any\n * single-element link rule. The `link` variant's hover underline is (0,3,0) and\n * still applies.\n */\na.button:is(:link, :visited, :hover, :active, :focus, :not([href])) {\n color: var(--_tempest-button-fg);\n text-decoration: none;\n}\n\n/* ============================================================\n * Variants — solid (default), soft, outline, ghost\n * Status colors: primary, secondary (neutral), danger, success\n * ============================================================ */\n\n/* primary — solid filled */\n.primary {\n background-color: var(--tempest-primary);\n --_tempest-button-fg: var(--tempest-primary-foreground);\n}\n.primary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-hover);\n}\n.primary:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-active);\n}\n\n/* secondary — neutral surface */\n.secondary {\n background-color: var(--tempest-surface);\n --_tempest-button-fg: var(--tempest-text);\n border-color: var(--tempest-border);\n}\n.secondary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n border-color: var(--tempest-border-strong);\n}\n\n/* danger — solid red */\n.danger {\n background-color: var(--tempest-danger-solid);\n --_tempest-button-fg: var(--tempest-danger-on-solid);\n}\n.danger:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-danger-hover);\n}\n\n/* success — solid green */\n.success {\n background-color: var(--tempest-success-solid);\n --_tempest-button-fg: var(--tempest-success-on-solid);\n}\n.success:hover:not(:disabled, [aria-disabled=\"true\"]) {\n filter: brightness(0.92);\n}\n\n/* ghost — transparent, hover surface */\n.ghost {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-text);\n box-shadow: none;\n}\n.ghost:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface);\n box-shadow: none;\n}\n.ghost:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n box-shadow: none;\n}\n\n/* soft — tinted background, primary text */\n.soft {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n box-shadow: none;\n}\n.soft:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft-hover);\n}\n\n/* outline — bordered, transparent fill */\n.outline {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n border-color: var(--tempest-primary);\n box-shadow: none;\n}\n/*\n * The text colour has to move with the background.\n *\n * `.outline` sets its text to `var(--tempest-primary)` over a transparent background,\n * where it is fine. This rule tints the background to `--tempest-primary-soft` and,\n * without restating the colour, leaves the fill token sitting on the tint: **4.38:1 in\n * the light theme and 4.28:1 in dark**, both under the 4.5:1 floor for text — so the\n * label got harder to read at the exact moment the pointer was on it.\n *\n * `--tempest-primary-on-soft` is the token for this ground (6.18:1 / 8.72:1) and\n * `docs/styles.md` has documented the rule all along. A rule that changes only the\n * background of a coloured element is the shape of this bug; the other eight places in\n * the SDK that tint a background inherit `--tempest-text`, `--tempest-text-muted` or\n * `--tempest-primary-on-soft` and are fine.\n */\n.outline:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n}\n\n/* link — text-only, underline on hover */\n.link {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n box-shadow: none;\n padding-left: 0;\n padding-right: 0;\n border-radius: var(--tempest-radius-sm);\n}\n.link:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --_tempest-button-fg: var(--tempest-primary-hover);\n text-decoration: underline;\n background: none;\n box-shadow: none;\n}\n\n/* ============================================================\n * Sizes — token-driven, density-aware\n * ============================================================ */\n.xs {\n height: var(--tempest-control-height-xs);\n padding: 0 var(--tempest-control-padding-xs);\n font-size: var(--tempest-control-font-xs);\n}\n.sm {\n height: var(--tempest-control-height-sm);\n padding: 0 var(--tempest-control-padding-sm);\n font-size: var(--tempest-control-font-sm);\n}\n.md {\n height: var(--tempest-control-height-md);\n padding: 0 var(--tempest-control-padding-md);\n font-size: var(--tempest-control-font-md);\n}\n.lg {\n height: var(--tempest-control-height-lg);\n padding: 0 var(--tempest-control-padding-lg);\n font-size: var(--tempest-control-font-lg);\n}\n.xl {\n height: var(--tempest-control-height-xl);\n padding: 0 var(--tempest-control-padding-xl);\n font-size: var(--tempest-control-font-xl);\n}\n\n/* Square (icon-only) — width matches height */\n.iconOnly {\n position: relative;\n}\n.iconOnly.xs {\n width: var(--tempest-control-height-xs);\n padding: 0;\n}\n.iconOnly.sm {\n width: var(--tempest-control-height-sm);\n padding: 0;\n}\n.iconOnly.md {\n width: var(--tempest-control-height-md);\n padding: 0;\n}\n.iconOnly.lg {\n width: var(--tempest-control-height-lg);\n padding: 0;\n}\n.iconOnly.xl {\n width: var(--tempest-control-height-xl);\n padding: 0;\n}\n\n/* Touch hit-slop — extend tap target to a min 44×44 on coarse pointers\n * for the smallest icon-only sizes, without changing visual footprint. */\n@media (pointer: coarse) {\n .iconOnly.xs::after,\n .iconOnly.sm::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n }\n}\n\n/* Pill shape */\n.pill {\n border-radius: var(--tempest-radius-full);\n}\n\n.fullWidth {\n width: 100%;\n}\n\n/*\n * Lay out leftIcon + label + rightIcon as one centered, gapped row. Without\n * this the three are inline inside a single span (no gap, icon baseline-\n * aligned instead of centered), which reads as off-center — most visible on\n * fullWidth buttons where the label has room to drift.\n */\n.content {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n min-width: 0;\n}\n\n.loading .hiddenText {\n
|
|
1
|
+
{"version":3,"file":"Button.module.js","names":[],"sources":["../../../src/components/Button/Button.module.css"],"sourcesContent":[".button {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n border: 1px solid transparent;\n border-radius: var(--tempest-control-radius, var(--tempest-radius-md));\n font-family: var(--tempest-font-sans);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-none);\n letter-spacing: var(--tempest-tracking-normal);\n color: var(--_tempest-button-fg);\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n transition: var(--tempest-transition-base);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .button:hover:not(:disabled, [aria-disabled=\"true\"]) {\n box-shadow: var(--tempest-shadow-sm);\n }\n}\n\n.button:active:not(:disabled, [aria-disabled=\"true\"]) {\n transform: translateY(1px);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.button:disabled,\n.button[aria-disabled=\"true\"] {\n opacity: 0.55;\n box-shadow: none;\n}\n\n.button[aria-disabled=\"true\"] {\n cursor: not-allowed;\n}\n\n/*\n * `<Button href>` and `<ButtonSlot>` around a link render an `<a>`, and an app's own link\n * rules reach it. `.button` is one class (0,1,0); `a:hover { color }` is (0,1,1) and\n * wins — the Vite React template ships exactly that rule, so in a fresh app a\n * primary link-button turned its label `#535bf2` on hover, over the primary fill.\n *\n * Each variant therefore sets its text colour as `--_tempest-button-fg` instead of\n * `color`, and this rule restates it on every link state at (0,2,1), above any\n * single-element link rule. The `link` variant's hover underline is (0,3,0) and\n * still applies.\n */\na.button:is(:link, :visited, :hover, :active, :focus, :not([href])) {\n color: var(--_tempest-button-fg);\n text-decoration: none;\n}\n\n/* ============================================================\n * Variants — solid (default), soft, outline, ghost\n * Status colors: primary, secondary (neutral), danger, success\n * ============================================================ */\n\n/* primary — solid filled */\n.primary {\n background-color: var(--tempest-primary);\n --_tempest-button-fg: var(--tempest-primary-foreground);\n}\n.primary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-hover);\n}\n.primary:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-active);\n}\n\n/* secondary — neutral surface */\n.secondary {\n background-color: var(--tempest-surface);\n --_tempest-button-fg: var(--tempest-text);\n border-color: var(--tempest-border);\n}\n.secondary:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n border-color: var(--tempest-border-strong);\n}\n\n/* danger — solid red */\n.danger {\n background-color: var(--tempest-danger-solid);\n --_tempest-button-fg: var(--tempest-danger-on-solid);\n}\n.danger:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-danger-hover);\n}\n\n/* success — solid green */\n.success {\n background-color: var(--tempest-success-solid);\n --_tempest-button-fg: var(--tempest-success-on-solid);\n}\n.success:hover:not(:disabled, [aria-disabled=\"true\"]) {\n filter: brightness(0.92);\n}\n\n/* ghost — transparent, hover surface */\n.ghost {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-text);\n box-shadow: none;\n}\n.ghost:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface);\n box-shadow: none;\n}\n.ghost:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-surface-2);\n box-shadow: none;\n}\n\n/* soft — tinted background, primary text */\n.soft {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n box-shadow: none;\n}\n.soft:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft-hover);\n}\n\n/* outline — bordered, transparent fill */\n.outline {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n border-color: var(--tempest-primary);\n box-shadow: none;\n}\n/*\n * The text colour has to move with the background.\n *\n * `.outline` sets its text to `var(--tempest-primary)` over a transparent background,\n * where it is fine. This rule tints the background to `--tempest-primary-soft` and,\n * without restating the colour, leaves the fill token sitting on the tint: **4.38:1 in\n * the light theme and 4.28:1 in dark**, both under the 4.5:1 floor for text — so the\n * label got harder to read at the exact moment the pointer was on it.\n *\n * `--tempest-primary-on-soft` is the token for this ground (6.18:1 / 8.72:1) and\n * `docs/styles.md` has documented the rule all along. A rule that changes only the\n * background of a coloured element is the shape of this bug; the other eight places in\n * the SDK that tint a background inherit `--tempest-text`, `--tempest-text-muted` or\n * `--tempest-primary-on-soft` and are fine.\n */\n.outline:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--tempest-primary-soft);\n --_tempest-button-fg: var(--tempest-primary-on-soft);\n}\n\n/* link — text-only, underline on hover */\n.link {\n background-color: transparent;\n --_tempest-button-fg: var(--tempest-primary);\n box-shadow: none;\n padding-left: 0;\n padding-right: 0;\n border-radius: var(--tempest-radius-sm);\n}\n.link:hover:not(:disabled, [aria-disabled=\"true\"]) {\n --_tempest-button-fg: var(--tempest-primary-hover);\n text-decoration: underline;\n background: none;\n box-shadow: none;\n}\n\n/* ============================================================\n * Sizes — token-driven, density-aware\n * ============================================================ */\n.xs {\n height: var(--tempest-control-height-xs);\n padding: 0 var(--tempest-control-padding-xs);\n font-size: var(--tempest-control-font-xs);\n}\n.sm {\n height: var(--tempest-control-height-sm);\n padding: 0 var(--tempest-control-padding-sm);\n font-size: var(--tempest-control-font-sm);\n}\n.md {\n height: var(--tempest-control-height-md);\n padding: 0 var(--tempest-control-padding-md);\n font-size: var(--tempest-control-font-md);\n}\n.lg {\n height: var(--tempest-control-height-lg);\n padding: 0 var(--tempest-control-padding-lg);\n font-size: var(--tempest-control-font-lg);\n}\n.xl {\n height: var(--tempest-control-height-xl);\n padding: 0 var(--tempest-control-padding-xl);\n font-size: var(--tempest-control-font-xl);\n}\n\n/* Square (icon-only) — width matches height */\n.iconOnly {\n position: relative;\n}\n.iconOnly.xs {\n width: var(--tempest-control-height-xs);\n padding: 0;\n}\n.iconOnly.sm {\n width: var(--tempest-control-height-sm);\n padding: 0;\n}\n.iconOnly.md {\n width: var(--tempest-control-height-md);\n padding: 0;\n}\n.iconOnly.lg {\n width: var(--tempest-control-height-lg);\n padding: 0;\n}\n.iconOnly.xl {\n width: var(--tempest-control-height-xl);\n padding: 0;\n}\n\n/* Touch hit-slop — extend tap target to a min 44×44 on coarse pointers\n * for the smallest icon-only sizes, without changing visual footprint. */\n@media (pointer: coarse) {\n .iconOnly.xs::after,\n .iconOnly.sm::after {\n content: \"\";\n position: absolute;\n inset: -8px;\n }\n}\n\n/* Pill shape */\n.pill {\n border-radius: var(--tempest-radius-full);\n}\n\n.fullWidth {\n width: 100%;\n}\n\n/*\n * Lay out leftIcon + label + rightIcon as one centered, gapped row. Without\n * this the three are inline inside a single span (no gap, icon baseline-\n * aligned instead of centered), which reads as off-center — most visible on\n * fullWidth buttons where the label has room to drift.\n */\n.content {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-control-gap, var(--tempest-space-2));\n min-width: 0;\n}\n\n/*\n * Hide the label by paint only. `visibility: hidden` also drops it from the\n * accessibility tree, so a loading button lost its name (#416). `opacity: 0`\n * keeps the name and the width; `pointer-events: none` keeps the invisible\n * label out of hit-testing, as it was. Forced colors leaves `opacity` alone.\n */\n.loading .hiddenText {\n opacity: 0;\n pointer-events: none;\n}\n\n.spinner {\n position: absolute;\n animation: tempest-spin 0.8s linear infinite;\n}\n\n@keyframes tempest-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n"],"mappings":";"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ButtonContent.cjs","names":[],"sources":["../../../src/components/Button/ButtonContent.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Button.module.css\";\n\n/** Props of {@link ButtonContent}. */\nexport interface ButtonContentProps {\n loading: boolean;\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * The inside of every button-looking element: the absolutely-positioned spinner\n * plus the icon/label row, shared by `Button` and `ButtonSlot`.\n *\n * @param props - See {@link ButtonContentProps}.\n * @returns The content nodes.\n */\nexport function ButtonContent({ loading, leftIcon, rightIcon, children }: ButtonContentProps) {\n return (\n <>\n {loading && (\n <span className={styles.spinner} aria-hidden>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M21 12a9 9 0 1 1-6.219-8.56\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n )}\n <span className={cn(styles.content, loading && styles.hiddenText)}>\n {leftIcon}\n {children}\n {rightIcon}\n </span>\n </>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ButtonContent.cjs","names":[],"sources":["../../../src/components/Button/ButtonContent.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Button.module.css\";\n\n/** Props of {@link ButtonContent}. */\nexport interface ButtonContentProps {\n loading: boolean;\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * The inside of every button-looking element: the absolutely-positioned spinner\n * plus the icon/label row, shared by `Button` and `ButtonSlot`.\n *\n * While loading, the row is hidden by paint only (`opacity: 0`), never with\n * `visibility: hidden` or `display: none`: those drop the label from the\n * accessibility tree and the button is announced with no name (#416). Painted\n * out, the label still sizes the button — its width does not move — and still\n * names it. The spinner is `aria-hidden`, so the name is the label alone and the\n * busy state comes from `aria-busy` on the host element.\n *\n * @param props - See {@link ButtonContentProps}.\n * @returns The content nodes.\n */\nexport function ButtonContent({ loading, leftIcon, rightIcon, children }: ButtonContentProps) {\n return (\n <>\n {loading && (\n <span className={styles.spinner} aria-hidden>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M21 12a9 9 0 1 1-6.219-8.56\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n )}\n <span className={cn(styles.content, loading && styles.hiddenText)}>\n {leftIcon}\n {children}\n {rightIcon}\n </span>\n </>\n );\n}\n"],"mappings":"0GA0BA,SAAgB,EAAc,CAAE,UAAS,WAAU,YAAW,YAAgC,CAC1F,OACI,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,CACK,IACG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,QAAS,cAAA,GAC7B,UAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,MAAM,6BAEN,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,EAAE,8BACF,OAAO,eACP,YAAY,IACZ,cAAc,OACjB,CAAA,CACA,CAAA,CACH,CAAA,GAEV,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,GAAW,EAAA,QAAO,UAAU,EAAhE,SAAA,CACK,EACA,EACA,CACC,CACR,CAAA,CAAA,CAAA,CAAA,CAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ButtonContent.js","names":[],"sources":["../../../src/components/Button/ButtonContent.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Button.module.css\";\n\n/** Props of {@link ButtonContent}. */\nexport interface ButtonContentProps {\n loading: boolean;\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * The inside of every button-looking element: the absolutely-positioned spinner\n * plus the icon/label row, shared by `Button` and `ButtonSlot`.\n *\n * @param props - See {@link ButtonContentProps}.\n * @returns The content nodes.\n */\nexport function ButtonContent({ loading, leftIcon, rightIcon, children }: ButtonContentProps) {\n return (\n <>\n {loading && (\n <span className={styles.spinner} aria-hidden>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M21 12a9 9 0 1 1-6.219-8.56\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n )}\n <span className={cn(styles.content, loading && styles.hiddenText)}>\n {leftIcon}\n {children}\n {rightIcon}\n </span>\n </>\n );\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"ButtonContent.js","names":[],"sources":["../../../src/components/Button/ButtonContent.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Button.module.css\";\n\n/** Props of {@link ButtonContent}. */\nexport interface ButtonContentProps {\n loading: boolean;\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * The inside of every button-looking element: the absolutely-positioned spinner\n * plus the icon/label row, shared by `Button` and `ButtonSlot`.\n *\n * While loading, the row is hidden by paint only (`opacity: 0`), never with\n * `visibility: hidden` or `display: none`: those drop the label from the\n * accessibility tree and the button is announced with no name (#416). Painted\n * out, the label still sizes the button — its width does not move — and still\n * names it. The spinner is `aria-hidden`, so the name is the label alone and the\n * busy state comes from `aria-busy` on the host element.\n *\n * @param props - See {@link ButtonContentProps}.\n * @returns The content nodes.\n */\nexport function ButtonContent({ loading, leftIcon, rightIcon, children }: ButtonContentProps) {\n return (\n <>\n {loading && (\n <span className={styles.spinner} aria-hidden>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M21 12a9 9 0 1 1-6.219-8.56\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n )}\n <span className={cn(styles.content, loading && styles.hiddenText)}>\n {leftIcon}\n {children}\n {rightIcon}\n </span>\n </>\n );\n}\n"],"mappings":";;;;AA0BA,SAAgB,EAAc,EAAE,YAAS,aAAU,cAAW,eAAgC;CAC1F,OACI,kBAAA,GAAA,EAAA,UAAA,CACK,KACG,kBAAC,QAAD;EAAM,WAAW,EAAO;EAAS,eAAA;EAC7B,UAAA,kBAAC,OAAD;GACI,OAAM;GACN,QAAO;GACP,SAAQ;GACR,MAAK;GACL,OAAM;GAEN,UAAA,kBAAC,QAAD;IACI,GAAE;IACF,QAAO;IACP,aAAY;IACZ,eAAc;GACjB,CAAA;EACA,CAAA;CACH,CAAA,GAEV,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAO,SAAS,KAAW,EAAO,UAAU;EAAhE,UAAA;GACK;GACA;GACA;EACC;CACR,CAAA,CAAA,EAAA,CAAA;AAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Carousel.module.cjs","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline:
|
|
1
|
+
{"version":3,"file":"Carousel.module.cjs","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.viewport {\n overflow: hidden;\n border-radius: var(--tempest-radius-lg);\n}\n\n.track {\n display: flex;\n transition: transform var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.slide {\n flex: 0 0 100%;\n min-width: 0;\n}\n\n.arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n box-shadow: var(--tempest-shadow-md);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xl);\n line-height: 1;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .arrow:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.arrow:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.arrow:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.prev {\n left: var(--tempest-space-2);\n}\n\n.next {\n right: var(--tempest-space-2);\n}\n\n.dots {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n margin-top: var(--tempest-space-3);\n}\n\n.dot {\n width: 0.5rem;\n height: 0.5rem;\n padding: 0;\n background-color: var(--tempest-border);\n border: none;\n border-radius: var(--tempest-radius-full);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n.dotActive {\n background-color: var(--tempest-primary);\n}\n\n.dot:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .track {\n transition: none;\n }\n}\n"],"mappings":";"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Carousel.module.js","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline:
|
|
1
|
+
{"version":3,"file":"Carousel.module.js","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.viewport {\n overflow: hidden;\n border-radius: var(--tempest-radius-lg);\n}\n\n.track {\n display: flex;\n transition: transform var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.slide {\n flex: 0 0 100%;\n min-width: 0;\n}\n\n.arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n box-shadow: var(--tempest-shadow-md);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xl);\n line-height: 1;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .arrow:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.arrow:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.arrow:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.prev {\n left: var(--tempest-space-2);\n}\n\n.next {\n right: var(--tempest-space-2);\n}\n\n.dots {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n margin-top: var(--tempest-space-3);\n}\n\n.dot {\n width: 0.5rem;\n height: 0.5rem;\n padding: 0;\n background-color: var(--tempest-border);\n border: none;\n border-radius: var(--tempest-radius-full);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n.dotActive {\n background-color: var(--tempest-primary);\n}\n\n.dot:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .track {\n transition: none;\n }\n}\n"],"mappings":";"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.module.cjs","names":[],"sources":["../../../src/components/Chat/Chat.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n height: var(--tempest-chat-height, 100%);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n flex: 0 0 auto;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.thread {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--tempest-space-3);\n min-height: 0;\n padding: var(--tempest-space-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.thread:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -2px;\n}\n\n.day {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.day::before,\n.day::after {\n flex: 1 1 auto;\n height: 1px;\n background-color: var(--tempest-border);\n content: \"\";\n}\n\n.dayLabel {\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n text-transform: capitalize;\n}\n\n.run {\n display: flex;\n gap: var(--tempest-space-3);\n align-items: flex-start;\n max-width: 100%;\n}\n\n/*\n * Own messages mirror the row instead of moving to a second column: the avatar,\n * the name and the bubbles keep the same source order, so a screen reader still\n * reads \"who, then what\" while the eye reads it from the other side.\n */\n.ownRun {\n flex-direction: row-reverse;\n}\n\n.avatar {\n flex: 0 0 auto;\n}\n\n.runBody {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n max-width: min(78%, 42rem);\n}\n\n.ownRun .runBody {\n align-items: flex-end;\n}\n\n.author {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-medium);\n}\n\n.bubbles {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.bubbleRow {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.ownRun .bubbleRow {\n flex-direction: row-reverse;\n}\n\n.bubble {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n}\n\n.ownBubble {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n/*\n * A failed message keeps its text readable and states the failure at the border\n * and in the meta row. Tinting the whole bubble danger-red would make the message\n * itself hard to read — and re-reading it is exactly what somebody does before\n * deciding to retry.\n */\n.failedBubble {\n border-color: var(--tempest-danger);\n background-color: var(--tempest-danger-bg);\n color: var(--tempest-text);\n}\n\n.body {\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n/*\n * The timestamp uses the muted token, not the subtle one, and switches to the\n * bubble's own foreground when the bubble is tinted.\n *\n * `--tempest-text-subtle` is solved against the page and surface backgrounds. On\n * `--tempest-primary-soft` it is a different composite, and the real browser\n * measured it below the 4.5:1 text floor — the same trap the syntax tokens hit.\n * Size is what de-emphasises the meta row here; colour still has to pass.\n */\n.meta {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.ownBubble .meta {\n color: var(--tempest-primary-on-soft);\n}\n\n.status {\n display: inline-flex;\n align-items: center;\n}\n\n.statusFailed {\n color: var(--tempest-danger);\n font-weight: var(--tempest-weight-bold);\n}\n\n/*\n * A bubble row carries more than a bubble now: the actions button sits beside it\n * and the reaction chips hang under it, so the row wraps and the chips are given\n * the whole width to fall onto.\n */\n.bubbleRow {\n flex-wrap: wrap;\n}\n\n.reactions {\n display: flex;\n flex-basis: 100%;\n flex-wrap: wrap;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ownRun .reactions {\n justify-content: flex-end;\n}\n\n.reaction {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: 0 var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full, 999px);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-xs);\n line-height: 1.8;\n cursor: pointer;\n}\n\n.reaction:disabled {\n cursor: default;\n}\n\n/*\n * Your own reaction is marked by a tinted chip and its own foreground, never by\n * `--tempest-text-subtle` over the tint: that token is solved against the page\n * background and fails the text floor on a tinted surface.\n */\n.reactionMine {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n font-weight: var(--tempest-weight-medium);\n}\n\n/*\n * The ⋮ button is always in the DOM — on touch there is no hover to reveal it,\n * and a control that only appears on hover is a control a phone does not have.\n * A fine pointer gets it faded until the row is hovered or it is focused.\n */\n.actionsButton {\n flex: 0 0 auto;\n padding: 0 var(--tempest-space-1);\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .actionsButton {\n opacity: 0;\n transition: var(--tempest-transition-opacity, opacity 120ms ease);\n }\n\n .bubbleRow:hover .actionsButton,\n .actionsButton:focus-visible {\n opacity: 1;\n }\n}\n\n/* The reply stub: a tinted strip with a bar on the side it is anchored to. */\n.quote {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 100%;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border-left: 3px solid var(--tempest-primary);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xs);\n text-align: left;\n}\n\n.quoteButton {\n border-top: none;\n border-right: none;\n border-bottom: none;\n font: inherit;\n font-size: var(--tempest-text-xs);\n cursor: pointer;\n}\n\n/*\n * The author of a quote is text, so it is coloured like text.\n *\n * `--tempest-primary` here measured **4.35:1** against `--tempest-surface-2` in a\n * real browser — below the 4.5:1 floor for a 12px label, and invisible to the\n * jsdom axe sweep, which disables `color-contrast` because nothing is painted.\n * The brand still marks the quote: it is the bar down the side, which is a\n * non-text indicator and only owes 3:1.\n */\n.quoteAuthor {\n color: var(--tempest-text);\n font-weight: var(--tempest-weight-medium);\n}\n\n.quoteText {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n/*\n * A revoked quote reads as absent, which is the point: the text of a deleted\n * message must not survive inside the reply to it.\n */\n.quoteRevoked {\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.tombstone {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.deletedBubble {\n border-style: dashed;\n background-color: transparent;\n}\n\n.edited {\n font-style: italic;\n}\n\n/* Read by everyone is the only state that turns the ticks. */\n.statusRead {\n color: var(--tempest-info, var(--tempest-primary));\n}\n\n.attachments {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n max-width: 320px;\n}\n\n/* Holds the row's height while the attachments chunk is still loading. */\n.attachmentsFallback {\n min-height: var(--tempest-space-8, 2rem);\n}\n\n.imageAttachment {\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-md);\n background: none;\n line-height: 0;\n cursor: pointer;\n}\n\n.imageAttachment img {\n max-width: 100%;\n max-height: 260px;\n border-radius: var(--tempest-radius-md);\n object-fit: cover;\n}\n\n.videoAttachment {\n max-width: 100%;\n border-radius: var(--tempest-radius-md);\n}\n\n.voiceAttachment {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n}\n\n/*\n * The waveform is the difference between a voice note and a grey rectangle: it\n * is what tells somebody whether this is a word or a two-minute monologue.\n */\n.waveform {\n display: flex;\n align-items: flex-end;\n gap: 2px;\n height: 28px;\n}\n\n.waveform span {\n flex: 1 1 auto;\n min-width: 2px;\n border-radius: 1px;\n background-color: var(--tempest-primary);\n opacity: 0.7;\n}\n\n.fileAttachment {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n color: var(--tempest-text);\n text-decoration: none;\n}\n\n.fileName {\n overflow-wrap: anywhere;\n font-weight: var(--tempest-weight-medium);\n}\n\n.fileMeta {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.retry {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-danger);\n font: inherit;\n font-size: var(--tempest-text-xs);\n text-decoration: underline;\n cursor: pointer;\n}\n\n.typing {\n flex: 0 0 auto;\n margin: 0;\n padding: 0 var(--tempest-space-4) var(--tempest-space-2);\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n}\n\n.composer {\n display: flex;\n flex: 0 0 auto;\n align-items: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-top: 1px solid var(--tempest-border);\n}\n\n.field {\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: none;\n}\n\n.field:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -1px;\n}\n\n.field:disabled {\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.composerActions {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.send {\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.send:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n@media (max-width: 480px) {\n .runBody {\n max-width: 88%;\n }\n}\n"],"mappings":";"}
|
|
1
|
+
{"version":3,"file":"Chat.module.cjs","names":[],"sources":["../../../src/components/Chat/Chat.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n height: var(--tempest-chat-height, 100%);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n flex: 0 0 auto;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.thread {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--tempest-space-3);\n min-height: 0;\n padding: var(--tempest-space-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.thread:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.day {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.day::before,\n.day::after {\n flex: 1 1 auto;\n height: 1px;\n background-color: var(--tempest-border);\n content: \"\";\n}\n\n.dayLabel {\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n text-transform: capitalize;\n}\n\n.run {\n display: flex;\n gap: var(--tempest-space-3);\n align-items: flex-start;\n max-width: 100%;\n}\n\n/*\n * Own messages mirror the row instead of moving to a second column: the avatar,\n * the name and the bubbles keep the same source order, so a screen reader still\n * reads \"who, then what\" while the eye reads it from the other side.\n */\n.ownRun {\n flex-direction: row-reverse;\n}\n\n.avatar {\n flex: 0 0 auto;\n}\n\n.runBody {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n max-width: min(78%, 42rem);\n}\n\n.ownRun .runBody {\n align-items: flex-end;\n}\n\n.author {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-medium);\n}\n\n.bubbles {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.bubbleRow {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.ownRun .bubbleRow {\n flex-direction: row-reverse;\n}\n\n.bubble {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n}\n\n.ownBubble {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n/*\n * A failed message keeps its text readable and states the failure at the border\n * and in the meta row. Tinting the whole bubble danger-red would make the message\n * itself hard to read — and re-reading it is exactly what somebody does before\n * deciding to retry.\n */\n.failedBubble {\n border-color: var(--tempest-danger);\n background-color: var(--tempest-danger-bg);\n color: var(--tempest-text);\n}\n\n.body {\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n/*\n * The timestamp uses the muted token, not the subtle one, and switches to the\n * bubble's own foreground when the bubble is tinted.\n *\n * `--tempest-text-subtle` is solved against the page and surface backgrounds. On\n * `--tempest-primary-soft` it is a different composite, and the real browser\n * measured it below the 4.5:1 text floor — the same trap the syntax tokens hit.\n * Size is what de-emphasises the meta row here; colour still has to pass.\n */\n.meta {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.ownBubble .meta {\n color: var(--tempest-primary-on-soft);\n}\n\n.status {\n display: inline-flex;\n align-items: center;\n}\n\n.statusFailed {\n color: var(--tempest-danger);\n font-weight: var(--tempest-weight-bold);\n}\n\n/*\n * A bubble row carries more than a bubble now: the actions button sits beside it\n * and the reaction chips hang under it, so the row wraps and the chips are given\n * the whole width to fall onto.\n */\n.bubbleRow {\n flex-wrap: wrap;\n}\n\n.reactions {\n display: flex;\n flex-basis: 100%;\n flex-wrap: wrap;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ownRun .reactions {\n justify-content: flex-end;\n}\n\n.reaction {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: 0 var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full, 999px);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-xs);\n line-height: 1.8;\n cursor: pointer;\n}\n\n.reaction:disabled {\n cursor: default;\n}\n\n/*\n * Your own reaction is marked by a tinted chip and its own foreground, never by\n * `--tempest-text-subtle` over the tint: that token is solved against the page\n * background and fails the text floor on a tinted surface.\n */\n.reactionMine {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n font-weight: var(--tempest-weight-medium);\n}\n\n/*\n * The ⋮ button is always in the DOM — on touch there is no hover to reveal it,\n * and a control that only appears on hover is a control a phone does not have.\n * A fine pointer gets it faded until the row is hovered or it is focused.\n */\n.actionsButton {\n flex: 0 0 auto;\n padding: 0 var(--tempest-space-1);\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .actionsButton {\n opacity: 0;\n transition: var(--tempest-transition-opacity, opacity 120ms ease);\n }\n\n .bubbleRow:hover .actionsButton,\n .actionsButton:focus-visible {\n opacity: 1;\n }\n}\n\n/* The reply stub: a tinted strip with a bar on the side it is anchored to. */\n.quote {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 100%;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border-left: 3px solid var(--tempest-primary);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xs);\n text-align: left;\n}\n\n.quoteButton {\n border-top: none;\n border-right: none;\n border-bottom: none;\n font: inherit;\n font-size: var(--tempest-text-xs);\n cursor: pointer;\n}\n\n/*\n * The author of a quote is text, so it is coloured like text.\n *\n * `--tempest-primary` here measured **4.35:1** against `--tempest-surface-2` in a\n * real browser — below the 4.5:1 floor for a 12px label, and invisible to the\n * jsdom axe sweep, which disables `color-contrast` because nothing is painted.\n * The brand still marks the quote: it is the bar down the side, which is a\n * non-text indicator and only owes 3:1.\n */\n.quoteAuthor {\n color: var(--tempest-text);\n font-weight: var(--tempest-weight-medium);\n}\n\n.quoteText {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n/*\n * A revoked quote reads as absent, which is the point: the text of a deleted\n * message must not survive inside the reply to it.\n */\n.quoteRevoked {\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.tombstone {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.deletedBubble {\n border-style: dashed;\n background-color: transparent;\n}\n\n.edited {\n font-style: italic;\n}\n\n/* Read by everyone is the only state that turns the ticks. */\n.statusRead {\n color: var(--tempest-info, var(--tempest-primary));\n}\n\n.attachments {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n max-width: 320px;\n}\n\n/* Holds the row's height while the attachments chunk is still loading. */\n.attachmentsFallback {\n min-height: var(--tempest-space-8, 2rem);\n}\n\n.imageAttachment {\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-md);\n background: none;\n line-height: 0;\n cursor: pointer;\n}\n\n.imageAttachment img {\n max-width: 100%;\n max-height: 260px;\n border-radius: var(--tempest-radius-md);\n object-fit: cover;\n}\n\n.videoAttachment {\n max-width: 100%;\n border-radius: var(--tempest-radius-md);\n}\n\n.voiceAttachment {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n}\n\n/*\n * The waveform is the difference between a voice note and a grey rectangle: it\n * is what tells somebody whether this is a word or a two-minute monologue.\n */\n.waveform {\n display: flex;\n align-items: flex-end;\n gap: 2px;\n height: 28px;\n}\n\n.waveform span {\n flex: 1 1 auto;\n min-width: 2px;\n border-radius: 1px;\n background-color: var(--tempest-primary);\n opacity: 0.7;\n}\n\n.fileAttachment {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n color: var(--tempest-text);\n text-decoration: none;\n}\n\n.fileName {\n overflow-wrap: anywhere;\n font-weight: var(--tempest-weight-medium);\n}\n\n.fileMeta {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.retry {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-danger);\n font: inherit;\n font-size: var(--tempest-text-xs);\n text-decoration: underline;\n cursor: pointer;\n}\n\n.typing {\n flex: 0 0 auto;\n margin: 0;\n padding: 0 var(--tempest-space-4) var(--tempest-space-2);\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n}\n\n.composer {\n display: flex;\n flex: 0 0 auto;\n align-items: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-top: 1px solid var(--tempest-border);\n}\n\n.field {\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: none;\n}\n\n.field:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.field:disabled {\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.composerActions {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.send {\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.send:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n@media (max-width: 480px) {\n .runBody {\n max-width: 88%;\n }\n}\n"],"mappings":";"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.module.js","names":[],"sources":["../../../src/components/Chat/Chat.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n height: var(--tempest-chat-height, 100%);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n flex: 0 0 auto;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.thread {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--tempest-space-3);\n min-height: 0;\n padding: var(--tempest-space-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.thread:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -2px;\n}\n\n.day {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.day::before,\n.day::after {\n flex: 1 1 auto;\n height: 1px;\n background-color: var(--tempest-border);\n content: \"\";\n}\n\n.dayLabel {\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n text-transform: capitalize;\n}\n\n.run {\n display: flex;\n gap: var(--tempest-space-3);\n align-items: flex-start;\n max-width: 100%;\n}\n\n/*\n * Own messages mirror the row instead of moving to a second column: the avatar,\n * the name and the bubbles keep the same source order, so a screen reader still\n * reads \"who, then what\" while the eye reads it from the other side.\n */\n.ownRun {\n flex-direction: row-reverse;\n}\n\n.avatar {\n flex: 0 0 auto;\n}\n\n.runBody {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n max-width: min(78%, 42rem);\n}\n\n.ownRun .runBody {\n align-items: flex-end;\n}\n\n.author {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-medium);\n}\n\n.bubbles {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.bubbleRow {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.ownRun .bubbleRow {\n flex-direction: row-reverse;\n}\n\n.bubble {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n}\n\n.ownBubble {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n/*\n * A failed message keeps its text readable and states the failure at the border\n * and in the meta row. Tinting the whole bubble danger-red would make the message\n * itself hard to read — and re-reading it is exactly what somebody does before\n * deciding to retry.\n */\n.failedBubble {\n border-color: var(--tempest-danger);\n background-color: var(--tempest-danger-bg);\n color: var(--tempest-text);\n}\n\n.body {\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n/*\n * The timestamp uses the muted token, not the subtle one, and switches to the\n * bubble's own foreground when the bubble is tinted.\n *\n * `--tempest-text-subtle` is solved against the page and surface backgrounds. On\n * `--tempest-primary-soft` it is a different composite, and the real browser\n * measured it below the 4.5:1 text floor — the same trap the syntax tokens hit.\n * Size is what de-emphasises the meta row here; colour still has to pass.\n */\n.meta {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.ownBubble .meta {\n color: var(--tempest-primary-on-soft);\n}\n\n.status {\n display: inline-flex;\n align-items: center;\n}\n\n.statusFailed {\n color: var(--tempest-danger);\n font-weight: var(--tempest-weight-bold);\n}\n\n/*\n * A bubble row carries more than a bubble now: the actions button sits beside it\n * and the reaction chips hang under it, so the row wraps and the chips are given\n * the whole width to fall onto.\n */\n.bubbleRow {\n flex-wrap: wrap;\n}\n\n.reactions {\n display: flex;\n flex-basis: 100%;\n flex-wrap: wrap;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ownRun .reactions {\n justify-content: flex-end;\n}\n\n.reaction {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: 0 var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full, 999px);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-xs);\n line-height: 1.8;\n cursor: pointer;\n}\n\n.reaction:disabled {\n cursor: default;\n}\n\n/*\n * Your own reaction is marked by a tinted chip and its own foreground, never by\n * `--tempest-text-subtle` over the tint: that token is solved against the page\n * background and fails the text floor on a tinted surface.\n */\n.reactionMine {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n font-weight: var(--tempest-weight-medium);\n}\n\n/*\n * The ⋮ button is always in the DOM — on touch there is no hover to reveal it,\n * and a control that only appears on hover is a control a phone does not have.\n * A fine pointer gets it faded until the row is hovered or it is focused.\n */\n.actionsButton {\n flex: 0 0 auto;\n padding: 0 var(--tempest-space-1);\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .actionsButton {\n opacity: 0;\n transition: var(--tempest-transition-opacity, opacity 120ms ease);\n }\n\n .bubbleRow:hover .actionsButton,\n .actionsButton:focus-visible {\n opacity: 1;\n }\n}\n\n/* The reply stub: a tinted strip with a bar on the side it is anchored to. */\n.quote {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 100%;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border-left: 3px solid var(--tempest-primary);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xs);\n text-align: left;\n}\n\n.quoteButton {\n border-top: none;\n border-right: none;\n border-bottom: none;\n font: inherit;\n font-size: var(--tempest-text-xs);\n cursor: pointer;\n}\n\n/*\n * The author of a quote is text, so it is coloured like text.\n *\n * `--tempest-primary` here measured **4.35:1** against `--tempest-surface-2` in a\n * real browser — below the 4.5:1 floor for a 12px label, and invisible to the\n * jsdom axe sweep, which disables `color-contrast` because nothing is painted.\n * The brand still marks the quote: it is the bar down the side, which is a\n * non-text indicator and only owes 3:1.\n */\n.quoteAuthor {\n color: var(--tempest-text);\n font-weight: var(--tempest-weight-medium);\n}\n\n.quoteText {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n/*\n * A revoked quote reads as absent, which is the point: the text of a deleted\n * message must not survive inside the reply to it.\n */\n.quoteRevoked {\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.tombstone {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.deletedBubble {\n border-style: dashed;\n background-color: transparent;\n}\n\n.edited {\n font-style: italic;\n}\n\n/* Read by everyone is the only state that turns the ticks. */\n.statusRead {\n color: var(--tempest-info, var(--tempest-primary));\n}\n\n.attachments {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n max-width: 320px;\n}\n\n/* Holds the row's height while the attachments chunk is still loading. */\n.attachmentsFallback {\n min-height: var(--tempest-space-8, 2rem);\n}\n\n.imageAttachment {\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-md);\n background: none;\n line-height: 0;\n cursor: pointer;\n}\n\n.imageAttachment img {\n max-width: 100%;\n max-height: 260px;\n border-radius: var(--tempest-radius-md);\n object-fit: cover;\n}\n\n.videoAttachment {\n max-width: 100%;\n border-radius: var(--tempest-radius-md);\n}\n\n.voiceAttachment {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n}\n\n/*\n * The waveform is the difference between a voice note and a grey rectangle: it\n * is what tells somebody whether this is a word or a two-minute monologue.\n */\n.waveform {\n display: flex;\n align-items: flex-end;\n gap: 2px;\n height: 28px;\n}\n\n.waveform span {\n flex: 1 1 auto;\n min-width: 2px;\n border-radius: 1px;\n background-color: var(--tempest-primary);\n opacity: 0.7;\n}\n\n.fileAttachment {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n color: var(--tempest-text);\n text-decoration: none;\n}\n\n.fileName {\n overflow-wrap: anywhere;\n font-weight: var(--tempest-weight-medium);\n}\n\n.fileMeta {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.retry {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-danger);\n font: inherit;\n font-size: var(--tempest-text-xs);\n text-decoration: underline;\n cursor: pointer;\n}\n\n.typing {\n flex: 0 0 auto;\n margin: 0;\n padding: 0 var(--tempest-space-4) var(--tempest-space-2);\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n}\n\n.composer {\n display: flex;\n flex: 0 0 auto;\n align-items: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-top: 1px solid var(--tempest-border);\n}\n\n.field {\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: none;\n}\n\n.field:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: -1px;\n}\n\n.field:disabled {\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.composerActions {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.send {\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.send:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n@media (max-width: 480px) {\n .runBody {\n max-width: 88%;\n }\n}\n"],"mappings":";"}
|
|
1
|
+
{"version":3,"file":"Chat.module.js","names":[],"sources":["../../../src/components/Chat/Chat.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n height: var(--tempest-chat-height, 100%);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n flex: 0 0 auto;\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.thread {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--tempest-space-3);\n min-height: 0;\n padding: var(--tempest-space-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.thread:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.day {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-3);\n}\n\n.day::before,\n.day::after {\n flex: 1 1 auto;\n height: 1px;\n background-color: var(--tempest-border);\n content: \"\";\n}\n\n.dayLabel {\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n text-transform: capitalize;\n}\n\n.run {\n display: flex;\n gap: var(--tempest-space-3);\n align-items: flex-start;\n max-width: 100%;\n}\n\n/*\n * Own messages mirror the row instead of moving to a second column: the avatar,\n * the name and the bubbles keep the same source order, so a screen reader still\n * reads \"who, then what\" while the eye reads it from the other side.\n */\n.ownRun {\n flex-direction: row-reverse;\n}\n\n.avatar {\n flex: 0 0 auto;\n}\n\n.runBody {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n max-width: min(78%, 42rem);\n}\n\n.ownRun .runBody {\n align-items: flex-end;\n}\n\n.author {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-medium);\n}\n\n.bubbles {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.bubbleRow {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.ownRun .bubbleRow {\n flex-direction: row-reverse;\n}\n\n.bubble {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-surface);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n}\n\n.ownBubble {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n/*\n * A failed message keeps its text readable and states the failure at the border\n * and in the meta row. Tinting the whole bubble danger-red would make the message\n * itself hard to read — and re-reading it is exactly what somebody does before\n * deciding to retry.\n */\n.failedBubble {\n border-color: var(--tempest-danger);\n background-color: var(--tempest-danger-bg);\n color: var(--tempest-text);\n}\n\n.body {\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n/*\n * The timestamp uses the muted token, not the subtle one, and switches to the\n * bubble's own foreground when the bubble is tinted.\n *\n * `--tempest-text-subtle` is solved against the page and surface backgrounds. On\n * `--tempest-primary-soft` it is a different composite, and the real browser\n * measured it below the 4.5:1 text floor — the same trap the syntax tokens hit.\n * Size is what de-emphasises the meta row here; colour still has to pass.\n */\n.meta {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.ownBubble .meta {\n color: var(--tempest-primary-on-soft);\n}\n\n.status {\n display: inline-flex;\n align-items: center;\n}\n\n.statusFailed {\n color: var(--tempest-danger);\n font-weight: var(--tempest-weight-bold);\n}\n\n/*\n * A bubble row carries more than a bubble now: the actions button sits beside it\n * and the reaction chips hang under it, so the row wraps and the chips are given\n * the whole width to fall onto.\n */\n.bubbleRow {\n flex-wrap: wrap;\n}\n\n.reactions {\n display: flex;\n flex-basis: 100%;\n flex-wrap: wrap;\n gap: var(--tempest-space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ownRun .reactions {\n justify-content: flex-end;\n}\n\n.reaction {\n display: inline-flex;\n align-items: center;\n gap: var(--tempest-space-1);\n padding: 0 var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full, 999px);\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n font: inherit;\n font-size: var(--tempest-text-xs);\n line-height: 1.8;\n cursor: pointer;\n}\n\n.reaction:disabled {\n cursor: default;\n}\n\n/*\n * Your own reaction is marked by a tinted chip and its own foreground, never by\n * `--tempest-text-subtle` over the tint: that token is solved against the page\n * background and fails the text floor on a tinted surface.\n */\n.reactionMine {\n border-color: transparent;\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n font-weight: var(--tempest-weight-medium);\n}\n\n/*\n * The ⋮ button is always in the DOM — on touch there is no hover to reveal it,\n * and a control that only appears on hover is a control a phone does not have.\n * A fine pointer gets it faded until the row is hovered or it is focused.\n */\n.actionsButton {\n flex: 0 0 auto;\n padding: 0 var(--tempest-space-1);\n border: none;\n background: none;\n color: var(--tempest-text-muted);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .actionsButton {\n opacity: 0;\n transition: var(--tempest-transition-opacity, opacity 120ms ease);\n }\n\n .bubbleRow:hover .actionsButton,\n .actionsButton:focus-visible {\n opacity: 1;\n }\n}\n\n/* The reply stub: a tinted strip with a bar on the side it is anchored to. */\n.quote {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 100%;\n padding: var(--tempest-space-1) var(--tempest-space-2);\n border-left: 3px solid var(--tempest-primary);\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xs);\n text-align: left;\n}\n\n.quoteButton {\n border-top: none;\n border-right: none;\n border-bottom: none;\n font: inherit;\n font-size: var(--tempest-text-xs);\n cursor: pointer;\n}\n\n/*\n * The author of a quote is text, so it is coloured like text.\n *\n * `--tempest-primary` here measured **4.35:1** against `--tempest-surface-2` in a\n * real browser — below the 4.5:1 floor for a 12px label, and invisible to the\n * jsdom axe sweep, which disables `color-contrast` because nothing is painted.\n * The brand still marks the quote: it is the bar down the side, which is a\n * non-text indicator and only owes 3:1.\n */\n.quoteAuthor {\n color: var(--tempest-text);\n font-weight: var(--tempest-weight-medium);\n}\n\n.quoteText {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n/*\n * A revoked quote reads as absent, which is the point: the text of a deleted\n * message must not survive inside the reply to it.\n */\n.quoteRevoked {\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.tombstone {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-1);\n color: var(--tempest-text-muted);\n font-style: italic;\n}\n\n.deletedBubble {\n border-style: dashed;\n background-color: transparent;\n}\n\n.edited {\n font-style: italic;\n}\n\n/* Read by everyone is the only state that turns the ticks. */\n.statusRead {\n color: var(--tempest-info, var(--tempest-primary));\n}\n\n.attachments {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n max-width: 320px;\n}\n\n/* Holds the row's height while the attachments chunk is still loading. */\n.attachmentsFallback {\n min-height: var(--tempest-space-8, 2rem);\n}\n\n.imageAttachment {\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-md);\n background: none;\n line-height: 0;\n cursor: pointer;\n}\n\n.imageAttachment img {\n max-width: 100%;\n max-height: 260px;\n border-radius: var(--tempest-radius-md);\n object-fit: cover;\n}\n\n.videoAttachment {\n max-width: 100%;\n border-radius: var(--tempest-radius-md);\n}\n\n.voiceAttachment {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n}\n\n/*\n * The waveform is the difference between a voice note and a grey rectangle: it\n * is what tells somebody whether this is a word or a two-minute monologue.\n */\n.waveform {\n display: flex;\n align-items: flex-end;\n gap: 2px;\n height: 28px;\n}\n\n.waveform span {\n flex: 1 1 auto;\n min-width: 2px;\n border-radius: 1px;\n background-color: var(--tempest-primary);\n opacity: 0.7;\n}\n\n.fileAttachment {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--tempest-space-2);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n color: var(--tempest-text);\n text-decoration: none;\n}\n\n.fileName {\n overflow-wrap: anywhere;\n font-weight: var(--tempest-weight-medium);\n}\n\n.fileMeta {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n font-variant-numeric: tabular-nums;\n}\n\n.retry {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-danger);\n font: inherit;\n font-size: var(--tempest-text-xs);\n text-decoration: underline;\n cursor: pointer;\n}\n\n.typing {\n flex: 0 0 auto;\n margin: 0;\n padding: 0 var(--tempest-space-4) var(--tempest-space-2);\n color: var(--tempest-text-subtle);\n font-size: var(--tempest-text-xs);\n}\n\n.composer {\n display: flex;\n flex: 0 0 auto;\n align-items: flex-end;\n gap: var(--tempest-space-2);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-top: 1px solid var(--tempest-border);\n}\n\n.field {\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-bg);\n color: inherit;\n font: inherit;\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n resize: none;\n}\n\n.field:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-width) * -1);\n}\n\n.field:disabled {\n background-color: var(--tempest-surface-2);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.composerActions {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n}\n\n.send {\n padding: var(--tempest-space-2) var(--tempest-space-4);\n border: none;\n border-radius: var(--tempest-radius-md);\n background-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n font: inherit;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n cursor: pointer;\n}\n\n.send:disabled {\n background-color: var(--tempest-surface-3);\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n@media (max-width: 480px) {\n .runBody {\n max-width: 88%;\n }\n}\n"],"mappings":";"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../utils/cn.cjs"),t=require("../Portal/Portal.cjs"),n=require("../Portal/anchor-position.cjs"),r=require("../Select/CaretIcon.cjs"),i=require("./Combobox.module.cjs");let
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("../Portal/Portal.cjs"),n=require("../Portal/anchor-position.cjs"),r=require("../Select/CaretIcon.cjs"),i=require("./Combobox.module.cjs"),a=require("./use-listbox-dismiss.cjs");let o=require("react"),s=require("react/jsx-runtime");var c=4;function l(e,t){return!t||e.label.toLowerCase().includes(t.toLowerCase())}function u({options:u,value:d,onChange:f,label:p,placeholder:m=`Selecione`,helperText:h,error:g,disabled:_,filter:v=l,emptyMessage:y=`Nenhuma opção encontrada`,portal:b=!0,className:x}){let S=(0,o.useId)(),C=(0,o.useRef)(null),w=(0,o.useRef)(null),[T,E]=(0,o.useState)(!1),[D,O]=(0,o.useState)(``),[k,A]=(0,o.useState)(0),[j,M]=(0,o.useState)(null),[N,P]=(0,o.useState)(null),F=n.useAnchorPosition({anchor:j,floating:N,side:`bottom`,align:`start`,offset:c,enabled:b&&T,matchWidth:!0}),I=(0,o.useMemo)(()=>u.find(e=>e.value===d)?.label??``,[u,d]),L=(0,o.useMemo)(()=>u.filter(e=>v(e,D)),[u,v,D]),R=(0,o.useCallback)(()=>{E(!1),O(``),A(0)},[]),z=(0,o.useCallback)(e=>{e.disabled||(f(e.value),R())},[f,R]),{onInputBlur:B,onListMouseDown:V}=a.useListboxDismiss({open:T,rootRef:C,listNode:N,onDismiss:R}),H=e=>`${S}-option-${e}`,U=T?L[k]:void 0,W=e=>{if(e.key===`ArrowDown`)e.preventDefault(),E(!0),A(e=>Math.min(L.length-1,e+1));else if(e.key===`ArrowUp`)e.preventDefault(),A(e=>Math.max(0,e-1));else if(e.key===`Enter`){e.preventDefault();let t=L[k];t&&z(t)}else e.key===`Escape`&&(T&&e.preventDefault(),R())},G=(0,s.jsx)(`ul`,{ref:P,id:`${S}-listbox`,role:`listbox`,className:e.cn(i.default.menu,b&&i.default.portalled),style:F,onMouseDown:V,children:L.length===0?(0,s.jsx)(`li`,{className:i.default.empty,children:y}):L.map((t,n)=>(0,s.jsx)(`li`,{id:H(n),role:`option`,"aria-selected":t.value===d,className:e.cn(i.default.option,n===k&&i.default.active,t.value===d&&i.default.selected),onMouseEnter:()=>A(n),onMouseDown:()=>z(t),children:t.label},t.value))});return(0,s.jsxs)(`div`,{ref:C,className:e.cn(i.default.wrapper,g&&i.default.error,x),children:[p&&(0,s.jsx)(`label`,{htmlFor:S,className:i.default.label,children:p}),(0,s.jsxs)(`div`,{ref:M,className:i.default.field,children:[(0,s.jsx)(`input`,{id:S,ref:w,type:`text`,role:`combobox`,"aria-expanded":T,"aria-controls":`${S}-listbox`,"aria-autocomplete":`list`,"aria-activedescendant":U?H(k):void 0,className:i.default.input,placeholder:m,disabled:_,value:T?D:I,onFocus:()=>E(!0),onChange:e=>{O(e.target.value),E(!0),A(0)},onKeyDown:W,onBlur:B}),(0,s.jsx)(`span`,{className:i.default.caret,"aria-hidden":!0,children:(0,s.jsx)(r.CaretIcon,{})})]}),T&&(b?(0,s.jsx)(t.Portal,{children:G}):G),g?(0,s.jsx)(`span`,{className:i.default.errorText,children:g}):h?(0,s.jsx)(`span`,{className:i.default.helper,children:h}):null]})}exports.Combobox=u;
|
|
2
2
|
//# sourceMappingURL=Combobox.cjs.map
|