@teamix-evo/ui 0.6.1 → 0.7.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/manifest.json CHANGED
@@ -1150,6 +1150,11 @@
1150
1150
  "source": "src/components/tree/index.tsx",
1151
1151
  "targetAlias": "components",
1152
1152
  "targetName": "tree.tsx"
1153
+ },
1154
+ {
1155
+ "source": "src/components/tree/utils.ts",
1156
+ "targetAlias": "components",
1157
+ "targetName": "utils.ts"
1153
1158
  }
1154
1159
  ],
1155
1160
  "meta": "src/components/tree/meta.md",
@@ -1372,7 +1377,7 @@
1372
1377
  }
1373
1378
  ],
1374
1379
  "meta": "src/components/tree-select/meta.md",
1375
- "registryDependencies": ["cn", "popover", "checkbox"],
1380
+ "registryDependencies": ["cn", "popover", "checkbox", "tree"],
1376
1381
  "dependencies": {
1377
1382
  "lucide-react": "^0.460.0",
1378
1383
  "class-variance-authority": "^0.7.1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamix-evo/ui",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Source-injected UI components for Teamix Evo (shadcn-based, antd capabilities)",
5
5
  "type": "module",
6
6
  "files": [
@@ -51,9 +51,9 @@
51
51
  "vite": "^5.4.0",
52
52
  "vite-tsconfig-paths": "^6.1.1",
53
53
  "zod": "^3",
54
+ "@teamix-evo/registry": "0.12.0",
54
55
  "@teamix-evo/eslint-config": "0.2.3",
55
- "@teamix-evo/tokens": "^0.7.2",
56
- "@teamix-evo/registry": "0.12.0"
56
+ "@teamix-evo/tokens": "^0.8.0"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public",
@@ -289,12 +289,6 @@ function alignClass(align?: DataTableColumn<unknown>['align']) {
289
289
  return undefined;
290
290
  }
291
291
 
292
- function widthStyle(col: DataTableColumn<unknown>): React.CSSProperties {
293
- const w = col.size ?? col.width;
294
- if (w === undefined) return {};
295
- return { width: typeof w === 'number' ? `${w}px` : w };
296
- }
297
-
298
292
  /** 把 DataTableColumn 适配为 TanStack ColumnDef;同时按 fixed 重排(左→中→右)以满足锁列 sticky 计算。 */
299
293
  function adaptColumns<T>(
300
294
  columns: DataTableColumn<T>[],
@@ -50,7 +50,6 @@ import { Spinner } from '@/components/spinner';
50
50
  import {
51
51
  TimePickerPanel,
52
52
  parseTime,
53
- formatTime,
54
53
  triggerVariants,
55
54
  type TimeParts,
56
55
  type TriggerSize,
@@ -23,6 +23,7 @@ import * as React from 'react';
23
23
  import { Dialog as DialogPrimitive } from 'radix-ui';
24
24
 
25
25
  import { cn } from '@/lib/utils';
26
+ import { useRadixPopperGuard } from '@/hooks/use-radix-popper-guard';
26
27
  import { XIcon } from 'lucide-react';
27
28
 
28
29
  export interface DialogProps
@@ -95,6 +96,7 @@ function DialogContent({
95
96
  children,
96
97
  size = 'sm',
97
98
  showCloseButton = true,
99
+ onPointerDownOutside,
98
100
  ...props
99
101
  }: React.ComponentProps<typeof DialogPrimitive.Content> & {
100
102
  /** 内容区尺寸。 @default 'sm' */
@@ -102,12 +104,18 @@ function DialogContent({
102
104
  /** 是否显示右上角关闭按钮。 @default true */
103
105
  showCloseButton?: boolean;
104
106
  }) {
107
+ const guard = useRadixPopperGuard();
108
+
105
109
  return (
106
110
  <DialogPortal>
107
111
  <DialogOverlay />
108
112
  <DialogPrimitive.Content
109
113
  data-slot="dialog-content"
110
114
  data-size={size}
115
+ onPointerDownOutside={(e) => {
116
+ guard.onPointerDownOutside(e);
117
+ onPointerDownOutside?.(e);
118
+ }}
111
119
  className={cn(
112
120
  // eslint-disable-next-line teamix-evo/no-arbitrary-tw-value -- mobile viewport needs calc(100% - 2rem) for safe inset; box-shadow drives via component-level token --dialog-shadow per ADR 0026.
113
121
  'fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-md bg-popover text-sm text-popover-foreground shadow-[var(--dialog-shadow,0px_6px_24px_0px_rgba(0,0,0,0.1))] duration-100 outline-none data-[size=sm]:sm:max-w-md data-[size=md]:sm:max-w-xl data-[size=lg]:sm:max-w-3xl data-[size=xl]:sm:max-w-6xl data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
@@ -199,7 +207,8 @@ function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
199
207
  <div
200
208
  data-slot="dialog-footer"
201
209
  className={cn(
202
- 'flex flex-col-reverse gap-2 border-t border-transparent px-5 py-4 sm:flex-row sm:justify-end',
210
+ // eslint-disable-next-line teamix-evo/no-bare-border -- border-footer-separator @theme 声明的语义 token,已加入 lint-core 白名单
211
+ 'flex flex-col-reverse gap-2 border-t border-footer-separator px-5 py-4 sm:flex-row sm:justify-end',
203
212
  className,
204
213
  )}
205
214
  {...props}
@@ -39,8 +39,94 @@ export default meta;
39
39
 
40
40
  type Story = StoryObj<typeof meta>;
41
41
 
42
- /** 完整版页头:面包屑 + 帮助链接 + 返回 + 主图标 + 标题(含 ⓘ) + 描述 + 多操作 + 底部信息。 */
42
+ /** 仅标题:最基础的页头形态,只包含一个标题。 */
43
43
  export const Default: Story = {
44
+ render: () => (
45
+ <PageHeader>
46
+ <PageHeaderContent>
47
+ <PageHeaderHeading>
48
+ <PageHeaderTitle>页面标题</PageHeaderTitle>
49
+ </PageHeaderHeading>
50
+ </PageHeaderContent>
51
+ </PageHeader>
52
+ ),
53
+ };
54
+
55
+ /** 标题 + 描述:标题下方附加一行描述文字。 */
56
+ export const WithDescription: Story = {
57
+ render: () => (
58
+ <PageHeader>
59
+ <PageHeaderContent>
60
+ <div className="flex flex-col">
61
+ <PageHeaderHeading>
62
+ <PageHeaderTitle>页面标题</PageHeaderTitle>
63
+ </PageHeaderHeading>
64
+ <PageHeaderDescription>
65
+ 页面描述页面描述页面描述页面描述页面描述页面描述页面描述
66
+ </PageHeaderDescription>
67
+ </div>
68
+ </PageHeaderContent>
69
+ </PageHeader>
70
+ ),
71
+ };
72
+
73
+ /** 仅面包屑:只有面包屑导航,无标题。 */
74
+ export const OnlyBreadcrumb: Story = {
75
+ render: () => (
76
+ <PageHeader>
77
+ <PageHeaderNav>
78
+ <Breadcrumb>
79
+ <BreadcrumbList>
80
+ <BreadcrumbItem>
81
+ <BreadcrumbLink href="#">首页</BreadcrumbLink>
82
+ </BreadcrumbItem>
83
+ <BreadcrumbSeparator />
84
+ <BreadcrumbItem>
85
+ <BreadcrumbLink href="#">实例列表</BreadcrumbLink>
86
+ </BreadcrumbItem>
87
+ <BreadcrumbSeparator />
88
+ <BreadcrumbItem>
89
+ <BreadcrumbPage>实例详情</BreadcrumbPage>
90
+ </BreadcrumbItem>
91
+ </BreadcrumbList>
92
+ </Breadcrumb>
93
+ </PageHeaderNav>
94
+ </PageHeader>
95
+ ),
96
+ };
97
+
98
+ /** 面包屑 + 标题:面包屑导航 + 标题,常见于二级页面。 */
99
+ export const WithBreadcrumb: Story = {
100
+ render: () => (
101
+ <PageHeader>
102
+ <PageHeaderNav>
103
+ <Breadcrumb>
104
+ <BreadcrumbList>
105
+ <BreadcrumbItem>
106
+ <BreadcrumbLink href="#">首页</BreadcrumbLink>
107
+ </BreadcrumbItem>
108
+ <BreadcrumbSeparator />
109
+ <BreadcrumbItem>
110
+ <BreadcrumbLink href="#">实例列表</BreadcrumbLink>
111
+ </BreadcrumbItem>
112
+ <BreadcrumbSeparator />
113
+ <BreadcrumbItem>
114
+ <BreadcrumbPage>实例详情</BreadcrumbPage>
115
+ </BreadcrumbItem>
116
+ </BreadcrumbList>
117
+ </Breadcrumb>
118
+ </PageHeaderNav>
119
+ <PageHeaderContent>
120
+ <PageHeaderHeading>
121
+ <PageHeaderTitle>实例详情</PageHeaderTitle>
122
+ </PageHeaderHeading>
123
+ </PageHeaderContent>
124
+ </PageHeader>
125
+ ),
126
+ };
127
+
128
+ /** 完整版页头:面包屑 + 帮助链接 + 返回 + 主图标 + 标题(含 ⓘ) + 描述 + 多操作。 */
129
+ export const Full: Story = {
44
130
  render: () => (
45
131
  <PageHeader>
46
132
  <PageHeaderNav>
@@ -25,6 +25,7 @@ import * as React from 'react';
25
25
  import { Dialog as SheetPrimitive } from 'radix-ui';
26
26
 
27
27
  import { cn } from '@/lib/utils';
28
+ import { useRadixPopperGuard } from '@/hooks/use-radix-popper-guard';
28
29
  import { XIcon } from 'lucide-react';
29
30
 
30
31
  export interface SheetProps
@@ -104,6 +105,7 @@ function SheetContent({
104
105
  side = 'right',
105
106
  size = 'sm',
106
107
  showCloseButton = true,
108
+ onPointerDownOutside,
107
109
  ...props
108
110
  }: React.ComponentProps<typeof SheetPrimitive.Content> & {
109
111
  /** 弹出方向。 @default 'right' */
@@ -113,6 +115,8 @@ function SheetContent({
113
115
  /** 是否显示右上角关闭按钮。 @default true */
114
116
  showCloseButton?: boolean;
115
117
  }) {
118
+ const guard = useRadixPopperGuard();
119
+
116
120
  return (
117
121
  <SheetPortal>
118
122
  <SheetOverlay />
@@ -120,6 +124,10 @@ function SheetContent({
120
124
  data-slot="sheet-content"
121
125
  data-side={side}
122
126
  data-size={size}
127
+ onPointerDownOutside={(e) => {
128
+ guard.onPointerDownOutside(e);
129
+ onPointerDownOutside?.(e);
130
+ }}
123
131
  className={cn(
124
132
  // 基础布局:fixed 定位 + flex 列容器 + token 化阴影(抽屉与背景的边界由阴影表达,不画 border)
125
133
  // eslint-disable-next-line teamix-evo/no-arbitrary-tw-value -- box-shadow 走 component-level token --drawer-shadow,按 ADR 0026 在源码内显式声明。
@@ -237,7 +245,8 @@ function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
237
245
  <div
238
246
  data-slot="sheet-footer"
239
247
  className={cn(
240
- 'flex flex-col gap-2 border-t border-transparent px-4 py-2.5 sm:flex-row sm:justify-start',
248
+ // eslint-disable-next-line teamix-evo/no-bare-border -- border-footer-separator @theme 声明的语义 token,已加入 lint-core 白名单
249
+ 'flex flex-col gap-2 border-t border-footer-separator px-4 py-2.5 sm:flex-row sm:justify-start',
241
250
  className,
242
251
  )}
243
252
  {...props}
@@ -154,7 +154,7 @@ function Table({
154
154
  // ─── TableHeader ────────────────────────────────────────────────────────────
155
155
 
156
156
  function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {
157
- const { stickyHeader, bordered, size } = useTableContext();
157
+ const { stickyHeader } = useTableContext();
158
158
  return (
159
159
  <thead
160
160
  data-slot="table-header"
@@ -269,7 +269,7 @@ const tabsTriggerVariants = cva(
269
269
  {
270
270
  variants: {
271
271
  variant: {
272
- line: '-mb-px border-b-2 border-transparent text-muted-foreground data-[state=active]:border-primary data-[state=active]:text-foreground group-data-[orientation=vertical]/tabs:mb-0 group-data-[orientation=vertical]/tabs:-mr-px group-data-[orientation=vertical]/tabs:border-b-0 group-data-[orientation=vertical]/tabs:border-r-2 group-data-[orientation=vertical]/tabs:justify-start',
272
+ line: '-mb-px border-b-2 border-transparent text-muted-foreground data-[state=active]:border-tab-indicator data-[state=active]:text-foreground group-data-[orientation=vertical]/tabs:mb-0 group-data-[orientation=vertical]/tabs:-mr-px group-data-[orientation=vertical]/tabs:border-b-0 group-data-[orientation=vertical]/tabs:border-r-2 group-data-[orientation=vertical]/tabs:justify-start',
273
273
  capsule:
274
274
  'rounded-md text-muted-foreground data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
275
275
  // text 模式:trigger 间 ::after 竖线分隔(8px 高、1px 宽、垂直居中、border 色)