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.
Files changed (46) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +38 -2
  3. package/dist/djm-ui.cjs +1625 -803
  4. package/dist/djm-ui.cjs.map +4 -4
  5. package/dist/djm-ui.css +1043 -41
  6. package/dist/djm-ui.esm.js +1581 -761
  7. package/dist/djm-ui.esm.js.map +4 -4
  8. package/dist/djm-ui.esm.min.js +439 -247
  9. package/dist/djm-ui.min.cjs +439 -247
  10. package/dist/djm-ui.min.css +2 -2
  11. package/dist/djm-ui.umd.js +1104 -285
  12. package/dist/djm-ui.umd.min.js +439 -247
  13. package/dist/mcp/manifest.json +12300 -0
  14. package/dist/mcp/server.js +90 -0
  15. package/package.json +12 -4
  16. package/src/components/drawer/index.js +4 -2
  17. package/src/components/icon/index.js +13 -1
  18. package/src/components/modal/index.js +4 -2
  19. package/src/components/progress/index.js +72 -3
  20. package/src/components/rich-editor/index.js +724 -61
  21. package/src/components/spin/index.js +69 -22
  22. package/src/index.js +2 -1
  23. package/src/locale/en-US.js +33 -1
  24. package/src/locale/zh-CN.js +33 -1
  25. package/src/styles/base.css +2 -3
  26. package/src/styles/components/button.css +2 -1
  27. package/src/styles/components/console.css +5 -0
  28. package/src/styles/components/content.css +517 -0
  29. package/src/styles/components/feedback.css +46 -0
  30. package/src/styles/components/form.css +5 -0
  31. package/src/styles/components/glass.css +58 -0
  32. package/src/styles/components/layout.css +326 -0
  33. package/src/styles/components/media-picker.css +3 -3
  34. package/src/styles/components/menu.css +2 -1
  35. package/src/styles/components/org-picker.css +1 -1
  36. package/src/styles/components/responsive.css +86 -0
  37. package/src/styles/components/rich-editor.css +206 -7
  38. package/src/styles/components/skin.css +54 -0
  39. package/src/styles/components/spin.css +156 -4
  40. package/src/styles/components/template.css +5 -0
  41. package/src/styles/index.css +2 -0
  42. package/src/styles/theme-dark.css +5 -0
  43. package/src/styles/tokens.css +13 -0
  44. package/src/theme/index.js +62 -0
  45. package/src/utils/sanitize-html.js +44 -6
  46. 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, '').toLowerCase()
34
- if (url.startsWith('javascript:') || url.startsWith('vbscript:')) return false
35
- // data: 只允许图片,且只能用于 img,避免链接跳到可执行的 SVG
36
- if (url.startsWith('data:')) return tag === 'img' && url.startsWith('data:image/')
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
  /* ---------------- 业务组件 ---------------- */