drawui-react 0.5.1 → 0.5.3
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.
- package/IMAGE_UPLOAD.md +205 -0
- package/README.md +41 -3
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +1 -1
- package/dist/styles.css +167 -0
- package/package.json +10 -3
package/IMAGE_UPLOAD.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# 图片上传通道 · 集成指南
|
|
2
|
+
|
|
3
|
+
> 📌 本文件是 `packages/core/IMAGE_UPLOAD.md` 的**同步副本**,随 `drawui-react` 一起发布,安装后不必跳转即可阅读。内容改动请以 core 那份为准,改完同步覆盖本文件。
|
|
4
|
+
|
|
5
|
+
> 面向接入方(队友 / 业务方)。用于把 drawui 的「图片」按钮、粘贴、拖入文件统一接到自家上传服务(OSS / 自建后端 / 其它对象存储)。
|
|
6
|
+
|
|
7
|
+
## 〇、这份文档在哪
|
|
8
|
+
|
|
9
|
+
| 场景 | 路径 |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| 本仓库(真源,改动以此为准) | `packages/core/IMAGE_UPLOAD.md` |
|
|
12
|
+
| 本仓库(同步副本) | `packages/react/IMAGE_UPLOAD.md` |
|
|
13
|
+
| 安装依赖后 | `node_modules/drawui-core/IMAGE_UPLOAD.md` / `node_modules/drawui-react/IMAGE_UPLOAD.md` |
|
|
14
|
+
| 在线 | <https://github.com/weishell/drawui/blob/main/packages/core/IMAGE_UPLOAD.md> |
|
|
15
|
+
|
|
16
|
+
> 两个 npm 包均已把该文档列入 `files`,`README.md` 里的链接使用的是包内相对路径,安装后同样点得开。
|
|
17
|
+
|
|
18
|
+
## 一、能力定位
|
|
19
|
+
|
|
20
|
+
- **drawui 不内置任何对象存储 SDK**(不依赖 `ali-oss`、不预置 STS、不暴露任何 accessKey)。
|
|
21
|
+
- SDK 只负责「选文件 → 拿到一个 URL → 在画布上渲染图片」,至于 URL 从哪儿来,完全由接入方决定。
|
|
22
|
+
- 提供 **两条通道**,二选一或并存:
|
|
23
|
+
|
|
24
|
+
| 通道 | 形式 | 适用 |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| **A. `ImageUploadConfig`** | 配 `{ url, method, fieldName, headers, fields, responseUrlPath, timeoutMs, maxSizeBytes }` | 队友有自己的中转接口(前端 → 队友后端 → OSS) |
|
|
27
|
+
| **B. `ImageUploader` 函数** | `(file: File) => Promise<string>`,函数内自行拿到 STS、签名直传 OSS | 前端直传 OSS / 自定义分片 / 自定义压缩 |
|
|
28
|
+
|
|
29
|
+
**优先级 B > A**(函数优先于配置)。
|
|
30
|
+
|
|
31
|
+
## 二、硬性约定(已默认开启,接入方不需要写)
|
|
32
|
+
|
|
33
|
+
| 项 | 默认值 | 覆盖方式 |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| **单张图片体积上限** | **30 MB**(超过直接拒绝,不会发出请求) | `ImageUploadConfig.maxSizeBytes` 自定义;写 `ImageUploader` 函数时需自己检查 |
|
|
36
|
+
| **上传超时** | **60 秒**(之前是 30 秒,已调大) | `ImageUploadConfig.timeoutMs` 自定义 |
|
|
37
|
+
| **失败重试** | 不重试,抛错后由调用方提示用户 | 自定义 `ImageUploader` 时自己实现 |
|
|
38
|
+
| **请求并发控制** | 不限制,多文件并发上传 | 自定义 `ImageUploader` 时自己实现 |
|
|
39
|
+
| **跨域** | 远端图默认 `crossOrigin='anonymous'` | `setImageCrossOrigin(null)` 关闭(注意会污染画布导致 PNG 导出失败) |
|
|
40
|
+
|
|
41
|
+
> 体积超限走错误码 `image.tooLarge:`(前端 toast 已自动用 `image.tooLarge` 文案显示)。
|
|
42
|
+
|
|
43
|
+
## 三、怎么调(按场景)
|
|
44
|
+
|
|
45
|
+
### 场景 1:队友有自己的上传中转接口(最常见)
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { CanvasBoard } from 'drawui-react'
|
|
49
|
+
|
|
50
|
+
<CanvasBoard
|
|
51
|
+
imageUpload={{
|
|
52
|
+
url: 'https://api.team.com/upload',
|
|
53
|
+
method: 'POST',
|
|
54
|
+
fieldName: 'file', // 后端接收字段名
|
|
55
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
56
|
+
// responseUrlPath: 'data.url', // 响应 JSON 里 url 的路径;不填自动探测
|
|
57
|
+
// timeoutMs: 60000, // 默认 60s
|
|
58
|
+
// maxSizeBytes: 30 * 1024 * 1024, // 默认 30 MB
|
|
59
|
+
}}
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
后端返回任一形式即可(自动探测顺序:`url` → `data.url` → `data` → `data.src` → `location` → `path` → `src` → `href` → `fileUrl` → `imageUrl` → `data.fileUrl`):
|
|
64
|
+
|
|
65
|
+
```jsonc
|
|
66
|
+
// 推荐:直接给 url
|
|
67
|
+
{ "url": "https://cdn.example.com/foo.png" }
|
|
68
|
+
|
|
69
|
+
// 或者套了一层
|
|
70
|
+
{ "code": 0, "data": { "url": "https://cdn.example.com/foo.png" } }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
如果自动探测拿不准,**强烈建议显式配 `responseUrlPath: 'data.url'`**,避免 JSON 里其它字段(如 `userUrl`)被误识别。
|
|
74
|
+
|
|
75
|
+
### 场景 2:前端直传 OSS(拿 STS 后 PutObject)
|
|
76
|
+
|
|
77
|
+
**必须用 `ImageUploader` 函数,不要用 `ImageUploadConfig.headers` 试图塞 OSS 签名 —— 浏览器会先发 CORS 预检,而 OSS 默认不回 `x-oss-*` 自定义头的预检响应。**
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import OSS from 'ali-oss'
|
|
81
|
+
import { CanvasBoard } from 'drawui-react'
|
|
82
|
+
|
|
83
|
+
async function uploadToOSS(file: File): Promise<string> {
|
|
84
|
+
// 1. 跟你们后端拿 STS 临时凭证
|
|
85
|
+
const sts = await fetch('/api/oss/sts', { credentials: 'include' }).then(r => r.json())
|
|
86
|
+
// 期望字段:accessKeyId / accessKeySecret / securityToken / region / bucket / host / dir
|
|
87
|
+
const { accessKeyId, accessKeySecret, securityToken, region, bucket, host, dir } = sts
|
|
88
|
+
|
|
89
|
+
// 2. 客户端压缩一下,避免撞 60s 超时
|
|
90
|
+
const compressed = await compressIfNeeded(file, 30 * 1024 * 1024)
|
|
91
|
+
|
|
92
|
+
// 3. 直传 OSS
|
|
93
|
+
const oss = new OSS({
|
|
94
|
+
accessKeyId, accessKeySecret, stsToken: securityToken,
|
|
95
|
+
bucket, region, secure: true,
|
|
96
|
+
})
|
|
97
|
+
const filename = `${dir}/${Date.now()}_${compressed.name}`
|
|
98
|
+
await oss.put(filename, compressed, {
|
|
99
|
+
headers: { 'x-oss-object-acl': 'public-read' },
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// 4. 必须返回公网可访问的 URL
|
|
103
|
+
return `${host}/${filename}`
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
<CanvasBoard imageUpload={uploadToOSS} />
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
> STS 接口必须保证返回的 `host` + 文件路径能在浏览器里直接 GET 到,并且对应 OSS 桶回 **正确的 CORS 头**。
|
|
110
|
+
|
|
111
|
+
### 场景 3:暂未接入上传服务
|
|
112
|
+
|
|
113
|
+
不传 `imageUpload` 也能用 —— SDK 会走 `URL.createObjectURL(file)` 本地兜底,图片以 **`temporary: true`** 标记。**但**:刷新页面图片即丢失。SDK 会自动弹「已插入临时图片(未配置上传接口,刷新后会丢失)」toast 提示用户。
|
|
114
|
+
|
|
115
|
+
接入方在保存数据前可调用 `editor.hasTemporaryImages()` 检测并提示用户:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
if (editor.hasTemporaryImages()) {
|
|
119
|
+
// 让用户先上传完再保存,或者保存时提醒刷新会丢
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 四、调用链速览(接入方排查用)
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Toolbar「图片」按钮 ─► onInsertImage(files)
|
|
127
|
+
│
|
|
128
|
+
▼
|
|
129
|
+
CanvasBoard (imageUpload?: ImageUploadOption)
|
|
130
|
+
│
|
|
131
|
+
▼
|
|
132
|
+
editor.insertImageFiles(files, at)
|
|
133
|
+
│
|
|
134
|
+
▼
|
|
135
|
+
Editor.insertImageFile(file, at) ← packages/core/src/editor/Editor.ts
|
|
136
|
+
│
|
|
137
|
+
┌─────────┴─────────┐
|
|
138
|
+
配了 imageUploadOption 没配(默认)
|
|
139
|
+
│ │
|
|
140
|
+
▼ ▼
|
|
141
|
+
runUploader(option, file) URL.createObjectURL(file)
|
|
142
|
+
─► 拿远端 URL ─► blob:xxx(temporary:true)
|
|
143
|
+
│ │
|
|
144
|
+
└─────────┬───────────┘
|
|
145
|
+
▼
|
|
146
|
+
loadImage(src) → ImageShape
|
|
147
|
+
▼
|
|
148
|
+
src 入画布(不是 base64)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
三条触发路径都走同一通道:
|
|
152
|
+
|
|
153
|
+
| 入口 | 代码位置(按符号定位,行号会漂移) |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| 工具栏「图片」按钮 | `Toolbar.tsx` → `handleImagePicked`(隐藏 `<input type="file">` 的 `onChange`) |
|
|
156
|
+
| 拖拽图片到画布 | `CanvasBoard.tsx` → `onDrop` → `editor.insertImageFiles(dropped, at)` |
|
|
157
|
+
| 粘贴图片 | `CanvasBoard.tsx` → 粘贴处理 → `editor.insertImageFiles(files)`(失败经 `imageError` UI 通道回流) |
|
|
158
|
+
|
|
159
|
+
## 五、接 OSS 时最容易踩的 10 个坑
|
|
160
|
+
|
|
161
|
+
| # | 现象 | 根因 / 处理 |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| 1 | 上传完图裂了 | OSS 桶没回 CORS 头。检查桶的「跨域设置」:允许源 `*`(或具体域名)、允许方法 `GET/HEAD/PUT/POST`、允许头 `*` |
|
|
164
|
+
| 2 | `ImageUploadConfig.headers` 加 `Authorization` 后浏览器报错 | 浏览器会先发 CORS 预检,队友接口没回 `Access-Control-Allow-Headers`。要么后端放开,要么改走 `ImageUploader` 函数自己 fetch |
|
|
165
|
+
| 3 | 60 秒超时 | 大图直传。压缩后再上传,或调大 `timeoutMs: 180000` |
|
|
166
|
+
| 4 | 一次选 20 张图全失败 | 并发数太高被 OSS 限流。自定义 `ImageUploader` 内做并发限流(如 p-limit) |
|
|
167
|
+
| 5 | 上传报错后用户重试不了 | SDK 不内置重试,在 `ImageUploader` 内自己加 |
|
|
168
|
+
| 6 | 刷新后图全没了 | 拿到的是 `blob:` 本地地址或返回的 URL 不公网可访问。`editor.hasTemporaryImages()` 帮你在保存前检测 |
|
|
169
|
+
| 7 | 客户端工具菜单「另存为图片」导出 PNG 失败 | OSS 没配 CORS 头,canvas 被污染。用 `setImageCrossOrigin(null)` 可暂解,但会失去 PNG/SVG 导出能力 |
|
|
170
|
+
| 8 | 自动探测 URL 拿错了字段 | 返回 JSON 里恰好有非图片含义的 `url` 字段。**显式配 `responseUrlPath`** |
|
|
171
|
+
| 9 | 拖拽多个文件只插入一张 | `CanvasBoard.tsx` 的 `onDrop` 已过滤非图片。检查 `file.type` 是否正确 |
|
|
172
|
+
| 10 | 大于 30 MB 静默失败 | 不静默,会抛 `image.tooLarge:`,前端 toast 用 `image.tooLarge` 文案显式提示用户。要调大用 `maxSizeBytes` |
|
|
173
|
+
|
|
174
|
+
## 六、自检 checklist(上线前过一遍)
|
|
175
|
+
|
|
176
|
+
- [ ] OSS 桶已配 CORS
|
|
177
|
+
- [ ] STS 接口走自家鉴权(不依赖前端 cookie)
|
|
178
|
+
- [ ] 返回的图片 URL 公网可访问,浏览器 GET 200
|
|
179
|
+
- [ ] 上传 > 30 MB 的图被拒绝(toast 提示用户)
|
|
180
|
+
- [ ] 上传 > 60s 的请求会超时(确认是自己调的 60s 还是后端更快超时)
|
|
181
|
+
- [ ] 上传完 → 刷新页面 → 图片还在(验证不是 `blob:`)
|
|
182
|
+
- [ ] 保存文档前调用 `editor.hasTemporaryImages()` 提示用户
|
|
183
|
+
- [ ] `image.tooLarge` 文案在你们支持的语言里都翻译到位(默认带 7 种语言,扩展见 `packages/core/src/i18n.ts`)
|
|
184
|
+
|
|
185
|
+
## 七、相关导出(来自 `drawui-core`)
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import {
|
|
189
|
+
Editor,
|
|
190
|
+
DEFAULT_IMAGE_MAX_SIZE_BYTES, // 30 * 1024 * 1024
|
|
191
|
+
type ImageUploadOption, // 配置 | 函数,二选一
|
|
192
|
+
type ImageUploadConfig, // url / method / headers / responseUrlPath / timeoutMs / maxSizeBytes ...
|
|
193
|
+
type ImageUploader, // (file: File) => Promise<string>
|
|
194
|
+
isUploaderFunction,
|
|
195
|
+
parseUploadResponse, // 解析后端响应文本 → URL(业务方自实现上传函数时可复用)
|
|
196
|
+
} from 'drawui-core'
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
核心文件:
|
|
200
|
+
|
|
201
|
+
- `packages/core/src/imageUpload.ts`:上传通道定义 + fetch 实现
|
|
202
|
+
- `packages/core/src/editor/Editor.ts`:`insertImageFile` / `insertImageFiles`(带 30 MB 闸门)
|
|
203
|
+
- `packages/core/src/imageStore.ts`:图片加载、缓存、跨域处理
|
|
204
|
+
- `packages/react/src/components/CanvasBoard.tsx`:`imageUpload` prop + toast 文案
|
|
205
|
+
- `packages/core/src/i18n.ts`:多语言文案(含新增的 `image.tooLarge`)
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
基于 [drawui-core](https://www.npmjs.com/package/drawui-core) 的 React 封装,提供开箱即用的画布组件。
|
|
6
6
|
|
|
7
|
-
> 🛠 **图片上传对接**(接 OSS /
|
|
7
|
+
> 🛠 **图片上传对接**(接 OSS / 自建后端):完整指南随包发布,安装后直接打开 `node_modules/drawui-react/IMAGE_UPLOAD.md` 查看。含 `imageUpload` prop 的两种通道(`ImageUploadConfig` 与 `ImageUploader` 函数)、30 MB 体积上限、60 s 超时、OSS CORS 与 STS 直传示例。
|
|
8
8
|
|
|
9
9
|
## 安装
|
|
10
10
|
|
|
@@ -61,6 +61,25 @@ export function App() {
|
|
|
61
61
|
|
|
62
62
|
## 更新日志
|
|
63
63
|
|
|
64
|
+
### v0.5.3
|
|
65
|
+
|
|
66
|
+
> 主题:**继承 core 的连线避让 / 线段手柄 / 橡皮擦渐隐**(依赖 `drawui-core@0.5.3`)
|
|
67
|
+
|
|
68
|
+
- 🧭 **连线不再压线**:绕行路由随 core 生效 —— 从右边缘出线、目标在左边时,末段不再横穿目标图形。
|
|
69
|
+
- 🎚️ **线段手柄收敛**:只有折线与直角折线会显示可拖动的线段手柄,直线与曲线移除(绘制与命中都关掉)。
|
|
70
|
+
- 🫥 **橡皮擦渐隐**:擦除时图形 200ms 内淡出再消失,React 层无需任何配置;`CanvasBoard` 未改动。
|
|
71
|
+
- 📄 `IMAGE_UPLOAD.md` 入口说明改为「随包发布,安装后在 `node_modules/drawui-react/` 下查看」。
|
|
72
|
+
|
|
73
|
+
### v0.5.2
|
|
74
|
+
|
|
75
|
+
> 主题:**思维导图升降层级入口 + 拖拽换层级提示**(依赖 `drawui-core@0.5.2`)
|
|
76
|
+
|
|
77
|
+
- ⬆️ **悬浮样式条新增「层级」入口**:选中单个思维导图且它存在活动节点时,底部悬浮样式条(原本 4 个图标:填充 / 边框 / 文字 / 高亮)多出第 5 个「层级」按钮,点开含「升一级 / 升两级」,按当前节点深度自动置灰。**单击任意节点即可触发**(单击本就会把该节点设为活动节点,无需先双击)。
|
|
78
|
+
- 🖱️ **拖拽换层级**:把节点拖到**另一个节点框内部** → 成为它的**子节点**;拖到**节点框外侧** → 成为它的**同方向兄弟**。
|
|
79
|
+
- 🟦 **拖拽落点提示**:给「落点框将来挂靠的父节点」描虚线环,并画一条与真实父子连线同款的贝塞尔虚线接到落点占位框。
|
|
80
|
+
- 🫥 **拖拽时隐藏全部浮动 chrome**:拖任意图形(移动 / 缩放 / 旋转…)时,**顶部工具栏 + 底部悬浮样式条 + 表格浮动条**同时隐藏,松手恢复(手型平移不隐藏)。
|
|
81
|
+
- 📦 依赖的 `drawui-core` 同步升级到 `0.5.2`。
|
|
82
|
+
|
|
64
83
|
### v0.5.1
|
|
65
84
|
|
|
66
85
|
> 主题:**思维导图四方向布局与交互重做**(依赖 `drawui-core@0.5.1`)
|
|
@@ -79,7 +98,7 @@ export function App() {
|
|
|
79
98
|
- ⏱ **上传超时 30 s → 60 s**:默认 `timeoutMs` 从 30000 调整为 60000。
|
|
80
99
|
- 🧰 **`imageUpload` 现在支持两种通道**:`ImageUploadConfig`(配 `{ url, method, headers, responseUrlPath, timeoutMs, maxSizeBytes }`)或 `ImageUploader` 函数(`(file: File) => Promise<string>`),函数优先级高于配置。
|
|
81
100
|
- 🌐 **多语言新增 `image.tooLarge` 文案**:7 种语言全部同步,体积超限时 toast 用对应语言提示用户。
|
|
82
|
-
- 📄
|
|
101
|
+
- 📄 **图片上传对接指南**:见 `node_modules/drawui-react/IMAGE_UPLOAD.md`(随包发布)。
|
|
83
102
|
|
|
84
103
|
### v0.4.2
|
|
85
104
|
|
|
@@ -247,6 +266,25 @@ export function App() {
|
|
|
247
266
|
|
|
248
267
|
## Changelog
|
|
249
268
|
|
|
269
|
+
### v0.5.3
|
|
270
|
+
|
|
271
|
+
> Theme: **inherits core's connector detour, narrower segment handles and eraser fade-out** (depends on `drawui-core@0.5.3`)
|
|
272
|
+
|
|
273
|
+
- 🧭 **Connectors no longer overlap shapes**: detour routing from core — exiting the right edge towards a target on the left no longer runs the last leg through the target.
|
|
274
|
+
- 🎚️ **Segment handles narrowed**: only polyline and orthogonal connectors show draggable segment handles; straight and curve connectors drop them (both drawing and hit-testing).
|
|
275
|
+
- 🫥 **Eraser fade-out**: shapes fade over 200 ms before being removed. No React API changes; `CanvasBoard` is untouched.
|
|
276
|
+
- 📄 The `IMAGE_UPLOAD.md` entry now points at `node_modules/drawui-react/` instead of a relative link.
|
|
277
|
+
|
|
278
|
+
### v0.5.2
|
|
279
|
+
|
|
280
|
+
> Theme: **Mind map level controls + drag-to-re-parent hints** (depends on `drawui-core@0.5.2`)
|
|
281
|
+
|
|
282
|
+
- ⬆️ **New "Level" entry in the floating style bar**: when a single mind map is selected and has an active node, the floating bar (previously four icons: fill / stroke / text / highlight) gains a fifth **Level** button. It opens a popover with **Promote** / **Promote 2**, auto-disabled by the node's depth. **A single click on any node is enough** — clicking already makes that node active, no double-click required.
|
|
283
|
+
- 🖱️ **Drag to re-parent**: drop a node **inside** another node's box → it becomes that node's **child**; drop **outside** the box → it becomes that node's **same-direction sibling**.
|
|
284
|
+
- 🟦 **Drop hints**: the node the placeholder will hang under is outlined with a dashed ring, with a dashed bézier (same style as real parent-child links) connecting it to the placeholder box.
|
|
285
|
+
- 🫥 **All floating chrome hides while dragging**: dragging any shape (move / resize / rotate…) hides the **top toolbar, the floating style bar and the table toolbar** at once, restoring them on release (hand panning excluded).
|
|
286
|
+
- 📦 Bundled `drawui-core` is bumped to `0.5.2`.
|
|
287
|
+
|
|
250
288
|
### v0.5.1
|
|
251
289
|
|
|
252
290
|
> Theme: **Mind map four-direction layout & interaction rework** (depends on `drawui-core@0.5.1`)
|
|
@@ -265,7 +303,7 @@ export function App() {
|
|
|
265
303
|
- ⏱ **Upload timeout 30 s → 60 s**: default `timeoutMs` bumped from 30000 to 60000.
|
|
266
304
|
- 🧰 **`imageUpload` now accepts two channels**: `ImageUploadConfig` (with `{ url, method, headers, responseUrlPath, timeoutMs, maxSizeBytes }`) **or** an `ImageUploader` function (`(file: File) => Promise<string>`); the function takes priority over the config.
|
|
267
305
|
- 🌐 **`image.tooLarge` localized**: added in all 7 supported languages so the size-cap toast always uses the user's language.
|
|
268
|
-
- 📄 **Image upload integration guide**: see
|
|
306
|
+
- 📄 **Image upload integration guide**: see `node_modules/drawui-react/IMAGE_UPLOAD.md` (ships with the package).
|
|
269
307
|
|
|
270
308
|
### v0.4.2
|
|
271
309
|
|