@flamingo-stack/openframe-frontend-core 0.0.325 → 0.0.326-snapshot.20260626135722
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-U74OC6PM.cjs → chunk-3AXH7BDM.cjs} +26 -26
- package/dist/{chunk-U74OC6PM.cjs.map → chunk-3AXH7BDM.cjs.map} +1 -1
- package/dist/{chunk-VSUBZBG7.js → chunk-3UVR2JIB.js} +2 -2
- package/dist/{chunk-GYWMN4AK.js → chunk-46GJFN4V.js} +4 -4
- package/dist/{chunk-5GXMQPG7.cjs → chunk-4ZHA24HS.cjs} +37 -37
- package/dist/{chunk-5GXMQPG7.cjs.map → chunk-4ZHA24HS.cjs.map} +1 -1
- package/dist/{chunk-VUE2FSVD.js → chunk-5WDRXBM3.js} +2 -2
- package/dist/{chunk-HS2YU2NF.js → chunk-62O2VTR2.js} +2 -2
- package/dist/{chunk-XTV2EZHO.cjs → chunk-7FY2OM5W.cjs} +31 -31
- package/dist/{chunk-XTV2EZHO.cjs.map → chunk-7FY2OM5W.cjs.map} +1 -1
- package/dist/{chunk-5COLEZW6.cjs → chunk-BWWUHOE3.cjs} +62 -62
- package/dist/{chunk-5COLEZW6.cjs.map → chunk-BWWUHOE3.cjs.map} +1 -1
- package/dist/{chunk-5DXWGCTW.cjs → chunk-CRHOAKG5.cjs} +56 -56
- package/dist/{chunk-5DXWGCTW.cjs.map → chunk-CRHOAKG5.cjs.map} +1 -1
- package/dist/{chunk-P3IIAUCL.js → chunk-CWXO6VCD.js} +4253 -4172
- package/dist/chunk-CWXO6VCD.js.map +1 -0
- package/dist/{chunk-AYBSXRRC.cjs → chunk-GABTFTDE.cjs} +879 -798
- package/dist/chunk-GABTFTDE.cjs.map +1 -0
- package/dist/{chunk-4USOR7KK.cjs → chunk-HQ6BILVP.cjs} +25 -25
- package/dist/{chunk-4USOR7KK.cjs.map → chunk-HQ6BILVP.cjs.map} +1 -1
- package/dist/{chunk-WAYJ7VBD.cjs → chunk-I4OFXYJR.cjs} +12 -12
- package/dist/{chunk-WAYJ7VBD.cjs.map → chunk-I4OFXYJR.cjs.map} +1 -1
- package/dist/{chunk-XFRQUV5M.js → chunk-IDMM6DVL.js} +2 -2
- package/dist/{chunk-MIVP6B6P.js → chunk-J4HHXHMC.js} +4 -4
- package/dist/{chunk-6GSM6K5W.js → chunk-LESTX5DM.js} +2 -2
- package/dist/{chunk-EQSGC5WT.js → chunk-MJUYWNQB.js} +2 -2
- package/dist/{chunk-5HRCKYFX.cjs → chunk-MWAEG3XK.cjs} +9 -9
- package/dist/{chunk-5HRCKYFX.cjs.map → chunk-MWAEG3XK.cjs.map} +1 -1
- package/dist/{chunk-XQBK7IVF.cjs → chunk-NROSNR5J.cjs} +15 -15
- package/dist/{chunk-XQBK7IVF.cjs.map → chunk-NROSNR5J.cjs.map} +1 -1
- package/dist/{chunk-QLSUOQMU.cjs → chunk-PGFQ6WQR.cjs} +7 -7
- package/dist/{chunk-QLSUOQMU.cjs.map → chunk-PGFQ6WQR.cjs.map} +1 -1
- package/dist/{chunk-UJIDDEXD.js → chunk-QF4XERYJ.js} +2 -2
- package/dist/{chunk-5CWJGCOL.js → chunk-U7GDY7Y3.js} +4 -4
- package/dist/{chunk-5YGKK636.js → chunk-UHHJIHUZ.js} +4 -4
- package/dist/{chunk-K2PS5MJH.cjs → chunk-XDNQJQGP.cjs} +5 -5
- package/dist/{chunk-K2PS5MJH.cjs.map → chunk-XDNQJQGP.cjs.map} +1 -1
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/help-center-pages/index.cjs +20 -20
- package/dist/components/help-center-pages/index.js +11 -11
- package/dist/components/index.cjs +122 -120
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +11 -9
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/index.cjs +4 -2
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +3 -1
- package/dist/components/ui/info-section.d.ts +63 -0
- package/dist/components/ui/info-section.d.ts.map +1 -0
- package/dist/components/ui/page-actions.d.ts +2 -0
- package/dist/components/ui/page-actions.d.ts.map +1 -1
- package/dist/components/ui/ticket-attachments-list.d.ts +2 -0
- package/dist/components/ui/ticket-attachments-list.d.ts.map +1 -1
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/info-section.tsx +151 -0
- package/src/components/ui/page-actions.tsx +16 -0
- package/src/components/ui/ticket-attachments-list.tsx +14 -2
- package/src/stories/InfoSection.stories.tsx +110 -0
- package/dist/chunk-AYBSXRRC.cjs.map +0 -1
- package/dist/chunk-P3IIAUCL.js.map +0 -1
- /package/dist/{chunk-VSUBZBG7.js.map → chunk-3UVR2JIB.js.map} +0 -0
- /package/dist/{chunk-GYWMN4AK.js.map → chunk-46GJFN4V.js.map} +0 -0
- /package/dist/{chunk-VUE2FSVD.js.map → chunk-5WDRXBM3.js.map} +0 -0
- /package/dist/{chunk-HS2YU2NF.js.map → chunk-62O2VTR2.js.map} +0 -0
- /package/dist/{chunk-XFRQUV5M.js.map → chunk-IDMM6DVL.js.map} +0 -0
- /package/dist/{chunk-MIVP6B6P.js.map → chunk-J4HHXHMC.js.map} +0 -0
- /package/dist/{chunk-6GSM6K5W.js.map → chunk-LESTX5DM.js.map} +0 -0
- /package/dist/{chunk-EQSGC5WT.js.map → chunk-MJUYWNQB.js.map} +0 -0
- /package/dist/{chunk-UJIDDEXD.js.map → chunk-QF4XERYJ.js.map} +0 -0
- /package/dist/{chunk-5CWJGCOL.js.map → chunk-U7GDY7Y3.js.map} +0 -0
- /package/dist/{chunk-5YGKK636.js.map → chunk-UHHJIHUZ.js.map} +0 -0
|
@@ -6,6 +6,7 @@ import { Chevron02DownIcon } from '../icons-v2-generated'
|
|
|
6
6
|
import { ActionsMenuDropdown, type ActionsMenuGroup, type ActionsMenuItem } from './actions-menu'
|
|
7
7
|
import type { ButtonProps, SplitButtonIconAction } from './button'
|
|
8
8
|
import { Button, SplitButton } from './button'
|
|
9
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './tooltip'
|
|
9
10
|
|
|
10
11
|
export type PageActionButton = {
|
|
11
12
|
/** Button label. Omit to render an icon-only button. */
|
|
@@ -50,6 +51,8 @@ export type PageActionButton = {
|
|
|
50
51
|
* Mutually exclusive with `iconAction` and `href`/`onClick`.
|
|
51
52
|
*/
|
|
52
53
|
submenu?: ActionsMenuItem[]
|
|
54
|
+
/** When set, the rendered desktop button is wrapped in a hover tooltip. */
|
|
55
|
+
tooltip?: React.ReactNode
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
function actionKey(action: PageActionButton, idx: number) {
|
|
@@ -97,6 +100,19 @@ interface RenderOptions {
|
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
function renderActionButton(action: PageActionButton, opts: RenderOptions = {}): React.ReactNode {
|
|
103
|
+
const button = renderRawActionButton(action, opts)
|
|
104
|
+
if (!action.tooltip) return button
|
|
105
|
+
return (
|
|
106
|
+
<TooltipProvider delayDuration={0}>
|
|
107
|
+
<Tooltip>
|
|
108
|
+
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
|
109
|
+
<TooltipContent>{action.tooltip}</TooltipContent>
|
|
110
|
+
</Tooltip>
|
|
111
|
+
</TooltipProvider>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function renderRawActionButton(action: PageActionButton, opts: RenderOptions = {}): React.ReactNode {
|
|
100
116
|
// Two-target SplitButton — primary action + secondary icon action.
|
|
101
117
|
if (action.iconAction) {
|
|
102
118
|
return (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from "react"
|
|
4
|
-
import {
|
|
4
|
+
import { Download02Icon, FileIcon, TrashIcon } from "../icons-v2-generated"
|
|
5
5
|
import { cn } from "../../utils/cn"
|
|
6
6
|
import { SquareAvatar } from "./square-avatar"
|
|
7
7
|
|
|
@@ -11,6 +11,8 @@ export interface TicketAttachment {
|
|
|
11
11
|
fileSize: string
|
|
12
12
|
thumbnailSrc?: string
|
|
13
13
|
onDownload?: () => void
|
|
14
|
+
/** When set, a trash button is rendered before the download button. */
|
|
15
|
+
onDelete?: () => void
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface TicketAttachmentsListProps {
|
|
@@ -65,6 +67,16 @@ export function TicketAttachmentsList({ attachments, className, size = 'default'
|
|
|
65
67
|
<p className="text-h6 text-ods-text-secondary">{attachment.fileSize}</p>
|
|
66
68
|
)}
|
|
67
69
|
</div>
|
|
70
|
+
{attachment.onDelete && (
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
onClick={attachment.onDelete}
|
|
74
|
+
className="shrink-0 text-ods-text-secondary hover:text-ods-error transition-colors"
|
|
75
|
+
aria-label={`Delete ${attachment.fileName}`}
|
|
76
|
+
>
|
|
77
|
+
<TrashIcon className={compact ? "size-4" : "size-5"} />
|
|
78
|
+
</button>
|
|
79
|
+
)}
|
|
68
80
|
{attachment.onDownload && (
|
|
69
81
|
<button
|
|
70
82
|
type="button"
|
|
@@ -72,7 +84,7 @@ export function TicketAttachmentsList({ attachments, className, size = 'default'
|
|
|
72
84
|
className="shrink-0 text-ods-text-secondary hover:text-ods-text-primary transition-colors"
|
|
73
85
|
aria-label={`Download ${attachment.fileName}`}
|
|
74
86
|
>
|
|
75
|
-
<
|
|
87
|
+
<Download02Icon className={compact ? "size-4" : "size-6"} />
|
|
76
88
|
</button>
|
|
77
89
|
)}
|
|
78
90
|
</div>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Badge } from '../components/ui/badge';
|
|
4
|
+
import { InfoSection, type InfoSectionRow } from '../components/ui/info-section';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'Tickets/InfoSection',
|
|
8
|
+
component: InfoSection,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'padded',
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'A labelled info card: a vertical stack of `label —— value` rows. Each value is configurable — plain text (with an optional trailing image), an inline assignee picker (autocomplete with search), an inline status dropdown, or an arbitrary node.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
tags: ['autodocs'],
|
|
19
|
+
decorators: [
|
|
20
|
+
Story => (
|
|
21
|
+
<div style={{ width: '360px' }}>
|
|
22
|
+
<Story />
|
|
23
|
+
</div>
|
|
24
|
+
),
|
|
25
|
+
],
|
|
26
|
+
} satisfies Meta<typeof InfoSection>;
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<typeof meta>;
|
|
30
|
+
|
|
31
|
+
const assigneeOptions = [
|
|
32
|
+
{ value: 'u1', label: 'Roman Smith' },
|
|
33
|
+
{ value: 'u2', label: 'John Doe' },
|
|
34
|
+
{ value: 'u3', label: 'Marcus Chen' },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const statusOptions = [
|
|
38
|
+
{ id: 's1', name: 'AI Assistance', color: '#3a3a3a' },
|
|
39
|
+
{ id: 's2', name: 'Tech Required', color: '#f59e0b' },
|
|
40
|
+
{ id: 's3', name: 'Resolved', color: '#5ea62e' },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The "Ticket Details" card from the design: text, text-with-avatar, an inline
|
|
45
|
+
* assignee picker, and an inline status dropdown.
|
|
46
|
+
*/
|
|
47
|
+
export const TicketDetails: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
title: 'Ticket Details',
|
|
50
|
+
rows: [
|
|
51
|
+
{ id: 'customer', label: 'Customer', value: { text: 'Acme Corp', imageFallback: 'Acme Corp' } },
|
|
52
|
+
{ id: 'device', label: 'Device', value: { text: 'TB-156-SEA', onClick: () => alert('Navigate to device') } },
|
|
53
|
+
{
|
|
54
|
+
id: 'assigned',
|
|
55
|
+
label: 'Assigned',
|
|
56
|
+
value: { type: 'assignee', options: assigneeOptions, onAssign: id => alert(`Assign: ${id}`) },
|
|
57
|
+
},
|
|
58
|
+
{ id: 'created', label: 'Created', value: { text: '07/12/25, 10:03 AM' } },
|
|
59
|
+
{ id: 'created-by', label: 'Created by', value: { text: 'Fae', imageFallback: 'Fae' } },
|
|
60
|
+
{
|
|
61
|
+
id: 'status',
|
|
62
|
+
label: 'Status',
|
|
63
|
+
value: { type: 'status', status: 'AI_ASSISTANCE', options: statusOptions, onSelect: id => alert(`Status: ${id}`) },
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Live state: assigning a user and changing status update the rows in place.
|
|
71
|
+
*/
|
|
72
|
+
export const Interactive: Story = {
|
|
73
|
+
args: { title: 'Ticket Details', rows: [] },
|
|
74
|
+
render: function InteractiveStory() {
|
|
75
|
+
const [assignee, setAssignee] = useState<string | null>(null);
|
|
76
|
+
const [statusId, setStatusId] = useState('s1');
|
|
77
|
+
|
|
78
|
+
const current = assigneeOptions.find(o => o.value === assignee);
|
|
79
|
+
const status = statusOptions.find(o => o.id === statusId);
|
|
80
|
+
|
|
81
|
+
const rows: InfoSectionRow[] = [
|
|
82
|
+
{ id: 'customer', label: 'Customer', value: { text: 'Acme Corp', imageFallback: 'Acme Corp' } },
|
|
83
|
+
{
|
|
84
|
+
id: 'assigned',
|
|
85
|
+
label: 'Assigned',
|
|
86
|
+
value: {
|
|
87
|
+
type: 'assignee',
|
|
88
|
+
currentAssignee: current ? { id: current.value, name: current.label } : undefined,
|
|
89
|
+
options: assigneeOptions,
|
|
90
|
+
onAssign: setAssignee,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'status',
|
|
95
|
+
label: 'Status',
|
|
96
|
+
value: {
|
|
97
|
+
type: 'status',
|
|
98
|
+
status: 'AI_ASSISTANCE',
|
|
99
|
+
label: status?.name,
|
|
100
|
+
color: status?.color,
|
|
101
|
+
options: statusOptions,
|
|
102
|
+
onSelect: setStatusId,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{ id: 'priority', label: 'Priority', value: { type: 'custom', content: <Badge>High</Badge> } },
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
return <InfoSection title="Ticket Details" rows={rows} />;
|
|
109
|
+
},
|
|
110
|
+
};
|