@dxos/react-ui-rdf 0.0.0 → 0.11.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/dist/lib/index.mjs +338 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/types/src/components/FactViewer/FactViewer.d.ts +73 -0
- package/dist/types/src/components/FactViewer/FactViewer.d.ts.map +1 -0
- package/dist/types/src/{FactViewer.stories.d.ts → components/FactViewer/FactViewer.stories.d.ts} +4 -2
- package/dist/types/src/components/FactViewer/FactViewer.stories.d.ts.map +1 -0
- package/dist/types/src/components/FactViewer/FactViewer.theme.d.ts +74 -0
- package/dist/types/src/components/FactViewer/FactViewer.theme.d.ts.map +1 -0
- package/dist/types/src/components/FactViewer/index.d.ts +2 -0
- package/dist/types/src/components/FactViewer/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +2 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -13
- package/src/{FactViewer.stories.tsx → components/FactViewer/FactViewer.stories.tsx} +15 -2
- package/src/components/FactViewer/FactViewer.theme.ts +51 -0
- package/src/components/FactViewer/FactViewer.tsx +289 -0
- package/src/components/FactViewer/index.ts +5 -0
- package/src/components/index.ts +5 -0
- package/src/index.ts +1 -1
- package/dist/lib/browser/index.mjs +0 -249
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node-esm/index.mjs +0 -251
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/types/src/FactViewer.d.ts +0 -18
- package/dist/types/src/FactViewer.d.ts.map +0 -1
- package/dist/types/src/FactViewer.stories.d.ts.map +0 -1
- package/src/FactViewer.tsx +0 -161
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-rdf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Presentational viewer for extracted semantic facts.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
".": {
|
|
17
17
|
"source": "./src/index.ts",
|
|
18
18
|
"types": "./dist/types/src/index.d.ts",
|
|
19
|
-
"
|
|
20
|
-
"node": "./dist/lib/node-esm/index.mjs"
|
|
19
|
+
"import": "./dist/lib/index.mjs"
|
|
21
20
|
}
|
|
22
21
|
},
|
|
23
22
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -26,10 +25,10 @@
|
|
|
26
25
|
"src"
|
|
27
26
|
],
|
|
28
27
|
"dependencies": {
|
|
29
|
-
"@dxos/
|
|
30
|
-
"@dxos/ui-
|
|
31
|
-
"@dxos/
|
|
32
|
-
"@dxos/
|
|
28
|
+
"@dxos/react-ui-graph": "0.11.0",
|
|
29
|
+
"@dxos/react-ui-list": "0.11.0",
|
|
30
|
+
"@dxos/ui-types": "0.11.0",
|
|
31
|
+
"@dxos/pipeline-rdf": "0.11.0"
|
|
33
32
|
},
|
|
34
33
|
"devDependencies": {
|
|
35
34
|
"@storybook/react-vite": "^10.4.2",
|
|
@@ -37,16 +36,16 @@
|
|
|
37
36
|
"@types/react-dom": "~19.2.3",
|
|
38
37
|
"react": "~19.2.7",
|
|
39
38
|
"react-dom": "~19.2.7",
|
|
40
|
-
"vite": "^8.
|
|
41
|
-
"@dxos/react-ui": "0.
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
39
|
+
"vite": "^8.1.4",
|
|
40
|
+
"@dxos/react-ui": "0.11.0",
|
|
41
|
+
"@dxos/storybook-utils": "0.11.0",
|
|
42
|
+
"@dxos/ui-theme": "0.11.0"
|
|
44
43
|
},
|
|
45
44
|
"peerDependencies": {
|
|
46
45
|
"react": "~19.2.7",
|
|
47
46
|
"react-dom": "~19.2.7",
|
|
48
|
-
"@dxos/react-ui": "0.
|
|
49
|
-
"@dxos/ui-theme": "0.
|
|
47
|
+
"@dxos/react-ui": "0.11.0",
|
|
48
|
+
"@dxos/ui-theme": "0.11.0"
|
|
50
49
|
},
|
|
51
50
|
"publishConfig": {
|
|
52
51
|
"access": "public"
|
|
@@ -17,7 +17,7 @@ import React from 'react';
|
|
|
17
17
|
import { type RDF } from '@dxos/pipeline-rdf';
|
|
18
18
|
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
19
19
|
|
|
20
|
-
import { FactViewer, type
|
|
20
|
+
import { FactViewer, type FactViewerRootProps } from './FactViewer';
|
|
21
21
|
|
|
22
22
|
const extractor = {
|
|
23
23
|
id: 'default',
|
|
@@ -88,7 +88,7 @@ const DEMO_FACTS: RDF.Fact[] = [
|
|
|
88
88
|
},
|
|
89
89
|
] satisfies RDF.Fact[];
|
|
90
90
|
|
|
91
|
-
const DefaultStory = (props:
|
|
91
|
+
const DefaultStory = (props: FactViewerRootProps) => <FactViewer.Root {...props} />;
|
|
92
92
|
|
|
93
93
|
const meta = {
|
|
94
94
|
title: 'ui/react-ui-rdf/FactViewer',
|
|
@@ -111,3 +111,16 @@ export const Empty: Story = {
|
|
|
111
111
|
facts: [],
|
|
112
112
|
},
|
|
113
113
|
};
|
|
114
|
+
|
|
115
|
+
/** Explicit composition of the parts (`FactViewer.Toolbar` + `FactViewer.List`) under `FactViewer.Root`. */
|
|
116
|
+
export const Composed: Story = {
|
|
117
|
+
args: {
|
|
118
|
+
facts: DEMO_FACTS,
|
|
119
|
+
},
|
|
120
|
+
render: ({ facts }) => (
|
|
121
|
+
<FactViewer.Root facts={facts}>
|
|
122
|
+
<FactViewer.Toolbar />
|
|
123
|
+
<FactViewer.List />
|
|
124
|
+
</FactViewer.Root>
|
|
125
|
+
),
|
|
126
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { tv } from '@dxos/ui-theme';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Tailwind-variants theme for the {@link FactViewer} composite. Consumers call
|
|
9
|
+
* `factViewerTheme.styles()` for the per-slot class functions; each accepts an optional
|
|
10
|
+
* `{ class: … }` override for per-instance merging (mirrors the react-ui-list theme pattern).
|
|
11
|
+
*/
|
|
12
|
+
const factViewerStyles = tv({
|
|
13
|
+
slots: {
|
|
14
|
+
// Toolbar spacer pushing the view toggles to the inline-end edge.
|
|
15
|
+
toolbarSpacer: 'grow',
|
|
16
|
+
|
|
17
|
+
// List view.
|
|
18
|
+
listViewport: 'flex flex-col gap-2 py-1',
|
|
19
|
+
|
|
20
|
+
// Graph view.
|
|
21
|
+
graphContent: 'overflow-hidden',
|
|
22
|
+
graphTree: 'w-full h-full',
|
|
23
|
+
|
|
24
|
+
// Subject group card.
|
|
25
|
+
group: 'shrink-0 flex flex-col dx-card-surface border border-subdued-separator rounded-sm overflow-hidden',
|
|
26
|
+
groupHeader: 'flex px-3 py-1 items-center justify-between',
|
|
27
|
+
groupConflict: 'flex items-center gap-1',
|
|
28
|
+
|
|
29
|
+
// Fact row.
|
|
30
|
+
row: 'flex flex-col items-stretch gap-2 px-3 py-1',
|
|
31
|
+
rowQuote: 'text-sm text-description italic',
|
|
32
|
+
rowGrid: 'grid grid-cols-[1fr_5rem] items-center justify-between gap-2',
|
|
33
|
+
rowTriple: 'w-full grid grid-cols-[1fr_1rem_1fr_1rem_1fr] items-center flex-wrap',
|
|
34
|
+
cell: 'bg-input-surface border border-subdued-separator rounded-sm px-2 py-0.5 font-medium whitespace-nowrap truncate',
|
|
35
|
+
cellDivider: 'border border-subdued-separator',
|
|
36
|
+
rowMeta: 'flex items-center justify-end gap-2 shrink-0',
|
|
37
|
+
rowConfidence: 'text-xs text-subdued',
|
|
38
|
+
rowAttribution: 'text-xs text-subdued text-right',
|
|
39
|
+
},
|
|
40
|
+
variants: {
|
|
41
|
+
// Conflicting facts get a warning rule on the inline-start edge.
|
|
42
|
+
conflicting: {
|
|
43
|
+
true: { row: 'border-is-2 border-warning-border' },
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/** react-ui-rdf FactViewer theme: call `.styles()` for per-slot class functions. */
|
|
49
|
+
export const factViewerTheme = {
|
|
50
|
+
styles: factViewerStyles,
|
|
51
|
+
};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { type ReactNode, createContext, forwardRef, useContext, useMemo, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type RDF, buildFactGraph, factSourceFromFacts } from '@dxos/pipeline-rdf';
|
|
8
|
+
import { Icon, IconButton, Input, Panel, ScrollArea, Tag, type ThemedClassName, Toolbar } from '@dxos/react-ui';
|
|
9
|
+
import { Tree } from '@dxos/react-ui-graph';
|
|
10
|
+
import { Empty, Listbox } from '@dxos/react-ui-list';
|
|
11
|
+
import { mx } from '@dxos/ui-theme';
|
|
12
|
+
|
|
13
|
+
import { type Group, factualityColor, formatDate, formatTerm, graphToTreeNode, groupFacts, termKey } from '../../types';
|
|
14
|
+
import { factViewerTheme } from './FactViewer.theme';
|
|
15
|
+
|
|
16
|
+
const styles = factViewerTheme.styles();
|
|
17
|
+
|
|
18
|
+
type View = 'list' | 'graph';
|
|
19
|
+
|
|
20
|
+
//
|
|
21
|
+
// Context
|
|
22
|
+
//
|
|
23
|
+
|
|
24
|
+
type FactViewerContextValue = {
|
|
25
|
+
facts: RDF.Fact[];
|
|
26
|
+
context?: string;
|
|
27
|
+
predicate?: string;
|
|
28
|
+
groups: Group[];
|
|
29
|
+
graph: ReturnType<typeof graphToTreeNode> | undefined;
|
|
30
|
+
filter: string;
|
|
31
|
+
setFilter: (value: string) => void;
|
|
32
|
+
view: View;
|
|
33
|
+
setView: (view: View) => void;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const FactViewerContext = createContext<FactViewerContextValue | null>(null);
|
|
37
|
+
|
|
38
|
+
const useFactViewerContext = (consumer: string): FactViewerContextValue => {
|
|
39
|
+
const context = useContext(FactViewerContext);
|
|
40
|
+
if (!context) {
|
|
41
|
+
throw new Error(`FactViewer.${consumer} must be rendered within FactViewer.Root`);
|
|
42
|
+
}
|
|
43
|
+
return context;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
//
|
|
47
|
+
// Root
|
|
48
|
+
//
|
|
49
|
+
|
|
50
|
+
type FactViewerRootProps = ThemedClassName<{
|
|
51
|
+
facts: RDF.Fact[];
|
|
52
|
+
/** Context entity id; scopes the list and roots the graph. */
|
|
53
|
+
context?: string;
|
|
54
|
+
/** Predicate filter; when set, only facts with this predicate are shown. */
|
|
55
|
+
predicate?: string;
|
|
56
|
+
/** Custom composition; when omitted the default toolbar + list/graph body is rendered. */
|
|
57
|
+
children?: ReactNode;
|
|
58
|
+
}>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Viewer for extracted semantic facts with two views: a grouped **list** (by subject entity, with
|
|
62
|
+
* conflicts highlighted) and a **graph** (tidy tree rooted at the context entity). A `context` entity
|
|
63
|
+
* scopes the list and roots the graph; a `predicate` further filters the list. Pure/presentational.
|
|
64
|
+
*
|
|
65
|
+
* Renders a default toolbar + body when given no children; pass children to compose the parts
|
|
66
|
+
* (`FactViewer.Toolbar`, `FactViewer.List`, `FactViewer.Graph`) directly.
|
|
67
|
+
*/
|
|
68
|
+
const FactViewerRoot = forwardRef<HTMLDivElement, FactViewerRootProps>(
|
|
69
|
+
({ classNames, facts, context, predicate, children }, forwardedRef) => {
|
|
70
|
+
const [filter, setFilter] = useState('');
|
|
71
|
+
const [view, setView] = useState<View>('list');
|
|
72
|
+
const scoped = useMemo(
|
|
73
|
+
() =>
|
|
74
|
+
facts.filter(
|
|
75
|
+
(fact) =>
|
|
76
|
+
(context == null ||
|
|
77
|
+
termKey(fact.assertion.subject) === context ||
|
|
78
|
+
termKey(fact.assertion.object) === context) &&
|
|
79
|
+
(predicate == null || fact.assertion.predicate === predicate),
|
|
80
|
+
),
|
|
81
|
+
[facts, context, predicate],
|
|
82
|
+
);
|
|
83
|
+
const groups = useMemo(() => groupFacts(scoped, filter), [scoped, filter]);
|
|
84
|
+
const graph = useMemo(
|
|
85
|
+
() =>
|
|
86
|
+
context == null ? undefined : graphToTreeNode(buildFactGraph(context, factSourceFromFacts(facts)), context),
|
|
87
|
+
[facts, context],
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const value = useMemo<FactViewerContextValue>(
|
|
91
|
+
() => ({ facts, context, predicate, groups, graph, filter, setFilter, view, setView }),
|
|
92
|
+
[facts, context, predicate, groups, graph, filter, view],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<FactViewerContext.Provider value={value}>
|
|
97
|
+
<Panel.Root classNames={classNames} ref={forwardedRef}>
|
|
98
|
+
{children ?? (
|
|
99
|
+
<>
|
|
100
|
+
<FactViewerToolbar />
|
|
101
|
+
{view === 'list' ? <FactViewerList /> : <FactViewerGraph />}
|
|
102
|
+
</>
|
|
103
|
+
)}
|
|
104
|
+
</Panel.Root>
|
|
105
|
+
</FactViewerContext.Provider>
|
|
106
|
+
);
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
FactViewerRoot.displayName = 'FactViewer.Root';
|
|
111
|
+
|
|
112
|
+
//
|
|
113
|
+
// Toolbar
|
|
114
|
+
//
|
|
115
|
+
|
|
116
|
+
type FactViewerToolbarProps = ThemedClassName<{}>;
|
|
117
|
+
|
|
118
|
+
const FactViewerToolbar = ({ classNames }: FactViewerToolbarProps) => {
|
|
119
|
+
const { filter, setFilter, view, setView } = useFactViewerContext('Toolbar');
|
|
120
|
+
return (
|
|
121
|
+
<Panel.Toolbar asChild>
|
|
122
|
+
<Toolbar.Root classNames={classNames}>
|
|
123
|
+
<Input.Root>
|
|
124
|
+
<Input.Label srOnly>Filter facts</Input.Label>
|
|
125
|
+
<Input.TextInput
|
|
126
|
+
placeholder='Filter by entity or predicate…'
|
|
127
|
+
value={filter}
|
|
128
|
+
onChange={(event) => setFilter(event.target.value)}
|
|
129
|
+
/>
|
|
130
|
+
</Input.Root>
|
|
131
|
+
<div className={styles.toolbarSpacer()} />
|
|
132
|
+
<IconButton
|
|
133
|
+
icon='ph--list--regular'
|
|
134
|
+
iconOnly
|
|
135
|
+
label='List view'
|
|
136
|
+
variant={view === 'list' ? 'primary' : 'default'}
|
|
137
|
+
onClick={() => setView('list')}
|
|
138
|
+
/>
|
|
139
|
+
<IconButton
|
|
140
|
+
icon='ph--graph--regular'
|
|
141
|
+
iconOnly
|
|
142
|
+
label='Graph view'
|
|
143
|
+
variant={view === 'graph' ? 'primary' : 'default'}
|
|
144
|
+
onClick={() => setView('graph')}
|
|
145
|
+
/>
|
|
146
|
+
</Toolbar.Root>
|
|
147
|
+
</Panel.Toolbar>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
FactViewerToolbar.displayName = 'FactViewer.Toolbar';
|
|
152
|
+
|
|
153
|
+
//
|
|
154
|
+
// List
|
|
155
|
+
//
|
|
156
|
+
|
|
157
|
+
type FactViewerListProps = ThemedClassName<{}>;
|
|
158
|
+
|
|
159
|
+
const FactViewerList = ({ classNames }: FactViewerListProps) => {
|
|
160
|
+
const { groups } = useFactViewerContext('List');
|
|
161
|
+
return (
|
|
162
|
+
<Panel.Content asChild>
|
|
163
|
+
<ScrollArea.Root padding classNames={classNames}>
|
|
164
|
+
<ScrollArea.Viewport classNames={styles.listViewport()}>
|
|
165
|
+
{groups.length === 0 && <Empty label='No facts.' />}
|
|
166
|
+
{groups.map((group) => (
|
|
167
|
+
<FactViewerGroup key={group.subject} group={group} />
|
|
168
|
+
))}
|
|
169
|
+
</ScrollArea.Viewport>
|
|
170
|
+
</ScrollArea.Root>
|
|
171
|
+
</Panel.Content>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
FactViewerList.displayName = 'FactViewer.List';
|
|
176
|
+
|
|
177
|
+
//
|
|
178
|
+
// Graph
|
|
179
|
+
//
|
|
180
|
+
|
|
181
|
+
type FactViewerGraphProps = ThemedClassName<{}>;
|
|
182
|
+
|
|
183
|
+
const FactViewerGraph = ({ classNames }: FactViewerGraphProps) => {
|
|
184
|
+
const { graph } = useFactViewerContext('Graph');
|
|
185
|
+
return (
|
|
186
|
+
<Panel.Content classNames={mx(styles.graphContent(), classNames)}>
|
|
187
|
+
{graph ? (
|
|
188
|
+
<Tree data={graph} variant='tidy' margin={80} classNames={styles.graphTree()} />
|
|
189
|
+
) : (
|
|
190
|
+
<Empty icon='ph--graph--regular' label='Select an entity to root the graph.' />
|
|
191
|
+
)}
|
|
192
|
+
</Panel.Content>
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
FactViewerGraph.displayName = 'FactViewer.Graph';
|
|
197
|
+
|
|
198
|
+
//
|
|
199
|
+
// Group
|
|
200
|
+
//
|
|
201
|
+
|
|
202
|
+
type FactViewerGroupProps = ThemedClassName<{ group: Group }>;
|
|
203
|
+
|
|
204
|
+
const FactViewerGroup = forwardRef<HTMLDivElement, FactViewerGroupProps>(({ classNames, group }, forwardedRef) => (
|
|
205
|
+
<div className={styles.group({ class: mx(classNames) })} ref={forwardedRef}>
|
|
206
|
+
<div className={styles.groupHeader()}>
|
|
207
|
+
<h3>{group.subject}</h3>
|
|
208
|
+
{group.conflicted && (
|
|
209
|
+
<Tag hue='warning'>
|
|
210
|
+
<span className={styles.groupConflict()}>
|
|
211
|
+
<Icon icon='ph--warning--regular' size={3} />
|
|
212
|
+
conflict
|
|
213
|
+
</span>
|
|
214
|
+
</Tag>
|
|
215
|
+
)}
|
|
216
|
+
</div>
|
|
217
|
+
<Listbox.Root>
|
|
218
|
+
<Listbox.Content aria-label={group.subject}>
|
|
219
|
+
{group.facts.map((fact) => (
|
|
220
|
+
<FactViewerRow key={fact.id} fact={fact} conflicting={group.conflictedIds.has(fact.id)} />
|
|
221
|
+
))}
|
|
222
|
+
</Listbox.Content>
|
|
223
|
+
</Listbox.Root>
|
|
224
|
+
</div>
|
|
225
|
+
));
|
|
226
|
+
|
|
227
|
+
FactViewerGroup.displayName = 'FactViewer.Group';
|
|
228
|
+
|
|
229
|
+
//
|
|
230
|
+
// Row
|
|
231
|
+
//
|
|
232
|
+
|
|
233
|
+
type FactViewerRowProps = ThemedClassName<{ fact: RDF.Fact; conflicting?: boolean }>;
|
|
234
|
+
|
|
235
|
+
const FactViewerRow = forwardRef<HTMLLIElement, FactViewerRowProps>(
|
|
236
|
+
({ classNames, fact, conflicting }, forwardedRef) => {
|
|
237
|
+
const { assertion, factuality, attribution } = fact;
|
|
238
|
+
return (
|
|
239
|
+
<Listbox.Item id={fact.id} classNames={styles.row({ conflicting, class: mx(classNames) })} ref={forwardedRef}>
|
|
240
|
+
{assertion.quote && <div className={styles.rowQuote()}>"{assertion.quote}"</div>}
|
|
241
|
+
|
|
242
|
+
<div className={styles.rowGrid()}>
|
|
243
|
+
<div className={styles.rowTriple()}>
|
|
244
|
+
<span className={styles.cell({ class: 'text-right' })}>{formatTerm(assertion.subject)}</span>
|
|
245
|
+
<span className={styles.cellDivider()} />
|
|
246
|
+
<span className={styles.cell({ class: 'text-center text-description' })}>{assertion.predicate}</span>
|
|
247
|
+
<span className={styles.cellDivider()} />
|
|
248
|
+
<span className={styles.cell()}>{formatTerm(assertion.object)}</span>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
<div className={styles.rowMeta()}>
|
|
252
|
+
{factuality.confidence != null && (
|
|
253
|
+
<span className={styles.rowConfidence()}>{Math.round(factuality.confidence * 100)}%</span>
|
|
254
|
+
)}
|
|
255
|
+
<Tag hue={factualityColor(factuality.value)}>{factuality.value}</Tag>
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<div className={styles.rowAttribution()}>
|
|
260
|
+
{[attribution.agent, attribution.source, formatDate(attribution.generatedAtTime)].filter(Boolean).join(' · ')}
|
|
261
|
+
</div>
|
|
262
|
+
</Listbox.Item>
|
|
263
|
+
);
|
|
264
|
+
},
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
FactViewerRow.displayName = 'FactViewer.Row';
|
|
268
|
+
|
|
269
|
+
//
|
|
270
|
+
// FactViewer
|
|
271
|
+
//
|
|
272
|
+
|
|
273
|
+
export const FactViewer = {
|
|
274
|
+
Root: FactViewerRoot,
|
|
275
|
+
Toolbar: FactViewerToolbar,
|
|
276
|
+
List: FactViewerList,
|
|
277
|
+
Graph: FactViewerGraph,
|
|
278
|
+
Group: FactViewerGroup,
|
|
279
|
+
Row: FactViewerRow,
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export type {
|
|
283
|
+
FactViewerGraphProps,
|
|
284
|
+
FactViewerGroupProps,
|
|
285
|
+
FactViewerListProps,
|
|
286
|
+
FactViewerRootProps,
|
|
287
|
+
FactViewerRowProps,
|
|
288
|
+
FactViewerToolbarProps,
|
|
289
|
+
};
|
package/src/index.ts
CHANGED