@dxos/app-framework 0.3.10-main.678d1a6 → 0.3.10-main.74608f1

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 (43) hide show
  1. package/dist/lib/browser/index.mjs +267 -34
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +273 -46
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/types/src/plugins/PluginHost/PluginContext.d.ts +1 -8
  8. package/dist/types/src/plugins/PluginHost/PluginContext.d.ts.map +1 -1
  9. package/dist/types/src/plugins/PluginHost/PluginHost.d.ts.map +1 -1
  10. package/dist/types/src/plugins/PluginHost/plugin.d.ts +8 -0
  11. package/dist/types/src/plugins/PluginHost/plugin.d.ts.map +1 -1
  12. package/dist/types/src/plugins/common/index.d.ts +1 -0
  13. package/dist/types/src/plugins/common/index.d.ts.map +1 -1
  14. package/dist/types/src/plugins/common/layout.d.ts +9 -6
  15. package/dist/types/src/plugins/common/layout.d.ts.map +1 -1
  16. package/dist/types/src/plugins/common/settings.d.ts +8 -0
  17. package/dist/types/src/plugins/common/settings.d.ts.map +1 -0
  18. package/dist/types/src/plugins/components/CommandsDialog.d.ts +5 -0
  19. package/dist/types/src/plugins/components/CommandsDialog.d.ts.map +1 -0
  20. package/dist/types/src/plugins/components/SettingsDialog.d.ts +2 -0
  21. package/dist/types/src/plugins/components/SettingsDialog.d.ts.map +1 -0
  22. package/dist/types/src/plugins/components/SettingsValue.d.ts +8 -0
  23. package/dist/types/src/plugins/components/SettingsValue.d.ts.map +1 -0
  24. package/dist/types/src/plugins/components/ShortcutsDialog.d.ts +2 -0
  25. package/dist/types/src/plugins/components/ShortcutsDialog.d.ts.map +1 -0
  26. package/dist/types/src/plugins/components/index.d.ts +5 -0
  27. package/dist/types/src/plugins/components/index.d.ts.map +1 -0
  28. package/dist/types/src/plugins/index.d.ts +1 -0
  29. package/dist/types/src/plugins/index.d.ts.map +1 -1
  30. package/package.json +16 -9
  31. package/src/plugins/PluginHost/PluginContext.tsx +2 -11
  32. package/src/plugins/PluginHost/PluginHost.tsx +6 -5
  33. package/src/plugins/PluginHost/plugin.ts +5 -0
  34. package/src/plugins/common/index.ts +1 -0
  35. package/src/plugins/common/layout.ts +10 -3
  36. package/src/plugins/common/settings.ts +16 -0
  37. package/src/plugins/components/CommandsDialog.tsx +102 -0
  38. package/src/plugins/components/SettingsDialog.tsx +98 -0
  39. package/src/plugins/components/SettingsValue.tsx +36 -0
  40. package/src/plugins/components/ShortcutsDialog.tsx +59 -0
  41. package/src/plugins/components/index.ts +8 -0
  42. package/src/plugins/index.ts +1 -0
  43. package/tsconfig.json +15 -0
@@ -1,4 +1,5 @@
1
1
  export * from './common';
2
+ export * from './components';
2
3
  export * from './helpers';
3
4
  export * from './IntentPlugin';
4
5
  export * from './PluginHost';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAE1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAE1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/app-framework",
3
- "version": "0.3.10-main.678d1a6",
3
+ "version": "0.3.10-main.74608f1",
4
4
  "description": "A framework for building applications from composible plugins.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -16,19 +16,26 @@
16
16
  "@preact/signals-react": "^1.3.6",
17
17
  "deepsignal": "1.4.0-shallow.0",
18
18
  "zod": "^3.22.4",
19
- "@dxos/app-graph": "0.3.10-main.678d1a6",
20
- "@dxos/async": "0.3.10-main.678d1a6",
21
- "@dxos/local-storage": "0.3.10-main.678d1a6",
22
- "@dxos/invariant": "0.3.10-main.678d1a6",
23
- "@dxos/log": "0.3.10-main.678d1a6",
24
- "@dxos/debug": "0.3.10-main.678d1a6"
19
+ "@dxos/app-graph": "0.3.10-main.74608f1",
20
+ "@dxos/async": "0.3.10-main.74608f1",
21
+ "@dxos/debug": "0.3.10-main.74608f1",
22
+ "@dxos/keyboard": "0.3.10-main.74608f1",
23
+ "@dxos/invariant": "0.3.10-main.74608f1",
24
+ "@dxos/local-storage": "0.3.10-main.74608f1",
25
+ "@dxos/log": "0.3.10-main.74608f1",
26
+ "@dxos/react-ui-searchlist": "0.3.10-main.74608f1"
25
27
  },
26
28
  "devDependencies": {
27
29
  "@types/react": "^18.0.21",
28
- "react": "^18.2.0"
30
+ "react": "^18.2.0",
31
+ "@dxos/storybook-utils": "0.3.10-main.74608f1",
32
+ "@dxos/react-ui-theme": "0.3.10-main.74608f1",
33
+ "@dxos/react-ui": "0.3.10-main.74608f1"
29
34
  },
30
35
  "peerDependencies": {
31
- "react": "*"
36
+ "react": "*",
37
+ "@dxos/react-ui-theme": "0.3.10-main.74608f1",
38
+ "@dxos/react-ui": "0.3.10-main.74608f1"
32
39
  },
33
40
  "publishConfig": {
34
41
  "access": "public"
@@ -30,17 +30,9 @@ export type PluginContext = {
30
30
 
31
31
  /**
32
32
  * Mark plugin as enabled.
33
- *
34
33
  * Requires reload to take effect.
35
34
  */
36
- enablePlugin: (id: string) => void;
37
-
38
- /**
39
- * Mark plugin as disabled.
40
- *
41
- * Requires reload to take effect.
42
- */
43
- disablePlugin: (id: string) => void;
35
+ setPlugin: (id: string, enabled: boolean) => void;
44
36
  };
45
37
 
46
38
  const PluginContext: Context<PluginContext> = createContext<PluginContext>({
@@ -48,8 +40,7 @@ const PluginContext: Context<PluginContext> = createContext<PluginContext>({
48
40
  enabled: [],
49
41
  plugins: [],
50
42
  available: [],
51
- enablePlugin: () => {},
52
- disablePlugin: () => {},
43
+ setPlugin: () => {},
53
44
  });
54
45
 
55
46
  /**
@@ -43,11 +43,12 @@ export const PluginHost = ({
43
43
  enabled: [...defaults],
44
44
  plugins: [],
45
45
  available: order.filter(({ id }) => !core.includes(id)),
46
- enablePlugin: (id: string) => {
47
- state.values.enabled = [...state.values.enabled, id];
48
- },
49
- disablePlugin: (id: string) => {
50
- state.values.enabled = state.values.enabled.filter((enabled) => enabled !== id);
46
+ setPlugin: (id: string, enabled: boolean) => {
47
+ if (enabled) {
48
+ state.values.enabled = [...state.values.enabled, id];
49
+ } else {
50
+ state.values.enabled = state.values.enabled.filter((enabled) => enabled !== id);
51
+ }
51
52
  },
52
53
  });
53
54
 
@@ -54,6 +54,11 @@ export type Plugin<TProvides = {}> = {
54
54
  */
55
55
  description?: string;
56
56
 
57
+ /**
58
+ * URL of home page.
59
+ */
60
+ homePage?: string;
61
+
57
62
  /**
58
63
  * Tags to help categorize the plugin.
59
64
  */
@@ -5,4 +5,5 @@
5
5
  export * from './graph';
6
6
  export * from './layout';
7
7
  export * from './metadata';
8
+ export * from './settings';
8
9
  export * from './translations';
@@ -13,17 +13,19 @@ import type { Plugin } from '../PluginHost';
13
13
  /**
14
14
  * Basic state provided by a layout plugin.
15
15
  */
16
+ // TODO(burdon): Josiah: why do we use zod here?
16
17
  export const Layout = z.object({
17
18
  fullscreen: z.boolean(),
18
19
  sidebarOpen: z.boolean(),
19
20
  complementarySidebarOpen: z.boolean(),
20
21
 
21
- dialogContent: z.any().optional().describe('Data to be passed to the dialog Surface.'),
22
+ // TODO(burdon): Why do we have a single root?
22
23
  dialogOpen: z.boolean(),
24
+ dialogContent: z.any().optional().describe('Data to be passed to the dialog Surface.'),
23
25
 
24
- popoverAnchorId: z.string().optional(),
25
- popoverContent: z.any().optional().describe('Data to be passed to the popover Surface.'),
26
26
  popoverOpen: z.boolean(),
27
+ popoverContent: z.any().optional().describe('Data to be passed to the popover Surface.'),
28
+ popoverAnchorId: z.string().optional(),
27
29
 
28
30
  // TODO(wittjosiah): Array?
29
31
  active: z.string().optional().describe('Id of the currently active item.'),
@@ -63,6 +65,11 @@ export enum LayoutAction {
63
65
  OPEN_POPOVER = `${LAYOUT_ACTION}/open-popover`,
64
66
  CLOSE_POPOVER = `${LAYOUT_ACTION}/close-popover`,
65
67
  ACTIVATE = `${LAYOUT_ACTION}/activate`,
68
+
69
+ // TODO(burdon): Move to new plugin.
70
+ OPEN_COMMANDS = `${LAYOUT_ACTION}/open-commands`,
71
+ OPEN_SETTINGS = `${LAYOUT_ACTION}/open-settings`,
72
+ OPEN_SHORTCUTS = `${LAYOUT_ACTION}/open-shortcuts`,
66
73
  }
67
74
 
68
75
  /**
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Plugin } from '../PluginHost';
6
+
7
+ // TODO(burdon): Plugins should export ts-effect object (see local-storage).
8
+ // TODO(burdon): Auto generate form.
9
+ // TODO(burdon): Set surface's data.type to plugin id (allow custom settings surface).
10
+
11
+ export type SettingsProvides<T> = {
12
+ settings: {
13
+ meta: Plugin['meta'];
14
+ values: T; // TODO(burdon): Read-only?
15
+ };
16
+ };
@@ -0,0 +1,102 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { DotOutline } from '@phosphor-icons/react';
6
+ import React, { useMemo, useRef } from 'react';
7
+
8
+ import { type Action, type Graph, type Label } from '@dxos/app-graph';
9
+ import { Keyboard, keySymbols } from '@dxos/keyboard';
10
+ import { Button, Dialog, useTranslation } from '@dxos/react-ui';
11
+ import { SearchList } from '@dxos/react-ui-searchlist';
12
+ import { descriptionText, getSize, mx } from '@dxos/react-ui-theme';
13
+
14
+ export const CommandsDialogContent = ({ graph }: { graph?: Graph }) => {
15
+ const { t } = useTranslation('os');
16
+
17
+ // TODO(burdon): Factor out.
18
+ // TODO(burdon): How to access all translations across plugins?
19
+ const getLabel = (label: Label) => (Array.isArray(label) ? t(...label) : label);
20
+
21
+ // Traverse graph.
22
+ // TODO(burdon): Factor out commonality with shortcuts.
23
+ const actions = useMemo(() => {
24
+ // TODO(burdon): Get from navtree (not keyboard).
25
+ const current = Keyboard.singleton.getCurrentContext();
26
+ const actionMap = new Set<string>();
27
+ const actions: Action[] = [];
28
+ graph?.traverse({
29
+ visitor: (node, path) => {
30
+ if (current.startsWith(path.join('/'))) {
31
+ node.actions.forEach((action) => {
32
+ if (!actionMap.has(action.id)) {
33
+ actionMap.add(action.id);
34
+ actions.push(action);
35
+ }
36
+ });
37
+ }
38
+ },
39
+ });
40
+
41
+ // console.log(JSON.stringify(actions, undefined, 2));
42
+ return actions;
43
+ }, [graph]);
44
+
45
+ // TODO(burdon): Remove.
46
+ const buttonRef = useRef<HTMLButtonElement>(null);
47
+
48
+ return (
49
+ <Dialog.Content classNames={['h-[50%] md:max-is-[30rem] overflow-hidden']}>
50
+ <Dialog.Title>{t('commands dialog title', { ns: 'os' })}</Dialog.Title>
51
+
52
+ <SearchList.Root label={t('commandlist input placeholder')} classNames='flex flex-col grow overflow-hidden my-2'>
53
+ <SearchList.Input placeholder={t('commandlist input placeholder')} classNames={mx('px-3 my-2')} />
54
+ <SearchList.Content classNames={['min-bs-[12rem] bs-[50dvh] max-bs-[20rem] overflow-auto']}>
55
+ {actions?.map((action) => {
56
+ const label = getLabel(action.label);
57
+ const Icon = action.icon ?? DotOutline;
58
+ return (
59
+ <SearchList.Item
60
+ value={label}
61
+ key={action.id}
62
+ onSelect={() => {
63
+ if (action.properties.disabled) {
64
+ return;
65
+ }
66
+
67
+ // TODO(burdon): Remove hack to close dialog (via hook?)
68
+ buttonRef.current?.click();
69
+ setTimeout(() => {
70
+ void action.invoke();
71
+ });
72
+
73
+ // TODO(burdon): Reconcile with NavTreeItemAction.
74
+ // suppressNextTooltip.current = true;
75
+ // setOptionsMenuOpen(false);
76
+ // onAction?.(action);
77
+ }}
78
+ classNames='flex items-center gap-2 pli-2'
79
+ disabled={action.properties.disabled}
80
+ {...(action.properties?.testId && { 'data-testid': action.properties.testId })}
81
+ >
82
+ <Icon className={mx(getSize(4), 'shrink-0', !action.icon && 'invisible')} />
83
+ <span className='grow truncate'>{label}</span>
84
+ {action.keyBinding && (
85
+ <span className={mx('shrink-0', descriptionText)}>{keySymbols(action.keyBinding).join('')}</span>
86
+ )}
87
+ </SearchList.Item>
88
+ );
89
+ })}
90
+ </SearchList.Content>
91
+ {/* <div role='none' className='flex items-center plb-2 pli-3'> */}
92
+ {/* <span className={descriptionText}>{label}</span> */}
93
+ {/* </div> */}
94
+ </SearchList.Root>
95
+ <Dialog.Close asChild>
96
+ <Button ref={buttonRef} variant='primary' classNames='mbs-2'>
97
+ {t('close label', { ns: 'os' })}
98
+ </Button>
99
+ </Dialog.Close>
100
+ </Dialog.Content>
101
+ );
102
+ };
@@ -0,0 +1,98 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { useState } from 'react';
6
+
7
+ import { Button, Dialog, List, ListItem, useTranslation } from '@dxos/react-ui';
8
+ import { ghostHover, ghostSelected, groupBorder, mx } from '@dxos/react-ui-theme';
9
+
10
+ import { type Plugin, usePlugins } from '../PluginHost';
11
+ import { Surface } from '../SurfacePlugin';
12
+
13
+ // TODO(burdon): Move into separate plugin.
14
+ export const SettingsDialogContent = () => {
15
+ const { t } = useTranslation('os');
16
+
17
+ // TODO(burdon): Store preview tab.
18
+ const [plugin, setPlugin] = useState<string>('dxos.org/plugin/registry');
19
+ const { plugins, enabled } = usePlugins();
20
+
21
+ const core = [
22
+ 'dxos.org/plugin/layout',
23
+ 'dxos.org/plugin/client',
24
+ 'dxos.org/plugin/space',
25
+ 'dxos.org/plugin/registry',
26
+ ];
27
+
28
+ const filteredPlugins = enabled
29
+ .map((id) => plugins.find((plugin) => plugin.meta.id === id))
30
+ .filter((plugin) => (plugin?.provides as any)?.settings)
31
+ .map((plugin) => plugin!.meta)
32
+ .sort(({ name: a }, { name: b }) => a?.localeCompare(b ?? '') ?? 0);
33
+
34
+ // TODO(burdon): Vertical layout if mobile (pattern).
35
+ return (
36
+ <Dialog.Content classNames={['h-[90%] md:max-is-[40rem] overflow-hidden']}>
37
+ <Dialog.Title>{t('settings dialog title', { ns: 'os' })}</Dialog.Title>
38
+
39
+ <div className='flex grow mlb-4 overflow-hidden'>
40
+ <div className={mx('flex flex-col w-[200px] space-y-4 pr-4 border-r overflow-y-auto', groupBorder)}>
41
+ <PluginList
42
+ title='Options'
43
+ plugins={core.map((id) => plugins.find((p) => p.meta.id === id)!.meta)}
44
+ selected={plugin}
45
+ onSelect={(plugin) => setPlugin(plugin)}
46
+ />
47
+
48
+ <PluginList
49
+ title='Plugins'
50
+ plugins={filteredPlugins}
51
+ selected={plugin}
52
+ onSelect={(plugin) => setPlugin(plugin)}
53
+ />
54
+ </div>
55
+
56
+ <div className={mx('flex flex-col w-full md:px-4 divide-y overflow-y-auto', groupBorder)}>
57
+ <Surface role='settings' data={{ plugin }} />
58
+ </div>
59
+ </div>
60
+
61
+ <Dialog.Close asChild>
62
+ <Button variant='primary' classNames='mbs-2'>
63
+ {t('done label', { ns: 'os' })}
64
+ </Button>
65
+ </Dialog.Close>
66
+ </Dialog.Content>
67
+ );
68
+ };
69
+
70
+ const PluginList = ({
71
+ title,
72
+ plugins,
73
+ selected,
74
+ onSelect,
75
+ }: {
76
+ title: string;
77
+ plugins: Plugin['meta'][];
78
+ selected?: string;
79
+ onSelect: (plugin: string) => void;
80
+ }) => {
81
+ return (
82
+ <div role='none'>
83
+ <h2 className='my-1 px-2 text-sm text-neutral-500'>{title}</h2>
84
+ <List selectable>
85
+ {plugins.map((plugin) => (
86
+ <ListItem.Root
87
+ key={plugin.id}
88
+ onClick={() => onSelect(plugin.id)}
89
+ selected={plugin.id === selected}
90
+ classNames={['px-2 rounded', plugin.id === selected && ghostSelected, ghostHover]}
91
+ >
92
+ <ListItem.Heading classNames={['flex w-full items-center cursor-pointer']}>{plugin.name}</ListItem.Heading>
93
+ </ListItem.Root>
94
+ ))}
95
+ </List>
96
+ </div>
97
+ );
98
+ };
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { type PropsWithChildren } from 'react';
6
+
7
+ import { Input } from '@dxos/react-ui';
8
+
9
+ type SettingValueProps = {
10
+ label: string;
11
+ description?: JSX.Element;
12
+ };
13
+
14
+ export const SettingsValue = ({ label, description, children }: PropsWithChildren<SettingValueProps>) => {
15
+ return (
16
+ <div role='none' className='flex w-full gap-4 py-1'>
17
+ <Input.Root>
18
+ <div role='none' className='flex flex-col w-full'>
19
+ {/* TODO(burdon): Consistent height for controls (e.g., Select, Textbox, and Checkbox are all different). */}
20
+ <Input.Label classNames='flex min-h-[40px] items-center'>{label}</Input.Label>
21
+ {description && (
22
+ <Input.DescriptionAndValidation classNames='mbs-0.5'>
23
+ <Input.Description>{description}</Input.Description>
24
+ </Input.DescriptionAndValidation>
25
+ )}
26
+ </div>
27
+
28
+ <div role='none'>
29
+ <div role='none' className='flex min-h-[40px] items-center'>
30
+ {children}
31
+ </div>
32
+ </div>
33
+ </Input.Root>
34
+ </div>
35
+ );
36
+ };
@@ -0,0 +1,59 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { type Label } from '@dxos/app-graph';
8
+ import { Keyboard, keySymbols } from '@dxos/keyboard';
9
+ import { Button, Dialog, useTranslation } from '@dxos/react-ui';
10
+ import { mx } from '@dxos/react-ui-theme';
11
+
12
+ export const ShortcutsDialogContent = () => {
13
+ const { t } = useTranslation('os');
14
+
15
+ const bindings = Keyboard.singleton.getBindings();
16
+
17
+ // TODO(burdon): Factor out.
18
+ // TODO(burdon): How to access all translations across plugins?
19
+ const getLabel = (label: Label) => (Array.isArray(label) ? t(...label) : label);
20
+
21
+ return (
22
+ <Dialog.Content classNames={['md:max-is-[30rem] overflow-hidden']}>
23
+ <Dialog.Title>{t('shortcuts dialog title', { ns: 'os' })}</Dialog.Title>
24
+
25
+ <table className='table-fixed border-collapse my-4'>
26
+ <tbody>
27
+ {bindings.map((binding, i) => (
28
+ <tr key={i}>
29
+ <td className='p-1 w-[120px]'>
30
+ <div className='flex gap-1'>
31
+ {keySymbols(binding.binding).map((c, i) => (
32
+ <span
33
+ key={i}
34
+ className={mx(
35
+ 'inline-flex w-[24px] h-[24px] justify-center items-center text-xs',
36
+ 'rounded border border-neutral-300 dark:border-neutral-600 bg-neutral-50 dark:bg-neutral-850',
37
+ )}
38
+ >
39
+ {c}
40
+ </span>
41
+ ))}
42
+ </div>
43
+ </td>
44
+ <td className='p-1'>
45
+ <span className='grow truncate'>{getLabel(binding.data as Label)}</span>
46
+ </td>
47
+ </tr>
48
+ ))}
49
+ </tbody>
50
+ </table>
51
+
52
+ <Dialog.Close asChild>
53
+ <Button variant='primary' classNames='mbs-2'>
54
+ {t('close label', { ns: 'os' })}
55
+ </Button>
56
+ </Dialog.Close>
57
+ </Dialog.Content>
58
+ );
59
+ };
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './CommandsDialog';
6
+ export * from './SettingsDialog';
7
+ export * from './SettingsValue';
8
+ export * from './ShortcutsDialog';
@@ -3,6 +3,7 @@
3
3
  //
4
4
 
5
5
  export * from './common';
6
+ export * from './components';
6
7
  export * from './helpers';
7
8
 
8
9
  export * from './IntentPlugin';
package/tsconfig.json CHANGED
@@ -26,12 +26,27 @@
26
26
  {
27
27
  "path": "../../common/invariant"
28
28
  },
29
+ {
30
+ "path": "../../common/keyboard"
31
+ },
29
32
  {
30
33
  "path": "../../common/local-storage"
31
34
  },
32
35
  {
33
36
  "path": "../../common/log"
34
37
  },
38
+ {
39
+ "path": "../../ui/react-ui"
40
+ },
41
+ {
42
+ "path": "../../ui/react-ui-searchlist"
43
+ },
44
+ {
45
+ "path": "../../ui/react-ui-theme"
46
+ },
47
+ {
48
+ "path": "../../ui/storybook-utils"
49
+ },
35
50
  {
36
51
  "path": "../app-graph"
37
52
  }