Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Make tree- and list-like components more accessible:
* Change `ClassTree`, `InstancesSearch`, `ConnectionsMenu` and `SearchResults` to be "focus group" components with support for keyboard interaction (arrow keys to move focus or toggle tree items, space to select);
* Add proper `aria-*` attributes for "focus group" containers and children e.g. `tree` and `treeitem` roles;
- Support creating standalone workspace state (context) separated from UI components:
* Workspace state can be created with `createWorkspace()` and provided to the UI components via `WorkspaceProvider`;
* Allow nested definitions of `WorkspaceRoot` to use built-in styling outside the workspace component.

#### 🐛 Fixed
- Fix partially or fully hidden outlines for `WorkspaceLayoutItem` headers and `Navigator` toggle button.
Expand All @@ -16,14 +19,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Fix canvas panning optimization not being applied due to incorrect `z-index` value.

#### 💅 Polish
- Allow to define `WorkspaceRoot` and `TranslationProvider` as parent to the `Workspace` component so they can be shared between multiple workspaces or used outside the workspace itself:
* Deprecate `translations`, `useDefaultTranslation` and `selectLabelLanguage` props on `Workspace` component in favor of wrapping the workspace in `TranslationProvider` with (newly) exported `DefaultTranslation`;
- Export `TranslationProvider` and `DefaultTranslation` to be able to use `useTranslation()` outside the workspace component:
* Remove deprecated `Translation.formatIri()` method (use `DataLocaleProvider.formatIri()` instead).
- Always display ungroup buttons on `StandardGroup` when the element is single-selected.
- Allow to configure `SearchResults` utility component with `isItemDisabled` and `multiSelection` props:
* Remove `singleSelectOnClick` mode from `SearchResults` as it mostly superseded by `multiSelection`.
- Extend `ListElementView` utility component to accept any other additional HTML props.
- Export `AccessibleList` component as base for [accessible](https://www.w3.org/TR/wai-aria/) list-like container.
- Always display ungroup buttons on `StandardGroup` when the element is single-selected.

## [0.34.1] - 2026-03-30
#### 🐛 Fixed
Expand Down
9 changes: 6 additions & 3 deletions examples/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function BasicExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
}));

const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
const {model, performLayout} = context;
Expand All @@ -38,10 +41,10 @@ function BasicExample() {
}, []);

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace />
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
21 changes: 10 additions & 11 deletions examples/classicWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function ClassicWorkspaceExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
metadataProvider: new ExampleMetadataProvider(),
validationProvider: new ExampleValidationProvider(),
renameLinkProvider: new RenameSubclassOfProvider(),
typeStyleResolver: SemanticTypeStyles,
}));

const [turtleData, setTurtleData] = React.useState(TURTLE_DATA);
const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
Expand All @@ -39,17 +46,9 @@ function ClassicWorkspaceExample() {
});
}, [turtleData]);

const [metadataProvider] = React.useState(() => new ExampleMetadataProvider());
const [validationProvider] = React.useState(() => new ExampleValidationProvider());
const [renameLinkProvider] = React.useState(() => new RenameSubclassOfProvider());

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}
metadataProvider={metadataProvider}
validationProvider={validationProvider}
renameLinkProvider={renameLinkProvider}
typeStyleResolver={SemanticTypeStyles}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.ClassicWorkspace
canvas={{
elementTemplateResolver: types => {
Expand All @@ -74,7 +73,7 @@ function ClassicWorkspaceExample() {
),
}}
/>
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
19 changes: 9 additions & 10 deletions examples/graphAuthoring.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function GraphAuthoringExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
metadataProvider: new ExampleMetadataProvider(),
validationProvider: new ExampleValidationProvider(),
renameLinkProvider: new RenameSubclassOfProvider(),
}));

const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
const {model, editor, translation: t, performLayout} = context;
Expand Down Expand Up @@ -62,16 +68,9 @@ function GraphAuthoringExample() {
}
}, []);

const [metadataProvider] = React.useState(() => new ExampleMetadataProvider());
const [validationProvider] = React.useState(() => new ExampleValidationProvider());
const [renameLinkProvider] = React.useState(() => new RenameSubclassOfProvider());

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}
metadataProvider={metadataProvider}
validationProvider={validationProvider}
renameLinkProvider={renameLinkProvider}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace
menu={<ExampleToolbarMenu />}
visualAuthoring={{
Expand Down Expand Up @@ -110,7 +109,7 @@ function GraphAuthoringExample() {
{code: 'ja', label: '日本語'},
]}
/>
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
70 changes: 35 additions & 35 deletions examples/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,35 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function I18nExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);

const translation = React.useMemo(() => new Reactodia.DefaultTranslation({
bundles: [
{
'default_workspace': {
'search_section_entities.label': 'Nodes',
'search_section_entities.title': 'Graph Nodes Lookup',
'search_section_entity_types.label': 'Node Types',
'search_section_entity_types.title': 'Graph Node Type Hierarchy',
'search_section_link_types.label': 'Edge Types',
'search_section_link_types.title': 'Graph Edge Types on the diagram'
},
'search_defaults': {
'input_term_too_short': 'Minimum search term length is {{termLength}}',
},
'search_entities': {
'criteria_connected_to_source':
'{{sourceIcon}}\u00A0{{entity}} (source) via {{relationType}}',
'criteria_connected_to_target':
'{{targetIcon}}\u00A0{{entity}} (target) via {{relationType}}',
},
'toolbar_action': {
'layout.label': 'Layout the graph',
},
}
]
}), []);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
translation: new Reactodia.DefaultTranslation({
bundles: [
{
'default_workspace': {
'search_section_entities.label': 'Nodes',
'search_section_entities.title': 'Graph Nodes Lookup',
'search_section_entity_types.label': 'Node Types',
'search_section_entity_types.title': 'Graph Node Type Hierarchy',
'search_section_link_types.label': 'Edge Types',
'search_section_link_types.title': 'Graph Edge Types on the diagram'
},
'search_defaults': {
'input_term_too_short': 'Minimum search term length is {{termLength}}',
},
'search_entities': {
'criteria_connected_to_source':
'{{sourceIcon}}\u00A0{{entity}} (source) via {{relationType}}',
'criteria_connected_to_target':
'{{targetIcon}}\u00A0{{entity}} (target) via {{relationType}}',
},
'toolbar_action': {
'layout.label': 'Layout the graph',
},
}
],
}),
defaultLayout,
}));

const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
const {model} = context;
Expand All @@ -58,14 +60,12 @@ function I18nExample() {
}, []);

return (
<Reactodia.TranslationProvider translation={translation}>
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}>
<Reactodia.DefaultWorkspace
menu={<ExampleToolbarMenu />}
/>
</Reactodia.Workspace>
</Reactodia.TranslationProvider>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace
menu={<ExampleToolbarMenu />}
/>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
9 changes: 6 additions & 3 deletions examples/rdfExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function RdfExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
}));

const [turtleData, setTurtleData] = React.useState(TURTLE_DATA);
const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
Expand Down Expand Up @@ -41,8 +44,8 @@ function RdfExample() {
}, [turtleData]);

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace
menu={
<>
Expand All @@ -63,7 +66,7 @@ function RdfExample() {
{code: 'zh', label: '汉语'},
]}
/>
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
9 changes: 6 additions & 3 deletions examples/sparql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function SparqlExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
}));

const [connectionSettings, setConnectionSettings] = React.useState(
(): SparqlConnectionSettings | undefined => {
Expand Down Expand Up @@ -61,8 +64,8 @@ function SparqlExample() {
}, [connectionSettings]);

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace
menu={<ExampleToolbarMenu />}
languages={[
Expand All @@ -84,7 +87,7 @@ function SparqlExample() {
/>
</Reactodia.Toolbar>
</Reactodia.DefaultWorkspace>
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
9 changes: 6 additions & 3 deletions examples/stressTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function StressTestExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
}));

const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
const {model, view} = context;
Expand Down Expand Up @@ -58,15 +61,15 @@ function StressTestExample() {
}, []);

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace
menu={<ExampleToolbarMenu />}
navigator={{
expanded: false,
}}
/>
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
35 changes: 19 additions & 16 deletions examples/styleCustomization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function StyleCustomizationExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
typeStyleResolver: types => {
if (types.includes('http://www.w3.org/2000/01/rdf-schema#Class')) {
return {icon: CERTIFICATE_ICON, iconMonochrome: true};
} else if (types.includes('http://www.w3.org/2002/07/owl#Class')) {
return {icon: CERTIFICATE_ICON, iconMonochrome: true};
} else if (types.includes('http://www.w3.org/2002/07/owl#ObjectProperty')) {
return {icon: COG_ICON, iconMonochrome: true};
} else if (types.includes('http://www.w3.org/2002/07/owl#DatatypeProperty')) {
return {color: '#00b9f2'};
} else {
return undefined;
}
},
}));

const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
const {model} = context;
Expand All @@ -36,21 +52,8 @@ function StyleCustomizationExample() {
}, []);

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}
typeStyleResolver={types => {
if (types.includes('http://www.w3.org/2000/01/rdf-schema#Class')) {
return {icon: CERTIFICATE_ICON, iconMonochrome: true};
} else if (types.includes('http://www.w3.org/2002/07/owl#Class')) {
return {icon: CERTIFICATE_ICON, iconMonochrome: true};
} else if (types.includes('http://www.w3.org/2002/07/owl#ObjectProperty')) {
return {icon: COG_ICON, iconMonochrome: true};
} else if (types.includes('http://www.w3.org/2002/07/owl#DatatypeProperty')) {
return {color: '#00b9f2'};
} else {
return undefined;
}
}}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace
canvas={{
elementTemplateResolver: (types, element) => {
Expand All @@ -71,7 +74,7 @@ function StyleCustomizationExample() {
menu={<ExampleToolbarMenu />}>
<BookDecorations />
</Reactodia.DefaultWorkspace>
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
9 changes: 6 additions & 3 deletions examples/wikidata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const Layouts = Reactodia.defineLayoutWorker(() => new Worker(

function WikidataExample() {
const {defaultLayout} = Reactodia.useWorker(Layouts);
const [workspace] = React.useState(() => Reactodia.createWorkspace({
defaultLayout,
}));

const {onMount, getContext} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
const {model, getCommandBus} = context;
Expand Down Expand Up @@ -65,8 +68,8 @@ function WikidataExample() {
}, []);

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}>
<Reactodia.WorkspaceProvider workspace={workspace}
onMount={onMount}>
<Reactodia.DefaultWorkspace
menu={
<>
Expand All @@ -92,7 +95,7 @@ function WikidataExample() {
{code: 'zh', label: '汉语'},
]}
/>
</Reactodia.Workspace>
</Reactodia.WorkspaceProvider>
);
}

Expand Down
Loading
Loading