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

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,62 +1,62 @@
1
- /**
2
- * 组件共用的几何量。
3
- *
4
- * 尺寸取自 DSH 的圆角标准与控制件实测值:标准控件高 36、紧凑控件高 28、
5
- * 输入框高 32;圆角按角色取 `--dsw-radius-*` 的像素等价量。颜色一律由
6
- * `bridge.ts` 里的 CSS 变量承担,本文件只管尺寸与字号。
7
- *
8
- * @module @dsh-plugin/dsh-ui-components/foundation/tokens
9
- */
10
-
11
- /** 组件共用的几何量,单位均为像素。 */
12
- export const G = {
13
- /** 标准控件高度。 */
14
- controlHeight: 36,
15
- /** 紧凑控件高度。 */
16
- controlHeightSm: 28,
17
- /** 输入框高度,介于标准与紧凑之间。 */
18
- inputHeight: 32,
19
- /** 标准圆角,对应 `--dsw-radius-md`。 */
20
- radius: 12,
21
- /** 紧凑圆角,对应 `--dsw-radius-sm`。 */
22
- radiusSm: 8,
23
- /** 大圆角,对应 `--dsw-radius-lg`。 */
24
- radiusLg: 16,
25
- /** 卡片圆角,对应 `--dsw-radius-xl`。 */
26
- radiusXl: 20,
27
- /** 面板圆角,对应 `--dsw-radius-panel`。 */
28
- radiusPanel: 28,
29
- /** 胶囊圆角。 */
30
- radiusPill: 999,
31
- /** 正文基准字号。 */
32
- fontSize: 14,
33
- /** 说明文字字号。 */
34
- fontSizeSm: 12,
35
- /** 正文行高。 */
36
- lineHeight: 22,
37
- /** 说明文字行高。 */
38
- lineHeightSm: 18,
39
- /** 标准间距。 */
40
- gap: 8,
41
- /** 紧凑间距。 */
42
- gapSm: 4,
43
- /** 分区间距。 */
44
- gapLg: 16,
45
- /** 弹出层与窗口上下的最小留白。 */
46
- overlayMargin: 120,
47
- } as const
48
-
49
- /**
50
- * 计算弹出层的最大高度。
51
- *
52
- * 全局规范要求弹出层与窗口顶部、底部各留至少 {@link G.overlayMargin},
53
- * 因此最大高度是视口高度减去两倍留白。
54
- *
55
- * @returns 形如 `calc(100dvh - 240px)` 的高度表达式。
56
- */
57
- export function overlayMaxHeight(): string {
58
- return `calc(100dvh - ${G.overlayMargin * 2}px)`
59
- }
60
-
61
- /** 弹出层最大高度的 CSS 值。 */
62
- export const OVERLAY_MAX_HEIGHT = overlayMaxHeight()
1
+ /**
2
+ * 组件共用的几何量。
3
+ *
4
+ * 尺寸取自 DSH 的圆角标准与控制件实测值:标准控件高 36、紧凑控件高 28、
5
+ * 输入框高 32;圆角按角色取 `--dsw-radius-*` 的像素等价量。颜色一律由
6
+ * `bridge.ts` 里的 CSS 变量承担,本文件只管尺寸与字号。
7
+ *
8
+ * @module @dsh-plugin/dsh-ui-components/foundation/tokens
9
+ */
10
+
11
+ /** 组件共用的几何量,单位均为像素。 */
12
+ export const G = {
13
+ /** 标准控件高度。 */
14
+ controlHeight: 36,
15
+ /** 紧凑控件高度。 */
16
+ controlHeightSm: 28,
17
+ /** 输入框高度,介于标准与紧凑之间。 */
18
+ inputHeight: 32,
19
+ /** 标准圆角,对应 `--dsw-radius-md`。 */
20
+ radius: 12,
21
+ /** 紧凑圆角,对应 `--dsw-radius-sm`。 */
22
+ radiusSm: 8,
23
+ /** 大圆角,对应 `--dsw-radius-lg`。 */
24
+ radiusLg: 16,
25
+ /** 卡片圆角,对应 `--dsw-radius-xl`。 */
26
+ radiusXl: 20,
27
+ /** 面板圆角,对应 `--dsw-radius-panel`。 */
28
+ radiusPanel: 28,
29
+ /** 胶囊圆角。 */
30
+ radiusPill: 999,
31
+ /** 正文基准字号。 */
32
+ fontSize: 14,
33
+ /** 说明文字字号。 */
34
+ fontSizeSm: 12,
35
+ /** 正文行高。 */
36
+ lineHeight: 22,
37
+ /** 说明文字行高。 */
38
+ lineHeightSm: 18,
39
+ /** 标准间距。 */
40
+ gap: 8,
41
+ /** 紧凑间距。 */
42
+ gapSm: 4,
43
+ /** 分区间距。 */
44
+ gapLg: 16,
45
+ /** 弹出层与窗口上下的最小留白。 */
46
+ overlayMargin: 120,
47
+ } as const
48
+
49
+ /**
50
+ * 计算弹出层的最大高度。
51
+ *
52
+ * 全局规范要求弹出层与窗口顶部、底部各留至少 {@link G.overlayMargin},
53
+ * 因此最大高度是视口高度减去两倍留白。
54
+ *
55
+ * @returns 形如 `calc(100dvh - 240px)` 的高度表达式。
56
+ */
57
+ export function overlayMaxHeight(): string {
58
+ return `calc(100dvh - ${G.overlayMargin * 2}px)`
59
+ }
60
+
61
+ /** 弹出层最大高度的 CSS 值。 */
62
+ export const OVERLAY_MAX_HEIGHT = overlayMaxHeight()
package/src/index.ts CHANGED
@@ -1,18 +1,18 @@
1
- /**
2
- * 包出口。
3
- *
4
- * 组件按批次分组再统一从这里导出,调用方只依赖一个入口。图标另有两条通道:
5
- * 根导出的策划命名集,以及 `./icons/<pascal>` 这类逐图标子路径。
6
- *
7
- * 组件需要 DSH 皮肤时,在插件根部挂一次 `DshProvider`;不挂也能渲染,但
8
- * Arco 的浮层会挂到 `body` 下而拿不到 `.dsh-ui` 的变量。
9
- *
10
- * @module @dsh-plugin/dsh-ui-components
11
- */
12
- export * from './foundation/index.js'
13
- export * from './basic/index.js'
14
- export * from './display/index.js'
15
- export * from './feedback/index.js'
16
- export * from './navigation/index.js'
17
- export * from './data/index.js'
18
- export * from './composites/index.js'
1
+ /**
2
+ * 包出口。
3
+ *
4
+ * 组件按批次分组再统一从这里导出,调用方只依赖一个入口。图标另有两条通道:
5
+ * 根导出的策划命名集,以及 `./icons/<pascal>` 这类逐图标子路径。
6
+ *
7
+ * 组件需要 DSH 皮肤时,在插件根部挂一次 `DshProvider`;不挂也能渲染,但
8
+ * Arco 的浮层会挂到 `body` 下而拿不到 `.dsh-ui` 的变量。
9
+ *
10
+ * @module @dsh-plugin/dsh-ui-components
11
+ */
12
+ export * from './foundation/index.js'
13
+ export * from './basic/index.js'
14
+ export * from './display/index.js'
15
+ export * from './feedback/index.js'
16
+ export * from './navigation/index.js'
17
+ export * from './data/index.js'
18
+ export * from './composites/index.js'
@@ -1,82 +1,82 @@
1
- /**
2
- * 页面结构与位置指示:面包屑、分页、步骤条。
3
- *
4
- * @module @dsh-plugin/dsh-ui-components/navigation/hierarchy
5
- */
6
- import * as React from 'react'
7
- import { Arco } from '@dsh-plugin/dsh-loader/client'
8
- import { injectNavigationStyles } from './styles.js'
9
-
10
- /** {@link Breadcrumb} 的 props。 */
11
- export type BreadcrumbProps = React.ComponentPropsWithoutRef<typeof Arco.Breadcrumb>
12
-
13
- /**
14
- * 层级路径。
15
- *
16
- * @param props - 见 {@link BreadcrumbProps}。
17
- * @returns 面包屑元素。
18
- */
19
- export function Breadcrumb(props: BreadcrumbProps): React.ReactElement {
20
- injectNavigationStyles()
21
- return <Arco.Breadcrumb {...props} />
22
- }
23
-
24
- /** {@link BreadcrumbItem} 的 props。 */
25
- export type BreadcrumbItemProps = React.ComponentPropsWithoutRef<typeof Arco.Breadcrumb.Item>
26
-
27
- /**
28
- * 面包屑中的一个节点。
29
- *
30
- * @param props - 见 {@link BreadcrumbItemProps}。
31
- * @returns 面包屑节点元素。
32
- */
33
- export function BreadcrumbItem(props: BreadcrumbItemProps): React.ReactElement {
34
- injectNavigationStyles()
35
- return <Arco.Breadcrumb.Item {...props} />
36
- }
37
-
38
- /** {@link Pagination} 的 props。 */
39
- export type PaginationProps = React.ComponentPropsWithoutRef<typeof Arco.Pagination>
40
-
41
- /**
42
- * 分页器。
43
- *
44
- * @param props - 见 {@link PaginationProps}。
45
- * @returns 分页元素。
46
- */
47
- export function Pagination(props: PaginationProps): React.ReactElement {
48
- injectNavigationStyles()
49
- return <Arco.Pagination {...props} />
50
- }
51
-
52
- /** {@link Steps} 的 props。 */
53
- export type StepsProps = React.ComponentPropsWithoutRef<typeof Arco.Steps>
54
-
55
- /**
56
- * 步骤条。
57
- *
58
- * `<Steps.Step />` 与 Arco 本身一致,用作单步。
59
- *
60
- * @param props - 见 {@link StepsProps}。
61
- * @returns 步骤条元素。
62
- */
63
- function StepsBase(props: StepsProps): React.ReactElement {
64
- injectNavigationStyles()
65
- return <Arco.Steps {...props} />
66
- }
67
-
68
- /** {@link Step} 的 props。 */
69
- export type StepProps = React.ComponentPropsWithoutRef<typeof Arco.Steps.Step>
70
-
71
- /**
72
- * 步骤条中的一步。
73
- *
74
- * 这里直接取 Arco 的原组件而不是包一层:Arco 通过 `child.type` 识别子步骤,
75
- * 包一层会让识别失败并静默渲染出空步骤条。
76
- */
77
- export const Step: typeof Arco.Steps.Step = Arco.Steps.Step
78
-
79
- /** 带静态子组件的步骤条导出。 */
80
- export const Steps: typeof StepsBase & { Step: typeof Arco.Steps.Step } = Object.assign(StepsBase, {
81
- Step: Arco.Steps.Step,
82
- })
1
+ /**
2
+ * 页面结构与位置指示:面包屑、分页、步骤条。
3
+ *
4
+ * @module @dsh-plugin/dsh-ui-components/navigation/hierarchy
5
+ */
6
+ import * as React from 'react'
7
+ import { Arco } from '@dsh-plugin/dsh-loader/client'
8
+ import { injectNavigationStyles } from './styles.js'
9
+
10
+ /** {@link Breadcrumb} 的 props。 */
11
+ export type BreadcrumbProps = React.ComponentPropsWithoutRef<typeof Arco.Breadcrumb>
12
+
13
+ /**
14
+ * 层级路径。
15
+ *
16
+ * @param props - 见 {@link BreadcrumbProps}。
17
+ * @returns 面包屑元素。
18
+ */
19
+ export function Breadcrumb(props: BreadcrumbProps): React.ReactElement {
20
+ injectNavigationStyles()
21
+ return <Arco.Breadcrumb {...props} />
22
+ }
23
+
24
+ /** {@link BreadcrumbItem} 的 props。 */
25
+ export type BreadcrumbItemProps = React.ComponentPropsWithoutRef<typeof Arco.Breadcrumb.Item>
26
+
27
+ /**
28
+ * 面包屑中的一个节点。
29
+ *
30
+ * @param props - 见 {@link BreadcrumbItemProps}。
31
+ * @returns 面包屑节点元素。
32
+ */
33
+ export function BreadcrumbItem(props: BreadcrumbItemProps): React.ReactElement {
34
+ injectNavigationStyles()
35
+ return <Arco.Breadcrumb.Item {...props} />
36
+ }
37
+
38
+ /** {@link Pagination} 的 props。 */
39
+ export type PaginationProps = React.ComponentPropsWithoutRef<typeof Arco.Pagination>
40
+
41
+ /**
42
+ * 分页器。
43
+ *
44
+ * @param props - 见 {@link PaginationProps}。
45
+ * @returns 分页元素。
46
+ */
47
+ export function Pagination(props: PaginationProps): React.ReactElement {
48
+ injectNavigationStyles()
49
+ return <Arco.Pagination {...props} />
50
+ }
51
+
52
+ /** {@link Steps} 的 props。 */
53
+ export type StepsProps = React.ComponentPropsWithoutRef<typeof Arco.Steps>
54
+
55
+ /**
56
+ * 步骤条。
57
+ *
58
+ * `<Steps.Step />` 与 Arco 本身一致,用作单步。
59
+ *
60
+ * @param props - 见 {@link StepsProps}。
61
+ * @returns 步骤条元素。
62
+ */
63
+ function StepsBase(props: StepsProps): React.ReactElement {
64
+ injectNavigationStyles()
65
+ return <Arco.Steps {...props} />
66
+ }
67
+
68
+ /** {@link Step} 的 props。 */
69
+ export type StepProps = React.ComponentPropsWithoutRef<typeof Arco.Steps.Step>
70
+
71
+ /**
72
+ * 步骤条中的一步。
73
+ *
74
+ * 这里直接取 Arco 的原组件而不是包一层:Arco 通过 `child.type` 识别子步骤,
75
+ * 包一层会让识别失败并静默渲染出空步骤条。
76
+ */
77
+ export const Step: typeof Arco.Steps.Step = Arco.Steps.Step
78
+
79
+ /** 带静态子组件的步骤条导出。 */
80
+ export const Steps: typeof StepsBase & { Step: typeof Arco.Steps.Step } = Object.assign(StepsBase, {
81
+ Step: Arco.Steps.Step,
82
+ })
@@ -1,21 +1,21 @@
1
- /**
2
- * 导航组件出口。
3
- *
4
- * @module @dsh-plugin/dsh-ui-components/navigation
5
- */
6
- export { Dropdown, Menu, MenuItem, TabPane, Tabs, type DropdownProps, type MenuItemProps, type MenuProps, type TabPaneProps, type TabsProps } from './menu.js'
7
- export {
8
- Breadcrumb,
9
- BreadcrumbItem,
10
- Pagination,
11
- Step,
12
- Steps,
13
- type BreadcrumbItemProps,
14
- type BreadcrumbProps,
15
- type PaginationProps,
16
- type StepProps,
17
- type StepsProps,
18
- } from './hierarchy.js'
19
- export { SegmentedControl, type Segment, type SegmentedControlProps } from './segmented.js'
20
- export { DisclosureRow, StateDot, type DisclosureRowProps, type StateDotProps, type StateDotState } from './indicator.js'
21
- export { NAVIGATION_CSS, injectNavigationStyles } from './styles.js'
1
+ /**
2
+ * 导航组件出口。
3
+ *
4
+ * @module @dsh-plugin/dsh-ui-components/navigation
5
+ */
6
+ export { Dropdown, Menu, MenuItem, TabPane, Tabs, type DropdownProps, type MenuItemProps, type MenuProps, type TabPaneProps, type TabsProps } from './menu.js'
7
+ export {
8
+ Breadcrumb,
9
+ BreadcrumbItem,
10
+ Pagination,
11
+ Step,
12
+ Steps,
13
+ type BreadcrumbItemProps,
14
+ type BreadcrumbProps,
15
+ type PaginationProps,
16
+ type StepProps,
17
+ type StepsProps,
18
+ } from './hierarchy.js'
19
+ export { SegmentedControl, type Segment, type SegmentedControlProps } from './segmented.js'
20
+ export { DisclosureRow, StateDot, type DisclosureRowProps, type StateDotProps, type StateDotState } from './indicator.js'
21
+ export { NAVIGATION_CSS, injectNavigationStyles } from './styles.js'
@@ -1,125 +1,125 @@
1
- /**
2
- * 折叠标题行与状态点。
3
- *
4
- * `DisclosureRow` 是宿主思考行、工具行那样「一行标题 + 就地展开内容」的结构;
5
- * `StateDot` 是列表与任务行的状态标记。
6
- *
7
- * @module @dsh-plugin/dsh-ui-components/navigation/indicator
8
- */
9
- import * as React from 'react'
10
- import { cx } from '../foundation/style.js'
11
- import { Icon } from '../foundation/icons.js'
12
- import { injectNavigationStyles } from './styles.js'
13
-
14
- /** {@link DisclosureRow} 的 props。 */
15
- export interface DisclosureRowProps {
16
- /** 标题。 */
17
- title: React.ReactNode
18
- /** 标题前的小图标。 */
19
- leading?: React.ReactNode
20
- /** 展开后的内容。不需要展开时省略。 */
21
- children?: React.ReactNode
22
- /** 受控展开状态;与 `onToggle` 同时提供时由调用方持有。 */
23
- expanded?: boolean
24
- /** 默认展开状态,非受控时使用。 */
25
- defaultExpanded?: boolean
26
- /** 展开状态变化时回调。 */
27
- onToggle?: (expanded: boolean) => void
28
- /** 标题行右侧的独立操作,点击它不会触发展开。 */
29
- accessory?: React.ReactNode
30
- /** 追加类名。 */
31
- className?: string
32
- }
33
-
34
- /**
35
- * 一行可折叠的标题。
36
- *
37
- * 展开时标题行显示向上箭头,收起时悬停显示向下箭头,与宿主的思考行一致。
38
- *
39
- * @param props - 见 {@link DisclosureRowProps}。
40
- * @returns 折叠行元素。
41
- */
42
- export function DisclosureRow({
43
- title,
44
- leading,
45
- children,
46
- expanded,
47
- defaultExpanded = false,
48
- onToggle,
49
- accessory,
50
- className,
51
- }: DisclosureRowProps): React.ReactElement {
52
- injectNavigationStyles()
53
- const [internal, setInternal] = React.useState(defaultExpanded)
54
- const open = expanded ?? internal
55
- const expandable = children !== undefined
56
-
57
- /**
58
- * 切换展开状态。受控与非受控都走同一入口。
59
- */
60
- const toggle = (): void => {
61
- if (!expandable) return
62
- const next = !open
63
- if (expanded === undefined) setInternal(next)
64
- onToggle?.(next)
65
- }
66
-
67
- const header = (
68
- <>
69
- {leading === undefined ? null : <span className="dsh-disclosure__leading" aria-hidden="true">{leading}</span>}
70
- <span className="dsh-disclosure__title">{title}</span>
71
- {expandable ? (
72
- <span className="dsh-disclosure__leading" aria-hidden="true">
73
- <Icon name={open ? 'ChevronDown' : 'ChevronRight'} size={14} />
74
- </span>
75
- ) : null}
76
- </>
77
- )
78
-
79
- return (
80
- <div className={cx('dsh-disclosure', className)}>
81
- <div className="dsh-disclosure__header">
82
- {expandable ? (
83
- <button
84
- type="button"
85
- className="dsh-disclosure__header--expandable"
86
- aria-expanded={open}
87
- onClick={toggle}
88
- style={{ display: 'flex', alignItems: 'center', gap: 6 }}
89
- >
90
- {header}
91
- </button>
92
- ) : (
93
- <span className="dsh-disclosure__header--expandable" style={{ display: 'flex', alignItems: 'center', gap: 6 }}>{header}</span>
94
- )}
95
- {accessory}
96
- </div>
97
- {expandable && open ? <div className="dsh-disclosure__content">{children}</div> : null}
98
- </div>
99
- )
100
- }
101
-
102
- /** 状态点的状态。 */
103
- export type StateDotState = 'done' | 'warning' | 'error' | 'idle' | 'ongoing'
104
-
105
- /** {@link StateDot} 的 props。 */
106
- export interface StateDotProps {
107
- /** 状态,默认 `idle`。 */
108
- state?: StateDotState
109
- /** 追加类名。 */
110
- className?: string
111
- }
112
-
113
- /**
114
- * 一个状态标记。
115
- *
116
- * 它是装饰元素(`aria-hidden`),名字由所在行的调用方提供;`ongoing` 渲染
117
- * 为持续旋转的圆环,其余状态是一枚实心圆点。
118
- *
119
- * @param props - 见 {@link StateDotProps}。
120
- * @returns 状态点元素。
121
- */
122
- export function StateDot({ state = 'idle', className }: StateDotProps): React.ReactElement {
123
- injectNavigationStyles()
124
- return <span className={cx('dsh-state-dot', className)} data-state={state} aria-hidden="true" />
125
- }
1
+ /**
2
+ * 折叠标题行与状态点。
3
+ *
4
+ * `DisclosureRow` 是宿主思考行、工具行那样「一行标题 + 就地展开内容」的结构;
5
+ * `StateDot` 是列表与任务行的状态标记。
6
+ *
7
+ * @module @dsh-plugin/dsh-ui-components/navigation/indicator
8
+ */
9
+ import * as React from 'react'
10
+ import { cx } from '../foundation/style.js'
11
+ import { Icon } from '../foundation/icons.js'
12
+ import { injectNavigationStyles } from './styles.js'
13
+
14
+ /** {@link DisclosureRow} 的 props。 */
15
+ export interface DisclosureRowProps {
16
+ /** 标题。 */
17
+ title: React.ReactNode
18
+ /** 标题前的小图标。 */
19
+ leading?: React.ReactNode
20
+ /** 展开后的内容。不需要展开时省略。 */
21
+ children?: React.ReactNode
22
+ /** 受控展开状态;与 `onToggle` 同时提供时由调用方持有。 */
23
+ expanded?: boolean
24
+ /** 默认展开状态,非受控时使用。 */
25
+ defaultExpanded?: boolean
26
+ /** 展开状态变化时回调。 */
27
+ onToggle?: (expanded: boolean) => void
28
+ /** 标题行右侧的独立操作,点击它不会触发展开。 */
29
+ accessory?: React.ReactNode
30
+ /** 追加类名。 */
31
+ className?: string
32
+ }
33
+
34
+ /**
35
+ * 一行可折叠的标题。
36
+ *
37
+ * 展开时标题行显示向上箭头,收起时悬停显示向下箭头,与宿主的思考行一致。
38
+ *
39
+ * @param props - 见 {@link DisclosureRowProps}。
40
+ * @returns 折叠行元素。
41
+ */
42
+ export function DisclosureRow({
43
+ title,
44
+ leading,
45
+ children,
46
+ expanded,
47
+ defaultExpanded = false,
48
+ onToggle,
49
+ accessory,
50
+ className,
51
+ }: DisclosureRowProps): React.ReactElement {
52
+ injectNavigationStyles()
53
+ const [internal, setInternal] = React.useState(defaultExpanded)
54
+ const open = expanded ?? internal
55
+ const expandable = children !== undefined
56
+
57
+ /**
58
+ * 切换展开状态。受控与非受控都走同一入口。
59
+ */
60
+ const toggle = (): void => {
61
+ if (!expandable) return
62
+ const next = !open
63
+ if (expanded === undefined) setInternal(next)
64
+ onToggle?.(next)
65
+ }
66
+
67
+ const header = (
68
+ <>
69
+ {leading === undefined ? null : <span className="dsh-disclosure__leading" aria-hidden="true">{leading}</span>}
70
+ <span className="dsh-disclosure__title">{title}</span>
71
+ {expandable ? (
72
+ <span className="dsh-disclosure__leading" aria-hidden="true">
73
+ <Icon name={open ? 'ChevronDown' : 'ChevronRight'} size={14} />
74
+ </span>
75
+ ) : null}
76
+ </>
77
+ )
78
+
79
+ return (
80
+ <div className={cx('dsh-disclosure', className)}>
81
+ <div className="dsh-disclosure__header">
82
+ {expandable ? (
83
+ <button
84
+ type="button"
85
+ className="dsh-disclosure__header--expandable"
86
+ aria-expanded={open}
87
+ onClick={toggle}
88
+ style={{ display: 'flex', alignItems: 'center', gap: 6 }}
89
+ >
90
+ {header}
91
+ </button>
92
+ ) : (
93
+ <span className="dsh-disclosure__header--expandable" style={{ display: 'flex', alignItems: 'center', gap: 6 }}>{header}</span>
94
+ )}
95
+ {accessory}
96
+ </div>
97
+ {expandable && open ? <div className="dsh-disclosure__content">{children}</div> : null}
98
+ </div>
99
+ )
100
+ }
101
+
102
+ /** 状态点的状态。 */
103
+ export type StateDotState = 'done' | 'warning' | 'error' | 'idle' | 'ongoing'
104
+
105
+ /** {@link StateDot} 的 props。 */
106
+ export interface StateDotProps {
107
+ /** 状态,默认 `idle`。 */
108
+ state?: StateDotState
109
+ /** 追加类名。 */
110
+ className?: string
111
+ }
112
+
113
+ /**
114
+ * 一个状态标记。
115
+ *
116
+ * 它是装饰元素(`aria-hidden`),名字由所在行的调用方提供;`ongoing` 渲染
117
+ * 为持续旋转的圆环,其余状态是一枚实心圆点。
118
+ *
119
+ * @param props - 见 {@link StateDotProps}。
120
+ * @returns 状态点元素。
121
+ */
122
+ export function StateDot({ state = 'idle', className }: StateDotProps): React.ReactElement {
123
+ injectNavigationStyles()
124
+ return <span className={cx('dsh-state-dot', className)} data-state={state} aria-hidden="true" />
125
+ }