From 220975b668411eeeec409a18bced5498dbf06fbc Mon Sep 17 00:00:00 2001 From: brokun Date: Sun, 28 Apr 2024 16:37:49 +0800 Subject: [PATCH 1/4] fix(core): export libro-context-key --- packages/libro-core/src/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/libro-core/src/index.tsx b/packages/libro-core/src/index.tsx index 24730413..7d14d780 100644 --- a/packages/libro-core/src/index.tsx +++ b/packages/libro-core/src/index.tsx @@ -22,3 +22,4 @@ export * from './settings/index.js'; export * from './virtualized-manager.js'; export * from './virtualized-manager-helper.js'; export * from './libro-workspace-service.js'; +export * from './libro-context-key.js'; From df5133b47cafd7bf79ba47919d348101779e61dc Mon Sep 17 00:00:00 2001 From: brokun Date: Sun, 28 Apr 2024 16:44:33 +0800 Subject: [PATCH 2/4] feat(widget): widget view can get its own management object from construction parameters --- .changeset/clean-feet-mate.md | 33 ++++++ .../src/widget/widget-render.tsx | 2 +- packages/libro-widget/src/base/index.ts | 1 + .../libro-widget/src/base/libro-widgets.ts | 24 +++- .../src/{widget-module.ts => base/module.ts} | 27 +---- packages/libro-widget/src/base/protocal.ts | 1 + .../libro-widget/src/base/widget-manager.ts | 4 + .../libro-widget/src/base/widget-view.tsx | 43 +++++-- packages/libro-widget/src/index.ts | 2 +- packages/libro-widget/src/module.ts | 9 ++ .../src/widgets/box/contribution.ts | 28 +++++ .../libro-widget/src/widgets/box/index.less | 3 + .../libro-widget/src/widgets/box/index.ts | 2 + .../libro-widget/src/widgets/box/view.tsx | 103 +++++++++++++++++ .../widgets/hbox-widget-view-contribution.ts | 20 ---- .../src/widgets/hbox-widget-view.tsx | 64 ----------- packages/libro-widget/src/widgets/index.ts | 13 +-- .../contribution.ts} | 6 +- .../src/widgets/instance-progress/index.ts | 2 + .../view.tsx} | 7 +- packages/libro-widget/src/widgets/module.ts | 31 +++++ .../contribution.ts} | 6 +- .../src/widgets/progress/index.ts | 2 + .../view.tsx} | 7 +- .../src/widgets/slider/contribution.ts | 24 ++++ .../src/widgets/slider/index.less | 3 + .../libro-widget/src/widgets/slider/index.ts | 2 + .../libro-widget/src/widgets/slider/view.tsx | 107 ++++++++++++++++++ .../contribution.ts} | 8 +- .../libro-widget/src/widgets/text/index.ts | 2 + .../{text-widget-view.tsx => text/view.tsx} | 16 ++- 31 files changed, 446 insertions(+), 156 deletions(-) create mode 100644 .changeset/clean-feet-mate.md rename packages/libro-widget/src/{widget-module.ts => base/module.ts} (50%) create mode 100644 packages/libro-widget/src/module.ts create mode 100644 packages/libro-widget/src/widgets/box/contribution.ts create mode 100644 packages/libro-widget/src/widgets/box/index.less create mode 100644 packages/libro-widget/src/widgets/box/index.ts create mode 100644 packages/libro-widget/src/widgets/box/view.tsx delete mode 100644 packages/libro-widget/src/widgets/hbox-widget-view-contribution.ts delete mode 100644 packages/libro-widget/src/widgets/hbox-widget-view.tsx rename packages/libro-widget/src/widgets/{instances-progress-widget-view-contribution.ts => instance-progress/contribution.ts} (72%) create mode 100644 packages/libro-widget/src/widgets/instance-progress/index.ts rename packages/libro-widget/src/widgets/{instances-progress-widget-view.tsx => instance-progress/view.tsx} (96%) create mode 100644 packages/libro-widget/src/widgets/module.ts rename packages/libro-widget/src/widgets/{progress-widget-view-contribution.ts => progress/contribution.ts} (77%) create mode 100644 packages/libro-widget/src/widgets/progress/index.ts rename packages/libro-widget/src/widgets/{progress-widget-view.tsx => progress/view.tsx} (92%) create mode 100644 packages/libro-widget/src/widgets/slider/contribution.ts create mode 100644 packages/libro-widget/src/widgets/slider/index.less create mode 100644 packages/libro-widget/src/widgets/slider/index.ts create mode 100644 packages/libro-widget/src/widgets/slider/view.tsx rename packages/libro-widget/src/widgets/{text-widget-view-contribution.ts => text/contribution.ts} (62%) create mode 100644 packages/libro-widget/src/widgets/text/index.ts rename packages/libro-widget/src/widgets/{text-widget-view.tsx => text/view.tsx} (81%) diff --git a/.changeset/clean-feet-mate.md b/.changeset/clean-feet-mate.md new file mode 100644 index 00000000..8481e8b4 --- /dev/null +++ b/.changeset/clean-feet-mate.md @@ -0,0 +1,33 @@ +--- +"@difizen/libro-cofine-editor-contribution": patch +"@difizen/libro-cofine-editor-core": patch +"@difizen/libro-search-code-cell": patch +"@difizen/libro-cofine-textmate": patch +"@difizen/libro-language-client": patch +"@difizen/libro-cofine-editor": patch +"@difizen/libro-markdown-cell": patch +"@difizen/libro-shared-model": patch +"@difizen/libro-code-editor": patch +"@difizen/libro-prompt-cell": patch +"@difizen/libro-virtualized": patch +"@difizen/libro-codemirror": patch +"@difizen/libro-rendermime": patch +"@difizen/libro-code-cell": patch +"@difizen/libro-markdown": patch +"@difizen/libro-raw-cell": patch +"@difizen/libro-terminal": patch +"@difizen/libro-jupyter": patch +"@difizen/libro-common": patch +"@difizen/libro-kernel": patch +"@difizen/libro-output": patch +"@difizen/libro-search": patch +"@difizen/libro-widget": patch +"@difizen/libro-core": patch +"@difizen/libro-l10n": patch +"@difizen/libro-lab": patch +"@difizen/libro-lsp": patch +"@difizen/libro-toc": patch +"@difizen/libro-docs": patch +--- + +Enhance widgets underlying capabilities diff --git a/packages/libro-jupyter/src/widget/widget-render.tsx b/packages/libro-jupyter/src/widget/widget-render.tsx index 2b955b86..f0c688a6 100644 --- a/packages/libro-jupyter/src/widget/widget-render.tsx +++ b/packages/libro-jupyter/src/widget/widget-render.tsx @@ -41,7 +41,7 @@ export const WidgetRender: React.FC<{ model: BaseOutputView }> = (props: { } return (
-
+
); }; diff --git a/packages/libro-widget/src/base/index.ts b/packages/libro-widget/src/base/index.ts index 3579120e..38276dbd 100644 --- a/packages/libro-widget/src/base/index.ts +++ b/packages/libro-widget/src/base/index.ts @@ -4,3 +4,4 @@ export * from './protocal.js'; export * from './widget-manager.js'; export * from './comm.js'; export * from './widget-view-contribution.js'; +export * from './module.js'; diff --git a/packages/libro-widget/src/base/libro-widgets.ts b/packages/libro-widget/src/base/libro-widgets.ts index ebd133fa..0a4951e6 100644 --- a/packages/libro-widget/src/base/libro-widgets.ts +++ b/packages/libro-widget/src/base/libro-widgets.ts @@ -140,9 +140,10 @@ export class LibroWidgets implements IWidgets { registerWidgetView(model_id: string, model: Promise): void { model - .then((WidgetView) => { - this.models.set(model_id, WidgetView); - this.widgetEmitter.fire({ WidgetViewName: WidgetView.model_name }); + .then((model) => { + this.models.set(model_id, model); + this.models.set(model.toModelKey(), model); + this.widgetEmitter.fire({ WidgetViewName: model.model_name }); return; }) .catch(() => { @@ -174,7 +175,11 @@ export class LibroWidgets implements IWidgets { } options.model_id = model_id; const provider = this.findProvider(attributes); - const WidgetView = provider.factory({ attributes: attributes, options: options }); + const WidgetView = provider.factory({ + attributes: attributes, + options: options, + widgetsId: this.id, + }); this.registerWidgetView(model_id, WidgetView); return WidgetView; } @@ -204,4 +209,15 @@ export class LibroWidgets implements IWidgets { */ id: string; readonly commTargetName = 'jupyter.widget'; + + /** + * Serialize the model. See the deserialization function at the top of this file + * and the kernel-side serializer/deserializer. + */ + toJSON(): string { + return JSON.stringify({ + kc_id: this.kernelConnection.id, + id: this.id, + }); + } } diff --git a/packages/libro-widget/src/widget-module.ts b/packages/libro-widget/src/base/module.ts similarity index 50% rename from packages/libro-widget/src/widget-module.ts rename to packages/libro-widget/src/base/module.ts index aab45462..38eed566 100644 --- a/packages/libro-widget/src/widget-module.ts +++ b/packages/libro-widget/src/base/module.ts @@ -1,7 +1,10 @@ import { LibroKernelManageModule } from '@difizen/libro-kernel'; import { ManaModule } from '@difizen/mana-app'; -import { Comm } from './base/comm.js'; +import { Comm } from './comm.js'; +import { LibroWidgetManager } from './widget-manager.js'; +import { DefaultWidgetViewContribution } from './widget-view-contribution.js'; + import { WidgetsOption, LibroWidgetCommFactory, @@ -10,19 +13,9 @@ import { LibroWidgetsFactory, WidgetView, WidgetViewContribution, -} from './base/index.js'; -import { LibroWidgetManager } from './base/widget-manager.js'; -import { DefaultWidgetViewContribution } from './base/widget-view-contribution.js'; -import { HBoxModelContribution } from './widgets/hbox-widget-view-contribution.js'; -import { HBoxWidget } from './widgets/hbox-widget-view.js'; -import { ProgressWidget } from './widgets/index.js'; -import { InstancesProgressWidgetViewContribution } from './widgets/instances-progress-widget-view-contribution.js'; -import { InstancesProgressWidget } from './widgets/instances-progress-widget-view.js'; -import { ProgressWidgetViewContribution } from './widgets/progress-widget-view-contribution.js'; -import { TextModelContribution } from './widgets/text-widget-view-contribution.js'; -import { LibroTextWidget } from './widgets/text-widget-view.js'; +} from './index.js'; -export const WidgetModule = ManaModule.create() +export const BaseWidgetModule = ManaModule.create() .contribution(WidgetViewContribution) .register( Comm, @@ -55,14 +48,6 @@ export const WidgetModule = ManaModule.create() }, LibroWidgetManager, WidgetView, - ProgressWidget, DefaultWidgetViewContribution, - ProgressWidgetViewContribution, - InstancesProgressWidgetViewContribution, - InstancesProgressWidget, - HBoxModelContribution, - HBoxWidget, - LibroTextWidget, - TextModelContribution, ) .dependOn(LibroKernelManageModule); diff --git a/packages/libro-widget/src/base/protocal.ts b/packages/libro-widget/src/base/protocal.ts index 0035d52f..4e3baa14 100644 --- a/packages/libro-widget/src/base/protocal.ts +++ b/packages/libro-widget/src/base/protocal.ts @@ -12,6 +12,7 @@ export interface IWidgetViewOptions { export interface IWidgetViewProps { attributes: any; options: IWidgetViewOptions; + widgetsId: string; } /** diff --git a/packages/libro-widget/src/base/widget-manager.ts b/packages/libro-widget/src/base/widget-manager.ts index 33ce442e..383a25f8 100644 --- a/packages/libro-widget/src/base/widget-manager.ts +++ b/packages/libro-widget/src/base/widget-manager.ts @@ -33,6 +33,10 @@ export class LibroWidgetManager implements ApplicationContribution { return newWidgets; }; + getWidgets(id: string) { + return this.widgets.get(id); + } + /** * Dictionary of model ids and model instance promises */ diff --git a/packages/libro-widget/src/base/widget-view.tsx b/packages/libro-widget/src/base/widget-view.tsx index 8fb04031..c388ad6d 100644 --- a/packages/libro-widget/src/base/widget-view.tsx +++ b/packages/libro-widget/src/base/widget-view.tsx @@ -1,7 +1,7 @@ import type { JSONValue } from '@difizen/libro-common'; import { LibroContextKey } from '@difizen/libro-core'; import type { KernelMessage } from '@difizen/libro-kernel'; -import { inject, transient, ViewOption, view, BaseView } from '@difizen/mana-app'; +import { inject, transient, ViewOption, view, BaseView, prop } from '@difizen/mana-app'; import type { ViewComponent } from '@difizen/mana-app'; import { forwardRef } from 'react'; @@ -15,6 +15,7 @@ import type { ICallbacks, } from './protocal.js'; import { assign } from './utils.js'; +import { LibroWidgetManager } from './widget-manager.js'; export const LibroWidgetComponent = forwardRef( function LibroWidgetComponent() { @@ -27,6 +28,9 @@ export const LibroWidgetComponent = forwardRef( export class WidgetView extends BaseView implements IWidgetView { override view: ViewComponent = LibroWidgetComponent; libroContextKey: LibroContextKey; + widgetsId: string; + @inject(LibroWidgetManager) libroWidgetManager: LibroWidgetManager; + disableCommandMode = true; constructor( @inject(ViewOption) props: IWidgetViewProps, @@ -38,6 +42,8 @@ export class WidgetView extends BaseView implements IWidgetView { } override onViewMount() { + this.widgets = this.libroWidgetManager.getWidgets(this.widgetsId)!; + if (this.container && this.container.current && this.disableCommandMode) { this.container.current.addEventListener('focusin', () => { this.libroContextKey.disableCommandMode(); @@ -53,16 +59,17 @@ export class WidgetView extends BaseView implements IWidgetView { } initialize(props: IWidgetViewProps): void { - this.model_module = props.attributes._model_module; - this.model_name = props.attributes._model_name; - this.model_module_version = props.attributes._model_module_version; - this.view_module = props.attributes._view_module; - this.view_name = props.attributes._view_name; - this.view_module_version = props.attributes._view_module_version; - this.view_count = props.attributes._view_count; + this.widgetsId = props.widgetsId; + const attributes = props.attributes; + this.model_module = attributes._model_module; + this.model_name = attributes._model_name; + this.model_module_version = attributes._model_module_version; + this.view_module = attributes._view_module; + this.view_name = attributes._view_name; + this.view_module_version = attributes._view_module_version; + this.view_count = attributes._view_count; // Attributes should be initialized here, since user initialization may depend on it - // this.libroWidgets = props.options.libroWidgets; const comm = props.options.comm; if (comm) { // Remember comm associated with the model. @@ -77,6 +84,15 @@ export class WidgetView extends BaseView implements IWidgetView { this.model_id = props.options.model_id; this.state_change = Promise.resolve(); + + this.trySetValue(attributes, 'tabbable'); + this.trySetValue(attributes, 'tooltip'); + } + + protected trySetValue(attributes: any, propKey: keyof this) { + if (propKey in attributes && attributes[propKey] !== undefined) { + this[propKey] = attributes[propKey]; + } } /** @@ -112,6 +128,10 @@ export class WidgetView extends BaseView implements IWidgetView { * and the kernel-side serializer/deserializer. */ toJSON(): string { + return this.toModelKey(); + } + + toModelKey(): string { return `IPY_MODEL_${this.model_id}`; } @@ -129,7 +149,7 @@ export class WidgetView extends BaseView implements IWidgetView { }; comm: IClassicComm; - libroWidgets: IWidgets; + @prop() widgets?: IWidgets; model_id: string; state_change: Promise; name: string; @@ -143,4 +163,7 @@ export class WidgetView extends BaseView implements IWidgetView { view_name: string | null; view_module_version: string; view_count: number | null; + + @prop() tabbable: boolean | null = null; + @prop() tooltip: string | null = null; } diff --git a/packages/libro-widget/src/index.ts b/packages/libro-widget/src/index.ts index cb80df22..c9114be5 100644 --- a/packages/libro-widget/src/index.ts +++ b/packages/libro-widget/src/index.ts @@ -1,4 +1,4 @@ export * from './components/index.js'; export * from './base/index.js'; -export * from './widget-module.js'; export * from './widgets/index.js'; +export * from './module.js'; diff --git a/packages/libro-widget/src/module.ts b/packages/libro-widget/src/module.ts new file mode 100644 index 00000000..db8eb138 --- /dev/null +++ b/packages/libro-widget/src/module.ts @@ -0,0 +1,9 @@ +import { ManaModule } from '@difizen/mana-app'; + +import { BaseWidgetModule } from './base/index.js'; +import { CommonWidgetsModule } from './widgets/index.js'; + +export const WidgetModule = ManaModule.create().dependOn( + BaseWidgetModule, + CommonWidgetsModule, +); diff --git a/packages/libro-widget/src/widgets/box/contribution.ts b/packages/libro-widget/src/widgets/box/contribution.ts new file mode 100644 index 00000000..c0d8b97e --- /dev/null +++ b/packages/libro-widget/src/widgets/box/contribution.ts @@ -0,0 +1,28 @@ +import type { IWidgetViewProps } from '@difizen/libro-widget'; +import { WidgetViewContribution } from '@difizen/libro-widget'; +import { ViewManager, inject, singleton } from '@difizen/mana-app'; + +import { VBoxWidget } from './view.js'; + +@singleton({ contrib: WidgetViewContribution }) +export class VBoxWidgetContribution implements WidgetViewContribution { + @inject(ViewManager) viewManager: ViewManager; + canHandle = (attributes: any) => { + if (attributes._model_name === 'VBoxModel') { + return 100; + } + if (attributes.__view_name === 'VBoxView') { + return 100; + } + if (attributes._model_name === 'HBoxModel') { + return 100; + } + if (attributes.__view_name === 'HBoxView') { + return 100; + } + return 1; + }; + factory(props: IWidgetViewProps) { + return this.viewManager.getOrCreateView(VBoxWidget, props); + } +} diff --git a/packages/libro-widget/src/widgets/box/index.less b/packages/libro-widget/src/widgets/box/index.less new file mode 100644 index 00000000..07c65c69 --- /dev/null +++ b/packages/libro-widget/src/widgets/box/index.less @@ -0,0 +1,3 @@ +.libro-widget-hbox { + display: flex; +} diff --git a/packages/libro-widget/src/widgets/box/index.ts b/packages/libro-widget/src/widgets/box/index.ts new file mode 100644 index 00000000..7be67da4 --- /dev/null +++ b/packages/libro-widget/src/widgets/box/index.ts @@ -0,0 +1,2 @@ +export * from './contribution.js'; +export * from './view.js'; diff --git a/packages/libro-widget/src/widgets/box/view.tsx b/packages/libro-widget/src/widgets/box/view.tsx new file mode 100644 index 00000000..bc43059c --- /dev/null +++ b/packages/libro-widget/src/widgets/box/view.tsx @@ -0,0 +1,103 @@ +import { LibroContextKey } from '@difizen/libro-core'; +import type { KernelMessage } from '@difizen/libro-kernel'; +import type { IWidgetViewProps, IWidgets } from '@difizen/libro-widget'; +import { WidgetView } from '@difizen/libro-widget'; +import { + view, + transient, + useInject, + ViewInstance, + prop, + inject, + ViewOption, + ViewRender, +} from '@difizen/mana-app'; +import { forwardRef } from 'react'; + +import './index.less'; + +const WidgetRender = (props: { widgets: IWidgets | undefined; modelId: string }) => { + const { widgets, modelId } = props; + if (!widgets) { + return null; + } + let widgetView; + try { + widgetView = widgets.getModel(modelId); + } catch (ex) { + // + } + if (!widgetView) { + return null; + } + if (widgetView.isCommClosed) { + return null; + } + return ( +
+
+ +
+
+ ); +}; + +export const LibroWidgetBoxComponent = forwardRef( + function LibroWidgetBoxComponent(props, ref) { + const widget = useInject(ViewInstance); + + return ( +
+ {widget.children.map((modelId) => ( + + ))} +
+ ); + }, +); + +@transient() +@view('libro-widget-box-view') +export class VBoxWidget extends WidgetView { + override view = LibroWidgetBoxComponent; + + @prop() children: string[] = []; + @prop() box_style?: string; + + constructor( + @inject(ViewOption) props: IWidgetViewProps, + @inject(LibroContextKey) libroContextKey: LibroContextKey, + ) { + super(props, libroContextKey); + } + + override initialize(props: IWidgetViewProps): void { + super.initialize(props); + const attributes = props.attributes; + this.trySetValue(attributes, 'children'); + this.trySetValue(attributes, 'box_style'); + } + + override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise { + const data = msg.content.data as any; + const method = data.method; + switch (method) { + case 'update': + case 'echo_update': + if (data.state.children) { + this.children = data.state.children; + } + } + return Promise.resolve(); + } + + getCls = () => { + if (this.model_name === 'HBoxModel') { + return 'libro-widget-hbox'; + } + if (this.model_name === 'VBoxModel') { + return 'libro-widget-vbox'; + } + return ''; + }; +} diff --git a/packages/libro-widget/src/widgets/hbox-widget-view-contribution.ts b/packages/libro-widget/src/widgets/hbox-widget-view-contribution.ts deleted file mode 100644 index c86b10a8..00000000 --- a/packages/libro-widget/src/widgets/hbox-widget-view-contribution.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ViewManager, inject, singleton } from '@difizen/mana-app'; - -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetViewContribution } from '../base/protocal.js'; - -import { HBoxWidget } from './hbox-widget-view.js'; - -@singleton({ contrib: WidgetViewContribution }) -export class HBoxModelContribution implements WidgetViewContribution { - @inject(ViewManager) viewManager: ViewManager; - canHandle = (attributes: any) => { - if (attributes._model_name === 'HBoxModel') { - return 100; - } - return 1; - }; - factory(props: IWidgetViewProps) { - return this.viewManager.getOrCreateView(HBoxWidget, props); - } -} diff --git a/packages/libro-widget/src/widgets/hbox-widget-view.tsx b/packages/libro-widget/src/widgets/hbox-widget-view.tsx deleted file mode 100644 index 73e6b755..00000000 --- a/packages/libro-widget/src/widgets/hbox-widget-view.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { LibroContextKey } from '@difizen/libro-core'; -import { - view, - ViewOption, - ViewRender, - transient, - useInject, - ViewInstance, - inject, -} from '@difizen/mana-app'; -import { forwardRef } from 'react'; - -import { LibroWidgets } from '../base/libro-widgets.js'; -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetView } from '../base/widget-view.js'; -import './index.less'; - -export const HBoxWidgetComponent = forwardRef( - function HBoxWidgetComponent() { - const widgetView = useInject(ViewInstance); - if (widgetView.isCommClosed) { - return null; - } - const hboxChildrenWidget = widgetView.get_child_model(); - return ( -
- {hboxChildrenWidget.map((childrenWidgets) => ( - - ))} -
- ); - }, -); -@transient() -@view('libro-hbox-widget-view') -export class HBoxWidget extends WidgetView { - override view = HBoxWidgetComponent; - children: string[]; - layout: string; - box_style: string; - override libroWidgets: LibroWidgets; - constructor( - @inject(ViewOption) props: IWidgetViewProps, - @inject(LibroContextKey) libroContextKey: LibroContextKey, - @inject(LibroWidgets) libroWidgets: LibroWidgets, - ) { - super(props, libroContextKey); - this.box_style = props.attributes.bar_style; - this.layout = props.attributes.layout; - this.children = props.attributes.children; - this.libroContextKey = libroContextKey; - this.libroWidgets = libroWidgets; - } - - get_child_model(): WidgetView[] { - const childrenWidgets: WidgetView[] = []; - this.children.forEach((child) => { - if (this.libroWidgets.hasModel(child.substring(10))) { - childrenWidgets.push(this.libroWidgets.getModel(child.substring(10))); - } - }); - return childrenWidgets; - } -} diff --git a/packages/libro-widget/src/widgets/index.ts b/packages/libro-widget/src/widgets/index.ts index 454320fe..53e0215a 100644 --- a/packages/libro-widget/src/widgets/index.ts +++ b/packages/libro-widget/src/widgets/index.ts @@ -1,8 +1,5 @@ -export * from './hbox-widget-view.js'; -export * from './hbox-widget-view-contribution.js'; -export * from './instances-progress-widget-view.js'; -export * from './instances-progress-widget-view-contribution.js'; -export * from './progress-widget-view.js'; -export * from './progress-widget-view-contribution.js'; -export * from './text-widget-view.js'; -export * from './text-widget-view-contribution.js'; +export * from './instance-progress/index.js'; +export * from './progress/index.js'; +export * from './text/index.js'; +export * from './box/index.js'; +export * from './module.js'; diff --git a/packages/libro-widget/src/widgets/instances-progress-widget-view-contribution.ts b/packages/libro-widget/src/widgets/instance-progress/contribution.ts similarity index 72% rename from packages/libro-widget/src/widgets/instances-progress-widget-view-contribution.ts rename to packages/libro-widget/src/widgets/instance-progress/contribution.ts index a10069b9..33f1821f 100644 --- a/packages/libro-widget/src/widgets/instances-progress-widget-view-contribution.ts +++ b/packages/libro-widget/src/widgets/instance-progress/contribution.ts @@ -1,9 +1,9 @@ import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetViewContribution } from '../base/protocal.js'; +import type { IWidgetViewProps } from '../../base/protocal.js'; +import { WidgetViewContribution } from '../../base/protocal.js'; -import { InstancesProgressWidget } from './instances-progress-widget-view.js'; +import { InstancesProgressWidget } from './view.js'; @singleton({ contrib: WidgetViewContribution }) export class InstancesProgressWidgetViewContribution implements WidgetViewContribution { diff --git a/packages/libro-widget/src/widgets/instance-progress/index.ts b/packages/libro-widget/src/widgets/instance-progress/index.ts new file mode 100644 index 00000000..7be67da4 --- /dev/null +++ b/packages/libro-widget/src/widgets/instance-progress/index.ts @@ -0,0 +1,2 @@ +export * from './contribution.js'; +export * from './view.js'; diff --git a/packages/libro-widget/src/widgets/instances-progress-widget-view.tsx b/packages/libro-widget/src/widgets/instance-progress/view.tsx similarity index 96% rename from packages/libro-widget/src/widgets/instances-progress-widget-view.tsx rename to packages/libro-widget/src/widgets/instance-progress/view.tsx index ce35a07f..6a3103b1 100644 --- a/packages/libro-widget/src/widgets/instances-progress-widget-view.tsx +++ b/packages/libro-widget/src/widgets/instance-progress/view.tsx @@ -15,10 +15,9 @@ import type { InstanceRecord, InstancesRecords, ProgressItem, -} from '../base/protocal.js'; -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetView } from '../base/widget-view.js'; -import './index.less'; +} from '../../base/protocal.js'; +import type { IWidgetViewProps } from '../../base/protocal.js'; +import { WidgetView } from '../../base/widget-view.js'; export interface ProgressOverviewProps { progressMap: Record; diff --git a/packages/libro-widget/src/widgets/module.ts b/packages/libro-widget/src/widgets/module.ts new file mode 100644 index 00000000..90bb8b7f --- /dev/null +++ b/packages/libro-widget/src/widgets/module.ts @@ -0,0 +1,31 @@ +import { ManaModule } from '@difizen/mana-app'; + +import { BaseWidgetModule } from '../base/index.js'; + +import { VBoxWidget, VBoxWidgetContribution } from './box/index.js'; +import { + InstancesProgressWidget, + InstancesProgressWidgetViewContribution, +} from './instance-progress/index.js'; +import { ProgressWidget, ProgressWidgetViewContribution } from './progress/index.js'; +import { SilderWidgetContribution, SliderWidget } from './slider/index.js'; +import { TextModelContribution, TextWidget } from './text/index.js'; + +export const CommonWidgetsModule = ManaModule.create() + .register( + VBoxWidget, + VBoxWidgetContribution, + + SliderWidget, + SilderWidgetContribution, + + ProgressWidget, + ProgressWidgetViewContribution, + + InstancesProgressWidget, + InstancesProgressWidgetViewContribution, + + TextWidget, + TextModelContribution, + ) + .dependOn(BaseWidgetModule); diff --git a/packages/libro-widget/src/widgets/progress-widget-view-contribution.ts b/packages/libro-widget/src/widgets/progress/contribution.ts similarity index 77% rename from packages/libro-widget/src/widgets/progress-widget-view-contribution.ts rename to packages/libro-widget/src/widgets/progress/contribution.ts index b51e7446..b90108a9 100644 --- a/packages/libro-widget/src/widgets/progress-widget-view-contribution.ts +++ b/packages/libro-widget/src/widgets/progress/contribution.ts @@ -1,9 +1,9 @@ import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetViewContribution } from '../base/protocal.js'; +import type { IWidgetViewProps } from '../../base/protocal.js'; +import { WidgetViewContribution } from '../../base/protocal.js'; -import { ProgressWidget } from './progress-widget-view.js'; +import { ProgressWidget } from './view.js'; @singleton({ contrib: WidgetViewContribution }) export class ProgressWidgetViewContribution implements WidgetViewContribution { diff --git a/packages/libro-widget/src/widgets/progress/index.ts b/packages/libro-widget/src/widgets/progress/index.ts new file mode 100644 index 00000000..7be67da4 --- /dev/null +++ b/packages/libro-widget/src/widgets/progress/index.ts @@ -0,0 +1,2 @@ +export * from './contribution.js'; +export * from './view.js'; diff --git a/packages/libro-widget/src/widgets/progress-widget-view.tsx b/packages/libro-widget/src/widgets/progress/view.tsx similarity index 92% rename from packages/libro-widget/src/widgets/progress-widget-view.tsx rename to packages/libro-widget/src/widgets/progress/view.tsx index 0c5d05f3..cb010273 100644 --- a/packages/libro-widget/src/widgets/progress-widget-view.tsx +++ b/packages/libro-widget/src/widgets/progress/view.tsx @@ -11,10 +11,9 @@ import { } from '@difizen/mana-app'; import { forwardRef } from 'react'; -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetView } from '../base/widget-view.js'; -import { ProgressBar } from '../components/index.js'; -import './index.less'; +import type { IWidgetViewProps } from '../../base/protocal.js'; +import { WidgetView } from '../../base/widget-view.js'; +import { ProgressBar } from '../../components/index.js'; export const LibroProgressWidgetComponent = forwardRef( function LibroProgressWidgetComponent() { diff --git a/packages/libro-widget/src/widgets/slider/contribution.ts b/packages/libro-widget/src/widgets/slider/contribution.ts new file mode 100644 index 00000000..104fc620 --- /dev/null +++ b/packages/libro-widget/src/widgets/slider/contribution.ts @@ -0,0 +1,24 @@ +import { ViewManager, inject, singleton } from '@difizen/mana-app'; +import type { IWidgetViewProps } from '@difizen/libro-widget'; +import { WidgetViewContribution } from '@difizen/libro-widget'; +import { SliderWidget } from './view.js'; + +@singleton({ contrib: WidgetViewContribution }) +export class SilderWidgetContribution implements WidgetViewContribution { + @inject(ViewManager) viewManager: ViewManager; + canHandle = (attributes: any) => { + if (attributes._model_name === 'IntSliderModel') { + return 100; + } + if (attributes.__view_name === 'IntSliderView') { + return 100; + } + if (attributes._model_name === 'FloatSliderModel') { + return 100; + } + return 1; + }; + factory(props: IWidgetViewProps) { + return this.viewManager.getOrCreateView(SliderWidget, props); + } +} diff --git a/packages/libro-widget/src/widgets/slider/index.less b/packages/libro-widget/src/widgets/slider/index.less new file mode 100644 index 00000000..e6588a9f --- /dev/null +++ b/packages/libro-widget/src/widgets/slider/index.less @@ -0,0 +1,3 @@ +.libro-widget-slider { + display: block; +} diff --git a/packages/libro-widget/src/widgets/slider/index.ts b/packages/libro-widget/src/widgets/slider/index.ts new file mode 100644 index 00000000..7be67da4 --- /dev/null +++ b/packages/libro-widget/src/widgets/slider/index.ts @@ -0,0 +1,2 @@ +export * from './contribution.js'; +export * from './view.js'; diff --git a/packages/libro-widget/src/widgets/slider/view.tsx b/packages/libro-widget/src/widgets/slider/view.tsx new file mode 100644 index 00000000..771a89ac --- /dev/null +++ b/packages/libro-widget/src/widgets/slider/view.tsx @@ -0,0 +1,107 @@ +import { LibroContextKey } from '@difizen/libro-core'; +import type { KernelMessage } from '@difizen/libro-kernel'; +import type { IWidgetViewProps } from '@difizen/libro-widget'; +import { WidgetView } from '@difizen/libro-widget'; +import { + view, + transient, + useInject, + ViewInstance, + prop, + inject, + ViewOption, +} from '@difizen/mana-app'; +import { Slider } from 'antd'; +import { forwardRef } from 'react'; +import './index.less'; + +export const LibroWidgetIntSliderComponent = forwardRef( + function LibroWidgetIntSliderComponent(props, ref) { + const widget = useInject(ViewInstance); + + if (widget.isCommClosed) { + return null; + } + + return ( +
+ +
+ ); + }, +); + +@transient() +@view('libro-widget-slider-view') +export class SliderWidget extends WidgetView { + override view = LibroWidgetIntSliderComponent; + + @prop() behavior = 'drag-drop'; + @prop() continuous_update = false; + @prop() description = ''; + @prop() description_allow_html = false; + @prop() disabled = false; + @prop() layout?: string; + @prop() max?: number; + @prop() min?: number; + @prop() orientation: 'horizontal' | 'vertical' = 'horizontal'; + @prop() readout = true; + @prop() readout_format = 'd'; + @prop() step = 1; + @prop() style?: string; + + @prop() value: number; + + constructor( + @inject(ViewOption) props: IWidgetViewProps, + @inject(LibroContextKey) libroContextKey: LibroContextKey, + ) { + super(props, libroContextKey); + } + + override initialize(props: IWidgetViewProps): void { + super.initialize(props); + if (this.model_name === 'FloatSliderModel') { + if (!this.step) { + this.step === 0.01; + } + } + const attributes = props.attributes; + this.trySetValue(attributes, 'behavior'); + this.trySetValue(attributes, 'continuous_update'); + this.trySetValue(attributes, 'description'); + this.trySetValue(attributes, 'description_allow_html'); + this.trySetValue(attributes, 'disabled'); + this.trySetValue(attributes, 'layout'); + this.trySetValue(attributes, 'max'); + this.trySetValue(attributes, 'min'); + this.trySetValue(attributes, 'orientation'); + this.trySetValue(attributes, 'readout'); + this.trySetValue(attributes, 'readout_format'); + this.trySetValue(attributes, 'step'); + this.trySetValue(attributes, 'style'); + this.trySetValue(attributes, 'value'); + } + + override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise { + const data = msg.content.data as any; + const method = data.method; + switch (method) { + case 'update': + case 'echo_update': + if (data.state.value) { + this.value = data.state.value; + } + } + return Promise.resolve(); + } + + handleChange = (value: number) => { + const data = { + buffer_paths: [], + method: 'update', + state: { value: value }, + }; + this.send(data); + }; +} diff --git a/packages/libro-widget/src/widgets/text-widget-view-contribution.ts b/packages/libro-widget/src/widgets/text/contribution.ts similarity index 62% rename from packages/libro-widget/src/widgets/text-widget-view-contribution.ts rename to packages/libro-widget/src/widgets/text/contribution.ts index 5d3efcea..3d2188bd 100644 --- a/packages/libro-widget/src/widgets/text-widget-view-contribution.ts +++ b/packages/libro-widget/src/widgets/text/contribution.ts @@ -1,9 +1,9 @@ import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetViewContribution } from '../base/protocal.js'; +import type { IWidgetViewProps } from '../../base/protocal.js'; +import { WidgetViewContribution } from '../../base/protocal.js'; -import { LibroTextWidget } from './text-widget-view.js'; +import { TextWidget } from './view.js'; @singleton({ contrib: WidgetViewContribution }) export class TextModelContribution implements WidgetViewContribution { @@ -15,6 +15,6 @@ export class TextModelContribution implements WidgetViewContribution { return 1; }; factory(props: IWidgetViewProps) { - return this.viewManager.getOrCreateView(LibroTextWidget, props); + return this.viewManager.getOrCreateView(TextWidget, props); } } diff --git a/packages/libro-widget/src/widgets/text/index.ts b/packages/libro-widget/src/widgets/text/index.ts new file mode 100644 index 00000000..7be67da4 --- /dev/null +++ b/packages/libro-widget/src/widgets/text/index.ts @@ -0,0 +1,2 @@ +export * from './contribution.js'; +export * from './view.js'; diff --git a/packages/libro-widget/src/widgets/text-widget-view.tsx b/packages/libro-widget/src/widgets/text/view.tsx similarity index 81% rename from packages/libro-widget/src/widgets/text-widget-view.tsx rename to packages/libro-widget/src/widgets/text/view.tsx index 6e841126..b9ea1559 100644 --- a/packages/libro-widget/src/widgets/text-widget-view.tsx +++ b/packages/libro-widget/src/widgets/text/view.tsx @@ -11,14 +11,12 @@ import { import { Input } from 'antd'; import { forwardRef } from 'react'; -import type { IWidgetViewProps } from '../base/protocal.js'; -import { WidgetView } from '../base/widget-view.js'; +import type { IWidgetViewProps } from '../../base/protocal.js'; +import { WidgetView } from '../../base/widget-view.js'; -import './index.less'; - -export const LibroTextWidgetComponent = forwardRef( - function LibroTextWidgetComponent(_props, ref) { - const widgetView = useInject(ViewInstance); +export const TextWidgetComponent = forwardRef( + function TextWidgetComponent(_props, ref) { + const widgetView = useInject(ViewInstance); if (widgetView.isCommClosed) { return null; } @@ -55,8 +53,8 @@ export const LibroTextWidgetComponent = forwardRef( ); @transient() @view('libro-widget-text-view') -export class LibroTextWidget extends WidgetView { - override view = LibroTextWidgetComponent; +export class TextWidget extends WidgetView { + override view = TextWidgetComponent; bar_style: string; description: string; description_tooltip: null; From 4106878c00a30b2e66396c6001650804c6458ad9 Mon Sep 17 00:00:00 2001 From: brokun Date: Thu, 9 May 2024 11:29:58 +0800 Subject: [PATCH 3/4] refactor(widget): add the state attribute to the widget --- packages/libro-widget/src/base/protocal.ts | 1 - .../libro-widget/src/base/widget-view.tsx | 67 ++++++++-------- .../libro-widget/src/widgets/box/view.tsx | 35 ++++----- .../src/widgets/progress/view.tsx | 77 +++++++++---------- packages/libro-widget/src/widgets/protocol.ts | 25 ++++++ .../libro-widget/src/widgets/slider/view.tsx | 77 +++++++++++-------- 6 files changed, 152 insertions(+), 130 deletions(-) create mode 100644 packages/libro-widget/src/widgets/protocol.ts diff --git a/packages/libro-widget/src/base/protocal.ts b/packages/libro-widget/src/base/protocal.ts index 4e3baa14..01a49689 100644 --- a/packages/libro-widget/src/base/protocal.ts +++ b/packages/libro-widget/src/base/protocal.ts @@ -69,7 +69,6 @@ export interface WidgetsOption { } export interface IWidgetView { - initialize: (props: IWidgetViewProps) => void; toJSON: () => string; set_state: (state: Dict) => void; handleCommMsg: (msg: KernelMessage.ICommMsgMsg) => Promise; diff --git a/packages/libro-widget/src/base/widget-view.tsx b/packages/libro-widget/src/base/widget-view.tsx index c388ad6d..84c26a03 100644 --- a/packages/libro-widget/src/base/widget-view.tsx +++ b/packages/libro-widget/src/base/widget-view.tsx @@ -1,4 +1,4 @@ -import type { JSONValue } from '@difizen/libro-common'; +import type { JSONObject, JSONValue } from '@difizen/libro-common'; import { LibroContextKey } from '@difizen/libro-core'; import type { KernelMessage } from '@difizen/libro-kernel'; import { inject, transient, ViewOption, view, BaseView, prop } from '@difizen/mana-app'; @@ -7,14 +7,12 @@ import { forwardRef } from 'react'; import type { IWidgetViewProps } from './protocal.js'; import type { - BufferJSON, Dict, IWidgets, IWidgetView, IClassicComm, ICallbacks, } from './protocal.js'; -import { assign } from './utils.js'; import { LibroWidgetManager } from './widget-manager.js'; export const LibroWidgetComponent = forwardRef( @@ -31,34 +29,15 @@ export class WidgetView extends BaseView implements IWidgetView { widgetsId: string; @inject(LibroWidgetManager) libroWidgetManager: LibroWidgetManager; + @prop() + state: JSONObject = {}; + disableCommandMode = true; constructor( @inject(ViewOption) props: IWidgetViewProps, @inject(LibroContextKey) libroContextKey: LibroContextKey, ) { super(); - this.initialize(props); - this.libroContextKey = libroContextKey; - } - - override onViewMount() { - this.widgets = this.libroWidgetManager.getWidgets(this.widgetsId)!; - - if (this.container && this.container.current && this.disableCommandMode) { - this.container.current.addEventListener('focusin', () => { - this.libroContextKey.disableCommandMode(); - }); - this.container.current.addEventListener('blur', (e) => { - if (this.container?.current?.contains(e.relatedTarget as Node)) { - this.libroContextKey.disableCommandMode(); - } else { - this.libroContextKey.enableCommandMode(); - } - }); - } - } - - initialize(props: IWidgetViewProps): void { this.widgetsId = props.widgetsId; const attributes = props.attributes; this.model_module = attributes._model_module; @@ -87,11 +66,29 @@ export class WidgetView extends BaseView implements IWidgetView { this.trySetValue(attributes, 'tabbable'); this.trySetValue(attributes, 'tooltip'); + this.libroContextKey = libroContextKey; + } + + override onViewMount() { + this.widgets = this.libroWidgetManager.getWidgets(this.widgetsId)!; + + if (this.container && this.container.current && this.disableCommandMode) { + this.container.current.addEventListener('focusin', () => { + this.libroContextKey.disableCommandMode(); + }); + this.container.current.addEventListener('blur', (e) => { + if (this.container?.current?.contains(e.relatedTarget as Node)) { + this.libroContextKey.disableCommandMode(); + } else { + this.libroContextKey.enableCommandMode(); + } + }); + } } - protected trySetValue(attributes: any, propKey: keyof this) { + protected trySetValue(attributes: any, propKey: string) { if (propKey in attributes && attributes[propKey] !== undefined) { - this[propKey] = attributes[propKey]; + this.state[propKey] = attributes[propKey]; } } @@ -104,9 +101,7 @@ export class WidgetView extends BaseView implements IWidgetView { switch (method) { case 'update': case 'echo_update': - // eslint-disable-next-line no-case-declarations - const state: Dict = data.state; - this.set_state(state); + this.set_state(data.state); } return Promise.resolve(); } @@ -119,8 +114,10 @@ export class WidgetView extends BaseView implements IWidgetView { * * This function is meant for internal use only. Values set here will not be propagated on a sync. */ - set_state(state: Dict): void { - assign(this, state); + set_state(state: Dict): void { + for (const key in state) { + this.state[key] = state[key]; + } } /** @@ -144,8 +141,9 @@ export class WidgetView extends BaseView implements IWidgetView { buffers?: ArrayBuffer[] | ArrayBufferView[], ) => { if (this.comm !== undefined) { - this.comm.send(data, callbacks, {}, buffers); + return this.comm.send(data, callbacks, {}, buffers); } + return undefined; }; comm: IClassicComm; @@ -163,7 +161,4 @@ export class WidgetView extends BaseView implements IWidgetView { view_name: string | null; view_module_version: string; view_count: number | null; - - @prop() tabbable: boolean | null = null; - @prop() tooltip: string | null = null; } diff --git a/packages/libro-widget/src/widgets/box/view.tsx b/packages/libro-widget/src/widgets/box/view.tsx index bc43059c..4a196d68 100644 --- a/packages/libro-widget/src/widgets/box/view.tsx +++ b/packages/libro-widget/src/widgets/box/view.tsx @@ -1,5 +1,4 @@ import { LibroContextKey } from '@difizen/libro-core'; -import type { KernelMessage } from '@difizen/libro-kernel'; import type { IWidgetViewProps, IWidgets } from '@difizen/libro-widget'; import { WidgetView } from '@difizen/libro-widget'; import { @@ -14,6 +13,9 @@ import { } from '@difizen/mana-app'; import { forwardRef } from 'react'; +import type { WidgetState } from '../protocol.js'; +import { defaultWidgetState } from '../protocol.js'; + import './index.less'; const WidgetRender = (props: { widgets: IWidgets | undefined; modelId: string }) => { @@ -48,7 +50,7 @@ export const LibroWidgetBoxComponent = forwardRef( return (
- {widget.children.map((modelId) => ( + {widget.state.children.map((modelId) => ( ))}
@@ -56,41 +58,36 @@ export const LibroWidgetBoxComponent = forwardRef( }, ); +interface BoxState extends WidgetState { + children: string[]; + box_style?: string; +} + @transient() @view('libro-widget-box-view') export class VBoxWidget extends WidgetView { override view = LibroWidgetBoxComponent; - @prop() children: string[] = []; - @prop() box_style?: string; + @prop() + override state: BoxState = { + ...defaultWidgetState, + children: [], + }; constructor( @inject(ViewOption) props: IWidgetViewProps, @inject(LibroContextKey) libroContextKey: LibroContextKey, ) { super(props, libroContextKey); + this.initialize(props); } - override initialize(props: IWidgetViewProps): void { - super.initialize(props); + protected initialize(props: IWidgetViewProps): void { const attributes = props.attributes; this.trySetValue(attributes, 'children'); this.trySetValue(attributes, 'box_style'); } - override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise { - const data = msg.content.data as any; - const method = data.method; - switch (method) { - case 'update': - case 'echo_update': - if (data.state.children) { - this.children = data.state.children; - } - } - return Promise.resolve(); - } - getCls = () => { if (this.model_name === 'HBoxModel') { return 'libro-widget-hbox'; diff --git a/packages/libro-widget/src/widgets/progress/view.tsx b/packages/libro-widget/src/widgets/progress/view.tsx index cb010273..0ccd63cc 100644 --- a/packages/libro-widget/src/widgets/progress/view.tsx +++ b/packages/libro-widget/src/widgets/progress/view.tsx @@ -1,5 +1,5 @@ +import type { JSONObject } from '@difizen/libro-common'; import { LibroContextKey } from '@difizen/libro-core'; -import type { KernelMessage } from '@difizen/libro-kernel'; import { view, ViewOption, @@ -14,71 +14,66 @@ import { forwardRef } from 'react'; import type { IWidgetViewProps } from '../../base/protocal.js'; import { WidgetView } from '../../base/widget-view.js'; import { ProgressBar } from '../../components/index.js'; +import type { WidgetState } from '../protocol.js'; +import { defaultWidgetState } from '../protocol.js'; export const LibroProgressWidgetComponent = forwardRef( function LibroProgressWidgetComponent() { const widgetView = useInject(ViewInstance); - const percent = widgetView.value / ((widgetView.max - widgetView.min) / 100); + const percent = + widgetView.state.max && widgetView.state.min + ? widgetView.state.value / ((widgetView.state.max - widgetView.state.min) / 100) + : 0; if (widgetView.isCommClosed) { return null; } return (
- {widgetView.description} + {widgetView.state.description}
); }, ); + +interface ProgressState extends WidgetState { + max?: number; + min?: number; + bar_style?: string; + value: number; +} @transient() @view('libro-widget-progress-view') export class ProgressWidget extends WidgetView { override view = LibroProgressWidgetComponent; - bar_style: string; - description: string; - description_tooltip: null; - layout: string; - @prop() - max: number; - @prop() - min: number; - orientation: string; - style: string; + @prop() - value: number; + override state: JSONObject & ProgressState = { + ...defaultWidgetState, + max: 1, + min: 0, + value: 0, + }; constructor( @inject(ViewOption) props: IWidgetViewProps, @inject(LibroContextKey) libroContextKey: LibroContextKey, ) { super(props, libroContextKey); - this.bar_style = props.attributes.bar_style; - this.description = props.attributes.description; - this.description_tooltip = props.attributes.description_tooltip; - this.layout = props.attributes.layout; - this.max = props.attributes.max; - this.min = props.attributes.min; - this.orientation = props.attributes.orientation; - this.style = props.attributes.style; - this.value = props.attributes.value; - } - /** - * Handle incoming comm msg. - */ - override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise { - const data = msg.content.data as any; - const method = data.method; - switch (method) { - case 'update': - case 'echo_update': - if (data.state.value) { - this.value = data.state.value; - } - if (data.state.description) { - this.description = data.state.description; - } - } - return Promise.resolve(); + + const attributes = props.attributes; + this.state.max = attributes.max; + this.state.min = attributes.min; + this.trySetValue(attributes, 'bar_style'); + this.trySetValue(attributes, 'description'); + this.trySetValue(attributes, 'description_allow_html'); + this.trySetValue(attributes, 'disabled'); + this.trySetValue(attributes, 'layout'); + this.trySetValue(attributes, 'max'); + this.trySetValue(attributes, 'min'); + this.trySetValue(attributes, 'orientation'); + this.trySetValue(attributes, 'style'); + this.trySetValue(attributes, 'value'); } } diff --git a/packages/libro-widget/src/widgets/protocol.ts b/packages/libro-widget/src/widgets/protocol.ts new file mode 100644 index 00000000..949719f5 --- /dev/null +++ b/packages/libro-widget/src/widgets/protocol.ts @@ -0,0 +1,25 @@ +export interface WidgetState { + behavior?: string; + continuous_update: boolean; + description: string; + description_allow_html: boolean; + disabled: boolean; + layout?: string; + readout: boolean; + readout_format: string; + style?: string; + [key: string]: any; +} + +export const defaultWidgetState: WidgetState = { + continuous_update: false, + description_allow_html: false, + description: '', + disabled: false, + readout: true, + readout_format: 'd', +}; + +export interface OrientableState { + orientation: 'horizontal' | 'vertical'; +} diff --git a/packages/libro-widget/src/widgets/slider/view.tsx b/packages/libro-widget/src/widgets/slider/view.tsx index 771a89ac..d9f71cf1 100644 --- a/packages/libro-widget/src/widgets/slider/view.tsx +++ b/packages/libro-widget/src/widgets/slider/view.tsx @@ -1,5 +1,5 @@ +import type { JSONObject } from '@difizen/libro-common'; import { LibroContextKey } from '@difizen/libro-core'; -import type { KernelMessage } from '@difizen/libro-kernel'; import type { IWidgetViewProps } from '@difizen/libro-widget'; import { WidgetView } from '@difizen/libro-widget'; import { @@ -13,6 +13,9 @@ import { } from '@difizen/mana-app'; import { Slider } from 'antd'; import { forwardRef } from 'react'; + +import type { OrientableState, WidgetState } from '../protocol.js'; +import { defaultWidgetState } from '../protocol.js'; import './index.less'; export const LibroWidgetIntSliderComponent = forwardRef( @@ -25,48 +28,56 @@ export const LibroWidgetIntSliderComponent = forwardRef( return (
- +
); }, ); +interface SliderState extends WidgetState, OrientableState { + max?: number; + min?: number; + step: number; + value: number; +} + @transient() @view('libro-widget-slider-view') export class SliderWidget extends WidgetView { override view = LibroWidgetIntSliderComponent; - @prop() behavior = 'drag-drop'; - @prop() continuous_update = false; - @prop() description = ''; - @prop() description_allow_html = false; - @prop() disabled = false; - @prop() layout?: string; - @prop() max?: number; - @prop() min?: number; - @prop() orientation: 'horizontal' | 'vertical' = 'horizontal'; - @prop() readout = true; - @prop() readout_format = 'd'; - @prop() step = 1; - @prop() style?: string; - - @prop() value: number; + @prop() + override state: JSONObject & SliderState = { + ...defaultWidgetState, + orientation: 'horizontal', + step: 1, + value: 0, + }; constructor( @inject(ViewOption) props: IWidgetViewProps, @inject(LibroContextKey) libroContextKey: LibroContextKey, ) { super(props, libroContextKey); + this.initialize(props); } - override initialize(props: IWidgetViewProps): void { - super.initialize(props); + protected initialize(props: IWidgetViewProps): void { if (this.model_name === 'FloatSliderModel') { - if (!this.step) { - this.step === 0.01; + if (!this.state.step) { + this.state.step === 0.01; } } const attributes = props.attributes; + this.state.max = attributes.max; + this.state.min = attributes.min; this.trySetValue(attributes, 'behavior'); this.trySetValue(attributes, 'continuous_update'); this.trySetValue(attributes, 'description'); @@ -83,18 +94,18 @@ export class SliderWidget extends WidgetView { this.trySetValue(attributes, 'value'); } - override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise { - const data = msg.content.data as any; - const method = data.method; - switch (method) { - case 'update': - case 'echo_update': - if (data.state.value) { - this.value = data.state.value; - } - } - return Promise.resolve(); - } + // override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise { + // const data = msg.content.data as any; + // const method = data.method; + // switch (method) { + // case 'update': + // case 'echo_update': + // if (data.state.value) { + // this.value = data.state.value; + // } + // } + // return Promise.resolve(); + // } handleChange = (value: number) => { const data = { From e30cfcdb865ce996798033f694b00023c61c559b Mon Sep 17 00:00:00 2001 From: brokun Date: Fri, 10 May 2024 17:58:56 +0800 Subject: [PATCH 4/4] feat: refactor the widget-related modules & support interactive operations --- .changeset/gold-lions-deny.md | 33 +++++ .../libro-core/src/cell/libro-cell-view.tsx | 18 ++- .../libro-core/src/output/output-area.tsx | 43 ++++-- .../libro-core/src/output/output-model.tsx | 6 +- .../libro-core/src/output/output-protocol.ts | 5 + packages/libro-jupyter/package.json | 1 - .../src/cell/jupyter-code-cell-view.tsx | 11 +- packages/libro-jupyter/src/index.ts | 1 + packages/libro-jupyter/src/module.ts | 4 +- .../src/output/libro-jupyter-outputarea.tsx | 105 +++++++------- .../src/widget}/box/contribution.ts | 5 +- .../src/widget}/box/index.less | 0 .../src/widget}/box/index.ts | 0 .../src/widget}/box/view.tsx | 28 ++-- .../base => libro-jupyter/src/widget}/comm.ts | 8 +- packages/libro-jupyter/src/widget/index.ts | 7 + .../widget}/instance-progress/contribution.ts | 4 +- .../src/widget}/instance-progress/index.ts | 0 .../src/widget}/instance-progress/view.tsx | 10 +- .../src/widget}/libro-widgets.ts | 4 +- .../src/widget}/module.ts | 36 +++-- .../src/widget}/progress/contribution.ts | 4 +- .../src/widget}/progress/index.ts | 0 .../src/widget/progress}/progressBar.tsx | 0 .../src/widget}/progress/view.tsx | 19 +-- .../src/widget/protocol.ts} | 43 +++++- .../src/widget}/utils.ts | 2 +- .../src/widget}/version.ts | 0 .../src/widget}/widget-manager.ts | 4 +- .../src/widget/widget-render.tsx | 13 +- .../widget/widget-rendermime-contribution.ts | 3 +- .../src/widget}/widget-view-contribution.ts | 4 +- .../src/widget}/widget-view.tsx | 133 +++++++++++++++--- packages/libro-kernel/src/kernel/future.ts | 7 +- .../src/kernel/kernel-connection.ts | 9 +- .../src/kernel/libro-kernel-protocol.ts | 2 +- packages/libro-lab/package.json | 1 + packages/libro-lab/src/module.tsx | 2 + .../display-data-output-model.tsx | 33 +++-- .../src/stream-output/stream-output-model.tsx | 24 ++-- .../src/rendermime-protocol.ts | 5 +- .../src/rendermime-registry.ts | 9 +- packages/libro-widget/package.json | 1 + packages/libro-widget/src/base/index.ts | 7 - packages/libro-widget/src/components/index.ts | 3 - .../src/components/progressCircle.tsx | 18 --- packages/libro-widget/src/index.spec.ts | 5 +- packages/libro-widget/src/index.ts | 5 +- packages/libro-widget/src/module.ts | 18 ++- .../src/{widgets => }/slider/contribution.ts | 5 +- .../src/{widgets => }/slider/index.less | 0 .../src/{widgets => }/slider/index.ts | 0 .../src/{widgets => }/slider/view.tsx | 36 +---- .../src/{widgets => }/text/contribution.ts | 5 +- .../src/{widgets => }/text/index.ts | 0 .../src/{widgets => }/text/view.tsx | 5 +- packages/libro-widget/src/widgets/index.less | 3 - packages/libro-widget/src/widgets/index.ts | 5 - packages/libro-widget/src/widgets/module.ts | 31 ---- packages/libro-widget/src/widgets/protocol.ts | 25 ---- 60 files changed, 498 insertions(+), 320 deletions(-) create mode 100644 .changeset/gold-lions-deny.md rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/box/contribution.ts (85%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/box/index.less (100%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/box/index.ts (100%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/box/view.tsx (75%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/comm.ts (94%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/instance-progress/contribution.ts (81%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/instance-progress/index.ts (100%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/instance-progress/view.tsx (95%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/libro-widgets.ts (99%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/module.ts (63%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/progress/contribution.ts (83%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/progress/index.ts (100%) rename packages/{libro-widget/src/components => libro-jupyter/src/widget/progress}/progressBar.tsx (100%) rename packages/{libro-widget/src/widgets => libro-jupyter/src/widget}/progress/view.tsx (70%) rename packages/{libro-widget/src/base/protocal.ts => libro-jupyter/src/widget/protocol.ts} (85%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/utils.ts (97%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/version.ts (100%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/widget-manager.ts (92%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/widget-view-contribution.ts (79%) rename packages/{libro-widget/src/base => libro-jupyter/src/widget}/widget-view.tsx (56%) delete mode 100644 packages/libro-widget/src/base/index.ts delete mode 100644 packages/libro-widget/src/components/index.ts delete mode 100644 packages/libro-widget/src/components/progressCircle.tsx rename packages/libro-widget/src/{widgets => }/slider/contribution.ts (84%) rename packages/libro-widget/src/{widgets => }/slider/index.less (100%) rename packages/libro-widget/src/{widgets => }/slider/index.ts (100%) rename packages/libro-widget/src/{widgets => }/slider/view.tsx (61%) rename packages/libro-widget/src/{widgets => }/text/contribution.ts (80%) rename packages/libro-widget/src/{widgets => }/text/index.ts (100%) rename packages/libro-widget/src/{widgets => }/text/view.tsx (94%) delete mode 100644 packages/libro-widget/src/widgets/index.less delete mode 100644 packages/libro-widget/src/widgets/index.ts delete mode 100644 packages/libro-widget/src/widgets/module.ts delete mode 100644 packages/libro-widget/src/widgets/protocol.ts diff --git a/.changeset/gold-lions-deny.md b/.changeset/gold-lions-deny.md new file mode 100644 index 00000000..10b113f2 --- /dev/null +++ b/.changeset/gold-lions-deny.md @@ -0,0 +1,33 @@ +--- +"@difizen/libro-cofine-editor-contribution": patch +"@difizen/libro-cofine-editor-core": patch +"@difizen/libro-search-code-cell": patch +"@difizen/libro-cofine-textmate": patch +"@difizen/libro-language-client": patch +"@difizen/libro-cofine-editor": patch +"@difizen/libro-markdown-cell": patch +"@difizen/libro-shared-model": patch +"@difizen/libro-code-editor": patch +"@difizen/libro-prompt-cell": patch +"@difizen/libro-virtualized": patch +"@difizen/libro-codemirror": patch +"@difizen/libro-rendermime": patch +"@difizen/libro-code-cell": patch +"@difizen/libro-markdown": patch +"@difizen/libro-raw-cell": patch +"@difizen/libro-terminal": patch +"@difizen/libro-jupyter": patch +"@difizen/libro-common": patch +"@difizen/libro-kernel": patch +"@difizen/libro-output": patch +"@difizen/libro-search": patch +"@difizen/libro-widget": patch +"@difizen/libro-core": patch +"@difizen/libro-l10n": patch +"@difizen/libro-lab": patch +"@difizen/libro-lsp": patch +"@difizen/libro-toc": patch +"@difizen/libro-docs": patch +--- + +Support widget interactive! diff --git a/packages/libro-core/src/cell/libro-cell-view.tsx b/packages/libro-core/src/cell/libro-cell-view.tsx index e9120f11..e6c6bc27 100644 --- a/packages/libro-core/src/cell/libro-cell-view.tsx +++ b/packages/libro-core/src/cell/libro-cell-view.tsx @@ -1,4 +1,5 @@ import type { ViewComponent } from '@difizen/mana-app'; +import { Deferred } from '@difizen/mana-app'; import { useInject, watch } from '@difizen/mana-app'; import { BaseView, view, ViewInstance, ViewOption } from '@difizen/mana-app'; import { inject } from '@difizen/mana-app'; @@ -36,7 +37,22 @@ export class LibroCellView extends BaseView implements CellView { model: CellModel; protected cellService: CellService; override view: ViewComponent = LibroCellComponent; - parent: NotebookView; + + protected _parent: NotebookView; + + get parent() { + return this._parent; + } + set parent(value: NotebookView) { + this._parent = value; + this.parentDefer.resolve(this.parent); + } + + protected parentDefer = new Deferred(); + + get parentReady() { + return this.parentDefer.promise; + } @prop() override className?: string | undefined = 'libro-cell-view-container'; diff --git a/packages/libro-core/src/output/output-area.tsx b/packages/libro-core/src/output/output-area.tsx index b4938103..e37a520e 100644 --- a/packages/libro-core/src/output/output-area.tsx +++ b/packages/libro-core/src/output/output-area.tsx @@ -35,7 +35,15 @@ const LibroOutputAreaRender = forwardRef( useEffect(() => { outputArea.onUpdateEmitter.fire(); }, [outputArea.onUpdateEmitter, outputArea.outputs]); - + const childrenCannotClear = []; + const children = []; + for (const output of outputArea.outputs) { + if (output.allowClear === false) { + childrenCannotClear.push(output); + } else { + children.push(output); + } + } return (
( //设置最小高度,用于优化长文本输出再次执行时的页面的滚动控制 // style={{ minHeight: `${executing ? outputArea.lastOutputContainerHeight + 'px' : 'unset'}` }} > - {outputArea.outputs.map((output) => { + {childrenCannotClear.map((output) => { + return ; + })} + {children.map((output) => { return ; })}
@@ -103,10 +114,10 @@ export class LibroOutputArea extends BaseView implements BaseOutputArea { }); } add = async (output: IOutput): Promise => { - // if (this.clearNext) { - // this.clear(); - // this.clearNext = false; - // } + if (this.clearNext) { + this.clear(); + this.clearNext = false; + } // Consolidate outputs if they are stream outputs of the same kind. if ( isStream(output) && @@ -141,13 +152,28 @@ export class LibroOutputArea extends BaseView implements BaseOutputArea { } else { this.lastStream = ''; } - return this.outputs.push(await outputModel); + const model = await outputModel; + model.onDisposed(() => { + this.remove(model); + }); + return this.outputs.push(model); }; + + protected remove(model: BaseOutputView) { + let outputs = [...this.outputs]; + outputs = outputs.filter((item) => item !== model); + this.outputs = outputs; + } + set = async (index: number, output: IOutput) => { const outputModel = this.doCreateOutput(output); const current = this.outputs[index]; current.dispose(); - this.outputs[index] = await outputModel; + const model = await outputModel; + model.onDisposed(() => { + this.remove(model); + }); + this.outputs[index] = model; }; clear(wait?: boolean | undefined) { this.lastStream = ''; @@ -158,7 +184,6 @@ export class LibroOutputArea extends BaseView implements BaseOutputArea { this.outputs.forEach((output) => { output.dispose(); }); - this.outputs = []; } fromJSON = async (values: IOutput[]) => { if (!values) { diff --git a/packages/libro-core/src/output/output-model.tsx b/packages/libro-core/src/output/output-model.tsx index 3970be45..431cbdbc 100644 --- a/packages/libro-core/src/output/output-model.tsx +++ b/packages/libro-core/src/output/output-model.tsx @@ -26,6 +26,10 @@ export class LibroOutputView extends BaseView implements BaseOutputView { @prop() raw: IOutput; + + @prop() + allowClear = true; + @prop() data: JSONObject; @prop() @@ -45,7 +49,7 @@ export class LibroOutputView extends BaseView implements BaseOutputView { render: FC<{ output: BaseOutputView }> = LibroOutputModelRender; override dispose() { - // + super.dispose(); } toJSON() { return this.raw; diff --git a/packages/libro-core/src/output/output-protocol.ts b/packages/libro-core/src/output/output-protocol.ts index 14ee35a4..13ba1f76 100644 --- a/packages/libro-core/src/output/output-protocol.ts +++ b/packages/libro-core/src/output/output-protocol.ts @@ -126,6 +126,11 @@ export interface BaseOutputView extends View { * Depending on the implementation of the mime model, */ setData(options: ISetDataOptions): void; + + /** + * undefined is considered allowed + */ + allowClear?: boolean; } /** diff --git a/packages/libro-jupyter/package.json b/packages/libro-jupyter/package.json index d4cdbb50..437613f4 100644 --- a/packages/libro-jupyter/package.json +++ b/packages/libro-jupyter/package.json @@ -60,7 +60,6 @@ "@difizen/libro-markdown-cell": "^0.1.33", "@difizen/libro-raw-cell": "^0.1.33", "@difizen/libro-language-client": "^0.1.33", - "@difizen/libro-widget": "^0.1.33", "@difizen/mana-app": "latest", "@difizen/mana-l10n": "latest", "@ant-design/colors": "^7.0.0", diff --git a/packages/libro-jupyter/src/cell/jupyter-code-cell-view.tsx b/packages/libro-jupyter/src/cell/jupyter-code-cell-view.tsx index eccfdd2a..6f6a48fa 100644 --- a/packages/libro-jupyter/src/cell/jupyter-code-cell-view.tsx +++ b/packages/libro-jupyter/src/cell/jupyter-code-cell-view.tsx @@ -39,7 +39,16 @@ const JupyterCodeCellComponent = forwardRef( @transient() @view('jupyter-code-cell-view') export class JupyterCodeCellView extends LibroCodeCellView { - declare parent: LibroJupyterView; + protected declare _parent: LibroJupyterView; + + override get parent() { + return this._parent; + } + override set parent(value: LibroJupyterView) { + this._parent = value; + this.parentDefer.resolve(this.parent); + } + override view = JupyterCodeCellComponent; declare model: JupyterCodeCellModel; diff --git a/packages/libro-jupyter/src/index.ts b/packages/libro-jupyter/src/index.ts index 97b5a8b6..9c6b1759 100644 --- a/packages/libro-jupyter/src/index.ts +++ b/packages/libro-jupyter/src/index.ts @@ -32,3 +32,4 @@ export * from './toolbar/index.js'; export * from './file/index.js'; export * from './libro-jupyter-view.js'; export * from './config/index.js'; +export * from './widget/index.js'; diff --git a/packages/libro-jupyter/src/module.ts b/packages/libro-jupyter/src/module.ts index e412897f..c8e9ebdf 100644 --- a/packages/libro-jupyter/src/module.ts +++ b/packages/libro-jupyter/src/module.ts @@ -25,7 +25,6 @@ import { import { RawCellModule } from '@difizen/libro-raw-cell'; import { LibroSearchModule } from '@difizen/libro-search'; import { SearchCodeCellModule } from '@difizen/libro-search-code-cell'; -import { WidgetModule } from '@difizen/libro-widget'; import { ManaModule } from '@difizen/mana-app'; import { LibroBetweenCellModule } from './add-between-cell/index.js'; @@ -57,7 +56,7 @@ import { LibroJupyterToolbarContribution, SaveFileErrorContribution, } from './toolbar/index.js'; -import { LibroWidgetMimeContribution } from './widget/index.js'; +import { WidgetModule } from './widget/index.js'; export const LibroJupyterModule = ManaModule.create() .register( @@ -76,7 +75,6 @@ export const LibroJupyterModule = ManaModule.create() LibroJupyterSettingContribution, JupyterServerLaunchManager, LibroJupyterView, - LibroWidgetMimeContribution, { token: CellExecutionTimeProvider, useValue: CellExecutionTip, diff --git a/packages/libro-jupyter/src/output/libro-jupyter-outputarea.tsx b/packages/libro-jupyter/src/output/libro-jupyter-outputarea.tsx index ef043790..8cb99a94 100644 --- a/packages/libro-jupyter/src/output/libro-jupyter-outputarea.tsx +++ b/packages/libro-jupyter/src/output/libro-jupyter-outputarea.tsx @@ -6,8 +6,10 @@ import type { } from '@difizen/libro-core'; import { LibroOutputArea } from '@difizen/libro-core'; import { + isClearOutputMsg, isDisplayDataMsg, isErrorMsg, + isExecuteInputMsg, isExecuteReplyMsg, isExecuteResultMsg, isStreamMsg, @@ -31,58 +33,61 @@ export class LibroJupyterOutputArea extends LibroOutputArea { cellModel.msgChangeEmitter.event((msg) => { const transientMsg = (msg.content.transient || {}) as nbformat.JSONObject; const displayId = transientMsg['display_id'] as string; - if (msg.header.msg_type !== 'status') { - if (msg.header.msg_type === 'execute_input') { - cellModel.executeCount = msg.content.execution_count; - } - if ( - isDisplayDataMsg(msg) || - isStreamMsg(msg) || - isErrorMsg(msg) || - isExecuteResultMsg(msg) - ) { - const output: nbformat.IOutput = { - ...msg.content, - output_type: msg.header.msg_type, - }; - this.add(output); - } - if (isUpdateDisplayDataMsg(msg)) { - const output = { ...msg.content, output_type: 'display_data' }; - const targets = this.displayIdMap.get(displayId); - if (targets) { - for (const index of targets) { - this.set(index, output); - } + if (isExecuteInputMsg(msg)) { + cellModel.executeCount = msg.content.execution_count; + } + if ( + isDisplayDataMsg(msg) || + isStreamMsg(msg) || + isErrorMsg(msg) || + isExecuteResultMsg(msg) + ) { + const output: nbformat.IOutput = { + ...msg.content, + output_type: msg.header.msg_type, + }; + this.add(output); + } + if (isUpdateDisplayDataMsg(msg)) { + const output = { ...msg.content, output_type: 'display_data' }; + const targets = this.displayIdMap.get(displayId); + if (targets) { + for (const index of targets) { + this.set(index, output); } } - if (displayId && isDisplayDataMsg(msg)) { - const targets = this.displayIdMap.get(displayId) || []; - targets.push(this.outputs.length); - this.displayIdMap.set(displayId, targets); + } + if (displayId && isDisplayDataMsg(msg)) { + const targets = this.displayIdMap.get(displayId) || []; + targets.push(this.outputs.length); + this.displayIdMap.set(displayId, targets); + } + //Handle an execute reply message. + if (isExecuteReplyMsg(msg)) { + const content = msg.content; + if (content.status !== 'ok') { + return; } - //Handle an execute reply message. - if (isExecuteReplyMsg(msg)) { - const content = msg.content; - if (content.status !== 'ok') { - return; - } - const payload = content && content.payload; - if (!payload || !payload.length) { - return; - } - const pages = payload.filter((i: any) => i.source === 'page'); - if (!pages.length) { - return; - } - const page = JSON.parse(JSON.stringify(pages[0])); - const output: nbformat.IOutput = { - output_type: 'display_data', - data: page.data as nbformat.IMimeBundle, - metadata: {}, - }; - this.add(output); + const payload = content && content.payload; + if (!payload || !payload.length) { + return; + } + const pages = payload.filter((i: any) => i.source === 'page'); + if (!pages.length) { + return; } + const page = JSON.parse(JSON.stringify(pages[0])); + const output: nbformat.IOutput = { + output_type: 'display_data', + data: page.data as nbformat.IMimeBundle, + metadata: {}, + }; + this.add(output); + } + + if (isClearOutputMsg(msg)) { + const wait = msg.content.wait; + this.clear(wait); } }); } @@ -94,6 +99,8 @@ export class LibroJupyterOutputArea extends LibroOutputArea { override clear(wait?: boolean | undefined): void { super.clear(wait); - this.displayIdMap.clear(); + if (!wait) { + this.displayIdMap.clear(); + } } } diff --git a/packages/libro-widget/src/widgets/box/contribution.ts b/packages/libro-jupyter/src/widget/box/contribution.ts similarity index 85% rename from packages/libro-widget/src/widgets/box/contribution.ts rename to packages/libro-jupyter/src/widget/box/contribution.ts index c0d8b97e..ba6ff4ec 100644 --- a/packages/libro-widget/src/widgets/box/contribution.ts +++ b/packages/libro-jupyter/src/widget/box/contribution.ts @@ -1,7 +1,8 @@ -import type { IWidgetViewProps } from '@difizen/libro-widget'; -import { WidgetViewContribution } from '@difizen/libro-widget'; import { ViewManager, inject, singleton } from '@difizen/mana-app'; +import type { IWidgetViewProps } from '../protocol.js'; +import { WidgetViewContribution } from '../protocol.js'; + import { VBoxWidget } from './view.js'; @singleton({ contrib: WidgetViewContribution }) diff --git a/packages/libro-widget/src/widgets/box/index.less b/packages/libro-jupyter/src/widget/box/index.less similarity index 100% rename from packages/libro-widget/src/widgets/box/index.less rename to packages/libro-jupyter/src/widget/box/index.less diff --git a/packages/libro-widget/src/widgets/box/index.ts b/packages/libro-jupyter/src/widget/box/index.ts similarity index 100% rename from packages/libro-widget/src/widgets/box/index.ts rename to packages/libro-jupyter/src/widget/box/index.ts diff --git a/packages/libro-widget/src/widgets/box/view.tsx b/packages/libro-jupyter/src/widget/box/view.tsx similarity index 75% rename from packages/libro-widget/src/widgets/box/view.tsx rename to packages/libro-jupyter/src/widget/box/view.tsx index 4a196d68..254edf6c 100644 --- a/packages/libro-widget/src/widgets/box/view.tsx +++ b/packages/libro-jupyter/src/widget/box/view.tsx @@ -1,6 +1,5 @@ +import type { CellView } from '@difizen/libro-core'; import { LibroContextKey } from '@difizen/libro-core'; -import type { IWidgetViewProps, IWidgets } from '@difizen/libro-widget'; -import { WidgetView } from '@difizen/libro-widget'; import { view, transient, @@ -10,16 +9,22 @@ import { inject, ViewOption, ViewRender, + getOrigin, } from '@difizen/mana-app'; import { forwardRef } from 'react'; -import type { WidgetState } from '../protocol.js'; +import type { IWidgets, IWidgetViewProps, WidgetState } from '../protocol.js'; import { defaultWidgetState } from '../protocol.js'; +import { WidgetView } from '../widget-view.js'; import './index.less'; -const WidgetRender = (props: { widgets: IWidgets | undefined; modelId: string }) => { - const { widgets, modelId } = props; +const WidgetRender = (props: { + cell?: CellView; + widgets: IWidgets | undefined; + modelId: string; +}) => { + const { widgets, modelId, cell } = props; if (!widgets) { return null; } @@ -32,6 +37,9 @@ const WidgetRender = (props: { widgets: IWidgets | undefined; modelId: string }) if (!widgetView) { return null; } + if (cell) { + widgetView.setCell(getOrigin(cell)); + } if (widgetView.isCommClosed) { return null; } @@ -51,7 +59,12 @@ export const LibroWidgetBoxComponent = forwardRef( return (
{widget.state.children.map((modelId) => ( - + ))}
); @@ -84,8 +97,7 @@ export class VBoxWidget extends WidgetView { protected initialize(props: IWidgetViewProps): void { const attributes = props.attributes; - this.trySetValue(attributes, 'children'); - this.trySetValue(attributes, 'box_style'); + this.setState(attributes); } getCls = () => { diff --git a/packages/libro-widget/src/base/comm.ts b/packages/libro-jupyter/src/widget/comm.ts similarity index 94% rename from packages/libro-widget/src/base/comm.ts rename to packages/libro-jupyter/src/widget/comm.ts index 8c87a67d..7ac5b278 100644 --- a/packages/libro-widget/src/base/comm.ts +++ b/packages/libro-jupyter/src/widget/comm.ts @@ -2,8 +2,8 @@ import type { JSONObject } from '@difizen/libro-common'; import type { IComm, IKernelConnection, IShellFuture } from '@difizen/libro-kernel'; import { inject, transient } from '@difizen/mana-app'; -import type { ICallbacks, IClassicComm } from './protocal.js'; -import { WidgetCommOption } from './protocal.js'; +import type { ICallbacks, IClassicComm } from './protocol.js'; +import { WidgetCommOption } from './protocol.js'; /** * Public constructor @@ -90,7 +90,7 @@ export class Comm implements IClassicComm { * Register a message handler * @param callback, which is given a message */ - on_msg(callback: (x: any) => void): void { + onMsg(callback: (x: any) => void): void { this.jsServicesComm.onMsg = callback.bind(this); } @@ -98,7 +98,7 @@ export class Comm implements IClassicComm { * Register a handler for when the comm is closed by the backend * @param callback, which is given a message */ - on_close(callback: (x: any) => void): void { + onClose(callback: (x: any) => void): void { this.jsServicesComm.onClose = callback.bind(this); } diff --git a/packages/libro-jupyter/src/widget/index.ts b/packages/libro-jupyter/src/widget/index.ts index edb5f0ab..4a7a9687 100644 --- a/packages/libro-jupyter/src/widget/index.ts +++ b/packages/libro-jupyter/src/widget/index.ts @@ -1,2 +1,9 @@ export * from './widget-render.js'; export * from './widget-rendermime-contribution.js'; +export * from './libro-widgets.js'; +export * from './widget-view.js'; +export * from './widget-manager.js'; +export * from './comm.js'; +export * from './widget-view-contribution.js'; +export * from './module.js'; +export * from './protocol.js'; diff --git a/packages/libro-widget/src/widgets/instance-progress/contribution.ts b/packages/libro-jupyter/src/widget/instance-progress/contribution.ts similarity index 81% rename from packages/libro-widget/src/widgets/instance-progress/contribution.ts rename to packages/libro-jupyter/src/widget/instance-progress/contribution.ts index 33f1821f..4ad06c6b 100644 --- a/packages/libro-widget/src/widgets/instance-progress/contribution.ts +++ b/packages/libro-jupyter/src/widget/instance-progress/contribution.ts @@ -1,7 +1,7 @@ import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from '../../base/protocal.js'; -import { WidgetViewContribution } from '../../base/protocal.js'; +import type { IWidgetViewProps } from '../protocol.js'; +import { WidgetViewContribution } from '../protocol.js'; import { InstancesProgressWidget } from './view.js'; diff --git a/packages/libro-widget/src/widgets/instance-progress/index.ts b/packages/libro-jupyter/src/widget/instance-progress/index.ts similarity index 100% rename from packages/libro-widget/src/widgets/instance-progress/index.ts rename to packages/libro-jupyter/src/widget/instance-progress/index.ts diff --git a/packages/libro-widget/src/widgets/instance-progress/view.tsx b/packages/libro-jupyter/src/widget/instance-progress/view.tsx similarity index 95% rename from packages/libro-widget/src/widgets/instance-progress/view.tsx rename to packages/libro-jupyter/src/widget/instance-progress/view.tsx index 6a3103b1..3ac3a835 100644 --- a/packages/libro-widget/src/widgets/instance-progress/view.tsx +++ b/packages/libro-jupyter/src/widget/instance-progress/view.tsx @@ -11,13 +11,9 @@ import { } from '@difizen/mana-app'; import { forwardRef } from 'react'; -import type { - InstanceRecord, - InstancesRecords, - ProgressItem, -} from '../../base/protocal.js'; -import type { IWidgetViewProps } from '../../base/protocal.js'; -import { WidgetView } from '../../base/widget-view.js'; +import type { IWidgetViewProps } from '../protocol.js'; +import type { InstanceRecord, InstancesRecords, ProgressItem } from '../protocol.js'; +import { WidgetView } from '../widget-view.js'; export interface ProgressOverviewProps { progressMap: Record; diff --git a/packages/libro-widget/src/base/libro-widgets.ts b/packages/libro-jupyter/src/widget/libro-widgets.ts similarity index 99% rename from packages/libro-widget/src/base/libro-widgets.ts rename to packages/libro-jupyter/src/widget/libro-widgets.ts index 0a4951e6..15a08808 100644 --- a/packages/libro-widget/src/base/libro-widgets.ts +++ b/packages/libro-jupyter/src/widget/libro-widgets.ts @@ -11,12 +11,12 @@ import type { IWidgetViewOptions, IClassicComm, WidgetCommOption, -} from './protocal.js'; +} from './protocol.js'; import { LibroWidgetCommFactory, WidgetsOption, WidgetViewContribution, -} from './protocal.js'; +} from './protocol.js'; import { put_buffers, reject } from './utils.js'; import { PROTOCOL_VERSION } from './version.js'; import type { WidgetView } from './widget-view.js'; diff --git a/packages/libro-widget/src/base/module.ts b/packages/libro-jupyter/src/widget/module.ts similarity index 63% rename from packages/libro-widget/src/base/module.ts rename to packages/libro-jupyter/src/widget/module.ts index 38eed566..3aeb6c4d 100644 --- a/packages/libro-widget/src/base/module.ts +++ b/packages/libro-jupyter/src/widget/module.ts @@ -1,19 +1,25 @@ import { LibroKernelManageModule } from '@difizen/libro-kernel'; import { ManaModule } from '@difizen/mana-app'; +import { VBoxWidget, VBoxWidgetContribution } from './box/index.js'; import { Comm } from './comm.js'; -import { LibroWidgetManager } from './widget-manager.js'; -import { DefaultWidgetViewContribution } from './widget-view-contribution.js'; - import { - WidgetsOption, + InstancesProgressWidget, + InstancesProgressWidgetViewContribution, +} from './instance-progress/index.js'; +import { LibroWidgets } from './libro-widgets.js'; +import { ProgressWidget, ProgressWidgetViewContribution } from './progress/index.js'; +import { LibroWidgetCommFactory, - WidgetCommOption, - LibroWidgets, LibroWidgetsFactory, - WidgetView, + WidgetCommOption, + WidgetsOption, WidgetViewContribution, -} from './index.js'; +} from './protocol.js'; +import { LibroWidgetManager } from './widget-manager.js'; +import { LibroWidgetMimeContribution } from './widget-rendermime-contribution.js'; +import { DefaultWidgetViewContribution } from './widget-view-contribution.js'; +import { WidgetView } from './widget-view.js'; export const BaseWidgetModule = ManaModule.create() .contribution(WidgetViewContribution) @@ -49,5 +55,19 @@ export const BaseWidgetModule = ManaModule.create() LibroWidgetManager, WidgetView, DefaultWidgetViewContribution, + LibroWidgetMimeContribution, ) .dependOn(LibroKernelManageModule); + +export const WidgetModule = ManaModule.create() + .register( + VBoxWidget, + VBoxWidgetContribution, + + ProgressWidget, + ProgressWidgetViewContribution, + + InstancesProgressWidget, + InstancesProgressWidgetViewContribution, + ) + .dependOn(BaseWidgetModule); diff --git a/packages/libro-widget/src/widgets/progress/contribution.ts b/packages/libro-jupyter/src/widget/progress/contribution.ts similarity index 83% rename from packages/libro-widget/src/widgets/progress/contribution.ts rename to packages/libro-jupyter/src/widget/progress/contribution.ts index b90108a9..0bc76d96 100644 --- a/packages/libro-widget/src/widgets/progress/contribution.ts +++ b/packages/libro-jupyter/src/widget/progress/contribution.ts @@ -1,7 +1,7 @@ import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from '../../base/protocal.js'; -import { WidgetViewContribution } from '../../base/protocal.js'; +import type { IWidgetViewProps } from '../protocol.js'; +import { WidgetViewContribution } from '../protocol.js'; import { ProgressWidget } from './view.js'; diff --git a/packages/libro-widget/src/widgets/progress/index.ts b/packages/libro-jupyter/src/widget/progress/index.ts similarity index 100% rename from packages/libro-widget/src/widgets/progress/index.ts rename to packages/libro-jupyter/src/widget/progress/index.ts diff --git a/packages/libro-widget/src/components/progressBar.tsx b/packages/libro-jupyter/src/widget/progress/progressBar.tsx similarity index 100% rename from packages/libro-widget/src/components/progressBar.tsx rename to packages/libro-jupyter/src/widget/progress/progressBar.tsx diff --git a/packages/libro-widget/src/widgets/progress/view.tsx b/packages/libro-jupyter/src/widget/progress/view.tsx similarity index 70% rename from packages/libro-widget/src/widgets/progress/view.tsx rename to packages/libro-jupyter/src/widget/progress/view.tsx index 0ccd63cc..df008273 100644 --- a/packages/libro-widget/src/widgets/progress/view.tsx +++ b/packages/libro-jupyter/src/widget/progress/view.tsx @@ -11,11 +11,11 @@ import { } from '@difizen/mana-app'; import { forwardRef } from 'react'; -import type { IWidgetViewProps } from '../../base/protocal.js'; -import { WidgetView } from '../../base/widget-view.js'; -import { ProgressBar } from '../../components/index.js'; -import type { WidgetState } from '../protocol.js'; +import type { IWidgetViewProps, WidgetState } from '../protocol.js'; import { defaultWidgetState } from '../protocol.js'; +import { WidgetView } from '../widget-view.js'; + +import { ProgressBar } from './progressBar.js'; export const LibroProgressWidgetComponent = forwardRef( function LibroProgressWidgetComponent() { @@ -65,15 +65,6 @@ export class ProgressWidget extends WidgetView { const attributes = props.attributes; this.state.max = attributes.max; this.state.min = attributes.min; - this.trySetValue(attributes, 'bar_style'); - this.trySetValue(attributes, 'description'); - this.trySetValue(attributes, 'description_allow_html'); - this.trySetValue(attributes, 'disabled'); - this.trySetValue(attributes, 'layout'); - this.trySetValue(attributes, 'max'); - this.trySetValue(attributes, 'min'); - this.trySetValue(attributes, 'orientation'); - this.trySetValue(attributes, 'style'); - this.trySetValue(attributes, 'value'); + this.setState(attributes); } } diff --git a/packages/libro-widget/src/base/protocal.ts b/packages/libro-jupyter/src/widget/protocol.ts similarity index 85% rename from packages/libro-widget/src/base/protocal.ts rename to packages/libro-jupyter/src/widget/protocol.ts index 01a49689..64621a0c 100644 --- a/packages/libro-widget/src/base/protocal.ts +++ b/packages/libro-jupyter/src/widget/protocol.ts @@ -70,7 +70,7 @@ export interface WidgetsOption { export interface IWidgetView { toJSON: () => string; - set_state: (state: Dict) => void; + setState: (state: Dict) => void; handleCommMsg: (msg: KernelMessage.ICommMsgMsg) => Promise; model_id: string; name: string; @@ -208,11 +208,48 @@ export interface IClassicComm { * Register a message handler * @param callback, which is given a message */ - on_msg(callback: (x: any) => void): void; + onMsg(callback: (x: any) => void): void; /** * Register a handler for when the comm is closed by the backend * @param callback, which is given a message */ - on_close(callback: (x: any) => void): void; + onClose(callback: (x: any) => void): void; +} + +export interface WidgetState { + msg_id?: string; + behavior?: string; + continuous_update: boolean; + description: string; + description_allow_html: boolean; + disabled: boolean; + layout?: string; + readout: boolean; + readout_format: string; + style?: string; + [key: string]: any; +} + +export const defaultWidgetState: WidgetState = { + continuous_update: false, + description_allow_html: false, + description: '', + disabled: false, + readout: true, + readout_format: 'd', +}; + +export interface FormattableState { + readout: boolean; + readout_format: string; +} + +export const defaultFormattableState: FormattableState = { + readout: true, + readout_format: 'd', +}; + +export interface OrientableState { + orientation: 'horizontal' | 'vertical'; } diff --git a/packages/libro-widget/src/base/utils.ts b/packages/libro-jupyter/src/widget/utils.ts similarity index 97% rename from packages/libro-widget/src/base/utils.ts rename to packages/libro-jupyter/src/widget/utils.ts index 2157f199..740a659f 100644 --- a/packages/libro-widget/src/base/utils.ts +++ b/packages/libro-jupyter/src/widget/utils.ts @@ -1,4 +1,4 @@ -import type { BufferJSON, Dict } from './protocal.js'; +import type { BufferJSON, Dict } from './protocol.js'; /** * Takes an object 'state' and fills in buffer[i] at 'path' buffer_paths[i] diff --git a/packages/libro-widget/src/base/version.ts b/packages/libro-jupyter/src/widget/version.ts similarity index 100% rename from packages/libro-widget/src/base/version.ts rename to packages/libro-jupyter/src/widget/version.ts diff --git a/packages/libro-widget/src/base/widget-manager.ts b/packages/libro-jupyter/src/widget/widget-manager.ts similarity index 92% rename from packages/libro-widget/src/base/widget-manager.ts rename to packages/libro-jupyter/src/widget/widget-manager.ts index 383a25f8..2e483111 100644 --- a/packages/libro-widget/src/base/widget-manager.ts +++ b/packages/libro-jupyter/src/widget/widget-manager.ts @@ -4,8 +4,8 @@ import { KernelConnection, LibroKernelManager } from '@difizen/libro-kernel'; import { inject, prop, singleton, ApplicationContribution } from '@difizen/mana-app'; import type { LibroWidgets } from './libro-widgets.js'; -import { LibroWidgetsFactory } from './protocal.js'; -import type { WidgetsOption } from './protocal.js'; +import { LibroWidgetsFactory } from './protocol.js'; +import type { WidgetsOption } from './protocol.js'; @singleton({ contrib: ApplicationContribution }) export class LibroWidgetManager implements ApplicationContribution { diff --git a/packages/libro-jupyter/src/widget/widget-render.tsx b/packages/libro-jupyter/src/widget/widget-render.tsx index f0c688a6..b81551f3 100644 --- a/packages/libro-jupyter/src/widget/widget-render.tsx +++ b/packages/libro-jupyter/src/widget/widget-render.tsx @@ -1,18 +1,22 @@ -import type { BaseOutputView } from '@difizen/libro-core'; +import type { BaseOutputView, LibroOutputView } from '@difizen/libro-core'; import { RenderMimeRegistry } from '@difizen/libro-rendermime'; import type { IRenderMimeRegistry } from '@difizen/libro-rendermime'; -import { LibroWidgetManager } from '@difizen/libro-widget'; -import { getOrigin, useInject, ViewRender } from '@difizen/mana-app'; +import { getOrigin, useInject, ViewInstance, ViewRender } from '@difizen/mana-app'; import React from 'react'; -import './index.less'; +import './index.less'; import { LibroJupyterModel } from '../libro-jupyter-model.js'; +import { LibroWidgetManager } from './widget-manager.js'; + export const WidgetRender: React.FC<{ model: BaseOutputView }> = (props: { model: BaseOutputView; }) => { const { model } = props; + // The widget will be rendered in the output through the MIME mechanism, obtaining the output context. + const output = useInject(ViewInstance); + const widgetManager = useInject(LibroWidgetManager); const defaultRenderMime = useInject(RenderMimeRegistry); const libro = model.cell.parent; @@ -27,6 +31,7 @@ export const WidgetRender: React.FC<{ model: BaseOutputView }> = (props: { const model_id = JSON.parse(JSON.stringify(model.data[mimeType])).model_id; if (model_id) { const widgetView = widgets.getModel(model_id); + widgetView.setCell(getOrigin(output.cell)); if (widgetView.isCommClosed) { return null; } diff --git a/packages/libro-jupyter/src/widget/widget-rendermime-contribution.ts b/packages/libro-jupyter/src/widget/widget-rendermime-contribution.ts index 4e4310cf..bb0df4ac 100644 --- a/packages/libro-jupyter/src/widget/widget-rendermime-contribution.ts +++ b/packages/libro-jupyter/src/widget/widget-rendermime-contribution.ts @@ -1,10 +1,10 @@ import type { BaseOutputView } from '@difizen/libro-core'; import { RenderMimeContribution } from '@difizen/libro-rendermime'; -import { LibroWidgetManager } from '@difizen/libro-widget'; import { inject, singleton } from '@difizen/mana-app'; import { LibroJupyterModel } from '../libro-jupyter-model.js'; +import { LibroWidgetManager } from './widget-manager.js'; import { WidgetRender } from './widget-render.js'; @singleton({ contrib: RenderMimeContribution }) @@ -31,5 +31,6 @@ export class LibroWidgetMimeContribution implements RenderMimeContribution { renderType = 'widgetRenderer'; safe = true; mimeTypes = ['application/vnd.jupyter.widget-view+json']; + allowClear = false; render = WidgetRender; } diff --git a/packages/libro-widget/src/base/widget-view-contribution.ts b/packages/libro-jupyter/src/widget/widget-view-contribution.ts similarity index 79% rename from packages/libro-widget/src/base/widget-view-contribution.ts rename to packages/libro-jupyter/src/widget/widget-view-contribution.ts index 80d197b7..fbaf24df 100644 --- a/packages/libro-widget/src/base/widget-view-contribution.ts +++ b/packages/libro-jupyter/src/widget/widget-view-contribution.ts @@ -1,7 +1,7 @@ import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from './protocal.js'; -import { WidgetViewContribution } from './protocal.js'; +import type { IWidgetViewProps } from './protocol.js'; +import { WidgetViewContribution } from './protocol.js'; import { WidgetView } from './widget-view.js'; @singleton({ contrib: WidgetViewContribution }) diff --git a/packages/libro-widget/src/base/widget-view.tsx b/packages/libro-jupyter/src/widget/widget-view.tsx similarity index 56% rename from packages/libro-widget/src/base/widget-view.tsx rename to packages/libro-jupyter/src/widget/widget-view.tsx index 84c26a03..ef3af7a2 100644 --- a/packages/libro-widget/src/base/widget-view.tsx +++ b/packages/libro-jupyter/src/widget/widget-view.tsx @@ -1,18 +1,32 @@ -import type { JSONObject, JSONValue } from '@difizen/libro-common'; +import type { JSONObject, JSONValue, IOutput, OutputType } from '@difizen/libro-common'; +import type { CellView, LibroExecutableCellView } from '@difizen/libro-core'; +import { ExecutableCellView } from '@difizen/libro-core'; import { LibroContextKey } from '@difizen/libro-core'; import type { KernelMessage } from '@difizen/libro-kernel'; -import { inject, transient, ViewOption, view, BaseView, prop } from '@difizen/mana-app'; -import type { ViewComponent } from '@difizen/mana-app'; +import { + inject, + transient, + ViewOption, + view, + BaseView, + prop, + watch, +} from '@difizen/mana-app'; +import type { ViewComponent, Disposable } from '@difizen/mana-app'; import { forwardRef } from 'react'; -import type { IWidgetViewProps } from './protocal.js'; +import { LibroJupyterModel } from '../libro-jupyter-model.js'; + +import { defaultWidgetState } from './protocol.js'; import type { Dict, IWidgets, IWidgetView, IClassicComm, ICallbacks, -} from './protocal.js'; + IWidgetViewProps, + WidgetState, +} from './protocol.js'; import { LibroWidgetManager } from './widget-manager.js'; export const LibroWidgetComponent = forwardRef( @@ -27,12 +41,26 @@ export class WidgetView extends BaseView implements IWidgetView { override view: ViewComponent = LibroWidgetComponent; libroContextKey: LibroContextKey; widgetsId: string; + protected _msgHook: (msg: KernelMessage.IIOPubMessage) => boolean; + @inject(LibroWidgetManager) libroWidgetManager: LibroWidgetManager; @prop() - state: JSONObject = {}; + state: JSONObject & WidgetState = defaultWidgetState; + + cell?: LibroExecutableCellView; + + get outputs() { + if (this.cell) { + return this.cell.outputArea; + } + return undefined; + } disableCommandMode = true; + + toDisposeOnMsgChanged?: Disposable; + constructor( @inject(ViewOption) props: IWidgetViewProps, @inject(LibroContextKey) libroContextKey: LibroContextKey, @@ -48,6 +76,11 @@ export class WidgetView extends BaseView implements IWidgetView { this.view_module_version = attributes._view_module_version; this.view_count = attributes._view_count; + this._msgHook = (msg: KernelMessage.IIOPubMessage): boolean => { + this.addFromMessage(msg); + return false; + }; + // Attributes should be initialized here, since user initialization may depend on it const comm = props.options.comm; if (comm) { @@ -55,20 +88,84 @@ export class WidgetView extends BaseView implements IWidgetView { this.comm = comm; // Hook comm messages up to model. - comm.on_close(this.handleCommClosed.bind(this)); - comm.on_msg(this.handleCommMsg.bind(this)); + comm.onClose(this.handleCommClosed.bind(this)); + comm.onMsg(this.handleCommMsg.bind(this)); } else { this.isCommClosed = false; } this.model_id = props.options.model_id; this.state_change = Promise.resolve(); - - this.trySetValue(attributes, 'tabbable'); - this.trySetValue(attributes, 'tooltip'); + this.setState(attributes); this.libroContextKey = libroContextKey; } + setCell(cell: CellView) { + if (ExecutableCellView.is(cell)) { + this.cell = cell as LibroExecutableCellView; + if (this.cell) { + this.cell.parentReady + .then(() => { + const notebookModel = this.cell?.parent.model; + if (notebookModel instanceof LibroJupyterModel) { + watch(notebookModel, 'kernelConnection', this.handleKernelChanged); + } + return; + }) + .catch(console.error); + } + } + } + + /** + * Register a new kernel + */ + handleKernelChanged = (): void => { + this.setState({ msg_id: undefined }); + }; + + /** + * Reset the message id. + */ + resetMsgId(): void { + this.toDisposeOnMsgChanged?.dispose(); + const notebookModel = this.cell?.parent?.model; + + if (notebookModel instanceof LibroJupyterModel) { + const kernel = notebookModel.kernelConnection; + if (kernel && this.state['msg_id']) { + this.toDisposeOnMsgChanged = kernel.registerMessageHook( + this.state['msg_id'], + this._msgHook, + ); + } + } + } + + addFromMessage(msg: KernelMessage.IIOPubMessage) { + const msgType = msg.header.msg_type; + switch (msgType) { + case 'execute_result': + case 'display_data': + case 'stream': + case 'error': { + const model = msg.content as IOutput; + model.output_type = msgType as OutputType; + this.outputs?.add(model); + break; + } + case 'clear_output': + this.clearOutput((msg as KernelMessage.IClearOutputMsg).content.wait); + break; + default: + break; + } + } + + clearOutput(wait = false): void { + this.outputs?.clear(wait); + } + override onViewMount() { this.widgets = this.libroWidgetManager.getWidgets(this.widgetsId)!; @@ -86,12 +183,6 @@ export class WidgetView extends BaseView implements IWidgetView { } } - protected trySetValue(attributes: any, propKey: string) { - if (propKey in attributes && attributes[propKey] !== undefined) { - this.state[propKey] = attributes[propKey]; - } - } - /** * Handle incoming comm msg. */ @@ -101,7 +192,7 @@ export class WidgetView extends BaseView implements IWidgetView { switch (method) { case 'update': case 'echo_update': - this.set_state(data.state); + this.setState(data.state); } return Promise.resolve(); } @@ -114,9 +205,13 @@ export class WidgetView extends BaseView implements IWidgetView { * * This function is meant for internal use only. Values set here will not be propagated on a sync. */ - set_state(state: Dict): void { + setState(state: Dict): void { for (const key in state) { + const oldMsgId = this.state['msg_id']; this.state[key] = state[key]; + if (key === 'msg_id' && oldMsgId !== state['msg_id']) { + this.resetMsgId(); + } } } diff --git a/packages/libro-kernel/src/kernel/future.ts b/packages/libro-kernel/src/kernel/future.ts index 4e72b1a9..e78e9571 100644 --- a/packages/libro-kernel/src/kernel/future.ts +++ b/packages/libro-kernel/src/kernel/future.ts @@ -1,4 +1,4 @@ -import type { Disposable } from '@difizen/mana-app'; +import { Disposable } from '@difizen/mana-app'; import { Deferred } from '@difizen/mana-app'; import type { @@ -280,11 +280,14 @@ export abstract class KernelFutureHandler< */ registerMessageHook( hook: (msg: KernelMessage.IIOPubMessage) => boolean | PromiseLike, - ): void { + ): Disposable { if (this.disposed) { throw new Error('Kernel future is disposed'); } this._hooks.add(hook); + return Disposable.create(() => { + this.removeMessageHook(hook); + }); } /** diff --git a/packages/libro-kernel/src/kernel/kernel-connection.ts b/packages/libro-kernel/src/kernel/kernel-connection.ts index 4cc51837..475998ef 100644 --- a/packages/libro-kernel/src/kernel/kernel-connection.ts +++ b/packages/libro-kernel/src/kernel/kernel-connection.ts @@ -1,6 +1,7 @@ import type { JSONObject } from '@difizen/libro-common'; import { deepCopy, URL } from '@difizen/libro-common'; -import type { Disposable, Event as ManaEvent } from '@difizen/mana-app'; +import type { Event as ManaEvent } from '@difizen/mana-app'; +import { Disposable } from '@difizen/mana-app'; import { prop } from '@difizen/mana-app'; import { Deferred, Emitter } from '@difizen/mana-app'; import { inject, transient } from '@difizen/mana-app'; @@ -1070,11 +1071,12 @@ export class KernelConnection implements IKernelConnection { registerMessageHook( msgId: string, hook: (msg: KernelMessage.IIOPubMessage) => boolean | PromiseLike, - ): void { + ): Disposable { const future = this._futures?.get(msgId); if (future) { - future.registerMessageHook(hook); + return future.registerMessageHook(hook); } + return Disposable.NONE; } /** @@ -1324,7 +1326,6 @@ export class KernelConnection implements IKernelConnection { } const onMsg = comm.onMsg; if (onMsg) { - // tslint:disable-next-line:await-promise await onMsg(msg); } } diff --git a/packages/libro-kernel/src/kernel/libro-kernel-protocol.ts b/packages/libro-kernel/src/kernel/libro-kernel-protocol.ts index 8a51cb22..6536376e 100644 --- a/packages/libro-kernel/src/kernel/libro-kernel-protocol.ts +++ b/packages/libro-kernel/src/kernel/libro-kernel-protocol.ts @@ -739,7 +739,7 @@ export interface IKernelConnection extends ObservableDisposable { registerMessageHook: ( msgId: string, hook: (msg: KernelMessage.IIOPubMessage) => boolean | PromiseLike, - ) => void; + ) => Disposable; /** * Remove an IOPub message hook. diff --git a/packages/libro-lab/package.json b/packages/libro-lab/package.json index 54fe6c98..0addee81 100644 --- a/packages/libro-lab/package.json +++ b/packages/libro-lab/package.json @@ -55,6 +55,7 @@ "@difizen/libro-toc": "^0.1.33", "@difizen/libro-cofine-editor-core": "^0.1.33", "@difizen/libro-language-client": "^0.1.33", + "@difizen/libro-widget": "^0.1.31", "@difizen/mana-app": "latest", "@difizen/mana-common": "latest", "@difizen/mana-react": "latest", diff --git a/packages/libro-lab/src/module.tsx b/packages/libro-lab/src/module.tsx index 1d86455d..937611a4 100644 --- a/packages/libro-lab/src/module.tsx +++ b/packages/libro-lab/src/module.tsx @@ -1,6 +1,7 @@ import { FileView, LibroJupyterModule } from '@difizen/libro-jupyter'; import { LibroPromptCellModule } from '@difizen/libro-prompt-cell'; import { TerminalModule } from '@difizen/libro-terminal'; +import { CommonWidgetsModule } from '@difizen/libro-widget'; import { ManaModule, createSlotPreference, @@ -98,6 +99,7 @@ export const LibroLabModule = ManaModule.create() ) .dependOn( LibroJupyterModule, + CommonWidgetsModule, LibroLabLayoutModule, LibroLabHeaderMenuModule, LibroLabTocModule, diff --git a/packages/libro-output/src/display-data-output/display-data-output-model.tsx b/packages/libro-output/src/display-data-output/display-data-output-model.tsx index e3d762c3..0cd01e6d 100644 --- a/packages/libro-output/src/display-data-output/display-data-output-model.tsx +++ b/packages/libro-output/src/display-data-output/display-data-output-model.tsx @@ -2,7 +2,7 @@ import type { JSONObject } from '@difizen/libro-common'; import { LibroOutputView } from '@difizen/libro-core'; import type { BaseOutputView, IOutputOptions } from '@difizen/libro-core'; import { RenderMimeRegistry } from '@difizen/libro-rendermime'; -import type { IRenderMimeRegistry } from '@difizen/libro-rendermime'; +import type { IRenderMimeRegistry, IRendererFactory } from '@difizen/libro-rendermime'; import { getOrigin, useInject, @@ -19,16 +19,11 @@ import '../index.less'; const DisplayDataOutputModelRender = forwardRef( function DisplayDataOutputModelRender(_props, ref) { const output = useInject(ViewInstance); - const defaultRenderMime = useInject(RenderMimeRegistry); - const model = getOrigin(output); - const defaultRenderMimeType = defaultRenderMime.preferredMimeType(model); + const factory = model.getRenderFactory(); let children = null; - if (defaultRenderMimeType) { - const OutputRender = defaultRenderMime.createRenderer( - defaultRenderMimeType, - model, - ); + if (factory) { + const OutputRender = factory.render; children = ; } return ( @@ -41,6 +36,8 @@ const DisplayDataOutputModelRender = forwardRef( @transient() @view('libro-display-data-output-model') export class DisplayDataOutputModel extends LibroOutputView implements BaseOutputView { + @inject(RenderMimeRegistry) renderMimeRegistry: IRenderMimeRegistry; + renderFactory?: IRendererFactory; constructor(@inject(ViewOption) options: IOutputOptions) { super(options); const { data, metadata } = getBundleOptions(options.output); @@ -48,6 +45,17 @@ export class DisplayDataOutputModel extends LibroOutputView implements BaseOutpu this.data = data as JSONObject; this.metadata = metadata; } + + getRenderFactory() { + const renderMimeType = this.renderMimeRegistry.preferredMimeType(this); + if (renderMimeType) { + const renderMime = this.renderMimeRegistry.createRenderer(renderMimeType, this); + this.renderFactory = getOrigin(renderMime); + this.allowClear = renderMime.allowClear === false ? false : true; + return renderMime; + } + return undefined; + } override view = DisplayDataOutputModelRender; override toJSON() { if (this.raw.execution_count !== undefined) { @@ -64,4 +72,11 @@ export class DisplayDataOutputModel extends LibroOutputView implements BaseOutpu metadata: this.raw.metadata, }; } + + override dispose(force?: boolean): void { + if (!force && this.allowClear === false) { + return; + } + super.dispose(); + } } diff --git a/packages/libro-output/src/stream-output/stream-output-model.tsx b/packages/libro-output/src/stream-output/stream-output-model.tsx index 36fa5f06..3a74c0b9 100644 --- a/packages/libro-output/src/stream-output/stream-output-model.tsx +++ b/packages/libro-output/src/stream-output/stream-output-model.tsx @@ -2,7 +2,7 @@ import type { JSONObject } from '@difizen/libro-common'; import { LibroOutputView } from '@difizen/libro-core'; import type { BaseOutputView, IOutputOptions } from '@difizen/libro-core'; import { RenderMimeRegistry } from '@difizen/libro-rendermime'; -import type { IRenderMimeRegistry } from '@difizen/libro-rendermime'; +import type { IRenderMimeRegistry, IRendererFactory } from '@difizen/libro-rendermime'; import { inject, transient } from '@difizen/mana-app'; import { getOrigin, @@ -21,13 +21,9 @@ const StreamOutputModelRender = forwardRef( function StreamOutputModelRender(_props, ref) { const output = useInject(ViewInstance); const model = getOrigin(output); - const defaultRenderMime = useInject(RenderMimeRegistry); - const defaultRenderMimeType = defaultRenderMime.preferredMimeType(model); - if (defaultRenderMimeType) { - const OutputRender = defaultRenderMime.createRenderer( - defaultRenderMimeType, - model, - ); + const factory = model.getRenderFactory(); + if (factory) { + const OutputRender = factory.render; const children = ; return (
@@ -42,6 +38,9 @@ const StreamOutputModelRender = forwardRef( @transient() @view('libro-stream-output-model') export class StreamOutputModel extends LibroOutputView implements BaseOutputView { + @inject(RenderMimeRegistry) renderMimeRegistry: IRenderMimeRegistry; + renderFactory?: IRendererFactory; + constructor(@inject(ViewOption) options: IOutputOptions) { super(options); const { data, metadata } = getBundleOptions(options.output); @@ -49,6 +48,15 @@ export class StreamOutputModel extends LibroOutputView implements BaseOutputView this.data = data as JSONObject; this.metadata = metadata; } + getRenderFactory() { + const renderMimeType = this.renderMimeRegistry.preferredMimeType(this); + if (renderMimeType) { + const renderMime = this.renderMimeRegistry.createRenderer(renderMimeType, this); + this.renderFactory = getOrigin(renderMime); + return renderMime; + } + return undefined; + } override view = StreamOutputModelRender; override toJSON() { return { diff --git a/packages/libro-rendermime/src/rendermime-protocol.ts b/packages/libro-rendermime/src/rendermime-protocol.ts index 8917babc..d2e9cb38 100644 --- a/packages/libro-rendermime/src/rendermime-protocol.ts +++ b/packages/libro-rendermime/src/rendermime-protocol.ts @@ -6,7 +6,7 @@ import { Syringe } from '@difizen/mana-app'; export const DefaultRenderMimeRegistry = Symbol('RenderMimeRegistry'); export const IRenderMimeRegistryOptions = Symbol('IRenderMimeRegistryOptions'); export const RenderMimeContribution = Syringe.defineToken('RenderMimeTypeContribution'); -export interface RenderMimeContribution { +export interface RenderMimeContribution extends IRendererFactory { canHandle: (model: BaseOutputView) => number; safe: boolean; renderType: string; @@ -17,6 +17,7 @@ export interface RenderMimeContribution { * The interface for a renderer factory. */ export interface IRendererFactory { + allowClear?: boolean; /** * Whether the factory is a "safe" factory. * @@ -198,7 +199,7 @@ export interface IRenderMimeRegistry { mimeType: string, model: BaseOutputView, // model: BaseOutputModel, // host: HTMLElement, - ) => React.FC<{ model: BaseOutputView }>; + ) => IRendererFactory; // /** // * Create a new mime model. This is a convenience method. // * diff --git a/packages/libro-rendermime/src/rendermime-registry.ts b/packages/libro-rendermime/src/rendermime-registry.ts index f3d6dce5..a3bdc231 100644 --- a/packages/libro-rendermime/src/rendermime-registry.ts +++ b/packages/libro-rendermime/src/rendermime-registry.ts @@ -184,17 +184,16 @@ export class RenderMimeRegistry implements IRenderMimeRegistry { mimeType: string, model: BaseOutputView, // model: BaseOutputModel, // host: HTMLElement, - ): React.FC<{ model: BaseOutputView }> { + ): IRendererFactory { const renderMimes = this.getSortedRenderMimes(model); for (const renderMime of renderMimes) { for (const mt of renderMime.mimeTypes) { if (mimeType === mt) { - const OutputRender = renderMime.render; this.renderMimeEmitter.fire({ renderType: renderMime.renderType, mimeType, }); - return OutputRender; + return renderMime; } } } @@ -203,13 +202,13 @@ export class RenderMimeRegistry implements IRenderMimeRegistry { if (!(mimeType in this._factories)) { throw new Error(`No factory for mime type: '${mimeType}'`); } - const OutputRender = this._factories[mimeType].render; + const renderMime = this._factories[mimeType]; this.renderMimeEmitter.fire({ renderType: this._factories[mimeType].renderType, mimeType, }); // Invoke the best factory for the given mime type. - return OutputRender; + return renderMime; } /** diff --git a/packages/libro-widget/package.json b/packages/libro-widget/package.json index 6b840343..b6a0ea69 100644 --- a/packages/libro-widget/package.json +++ b/packages/libro-widget/package.json @@ -48,6 +48,7 @@ "@difizen/libro-common": "^0.1.33", "@difizen/libro-kernel": "^0.1.33", "@difizen/libro-rendermime": "^0.1.33", + "@difizen/libro-jupyter": "^0.1.33", "@difizen/mana-app": "latest" }, "peerDependencies": { diff --git a/packages/libro-widget/src/base/index.ts b/packages/libro-widget/src/base/index.ts deleted file mode 100644 index 38276dbd..00000000 --- a/packages/libro-widget/src/base/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './libro-widgets.js'; -export * from './widget-view.js'; -export * from './protocal.js'; -export * from './widget-manager.js'; -export * from './comm.js'; -export * from './widget-view-contribution.js'; -export * from './module.js'; diff --git a/packages/libro-widget/src/components/index.ts b/packages/libro-widget/src/components/index.ts deleted file mode 100644 index 7102c9f7..00000000 --- a/packages/libro-widget/src/components/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './progressBar.js'; - -export * from './progressCircle.js'; diff --git a/packages/libro-widget/src/components/progressCircle.tsx b/packages/libro-widget/src/components/progressCircle.tsx deleted file mode 100644 index 86b45b30..00000000 --- a/packages/libro-widget/src/components/progressCircle.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Progress } from 'antd'; -/** - * Props for the ProgressBar. - */ -export interface IProgressCircleProps { - /** - * The current progress percentage, from 0 to 100 - */ - percent: number; -} - -export function ProgressCircle(props: IProgressCircleProps) { - return ( - <> - ; - - ); -} diff --git a/packages/libro-widget/src/index.spec.ts b/packages/libro-widget/src/index.spec.ts index b78af1c7..cabad93e 100644 --- a/packages/libro-widget/src/index.spec.ts +++ b/packages/libro-widget/src/index.spec.ts @@ -1,11 +1,10 @@ import assert from 'assert'; -import { WidgetView, LibroWidgetManager } from './index.js'; +// import { SliderWidget } from './index.js'; import 'reflect-metadata'; describe('libro-widget', () => { it('#import', () => { - assert(LibroWidgetManager); - assert(WidgetView); + assert(true); }); }); diff --git a/packages/libro-widget/src/index.ts b/packages/libro-widget/src/index.ts index c9114be5..0012a049 100644 --- a/packages/libro-widget/src/index.ts +++ b/packages/libro-widget/src/index.ts @@ -1,4 +1,3 @@ -export * from './components/index.js'; -export * from './base/index.js'; -export * from './widgets/index.js'; export * from './module.js'; +export * from './slider/index.js'; +export * from './text/index.js'; diff --git a/packages/libro-widget/src/module.ts b/packages/libro-widget/src/module.ts index db8eb138..26bd1bf0 100644 --- a/packages/libro-widget/src/module.ts +++ b/packages/libro-widget/src/module.ts @@ -1,9 +1,15 @@ +import { WidgetModule } from '@difizen/libro-jupyter'; import { ManaModule } from '@difizen/mana-app'; -import { BaseWidgetModule } from './base/index.js'; -import { CommonWidgetsModule } from './widgets/index.js'; +import { SilderWidgetContribution, SliderWidget } from './slider/index.js'; +import { TextModelContribution, TextWidget } from './text/index.js'; -export const WidgetModule = ManaModule.create().dependOn( - BaseWidgetModule, - CommonWidgetsModule, -); +export const CommonWidgetsModule = ManaModule.create() + .register( + SliderWidget, + SilderWidgetContribution, + + TextWidget, + TextModelContribution, + ) + .dependOn(WidgetModule); diff --git a/packages/libro-widget/src/widgets/slider/contribution.ts b/packages/libro-widget/src/slider/contribution.ts similarity index 84% rename from packages/libro-widget/src/widgets/slider/contribution.ts rename to packages/libro-widget/src/slider/contribution.ts index 104fc620..64bb00c8 100644 --- a/packages/libro-widget/src/widgets/slider/contribution.ts +++ b/packages/libro-widget/src/slider/contribution.ts @@ -1,6 +1,7 @@ +import type { IWidgetViewProps } from '@difizen/libro-jupyter'; +import { WidgetViewContribution } from '@difizen/libro-jupyter'; import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from '@difizen/libro-widget'; -import { WidgetViewContribution } from '@difizen/libro-widget'; + import { SliderWidget } from './view.js'; @singleton({ contrib: WidgetViewContribution }) diff --git a/packages/libro-widget/src/widgets/slider/index.less b/packages/libro-widget/src/slider/index.less similarity index 100% rename from packages/libro-widget/src/widgets/slider/index.less rename to packages/libro-widget/src/slider/index.less diff --git a/packages/libro-widget/src/widgets/slider/index.ts b/packages/libro-widget/src/slider/index.ts similarity index 100% rename from packages/libro-widget/src/widgets/slider/index.ts rename to packages/libro-widget/src/slider/index.ts diff --git a/packages/libro-widget/src/widgets/slider/view.tsx b/packages/libro-widget/src/slider/view.tsx similarity index 61% rename from packages/libro-widget/src/widgets/slider/view.tsx rename to packages/libro-widget/src/slider/view.tsx index d9f71cf1..fb7dd106 100644 --- a/packages/libro-widget/src/widgets/slider/view.tsx +++ b/packages/libro-widget/src/slider/view.tsx @@ -1,7 +1,9 @@ import type { JSONObject } from '@difizen/libro-common'; import { LibroContextKey } from '@difizen/libro-core'; -import type { IWidgetViewProps } from '@difizen/libro-widget'; -import { WidgetView } from '@difizen/libro-widget'; +import type { IWidgetViewProps } from '@difizen/libro-jupyter'; +import type { OrientableState, WidgetState } from '@difizen/libro-jupyter'; +import { WidgetView } from '@difizen/libro-jupyter'; +import { defaultWidgetState } from '@difizen/libro-jupyter'; import { view, transient, @@ -14,8 +16,6 @@ import { import { Slider } from 'antd'; import { forwardRef } from 'react'; -import type { OrientableState, WidgetState } from '../protocol.js'; -import { defaultWidgetState } from '../protocol.js'; import './index.less'; export const LibroWidgetIntSliderComponent = forwardRef( @@ -78,35 +78,9 @@ export class SliderWidget extends WidgetView { const attributes = props.attributes; this.state.max = attributes.max; this.state.min = attributes.min; - this.trySetValue(attributes, 'behavior'); - this.trySetValue(attributes, 'continuous_update'); - this.trySetValue(attributes, 'description'); - this.trySetValue(attributes, 'description_allow_html'); - this.trySetValue(attributes, 'disabled'); - this.trySetValue(attributes, 'layout'); - this.trySetValue(attributes, 'max'); - this.trySetValue(attributes, 'min'); - this.trySetValue(attributes, 'orientation'); - this.trySetValue(attributes, 'readout'); - this.trySetValue(attributes, 'readout_format'); - this.trySetValue(attributes, 'step'); - this.trySetValue(attributes, 'style'); - this.trySetValue(attributes, 'value'); + this.setState(attributes); } - // override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise { - // const data = msg.content.data as any; - // const method = data.method; - // switch (method) { - // case 'update': - // case 'echo_update': - // if (data.state.value) { - // this.value = data.state.value; - // } - // } - // return Promise.resolve(); - // } - handleChange = (value: number) => { const data = { buffer_paths: [], diff --git a/packages/libro-widget/src/widgets/text/contribution.ts b/packages/libro-widget/src/text/contribution.ts similarity index 80% rename from packages/libro-widget/src/widgets/text/contribution.ts rename to packages/libro-widget/src/text/contribution.ts index 3d2188bd..4623886a 100644 --- a/packages/libro-widget/src/widgets/text/contribution.ts +++ b/packages/libro-widget/src/text/contribution.ts @@ -1,8 +1,7 @@ +import type { IWidgetViewProps } from '@difizen/libro-jupyter'; +import { WidgetViewContribution } from '@difizen/libro-jupyter'; import { ViewManager, inject, singleton } from '@difizen/mana-app'; -import type { IWidgetViewProps } from '../../base/protocal.js'; -import { WidgetViewContribution } from '../../base/protocal.js'; - import { TextWidget } from './view.js'; @singleton({ contrib: WidgetViewContribution }) diff --git a/packages/libro-widget/src/widgets/text/index.ts b/packages/libro-widget/src/text/index.ts similarity index 100% rename from packages/libro-widget/src/widgets/text/index.ts rename to packages/libro-widget/src/text/index.ts diff --git a/packages/libro-widget/src/widgets/text/view.tsx b/packages/libro-widget/src/text/view.tsx similarity index 94% rename from packages/libro-widget/src/widgets/text/view.tsx rename to packages/libro-widget/src/text/view.tsx index b9ea1559..aee70e0f 100644 --- a/packages/libro-widget/src/widgets/text/view.tsx +++ b/packages/libro-widget/src/text/view.tsx @@ -1,4 +1,6 @@ import { LibroContextKey } from '@difizen/libro-core'; +import type { IWidgetViewProps } from '@difizen/libro-jupyter'; +import { WidgetView } from '@difizen/libro-jupyter'; import { view, ViewOption, @@ -11,9 +13,6 @@ import { import { Input } from 'antd'; import { forwardRef } from 'react'; -import type { IWidgetViewProps } from '../../base/protocal.js'; -import { WidgetView } from '../../base/widget-view.js'; - export const TextWidgetComponent = forwardRef( function TextWidgetComponent(_props, ref) { const widgetView = useInject(ViewInstance); diff --git a/packages/libro-widget/src/widgets/index.less b/packages/libro-widget/src/widgets/index.less deleted file mode 100644 index 111f11dc..00000000 --- a/packages/libro-widget/src/widgets/index.less +++ /dev/null @@ -1,3 +0,0 @@ -.libro-input-widget { - display: flex; -} diff --git a/packages/libro-widget/src/widgets/index.ts b/packages/libro-widget/src/widgets/index.ts deleted file mode 100644 index 53e0215a..00000000 --- a/packages/libro-widget/src/widgets/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './instance-progress/index.js'; -export * from './progress/index.js'; -export * from './text/index.js'; -export * from './box/index.js'; -export * from './module.js'; diff --git a/packages/libro-widget/src/widgets/module.ts b/packages/libro-widget/src/widgets/module.ts deleted file mode 100644 index 90bb8b7f..00000000 --- a/packages/libro-widget/src/widgets/module.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ManaModule } from '@difizen/mana-app'; - -import { BaseWidgetModule } from '../base/index.js'; - -import { VBoxWidget, VBoxWidgetContribution } from './box/index.js'; -import { - InstancesProgressWidget, - InstancesProgressWidgetViewContribution, -} from './instance-progress/index.js'; -import { ProgressWidget, ProgressWidgetViewContribution } from './progress/index.js'; -import { SilderWidgetContribution, SliderWidget } from './slider/index.js'; -import { TextModelContribution, TextWidget } from './text/index.js'; - -export const CommonWidgetsModule = ManaModule.create() - .register( - VBoxWidget, - VBoxWidgetContribution, - - SliderWidget, - SilderWidgetContribution, - - ProgressWidget, - ProgressWidgetViewContribution, - - InstancesProgressWidget, - InstancesProgressWidgetViewContribution, - - TextWidget, - TextModelContribution, - ) - .dependOn(BaseWidgetModule); diff --git a/packages/libro-widget/src/widgets/protocol.ts b/packages/libro-widget/src/widgets/protocol.ts deleted file mode 100644 index 949719f5..00000000 --- a/packages/libro-widget/src/widgets/protocol.ts +++ /dev/null @@ -1,25 +0,0 @@ -export interface WidgetState { - behavior?: string; - continuous_update: boolean; - description: string; - description_allow_html: boolean; - disabled: boolean; - layout?: string; - readout: boolean; - readout_format: string; - style?: string; - [key: string]: any; -} - -export const defaultWidgetState: WidgetState = { - continuous_update: false, - description_allow_html: false, - description: '', - disabled: false, - readout: true, - readout_format: 'd', -}; - -export interface OrientableState { - orientation: 'horizontal' | 'vertical'; -}