From 9bd316c1b9f55aef55803b7f350f8a25a75c8026 Mon Sep 17 00:00:00 2001 From: martinRenou Date: Mon, 4 May 2026 12:06:44 +0200 Subject: [PATCH 1/3] Fix slider implementation --- .../simple-yjs-widget/notebooks/simple.ipynb | 86 ++----------------- examples/simple-yjs-widget/src/index.ts | 29 +++---- 2 files changed, 21 insertions(+), 94 deletions(-) diff --git a/examples/simple-yjs-widget/notebooks/simple.ipynb b/examples/simple-yjs-widget/notebooks/simple.ipynb index a588359..6fe1d30 100644 --- a/examples/simple-yjs-widget/notebooks/simple.ipynb +++ b/examples/simple-yjs-widget/notebooks/simple.ipynb @@ -7,64 +7,15 @@ "metadata": {}, "outputs": [], "source": [ + "from ypywidgets import Reactive, Widget\n", "from ypywidgets.comm import CommWidget\n", - "from pycrdt import Map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6d9538c9-4858-4c9d-b347-18965660115d", - "metadata": {}, - "outputs": [], - "source": [ - "class MySlider(CommWidget):\n", - " def __init__(self, value=50, min=0, max=100, step=1):\n", - " super().__init__(\n", - " comm_metadata={\n", - " \"ymodel_name\": \"MySlider\",\n", - " \"create_ydoc\": True,\n", - " }\n", - " )\n", - "\n", - " self.ydoc[\"state\"] = self._state = Map()\n", - "\n", - " self.min = min\n", - " self.max = max\n", - " self.step = step\n", - " self.value = value\n", - "\n", - " @property\n", - " def value(self):\n", - " return self._state['value']\n", - "\n", - " @value.setter\n", - " def value(self, v):\n", - " self._state['value'] = v\n", - "\n", - " @property\n", - " def min(self):\n", - " return self._state['min']\n", - "\n", - " @min.setter\n", - " def min(self, v):\n", - " self._state['min'] = v\n", - "\n", - " @property\n", - " def max(self):\n", - " return self._state['max']\n", - "\n", - " @max.setter\n", - " def max(self, v):\n", - " self._state['max'] = v\n", "\n", - " @property\n", - " def step(self):\n", - " return self._state['step']\n", "\n", - " @step.setter\n", - " def step(self, v):\n", - " self._state['step'] = v" + "class MySlider(CommWidget):\n", + " value = Reactive[int](50)\n", + " min = Reactive[int](0)\n", + " max = Reactive[int](100)\n", + " step = Reactive[int](1)" ] }, { @@ -121,32 +72,11 @@ { "cell_type": "code", "execution_count": null, - "id": "55896ccc-a128-4abf-a34d-4a50272946dd", - "metadata": {}, - "outputs": [], - "source": [ - "w2 = MySlider(max=200, step=2, value=152)\n", - "w2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c54528b0-6eae-4601-b6f6-ab2f31630815", - "metadata": {}, - "outputs": [], - "source": [ - "w2.value" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "23380f74-83ea-4409-a990-a0b8958dde2b", + "id": "dc6f7a60-2426-4c04-8e4e-ceb0ab728c3a", "metadata": {}, "outputs": [], "source": [ - "w2.value" + "w.max = 200" ] } ], diff --git a/examples/simple-yjs-widget/src/index.ts b/examples/simple-yjs-widget/src/index.ts index e9df237..297e388 100644 --- a/examples/simple-yjs-widget/src/index.ts +++ b/examples/simple-yjs-widget/src/index.ts @@ -1,49 +1,46 @@ import { IJupyterYModel, JupyterYModel, - IJupyterYWidgetManager + IJupyterYWidgetManager, + IJupyterYDoc } from 'yjs-widgets'; -import * as Y from 'yjs'; - import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; +import { MapChange } from '@jupyter/ydoc'; class MySlider { constructor(yModel: IJupyterYModel, node: HTMLElement) { this.yModel = yModel; this.node = node; - this.state = this.yModel.sharedModel.ydoc.getMap('state'); - - this.state.observe(this._stateChanged.bind(this)); - this.slider = document.createElement('input'); this.slider.setAttribute('type', 'range'); - this.slider.min = this.state.get('min'); - this.slider.max = this.state.get('max'); - this.slider.value = this.state.get('value'); - this.slider.step = this.state.get('step'); + this.yModel.sharedModel.attrsChanged.connect(this._stateChanged.bind(this)); + + this.slider.min = this.yModel.sharedModel.getAttr('min'); + this.slider.max = this.yModel.sharedModel.getAttr('max'); + this.slider.value = this.yModel.sharedModel.getAttr('value'); + this.slider.step = this.yModel.sharedModel.getAttr('step'); this.slider.onchange = this._sliderChanged.bind(this); node.appendChild(this.slider); } - _stateChanged(change: Y.YMapEvent): void { - for (const key of change.keysChanged) { - this.slider[key] = change.target.toJSON()[key]; + _stateChanged(_: IJupyterYDoc, change: MapChange): void { + for (const key of change.keys()) { + this.slider[key] = this.yModel.sharedModel.getAttr(key); } } _sliderChanged(): void { - this.state.set('value', parseInt(this.slider.value ?? '50')); + this.yModel.sharedModel.setAttr('value', parseInt(this.slider.value ?? '50')); } - state: Y.Map; yModel: IJupyterYModel; node: HTMLElement; slider: HTMLInputElement; From 2db773635e58ffb06766e81ca0da2b86dc0f330a Mon Sep 17 00:00:00 2001 From: martinRenou Date: Mon, 4 May 2026 14:33:03 +0200 Subject: [PATCH 2/3] Update examples/simple-yjs-widget/notebooks/simple.ipynb Co-authored-by: David Brochart --- examples/simple-yjs-widget/notebooks/simple.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simple-yjs-widget/notebooks/simple.ipynb b/examples/simple-yjs-widget/notebooks/simple.ipynb index 6fe1d30..88bd1a8 100644 --- a/examples/simple-yjs-widget/notebooks/simple.ipynb +++ b/examples/simple-yjs-widget/notebooks/simple.ipynb @@ -7,7 +7,7 @@ "metadata": {}, "outputs": [], "source": [ - "from ypywidgets import Reactive, Widget\n", + "from ypywidgets import Reactive\n", "from ypywidgets.comm import CommWidget\n", "\n", "\n", From 36e2c283f45aff87230b758685e90dcbf40443ec Mon Sep 17 00:00:00 2001 From: martinRenou Date: Mon, 4 May 2026 14:39:09 +0200 Subject: [PATCH 3/3] Handle review comment --- examples/simple-yjs-widget/notebooks/simple.ipynb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/simple-yjs-widget/notebooks/simple.ipynb b/examples/simple-yjs-widget/notebooks/simple.ipynb index 88bd1a8..2f66e2a 100644 --- a/examples/simple-yjs-widget/notebooks/simple.ipynb +++ b/examples/simple-yjs-widget/notebooks/simple.ipynb @@ -15,7 +15,15 @@ " value = Reactive[int](50)\n", " min = Reactive[int](0)\n", " max = Reactive[int](100)\n", - " step = Reactive[int](1)" + " step = Reactive[int](1)\n", + "\n", + " @value.watch\n", + " def _watch_value(self, old, new):\n", + " # Watch the value of the slider, and print the new value change\n", + " #\n", + " # From JupyterLab, show the log console with info level to see the print\n", + " # \"Ctrl + Shift + C\" then type \"Log Console\" to expand that panel\n", + " print(f\"value changed: '{old}'->'{new}'\")" ] }, {