@teambit/scope 0.0.566 → 0.0.570

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.
@@ -0,0 +1,13 @@
1
+ import { BitError } from '@teambit/bit-error';
2
+ import { ComponentID } from '@teambit/component';
3
+
4
+ export class ComponentNotFound extends BitError {
5
+ constructor(
6
+ /**
7
+ * id of the missing component.
8
+ */
9
+ id: ComponentID
10
+ ) {
11
+ super(`component with id: ${id} was not found`);
12
+ }
13
+ }
@@ -0,0 +1 @@
1
+ export { ComponentNotFound } from './component-not-found';
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@teambit/scope",
3
- "version": "0.0.566",
3
+ "version": "0.0.570",
4
4
  "homepage": "https://bit.dev/teambit/scope/scope",
5
5
  "main": "dist/index.js",
6
6
  "componentId": {
7
7
  "scope": "teambit.scope",
8
8
  "name": "scope",
9
- "version": "0.0.566"
9
+ "version": "0.0.570"
10
10
  },
11
11
  "dependencies": {
12
12
  "semver": "7.3.4",
@@ -23,50 +23,50 @@
23
23
  "@teambit/base-ui.surfaces.split-pane.hover-splitter": "1.0.0",
24
24
  "@teambit/base-ui.surfaces.split-pane.split-pane": "1.0.0",
25
25
  "@teambit/base-ui.graph.tree.recursive-tree": "1.0.0",
26
- "@teambit/scope.models.scope-model": "0.0.80",
27
- "@teambit/scope.ui.hooks.scope-context": "0.0.80",
28
- "@teambit/component": "0.0.566",
29
- "@teambit/logger": "0.0.478",
30
- "@teambit/aspect-loader": "0.0.566",
31
- "@teambit/builder": "0.0.566",
32
- "@teambit/cli": "0.0.393",
33
- "@teambit/compiler": "0.0.566",
34
- "@teambit/config": "0.0.405",
35
- "@teambit/envs": "0.0.566",
36
- "@teambit/express": "0.0.482",
37
- "@teambit/graphql": "0.0.566",
38
- "@teambit/harmony.modules.requireable-component": "0.0.468",
39
- "@teambit/isolator": "0.0.566",
40
- "@teambit/legacy-bit-id": "0.0.382",
41
- "@teambit/ui": "0.0.566",
42
- "@teambit/workspace.modules.match-pattern": "0.0.472",
43
- "@teambit/command-bar": "0.0.566",
44
- "@teambit/component-tree": "0.0.379",
26
+ "@teambit/scope.models.scope-model": "0.0.82",
27
+ "@teambit/scope.ui.hooks.scope-context": "0.0.82",
28
+ "@teambit/component": "0.0.570",
29
+ "@teambit/logger": "0.0.482",
30
+ "@teambit/aspect-loader": "0.0.570",
31
+ "@teambit/builder": "0.0.570",
32
+ "@teambit/cli": "0.0.395",
33
+ "@teambit/compiler": "0.0.570",
34
+ "@teambit/config": "0.0.407",
35
+ "@teambit/envs": "0.0.570",
36
+ "@teambit/express": "0.0.486",
37
+ "@teambit/graphql": "0.0.570",
38
+ "@teambit/harmony.modules.requireable-component": "0.0.470",
39
+ "@teambit/isolator": "0.0.570",
40
+ "@teambit/legacy-bit-id": "0.0.384",
41
+ "@teambit/ui": "0.0.570",
42
+ "@teambit/workspace.modules.match-pattern": "0.0.474",
43
+ "@teambit/command-bar": "0.0.570",
44
+ "@teambit/component-tree": "0.0.381",
45
45
  "@teambit/design.ui.surfaces.menu.link-item": "0.0.374",
46
- "@teambit/react-router": "0.0.566",
47
- "@teambit/sidebar": "0.0.566",
48
- "@teambit/ui-foundation.ui.main-dropdown": "0.0.470",
49
- "@teambit/ui-foundation.ui.menu": "0.0.470",
50
- "@teambit/ui-foundation.ui.react-router.slot-router": "0.0.472",
51
- "@teambit/bit-error": "0.0.379",
52
- "@teambit/ui-foundation.ui.constants.z-indexes": "0.0.471",
53
- "@teambit/scope.ui.hooks.use-scope": "0.0.81",
54
- "@teambit/ui-foundation.ui.buttons.collapser": "0.0.176",
55
- "@teambit/ui-foundation.ui.corner": "0.0.477",
56
- "@teambit/ui-foundation.ui.hooks.use-is-mobile": "0.0.163",
57
- "@teambit/ui-foundation.ui.top-bar": "0.0.473",
46
+ "@teambit/react-router": "0.0.570",
47
+ "@teambit/sidebar": "0.0.570",
48
+ "@teambit/ui-foundation.ui.main-dropdown": "0.0.472",
49
+ "@teambit/ui-foundation.ui.menu": "0.0.472",
50
+ "@teambit/ui-foundation.ui.react-router.slot-router": "0.0.474",
51
+ "@teambit/bit-error": "0.0.381",
52
+ "@teambit/ui-foundation.ui.constants.z-indexes": "0.0.473",
53
+ "@teambit/scope.ui.hooks.use-scope": "0.0.83",
54
+ "@teambit/ui-foundation.ui.buttons.collapser": "0.0.178",
55
+ "@teambit/ui-foundation.ui.corner": "0.0.479",
56
+ "@teambit/ui-foundation.ui.hooks.use-is-mobile": "0.0.165",
57
+ "@teambit/ui-foundation.ui.top-bar": "0.0.475",
58
58
  "@teambit/design.ui.styles.ellipsis": "0.0.346",
59
59
  "@teambit/design.ui.styles.muted-italic": "0.0.35",
60
- "@teambit/ui-foundation.ui.full-loader": "0.0.470",
61
- "@teambit/ui-foundation.ui.side-bar": "0.0.476",
62
- "@teambit/ui-foundation.ui.tree.drawer": "0.0.470",
63
- "@teambit/ui-foundation.ui.use-box.dropdown": "0.0.91",
64
- "@teambit/ui-foundation.ui.use-box.scope-menu": "0.0.91",
65
- "@teambit/explorer.ui.gallery.component-card": "0.0.474",
66
- "@teambit/explorer.ui.gallery.component-grid": "0.0.470",
67
- "@teambit/preview.ui.preview-placeholder": "0.0.470",
68
- "@teambit/scope.ui.empty-scope": "0.0.473",
69
- "@teambit/scope.ui.scope-details": "0.0.479"
60
+ "@teambit/ui-foundation.ui.full-loader": "0.0.472",
61
+ "@teambit/ui-foundation.ui.side-bar": "0.0.478",
62
+ "@teambit/ui-foundation.ui.tree.drawer": "0.0.472",
63
+ "@teambit/ui-foundation.ui.use-box.dropdown": "0.0.93",
64
+ "@teambit/ui-foundation.ui.use-box.scope-menu": "0.0.93",
65
+ "@teambit/explorer.ui.gallery.component-card": "0.0.476",
66
+ "@teambit/explorer.ui.gallery.component-grid": "0.0.472",
67
+ "@teambit/preview.ui.preview-placeholder": "0.0.472",
68
+ "@teambit/scope.ui.empty-scope": "0.0.475",
69
+ "@teambit/scope.ui.scope-details": "0.0.481"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/semver": "7.3.4",
@@ -82,7 +82,7 @@
82
82
  "@types/node": "12.20.4"
83
83
  },
84
84
  "peerDependencies": {
85
- "@teambit/legacy": "1.0.179",
85
+ "@teambit/legacy": "1.0.181",
86
86
  "react-dom": "^16.8.0 || ^17.0.0",
87
87
  "react": "^16.8.0 || ^17.0.0"
88
88
  },
@@ -110,27 +110,12 @@
110
110
  "react": "-"
111
111
  },
112
112
  "peerDependencies": {
113
- "@teambit/legacy": "1.0.179",
113
+ "@teambit/legacy": "1.0.181",
114
114
  "react-dom": "^16.8.0 || ^17.0.0",
115
115
  "react": "^16.8.0 || ^17.0.0"
116
116
  }
117
117
  }
118
118
  },
119
- "files": [
120
- "dist",
121
- "!dist/tsconfig.tsbuildinfo",
122
- "**/*.md",
123
- "**/*.mdx",
124
- "**/*.js",
125
- "**/*.json",
126
- "**/*.sass",
127
- "**/*.scss",
128
- "**/*.less",
129
- "**/*.css",
130
- "**/*.css",
131
- "**/*.jpeg",
132
- "**/*.gif"
133
- ],
134
119
  "private": false,
135
120
  "engines": {
136
121
  "node": ">=12.22.0"
@@ -0,0 +1,22 @@
1
+ import { Route, Verb, Request, Response } from '@teambit/express';
2
+ import { action } from '@teambit/legacy/dist/api/scope/lib/action';
3
+ import { getAuthDataFromHeader } from '@teambit/legacy/dist/scope/network/http/http';
4
+ import { ScopeMain } from '../scope.main.runtime';
5
+
6
+ export class ActionRoute implements Route {
7
+ constructor(private scope: ScopeMain) {}
8
+
9
+ method = 'post';
10
+ route = '/scope/action';
11
+ verb = Verb.WRITE;
12
+
13
+ middlewares = [
14
+ async (req: Request, res: Response) => {
15
+ req.setTimeout(this.scope.config.httpTimeOut);
16
+ const authData = getAuthDataFromHeader(req.headers.authorization);
17
+ const result = await action(this.scope.path, req.body.name, req.body.options, authData);
18
+ // in case the result is empty, send `{}` to make it a valid json.
19
+ res.json(result || {});
20
+ },
21
+ ];
22
+ }
@@ -0,0 +1,26 @@
1
+ import { Route, Verb, Request, Response } from '@teambit/express';
2
+ import { ScopeMain } from '../scope.main.runtime';
3
+
4
+ export class DeleteRoute implements Route {
5
+ constructor(private scope: ScopeMain) {}
6
+
7
+ method = 'post';
8
+ route = '/scope/delete';
9
+ verb = Verb.WRITE;
10
+
11
+ middlewares = [
12
+ async (req: Request, res: Response) => {
13
+ const { headers } = req;
14
+ req.setTimeout(this.scope.config.httpTimeOut);
15
+ const result = await this.scope.delete(
16
+ {
17
+ ids: req.body.ids,
18
+ force: req.body.force,
19
+ lanes: req.body.lanes,
20
+ },
21
+ headers
22
+ );
23
+ res.json(result);
24
+ },
25
+ ];
26
+ }
@@ -0,0 +1,45 @@
1
+ import { Route, Verb, Request, Response } from '@teambit/express';
2
+ import { fetch } from '@teambit/legacy/dist/api/scope';
3
+ import { ObjectList } from '@teambit/legacy/dist/scope/objects/object-list';
4
+ import { Logger } from '@teambit/logger';
5
+ import { promisify } from 'util';
6
+ import { pipeline } from 'stream';
7
+ import { ScopeMain } from '../scope.main.runtime';
8
+
9
+ export class FetchRoute implements Route {
10
+ constructor(private scope: ScopeMain, private logger: Logger) {}
11
+
12
+ route = '/scope/fetch';
13
+ method = 'post';
14
+ verb = Verb.READ;
15
+ middlewares = [
16
+ async (req: Request, res: Response) => {
17
+ req.setTimeout(this.scope.config.httpTimeOut);
18
+ const preFetchHookP = this.scope.preFetchObjects
19
+ .values()
20
+ .map((fn) => fn({ ids: req.body.ids, fetchOptions: req.body.fetchOptions }, { headers: req.headers }));
21
+
22
+ Promise.all(preFetchHookP).catch((err) => {
23
+ this.logger.error('fatal: onPreFetchObjects encountered an error (this error does not stop the process)', err);
24
+ });
25
+
26
+ const readable = await fetch(this.scope.path, req.body.ids, req.body.fetchOptions);
27
+ const pack = ObjectList.fromObjectStreamToTar(readable, this.scope.name);
28
+ const pipelinePromise = promisify(pipeline);
29
+ try {
30
+ await pipelinePromise(pack, res);
31
+ this.logger.info('fetch.router, the response has been sent successfully to the client', req.headers);
32
+ } catch (err: any) {
33
+ if (req.aborted) {
34
+ this.logger.warn('FetchRoute, the client aborted the request', err);
35
+ } else {
36
+ this.logger.error(
37
+ `FetchRoute encountered an error during the pipeline streaming, this should never happen.
38
+ make sure the error is caught in fromObjectStreamToTar and it streamed using the name "ERROR"`,
39
+ err
40
+ );
41
+ }
42
+ }
43
+ },
44
+ ];
45
+ }
@@ -0,0 +1,4 @@
1
+ export { FetchRoute } from './fetch.route';
2
+ export { PutRoute } from './put.route';
3
+ export { ActionRoute } from './action.route';
4
+ export { DeleteRoute } from './delete.route';
@@ -0,0 +1,37 @@
1
+ import { Route, Verb, Request, Response } from '@teambit/express';
2
+ import { ObjectList } from '@teambit/legacy/dist/scope/objects/object-list';
3
+ import { put } from '@teambit/legacy/dist/api/scope';
4
+ import { OnPostPutSlot, ScopeMain } from '../scope.main.runtime';
5
+
6
+ export class PutRoute implements Route {
7
+ constructor(private scope: ScopeMain, private postPutSlot: OnPostPutSlot) {}
8
+
9
+ method = 'post';
10
+ route = '/scope/put';
11
+ verb = Verb.WRITE;
12
+
13
+ middlewares = [
14
+ async (req: Request, res: Response) => {
15
+ req.setTimeout(this.scope.config.httpTimeOut);
16
+ const pushOptionsStr = req.headers['push-options'];
17
+ if (!pushOptionsStr) throw new Error('http is missing the push-options header');
18
+ const pushOptions = JSON.parse(pushOptionsStr as string);
19
+ const objectList = await ObjectList.fromTar(req);
20
+ const ids = await put(
21
+ {
22
+ path: this.scope.path,
23
+ objectList,
24
+ },
25
+ pushOptions
26
+ );
27
+
28
+ await Promise.all(
29
+ ids.map((id) => {
30
+ return this.scope.resolveComponentId(id);
31
+ })
32
+ );
33
+
34
+ res.json(ids);
35
+ },
36
+ ];
37
+ }
@@ -0,0 +1,327 @@
1
+ import type { ComponentUI, ComponentModel } from '@teambit/component';
2
+ import { ComponentAspect } from '@teambit/component';
3
+ import { Slot, SlotRegistry } from '@teambit/harmony';
4
+ import ReactRouterAspect, { ReactRouterUI } from '@teambit/react-router';
5
+ import { RouteSlot } from '@teambit/ui-foundation.ui.react-router.slot-router';
6
+ import { SidebarAspect, SidebarUI, SidebarItem, SidebarItemSlot } from '@teambit/sidebar';
7
+ import { ComponentTreeNode } from '@teambit/component-tree';
8
+ import { UIAspect, UIRootUI as UIRoot, UIRuntime, UiUI } from '@teambit/ui';
9
+ import React, { ComponentType, ReactNode } from 'react';
10
+ import { MenuItemSlot, MenuItem } from '@teambit/ui-foundation.ui.main-dropdown';
11
+ import { RouteProps } from 'react-router-dom';
12
+ import { MenuWidget, MenuWidgetSlot } from '@teambit/ui-foundation.ui.menu';
13
+ import { MenuLinkItem } from '@teambit/design.ui.surfaces.menu.link-item';
14
+ import CommandBarAspect, { CommandBarUI, ComponentSearcher, CommandHandler } from '@teambit/command-bar';
15
+ import { ScopeModel } from '@teambit/scope.models.scope-model';
16
+ import { ScopeMenu, ScopeUseBox } from './ui/menu';
17
+ import { ScopeAspect } from './scope.aspect';
18
+ import { Scope } from './ui/scope';
19
+ import { ComponentsDrawer } from './ui/components-drawer';
20
+
21
+ export type ScopeBadge = ComponentType;
22
+
23
+ export type ScopeBadgeSlot = SlotRegistry<ScopeBadge[]>;
24
+
25
+ export type ScopeContextType = ComponentType<{ scope: ScopeModel; children: ReactNode }>;
26
+
27
+ export type SidebarSlot = SlotRegistry<ComponentTreeNode>;
28
+
29
+ export type ScopeOverview = ComponentType;
30
+
31
+ export type ScopeOverviewSlot = SlotRegistry<ScopeOverview>;
32
+
33
+ export type Corner = ComponentType;
34
+
35
+ export type CornerSlot = SlotRegistry<Corner>;
36
+
37
+ export type OverviewLine = ComponentType;
38
+
39
+ export type OverviewLineSlot = SlotRegistry<OverviewLine[]>;
40
+
41
+ export class ScopeUI {
42
+ constructor(
43
+ /**
44
+ * route slot.
45
+ */
46
+ private routeSlot: RouteSlot,
47
+
48
+ /**
49
+ * component ui extension.
50
+ */
51
+ private componentUi: ComponentUI,
52
+ /**
53
+ * menu slot
54
+ */
55
+ private menuSlot: RouteSlot,
56
+
57
+ private sidebar: SidebarUI,
58
+
59
+ private sidebarSlot: SidebarSlot,
60
+
61
+ private commandBarUI: CommandBarUI,
62
+
63
+ private componentSearcher: ComponentSearcher,
64
+
65
+ private scopeBadgeSlot: ScopeBadgeSlot,
66
+
67
+ private menuWidgetSlot: MenuWidgetSlot,
68
+
69
+ /**
70
+ * sidebar link slot
71
+ */
72
+ private sidebarItemSlot: SidebarItemSlot,
73
+
74
+ /**
75
+ * main dropdown item slot
76
+ */
77
+ private menuItemSlot: MenuItemSlot,
78
+
79
+ /**
80
+ * corner slot
81
+ */
82
+ private cornerSlot: CornerSlot,
83
+
84
+ /**
85
+ * overview line slot to add new lines beneath the overview section
86
+ */
87
+ private overviewSlot: OverviewLineSlot
88
+ ) {}
89
+
90
+ private setSidebarToggle: (updated: CommandHandler) => void = () => {};
91
+
92
+ /**
93
+ * register a new badge into the scope overview.
94
+ */
95
+ registerBadge(...badges: ScopeBadge[]) {
96
+ this.scopeBadgeSlot.register(badges);
97
+ return this;
98
+ }
99
+
100
+ /**
101
+ * register a new line beneath the scope overview section.
102
+ */
103
+ registerOverviewLine(...lines: OverviewLine[]) {
104
+ this.overviewSlot.register(lines);
105
+ return this;
106
+ }
107
+
108
+ /**
109
+ * register a route to the scope.
110
+ */
111
+ registerRoute(route: RouteProps) {
112
+ this.routeSlot.register(route);
113
+ return this;
114
+ }
115
+
116
+ private registerExplicitRoutes() {
117
+ this.routeSlot.register({
118
+ path: this.componentUi.routePath,
119
+ children: this.componentUi.getComponentUI(ScopeAspect.id),
120
+ });
121
+
122
+ this.menuSlot.register([
123
+ {
124
+ path: this.componentUi.routePath,
125
+ children: this.componentUi.getMenu(ScopeAspect.id),
126
+ },
127
+ {
128
+ exact: true,
129
+ path: '/',
130
+ children: <ScopeMenu widgetSlot={this.menuWidgetSlot} menuItemSlot={this.menuItemSlot} />,
131
+ },
132
+ ]);
133
+ }
134
+
135
+ registerMenuWidget(...menuItems: MenuWidget[]) {
136
+ this.menuWidgetSlot.register(menuItems);
137
+ }
138
+
139
+ registerCorner(corner: Corner) {
140
+ this.cornerSlot.register(corner);
141
+ }
142
+
143
+ /**
144
+ * register a scope overview.
145
+ */
146
+ replaceOverview() {}
147
+
148
+ /**
149
+ * register description.
150
+ */
151
+ replaceDescription() {}
152
+
153
+ /**
154
+ * register metadata section.
155
+ */
156
+ replaceMetadataSection() {}
157
+
158
+ /**
159
+ * register a metadata item.
160
+ */
161
+ registerMetadataItem() {}
162
+
163
+ replaceComponentGrid() {}
164
+
165
+ /**
166
+ * register metadata.
167
+ */
168
+ registerMetadata() {}
169
+
170
+ private _context: () => ScopeContextType;
171
+
172
+ /**
173
+ * add a new context to the scope.
174
+ */
175
+ addContext(context: ScopeContextType) {
176
+ this._context = () => context;
177
+ }
178
+
179
+ getContext() {
180
+ if (!this._context) return undefined;
181
+ return this._context();
182
+ }
183
+
184
+ registerMenuItem = (menuItems: MenuItem[]) => {
185
+ this.menuItemSlot.register(menuItems);
186
+ };
187
+
188
+ /**
189
+ * register a sidebar link to the section above the drawers
190
+ */
191
+ registerSidebarLink = (...links: SidebarItem[]) => {
192
+ this.sidebarItemSlot.register(links);
193
+ };
194
+
195
+ uiRoot(): UIRoot {
196
+ this.sidebar.registerDrawer(new ComponentsDrawer(this.sidebarSlot));
197
+ this.commandBarUI.addSearcher(this.componentSearcher);
198
+
199
+ const [setKeyBindHandler] = this.commandBarUI.addCommand({
200
+ id: 'sidebar.toggle', // TODO - extract to a component!
201
+ handler: () => {},
202
+ displayName: 'Toggle component list',
203
+ keybinding: 'alt+s',
204
+ });
205
+ this.setSidebarToggle = setKeyBindHandler;
206
+
207
+ return {
208
+ routes: [
209
+ {
210
+ path: '/',
211
+ children: (
212
+ <Scope
213
+ routeSlot={this.routeSlot}
214
+ menuSlot={this.menuSlot}
215
+ sidebar={<this.sidebar.render itemSlot={this.sidebarItemSlot} />}
216
+ scopeUi={this}
217
+ badgeSlot={this.scopeBadgeSlot}
218
+ overviewLineSlot={this.overviewSlot}
219
+ context={this.getContext()}
220
+ onSidebarTogglerChange={this.setSidebarToggle}
221
+ cornerSlot={this.cornerSlot}
222
+ />
223
+ ),
224
+ },
225
+ ],
226
+ };
227
+ }
228
+
229
+ /** registers available components */
230
+ setComponents = (components: ComponentModel[]) => {
231
+ this.componentSearcher.update(components);
232
+ };
233
+
234
+ private menuItems: MenuItem[] = [
235
+ {
236
+ category: 'general',
237
+ title: 'Open command bar',
238
+ keyChar: 'mod+k',
239
+ handler: () => this.commandBarUI?.run('command-bar.open'),
240
+ },
241
+ {
242
+ category: 'general',
243
+ title: 'Toggle component list',
244
+ keyChar: 'alt+s',
245
+ handler: () => this.commandBarUI?.run('sidebar.toggle'),
246
+ },
247
+ ];
248
+
249
+ static dependencies = [UIAspect, ComponentAspect, SidebarAspect, CommandBarAspect, ReactRouterAspect];
250
+ static runtime = UIRuntime;
251
+ static slots = [
252
+ Slot.withType<RouteProps>(),
253
+ Slot.withType<RouteProps>(),
254
+ Slot.withType<ComponentTreeNode>(),
255
+ Slot.withType<ScopeBadge>(),
256
+ Slot.withType<ScopeOverview>(),
257
+ Slot.withType<MenuWidget[]>(),
258
+ Slot.withType<MenuItemSlot>(),
259
+ Slot.withType<CornerSlot>(),
260
+ Slot.withType<OverviewLineSlot>(),
261
+ Slot.withType<SidebarItemSlot>(),
262
+ ];
263
+
264
+ static async provider(
265
+ [ui, componentUi, sidebar, commandBarUI, reactRouterUI]: [
266
+ UiUI,
267
+ ComponentUI,
268
+ SidebarUI,
269
+ CommandBarUI,
270
+ ReactRouterUI
271
+ ],
272
+ config,
273
+ [
274
+ routeSlot,
275
+ menuSlot,
276
+ sidebarSlot,
277
+ scopeBadgeSlot,
278
+ menuWidgetSlot,
279
+ menuItemSlot,
280
+ sidebarItemSlot,
281
+ cornerSlot,
282
+ overviewSlot,
283
+ ]: [
284
+ RouteSlot,
285
+ RouteSlot,
286
+ SidebarSlot,
287
+ ScopeBadgeSlot,
288
+ MenuWidgetSlot,
289
+ MenuItemSlot,
290
+ SidebarItemSlot,
291
+ CornerSlot,
292
+ OverviewLineSlot
293
+ ]
294
+ ) {
295
+ const componentSearcher = new ComponentSearcher(reactRouterUI.navigateTo);
296
+ const scopeUi = new ScopeUI(
297
+ routeSlot,
298
+ componentUi,
299
+ menuSlot,
300
+ sidebar,
301
+ sidebarSlot,
302
+ commandBarUI,
303
+ componentSearcher,
304
+ scopeBadgeSlot,
305
+ menuWidgetSlot,
306
+ sidebarItemSlot,
307
+ menuItemSlot,
308
+ cornerSlot,
309
+ overviewSlot
310
+ );
311
+ scopeUi.registerExplicitRoutes();
312
+ scopeUi.registerMenuItem(scopeUi.menuItems);
313
+ scopeUi.registerMenuWidget(() => <ScopeUseBox />);
314
+ ui.registerRoot(scopeUi.uiRoot.bind(scopeUi));
315
+ scopeUi.registerSidebarLink(() => (
316
+ <MenuLinkItem exact href="/" icon="comps">
317
+ Gallery
318
+ </MenuLinkItem>
319
+ ));
320
+
321
+ return scopeUi;
322
+ }
323
+ }
324
+
325
+ export default ScopeUI;
326
+
327
+ ScopeAspect.addRuntime(ScopeUI);
@@ -0,0 +1,29 @@
1
+ declare module '*.png' {
2
+ const value: any;
3
+ export = value;
4
+ }
5
+ declare module '*.svg' {
6
+ import type { FunctionComponent, SVGProps } from 'react';
7
+
8
+ export const ReactComponent: FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;
9
+ const src: string;
10
+ export default src;
11
+ }
12
+
13
+ // @TODO Gilad
14
+ declare module '*.jpg' {
15
+ const value: any;
16
+ export = value;
17
+ }
18
+ declare module '*.jpeg' {
19
+ const value: any;
20
+ export = value;
21
+ }
22
+ declare module '*.gif' {
23
+ const value: any;
24
+ export = value;
25
+ }
26
+ declare module '*.bmp' {
27
+ const value: any;
28
+ export = value;
29
+ }
@@ -0,0 +1,42 @@
1
+ declare module '*.module.css' {
2
+ const classes: { readonly [key: string]: string };
3
+ export default classes;
4
+ }
5
+ declare module '*.module.scss' {
6
+ const classes: { readonly [key: string]: string };
7
+ export default classes;
8
+ }
9
+ declare module '*.module.sass' {
10
+ const classes: { readonly [key: string]: string };
11
+ export default classes;
12
+ }
13
+
14
+ declare module '*.module.less' {
15
+ const classes: { readonly [key: string]: string };
16
+ export default classes;
17
+ }
18
+
19
+ declare module '*.less' {
20
+ const classes: { readonly [key: string]: string };
21
+ export default classes;
22
+ }
23
+
24
+ declare module '*.css' {
25
+ const classes: { readonly [key: string]: string };
26
+ export default classes;
27
+ }
28
+
29
+ declare module '*.sass' {
30
+ const classes: { readonly [key: string]: string };
31
+ export default classes;
32
+ }
33
+
34
+ declare module '*.scss' {
35
+ const classes: { readonly [key: string]: string };
36
+ export default classes;
37
+ }
38
+
39
+ declare module '*.mdx' {
40
+ const component: any;
41
+ export default component;
42
+ }
@@ -0,0 +1,56 @@
1
+ import React, { useCallback } from 'react';
2
+ import classNames from 'classnames';
3
+ import {
4
+ ComponentTree,
5
+ ComponentView,
6
+ NamespaceTreeNode,
7
+ PayloadType,
8
+ ScopePayload,
9
+ } from '@teambit/ui-foundation.ui.side-bar';
10
+ import { TreeNodeProps } from '@teambit/base-ui.graph.tree.recursive-tree';
11
+
12
+ import { FullLoader } from '@teambit/ui-foundation.ui.full-loader';
13
+ import { ComponentTreeSlot } from '@teambit/component-tree';
14
+ import type { DrawerType } from '@teambit/ui-foundation.ui.tree.drawer';
15
+ import { mutedItalic } from '@teambit/design.ui.styles.muted-italic';
16
+ import { ellipsis } from '@teambit/design.ui.styles.ellipsis';
17
+ import { useScopeQuery } from '@teambit/scope.ui.hooks.use-scope';
18
+ import styles from './components-drawer.module.scss';
19
+
20
+ export class ComponentsDrawer implements DrawerType {
21
+ constructor(private treeNodeSlot: ComponentTreeSlot) {}
22
+
23
+ name = 'COMPONENTS';
24
+
25
+ render = () => {
26
+ const { scope } = useScopeQuery();
27
+ const { treeNodeSlot } = this;
28
+
29
+ const TreeNodeRenderer = useCallback(
30
+ function TreeNode(props: TreeNodeProps<PayloadType>) {
31
+ const children = props.node.children;
32
+
33
+ if (!children) return <ComponentView {...props} treeNodeSlot={treeNodeSlot} />;
34
+
35
+ // skip over scope node and render only children
36
+ if (props.node.payload instanceof ScopePayload) {
37
+ return (
38
+ <>
39
+ {children.map((childNode) => (
40
+ <TreeNodeRenderer key={childNode.id} {...props} node={childNode}></TreeNodeRenderer>
41
+ ))}
42
+ </>
43
+ );
44
+ }
45
+
46
+ return <NamespaceTreeNode {...props} />;
47
+ },
48
+ [treeNodeSlot]
49
+ );
50
+
51
+ if (!scope) return <FullLoader />;
52
+ if (scope.components.length === 0)
53
+ return <span className={classNames(mutedItalic, ellipsis, styles.emptyScope)}>Scope is empty</span>;
54
+ return <ComponentTree components={scope.components} TreeNode={TreeNodeRenderer} />;
55
+ };
56
+ }
@@ -0,0 +1 @@
1
+ export { ComponentsDrawer } from './components.drawer';
@@ -0,0 +1 @@
1
+ export { ScopeMenu, ScopeUseBox } from './menu';
@@ -0,0 +1,25 @@
1
+ import { Menu, MenuProps } from '@teambit/ui-foundation.ui.menu';
2
+ import { ScopeContext } from '@teambit/scope.ui.hooks.scope-context';
3
+ import classNames from 'classnames';
4
+ import React, { useContext } from 'react';
5
+ import { UseBoxDropdown } from '@teambit/ui-foundation.ui.use-box.dropdown';
6
+ import { Menu as ScopeUseBoxMenu } from '@teambit/ui-foundation.ui.use-box.scope-menu';
7
+ import styles from './menu.module.scss';
8
+
9
+ /**
10
+ * scope menu.
11
+ */
12
+ export function ScopeMenu({ className, ...rest }: MenuProps) {
13
+ return <Menu {...rest} className={classNames(styles.scopMenu, className)} />;
14
+ }
15
+
16
+ export function ScopeUseBox() {
17
+ const scope = useContext(ScopeContext);
18
+ return (
19
+ <UseBoxDropdown
20
+ position="bottom-end"
21
+ className={styles.useBox}
22
+ Menu={() => <ScopeUseBoxMenu scopeName={scope.name} />}
23
+ />
24
+ );
25
+ }
@@ -0,0 +1 @@
1
+ export * from './scope-overview';
@@ -0,0 +1,61 @@
1
+ import React, { useContext } from 'react';
2
+ import { ComponentCard } from '@teambit/explorer.ui.gallery.component-card';
3
+ import { ComponentGrid } from '@teambit/explorer.ui.gallery.component-grid';
4
+ import { ScopeDetails } from '@teambit/scope.ui.scope-details';
5
+ import { PreviewPlaceholder } from '@teambit/preview.ui.preview-placeholder';
6
+ import { EmptyScope } from '@teambit/scope.ui.empty-scope';
7
+ import { ComponentModel } from '@teambit/component';
8
+ import { ScopeContext } from '@teambit/scope.ui.hooks.scope-context';
9
+ import styles from './scope-overview.module.scss';
10
+ import type { ScopeBadgeSlot, OverviewLineSlot } from '../../scope.ui.runtime';
11
+
12
+ export type ScopeOverviewProps = {
13
+ badgeSlot: ScopeBadgeSlot;
14
+ overviewSlot: OverviewLineSlot;
15
+ };
16
+
17
+ export function ScopeOverview({ badgeSlot, overviewSlot }: ScopeOverviewProps) {
18
+ const scope = useContext(ScopeContext);
19
+ const { components } = scope;
20
+ if (!components || components.length === 0) return <EmptyScope name={scope.name} />;
21
+
22
+ return (
23
+ <div className={styles.container}>
24
+ <ScopeDetails
25
+ scopeName={scope.name}
26
+ icon={scope.icon}
27
+ backgroundIconColor={scope.backgroundIconColor}
28
+ badgeSlot={badgeSlot}
29
+ overviewSlot={overviewSlot}
30
+ description={scope.description}
31
+ componentCount={scope.components.length}
32
+ />
33
+ <ComponentGrid>
34
+ {components.map((component, index) => {
35
+ return (
36
+ <div key={index}>
37
+ <ScopeComponentCard component={component} />
38
+ </div>
39
+ );
40
+ })}
41
+ </ComponentGrid>
42
+ </div>
43
+ );
44
+ }
45
+
46
+ type ScopeComponentCardProps = {
47
+ component: ComponentModel;
48
+ };
49
+
50
+ export function ScopeComponentCard({ component }: ScopeComponentCardProps) {
51
+ const shouldShowPreview = component.compositions.length > 0;
52
+ return (
53
+ <ComponentCard
54
+ id={component.id.fullName}
55
+ envIcon={component.environment?.icon}
56
+ description={component.description}
57
+ version={component.version}
58
+ preview={<PreviewPlaceholder component={component} shouldShowPreview={shouldShowPreview} />}
59
+ />
60
+ );
61
+ }
package/ui/scope.tsx ADDED
@@ -0,0 +1,92 @@
1
+ import 'reset-css';
2
+ import { SplitPane, Pane, Layout } from '@teambit/base-ui.surfaces.split-pane.split-pane';
3
+ import { RouteSlot, SlotRouter } from '@teambit/ui-foundation.ui.react-router.slot-router';
4
+ import { Corner } from '@teambit/ui-foundation.ui.corner';
5
+ import { Collapser } from '@teambit/ui-foundation.ui.buttons.collapser';
6
+ import { HoverSplitter } from '@teambit/base-ui.surfaces.split-pane.hover-splitter';
7
+ import { TopBar } from '@teambit/ui-foundation.ui.top-bar';
8
+ import { FullLoader } from '@teambit/legacy/dist/to-eject/full-loader';
9
+ import React, { useReducer } from 'react';
10
+ import { Route } from 'react-router-dom';
11
+ import { useIsMobile } from '@teambit/ui-foundation.ui.hooks.use-is-mobile';
12
+ import { ScopeProvider } from '@teambit/scope.ui.hooks.scope-context';
13
+ import { useScopeQuery } from '@teambit/scope.ui.hooks.use-scope';
14
+ import { ScopeOverview } from './scope-overview';
15
+ import styles from './scope.module.scss';
16
+ import ScopeUI, { ScopeBadgeSlot, ScopeContextType, CornerSlot, OverviewLineSlot } from '../scope.ui.runtime';
17
+
18
+ export type ScopeProps = {
19
+ routeSlot: RouteSlot;
20
+ menuSlot: RouteSlot;
21
+ sidebar: JSX.Element;
22
+ scopeUi: ScopeUI;
23
+ badgeSlot: ScopeBadgeSlot;
24
+ overviewLineSlot: OverviewLineSlot;
25
+ cornerSlot: CornerSlot;
26
+ context?: ScopeContextType;
27
+ onSidebarTogglerChange: (callback: () => void) => void;
28
+ };
29
+
30
+ /**
31
+ * root component of the scope
32
+ */
33
+ export function Scope({
34
+ routeSlot,
35
+ menuSlot,
36
+ sidebar,
37
+ scopeUi,
38
+ badgeSlot,
39
+ overviewLineSlot,
40
+ cornerSlot,
41
+ context,
42
+ onSidebarTogglerChange,
43
+ }: ScopeProps) {
44
+ const { scope } = useScopeQuery();
45
+ const isMobile = useIsMobile();
46
+ const [isSidebarOpen, handleSidebarToggle] = useReducer((x) => !x, !isMobile);
47
+ const sidebarOpenness = isSidebarOpen ? Layout.row : Layout.right;
48
+ if (!scope) {
49
+ return <FullLoader />;
50
+ }
51
+ const CornerOverride = cornerSlot?.values()[0];
52
+ scopeUi.setComponents(scope.components);
53
+ const defaultContext = ({ children }) => <div>{children}</div>;
54
+ const Context = context || defaultContext;
55
+
56
+ onSidebarTogglerChange(handleSidebarToggle);
57
+
58
+ return (
59
+ <ScopeProvider scope={scope}>
60
+ <Context scope={scope}>
61
+ <div className={styles.scope}>
62
+ <TopBar
63
+ className={styles.topbar}
64
+ Corner={() => {
65
+ if (CornerOverride) return <CornerOverride />;
66
+ return <Corner name={scope.name} className={styles.whiteCorner} />;
67
+ }}
68
+ menu={menuSlot}
69
+ />
70
+
71
+ <SplitPane className={styles.main} size={264} layout={sidebarOpenness}>
72
+ <Pane className={styles.sidebar}>{sidebar}</Pane>
73
+ <HoverSplitter className={styles.splitter}>
74
+ <Collapser
75
+ isOpen={isSidebarOpen}
76
+ onMouseDown={(e) => e.stopPropagation()} // avoid split-pane drag
77
+ onClick={handleSidebarToggle}
78
+ tooltipContent={`${isSidebarOpen ? 'Hide' : 'Show'} side panel`}
79
+ />
80
+ </HoverSplitter>
81
+ <Pane>
82
+ <SlotRouter slot={routeSlot} />
83
+ <Route exact path="/">
84
+ <ScopeOverview badgeSlot={badgeSlot} overviewSlot={overviewLineSlot} />
85
+ </Route>
86
+ </Pane>
87
+ </SplitPane>
88
+ </div>
89
+ </Context>
90
+ </ScopeProvider>
91
+ );
92
+ }