@flamingo-stack/openframe-frontend-core 0.0.343-snapshot.20260630133421 → 0.0.343

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/{chunk-NSDBZFMP.cjs → chunk-23ZA3NAS.cjs} +7 -7
  2. package/dist/{chunk-NSDBZFMP.cjs.map → chunk-23ZA3NAS.cjs.map} +1 -1
  3. package/dist/{chunk-AZT66THN.cjs → chunk-2W5ELSDO.cjs} +25 -25
  4. package/dist/{chunk-AZT66THN.cjs.map → chunk-2W5ELSDO.cjs.map} +1 -1
  5. package/dist/{chunk-CABQCNG6.cjs → chunk-4S2J4RIC.cjs} +56 -56
  6. package/dist/{chunk-CABQCNG6.cjs.map → chunk-4S2J4RIC.cjs.map} +1 -1
  7. package/dist/{chunk-GGKCEZJI.cjs → chunk-AAMCLU3A.cjs} +5 -5
  8. package/dist/{chunk-GGKCEZJI.cjs.map → chunk-AAMCLU3A.cjs.map} +1 -1
  9. package/dist/{chunk-KFB7NUC7.cjs → chunk-AJE4JAPA.cjs} +37 -37
  10. package/dist/{chunk-KFB7NUC7.cjs.map → chunk-AJE4JAPA.cjs.map} +1 -1
  11. package/dist/{chunk-OI5FCI3I.cjs → chunk-DRHMR4RS.cjs} +26 -26
  12. package/dist/{chunk-OI5FCI3I.cjs.map → chunk-DRHMR4RS.cjs.map} +1 -1
  13. package/dist/{chunk-Z24XK3VU.js → chunk-EY5JK2PV.js} +2 -2
  14. package/dist/{chunk-LJWNUSKD.js → chunk-HI7OGVSK.js} +2 -2
  15. package/dist/{chunk-JYXN6WEX.js → chunk-HYHUDGT5.js} +4 -4
  16. package/dist/{chunk-LP2VM3E6.cjs → chunk-IXVWSZC6.cjs} +2 -79
  17. package/dist/chunk-IXVWSZC6.cjs.map +1 -0
  18. package/dist/{chunk-ZFPVKIAR.js → chunk-J6Z4BKMD.js} +4 -4
  19. package/dist/{chunk-7KQLWKM2.js → chunk-JIJVIIQB.js} +2743 -2820
  20. package/dist/chunk-JIJVIIQB.js.map +1 -0
  21. package/dist/{chunk-XAHPNJVR.cjs → chunk-L7JVTLPO.cjs} +62 -62
  22. package/dist/{chunk-XAHPNJVR.cjs.map → chunk-L7JVTLPO.cjs.map} +1 -1
  23. package/dist/{chunk-NBFUR64A.cjs → chunk-MIRRHOMH.cjs} +31 -31
  24. package/dist/{chunk-NBFUR64A.cjs.map → chunk-MIRRHOMH.cjs.map} +1 -1
  25. package/dist/{chunk-OWFV5FND.cjs → chunk-OCDAIFAI.cjs} +9 -9
  26. package/dist/{chunk-OWFV5FND.cjs.map → chunk-OCDAIFAI.cjs.map} +1 -1
  27. package/dist/{chunk-XE4FGAQI.js → chunk-OJNZ5XJR.js} +2 -2
  28. package/dist/{chunk-X5XTYAEM.js → chunk-PSOX77C2.js} +2 -2
  29. package/dist/{chunk-6VKKIVYU.js → chunk-PYEHGR3B.js} +2 -2
  30. package/dist/{chunk-G5VOYM2H.js → chunk-RGVXRRJF.js} +2 -2
  31. package/dist/{chunk-2GO2FK6O.cjs → chunk-TGC77CVV.cjs} +12 -12
  32. package/dist/{chunk-2GO2FK6O.cjs.map → chunk-TGC77CVV.cjs.map} +1 -1
  33. package/dist/{chunk-D7MGOMNT.js → chunk-VIHF6VQ6.js} +2 -2
  34. package/dist/{chunk-L5RSMSTC.js → chunk-VP7CNMFM.js} +4 -4
  35. package/dist/{chunk-XPTB5EMQ.js → chunk-YJJCUCPH.js} +4 -4
  36. package/dist/{chunk-D7Y5B7JK.cjs → chunk-ZERQ5VF3.cjs} +15 -15
  37. package/dist/{chunk-D7Y5B7JK.cjs.map → chunk-ZERQ5VF3.cjs.map} +1 -1
  38. package/dist/components/case-studies/index.cjs +8 -8
  39. package/dist/components/case-studies/index.js +2 -2
  40. package/dist/components/chat/index.cjs +2 -2
  41. package/dist/components/chat/index.js +1 -1
  42. package/dist/components/contact/index.cjs +3 -3
  43. package/dist/components/contact/index.js +2 -2
  44. package/dist/components/docs/index.cjs +5 -5
  45. package/dist/components/docs/index.js +4 -4
  46. package/dist/components/embeds/index.cjs +3 -3
  47. package/dist/components/embeds/index.js +2 -2
  48. package/dist/components/faq/index.cjs +3 -3
  49. package/dist/components/faq/index.js +2 -2
  50. package/dist/components/features/index.cjs +2 -2
  51. package/dist/components/features/index.js +1 -1
  52. package/dist/components/help-center-pages/index.cjs +20 -20
  53. package/dist/components/help-center-pages/index.js +11 -11
  54. package/dist/components/index.cjs +121 -123
  55. package/dist/components/index.cjs.map +1 -1
  56. package/dist/components/index.js +9 -11
  57. package/dist/components/index.js.map +1 -1
  58. package/dist/components/navigation/index.cjs +2 -2
  59. package/dist/components/navigation/index.js +1 -1
  60. package/dist/components/onboarding-guides/index.cjs +5 -5
  61. package/dist/components/onboarding-guides/index.js +4 -4
  62. package/dist/components/related-content/index.cjs +3 -3
  63. package/dist/components/related-content/index.js +2 -2
  64. package/dist/components/tickets/index.cjs +5 -5
  65. package/dist/components/tickets/index.js +4 -4
  66. package/dist/components/ui/index.cjs +2 -4
  67. package/dist/components/ui/index.cjs.map +1 -1
  68. package/dist/components/ui/index.d.ts +0 -1
  69. package/dist/components/ui/index.d.ts.map +1 -1
  70. package/dist/components/ui/index.js +1 -3
  71. package/dist/index.cjs +2 -4
  72. package/dist/index.cjs.map +1 -1
  73. package/dist/index.js +1 -3
  74. package/package.json +1 -1
  75. package/src/components/ui/index.ts +0 -1
  76. package/dist/chunk-7KQLWKM2.js.map +0 -1
  77. package/dist/chunk-LP2VM3E6.cjs.map +0 -1
  78. package/dist/components/ui/stacked-rows-panel.d.ts +0 -58
  79. package/dist/components/ui/stacked-rows-panel.d.ts.map +0 -1
  80. package/src/components/ui/stacked-rows-panel.tsx +0 -187
  81. package/src/stories/StackedRowsPanel.stories.tsx +0 -165
  82. /package/dist/{chunk-Z24XK3VU.js.map → chunk-EY5JK2PV.js.map} +0 -0
  83. /package/dist/{chunk-LJWNUSKD.js.map → chunk-HI7OGVSK.js.map} +0 -0
  84. /package/dist/{chunk-JYXN6WEX.js.map → chunk-HYHUDGT5.js.map} +0 -0
  85. /package/dist/{chunk-ZFPVKIAR.js.map → chunk-J6Z4BKMD.js.map} +0 -0
  86. /package/dist/{chunk-XE4FGAQI.js.map → chunk-OJNZ5XJR.js.map} +0 -0
  87. /package/dist/{chunk-X5XTYAEM.js.map → chunk-PSOX77C2.js.map} +0 -0
  88. /package/dist/{chunk-6VKKIVYU.js.map → chunk-PYEHGR3B.js.map} +0 -0
  89. /package/dist/{chunk-G5VOYM2H.js.map → chunk-RGVXRRJF.js.map} +0 -0
  90. /package/dist/{chunk-D7MGOMNT.js.map → chunk-VIHF6VQ6.js.map} +0 -0
  91. /package/dist/{chunk-L5RSMSTC.js.map → chunk-VP7CNMFM.js.map} +0 -0
  92. /package/dist/{chunk-XPTB5EMQ.js.map → chunk-YJJCUCPH.js.map} +0 -0
@@ -1,58 +0,0 @@
1
- import type * as React from "react";
2
- /**
3
- * StackedRowsPanel — a single bordered card that stacks rows inside it.
4
- *
5
- * Each row can be:
6
- * - a single full-width element (e.g. title + subtitle) — pass one column,
7
- * - N columns (each a value + label, possibly a tag/avatar) — pass several columns,
8
- * - an arbitrary node (e.g. a nested table) — pass `content`.
9
- *
10
- * Border-radius behaviour is handled entirely by the container: `rounded-md` +
11
- * `overflow-clip` clip the first/last rows to the rounded corners. So a single row
12
- * rounds all four corners, while many rows visually round only the top corners of
13
- * the first row and the bottom corners of the last — with no per-row corner logic.
14
- *
15
- * Cells render the ODS `value` (`text-h4`) over `label` (`text-h6`) pattern with an
16
- * optional leading icon, matching the app's detail layouts. Pass a node as `value`
17
- * (e.g. a `Tag`) to render a status chip with a caption beneath it.
18
- */
19
- export type PanelColumnAlign = "left" | "center" | "right";
20
- export type PanelHideAt = "md" | "lg" | "xl";
21
- export interface PanelColumn {
22
- /** Stable key for the column. */
23
- key: string;
24
- /** Custom cell content (tag, avatar + text, button…). Takes precedence over `value`/`label`. */
25
- content?: React.ReactNode;
26
- /** Primary value rendered in the ODS h4 style when `content` is not set. */
27
- value?: React.ReactNode;
28
- /** Secondary label rendered under the value (ODS h6, secondary colour). */
29
- label?: string;
30
- /** Icon shown before the value. */
31
- icon?: React.ReactNode;
32
- /** When set, the cell becomes an external link. */
33
- href?: string;
34
- /** Tailwind width class. Defaults to `flex-[1_0_0] min-w-0`. */
35
- width?: string;
36
- /** Horizontal alignment of the column content. Defaults to `left`. */
37
- align?: PanelColumnAlign;
38
- /** Hide the column below this breakpoint (mirrors the DataTable `hideAt` concept). */
39
- hideAt?: PanelHideAt;
40
- }
41
- export interface PanelRow {
42
- /** Stable key for the row. */
43
- id: string;
44
- /** One column → full-width row; several columns → a columns row. */
45
- columns?: PanelColumn[];
46
- /** Arbitrary content (e.g. a nested table). Takes precedence over `columns`. */
47
- content?: React.ReactNode;
48
- /** Per-row overrides (e.g. height, or `p-0` for a nested table that should reach the edges). */
49
- className?: string;
50
- }
51
- export interface StackedRowsPanelProps {
52
- rows: PanelRow[];
53
- /** Optional uppercase caption rendered above the card. */
54
- title?: string;
55
- className?: string;
56
- }
57
- export declare function StackedRowsPanel({ rows, title, className }: StackedRowsPanelProps): React.JSX.Element;
58
- //# sourceMappingURL=stacked-rows-panel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stacked-rows-panel.d.ts","sourceRoot":"","sources":["../../../src/components/ui/stacked-rows-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAGnC;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAC1D,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAE5C,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,gGAAgG;IAChG,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mCAAmC;IACnC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,sFAAsF;IACtF,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,oEAAoE;IACpE,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;IACvB,gFAAgF;IAChF,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAwGD,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,qBAAqB,qBAmBjF"}
@@ -1,187 +0,0 @@
1
- "use client"
2
-
3
- import type * as React from "react"
4
- import { cn } from "../../utils/cn"
5
-
6
- /**
7
- * StackedRowsPanel — a single bordered card that stacks rows inside it.
8
- *
9
- * Each row can be:
10
- * - a single full-width element (e.g. title + subtitle) — pass one column,
11
- * - N columns (each a value + label, possibly a tag/avatar) — pass several columns,
12
- * - an arbitrary node (e.g. a nested table) — pass `content`.
13
- *
14
- * Border-radius behaviour is handled entirely by the container: `rounded-md` +
15
- * `overflow-clip` clip the first/last rows to the rounded corners. So a single row
16
- * rounds all four corners, while many rows visually round only the top corners of
17
- * the first row and the bottom corners of the last — with no per-row corner logic.
18
- *
19
- * Cells render the ODS `value` (`text-h4`) over `label` (`text-h6`) pattern with an
20
- * optional leading icon, matching the app's detail layouts. Pass a node as `value`
21
- * (e.g. a `Tag`) to render a status chip with a caption beneath it.
22
- */
23
-
24
- export type PanelColumnAlign = "left" | "center" | "right"
25
- export type PanelHideAt = "md" | "lg" | "xl"
26
-
27
- export interface PanelColumn {
28
- /** Stable key for the column. */
29
- key: string
30
- /** Custom cell content (tag, avatar + text, button…). Takes precedence over `value`/`label`. */
31
- content?: React.ReactNode
32
- /** Primary value rendered in the ODS h4 style when `content` is not set. */
33
- value?: React.ReactNode
34
- /** Secondary label rendered under the value (ODS h6, secondary colour). */
35
- label?: string
36
- /** Icon shown before the value. */
37
- icon?: React.ReactNode
38
- /** When set, the cell becomes an external link. */
39
- href?: string
40
- /** Tailwind width class. Defaults to `flex-[1_0_0] min-w-0`. */
41
- width?: string
42
- /** Horizontal alignment of the column content. Defaults to `left`. */
43
- align?: PanelColumnAlign
44
- /** Hide the column below this breakpoint (mirrors the DataTable `hideAt` concept). */
45
- hideAt?: PanelHideAt
46
- }
47
-
48
- export interface PanelRow {
49
- /** Stable key for the row. */
50
- id: string
51
- /** One column → full-width row; several columns → a columns row. */
52
- columns?: PanelColumn[]
53
- /** Arbitrary content (e.g. a nested table). Takes precedence over `columns`. */
54
- content?: React.ReactNode
55
- /** Per-row overrides (e.g. height, or `p-0` for a nested table that should reach the edges). */
56
- className?: string
57
- }
58
-
59
- export interface StackedRowsPanelProps {
60
- rows: PanelRow[]
61
- /** Optional uppercase caption rendered above the card. */
62
- title?: string
63
- className?: string
64
- }
65
-
66
- const ALIGN_CLASS: Record<PanelColumnAlign, string> = {
67
- left: "justify-start items-start",
68
- center: "justify-center items-center",
69
- right: "justify-end items-end",
70
- }
71
-
72
- // Horizontal alignment for value/label cells. `left` keeps the default stretch so
73
- // the value/label can truncate; center/right shrink to content and align the cell.
74
- const CELL_ITEMS_ALIGN: Record<PanelColumnAlign, string> = {
75
- left: "",
76
- center: "items-center",
77
- right: "items-end",
78
- }
79
-
80
- const HIDE_CLASS: Record<PanelHideAt, string> = {
81
- md: "hidden md:flex",
82
- lg: "hidden lg:flex",
83
- xl: "hidden xl:flex",
84
- }
85
-
86
- // Base column-row class. Row height is content-driven via the min-heights, matching
87
- // the joined-row pattern used across the detail layouts (56px mobile, 80px tablet+).
88
- const ROW_CLASS =
89
- "flex items-center gap-[var(--spacing-system-m)] px-[var(--spacing-system-m)] min-h-14 md:min-h-20 border-b border-ods-border last:border-b-0"
90
-
91
- function CellValue({ column }: { column: PanelColumn }) {
92
- const valueNode = (
93
- <div
94
- className="text-ods-text-primary text-h4 truncate"
95
- title={typeof column.value === "string" ? column.value : undefined}
96
- >
97
- {column.value}
98
- </div>
99
- )
100
-
101
- return (
102
- <>
103
- <div className="flex items-center gap-[var(--spacing-system-xxs)] min-w-0">
104
- {column.icon && <span className="shrink-0">{column.icon}</span>}
105
- {column.href ? (
106
- <a
107
- href={column.href}
108
- target="_blank"
109
- rel="noreferrer"
110
- className="min-w-0 transition-opacity hover:opacity-80"
111
- >
112
- {valueNode}
113
- </a>
114
- ) : (
115
- valueNode
116
- )}
117
- </div>
118
- {column.label ? <p className="text-ods-text-secondary text-h6 truncate">{column.label}</p> : null}
119
- </>
120
- )
121
- }
122
-
123
- function PanelCell({ column }: { column: PanelColumn }) {
124
- const widthClass = column.width ?? "flex-[1_0_0] min-w-0"
125
- const hideClass = column.hideAt ? HIDE_CLASS[column.hideAt] : "flex"
126
-
127
- if (column.content !== undefined) {
128
- return (
129
- <div className={cn(hideClass, "flex-col", ALIGN_CLASS[column.align ?? "left"], widthClass)}>{column.content}</div>
130
- )
131
- }
132
-
133
- return (
134
- <div className={cn(hideClass, "flex-col justify-center", CELL_ITEMS_ALIGN[column.align ?? "left"], widthClass)}>
135
- <CellValue column={column} />
136
- </div>
137
- )
138
- }
139
-
140
- function PanelRowView({ row }: { row: PanelRow }) {
141
- // Arbitrary content (e.g. a nested table): keep it edge-to-edge unless the caller
142
- // overrides via `className`. No fixed height — let the content size itself.
143
- if (row.content !== undefined) {
144
- return <div className={cn("border-b border-ods-border last:border-b-0", row.className)}>{row.content}</div>
145
- }
146
-
147
- const columns = row.columns ?? []
148
- const isFullWidth = columns.length === 1
149
-
150
- // A single-column row is a full-width title/subtitle row: pad symmetrically
151
- // (ODS `m`) instead of using a fixed column-row height.
152
- const rowClass = isFullWidth
153
- ? cn(
154
- "flex items-center gap-[var(--spacing-system-m)] p-[var(--spacing-system-m)] border-b border-ods-border last:border-b-0",
155
- row.className,
156
- )
157
- : cn(ROW_CLASS, row.className)
158
-
159
- return (
160
- <div className={rowClass}>
161
- {columns.map(column => (
162
- <PanelCell key={column.key} column={column} />
163
- ))}
164
- </div>
165
- )
166
- }
167
-
168
- export function StackedRowsPanel({ rows, title, className }: StackedRowsPanelProps) {
169
- const card = (
170
- <div className="flex flex-col overflow-clip rounded-md border border-ods-border bg-ods-card">
171
- {rows.map(row => (
172
- <PanelRowView key={row.id} row={row} />
173
- ))}
174
- </div>
175
- )
176
-
177
- if (!title) {
178
- return <div className={className}>{card}</div>
179
- }
180
-
181
- return (
182
- <div className={cn("flex flex-col gap-[var(--spacing-system-xxs)]", className)}>
183
- <p className="text-h5 uppercase text-ods-text-secondary">{title}</p>
184
- {card}
185
- </div>
186
- )
187
- }
@@ -1,165 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/nextjs-vite'
2
- import { useMemo } from 'react'
3
- import { type ColumnDef, DataTable, type Row, useDataTable } from '../components/ui/data-table'
4
- import { EntityImage } from '../components/ui/entity-image'
5
- import { StackedRowsPanel } from '../components/ui/stacked-rows-panel'
6
- import { Tag } from '../components/ui/tag'
7
-
8
- const meta = {
9
- title: 'UI/StackedRowsPanel',
10
- component: StackedRowsPanel,
11
- parameters: {
12
- layout: 'padded',
13
- docs: {
14
- description: {
15
- component:
16
- 'A single bordered card that stacks rows inside it. Each row can be one full-width element ' +
17
- '(title + subtitle), several columns (value + label, optionally a tag/avatar), or an arbitrary ' +
18
- 'node such as a nested table. The container handles all rounding: one row rounds every corner, ' +
19
- 'while many rows round only the first row’s top corners and the last row’s bottom corners.',
20
- },
21
- },
22
- },
23
- tags: ['autodocs'],
24
- } satisfies Meta<typeof StackedRowsPanel>
25
-
26
- export default meta
27
- type Story = StoryObj<typeof meta>
28
-
29
- /** Header card: a full-width title/description row followed by a columns row. */
30
- export const HeaderCard: Story = {
31
- args: {
32
- rows: [
33
- {
34
- id: 'title',
35
- columns: [
36
- {
37
- key: 'title',
38
- value: 'Monitors sustained high processor utilization indicating performance bottlenecks',
39
- label: 'Description',
40
- },
41
- ],
42
- },
43
- {
44
- id: 'meta',
45
- columns: [
46
- { key: 'severity', value: 'Critical', label: 'Severity' },
47
- { key: 'status', value: <Tag label="Failing" variant="error" />, label: 'Status' },
48
- { key: 'author', value: 'Jane Doe', label: 'Author' },
49
- ],
50
- },
51
- ],
52
- },
53
- }
54
-
55
- /** Standard table: uniform multi-column rows (avatar + name/email, role, status tag). */
56
- export const StandardTable: Story = {
57
- args: {
58
- rows: [
59
- {
60
- id: 'jane',
61
- columns: [
62
- {
63
- key: 'user',
64
- content: (
65
- <div className="flex items-center gap-[var(--spacing-system-m)] min-w-0">
66
- <EntityImage alt="Jane Doe" fallbackText="Jane Doe" className="size-8 rounded-full" />
67
- <div className="flex flex-col min-w-0">
68
- <span className="text-ods-text-primary text-h4 truncate">Jane Doe</span>
69
- <span className="text-ods-text-secondary text-h6 truncate">jane.doe@example.com</span>
70
- </div>
71
- </div>
72
- ),
73
- },
74
- { key: 'role', value: 'Admin', hideAt: 'md' },
75
- { key: 'status', content: <Tag label="Active" variant="success" />, align: 'right' },
76
- ],
77
- },
78
- {
79
- id: 'john',
80
- columns: [
81
- {
82
- key: 'user',
83
- content: (
84
- <div className="flex items-center gap-[var(--spacing-system-m)] min-w-0">
85
- <EntityImage alt="John Roe" fallbackText="John Roe" className="size-8 rounded-full" />
86
- <div className="flex flex-col min-w-0">
87
- <span className="text-ods-text-primary text-h4 truncate">John Roe</span>
88
- <span className="text-ods-text-secondary text-h6 truncate">john.roe@example.com</span>
89
- </div>
90
- </div>
91
- ),
92
- },
93
- { key: 'role', value: 'Admin', hideAt: 'md' },
94
- { key: 'status', content: <Tag label="Offline" variant="grey" />, align: 'right' },
95
- ],
96
- },
97
- ],
98
- },
99
- }
100
-
101
- /** A single row rounds all four corners. */
102
- export const SingleRow: Story = {
103
- args: {
104
- rows: [{ id: 'only', columns: [{ key: 'only', value: 'High CPU Usage >85%', label: 'Policy' }] }],
105
- },
106
- }
107
-
108
- interface DemoDevice {
109
- id: string
110
- name: string
111
- status: 'NON-COMPLIANT' | 'COMPLIANT'
112
- }
113
-
114
- const DEMO_DEVICES: DemoDevice[] = [
115
- { id: '1', name: "John's Device", status: 'NON-COMPLIANT' },
116
- { id: '2', name: 'Workstation-04', status: 'COMPLIANT' },
117
- ]
118
-
119
- function NestedDevicesTable() {
120
- const columns = useMemo<ColumnDef<DemoDevice>[]>(
121
- () => [
122
- {
123
- accessorKey: 'name',
124
- header: 'DEVICE',
125
- cell: ({ row }: { row: Row<DemoDevice> }) => (
126
- <div className="flex flex-col">
127
- <span className="text-ods-text-primary text-h4 truncate">{row.original.name}</span>
128
- <span className="text-ods-text-secondary text-h6 truncate">Last Online: 2 hours ago</span>
129
- </div>
130
- ),
131
- },
132
- {
133
- accessorKey: 'status',
134
- header: 'STATUS',
135
- cell: ({ row }: { row: Row<DemoDevice> }) => (
136
- <Tag label={row.original.status} variant={row.original.status === 'COMPLIANT' ? 'success' : 'error'} />
137
- ),
138
- meta: { width: 'w-[180px]' },
139
- },
140
- ],
141
- [],
142
- )
143
-
144
- const table = useDataTable<DemoDevice>({
145
- data: DEMO_DEVICES,
146
- columns,
147
- getRowId: (row: DemoDevice) => row.id,
148
- enableSorting: false,
149
- })
150
-
151
- return (
152
- <DataTable table={table}>
153
- <DataTable.Header />
154
- <DataTable.Body />
155
- </DataTable>
156
- )
157
- }
158
-
159
- /** A panel row can host an arbitrary node — here a nested DataTable. */
160
- export const WithNestedTable: Story = {
161
- args: {
162
- title: 'Devices',
163
- rows: [{ id: 'devices', className: 'p-[var(--spacing-system-m)]', content: <NestedDevicesTable /> }],
164
- },
165
- }