@difizen/libro-jupyter 0.3.29 → 0.3.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/es/module-noeditor.js +2 -2
  2. package/es/module.js +2 -2
  3. package/es/rendermime/image-url/image-url-render.d.ts +11 -0
  4. package/es/rendermime/image-url/image-url-render.d.ts.map +1 -0
  5. package/es/rendermime/image-url/image-url-render.js +115 -0
  6. package/es/rendermime/image-url/image-url-rendermime-contribution.d.ts +28 -0
  7. package/es/rendermime/image-url/image-url-rendermime-contribution.d.ts.map +1 -0
  8. package/es/rendermime/image-url/image-url-rendermime-contribution.js +74 -0
  9. package/es/rendermime/image-url/index.less +4 -0
  10. package/es/rendermime/index.d.ts +5 -3
  11. package/es/rendermime/index.d.ts.map +1 -1
  12. package/es/rendermime/index.js +5 -3
  13. package/es/rendermime/module.d.ts +1 -1
  14. package/es/rendermime/module.d.ts.map +1 -1
  15. package/es/rendermime/module.js +3 -2
  16. package/es/rendermime/ploty/plotly-render.d.ts.map +1 -0
  17. package/es/rendermime/ploty/plotly-renderers.d.ts.map +1 -0
  18. package/es/rendermime/ploty/plotly-rendermime-contribution.d.ts.map +1 -0
  19. package/package.json +17 -17
  20. package/src/module-noeditor.ts +2 -2
  21. package/src/module.ts +2 -2
  22. package/src/rendermime/image-url/image-url-render.tsx +145 -0
  23. package/src/rendermime/image-url/image-url-rendermime-contribution.ts +52 -0
  24. package/src/rendermime/image-url/index.less +4 -0
  25. package/src/rendermime/index.ts +5 -3
  26. package/src/rendermime/module.ts +4 -2
  27. package/es/rendermime/plotly-render.d.ts.map +0 -1
  28. package/es/rendermime/plotly-renderers.d.ts.map +0 -1
  29. package/es/rendermime/plotly-rendermime-contribution.d.ts.map +0 -1
  30. /package/es/rendermime/{assets → ploty/assets}/plotly.svg +0 -0
  31. /package/es/rendermime/{index.less → ploty/index.less} +0 -0
  32. /package/es/rendermime/{plotly-render.d.ts → ploty/plotly-render.d.ts} +0 -0
  33. /package/es/rendermime/{plotly-render.js → ploty/plotly-render.js} +0 -0
  34. /package/es/rendermime/{plotly-renderers.d.ts → ploty/plotly-renderers.d.ts} +0 -0
  35. /package/es/rendermime/{plotly-renderers.js → ploty/plotly-renderers.js} +0 -0
  36. /package/es/rendermime/{plotly-rendermime-contribution.d.ts → ploty/plotly-rendermime-contribution.d.ts} +0 -0
  37. /package/es/rendermime/{plotly-rendermime-contribution.js → ploty/plotly-rendermime-contribution.js} +0 -0
  38. /package/src/rendermime/{assets → ploty/assets}/plotly.svg +0 -0
  39. /package/src/rendermime/{index.less → ploty/index.less} +0 -0
  40. /package/src/rendermime/{plotly-render.tsx → ploty/plotly-render.tsx} +0 -0
  41. /package/src/rendermime/{plotly-renderers.ts → ploty/plotly-renderers.ts} +0 -0
  42. /package/src/rendermime/{plotly-rendermime-contribution.ts → ploty/plotly-rendermime-contribution.ts} +0 -0
@@ -23,7 +23,7 @@ import { KernelStatusAndSelectorProvider } from "./libro-jupyter-protocol.js";
23
23
  import { JupyterServerLaunchManager } from "./libro-jupyter-server-launch-manager.js";
24
24
  import { LibroJupyterView } from "./libro-jupyter-view.js";
25
25
  import { LibroJupyterOutputArea } from "./output/index.js";
26
- import { PlotlyModule } from "./rendermime/index.js";
26
+ import { CustomRenderMimeModule } from "./rendermime/index.js";
27
27
  import { LibroJupyterColorContribution } from "./theme/index.js";
28
28
  import { KernelStatusSelector, LibroJupyterToolbarContribution, SaveFileErrorContribution } from "./toolbar/index.js";
29
29
  import { WidgetModule } from "./widget/index.js";
@@ -51,4 +51,4 @@ export var LibroJupyterNoEditorModule = ManaModule.create().register(LibroJupyte
51
51
  useClass: JupyterCodeCellView
52
52
  }).dependOn(LibroModule, CodeCellModule, MarkdownCellModule, RawCellModule, StreamOutputModule, ErrorOutputModule, DisplayDataOutputModule, LibroToolbarModule, LibroKernelManageModule, LibroSearchModule, SearchCodeCellModule, LibroAddCellModule,
53
53
  // custom module
54
- LibroBetweenCellModule, KeybindInstructionsModule, PlotlyModule, LibroJupyterFileModule, WidgetModule);
54
+ LibroBetweenCellModule, KeybindInstructionsModule, CustomRenderMimeModule, LibroJupyterFileModule, WidgetModule);
package/es/module.js CHANGED
@@ -27,7 +27,7 @@ import { JupyterServerLaunchManager } from "./libro-jupyter-server-launch-manage
27
27
  import { LibroJupyterView } from "./libro-jupyter-view.js";
28
28
  import { JupyterWorkspaceService } from "./libro-jupyter-workspace.js";
29
29
  import { LibroJupyterOutputArea } from "./output/index.js";
30
- import { PlotlyModule } from "./rendermime/index.js";
30
+ import { CustomRenderMimeModule } from "./rendermime/index.js";
31
31
  import { LibroJupyterColorContribution } from "./theme/index.js";
32
32
  import { KernelStatusSelector, LibroJupyterToolbarContribution, SaveFileErrorContribution } from "./toolbar/index.js";
33
33
  import { WidgetModule } from "./widget/index.js";
@@ -55,5 +55,5 @@ export var LibroJupyterNoEditorModule = ManaModule.create().register(LibroJupyte
55
55
  useClass: JupyterCodeCellView
56
56
  }).dependOn(LibroModule, CodeCellModule, MarkdownCellModule, RawCellModule, StreamOutputModule, ErrorOutputModule, DisplayDataOutputModule, LibroToolbarModule, LibroKernelManageModule, LibroSearchModule, SearchCodeCellModule, LibroAddCellModule,
57
57
  // custom module
58
- LibroBetweenCellModule, KeybindInstructionsModule, PlotlyModule, LibroJupyterFileModule, WidgetModule);
58
+ LibroBetweenCellModule, KeybindInstructionsModule, CustomRenderMimeModule, LibroJupyterFileModule, WidgetModule);
59
59
  export var LibroJupyterModule = ManaModule.create().register(JupyterWorkspaceService).dependOn(LibroE2EditorModule, CodeMirrorEditorModule, LibroJupyterNoEditorModule, LibroLanguageClientModule);
@@ -0,0 +1,11 @@
1
+ import type { BaseOutputView } from '@difizen/libro-core';
2
+ import type { FC } from 'react';
3
+ export declare const imageUrlMimeTypes: string[];
4
+ /**
5
+ * 图片 URL 渲染组件
6
+ * 专门处理图片 URL 数据的渲染
7
+ */
8
+ export declare const ImageUrlRender: FC<{
9
+ model: BaseOutputView;
10
+ }>;
11
+ //# sourceMappingURL=image-url-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-url-render.d.ts","sourceRoot":"","sources":["../../../src/rendermime/image-url/image-url-render.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,eAAO,MAAM,iBAAiB,UAAgC,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,CAyCxD,CAAC"}
@@ -0,0 +1,115 @@
1
+ import { RenderMimeRegistry } from '@difizen/libro-rendermime';
2
+ import { useInject } from '@difizen/mana-app';
3
+ import { useEffect, useRef } from 'react';
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ export var imageUrlMimeTypes = ['image/vnd.libro.image-url'];
6
+
7
+ /**
8
+ * 图片 URL 渲染组件
9
+ * 专门处理图片 URL 数据的渲染
10
+ */
11
+ export var ImageUrlRender = function ImageUrlRender(props) {
12
+ var model = props.model;
13
+ var renderImageRef = useRef(null);
14
+ var defaultRenderMime = useInject(RenderMimeRegistry);
15
+
16
+ // 获取首选的图片 MIME 类型
17
+ var mimeType = defaultRenderMime.preferredMimeType(model);
18
+ useEffect(function () {
19
+ if (mimeType && renderImageRef.current) {
20
+ var imageData = model.data[mimeType];
21
+ if (typeof imageData === 'string') {
22
+ var _model$metadata$mimeT, _model$metadata$mimeT2;
23
+ renderImageUrl({
24
+ host: renderImageRef.current,
25
+ source: imageData,
26
+ width: model.metadata['width'] || ((_model$metadata$mimeT = model.metadata[mimeType]) === null || _model$metadata$mimeT === void 0 ? void 0 : _model$metadata$mimeT['width']),
27
+ height: model.metadata['height'] || ((_model$metadata$mimeT2 = model.metadata[mimeType]) === null || _model$metadata$mimeT2 === void 0 ? void 0 : _model$metadata$mimeT2['height']),
28
+ needsBackground: model.metadata['needs_background'],
29
+ unconfined: model.metadata && model.metadata['unconfined'],
30
+ mimeType: mimeType
31
+ });
32
+ }
33
+ }
34
+ // eslint-disable-next-line react-hooks/exhaustive-deps
35
+ }, []);
36
+ return /*#__PURE__*/_jsx("div", {
37
+ className: "libro-image-url-render-container",
38
+ children: /*#__PURE__*/_jsx("div", {
39
+ className: "libro-image-url-render",
40
+ ref: renderImageRef
41
+ })
42
+ });
43
+ };
44
+
45
+ /**
46
+ * 渲染图片 URL 的选项接口
47
+ */
48
+
49
+ /**
50
+ * 渲染图片 URL 到指定的宿主节点
51
+ * 支持 HTTP/HTTPS URL 和相对路径
52
+ */
53
+ function renderImageUrl(options) {
54
+ var host = options.host,
55
+ source = options.source,
56
+ width = options.width,
57
+ height = options.height,
58
+ needsBackground = options.needsBackground,
59
+ unconfined = options.unconfined;
60
+
61
+ // 清空宿主节点内容
62
+ host.textContent = '';
63
+
64
+ // 创建图片元素
65
+ var img = document.createElement('img');
66
+
67
+ // 设置图片源
68
+ // 如果是 URL(以 http 开头),直接使用
69
+ // 否则按照原有逻辑处理(兼容 base64 数据)
70
+ if (source.startsWith('http://') || source.startsWith('https://') || !source.startsWith('data:') && source.includes('/')) {
71
+ img.src = source;
72
+ } else {
73
+ // 兜底处理,按照原有的 base64 逻辑
74
+ img.src = source.startsWith('data:') ? source : "data:".concat(options.mimeType, ";base64,").concat(source);
75
+ }
76
+
77
+ // 设置图片尺寸
78
+ if (typeof height === 'number') {
79
+ img.height = height;
80
+ }
81
+ if (typeof width === 'number') {
82
+ img.width = width;
83
+ }
84
+
85
+ // 设置背景样式
86
+ if (needsBackground === 'light') {
87
+ img.classList.add('jp-needs-light-background');
88
+ } else if (needsBackground === 'dark') {
89
+ img.classList.add('jp-needs-dark-background');
90
+ }
91
+
92
+ // 设置无约束样式
93
+ if (unconfined === true) {
94
+ img.classList.add('jp-mod-unconfined');
95
+ }
96
+
97
+ // 添加错误处理
98
+ img.onerror = function () {
99
+ // 可以在这里添加占位符或错误提示
100
+ var errorDiv = document.createElement('div');
101
+ errorDiv.className = 'libro-image-url-error';
102
+ errorDiv.textContent = "\u65E0\u6CD5\u52A0\u8F7D\u56FE\u7247: ".concat(source);
103
+ errorDiv.style.cssText = "\n padding: 10px;\n border: 1px dashed #ccc;\n color: #666;\n text-align: center;\n background-color: #f9f9f9;\n ";
104
+ host.replaceChild(errorDiv, img);
105
+ };
106
+
107
+ // 添加加载成功处理
108
+ img.onload = function () {
109
+ // 图片加载成功
110
+ };
111
+
112
+ // 将图片添加到宿主节点
113
+ host.appendChild(img);
114
+ return Promise.resolve(undefined);
115
+ }
@@ -0,0 +1,28 @@
1
+ /// <reference types="react" resolution-mode="require"/>
2
+ import type { BaseOutputView } from '@difizen/libro-core';
3
+ import { RenderMimeContribution } from '@difizen/libro-rendermime';
4
+ import './index.less';
5
+ /**
6
+ * 自定义图片 URL MIME 渲染器贡献类
7
+ * 优先级高于默认图片渲染器,专门处理图片 URL 数据
8
+ */
9
+ export declare class LibroImageUrlMimeTypeContribution implements RenderMimeContribution {
10
+ private imageUrlMimeTypes;
11
+ /**
12
+ * 判断是否能处理该模型数据
13
+ * 返回值越高,优先级越高
14
+ * 只有当数据是图片 URL 时才返回高优先级
15
+ */
16
+ canHandle: (model: BaseOutputView) => number;
17
+ /**
18
+ * 检查字符串是否为图片 URL
19
+ */
20
+ private isImageUrl;
21
+ renderType: string;
22
+ safe: boolean;
23
+ mimeTypes: string[];
24
+ render: import("react").FC<{
25
+ model: BaseOutputView;
26
+ }>;
27
+ }
28
+ //# sourceMappingURL=image-url-rendermime-contribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-url-rendermime-contribution.d.ts","sourceRoot":"","sources":["../../../src/rendermime/image-url/image-url-rendermime-contribution.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAInE,OAAO,cAAc,CAAC;AAEtB;;;GAGG;AACH,qBACa,iCAAkC,YAAW,sBAAsB;IAC9E,OAAO,CAAC,iBAAiB,CAAqB;IAE9C;;;;OAIG;IACH,SAAS,UAAW,cAAc,KAAG,MAAM,CAazC;IAEF;;OAEG;IACH,OAAO,CAAC,UAAU;IASlB,UAAU,SAAoB;IAC9B,IAAI,UAAQ;IACZ,SAAS,WAA0B;IACnC,MAAM;;OAAkB;CACzB"}
@@ -0,0 +1,74 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ var _dec, _class;
3
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
4
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
5
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
6
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
8
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
9
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
10
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
11
+ import { RenderMimeContribution } from '@difizen/libro-rendermime';
12
+ import { singleton } from '@difizen/mana-app';
13
+ import { ImageUrlRender, imageUrlMimeTypes } from "./image-url-render.js";
14
+ import "./index.less";
15
+
16
+ /**
17
+ * 自定义图片 URL MIME 渲染器贡献类
18
+ * 优先级高于默认图片渲染器,专门处理图片 URL 数据
19
+ */
20
+ export var LibroImageUrlMimeTypeContribution = (_dec = singleton({
21
+ contrib: RenderMimeContribution
22
+ }), _dec(_class = /*#__PURE__*/function () {
23
+ function LibroImageUrlMimeTypeContribution() {
24
+ var _this = this;
25
+ _classCallCheck(this, LibroImageUrlMimeTypeContribution);
26
+ this.imageUrlMimeTypes = imageUrlMimeTypes;
27
+ /**
28
+ * 判断是否能处理该模型数据
29
+ * 返回值越高,优先级越高
30
+ * 只有当数据是图片 URL 时才返回高优先级
31
+ */
32
+ this.canHandle = function (model) {
33
+ // 检查是否包含图片 MIME 类型
34
+ var _iterator = _createForOfIteratorHelper(_this.imageUrlMimeTypes),
35
+ _step;
36
+ try {
37
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
38
+ var mimeType = _step.value;
39
+ if (mimeType in model.data) {
40
+ var data = model.data[mimeType];
41
+ // 检查数据是否为字符串且看起来像 URL
42
+ if (typeof data === 'string' && _this.isImageUrl(data)) {
43
+ return 200; // 高优先级,超过默认图片渲染器的 90
44
+ }
45
+ }
46
+ }
47
+ } catch (err) {
48
+ _iterator.e(err);
49
+ } finally {
50
+ _iterator.f();
51
+ }
52
+ return 0; // 不处理非 URL 图片数据
53
+ };
54
+ this.renderType = 'imageUrlRender';
55
+ this.safe = true;
56
+ this.mimeTypes = this.imageUrlMimeTypes;
57
+ this.render = ImageUrlRender;
58
+ }
59
+ _createClass(LibroImageUrlMimeTypeContribution, [{
60
+ key: "isImageUrl",
61
+ value:
62
+ /**
63
+ * 检查字符串是否为图片 URL
64
+ */
65
+ function isImageUrl(data) {
66
+ // 检查是否以 http:// 或 https:// 开头
67
+ if (data.startsWith('http://') || data.startsWith('https://')) {
68
+ return true;
69
+ }
70
+ return false;
71
+ }
72
+ }]);
73
+ return LibroImageUrlMimeTypeContribution;
74
+ }()) || _class);
@@ -0,0 +1,4 @@
1
+ .libro-image-url-render-container {
2
+ border-radius: 4px;
3
+ padding: 10px 24px;
4
+ }
@@ -1,5 +1,7 @@
1
1
  export * from './module.js';
2
- export * from './plotly-renderers.js';
3
- export * from './plotly-render.js';
4
- export * from './plotly-rendermime-contribution.js';
2
+ export * from './ploty/plotly-renderers.js';
3
+ export * from './ploty/plotly-render.js';
4
+ export * from './ploty/plotly-rendermime-contribution.js';
5
+ export * from './image-url/image-url-rendermime-contribution.js';
6
+ export * from './image-url/image-url-render.js';
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rendermime/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qCAAqC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rendermime/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2CAA2C,CAAC;AAC1D,cAAc,kDAAkD,CAAC;AACjE,cAAc,iCAAiC,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export * from "./module.js";
2
- export * from "./plotly-renderers.js";
3
- export * from "./plotly-render.js";
4
- export * from "./plotly-rendermime-contribution.js";
2
+ export * from "./ploty/plotly-renderers.js";
3
+ export * from "./ploty/plotly-render.js";
4
+ export * from "./ploty/plotly-rendermime-contribution.js";
5
+ export * from "./image-url/image-url-rendermime-contribution.js";
6
+ export * from "./image-url/image-url-render.js";
@@ -1,3 +1,3 @@
1
1
  import { ManaModule } from '@difizen/mana-app';
2
- export declare const PlotlyModule: ManaModule;
2
+ export declare const CustomRenderMimeModule: ManaModule;
3
3
  //# sourceMappingURL=module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/rendermime/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C,eAAO,MAAM,YAAY,YAExB,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/rendermime/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAK/C,eAAO,MAAM,sBAAsB,YAGlC,CAAC"}
@@ -1,3 +1,4 @@
1
1
  import { ManaModule } from '@difizen/mana-app';
2
- import { LibroPlotlyMimeTypeContribution } from "./plotly-rendermime-contribution.js";
3
- export var PlotlyModule = ManaModule.create().register(LibroPlotlyMimeTypeContribution);
2
+ import { LibroImageUrlMimeTypeContribution } from "./image-url/image-url-rendermime-contribution.js";
3
+ import { LibroPlotlyMimeTypeContribution } from "./ploty/plotly-rendermime-contribution.js";
4
+ export var CustomRenderMimeModule = ManaModule.create().register(LibroPlotlyMimeTypeContribution, LibroImageUrlMimeTypeContribution);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plotly-render.d.ts","sourceRoot":"","sources":["../../../src/rendermime/ploty/plotly-render.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC,OAAO,cAAc,CAAC;AAEtB,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,CAwBtD,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plotly-renderers.d.ts","sourceRoot":"","sources":["../../../src/rendermime/ploty/plotly-renderers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,WAAW,CAAC;AACxC;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB;;OAEG;IACH,MAAM,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,cAAc,CAAC;CACvB;AACD;;;GAGG;AACH,eAAO,MAAM,SAAS,mCAAmC,CAAC;AAO1D,qBAAa,cAAc;IACzB;;OAEG;gBACS,OAAO,EAAE,sBAAsB;IAc3C;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBjD,SAAS,CAAC,eAAe;IAMzB,SAAS,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM;IAMtC,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA+C3D,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACpC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC;IACjC,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC;IAC5B,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,UAAU,GAAG,IAAI,CAAQ;IACzD,SAAS,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IACnD,SAAS,CAAC,MAAM,CAAC,aAAa,gBAE3B;CACJ;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3E"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plotly-rendermime-contribution.d.ts","sourceRoot":"","sources":["../../../src/rendermime/ploty/plotly-rendermime-contribution.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAKnE,qBACa,+BAAgC,YAAW,sBAAsB;IAC5E,SAAS,eAEP;IACF,UAAU,SAAkB;IAC5B,IAAI,UAAQ;IACZ,SAAS,WAAsC;IAC/C,MAAM;;OAAgB;CACvB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@difizen/libro-jupyter",
3
- "version": "0.3.29",
3
+ "version": "0.3.30",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "libro"
@@ -37,22 +37,22 @@
37
37
  "dependencies": {
38
38
  "@ant-design/colors": "^7.0.0",
39
39
  "@ant-design/icons": "^5.1.0",
40
- "@difizen/libro-code-cell": "^0.3.29",
41
- "@difizen/libro-code-editor": "^0.3.29",
42
- "@difizen/libro-codemirror": "^0.3.29",
43
- "@difizen/libro-cofine-editor": "^0.3.29",
44
- "@difizen/libro-common": "^0.3.29",
45
- "@difizen/libro-core": "^0.3.29",
46
- "@difizen/libro-kernel": "^0.3.29",
47
- "@difizen/libro-l10n": "^0.3.29",
48
- "@difizen/libro-language-client": "^0.3.29",
49
- "@difizen/libro-lsp": "^0.3.29",
50
- "@difizen/libro-markdown-cell": "^0.3.29",
51
- "@difizen/libro-output": "^0.3.29",
52
- "@difizen/libro-raw-cell": "^0.3.29",
53
- "@difizen/libro-rendermime": "^0.3.29",
54
- "@difizen/libro-search": "^0.3.29",
55
- "@difizen/libro-search-code-cell": "^0.3.29",
40
+ "@difizen/libro-code-cell": "^0.3.30",
41
+ "@difizen/libro-code-editor": "^0.3.30",
42
+ "@difizen/libro-codemirror": "^0.3.30",
43
+ "@difizen/libro-cofine-editor": "^0.3.30",
44
+ "@difizen/libro-common": "^0.3.30",
45
+ "@difizen/libro-core": "^0.3.30",
46
+ "@difizen/libro-kernel": "^0.3.30",
47
+ "@difizen/libro-l10n": "^0.3.30",
48
+ "@difizen/libro-language-client": "^0.3.30",
49
+ "@difizen/libro-lsp": "^0.3.30",
50
+ "@difizen/libro-markdown-cell": "^0.3.30",
51
+ "@difizen/libro-output": "^0.3.30",
52
+ "@difizen/libro-raw-cell": "^0.3.30",
53
+ "@difizen/libro-rendermime": "^0.3.30",
54
+ "@difizen/libro-search": "^0.3.30",
55
+ "@difizen/libro-search-code-cell": "^0.3.30",
56
56
  "@difizen/mana-app": "latest",
57
57
  "@difizen/mana-l10n": "latest",
58
58
  "classnames": "^2.3.2",
@@ -46,7 +46,7 @@ import { KernelStatusAndSelectorProvider } from './libro-jupyter-protocol.js';
46
46
  import { JupyterServerLaunchManager } from './libro-jupyter-server-launch-manager.js';
47
47
  import { LibroJupyterView } from './libro-jupyter-view.js';
48
48
  import { LibroJupyterOutputArea } from './output/index.js';
49
- import { PlotlyModule } from './rendermime/index.js';
49
+ import { CustomRenderMimeModule } from './rendermime/index.js';
50
50
  import { LibroJupyterColorContribution } from './theme/index.js';
51
51
  import {
52
52
  KernelStatusSelector,
@@ -110,7 +110,7 @@ export const LibroJupyterNoEditorModule = ManaModule.create()
110
110
  // custom module
111
111
  LibroBetweenCellModule,
112
112
  KeybindInstructionsModule,
113
- PlotlyModule,
113
+ CustomRenderMimeModule,
114
114
  LibroJupyterFileModule,
115
115
  WidgetModule,
116
116
  );
package/src/module.ts CHANGED
@@ -50,7 +50,7 @@ import { JupyterServerLaunchManager } from './libro-jupyter-server-launch-manage
50
50
  import { LibroJupyterView } from './libro-jupyter-view.js';
51
51
  import { JupyterWorkspaceService } from './libro-jupyter-workspace.js';
52
52
  import { LibroJupyterOutputArea } from './output/index.js';
53
- import { PlotlyModule } from './rendermime/index.js';
53
+ import { CustomRenderMimeModule } from './rendermime/index.js';
54
54
  import { LibroJupyterColorContribution } from './theme/index.js';
55
55
  import {
56
56
  KernelStatusSelector,
@@ -114,7 +114,7 @@ export const LibroJupyterNoEditorModule = ManaModule.create()
114
114
  // custom module
115
115
  LibroBetweenCellModule,
116
116
  KeybindInstructionsModule,
117
- PlotlyModule,
117
+ CustomRenderMimeModule,
118
118
  LibroJupyterFileModule,
119
119
  WidgetModule,
120
120
  );
@@ -0,0 +1,145 @@
1
+ import type { JSONObject } from '@difizen/libro-common';
2
+ import type { BaseOutputView } from '@difizen/libro-core';
3
+ import type { IRenderMimeRegistry } from '@difizen/libro-rendermime';
4
+ import { RenderMimeRegistry } from '@difizen/libro-rendermime';
5
+ import { useInject } from '@difizen/mana-app';
6
+ import { useEffect, useRef } from 'react';
7
+ import type { FC } from 'react';
8
+
9
+ export const imageUrlMimeTypes = ['image/vnd.libro.image-url'];
10
+
11
+ /**
12
+ * 图片 URL 渲染组件
13
+ * 专门处理图片 URL 数据的渲染
14
+ */
15
+ export const ImageUrlRender: FC<{ model: BaseOutputView }> = (props: {
16
+ model: BaseOutputView;
17
+ }) => {
18
+ const { model } = props;
19
+ const renderImageRef = useRef<HTMLDivElement>(null);
20
+ const defaultRenderMime = useInject<IRenderMimeRegistry>(RenderMimeRegistry);
21
+
22
+ // 获取首选的图片 MIME 类型
23
+ const mimeType = defaultRenderMime.preferredMimeType(model);
24
+
25
+ useEffect(() => {
26
+ if (mimeType && renderImageRef.current) {
27
+ const imageData = model.data[mimeType];
28
+
29
+ if (typeof imageData === 'string') {
30
+ renderImageUrl({
31
+ host: renderImageRef.current,
32
+ source: imageData,
33
+ width: (model.metadata['width'] ||
34
+ (model.metadata[mimeType] as JSONObject)?.['width']) as unknown as
35
+ | number
36
+ | undefined,
37
+ height: (model.metadata['height'] ||
38
+ (model.metadata[mimeType] as JSONObject)?.['height']) as unknown as
39
+ | number
40
+ | undefined,
41
+ needsBackground: model.metadata['needs_background'] as string | undefined,
42
+ unconfined:
43
+ model.metadata && (model.metadata['unconfined'] as boolean | undefined),
44
+ mimeType: mimeType,
45
+ });
46
+ }
47
+ }
48
+ // eslint-disable-next-line react-hooks/exhaustive-deps
49
+ }, []);
50
+
51
+ return (
52
+ <div className="libro-image-url-render-container">
53
+ <div className="libro-image-url-render" ref={renderImageRef} />
54
+ </div>
55
+ );
56
+ };
57
+
58
+ /**
59
+ * 渲染图片 URL 的选项接口
60
+ */
61
+ interface IRenderImageUrlOptions {
62
+ host: HTMLElement;
63
+ mimeType: string;
64
+ source: string;
65
+ width?: number;
66
+ height?: number;
67
+ needsBackground?: string;
68
+ unconfined?: boolean;
69
+ }
70
+
71
+ /**
72
+ * 渲染图片 URL 到指定的宿主节点
73
+ * 支持 HTTP/HTTPS URL 和相对路径
74
+ */
75
+ function renderImageUrl(options: IRenderImageUrlOptions): Promise<void> {
76
+ const { host, source, width, height, needsBackground, unconfined } = options;
77
+
78
+ // 清空宿主节点内容
79
+ host.textContent = '';
80
+
81
+ // 创建图片元素
82
+ const img = document.createElement('img');
83
+
84
+ // 设置图片源
85
+ // 如果是 URL(以 http 开头),直接使用
86
+ // 否则按照原有逻辑处理(兼容 base64 数据)
87
+ if (
88
+ source.startsWith('http://') ||
89
+ source.startsWith('https://') ||
90
+ (!source.startsWith('data:') && source.includes('/'))
91
+ ) {
92
+ img.src = source;
93
+ } else {
94
+ // 兜底处理,按照原有的 base64 逻辑
95
+ img.src = source.startsWith('data:')
96
+ ? source
97
+ : `data:${options.mimeType};base64,${source}`;
98
+ }
99
+
100
+ // 设置图片尺寸
101
+ if (typeof height === 'number') {
102
+ img.height = height;
103
+ }
104
+ if (typeof width === 'number') {
105
+ img.width = width;
106
+ }
107
+
108
+ // 设置背景样式
109
+ if (needsBackground === 'light') {
110
+ img.classList.add('jp-needs-light-background');
111
+ } else if (needsBackground === 'dark') {
112
+ img.classList.add('jp-needs-dark-background');
113
+ }
114
+
115
+ // 设置无约束样式
116
+ if (unconfined === true) {
117
+ img.classList.add('jp-mod-unconfined');
118
+ }
119
+
120
+ // 添加错误处理
121
+ img.onerror = () => {
122
+ // 可以在这里添加占位符或错误提示
123
+ const errorDiv = document.createElement('div');
124
+ errorDiv.className = 'libro-image-url-error';
125
+ errorDiv.textContent = `无法加载图片: ${source}`;
126
+ errorDiv.style.cssText = `
127
+ padding: 10px;
128
+ border: 1px dashed #ccc;
129
+ color: #666;
130
+ text-align: center;
131
+ background-color: #f9f9f9;
132
+ `;
133
+ host.replaceChild(errorDiv, img);
134
+ };
135
+
136
+ // 添加加载成功处理
137
+ img.onload = () => {
138
+ // 图片加载成功
139
+ };
140
+
141
+ // 将图片添加到宿主节点
142
+ host.appendChild(img);
143
+
144
+ return Promise.resolve(undefined);
145
+ }
@@ -0,0 +1,52 @@
1
+ import type { BaseOutputView } from '@difizen/libro-core';
2
+ import { RenderMimeContribution } from '@difizen/libro-rendermime';
3
+ import { singleton } from '@difizen/mana-app';
4
+
5
+ import { ImageUrlRender, imageUrlMimeTypes } from './image-url-render.js';
6
+ import './index.less';
7
+
8
+ /**
9
+ * 自定义图片 URL MIME 渲染器贡献类
10
+ * 优先级高于默认图片渲染器,专门处理图片 URL 数据
11
+ */
12
+ @singleton({ contrib: RenderMimeContribution })
13
+ export class LibroImageUrlMimeTypeContribution implements RenderMimeContribution {
14
+ private imageUrlMimeTypes = imageUrlMimeTypes;
15
+
16
+ /**
17
+ * 判断是否能处理该模型数据
18
+ * 返回值越高,优先级越高
19
+ * 只有当数据是图片 URL 时才返回高优先级
20
+ */
21
+ canHandle = (model: BaseOutputView): number => {
22
+ // 检查是否包含图片 MIME 类型
23
+ for (const mimeType of this.imageUrlMimeTypes) {
24
+ if (mimeType in model.data) {
25
+ const data = model.data[mimeType];
26
+ // 检查数据是否为字符串且看起来像 URL
27
+ if (typeof data === 'string' && this.isImageUrl(data)) {
28
+ return 200; // 高优先级,超过默认图片渲染器的 90
29
+ }
30
+ }
31
+ }
32
+
33
+ return 0; // 不处理非 URL 图片数据
34
+ };
35
+
36
+ /**
37
+ * 检查字符串是否为图片 URL
38
+ */
39
+ private isImageUrl(data: string): boolean {
40
+ // 检查是否以 http:// 或 https:// 开头
41
+ if (data.startsWith('http://') || data.startsWith('https://')) {
42
+ return true;
43
+ }
44
+
45
+ return false;
46
+ }
47
+
48
+ renderType = 'imageUrlRender';
49
+ safe = true;
50
+ mimeTypes = this.imageUrlMimeTypes;
51
+ render = ImageUrlRender;
52
+ }
@@ -0,0 +1,4 @@
1
+ .libro-image-url-render-container {
2
+ border-radius: 4px;
3
+ padding: 10px 24px;
4
+ }
@@ -1,4 +1,6 @@
1
1
  export * from './module.js';
2
- export * from './plotly-renderers.js';
3
- export * from './plotly-render.js';
4
- export * from './plotly-rendermime-contribution.js';
2
+ export * from './ploty/plotly-renderers.js';
3
+ export * from './ploty/plotly-render.js';
4
+ export * from './ploty/plotly-rendermime-contribution.js';
5
+ export * from './image-url/image-url-rendermime-contribution.js';
6
+ export * from './image-url/image-url-render.js';
@@ -1,7 +1,9 @@
1
1
  import { ManaModule } from '@difizen/mana-app';
2
2
 
3
- import { LibroPlotlyMimeTypeContribution } from './plotly-rendermime-contribution.js';
3
+ import { LibroImageUrlMimeTypeContribution } from './image-url/image-url-rendermime-contribution.js';
4
+ import { LibroPlotlyMimeTypeContribution } from './ploty/plotly-rendermime-contribution.js';
4
5
 
5
- export const PlotlyModule = ManaModule.create().register(
6
+ export const CustomRenderMimeModule = ManaModule.create().register(
6
7
  LibroPlotlyMimeTypeContribution,
8
+ LibroImageUrlMimeTypeContribution,
7
9
  );
@@ -1 +0,0 @@
1
- {"version":3,"file":"plotly-render.d.ts","sourceRoot":"","sources":["../../src/rendermime/plotly-render.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC,OAAO,cAAc,CAAC;AAEtB,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,CAwBtD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"plotly-renderers.d.ts","sourceRoot":"","sources":["../../src/rendermime/plotly-renderers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,WAAW,CAAC;AACxC;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB;;OAEG;IACH,MAAM,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,cAAc,CAAC;CACvB;AACD;;;GAGG;AACH,eAAO,MAAM,SAAS,mCAAmC,CAAC;AAO1D,qBAAa,cAAc;IACzB;;OAEG;gBACS,OAAO,EAAE,sBAAsB;IAc3C;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBjD,SAAS,CAAC,eAAe;IAMzB,SAAS,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM;IAMtC,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,SAAS;IAQnB,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA+C3D,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACpC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC;IACjC,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC;IAC5B,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,UAAU,GAAG,IAAI,CAAQ;IACzD,SAAS,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IACnD,SAAS,CAAC,MAAM,CAAC,aAAa,gBAE3B;CACJ;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3E"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"plotly-rendermime-contribution.d.ts","sourceRoot":"","sources":["../../src/rendermime/plotly-rendermime-contribution.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAKnE,qBACa,+BAAgC,YAAW,sBAAsB;IAC5E,SAAS,eAEP;IACF,UAAU,SAAkB;IAC5B,IAAI,UAAQ;IACZ,SAAS,WAAsC;IAC/C,MAAM;;OAAgB;CACvB"}
File without changes
File without changes