djm-ui 0.67.4 → 0.73.0
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/CHANGELOG.md +116 -0
- package/README.md +38 -2
- package/dist/djm-ui.cjs +1625 -803
- package/dist/djm-ui.cjs.map +4 -4
- package/dist/djm-ui.css +1043 -41
- package/dist/djm-ui.esm.js +1581 -761
- package/dist/djm-ui.esm.js.map +4 -4
- package/dist/djm-ui.esm.min.js +439 -247
- package/dist/djm-ui.min.cjs +439 -247
- package/dist/djm-ui.min.css +2 -2
- package/dist/djm-ui.umd.js +1104 -285
- package/dist/djm-ui.umd.min.js +439 -247
- package/dist/mcp/manifest.json +12300 -0
- package/dist/mcp/server.js +90 -0
- package/package.json +12 -4
- package/src/components/drawer/index.js +4 -2
- package/src/components/icon/index.js +13 -1
- package/src/components/modal/index.js +4 -2
- package/src/components/progress/index.js +72 -3
- package/src/components/rich-editor/index.js +724 -61
- package/src/components/spin/index.js +69 -22
- package/src/index.js +2 -1
- package/src/locale/en-US.js +33 -1
- package/src/locale/zh-CN.js +33 -1
- package/src/styles/base.css +2 -3
- package/src/styles/components/button.css +2 -1
- package/src/styles/components/console.css +5 -0
- package/src/styles/components/content.css +517 -0
- package/src/styles/components/feedback.css +46 -0
- package/src/styles/components/form.css +5 -0
- package/src/styles/components/glass.css +58 -0
- package/src/styles/components/layout.css +326 -0
- package/src/styles/components/media-picker.css +3 -3
- package/src/styles/components/menu.css +2 -1
- package/src/styles/components/org-picker.css +1 -1
- package/src/styles/components/responsive.css +86 -0
- package/src/styles/components/rich-editor.css +206 -7
- package/src/styles/components/skin.css +54 -0
- package/src/styles/components/spin.css +156 -4
- package/src/styles/components/template.css +5 -0
- package/src/styles/index.css +2 -0
- package/src/styles/theme-dark.css +5 -0
- package/src/styles/tokens.css +13 -0
- package/src/theme/index.js +62 -0
- package/src/utils/sanitize-html.js +44 -6
- package/types/index.d.ts +17 -0
|
@@ -17,7 +17,13 @@ const TAGS = new Set([
|
|
|
17
17
|
])
|
|
18
18
|
|
|
19
19
|
// 通用属性
|
|
20
|
-
const GLOBAL_ATTRS = new Set(['class', 'title'])
|
|
20
|
+
const GLOBAL_ATTRS = new Set(['class', 'title', 'style'])
|
|
21
|
+
|
|
22
|
+
// 富文本用到的内联样式白名单:只放行排版类属性,避免靠样式做定位或引外部资源
|
|
23
|
+
const STYLE_PROPS = new Set([
|
|
24
|
+
'color', 'background-color', 'font-size', 'font-weight', 'font-style',
|
|
25
|
+
'text-decoration', 'text-align', 'text-indent', 'line-height'
|
|
26
|
+
])
|
|
21
27
|
|
|
22
28
|
// 各标签额外允许的属性
|
|
23
29
|
const TAG_ATTRS = {
|
|
@@ -28,13 +34,39 @@ const TAG_ATTRS = {
|
|
|
28
34
|
td: new Set(['colspan', 'rowspan'])
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
// 逐条过滤样式声明,丢掉白名单之外的属性与可疑取值
|
|
38
|
+
function cleanStyle (value) {
|
|
39
|
+
return String(value || '')
|
|
40
|
+
.split(';')
|
|
41
|
+
.map((item) => {
|
|
42
|
+
const index = item.indexOf(':')
|
|
43
|
+
if (index === -1) return ''
|
|
44
|
+
const name = item.slice(0, index).trim().toLowerCase()
|
|
45
|
+
const val = item.slice(index + 1).trim()
|
|
46
|
+
if (!STYLE_PROPS.has(name)) return ''
|
|
47
|
+
if (/url\s*\(|expression\s*\(|javascript:/i.test(val)) return ''
|
|
48
|
+
return name + ': ' + val
|
|
49
|
+
})
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.join('; ')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 允许的协议:相对地址没有协议,直接放行
|
|
55
|
+
const SAFE_SCHEMES = new Set(['http', 'https', 'mailto', 'tel'])
|
|
56
|
+
|
|
31
57
|
function safeUrl (value, tag) {
|
|
32
58
|
// 浏览器解析 URL 时会忽略换行、制表符等控制字符,先去掉再判断协议
|
|
33
|
-
const url = String(value || '').replace(/[\u0000-\u0020]+/g, '')
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return true
|
|
59
|
+
const url = String(value || '').replace(/[\u0000-\u0020]+/g, '')
|
|
60
|
+
const scheme = url.match(/^([a-z][a-z0-9+.-]*):/i)
|
|
61
|
+
if (!scheme) return true
|
|
62
|
+
const name = scheme[1].toLowerCase()
|
|
63
|
+
if (SAFE_SCHEMES.has(name)) return true
|
|
64
|
+
// 图片额外允许 blob 与 data:image;data:text/html 这类一律拒绝
|
|
65
|
+
if (tag === 'img') {
|
|
66
|
+
if (name === 'blob') return true
|
|
67
|
+
if (name === 'data' && /^data:image\//i.test(url)) return true
|
|
68
|
+
}
|
|
69
|
+
return false
|
|
38
70
|
}
|
|
39
71
|
|
|
40
72
|
function cleanNode (node) {
|
|
@@ -63,6 +95,12 @@ function cleanNode (node) {
|
|
|
63
95
|
child.removeAttribute(attr.name)
|
|
64
96
|
return
|
|
65
97
|
}
|
|
98
|
+
if (name === 'style') {
|
|
99
|
+
const style = cleanStyle(attr.value)
|
|
100
|
+
if (style) child.setAttribute('style', style)
|
|
101
|
+
else child.removeAttribute('style')
|
|
102
|
+
return
|
|
103
|
+
}
|
|
66
104
|
if ((name === 'href' || name === 'src') && !safeUrl(attr.value, tag)) {
|
|
67
105
|
child.removeAttribute(attr.name)
|
|
68
106
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -133,10 +133,13 @@ export const DjmCard: DefineComponent<{
|
|
|
133
133
|
|
|
134
134
|
export const DjmProgress: DefineComponent<{
|
|
135
135
|
percent?: number
|
|
136
|
+
type?: 'line' | 'circle'
|
|
136
137
|
status?: '' | 'success' | 'error' | 'warning'
|
|
137
138
|
showText?: boolean
|
|
138
139
|
strokeWidth?: number
|
|
139
140
|
color?: string
|
|
141
|
+
size?: number
|
|
142
|
+
label?: string
|
|
140
143
|
}>
|
|
141
144
|
|
|
142
145
|
export const DjmSkeleton: DefineComponent<{
|
|
@@ -312,7 +315,11 @@ export const DjmAlert: DefineComponent<{
|
|
|
312
315
|
export const DjmSpin: DefineComponent<{
|
|
313
316
|
spinning?: boolean
|
|
314
317
|
size?: string
|
|
318
|
+
type?: 'ring' | 'dots' | 'bars' | 'pulse'
|
|
315
319
|
tip?: string
|
|
320
|
+
delay?: number
|
|
321
|
+
fullscreen?: boolean
|
|
322
|
+
color?: string
|
|
316
323
|
}>
|
|
317
324
|
|
|
318
325
|
export const DjmPopconfirm: DefineComponent<{
|
|
@@ -944,6 +951,7 @@ export const DjmModal: DefineComponent<{
|
|
|
944
951
|
showClose?: boolean
|
|
945
952
|
closeOnEsc?: boolean
|
|
946
953
|
fullscreen?: boolean
|
|
954
|
+
glass?: boolean
|
|
947
955
|
}, {}, {}, {}, {}, {}, {}, DjmModalEmits>
|
|
948
956
|
|
|
949
957
|
export const DjmDrawer: DefineComponent<{
|
|
@@ -954,6 +962,7 @@ export const DjmDrawer: DefineComponent<{
|
|
|
954
962
|
maskClosable?: boolean
|
|
955
963
|
showClose?: boolean
|
|
956
964
|
closeOnEsc?: boolean
|
|
965
|
+
glass?: boolean
|
|
957
966
|
}, {}, {}, {}, {}, {}, {}, DjmModalEmits>
|
|
958
967
|
|
|
959
968
|
export type DjmConfirmDialogEmits = {
|
|
@@ -1117,6 +1126,7 @@ export const DjmTreeSelect: DefineComponent<{
|
|
|
1117
1126
|
|
|
1118
1127
|
export type DjmRichEditorEmits = {
|
|
1119
1128
|
'update:modelValue': (html: string) => void
|
|
1129
|
+
'upload-error': (payload: { file: File, message: string }) => void
|
|
1120
1130
|
}
|
|
1121
1131
|
|
|
1122
1132
|
export const DjmRichEditor: DefineComponent<{
|
|
@@ -1125,6 +1135,13 @@ export const DjmRichEditor: DefineComponent<{
|
|
|
1125
1135
|
minHeight?: number
|
|
1126
1136
|
sanitize?: boolean
|
|
1127
1137
|
disabled?: boolean
|
|
1138
|
+
toolbar?: 'simple' | 'basic' | 'full' | Array<'history' | 'format' | 'inline' | 'color' | 'align' | 'list' | 'insert' | 'view'>
|
|
1139
|
+
uploadImage?: ((file: File) => Promise<string | { url: string }>) | null
|
|
1140
|
+
media?: Array<string | { id?: string | number, url: string, name?: string }>
|
|
1141
|
+
accept?: string
|
|
1142
|
+
maxImageSize?: number
|
|
1143
|
+
multiple?: boolean
|
|
1144
|
+
showCount?: boolean
|
|
1128
1145
|
}, {}, {}, {}, {}, {}, {}, DjmRichEditorEmits>
|
|
1129
1146
|
|
|
1130
1147
|
/* ---------------- 业务组件 ---------------- */
|