Skip to content

Commit 836004f

Browse files
authored
Merge pull request #25 from QuantStack/fix_example_build
Fix example build and make it a slider
2 parents 4ca41c1 + 157de17 commit 836004f

5 files changed

Lines changed: 315 additions & 64 deletions

File tree

.gitignore

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ ui-tests/test-results/
120120
ui-tests/playwright-report/
121121

122122
examples/*.ipynb
123-
# Hatchling
123+
# Hatchling
124124
yjs_widgets/_version.py
125125

126-
.yarn/
126+
.yarn/
127+
128+
# Generated code and extension
129+
examples/simple-yjs-widget/simple_yjs_widget/_version.py
130+
examples/simple-yjs-widget/simple_yjs_widget/labextension/

examples/simple-yjs-widget/notebooks/simple.ipynb

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,64 @@
77
"metadata": {},
88
"outputs": [],
99
"source": [
10-
"from ypywidgets import Widget, reactive"
10+
"from ypywidgets.comm import CommWidget\n",
11+
"from pycrdt import Map"
1112
]
1213
},
1314
{
1415
"cell_type": "code",
1516
"execution_count": null,
16-
"id": "18d1ca71-1943-4902-b642-06e3d812e23f",
17+
"id": "6d9538c9-4858-4c9d-b347-18965660115d",
1718
"metadata": {},
1819
"outputs": [],
1920
"source": [
20-
"class MyWidget(Widget):\n",
21-
" foo = reactive(\"\")\n",
22-
" bar = reactive(\"\")"
21+
"class MySlider(CommWidget):\n",
22+
" def __init__(self, value=50, min=0, max=100, step=1):\n",
23+
" super().__init__(\n",
24+
" comm_metadata={\n",
25+
" \"ymodel_name\": \"MySlider\",\n",
26+
" \"create_ydoc\": True,\n",
27+
" }\n",
28+
" )\n",
29+
"\n",
30+
" self.ydoc[\"state\"] = self._state = Map()\n",
31+
"\n",
32+
" self.min = min\n",
33+
" self.max = max\n",
34+
" self.step = step\n",
35+
" self.value = value\n",
36+
"\n",
37+
" @property\n",
38+
" def value(self):\n",
39+
" return self._state['value']\n",
40+
"\n",
41+
" @value.setter\n",
42+
" def value(self, v):\n",
43+
" self._state['value'] = v\n",
44+
"\n",
45+
" @property\n",
46+
" def min(self):\n",
47+
" return self._state['min']\n",
48+
"\n",
49+
" @min.setter\n",
50+
" def min(self, v):\n",
51+
" self._state['min'] = v\n",
52+
"\n",
53+
" @property\n",
54+
" def max(self):\n",
55+
" return self._state['max']\n",
56+
"\n",
57+
" @max.setter\n",
58+
" def max(self, v):\n",
59+
" self._state['max'] = v\n",
60+
"\n",
61+
" @property\n",
62+
" def step(self):\n",
63+
" return self._state['step']\n",
64+
"\n",
65+
" @step.setter\n",
66+
" def step(self, v):\n",
67+
" self._state['step'] = v"
2368
]
2469
},
2570
{
@@ -29,28 +74,79 @@
2974
"metadata": {},
3075
"outputs": [],
3176
"source": [
32-
"w = MyWidget()\n",
77+
"w = MySlider()\n",
3378
"w"
3479
]
3580
},
3681
{
3782
"cell_type": "code",
3883
"execution_count": null,
39-
"id": "72a7799e-ce21-43ed-865c-77fa1fc69eb2",
84+
"id": "9269a3f1-a061-478f-8728-7393a4aec2d0",
4085
"metadata": {},
4186
"outputs": [],
4287
"source": [
43-
"w.foo = 3"
88+
"w.value"
4489
]
4590
},
4691
{
4792
"cell_type": "code",
4893
"execution_count": null,
49-
"id": "d7289dc9-29c1-4422-8962-1b013bfda40a",
94+
"id": "8ac7ea5c-8315-44eb-aa62-f223f86d267d",
5095
"metadata": {},
5196
"outputs": [],
5297
"source": [
53-
"w.bar = 4"
98+
"w.value = 98"
99+
]
100+
},
101+
{
102+
"cell_type": "code",
103+
"execution_count": null,
104+
"id": "bd2c92fb-9653-4de5-8a20-d463205f3a9e",
105+
"metadata": {},
106+
"outputs": [],
107+
"source": [
108+
"w.value = 36"
109+
]
110+
},
111+
{
112+
"cell_type": "code",
113+
"execution_count": null,
114+
"id": "3a5680c6-77ae-4f71-a982-b3447dcb4fd0",
115+
"metadata": {},
116+
"outputs": [],
117+
"source": [
118+
"w.value"
119+
]
120+
},
121+
{
122+
"cell_type": "code",
123+
"execution_count": null,
124+
"id": "55896ccc-a128-4abf-a34d-4a50272946dd",
125+
"metadata": {},
126+
"outputs": [],
127+
"source": [
128+
"w2 = MySlider(max=200, step=2, value=152)\n",
129+
"w2"
130+
]
131+
},
132+
{
133+
"cell_type": "code",
134+
"execution_count": null,
135+
"id": "c54528b0-6eae-4601-b6f6-ab2f31630815",
136+
"metadata": {},
137+
"outputs": [],
138+
"source": [
139+
"w2.value"
140+
]
141+
},
142+
{
143+
"cell_type": "code",
144+
"execution_count": null,
145+
"id": "23380f74-83ea-4409-a990-a0b8958dde2b",
146+
"metadata": {},
147+
"outputs": [],
148+
"source": [
149+
"w2.value"
54150
]
55151
}
56152
],
@@ -70,7 +166,7 @@
70166
"name": "python",
71167
"nbconvert_exporter": "python",
72168
"pygments_lexer": "ipython3",
73-
"version": "3.11.3"
169+
"version": "3.13.12"
74170
}
75171
},
76172
"nbformat": 4,

examples/simple-yjs-widget/package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"yjs-widgets": "^0.3.3"
5555
},
5656
"devDependencies": {
57-
"@jupyterlab/builder": "~4.0.0",
57+
"@jupyterlab/builder": "^4",
5858
"@types/node": "^16.11.10",
5959
"@typescript-eslint/eslint-plugin": "^4.8.1",
6060
"@typescript-eslint/parser": "^4.8.1",
@@ -81,6 +81,12 @@
8181
"jupyterlab": {
8282
"extension": true,
8383
"outputDir": "simple_yjs_widget/labextension",
84-
"webpackConfig": "./extension.webpack.config.js"
84+
"webpackConfig": "./extension.webpack.config.js",
85+
"sharedPackages": {
86+
"yjs-widgets": {
87+
"singleton": true,
88+
"bundled": false
89+
}
90+
}
8591
}
8692
}

examples/simple-yjs-widget/src/index.ts

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,60 @@
1-
import * as YjsWidgets from 'yjs-widgets';
1+
import {
2+
IJupyterYModel,
3+
JupyterYModel,
4+
IJupyterYWidgetManager
5+
} from 'yjs-widgets';
6+
7+
import * as Y from 'yjs';
28

39
import {
410
JupyterFrontEnd,
511
JupyterFrontEndPlugin
612
} from '@jupyterlab/application';
713

8-
class MyWidget {
9-
constructor(yModel: YjsWidgets.IJupyterYModel, node: HTMLElement) {
14+
class MySlider {
15+
constructor(yModel: IJupyterYModel, node: HTMLElement) {
1016
this.yModel = yModel;
1117
this.node = node;
12-
this.yModel.sharedModel.setAttr('foo', '');
13-
this.yModel.sharedModel.setAttr('bar', '');
14-
yModel.sharedModel.attrsChanged.connect(() => {
15-
this._attrsChanged();
16-
});
17-
setInterval(() => {
18-
this._changeAttrs();
19-
}, 1000);
20-
this._changeAttrs();
18+
19+
this.state = this.yModel.sharedModel.ydoc.getMap('state');
20+
21+
this.state.observe(this._stateChanged.bind(this));
22+
23+
this.slider = document.createElement('input');
24+
this.slider.setAttribute('type', 'range');
25+
26+
this.slider.min = this.state.get('min');
27+
this.slider.max = this.state.get('max');
28+
this.slider.value = this.state.get('value');
29+
this.slider.step = this.state.get('step');
30+
31+
this.slider.onchange = this._sliderChanged.bind(this);
32+
33+
node.appendChild(this.slider);
2134
}
2235

23-
_changeAttrs(): void {
24-
let foo: string = this.yModel.sharedModel.getAttr('foo') as string;
25-
let bar: string = this.yModel.sharedModel.getAttr('bar') as string;
26-
foo = `#${foo}`;
27-
bar = `#${bar}`;
28-
this.yModel.sharedModel.setAttr('foo', foo);
29-
this.yModel.sharedModel.setAttr('bar', bar);
30-
this.node.innerHTML = `foo=${foo}<br>bar=${bar}`;
36+
_stateChanged(change: Y.YMapEvent<any>): void {
37+
for (const key of change.keysChanged) {
38+
this.slider[key] = change.target.toJSON()[key];
39+
}
3140
}
3241

33-
_attrsChanged(): void {
34-
const foo: string = this.yModel.sharedModel.getAttr('foo') as string;
35-
const bar: string = this.yModel.sharedModel.getAttr('bar') as string;
36-
this.node.innerHTML = `foo=${foo}<br>bar=${bar}`;
42+
_sliderChanged(): void {
43+
this.state.set('value', parseInt(this.slider.value ?? '50'));
3744
}
3845

39-
yModel: YjsWidgets.IJupyterYModel;
46+
state: Y.Map<any>;
47+
yModel: IJupyterYModel;
4048
node: HTMLElement;
49+
slider: HTMLInputElement;
4150
}
4251

4352
const simple: JupyterFrontEndPlugin<void> = {
4453
id: 'example:simple',
4554
autoStart: true,
46-
requires: [YjsWidgets.IJupyterYWidgetManager],
47-
activate: (
48-
app: JupyterFrontEnd,
49-
wm: YjsWidgets.IJupyterYWidgetManager
50-
): void => {
51-
wm.registerWidget('MyWidget', YjsWidgets.JupyterYModel, MyWidget);
55+
requires: [IJupyterYWidgetManager],
56+
activate: (_: JupyterFrontEnd, wm: IJupyterYWidgetManager): void => {
57+
wm.registerWidget('MySlider', JupyterYModel, MySlider);
5258
}
5359
};
5460

0 commit comments

Comments
 (0)