@dsh-plugin/dsh-ui-components 0.0.1 → 0.1.0-dev.43616582648

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 (65) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +21 -21
  3. package/README.md +136 -136
  4. package/README.zh_CN.md +136 -136
  5. package/docs/tokens.md +67 -67
  6. package/lib/basic/form.js +49 -49
  7. package/lib/basic/styles.js +391 -391
  8. package/lib/composites/styles.js +427 -427
  9. package/lib/data/styles.js +257 -257
  10. package/lib/display/styles.js +310 -310
  11. package/lib/feedback/styles.js +228 -228
  12. package/lib/foundation/bridge.js +203 -203
  13. package/lib/navigation/styles.js +417 -417
  14. package/package.json +104 -104
  15. package/scripts/check-size.mjs +69 -69
  16. package/scripts/dump-npm-latest.mjs +59 -59
  17. package/scripts/gen-host-tokens.mjs +61 -61
  18. package/scripts/gen-icons.mjs +188 -178
  19. package/scripts/verify-no-literal-colors.mjs +63 -63
  20. package/scripts/verify-tokens.mjs +135 -135
  21. package/src/basic/button.tsx +76 -76
  22. package/src/basic/form.tsx +187 -187
  23. package/src/basic/icon-button.tsx +66 -66
  24. package/src/basic/index.ts +38 -38
  25. package/src/basic/input.tsx +140 -140
  26. package/src/basic/select.tsx +120 -120
  27. package/src/basic/styles.ts +412 -412
  28. package/src/basic/toggle.tsx +116 -116
  29. package/src/composites/data-view.tsx +189 -189
  30. package/src/composites/index.ts +11 -11
  31. package/src/composites/indicator.tsx +90 -90
  32. package/src/composites/menu-select.tsx +230 -230
  33. package/src/composites/panel.tsx +72 -72
  34. package/src/composites/settings.tsx +80 -80
  35. package/src/composites/styles.ts +450 -450
  36. package/src/data/collection.tsx +71 -71
  37. package/src/data/index.ts +39 -39
  38. package/src/data/info.tsx +89 -89
  39. package/src/data/picker.tsx +113 -113
  40. package/src/data/styles.ts +278 -278
  41. package/src/display/container.tsx +67 -67
  42. package/src/display/feedback.tsx +92 -92
  43. package/src/display/index.ts +44 -44
  44. package/src/display/label.tsx +165 -165
  45. package/src/display/overlay.tsx +103 -103
  46. package/src/display/styles.ts +332 -332
  47. package/src/feedback/global.tsx +110 -110
  48. package/src/feedback/index.ts +19 -19
  49. package/src/feedback/inline.tsx +50 -50
  50. package/src/feedback/panel.tsx +93 -93
  51. package/src/feedback/styles.ts +250 -250
  52. package/src/foundation/bridge.ts +318 -318
  53. package/src/foundation/icons.tsx +315 -315
  54. package/src/foundation/index.ts +33 -33
  55. package/src/foundation/palette.ts +153 -153
  56. package/src/foundation/provider.tsx +62 -62
  57. package/src/foundation/style.ts +63 -63
  58. package/src/foundation/tokens.ts +62 -62
  59. package/src/index.ts +18 -18
  60. package/src/navigation/hierarchy.tsx +82 -82
  61. package/src/navigation/index.ts +21 -21
  62. package/src/navigation/indicator.tsx +125 -125
  63. package/src/navigation/menu.tsx +94 -94
  64. package/src/navigation/segmented.tsx +136 -136
  65. package/src/navigation/styles.ts +438 -438
@@ -1,94 +1,94 @@
1
- /**
2
- * 菜单、下拉与标签页。
3
- *
4
- * @module @dsh-plugin/dsh-ui-components/navigation/menu
5
- */
6
- import * as React from 'react'
7
- import { Arco } from '@dsh-plugin/dsh-loader/client'
8
- import { cx } from '../foundation/style.js'
9
- import { injectNavigationStyles } from './styles.js'
10
-
11
- /** {@link Menu} 的 props。 */
12
- export type MenuProps = React.ComponentPropsWithoutRef<typeof Arco.Menu>
13
-
14
- /**
15
- * 侧边或页面内的菜单。选中项走宿主的选择态填充。
16
- *
17
- * @param props - 见 {@link MenuProps}。
18
- * @returns 菜单元素。
19
- */
20
- export function Menu(props: MenuProps): React.ReactElement {
21
- injectNavigationStyles()
22
- return <Arco.Menu {...props} />
23
- }
24
-
25
- /** {@link MenuItem} 的 props。 */
26
- export type MenuItemProps = React.ComponentPropsWithoutRef<typeof Arco.Menu.Item>
27
-
28
- /**
29
- * 菜单中的一项。
30
- *
31
- * @param props - 见 {@link MenuItemProps}。
32
- * @returns 菜单项元素。
33
- */
34
- export function MenuItem(props: MenuItemProps): React.ReactElement {
35
- injectNavigationStyles()
36
- return <Arco.Menu.Item {...props} />
37
- }
38
-
39
- /** {@link Dropdown} 的 props。 */
40
- export type DropdownProps = React.ComponentPropsWithoutRef<typeof Arco.Dropdown>
41
-
42
- /**
43
- * 附着在触发元素上的下拉菜单。
44
- *
45
- * @param props - 见 {@link DropdownProps}。
46
- * @returns 下拉元素。
47
- */
48
- export function Dropdown(props: DropdownProps): React.ReactElement {
49
- injectNavigationStyles()
50
- return <Arco.Dropdown {...props} />
51
- }
52
-
53
- /** {@link Tabs} 的 props。 */
54
- export type TabsProps = React.ComponentPropsWithoutRef<typeof Arco.Tabs> & {
55
- /**
56
- * 外观。`line` 是默认的下划线标签页;`segment` 渲染为胶囊分段控件,
57
- * 适合在少数几个模式之间切换。
58
- */
59
- appearance?: 'line' | 'segment'
60
- }
61
-
62
- /**
63
- * 标签页。
64
- *
65
- * `Tabs.TabPane` 与 Arco 本身一致,用作子页。
66
- *
67
- * @param props - 见 {@link TabsProps}。
68
- * @returns 标签页元素。
69
- */
70
- function TabsBase({ appearance = 'line', className, ...rest }: TabsProps): React.ReactElement {
71
- injectNavigationStyles()
72
- return (
73
- <Arco.Tabs
74
- {...rest}
75
- className={cx(appearance === 'segment' && 'dsh-tabs--segment', Array.isArray(className) ? className.join(' ') : className)}
76
- />
77
- )
78
- }
79
-
80
- /** {@link TabPane} 的 props。 */
81
- export type TabPaneProps = React.ComponentPropsWithoutRef<typeof Arco.Tabs.TabPane>
82
-
83
- /**
84
- * 标签页中的一页。
85
- *
86
- * 直接取 Arco 的原组件而不是包一层:Arco 通过 `child.type` 识别子页,包一层
87
- * 会让识别失败并静默渲染出空标签栏。
88
- */
89
- export const TabPane: typeof Arco.Tabs.TabPane = Arco.Tabs.TabPane
90
-
91
- /** 带静态子组件的标签页导出,`<Tabs><Tabs.TabPane /></Tabs>` 可直接使用。 */
92
- export const Tabs: typeof TabsBase & { TabPane: typeof Arco.Tabs.TabPane } = Object.assign(TabsBase, {
93
- TabPane: Arco.Tabs.TabPane,
94
- })
1
+ /**
2
+ * 菜单、下拉与标签页。
3
+ *
4
+ * @module @dsh-plugin/dsh-ui-components/navigation/menu
5
+ */
6
+ import * as React from 'react'
7
+ import { Arco } from '@dsh-plugin/dsh-loader/client'
8
+ import { cx } from '../foundation/style.js'
9
+ import { injectNavigationStyles } from './styles.js'
10
+
11
+ /** {@link Menu} 的 props。 */
12
+ export type MenuProps = React.ComponentPropsWithoutRef<typeof Arco.Menu>
13
+
14
+ /**
15
+ * 侧边或页面内的菜单。选中项走宿主的选择态填充。
16
+ *
17
+ * @param props - 见 {@link MenuProps}。
18
+ * @returns 菜单元素。
19
+ */
20
+ export function Menu(props: MenuProps): React.ReactElement {
21
+ injectNavigationStyles()
22
+ return <Arco.Menu {...props} />
23
+ }
24
+
25
+ /** {@link MenuItem} 的 props。 */
26
+ export type MenuItemProps = React.ComponentPropsWithoutRef<typeof Arco.Menu.Item>
27
+
28
+ /**
29
+ * 菜单中的一项。
30
+ *
31
+ * @param props - 见 {@link MenuItemProps}。
32
+ * @returns 菜单项元素。
33
+ */
34
+ export function MenuItem(props: MenuItemProps): React.ReactElement {
35
+ injectNavigationStyles()
36
+ return <Arco.Menu.Item {...props} />
37
+ }
38
+
39
+ /** {@link Dropdown} 的 props。 */
40
+ export type DropdownProps = React.ComponentPropsWithoutRef<typeof Arco.Dropdown>
41
+
42
+ /**
43
+ * 附着在触发元素上的下拉菜单。
44
+ *
45
+ * @param props - 见 {@link DropdownProps}。
46
+ * @returns 下拉元素。
47
+ */
48
+ export function Dropdown(props: DropdownProps): React.ReactElement {
49
+ injectNavigationStyles()
50
+ return <Arco.Dropdown {...props} />
51
+ }
52
+
53
+ /** {@link Tabs} 的 props。 */
54
+ export type TabsProps = React.ComponentPropsWithoutRef<typeof Arco.Tabs> & {
55
+ /**
56
+ * 外观。`line` 是默认的下划线标签页;`segment` 渲染为胶囊分段控件,
57
+ * 适合在少数几个模式之间切换。
58
+ */
59
+ appearance?: 'line' | 'segment'
60
+ }
61
+
62
+ /**
63
+ * 标签页。
64
+ *
65
+ * `Tabs.TabPane` 与 Arco 本身一致,用作子页。
66
+ *
67
+ * @param props - 见 {@link TabsProps}。
68
+ * @returns 标签页元素。
69
+ */
70
+ function TabsBase({ appearance = 'line', className, ...rest }: TabsProps): React.ReactElement {
71
+ injectNavigationStyles()
72
+ return (
73
+ <Arco.Tabs
74
+ {...rest}
75
+ className={cx(appearance === 'segment' && 'dsh-tabs--segment', Array.isArray(className) ? className.join(' ') : className)}
76
+ />
77
+ )
78
+ }
79
+
80
+ /** {@link TabPane} 的 props。 */
81
+ export type TabPaneProps = React.ComponentPropsWithoutRef<typeof Arco.Tabs.TabPane>
82
+
83
+ /**
84
+ * 标签页中的一页。
85
+ *
86
+ * 直接取 Arco 的原组件而不是包一层:Arco 通过 `child.type` 识别子页,包一层
87
+ * 会让识别失败并静默渲染出空标签栏。
88
+ */
89
+ export const TabPane: typeof Arco.Tabs.TabPane = Arco.Tabs.TabPane
90
+
91
+ /** 带静态子组件的标签页导出,`<Tabs><Tabs.TabPane /></Tabs>` 可直接使用。 */
92
+ export const Tabs: typeof TabsBase & { TabPane: typeof Arco.Tabs.TabPane } = Object.assign(TabsBase, {
93
+ TabPane: Arco.Tabs.TabPane,
94
+ })
@@ -1,136 +1,136 @@
1
- /**
2
- * 分段控件。
3
- *
4
- * 与 `Pill` 的差别同宿主一致:`Pill` 是一组各自独立的开关,`SegmentedControl`
5
- * 是少数互斥模式中的一个选择,带 tablist 键盘语义(方向键在段之间移动,只有
6
- * 选中段在 Tab 序列里)。
7
- *
8
- * 指示条的位置由段数与选中下标通过 CSS 变量推导,不测量 DOM。
9
- *
10
- * @module @dsh-plugin/dsh-ui-components/navigation/segmented
11
- */
12
- import * as React from 'react'
13
- import { cx } from '../foundation/style.js'
14
- import { injectNavigationStyles } from './styles.js'
15
-
16
- /** 一个分段。 */
17
- export interface Segment {
18
- /** 该段的值。 */
19
- value: string
20
- /** 展示文本。 */
21
- label: React.ReactNode
22
- /** 不可选。 */
23
- disabled?: boolean
24
- /** 禁用原因的悬停提示。 */
25
- disabledReason?: string
26
- }
27
-
28
- /** {@link SegmentedControl} 的 props。 */
29
- export interface SegmentedControlProps {
30
- /** 分段列表,至少两个。 */
31
- items: readonly Segment[]
32
- /** 当前选中的值。 */
33
- value: string
34
- /** 选中项变化时回调。 */
35
- onChange: (value: string) => void
36
- /** 列表的可访问名称。 */
37
- label: string
38
- /** id 前缀,用于生成每段的 id 与它控制的面板 id。 */
39
- id?: string
40
- /** 锁定全部段,用于有操作在途时。 */
41
- disabled?: boolean
42
- /** 撑满父容器宽度,默认按内容收缩。 */
43
- block?: boolean
44
- /** 追加类名。 */
45
- className?: string
46
- }
47
-
48
- /**
49
- * 一组互斥模式的分段切换。
50
- *
51
- * 每段的 id 是 `<id>-<value>`,它控制的面板 id 是 `<id>-<value>-panel`;面板
52
- * 由调用方渲染并用 `aria-labelledby` 指回该段。
53
- *
54
- * @param props - 见 {@link SegmentedControlProps}。
55
- * @returns 带 tablist 语义的分段控件。
56
- */
57
- export function SegmentedControl({
58
- items,
59
- value,
60
- onChange,
61
- label,
62
- id,
63
- disabled,
64
- block,
65
- className,
66
- }: SegmentedControlProps): React.ReactElement {
67
- injectNavigationStyles()
68
-
69
- const selectedIndex = Math.max(0, items.findIndex(item => item.value === value))
70
-
71
- /**
72
- * 方向键、Home、End 在段之间移动。
73
- *
74
- * @param event - 键盘事件。
75
- */
76
- const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
77
- if (disabled === true) return
78
- const delta = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0
79
- const enabled = items.map((item, index) => (item.disabled === true ? -1 : index)).filter(index => index >= 0)
80
- if (enabled.length === 0) return
81
-
82
- let nextIndex: number | undefined
83
- if (delta !== 0) {
84
- const position = enabled.indexOf(selectedIndex)
85
- const base = position >= 0 ? position : 0
86
- nextIndex = enabled[(base + delta + enabled.length) % enabled.length]
87
- } else if (event.key === 'Home') {
88
- nextIndex = enabled[0]
89
- } else if (event.key === 'End') {
90
- nextIndex = enabled[enabled.length - 1]
91
- }
92
-
93
- if (nextIndex === undefined) return
94
- event.preventDefault()
95
- const target = items[nextIndex]
96
- if (target !== undefined) onChange(target.value)
97
- }
98
-
99
- return (
100
- <div
101
- role="tablist"
102
- aria-label={label}
103
- aria-disabled={disabled === true ? true : undefined}
104
- className={cx('dsh-segmented', block === true && 'dsh-segmented--block', className)}
105
- style={
106
- {
107
- '--dsh-segment-count': items.length,
108
- '--dsh-segment-index': selectedIndex,
109
- } as React.CSSProperties
110
- }
111
- onKeyDown={onKeyDown}
112
- >
113
- <span className="dsh-segmented__indicator" aria-hidden="true" />
114
- {items.map(item => {
115
- const selected = item.value === value
116
- return (
117
- <button
118
- key={item.value}
119
- type="button"
120
- role="tab"
121
- id={id === undefined ? undefined : `${id}-${item.value}`}
122
- aria-selected={selected}
123
- aria-controls={id === undefined ? undefined : `${id}-${item.value}-panel`}
124
- tabIndex={selected ? 0 : -1}
125
- disabled={disabled === true || item.disabled === true}
126
- title={item.disabledReason}
127
- className="dsh-segmented__tab"
128
- onClick={() => onChange(item.value)}
129
- >
130
- {item.label}
131
- </button>
132
- )
133
- })}
134
- </div>
135
- )
136
- }
1
+ /**
2
+ * 分段控件。
3
+ *
4
+ * 与 `Pill` 的差别同宿主一致:`Pill` 是一组各自独立的开关,`SegmentedControl`
5
+ * 是少数互斥模式中的一个选择,带 tablist 键盘语义(方向键在段之间移动,只有
6
+ * 选中段在 Tab 序列里)。
7
+ *
8
+ * 指示条的位置由段数与选中下标通过 CSS 变量推导,不测量 DOM。
9
+ *
10
+ * @module @dsh-plugin/dsh-ui-components/navigation/segmented
11
+ */
12
+ import * as React from 'react'
13
+ import { cx } from '../foundation/style.js'
14
+ import { injectNavigationStyles } from './styles.js'
15
+
16
+ /** 一个分段。 */
17
+ export interface Segment {
18
+ /** 该段的值。 */
19
+ value: string
20
+ /** 展示文本。 */
21
+ label: React.ReactNode
22
+ /** 不可选。 */
23
+ disabled?: boolean
24
+ /** 禁用原因的悬停提示。 */
25
+ disabledReason?: string
26
+ }
27
+
28
+ /** {@link SegmentedControl} 的 props。 */
29
+ export interface SegmentedControlProps {
30
+ /** 分段列表,至少两个。 */
31
+ items: readonly Segment[]
32
+ /** 当前选中的值。 */
33
+ value: string
34
+ /** 选中项变化时回调。 */
35
+ onChange: (value: string) => void
36
+ /** 列表的可访问名称。 */
37
+ label: string
38
+ /** id 前缀,用于生成每段的 id 与它控制的面板 id。 */
39
+ id?: string
40
+ /** 锁定全部段,用于有操作在途时。 */
41
+ disabled?: boolean
42
+ /** 撑满父容器宽度,默认按内容收缩。 */
43
+ block?: boolean
44
+ /** 追加类名。 */
45
+ className?: string
46
+ }
47
+
48
+ /**
49
+ * 一组互斥模式的分段切换。
50
+ *
51
+ * 每段的 id 是 `<id>-<value>`,它控制的面板 id 是 `<id>-<value>-panel`;面板
52
+ * 由调用方渲染并用 `aria-labelledby` 指回该段。
53
+ *
54
+ * @param props - 见 {@link SegmentedControlProps}。
55
+ * @returns 带 tablist 语义的分段控件。
56
+ */
57
+ export function SegmentedControl({
58
+ items,
59
+ value,
60
+ onChange,
61
+ label,
62
+ id,
63
+ disabled,
64
+ block,
65
+ className,
66
+ }: SegmentedControlProps): React.ReactElement {
67
+ injectNavigationStyles()
68
+
69
+ const selectedIndex = Math.max(0, items.findIndex(item => item.value === value))
70
+
71
+ /**
72
+ * 方向键、Home、End 在段之间移动。
73
+ *
74
+ * @param event - 键盘事件。
75
+ */
76
+ const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
77
+ if (disabled === true) return
78
+ const delta = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0
79
+ const enabled = items.map((item, index) => (item.disabled === true ? -1 : index)).filter(index => index >= 0)
80
+ if (enabled.length === 0) return
81
+
82
+ let nextIndex: number | undefined
83
+ if (delta !== 0) {
84
+ const position = enabled.indexOf(selectedIndex)
85
+ const base = position >= 0 ? position : 0
86
+ nextIndex = enabled[(base + delta + enabled.length) % enabled.length]
87
+ } else if (event.key === 'Home') {
88
+ nextIndex = enabled[0]
89
+ } else if (event.key === 'End') {
90
+ nextIndex = enabled[enabled.length - 1]
91
+ }
92
+
93
+ if (nextIndex === undefined) return
94
+ event.preventDefault()
95
+ const target = items[nextIndex]
96
+ if (target !== undefined) onChange(target.value)
97
+ }
98
+
99
+ return (
100
+ <div
101
+ role="tablist"
102
+ aria-label={label}
103
+ aria-disabled={disabled === true ? true : undefined}
104
+ className={cx('dsh-segmented', block === true && 'dsh-segmented--block', className)}
105
+ style={
106
+ {
107
+ '--dsh-segment-count': items.length,
108
+ '--dsh-segment-index': selectedIndex,
109
+ } as React.CSSProperties
110
+ }
111
+ onKeyDown={onKeyDown}
112
+ >
113
+ <span className="dsh-segmented__indicator" aria-hidden="true" />
114
+ {items.map(item => {
115
+ const selected = item.value === value
116
+ return (
117
+ <button
118
+ key={item.value}
119
+ type="button"
120
+ role="tab"
121
+ id={id === undefined ? undefined : `${id}-${item.value}`}
122
+ aria-selected={selected}
123
+ aria-controls={id === undefined ? undefined : `${id}-${item.value}-panel`}
124
+ tabIndex={selected ? 0 : -1}
125
+ disabled={disabled === true || item.disabled === true}
126
+ title={item.disabledReason}
127
+ className="dsh-segmented__tab"
128
+ onClick={() => onChange(item.value)}
129
+ >
130
+ {item.label}
131
+ </button>
132
+ )
133
+ })}
134
+ </div>
135
+ )
136
+ }