@dxos/plugin-deck 0.8.2-staging.7ac8446 → 0.8.2
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/browser/{app-graph-builder-VYZ4IWI3.mjs → app-graph-builder-M5BT34YG.mjs} +17 -16
- package/dist/lib/browser/app-graph-builder-M5BT34YG.mjs.map +7 -0
- package/dist/lib/browser/{check-app-scheme-SEYECDHI.mjs → check-app-scheme-7AXGR6UT.mjs} +2 -3
- package/dist/lib/browser/check-app-scheme-7AXGR6UT.mjs.map +7 -0
- package/dist/lib/browser/{state-7TN26M42.mjs → chunk-FX44YX3G.mjs} +11 -8
- package/dist/lib/browser/chunk-FX44YX3G.mjs.map +7 -0
- package/dist/lib/browser/chunk-JE2ARGEB.mjs +1487 -0
- package/dist/lib/browser/chunk-JE2ARGEB.mjs.map +7 -0
- package/dist/lib/browser/{chunk-XMCG42ID.mjs → chunk-KLN73CM3.mjs} +2 -2
- package/dist/lib/browser/{chunk-XMCG42ID.mjs.map → chunk-KLN73CM3.mjs.map} +1 -1
- package/dist/lib/browser/chunk-SLQNOATN.mjs +127 -0
- package/dist/lib/browser/chunk-SLQNOATN.mjs.map +7 -0
- package/dist/lib/browser/chunk-TRFYUEBA.mjs +145 -0
- package/dist/lib/browser/chunk-TRFYUEBA.mjs.map +7 -0
- package/dist/lib/browser/chunk-YN5OZEGS.mjs +162 -0
- package/dist/lib/browser/chunk-YN5OZEGS.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +8 -8
- package/dist/lib/browser/index.mjs.map +2 -2
- package/dist/lib/browser/{intent-resolver-UDYKO2QW.mjs → intent-resolver-3GAC57UA.mjs} +135 -92
- package/dist/lib/browser/intent-resolver-3GAC57UA.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-root-XLXN2VEW.mjs → react-root-ISFFOJZX.mjs} +7 -7
- package/dist/lib/browser/{react-surface-WNGMZL7I.mjs → react-surface-A63RQB5N.mjs} +7 -7
- package/dist/lib/browser/{settings-HMDGSBGO.mjs → settings-X7GDEXU3.mjs} +6 -6
- package/dist/lib/browser/settings-X7GDEXU3.mjs.map +7 -0
- package/dist/lib/browser/state-VJ6E3ADY.mjs +10 -0
- package/dist/lib/browser/state-VJ6E3ADY.mjs.map +7 -0
- package/dist/lib/browser/{tools-SC6QEN7R.mjs → tools-N57NQ2LH.mjs} +28 -18
- package/dist/lib/browser/tools-N57NQ2LH.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +1 -1
- package/dist/lib/browser/{url-handler-ODG4B6NX.mjs → url-handler-BUGI6XRE.mjs} +5 -5
- package/dist/lib/browser/url-handler-BUGI6XRE.mjs.map +7 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +2 -179
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts +18 -8
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/check-app-scheme.d.ts +2 -2
- package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +8 -183
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/state.d.ts +12 -7
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/capabilities/tools.d.ts +1 -1
- package/dist/types/src/capabilities/tools.d.ts.map +1 -1
- package/dist/types/src/capabilities/url-handler.d.ts +2 -2
- package/dist/types/src/capabilities/url-handler.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Dialog.d.ts +3 -0
- package/dist/types/src/components/DeckLayout/Dialog.d.ts.map +1 -0
- package/dist/types/src/components/DeckLayout/Popover.d.ts +5 -0
- package/dist/types/src/components/DeckLayout/Popover.d.ts.map +1 -0
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
- package/dist/types/src/components/DeckSettings/DeckSettings.d.ts.map +1 -1
- package/dist/types/src/components/Plank/Plank.d.ts +18 -5
- package/dist/types/src/components/Plank/Plank.d.ts.map +1 -1
- package/dist/types/src/components/Plank/Plank.stories.d.ts +3 -3
- package/dist/types/src/components/Plank/Plank.stories.d.ts.map +1 -1
- package/dist/types/src/components/Plank/PlankControls.d.ts +3 -2
- package/dist/types/src/components/Plank/PlankControls.d.ts.map +1 -1
- package/dist/types/src/components/Plank/PlankError.d.ts.map +1 -1
- package/dist/types/src/components/Plank/PlankHeading.d.ts +3 -2
- package/dist/types/src/components/Plank/PlankHeading.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/SidebarButton.d.ts +2 -1
- package/dist/types/src/components/Sidebar/SidebarButton.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +5 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useBreakpoints.d.ts.map +1 -0
- package/dist/types/src/hooks/useCompanions.d.ts.map +1 -0
- package/dist/types/src/hooks/useDeckCompanions.d.ts +13 -0
- package/dist/types/src/hooks/useDeckCompanions.d.ts.map +1 -0
- package/dist/types/src/hooks/useHoistStatusbar.d.ts +3 -0
- package/dist/types/src/hooks/useHoistStatusbar.d.ts.map +1 -0
- package/dist/types/src/hooks/useNodeActionExpander.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/layout.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +108 -104
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -4
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/layoutAppliesTopbar.d.ts +2 -1
- package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -1
- package/dist/types/src/util/overscroll.d.ts.map +1 -1
- package/dist/types/src/util/set-active.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +39 -30
- package/src/capabilities/app-graph-builder.ts +120 -92
- package/src/capabilities/check-app-scheme.ts +3 -7
- package/src/capabilities/index.ts +3 -2
- package/src/capabilities/intent-resolver.ts +181 -135
- package/src/capabilities/settings.ts +4 -4
- package/src/capabilities/state.ts +7 -4
- package/src/capabilities/tools.ts +15 -12
- package/src/capabilities/url-handler.ts +4 -4
- package/src/components/DeckLayout/ContentEmpty.tsx +9 -4
- package/src/components/DeckLayout/DeckLayout.tsx +123 -188
- package/src/components/DeckLayout/Dialog.tsx +36 -0
- package/src/components/DeckLayout/Popover.tsx +104 -0
- package/src/components/Plank/Plank.stories.tsx +20 -8
- package/src/components/Plank/Plank.tsx +105 -69
- package/src/components/Plank/PlankControls.tsx +53 -57
- package/src/components/Plank/PlankError.tsx +2 -6
- package/src/components/Plank/PlankHeading.tsx +31 -12
- package/src/components/Sidebar/ComplementarySidebar.tsx +36 -57
- package/src/components/Sidebar/Sidebar.tsx +7 -4
- package/src/components/Sidebar/SidebarButton.tsx +26 -7
- package/src/components/fragments.ts +1 -1
- package/src/hooks/index.ts +5 -1
- package/src/{util → hooks}/useCompanions.ts +3 -3
- package/src/hooks/useDeckCompanions.ts +33 -0
- package/src/{util → hooks}/useHoistStatusbar.ts +9 -4
- package/src/hooks/useNodeActionExpander.ts +3 -8
- package/src/index.ts +1 -1
- package/src/translations.ts +2 -1
- package/src/types.ts +77 -71
- package/src/util/index.ts +1 -4
- package/src/util/layoutAppliesTopbar.ts +8 -2
- package/dist/lib/browser/app-graph-builder-VYZ4IWI3.mjs.map +0 -7
- package/dist/lib/browser/check-app-scheme-SEYECDHI.mjs.map +0 -7
- package/dist/lib/browser/chunk-6ZSOFCPP.mjs +0 -117
- package/dist/lib/browser/chunk-6ZSOFCPP.mjs.map +0 -7
- package/dist/lib/browser/chunk-B4LOJUWW.mjs +0 -24
- package/dist/lib/browser/chunk-B4LOJUWW.mjs.map +0 -7
- package/dist/lib/browser/chunk-FJBMNSUC.mjs +0 -1289
- package/dist/lib/browser/chunk-FJBMNSUC.mjs.map +0 -7
- package/dist/lib/browser/chunk-FLOVGNYB.mjs +0 -81
- package/dist/lib/browser/chunk-FLOVGNYB.mjs.map +0 -7
- package/dist/lib/browser/chunk-RJNCG4ND.mjs +0 -154
- package/dist/lib/browser/chunk-RJNCG4ND.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-UDYKO2QW.mjs.map +0 -7
- package/dist/lib/browser/settings-HMDGSBGO.mjs.map +0 -7
- package/dist/lib/browser/state-7TN26M42.mjs.map +0 -7
- package/dist/lib/browser/tools-SC6QEN7R.mjs.map +0 -7
- package/dist/lib/browser/url-handler-ODG4B6NX.mjs.map +0 -7
- package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +0 -5
- package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +0 -1
- package/dist/types/src/util/useBreakpoints.d.ts.map +0 -1
- package/dist/types/src/util/useCompanions.d.ts.map +0 -1
- package/dist/types/src/util/useHoistStatusbar.d.ts +0 -2
- package/dist/types/src/util/useHoistStatusbar.d.ts.map +0 -1
- package/src/components/DeckLayout/Fullscreen.tsx +0 -31
- /package/dist/lib/browser/{react-root-XLXN2VEW.mjs.map → react-root-ISFFOJZX.mjs.map} +0 -0
- /package/dist/lib/browser/{react-surface-WNGMZL7I.mjs.map → react-surface-A63RQB5N.mjs.map} +0 -0
- /package/dist/types/src/{util → hooks}/useBreakpoints.d.ts +0 -0
- /package/dist/types/src/{util → hooks}/useCompanions.d.ts +0 -0
- /package/src/{util → hooks}/useBreakpoints.ts +0 -0
|
@@ -5,39 +5,51 @@
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
7
|
import { type StoryObj, type Meta } from '@storybook/react';
|
|
8
|
+
import React from 'react';
|
|
8
9
|
|
|
9
|
-
import { IntentPlugin } from '@dxos/app-framework';
|
|
10
|
+
import { IntentPlugin, SettingsPlugin } from '@dxos/app-framework';
|
|
10
11
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
12
|
+
import { AttentionPlugin } from '@dxos/plugin-attention';
|
|
11
13
|
import { GraphPlugin } from '@dxos/plugin-graph';
|
|
14
|
+
import { Stack } from '@dxos/react-ui-stack';
|
|
12
15
|
import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
13
16
|
|
|
14
|
-
import { Plank } from './Plank';
|
|
17
|
+
import { Plank, type PlankProps } from './Plank';
|
|
18
|
+
import DeckStateFactory from '../../capabilities/state';
|
|
15
19
|
import translations from '../../translations';
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
const meta: Meta<typeof Plank> = {
|
|
21
|
+
const meta: Meta<PlankProps> = {
|
|
19
22
|
title: 'plugins/plugin-deck/Plank',
|
|
20
23
|
component: Plank,
|
|
24
|
+
render: (args) => {
|
|
25
|
+
return (
|
|
26
|
+
<Stack orientation='horizontal'>
|
|
27
|
+
<Plank {...args} />
|
|
28
|
+
</Stack>
|
|
29
|
+
);
|
|
30
|
+
},
|
|
21
31
|
decorators: [
|
|
22
32
|
withPluginManager({
|
|
23
|
-
plugins: [IntentPlugin(), GraphPlugin()],
|
|
33
|
+
plugins: [AttentionPlugin(), SettingsPlugin(), IntentPlugin(), GraphPlugin()],
|
|
34
|
+
capabilities: () => DeckStateFactory(),
|
|
24
35
|
}),
|
|
25
36
|
withTheme,
|
|
26
|
-
withLayout({ fullscreen: true
|
|
37
|
+
withLayout({ fullscreen: true }),
|
|
27
38
|
],
|
|
28
39
|
parameters: {
|
|
29
|
-
layout: 'centered',
|
|
30
40
|
translations,
|
|
31
41
|
},
|
|
32
42
|
};
|
|
33
43
|
|
|
34
44
|
export default meta;
|
|
35
45
|
|
|
36
|
-
type Story = StoryObj<
|
|
46
|
+
type Story = StoryObj<PlankProps>;
|
|
37
47
|
|
|
48
|
+
// TODO(burdon): Need to define surface provider?
|
|
38
49
|
export const Default: Story = {
|
|
39
50
|
args: {
|
|
40
51
|
id: 'plank-1',
|
|
41
52
|
part: 'solo',
|
|
53
|
+
layoutMode: 'deck',
|
|
42
54
|
},
|
|
43
55
|
};
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import React, {
|
|
6
|
-
Fragment,
|
|
7
6
|
type KeyboardEvent,
|
|
8
7
|
type PropsWithChildren,
|
|
9
8
|
memo,
|
|
@@ -31,40 +30,117 @@ import { PlankContentError, PlankError } from './PlankError';
|
|
|
31
30
|
import { PlankHeading } from './PlankHeading';
|
|
32
31
|
import { PlankLoading } from './PlankLoading';
|
|
33
32
|
import { DeckCapabilities } from '../../capabilities';
|
|
34
|
-
import { useMainSize } from '../../hooks';
|
|
33
|
+
import { useMainSize, useCompanions } from '../../hooks';
|
|
35
34
|
import { parseEntryId } from '../../layout';
|
|
36
|
-
import { DeckAction, type LayoutMode, type
|
|
37
|
-
import { useCompanions } from '../../util';
|
|
35
|
+
import { DeckAction, type LayoutMode, type ResolvedPart, type DeckSettingsProps } from '../../types';
|
|
38
36
|
|
|
39
37
|
const UNKNOWN_ID = 'unknown_id';
|
|
40
38
|
|
|
41
|
-
export type PlankProps = {
|
|
39
|
+
export type PlankProps = Pick<PlankComponentProps, 'layoutMode' | 'part' | 'path' | 'order' | 'active' | 'settings'> & {
|
|
42
40
|
id?: string;
|
|
43
41
|
companionId?: string;
|
|
44
|
-
part: Part;
|
|
45
|
-
path?: string[];
|
|
46
|
-
order?: number;
|
|
47
|
-
active?: string[];
|
|
48
|
-
layoutMode: LayoutMode;
|
|
49
|
-
settings?: DeckSettingsProps;
|
|
50
42
|
};
|
|
51
43
|
|
|
52
|
-
|
|
44
|
+
// TODO(burdon): Factor out conditional rendering.
|
|
45
|
+
// Remove this wrapper component and render the entire set of planks in the deck with conditional visibility
|
|
46
|
+
// to obviate mounting and unmounting when switching between solo and companion mode?
|
|
47
|
+
// NOTE(thure, in reply): Whether any surface should be rendered and hidden is a performance matter — remember that
|
|
48
|
+
// article surfaces contain full experiences, so being able to unmount them will yield relatively large performance
|
|
49
|
+
// benefits. I think where we anticipate users will definitely want to quickly switch between showing and hiding entire
|
|
50
|
+
// articles, over the (again probably large) performance benefit that unmounting them would confer, we can mount and
|
|
51
|
+
// hide them, but I think that scenario in its most unambiguous form is probably rare. You could extrapolate
|
|
52
|
+
// the scenario to include all “potential” planks such as companions, which we could keep mounted and hidden, but I
|
|
53
|
+
// don’t think the resulting performance would be acceptable. I think the real issue is “perceived performance” which
|
|
54
|
+
// has mitigations that are in between mounting and un-mounting since both of those have tradeoffs; we may need one or more
|
|
55
|
+
// “partially-mounted” experiences, like loading skeletons at the simple end, or screenshots of “sleeping” planks at
|
|
56
|
+
// the advanced end.
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A Plank is the main container for surfaces within a Deck.
|
|
60
|
+
* It may be paired with a companion plank that enables the user to select one of multiple companion surfaces.
|
|
61
|
+
*/
|
|
62
|
+
export const Plank = memo(({ id = UNKNOWN_ID, companionId, ...props }: PlankProps) => {
|
|
63
|
+
const { graph } = useAppGraph();
|
|
64
|
+
const node = useNode(graph, id);
|
|
65
|
+
const companions = useCompanions(id);
|
|
66
|
+
const currentCompanion = companions.find(({ id }) => id === companionId);
|
|
67
|
+
const hasCompanion = !!(companionId && currentCompanion);
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<PlankContainer solo={props.part === 'solo'} companion={hasCompanion}>
|
|
71
|
+
<PlankComponent
|
|
72
|
+
id={id}
|
|
73
|
+
node={node}
|
|
74
|
+
companioned={hasCompanion ? 'primary' : undefined}
|
|
75
|
+
companions={hasCompanion ? [] : companions}
|
|
76
|
+
{...props}
|
|
77
|
+
{...(props.part === 'solo' ? { part: 'solo-primary' } : {})}
|
|
78
|
+
/>
|
|
79
|
+
{hasCompanion && (
|
|
80
|
+
<PlankComponent
|
|
81
|
+
id={companionId}
|
|
82
|
+
node={currentCompanion}
|
|
83
|
+
primary={node}
|
|
84
|
+
companions={companions}
|
|
85
|
+
companioned='companion'
|
|
86
|
+
{...props}
|
|
87
|
+
{...(props.part === 'solo' ? { part: 'solo-companion' } : { order: (props.order ?? 0) + 1 })}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
</PlankContainer>
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const PlankContainer = ({ children, solo, companion }: PropsWithChildren<{ solo: boolean; companion: boolean }>) => {
|
|
95
|
+
const sizeAttrs = useMainSize();
|
|
96
|
+
if (!solo) {
|
|
97
|
+
return children;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// TODO(burdon): Make resizable.
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
role='none'
|
|
104
|
+
className={mx('absolute inset-0 grid', companion && 'grid-cols-[1fr_1fr]', railGridHorizontal, mainIntrinsicSize)}
|
|
105
|
+
{...sizeAttrs}
|
|
106
|
+
>
|
|
107
|
+
{children}
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
type PlankComponentProps = {
|
|
113
|
+
layoutMode: LayoutMode;
|
|
53
114
|
id: string;
|
|
54
115
|
part: ResolvedPart;
|
|
55
|
-
|
|
116
|
+
path?: string[];
|
|
117
|
+
order?: number;
|
|
118
|
+
active?: string[];
|
|
119
|
+
// TODO(burdon): Change to role?
|
|
56
120
|
companioned?: 'primary' | 'companion';
|
|
121
|
+
node?: Node;
|
|
57
122
|
primary?: Node;
|
|
58
123
|
companions?: Node[];
|
|
124
|
+
settings?: DeckSettingsProps;
|
|
59
125
|
};
|
|
60
126
|
|
|
61
|
-
const
|
|
62
|
-
({
|
|
127
|
+
const PlankComponent = memo(
|
|
128
|
+
({
|
|
129
|
+
layoutMode,
|
|
130
|
+
id,
|
|
131
|
+
part,
|
|
132
|
+
path,
|
|
133
|
+
order,
|
|
134
|
+
active,
|
|
135
|
+
companioned,
|
|
136
|
+
node,
|
|
137
|
+
primary,
|
|
138
|
+
companions,
|
|
139
|
+
settings,
|
|
140
|
+
}: PlankComponentProps) => {
|
|
63
141
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
64
142
|
const { deck, popoverAnchorId, scrollIntoView } = useCapability(DeckCapabilities.DeckState);
|
|
65
|
-
const rootElement = useRef<HTMLDivElement | null>(null);
|
|
66
143
|
const canResize = layoutMode === 'deck';
|
|
67
|
-
const Root = part.startsWith('solo') ? 'article' : StackItem.Root;
|
|
68
144
|
|
|
69
145
|
const attendableAttrs = useAttendableAttributes(primary?.id ?? id);
|
|
70
146
|
const index = active ? active.findIndex((entryId) => entryId === id) : 0;
|
|
@@ -72,10 +148,13 @@ const PlankImpl = memo(
|
|
|
72
148
|
const canIncrementStart = active && index !== undefined && index > 0 && length !== undefined && length > 1;
|
|
73
149
|
const canIncrementEnd = active && index !== undefined && index < length - 1 && length !== undefined;
|
|
74
150
|
|
|
151
|
+
const rootElement = useRef<HTMLDivElement | null>(null);
|
|
152
|
+
|
|
75
153
|
const { variant } = parseEntryId(id);
|
|
76
154
|
const sizeKey = `${id.split('+')[0]}${variant ? `${ATTENDABLE_PATH_SEPARATOR}${variant}` : ''}`;
|
|
77
155
|
const size = deck.plankSizing[sizeKey] as number | undefined;
|
|
78
|
-
|
|
156
|
+
|
|
157
|
+
const handleSizeChange = useCallback(
|
|
79
158
|
debounce((nextSize: number) => {
|
|
80
159
|
return dispatch(createIntent(DeckAction.UpdatePlankSize, { id: sizeKey, size: nextSize }));
|
|
81
160
|
}, 200),
|
|
@@ -101,9 +180,9 @@ const PlankImpl = memo(
|
|
|
101
180
|
}
|
|
102
181
|
}, [id, scrollIntoView, layoutMode]);
|
|
103
182
|
|
|
104
|
-
const isSolo = layoutMode
|
|
183
|
+
const isSolo = layoutMode.startsWith('solo') && part === 'solo';
|
|
105
184
|
const isAttendable =
|
|
106
|
-
(layoutMode
|
|
185
|
+
(layoutMode.startsWith('solo') && part.startsWith('solo')) || (layoutMode === 'deck' && part === 'deck');
|
|
107
186
|
|
|
108
187
|
const sizeAttrs = useMainSize();
|
|
109
188
|
|
|
@@ -116,14 +195,15 @@ const PlankImpl = memo(
|
|
|
116
195
|
path,
|
|
117
196
|
popoverAnchorId,
|
|
118
197
|
},
|
|
119
|
-
[node, node?.data, path, popoverAnchorId, primary?.data],
|
|
198
|
+
[node, node?.data, path, popoverAnchorId, primary?.data, variant],
|
|
120
199
|
);
|
|
121
200
|
|
|
122
201
|
// TODO(wittjosiah): Change prop to accept a component.
|
|
123
202
|
const placeholder = useMemo(() => <PlankLoading />, []);
|
|
124
203
|
|
|
204
|
+
const Root = part.startsWith('solo') ? 'article' : StackItem.Root;
|
|
125
205
|
const className = mx(
|
|
126
|
-
'attention-surface relative',
|
|
206
|
+
'attention-surface relative dx-focus-ring-inset-over-all',
|
|
127
207
|
isSolo && mainIntrinsicSize,
|
|
128
208
|
isSolo && railGridHorizontal,
|
|
129
209
|
isSolo && 'absolute inset-0',
|
|
@@ -143,7 +223,7 @@ const PlankImpl = memo(
|
|
|
143
223
|
: {
|
|
144
224
|
item: { id },
|
|
145
225
|
size,
|
|
146
|
-
onSizeChange:
|
|
226
|
+
onSizeChange: handleSizeChange,
|
|
147
227
|
classNames: className,
|
|
148
228
|
order,
|
|
149
229
|
role: 'article',
|
|
@@ -157,6 +237,7 @@ const PlankImpl = memo(
|
|
|
157
237
|
id={id}
|
|
158
238
|
part={part.startsWith('solo-') ? 'solo' : part}
|
|
159
239
|
node={node}
|
|
240
|
+
layoutMode={layoutMode}
|
|
160
241
|
deckEnabled={settings?.enableDeck}
|
|
161
242
|
canIncrementStart={canIncrementStart}
|
|
162
243
|
canIncrementEnd={canIncrementEnd}
|
|
@@ -177,54 +258,9 @@ const PlankImpl = memo(
|
|
|
177
258
|
) : (
|
|
178
259
|
<PlankError id={id} part={part} />
|
|
179
260
|
)}
|
|
261
|
+
|
|
180
262
|
{canResize && <StackItem.ResizeHandle />}
|
|
181
263
|
</Root>
|
|
182
264
|
);
|
|
183
265
|
},
|
|
184
266
|
);
|
|
185
|
-
|
|
186
|
-
const SplitFrame = ({ children }: PropsWithChildren<{}>) => {
|
|
187
|
-
const sizeAttrs = useMainSize();
|
|
188
|
-
return (
|
|
189
|
-
<div
|
|
190
|
-
role='none'
|
|
191
|
-
className={mx('grid grid-cols-[1fr_1fr] absolute inset-0', railGridHorizontal, mainIntrinsicSize)}
|
|
192
|
-
{...sizeAttrs}
|
|
193
|
-
>
|
|
194
|
-
{children}
|
|
195
|
-
</div>
|
|
196
|
-
);
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
export const Plank = ({ id = UNKNOWN_ID, ...props }: PlankProps) => {
|
|
200
|
-
const { graph } = useAppGraph();
|
|
201
|
-
const node = useNode(graph, id);
|
|
202
|
-
const companions = useCompanions(id);
|
|
203
|
-
const currentCompanion = companions.find(({ id }) => id === props.companionId);
|
|
204
|
-
|
|
205
|
-
if (props.companionId) {
|
|
206
|
-
const Root = props.part === 'solo' ? SplitFrame : Fragment;
|
|
207
|
-
return (
|
|
208
|
-
<Root>
|
|
209
|
-
<PlankImpl
|
|
210
|
-
id={id}
|
|
211
|
-
node={node}
|
|
212
|
-
companioned='primary'
|
|
213
|
-
{...props}
|
|
214
|
-
{...(props.part === 'solo' ? { part: 'solo-primary' } : {})}
|
|
215
|
-
/>
|
|
216
|
-
<PlankImpl
|
|
217
|
-
id={props.companionId}
|
|
218
|
-
node={currentCompanion}
|
|
219
|
-
companioned='companion'
|
|
220
|
-
primary={node}
|
|
221
|
-
companions={companions}
|
|
222
|
-
{...props}
|
|
223
|
-
{...(props.part === 'solo' ? { part: 'solo-companion' } : { order: props.order! + 1 })}
|
|
224
|
-
/>
|
|
225
|
-
</Root>
|
|
226
|
-
);
|
|
227
|
-
} else {
|
|
228
|
-
return <PlankImpl id={id} node={node} companions={companions} {...props} />;
|
|
229
|
-
}
|
|
230
|
-
};
|
|
@@ -6,18 +6,10 @@ import React, { forwardRef, useCallback } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { createIntent, useIntentDispatcher } from '@dxos/app-framework';
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
|
-
import {
|
|
10
|
-
Button,
|
|
11
|
-
ButtonGroup,
|
|
12
|
-
type ButtonGroupProps,
|
|
13
|
-
type ButtonProps,
|
|
14
|
-
Icon,
|
|
15
|
-
Tooltip,
|
|
16
|
-
useTranslation,
|
|
17
|
-
} from '@dxos/react-ui';
|
|
9
|
+
import { ButtonGroup, type ButtonGroupProps, type ButtonProps, IconButton, useTranslation } from '@dxos/react-ui';
|
|
18
10
|
|
|
19
11
|
import { DECK_PLUGIN } from '../../meta';
|
|
20
|
-
import { DeckAction } from '../../types';
|
|
12
|
+
import { DeckAction, type LayoutMode } from '../../types';
|
|
21
13
|
|
|
22
14
|
export type PlankControlHandler = (event: DeckAction.PartAdjustment) => void;
|
|
23
15
|
|
|
@@ -26,6 +18,7 @@ export type PlankCapabilities = {
|
|
|
26
18
|
incrementEnd?: boolean;
|
|
27
19
|
deck?: boolean;
|
|
28
20
|
solo?: boolean;
|
|
21
|
+
fullscreen?: boolean;
|
|
29
22
|
companion?: boolean;
|
|
30
23
|
};
|
|
31
24
|
|
|
@@ -34,27 +27,15 @@ export type PlankControlsProps = Omit<ButtonGroupProps, 'onClick'> & {
|
|
|
34
27
|
variant?: 'hide-disabled' | 'default';
|
|
35
28
|
close?: boolean | 'minify-start' | 'minify-end';
|
|
36
29
|
capabilities: PlankCapabilities;
|
|
37
|
-
|
|
30
|
+
layoutMode?: LayoutMode;
|
|
38
31
|
pin?: 'start' | 'end' | 'both';
|
|
39
32
|
};
|
|
40
33
|
|
|
41
34
|
const PlankControl = ({ icon, label, ...props }: Omit<ButtonProps, 'children'> & { label: string; icon: string }) => {
|
|
42
|
-
return
|
|
43
|
-
<Tooltip.Root>
|
|
44
|
-
<Tooltip.Trigger asChild>
|
|
45
|
-
<Button variant='ghost' {...props}>
|
|
46
|
-
<span className='sr-only'>{label}</span>
|
|
47
|
-
<Icon icon={icon} size={5} />
|
|
48
|
-
</Button>
|
|
49
|
-
</Tooltip.Trigger>
|
|
50
|
-
<Tooltip.Portal>
|
|
51
|
-
<Tooltip.Content side='bottom'>{label}</Tooltip.Content>
|
|
52
|
-
</Tooltip.Portal>
|
|
53
|
-
</Tooltip.Root>
|
|
54
|
-
);
|
|
35
|
+
return <IconButton iconOnly label={label} icon={icon} size={5} variant='ghost' tooltipSide='bottom' {...props} />;
|
|
55
36
|
};
|
|
56
37
|
|
|
57
|
-
const plankControlSpacing = 'pli-2
|
|
38
|
+
const plankControlSpacing = 'pli-2';
|
|
58
39
|
|
|
59
40
|
type PlankComplimentControlsProps = {
|
|
60
41
|
primary?: string;
|
|
@@ -73,8 +54,7 @@ export const PlankCompanionControls = forwardRef<HTMLDivElement, PlankCompliment
|
|
|
73
54
|
<PlankControl
|
|
74
55
|
label={t('close companion label')}
|
|
75
56
|
variant='ghost'
|
|
76
|
-
|
|
77
|
-
icon='ph--caret-left--regular'
|
|
57
|
+
icon='ph--x--regular'
|
|
78
58
|
onClick={handleCloseCompanion}
|
|
79
59
|
classNames={plankControlSpacing}
|
|
80
60
|
/>
|
|
@@ -88,35 +68,51 @@ export const PlankCompanionControls = forwardRef<HTMLDivElement, PlankCompliment
|
|
|
88
68
|
// NOTE(thure): Pinning & unpinning are disabled indefinitely.
|
|
89
69
|
export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
|
|
90
70
|
(
|
|
91
|
-
{ children, classNames, variant = 'default', capabilities,
|
|
71
|
+
{ children, classNames, variant = 'default', capabilities, layoutMode, pin, close = false, onClick, ...props },
|
|
92
72
|
forwardedRef,
|
|
93
73
|
) => {
|
|
94
74
|
const { t } = useTranslation(DECK_PLUGIN);
|
|
95
75
|
const buttonClassNames =
|
|
96
76
|
variant === 'hide-disabled' ? `disabled:hidden ${plankControlSpacing}` : plankControlSpacing;
|
|
97
77
|
|
|
98
|
-
|
|
99
|
-
<ButtonGroup {...props} classNames={['app-no-drag', classNames]} ref={forwardedRef}>
|
|
100
|
-
{/* {pin && !isSolo && ['both', 'start'].includes(pin) && (
|
|
101
|
-
<PlankControl
|
|
102
|
-
label={t('pin start label')}
|
|
103
|
-
variant='ghost'
|
|
104
|
-
classNames={buttonClassNames}
|
|
105
|
-
onClick={() => onClick?.('pin-start')}
|
|
106
|
-
icon='ph--caret-line-left--regular'
|
|
107
|
-
/>
|
|
108
|
-
)} */}
|
|
78
|
+
const layoutIsAnySolo = !!layoutMode?.startsWith('solo');
|
|
109
79
|
|
|
110
|
-
|
|
80
|
+
return (
|
|
81
|
+
<ButtonGroup {...props} classNames={['app-no-drag !opacity-100', classNames]} ref={forwardedRef}>
|
|
82
|
+
{capabilities.deck ? (
|
|
111
83
|
<>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
84
|
+
{capabilities.solo && (
|
|
85
|
+
<>
|
|
86
|
+
{layoutMode === 'solo' && (
|
|
87
|
+
<PlankControl
|
|
88
|
+
label={t('show fullscreen plank label')}
|
|
89
|
+
classNames={buttonClassNames}
|
|
90
|
+
icon='ph--corners-out--regular'
|
|
91
|
+
onClick={() => onClick?.('solo--fullscreen')}
|
|
92
|
+
/>
|
|
93
|
+
)}
|
|
94
|
+
<PlankControl
|
|
95
|
+
label={t(
|
|
96
|
+
layoutMode === 'solo--fullscreen'
|
|
97
|
+
? 'exit fullscreen label'
|
|
98
|
+
: layoutIsAnySolo
|
|
99
|
+
? 'show deck plank label'
|
|
100
|
+
: 'show solo plank label',
|
|
101
|
+
)}
|
|
102
|
+
classNames={buttonClassNames}
|
|
103
|
+
icon={
|
|
104
|
+
layoutMode === 'solo--fullscreen'
|
|
105
|
+
? 'ph--corners-in--regular'
|
|
106
|
+
: layoutIsAnySolo
|
|
107
|
+
? 'ph--arrows-in-line-horizontal--regular'
|
|
108
|
+
: 'ph--arrows-out-line-horizontal--regular'
|
|
109
|
+
}
|
|
110
|
+
onClick={() => onClick?.(layoutMode === 'solo--fullscreen' ? 'solo--fullscreen' : 'solo')}
|
|
111
|
+
/>
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
118
114
|
|
|
119
|
-
{!
|
|
115
|
+
{!layoutIsAnySolo && (
|
|
120
116
|
<>
|
|
121
117
|
<PlankControl
|
|
122
118
|
label={t('increment start label')}
|
|
@@ -135,18 +131,18 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
|
|
|
135
131
|
</>
|
|
136
132
|
)}
|
|
137
133
|
</>
|
|
134
|
+
) : (
|
|
135
|
+
capabilities.fullscreen && (
|
|
136
|
+
<PlankControl
|
|
137
|
+
label={t(layoutMode === 'solo--fullscreen' ? 'exit fullscreen label' : 'show fullscreen plank label')}
|
|
138
|
+
classNames={buttonClassNames}
|
|
139
|
+
icon={layoutMode === 'solo--fullscreen' ? 'ph--corners-in--regular' : 'ph--corners-out--regular'}
|
|
140
|
+
onClick={() => onClick?.('solo--fullscreen')}
|
|
141
|
+
/>
|
|
142
|
+
)
|
|
138
143
|
)}
|
|
139
144
|
|
|
140
|
-
{
|
|
141
|
-
<PlankControl
|
|
142
|
-
label={t('pin end label')}
|
|
143
|
-
classNames={buttonClassNames}
|
|
144
|
-
icon='ph--caret-line-right--regular'
|
|
145
|
-
onClick={() => onClick?.('pin-end')}
|
|
146
|
-
/>
|
|
147
|
-
)} */}
|
|
148
|
-
|
|
149
|
-
{close && !isSolo && (
|
|
145
|
+
{close && !layoutIsAnySolo && (
|
|
150
146
|
<PlankControl
|
|
151
147
|
label={t(`${typeof close === 'string' ? 'minify' : 'close'} label`)}
|
|
152
148
|
classNames={buttonClassNames}
|
|
@@ -6,7 +6,7 @@ import React, { useEffect, useState } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { type Node } from '@dxos/plugin-graph';
|
|
8
8
|
import { useTranslation } from '@dxos/react-ui';
|
|
9
|
-
import {
|
|
9
|
+
import { descriptionMessage, mx } from '@dxos/react-ui-theme';
|
|
10
10
|
|
|
11
11
|
import { PlankHeading, type PlankHeadingProps } from './PlankHeading';
|
|
12
12
|
import { PlankLoading } from './PlankLoading';
|
|
@@ -19,11 +19,7 @@ export const PlankContentError = ({ error }: { error?: Error }) => {
|
|
|
19
19
|
<div role='none' className='overflow-auto p-8 attention-surface grid place-items-center'>
|
|
20
20
|
<p
|
|
21
21
|
role='alert'
|
|
22
|
-
className={mx(
|
|
23
|
-
descriptionText,
|
|
24
|
-
'break-words border border-dashed border-separator rounded-lg p-8',
|
|
25
|
-
errorString.length < 256 && 'text-lg',
|
|
26
|
-
)}
|
|
22
|
+
className={mx(descriptionMessage, 'break-words rounded-lg p-8', errorString.length < 256 && 'text-lg')}
|
|
27
23
|
>
|
|
28
24
|
{error ? errorString : t('error fallback message')}
|
|
29
25
|
</p>
|
|
@@ -9,17 +9,21 @@ import { type Node } from '@dxos/plugin-graph';
|
|
|
9
9
|
import { Icon, IconButton, Popover, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
10
10
|
import { StackItem, type StackItemSigilAction } from '@dxos/react-ui-stack';
|
|
11
11
|
import { TextTooltip } from '@dxos/react-ui-text-tooltip';
|
|
12
|
+
import { hoverableControls, hoverableFocusedWithinControls } from '@dxos/react-ui-theme';
|
|
12
13
|
|
|
13
14
|
import { PlankCompanionControls, PlankControls } from './PlankControls';
|
|
15
|
+
import { useBreakpoints } from '../../hooks';
|
|
14
16
|
import { parseEntryId } from '../../layout';
|
|
15
17
|
import { DECK_PLUGIN } from '../../meta';
|
|
16
|
-
import { PLANK_COMPANION_TYPE, DeckAction, type ResolvedPart } from '../../types';
|
|
17
|
-
import { useBreakpoints } from '../../util';
|
|
18
|
+
import { PLANK_COMPANION_TYPE, DeckAction, type ResolvedPart, type LayoutMode } from '../../types';
|
|
18
19
|
import { soloInlinePadding } from '../fragments';
|
|
19
20
|
|
|
21
|
+
const MAX_COMPANIONS = 5;
|
|
22
|
+
|
|
20
23
|
export type PlankHeadingProps = {
|
|
21
24
|
id: string;
|
|
22
25
|
part: ResolvedPart;
|
|
26
|
+
layoutMode?: LayoutMode;
|
|
23
27
|
node?: Node;
|
|
24
28
|
deckEnabled?: boolean;
|
|
25
29
|
canIncrementStart?: boolean;
|
|
@@ -45,6 +49,7 @@ export const PlankHeading = memo(
|
|
|
45
49
|
pending,
|
|
46
50
|
companioned,
|
|
47
51
|
companions,
|
|
52
|
+
layoutMode,
|
|
48
53
|
actions = [],
|
|
49
54
|
}: PlankHeadingProps) => {
|
|
50
55
|
const { t } = useTranslation(DECK_PLUGIN);
|
|
@@ -61,7 +66,9 @@ export const PlankHeading = memo(
|
|
|
61
66
|
useEffect(() => {
|
|
62
67
|
const frame = requestAnimationFrame(() => {
|
|
63
68
|
// Load actions for the node.
|
|
64
|
-
|
|
69
|
+
if (node) {
|
|
70
|
+
void graph.expand(node.id);
|
|
71
|
+
}
|
|
65
72
|
});
|
|
66
73
|
|
|
67
74
|
return () => cancelAnimationFrame(frame);
|
|
@@ -74,6 +81,7 @@ export const PlankHeading = memo(
|
|
|
74
81
|
solo: breakpoint !== 'mobile' && (part === 'solo' || part === 'deck'),
|
|
75
82
|
incrementStart: canIncrementStart,
|
|
76
83
|
incrementEnd: canIncrementEnd,
|
|
84
|
+
fullscreen: !isCompanionNode,
|
|
77
85
|
companion: !isCompanionNode && companions && companions.length > 0,
|
|
78
86
|
}),
|
|
79
87
|
[breakpoint, part, companions, canIncrementStart, canIncrementEnd, isCompanionNode, deckEnabled],
|
|
@@ -86,17 +94,20 @@ export const PlankHeading = memo(
|
|
|
86
94
|
} else if (variant) {
|
|
87
95
|
return [];
|
|
88
96
|
} else {
|
|
89
|
-
return [actions, graph.
|
|
97
|
+
return [actions, graph.getActions(node.id)].filter((a) => a.length > 0);
|
|
90
98
|
}
|
|
91
99
|
}, [actions, node, variant, graph]);
|
|
92
100
|
|
|
93
|
-
const handleAction = useCallback(
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
const handleAction = useCallback(
|
|
102
|
+
(action: StackItemSigilAction) => {
|
|
103
|
+
typeof action.data === 'function' && action.data?.({ parent: node, caller: DECK_PLUGIN });
|
|
104
|
+
},
|
|
105
|
+
[node],
|
|
106
|
+
);
|
|
96
107
|
|
|
97
108
|
const handlePlankAction = useCallback(
|
|
98
109
|
(eventType: DeckAction.PartAdjustment) => {
|
|
99
|
-
if (eventType
|
|
110
|
+
if (eventType.startsWith('solo')) {
|
|
100
111
|
return dispatch(createIntent(DeckAction.Adjust, { type: eventType, id }));
|
|
101
112
|
} else if (eventType === 'close') {
|
|
102
113
|
if (part === 'complementary') {
|
|
@@ -139,18 +150,26 @@ export const PlankHeading = memo(
|
|
|
139
150
|
return (
|
|
140
151
|
<StackItem.Heading
|
|
141
152
|
classNames={[
|
|
142
|
-
'plb-1 border-be border-
|
|
153
|
+
'plb-1 border-be border-subduedSeparator items-stretch gap-1 sticky inline-start-12 app-drag min-is-0 contain-layout',
|
|
143
154
|
part === 'solo' ? soloInlinePadding : 'pli-1',
|
|
155
|
+
...(layoutMode === 'solo--fullscreen'
|
|
156
|
+
? [
|
|
157
|
+
hoverableControls,
|
|
158
|
+
hoverableFocusedWithinControls,
|
|
159
|
+
'[&>*]:transition-opacity [&>*]:opacity-[--controls-opacity] bg-transparent border-transparent transition-[background-color,border-color] hover-hover:hover:bg-headerSurface focus-within:bg-headerSurface hover-hover:hover:border-subduedSeparator focus-within:border-subduedSeparator',
|
|
160
|
+
]
|
|
161
|
+
: []),
|
|
144
162
|
]}
|
|
163
|
+
data-plank-heading
|
|
145
164
|
>
|
|
146
|
-
{companions && isCompanionNode ? (
|
|
165
|
+
{companions && isCompanionNode /* TODO(thure): This is a tablist, it should be implemented as such. */ ? (
|
|
147
166
|
<div role='none' className='flex-1 min-is-0 overflow-x-auto scrollbar-thin flex gap-1'>
|
|
148
167
|
{companions.map(({ id, properties: { icon, label } }) => (
|
|
149
168
|
<IconButton
|
|
150
169
|
key={id}
|
|
151
170
|
data-id={id}
|
|
152
171
|
icon={icon}
|
|
153
|
-
iconOnly={node?.id !== id}
|
|
172
|
+
iconOnly={companions.length > MAX_COMPANIONS && node?.id !== id}
|
|
154
173
|
label={toLocalizedString(label, t)}
|
|
155
174
|
size={5}
|
|
156
175
|
variant={node?.id === id ? 'primary' : 'default'}
|
|
@@ -196,7 +215,7 @@ export const PlankHeading = memo(
|
|
|
196
215
|
) : (
|
|
197
216
|
<PlankControls
|
|
198
217
|
capabilities={capabilities}
|
|
199
|
-
|
|
218
|
+
layoutMode={layoutMode}
|
|
200
219
|
close={part === 'complementary' ? 'minify-end' : true}
|
|
201
220
|
onClick={handlePlankAction}
|
|
202
221
|
/>
|