@flamingo-stack/openframe-frontend-core 0.0.222 → 0.0.223
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/dist/{chunk-AIKPR6BE.js → chunk-4VHWSAQR.js} +6069 -5235
- package/dist/chunk-4VHWSAQR.js.map +1 -0
- package/dist/{chunk-GMNE7P7V.cjs → chunk-4WBVMIKQ.cjs} +26 -26
- package/dist/{chunk-GMNE7P7V.cjs.map → chunk-4WBVMIKQ.cjs.map} +1 -1
- package/dist/{chunk-QYRV6MKX.js → chunk-53EA4QPZ.js} +13 -7
- package/dist/chunk-53EA4QPZ.js.map +1 -0
- package/dist/{chunk-4JOWZLEL.cjs → chunk-7TKYFZ3L.cjs} +7 -7
- package/dist/{chunk-4JOWZLEL.cjs.map → chunk-7TKYFZ3L.cjs.map} +1 -1
- package/dist/{chunk-IZA5WF44.cjs → chunk-ABBU7QOM.cjs} +12 -12
- package/dist/{chunk-IZA5WF44.cjs.map → chunk-ABBU7QOM.cjs.map} +1 -1
- package/dist/{chunk-KM4KK2A6.cjs → chunk-ENDUMC7Z.cjs} +2558 -1724
- package/dist/chunk-ENDUMC7Z.cjs.map +1 -0
- package/dist/{chunk-CCSEXVI4.js → chunk-GYYGA24C.js} +2 -2
- package/dist/{chunk-RMOHKAHA.js → chunk-ISWWP2BH.js} +3 -3
- package/dist/{chunk-QNYH3WUU.cjs → chunk-JUWPBMQM.cjs} +13 -7
- package/dist/chunk-JUWPBMQM.cjs.map +1 -0
- package/dist/{chunk-A2SFHYVF.cjs → chunk-KXLTWANQ.cjs} +10 -10
- package/dist/{chunk-A2SFHYVF.cjs.map → chunk-KXLTWANQ.cjs.map} +1 -1
- package/dist/{chunk-ND24XSVT.js → chunk-TA6Z2AKD.js} +3 -3
- package/dist/chunk-TA6Z2AKD.js.map +1 -0
- package/dist/{chunk-HRIAZQ5D.js → chunk-WOKB6RJ7.js} +3 -3
- package/dist/components/chat/chat-archive-page.d.ts.map +1 -1
- package/dist/components/chat/chat-composer.d.ts.map +1 -1
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-skeleton.d.ts +19 -4
- package/dist/components/chat/chat-message-skeleton.d.ts.map +1 -1
- package/dist/components/chat/chat-panel-header-mobile.d.ts +24 -0
- package/dist/components/chat/chat-panel-header-mobile.d.ts.map +1 -0
- package/dist/components/chat/chat-panel-header.d.ts +6 -0
- package/dist/components/chat/chat-panel-header.d.ts.map +1 -1
- package/dist/components/chat/chat-quick-action-row.d.ts +31 -0
- package/dist/components/chat/chat-quick-action-row.d.ts.map +1 -0
- package/dist/components/chat/embeddable-chat.d.ts +27 -0
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
- package/dist/components/chat/entity-cards/dispatch.d.ts +14 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
- package/dist/components/chat/entity-cards/github-activity-card.d.ts +10 -1
- package/dist/components/chat/entity-cards/github-activity-card.d.ts.map +1 -1
- package/dist/components/chat/guide-welcome.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +9 -0
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-slash-commands.d.ts +26 -0
- package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +12 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-unified-chat.d.ts +12 -0
- package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +9 -3
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +8 -2
- package/dist/components/chat/mingo-chat-history.d.ts +10 -0
- package/dist/components/chat/mingo-chat-history.d.ts.map +1 -1
- package/dist/components/chat/mingo-info-card.d.ts +63 -0
- package/dist/components/chat/mingo-info-card.d.ts.map +1 -0
- package/dist/components/chat/mingo-welcome.d.ts +14 -1
- package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
- package/dist/components/chat/types/chat.types.d.ts +6 -0
- package/dist/components/chat/types/chat.types.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +30 -0
- package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/features/index.cjs +3 -3
- package/dist/components/features/index.js +2 -2
- package/dist/components/index.cjs +110 -104
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +36 -30
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/app-layout-drawer.d.ts +7 -0
- package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/onboarding-guides/index.cjs +26 -26
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/tickets/index.cjs +67 -67
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/actions-menu.d.ts +9 -0
- package/dist/components/ui/actions-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-button.d.ts +2 -2
- package/dist/components/ui/dropdown-button.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +9 -3
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +8 -2
- package/dist/components/ui/modal-v2.d.ts.map +1 -1
- package/dist/components/ui/more-actions-menu.d.ts +13 -0
- package/dist/components/ui/more-actions-menu.d.ts.map +1 -1
- package/dist/components/ui/square-avatar.d.ts +4 -0
- package/dist/components/ui/square-avatar.d.ts.map +1 -1
- package/dist/components/ui/textarea.d.ts.map +1 -1
- package/dist/hooks/index.cjs +2 -2
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/ui/use-auto-limit-tags.d.ts +7 -1
- package/dist/hooks/ui/use-auto-limit-tags.d.ts.map +1 -1
- package/dist/index.cjs +9 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -2
- package/package.json +1 -1
- package/src/components/chat/chat-archive-page.tsx +32 -7
- package/src/components/chat/chat-composer.tsx +6 -2
- package/src/components/chat/chat-message-enhanced.tsx +24 -7
- package/src/components/chat/chat-message-list.tsx +1 -1
- package/src/components/chat/chat-message-skeleton.tsx +60 -60
- package/src/components/chat/chat-panel-header-mobile.tsx +94 -0
- package/src/components/chat/chat-panel-header.tsx +78 -50
- package/src/components/chat/chat-quick-action-row.tsx +146 -0
- package/src/components/chat/embeddable-chat.tsx +140 -45
- package/src/components/chat/entity-cards/dispatch.tsx +770 -232
- package/src/components/chat/entity-cards/github-activity-card.tsx +9 -3
- package/src/components/chat/guide-welcome.tsx +11 -8
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +80 -7
- package/src/components/chat/hooks/use-slash-commands.ts +39 -0
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +49 -45
- package/src/components/chat/hooks/use-unified-chat.ts +31 -8
- package/src/components/chat/mingo-chat-history.tsx +118 -36
- package/src/components/chat/mingo-info-card.tsx +214 -0
- package/src/components/chat/mingo-welcome.tsx +89 -36
- package/src/components/chat/types/chat.types.ts +4 -0
- package/src/components/chat/types/unified-chat-state.types.ts +35 -0
- package/src/components/chat/utils/process-historical-messages.ts +8 -0
- package/src/components/content-loading-container.tsx +1 -1
- package/src/components/empty-state.tsx +3 -3
- package/src/components/faq-accordion.tsx +2 -2
- package/src/components/features/changelog-manager.tsx +2 -2
- package/src/components/features/highlight-config-section.tsx +2 -2
- package/src/components/features/og-editor-preview.tsx +3 -3
- package/src/components/features/release-media-manager.tsx +2 -2
- package/src/components/loading/card-skeleton.tsx +3 -3
- package/src/components/loading/device-card-skeleton.tsx +1 -1
- package/src/components/loading/margin-report-skeleton.tsx +2 -2
- package/src/components/loading/organization-card-skeleton.tsx +1 -1
- package/src/components/loading/organization-icon-skeleton.tsx +1 -1
- package/src/components/loading/page-layout-skeleton.tsx +9 -9
- package/src/components/loading/users-grid-skeleton.tsx +2 -2
- package/src/components/logs-list.tsx +1 -1
- package/src/components/media-carousel.tsx +1 -1
- package/src/components/navigation/app-layout-drawer.tsx +70 -6
- package/src/components/open-source-features.tsx +2 -2
- package/src/components/ui/actions-menu.tsx +36 -13
- package/src/components/ui/allowed-domains-input.tsx +3 -3
- package/src/components/ui/cursor-pagination.tsx +1 -1
- package/src/components/ui/dropdown-button.tsx +6 -6
- package/src/components/ui/info-row.tsx +2 -2
- package/src/components/ui/modal-v2.tsx +8 -1
- package/src/components/ui/more-actions-menu.tsx +13 -0
- package/src/components/ui/square-avatar.tsx +6 -1
- package/src/components/ui/tags-input.tsx +1 -1
- package/src/components/ui/textarea.tsx +18 -4
- package/src/components/vendor-icon.tsx +1 -1
- package/src/components/vendor-tag.tsx +1 -1
- package/src/components/why-it-matters.tsx +1 -1
- package/src/hooks/ui/use-auto-limit-tags.ts +22 -8
- package/src/stories/ActionsMenu.stories.tsx +256 -0
- package/src/stories/AppLayoutSidebar.stories.tsx +6 -0
- package/src/stories/Board.stories.tsx +1 -1
- package/src/stories/ChatMingoInfoCards.stories.tsx +748 -0
- package/src/stories/ChatTicketList.stories.tsx +1 -1
- package/src/stories/DataTable.stories.tsx +17 -13
- package/src/stories/EmbeddableChat.stories.tsx +233 -1
- package/src/stories/MingoInfoCard.stories.tsx +193 -0
- package/src/stories/MingoOnboardingCard.stories.tsx +1 -1
- package/src/stories/Modal.stories.tsx +1 -0
- package/src/stories/NotificationDrawer.stories.tsx +14 -3
- package/src/stories/PageActions.stories.tsx +4 -4
- package/src/stories/PageContainer.stories.tsx +5 -5
- package/src/stories/PageLayout.stories.tsx +1 -1
- package/src/stories/TabSelector.stories.tsx +2 -2
- package/src/stories/Tag.stories.tsx +10 -5
- package/src/stories/TicketInfoSection.stories.tsx +23 -11
- package/src/stories/Toaster.stories.tsx +5 -5
- package/src/stories/__fixtures__/chat-card-decorator.tsx +44 -0
- package/dist/chunk-AIKPR6BE.js.map +0 -1
- package/dist/chunk-KM4KK2A6.cjs.map +0 -1
- package/dist/chunk-ND24XSVT.js.map +0 -1
- package/dist/chunk-QNYH3WUU.cjs.map +0 -1
- package/dist/chunk-QYRV6MKX.js.map +0 -1
- package/src/stories/.TicketDescriptionViewer.stories.md +0 -39
- package/src/stories/.TicketKnowledgeBaseList.stories.md +0 -36
- package/src/stories/TicketDescriptionViewer.stories.tsx +0 -70
- package/src/stories/TicketKnowledgeBaseList.stories.tsx +0 -51
- /package/dist/{chunk-CCSEXVI4.js.map → chunk-GYYGA24C.js.map} +0 -0
- /package/dist/{chunk-RMOHKAHA.js.map → chunk-ISWWP2BH.js.map} +0 -0
- /package/dist/{chunk-HRIAZQ5D.js.map → chunk-WOKB6RJ7.js.map} +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
4
|
+
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
4
5
|
import { Check } from "lucide-react";
|
|
5
6
|
import Link from "../../embed-shims/next-link";
|
|
6
|
-
import React, { useCallback
|
|
7
|
+
import React, { useCallback } from "react";
|
|
7
8
|
import { Chevron02RightIcon, Ellipsis01Icon } from "../icons-v2-generated";
|
|
8
9
|
import { cn } from "../../utils/cn";
|
|
9
10
|
import { Button } from "./button";
|
|
@@ -31,6 +32,8 @@ export interface ActionsMenuItem {
|
|
|
31
32
|
type?: "item" | "checkbox" | "submenu" | "separator";
|
|
32
33
|
checked?: boolean;
|
|
33
34
|
submenu?: ActionsMenuItem[];
|
|
35
|
+
/** Render the row in the error/destructive color (label + icon). */
|
|
36
|
+
danger?: boolean;
|
|
34
37
|
/** Optional URL for navigation items */
|
|
35
38
|
href?: string;
|
|
36
39
|
/**
|
|
@@ -59,12 +62,12 @@ interface MenuItemProps {
|
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
const ROW_CLASSES =
|
|
62
|
-
"flex flex-1 min-w-0 items-center gap-
|
|
65
|
+
"flex flex-1 min-w-0 items-center gap-[var(--spacing-system-xsf)] p-[var(--spacing-system-s)] cursor-pointer transition-colors bg-ods-bg outline-none";
|
|
63
66
|
const WRAPPER_CLASSES =
|
|
64
67
|
"relative flex items-stretch border-b border-ods-border last:border-b-0";
|
|
65
68
|
|
|
66
69
|
const SECONDARY_ACTION_CLASSES =
|
|
67
|
-
"flex
|
|
70
|
+
"flex p-[var(--spacing-system-s)] shrink-0 items-center justify-center self-stretch border-l border-ods-border transition-colors hover:bg-ods-bg-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-focus [&_svg]:w-4 [&_svg]:h-4 md:[&_svg]:w-6 md:[&_svg]:h-6";
|
|
68
71
|
|
|
69
72
|
const SecondaryAction: React.FC<{ action: ActionsMenuItemIconAction }> = ({ action }) => {
|
|
70
73
|
const handleClick = useCallback(
|
|
@@ -173,7 +176,7 @@ const MenuItem: React.FC<MenuItemProps> = ({ item, onItemClick }) => {
|
|
|
173
176
|
|
|
174
177
|
const subTriggerClasses = cn(
|
|
175
178
|
itemClasses,
|
|
176
|
-
"data-[state=open]:bg-
|
|
179
|
+
"data-[state=open]:bg-ods-bg-active focus:bg-ods-bg-hover",
|
|
177
180
|
);
|
|
178
181
|
|
|
179
182
|
const renderAsLink =
|
|
@@ -184,7 +187,8 @@ const MenuItem: React.FC<MenuItemProps> = ({ item, onItemClick }) => {
|
|
|
184
187
|
{item.icon && (
|
|
185
188
|
<div
|
|
186
189
|
className={cn(
|
|
187
|
-
"w-6 h-6 flex-shrink-0 flex items-center justify-center",
|
|
190
|
+
"w-4 h-4 md:w-6 md:h-6 flex-shrink-0 flex items-center justify-center",
|
|
191
|
+
item.danger && "text-ods-error",
|
|
188
192
|
item.disabled && "opacity-50",
|
|
189
193
|
)}
|
|
190
194
|
>
|
|
@@ -194,8 +198,12 @@ const MenuItem: React.FC<MenuItemProps> = ({ item, onItemClick }) => {
|
|
|
194
198
|
|
|
195
199
|
<span
|
|
196
200
|
className={cn(
|
|
197
|
-
"flex-1 text-
|
|
198
|
-
item.disabled
|
|
201
|
+
"flex-1 text-h4 font-medium leading-6",
|
|
202
|
+
item.disabled
|
|
203
|
+
? "text-ods-text-secondary"
|
|
204
|
+
: item.danger
|
|
205
|
+
? "text-ods-error"
|
|
206
|
+
: "text-ods-text-primary",
|
|
199
207
|
)}
|
|
200
208
|
>
|
|
201
209
|
{item.label}
|
|
@@ -204,20 +212,20 @@ const MenuItem: React.FC<MenuItemProps> = ({ item, onItemClick }) => {
|
|
|
204
212
|
{item.type === "checkbox" && (
|
|
205
213
|
<div
|
|
206
214
|
className={cn(
|
|
207
|
-
"w-6 h-6 flex items-center justify-center rounded-md transition-colors",
|
|
215
|
+
"w-4 h-4 md:w-6 md:h-6 flex items-center justify-center rounded-md transition-colors",
|
|
208
216
|
item.checked
|
|
209
|
-
? "bg-
|
|
217
|
+
? "bg-ods-accent"
|
|
210
218
|
: "border-2 border-ods-border bg-transparent",
|
|
211
219
|
)}
|
|
212
220
|
>
|
|
213
221
|
{item.checked && (
|
|
214
|
-
<Check className="w-4 h-4 text-
|
|
222
|
+
<Check className="w-3 h-3 md:w-4 md:h-4 text-ods-text-on-accent" strokeWidth={3} />
|
|
215
223
|
)}
|
|
216
224
|
</div>
|
|
217
225
|
)}
|
|
218
226
|
|
|
219
227
|
{item.type === "submenu" && (
|
|
220
|
-
<Chevron02RightIcon className="w-6 h-6 text-ods-text-secondary" />
|
|
228
|
+
<Chevron02RightIcon className="w-4 h-4 md:w-6 md:h-6 text-ods-text-secondary" />
|
|
221
229
|
)}
|
|
222
230
|
</>
|
|
223
231
|
);
|
|
@@ -331,6 +339,13 @@ export interface ActionsMenuDropdownProps extends ActionsMenuProps {
|
|
|
331
339
|
align?: "start" | "center" | "end";
|
|
332
340
|
side?: "top" | "right" | "bottom" | "left";
|
|
333
341
|
sideOffset?: number;
|
|
342
|
+
/** Controlled open state. Pair with `onOpenChange`. Uncontrolled by default. */
|
|
343
|
+
open?: boolean;
|
|
344
|
+
/** Open-state change handler (also fires when an item closes the menu). */
|
|
345
|
+
onOpenChange?: (open: boolean) => void;
|
|
346
|
+
/** Forwarded to the dropdown content — e.g. `e.preventDefault()` to stop
|
|
347
|
+
* Radix returning focus (and its focus ring) to the trigger on close. */
|
|
348
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
334
349
|
}
|
|
335
350
|
|
|
336
351
|
export const ActionsMenuDropdown: React.FC<ActionsMenuDropdownProps> = ({
|
|
@@ -345,8 +360,15 @@ export const ActionsMenuDropdown: React.FC<ActionsMenuDropdownProps> = ({
|
|
|
345
360
|
align = "end",
|
|
346
361
|
side = "bottom",
|
|
347
362
|
sideOffset = 6,
|
|
363
|
+
open: openProp,
|
|
364
|
+
onOpenChange,
|
|
365
|
+
onCloseAutoFocus,
|
|
348
366
|
}) => {
|
|
349
|
-
const [open, setOpen] =
|
|
367
|
+
const [open = false, setOpen] = useControllableState({
|
|
368
|
+
prop: openProp,
|
|
369
|
+
defaultProp: false,
|
|
370
|
+
onChange: onOpenChange,
|
|
371
|
+
});
|
|
350
372
|
|
|
351
373
|
const handleItemClick = useCallback(
|
|
352
374
|
(item: ActionsMenuItem) => {
|
|
@@ -355,7 +377,7 @@ export const ActionsMenuDropdown: React.FC<ActionsMenuDropdownProps> = ({
|
|
|
355
377
|
setOpen(false);
|
|
356
378
|
}
|
|
357
379
|
},
|
|
358
|
-
[onItemClick],
|
|
380
|
+
[onItemClick, setOpen],
|
|
359
381
|
);
|
|
360
382
|
|
|
361
383
|
return (
|
|
@@ -382,6 +404,7 @@ export const ActionsMenuDropdown: React.FC<ActionsMenuDropdownProps> = ({
|
|
|
382
404
|
align={align}
|
|
383
405
|
side={side}
|
|
384
406
|
sideOffset={sideOffset}
|
|
407
|
+
onCloseAutoFocus={onCloseAutoFocus}
|
|
385
408
|
className={cn(
|
|
386
409
|
"p-0 border-0 bg-transparent shadow-none overflow-visible",
|
|
387
410
|
contentClassName,
|
|
@@ -88,7 +88,7 @@ const AllowedDomainsInput = React.forwardRef<HTMLDivElement, AllowedDomainsInput
|
|
|
88
88
|
<Input
|
|
89
89
|
value={domain}
|
|
90
90
|
disabled
|
|
91
|
-
className="bg-
|
|
91
|
+
className="bg-ods-card border-ods-border rounded-[6px] flex-1"
|
|
92
92
|
/>
|
|
93
93
|
<Button
|
|
94
94
|
type="button"
|
|
@@ -114,7 +114,7 @@ const AllowedDomainsInput = React.forwardRef<HTMLDivElement, AllowedDomainsInput
|
|
|
114
114
|
onKeyDown={handleKeyDown}
|
|
115
115
|
placeholder={placeholder}
|
|
116
116
|
disabled={disabled}
|
|
117
|
-
className="bg-
|
|
117
|
+
className="bg-ods-card border-ods-border rounded-[6px] flex-1"
|
|
118
118
|
/>
|
|
119
119
|
</div>
|
|
120
120
|
|
|
@@ -128,7 +128,7 @@ const AllowedDomainsInput = React.forwardRef<HTMLDivElement, AllowedDomainsInput
|
|
|
128
128
|
onClick={addDomain}
|
|
129
129
|
disabled={disabled}
|
|
130
130
|
>
|
|
131
|
-
<PlusCircle className="h-5 w-5 text-
|
|
131
|
+
<PlusCircle className="h-5 w-5 text-ods-text-secondary" />
|
|
132
132
|
<span className="font-['DM_Sans'] font-bold text-base">Add Domain</span>
|
|
133
133
|
</button>
|
|
134
134
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { cn } from '../../utils/cn'
|
|
5
5
|
import { Chevron02DownIcon } from '../icons-v2-generated'
|
|
6
|
-
import {
|
|
6
|
+
import { ActionsMenuDropdown, type ActionsMenuItem } from './actions-menu'
|
|
7
7
|
|
|
8
8
|
export interface DropdownButtonProps {
|
|
9
9
|
/** Button label rendered next to the chevron. */
|
|
@@ -11,7 +11,7 @@ export interface DropdownButtonProps {
|
|
|
11
11
|
/** Optional leading icon rendered before the label. */
|
|
12
12
|
icon?: React.ReactNode
|
|
13
13
|
/** Items shown in the dropdown. */
|
|
14
|
-
items:
|
|
14
|
+
items: ActionsMenuItem[]
|
|
15
15
|
disabled?: boolean
|
|
16
16
|
className?: string
|
|
17
17
|
ariaLabel?: string
|
|
@@ -49,14 +49,14 @@ export function DropdownButton({
|
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
return (
|
|
52
|
-
<
|
|
53
|
-
|
|
52
|
+
<ActionsMenuDropdown
|
|
53
|
+
groups={[{ items }]}
|
|
54
54
|
open={open}
|
|
55
55
|
onOpenChange={handleOpenChange}
|
|
56
56
|
align={align}
|
|
57
57
|
side={side}
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
triggerAriaLabel={ariaLabel || label}
|
|
59
|
+
customTrigger={
|
|
60
60
|
<button
|
|
61
61
|
type="button"
|
|
62
62
|
disabled={disabled}
|
|
@@ -9,11 +9,11 @@ interface InfoRowProps {
|
|
|
9
9
|
export function InfoRow({ label, value, icon }: InfoRowProps) {
|
|
10
10
|
return (
|
|
11
11
|
<div className="flex gap-2 items-center w-full">
|
|
12
|
-
<div className="text-h4 text-
|
|
12
|
+
<div className="text-h4 text-ods-text-primary overflow-hidden text-ellipsis whitespace-nowrap">
|
|
13
13
|
{label}
|
|
14
14
|
</div>
|
|
15
15
|
<div className="flex-1 bg-[#3a3a3a] h-px min-h-px min-w-px" />
|
|
16
|
-
<div className="text-h4 text-
|
|
16
|
+
<div className="text-h4 text-ods-text-primary overflow-hidden text-ellipsis whitespace-nowrap flex items-center gap-1">
|
|
17
17
|
{value}
|
|
18
18
|
{icon}
|
|
19
19
|
</div>
|
|
@@ -82,7 +82,11 @@ const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
|
|
|
82
82
|
"absolute inset-0 bg-black/50 backdrop-blur-[2px] md:backdrop-blur-none",
|
|
83
83
|
"duration-200",
|
|
84
84
|
"data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
85
|
-
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0"
|
|
85
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
|
|
86
|
+
// Hold the hidden end-state until unmount so the backdrop doesn't
|
|
87
|
+
// flash back to full opacity when the animation finishes a frame
|
|
88
|
+
// before the unmount timeout fires.
|
|
89
|
+
"data-[state=closed]:fill-mode-forwards"
|
|
86
90
|
)}
|
|
87
91
|
onClick={onClose}
|
|
88
92
|
aria-hidden="true"
|
|
@@ -102,6 +106,9 @@ const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
|
|
|
102
106
|
"data-[state=open]:slide-in-from-bottom-4 md:data-[state=open]:slide-in-from-bottom-0 md:data-[state=open]:zoom-in-95",
|
|
103
107
|
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
|
|
104
108
|
"data-[state=closed]:slide-out-to-bottom-4 md:data-[state=closed]:slide-out-to-bottom-0 md:data-[state=closed]:zoom-out-95",
|
|
109
|
+
// Hold the hidden end-state until unmount so the panel doesn't snap
|
|
110
|
+
// back to opacity/scale 1 for a frame before it unmounts.
|
|
111
|
+
"data-[state=closed]:fill-mode-forwards",
|
|
105
112
|
className
|
|
106
113
|
)}
|
|
107
114
|
role="dialog"
|
|
@@ -12,6 +12,11 @@ import {
|
|
|
12
12
|
DropdownMenuTrigger
|
|
13
13
|
} from './dropdown-menu'
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Use `ActionsMenuItem` from `./actions-menu` with
|
|
17
|
+
* `ActionsMenuDropdown` instead. `MoreActionsMenu` is being phased out in favor
|
|
18
|
+
* of the `ActionsMenu*` family.
|
|
19
|
+
*/
|
|
15
20
|
export type MoreActionsItem = {
|
|
16
21
|
label: string
|
|
17
22
|
/** Click handler. Optional when `href` is provided. */
|
|
@@ -25,6 +30,9 @@ export type MoreActionsItem = {
|
|
|
25
30
|
danger?: boolean
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated Use `ActionsMenuDropdownProps` from `./actions-menu` instead.
|
|
35
|
+
*/
|
|
28
36
|
export interface MoreActionsMenuProps {
|
|
29
37
|
items: MoreActionsItem[]
|
|
30
38
|
align?: 'start' | 'center' | 'end'
|
|
@@ -50,6 +58,11 @@ export interface MoreActionsMenuProps {
|
|
|
50
58
|
/**
|
|
51
59
|
* Compact, reusable menu triggered by an ellipsis icon button.
|
|
52
60
|
* Built on top of Radix DropdownMenu used in the UI Kit.
|
|
61
|
+
*
|
|
62
|
+
* @deprecated Use `ActionsMenuDropdown` from `./actions-menu` instead — it
|
|
63
|
+
* supports the same trigger override (`customTrigger`), controlled `open` /
|
|
64
|
+
* `onOpenChange`, `onCloseAutoFocus`, and `danger` items, plus grouped items,
|
|
65
|
+
* checkboxes, and submenus. This component will be removed in a future release.
|
|
53
66
|
*/
|
|
54
67
|
export function MoreActionsMenu({
|
|
55
68
|
items,
|
|
@@ -11,10 +11,14 @@ interface SquareAvatarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
11
11
|
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
12
12
|
fallback?: string;
|
|
13
13
|
variant?: 'square' | 'round';
|
|
14
|
+
/** Override the initials-fallback styling (font size/color). Merged over the
|
|
15
|
+
* defaults (`text-xs font-medium text-ods-text-primary`) via tailwind-merge,
|
|
16
|
+
* so callers can shrink/recolor the initials for compact avatars. */
|
|
17
|
+
initialsClassName?: string;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
const SquareAvatar = React.memo(React.forwardRef<HTMLDivElement, SquareAvatarProps>(
|
|
17
|
-
({ className, src, alt, size = 'md', fallback, variant = 'square', ...props }, ref) => {
|
|
21
|
+
({ className, src, alt, size = 'md', fallback, variant = 'square', initialsClassName, ...props }, ref) => {
|
|
18
22
|
const sizeClasses = {
|
|
19
23
|
sm: 'h-8 w-8',
|
|
20
24
|
md: 'h-10 w-10',
|
|
@@ -55,6 +59,7 @@ const SquareAvatar = React.memo(React.forwardRef<HTMLDivElement, SquareAvatarPro
|
|
|
55
59
|
// (#fafafa) on the same pink yields ~3.5:1 (AA Large) and on the
|
|
56
60
|
// dark default bg yields ~15:1.
|
|
57
61
|
'flex items-center justify-center text-xs font-medium text-ods-text-primary',
|
|
62
|
+
initialsClassName,
|
|
58
63
|
src && 'hidden'
|
|
59
64
|
)}>
|
|
60
65
|
{getFirstLastInitials(fallback || alt) || '?'}
|
|
@@ -79,7 +79,7 @@ export function TagsInput({
|
|
|
79
79
|
placeholder={placeholder}
|
|
80
80
|
disabled={disabled || (maxTags ? value.length >= maxTags : false)}
|
|
81
81
|
className={cn(
|
|
82
|
-
"flex-1 bg-
|
|
82
|
+
"flex-1 bg-ods-bg border-ods-border text-ods-text-primary",
|
|
83
83
|
inputClassName
|
|
84
84
|
)}
|
|
85
85
|
/>
|
|
@@ -69,7 +69,12 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
69
69
|
// to the bottom-right when the textarea grows multi-line. Vertical
|
|
70
70
|
// padding lives here (not on the textarea) so both children share
|
|
71
71
|
// the same bottom baseline at any height.
|
|
72
|
-
|
|
72
|
+
//
|
|
73
|
+
// Padding is sized so the single-line height matches `Input` exactly
|
|
74
|
+
// (44px mobile / 48px desktop): line `leading-6` (24px) + 2× padding
|
|
75
|
+
// + 1px border top/bottom. `min-h-11 md:min-h-12` is the matching
|
|
76
|
+
// floor; with symmetric padding the single line stays centered.
|
|
77
|
+
"flex w-full items-end gap-2 rounded-[6px] border px-3 py-[9px] md:py-[11px] min-h-11 md:min-h-12 cursor-text",
|
|
73
78
|
"has-[:focus-visible]:outline-none",
|
|
74
79
|
"group",
|
|
75
80
|
"transition-colors duration-200",
|
|
@@ -88,7 +93,12 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
88
93
|
// JS needed to size to content. Falls back to `rows={1}` natural
|
|
89
94
|
// height on older browsers.
|
|
90
95
|
"[field-sizing:content]",
|
|
91
|
-
|
|
96
|
+
// `!leading-6` (not plain `leading-6`): on mobile `text-h4` sets a
|
|
97
|
+
// 20px line-height of its own that otherwise overrides the leading,
|
|
98
|
+
// leaving the 20px text box short of the 24px icon box and dropping
|
|
99
|
+
// the text below center under `items-end`. Forcing 24px keeps text
|
|
100
|
+
// and icon co-centered and the single-line height at 44px.
|
|
101
|
+
"text-h4 text-ods-text-primary placeholder:text-ods-text-secondary !leading-6",
|
|
92
102
|
// Hard cap on growth: beyond `max-h` the textarea scrolls
|
|
93
103
|
// internally instead of pushing the icon out of frame.
|
|
94
104
|
"max-h-[160px] overflow-y-auto",
|
|
@@ -105,7 +115,11 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
105
115
|
aria-label={endIconButtonProps?.['aria-label'] ?? 'Submit'}
|
|
106
116
|
{...endIconButtonProps}
|
|
107
117
|
className={cn(
|
|
108
|
-
|
|
118
|
+
// `h-6` matches the textarea's `leading-6` line box so the icon's
|
|
119
|
+
// visual center lines up with the text on the first line. Without
|
|
120
|
+
// it, `items-end` bottom-aligns the smaller mobile icon (size-4)
|
|
121
|
+
// against the 24px text line and drops it below the text center.
|
|
122
|
+
"flex h-6 shrink-0 items-center text-ods-text-secondary transition-colors duration-200",
|
|
109
123
|
"group-has-[:focus]:text-ods-accent group-data-[invalid]:text-ods-error",
|
|
110
124
|
"[&_svg]:size-4 md:[&_svg]:size-6",
|
|
111
125
|
"cursor-pointer hover:text-ods-text-primary",
|
|
@@ -119,7 +133,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
119
133
|
) : (
|
|
120
134
|
<span
|
|
121
135
|
className={cn(
|
|
122
|
-
"flex shrink-0 items-center text-ods-text-secondary transition-colors duration-200",
|
|
136
|
+
"flex h-6 shrink-0 items-center text-ods-text-secondary transition-colors duration-200",
|
|
123
137
|
"group-has-[:focus]:text-ods-accent group-data-[invalid]:text-ods-error",
|
|
124
138
|
"[&_svg]:size-4 md:[&_svg]:size-6",
|
|
125
139
|
)}
|
|
@@ -24,7 +24,7 @@ export function VendorTag({
|
|
|
24
24
|
}: VendorTagProps) {
|
|
25
25
|
// Base classes for the tag container
|
|
26
26
|
const baseClasses = cn(
|
|
27
|
-
"flex items-center gap-1.5 bg-
|
|
27
|
+
"flex items-center gap-1.5 bg-ods-bg border border-ods-border rounded whitespace-nowrap",
|
|
28
28
|
size === 'sm' ? "px-2 py-1" : "px-2.5 py-1.5"
|
|
29
29
|
)
|
|
30
30
|
|
|
@@ -59,7 +59,7 @@ const WhyItMatters = () => {
|
|
|
59
59
|
];
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
|
-
<section className="bg-
|
|
62
|
+
<section className="bg-ods-bg">
|
|
63
63
|
<div className="w-full max-w-[1920px] mx-auto px-6 md:px-20">
|
|
64
64
|
<h2 className="text-h1 text-center text-ods-text-primary tracking-[-0.02em] mb-6">
|
|
65
65
|
Why It Matters
|
|
@@ -9,6 +9,12 @@ export interface UseAutoLimitTagsOptions {
|
|
|
9
9
|
limitTags?: number | "auto"
|
|
10
10
|
/** Placeholder text used to reserve input width (only used in "auto" mode) */
|
|
11
11
|
placeholder?: string
|
|
12
|
+
/**
|
|
13
|
+
* Reserve trailing space for a text input (the autocomplete combobox). Set
|
|
14
|
+
* `false` for a pure chip row that has no input — then only the chips and the
|
|
15
|
+
* "+N" / "⋯" overflow badge compete for the available width. Default `true`.
|
|
16
|
+
*/
|
|
17
|
+
reserveInputWidth?: boolean
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export interface UseAutoLimitTagsReturn {
|
|
@@ -41,6 +47,7 @@ export function useAutoLimitTags({
|
|
|
41
47
|
count,
|
|
42
48
|
limitTags = "auto",
|
|
43
49
|
placeholder = "",
|
|
50
|
+
reserveInputWidth = true,
|
|
44
51
|
}: UseAutoLimitTagsOptions): UseAutoLimitTagsReturn {
|
|
45
52
|
const middleRef = useRef<HTMLDivElement>(null)
|
|
46
53
|
const measureRef = useRef<HTMLDivElement>(null)
|
|
@@ -74,15 +81,22 @@ export function useAutoLimitTags({
|
|
|
74
81
|
const gap = parseFloat(cs.gap) || 0
|
|
75
82
|
const middleW = middle.clientWidth
|
|
76
83
|
|
|
77
|
-
// Reserve space for the input
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
// Reserve trailing space for the input (autocomplete only). A pure chip row
|
|
85
|
+
// (`reserveInputWidth: false`) has no input, so nothing — and no gap before
|
|
86
|
+
// it — is reserved.
|
|
87
|
+
let inputReservedW = 0
|
|
88
|
+
let trailingGap = 0
|
|
89
|
+
if (reserveInputWidth) {
|
|
90
|
+
const textW = textMeasureRef.current?.offsetWidth ?? 60
|
|
91
|
+
const inputMinW = inputRef.current
|
|
92
|
+
? parseFloat(getComputedStyle(inputRef.current).minWidth) || 60
|
|
93
|
+
: 60
|
|
94
|
+
inputReservedW = Math.max(textW + 8, inputMinW)
|
|
95
|
+
trailingGap = gap
|
|
96
|
+
}
|
|
83
97
|
|
|
84
98
|
// Available = middle zone − padding − input reserved − gap before input
|
|
85
|
-
const available = middleW - padL - padR - inputReservedW -
|
|
99
|
+
const available = middleW - padL - padR - inputReservedW - trailingGap
|
|
86
100
|
|
|
87
101
|
// Measure every tag from the off-screen container
|
|
88
102
|
const tagEls = Array.from(measure.children) as HTMLElement[]
|
|
@@ -112,7 +126,7 @@ export function useAutoLimitTags({
|
|
|
112
126
|
}
|
|
113
127
|
|
|
114
128
|
setVisibleCount(Math.max(0, fitCount))
|
|
115
|
-
}, [count, limitTags, placeholder])
|
|
129
|
+
}, [count, limitTags, placeholder, reserveInputWidth])
|
|
116
130
|
|
|
117
131
|
// Recalculate when inputs change
|
|
118
132
|
useEffect(() => {
|