@autional/ui 0.1.0-rc.44 → 0.1.0-rc.46

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@autional/ui",
3
- "version": "0.1.0-rc.44",
4
- "description": "Autional shared React component library (atoms + molecules) — the canonical home of the component layer",
3
+ "version": "0.1.0-rc.46",
4
+ "description": "Autional shared React component library (atoms + molecules) �?the canonical home of the component layer",
5
5
  "license": "AGPL-3.0",
6
6
  "main": "./src/index.ts",
7
7
  "module": "./src/index.ts",
@@ -82,7 +82,7 @@
82
82
  "react-i18next": "17.0.7",
83
83
  "typescript": "5.8.3",
84
84
  "vitest": "3.2.0",
85
- "@autional/tokens": "0.1.0-rc.12"
85
+ "@autional/tokens": "0.1.0-rc.15"
86
86
  },
87
87
  "scripts": {
88
88
  "typecheck": "tsc --noEmit",
@@ -1,9 +1,10 @@
1
1
  import * as React from 'react';
2
- import { fieldControlClass, fieldControlHeight } from '../internal/field-styles';
2
+ import { fieldControlClass, fieldControlClassFor, fieldControlHeight, type FieldShape, type FieldSize } from '../internal/field-styles';
3
3
 
4
- // 注:`prefix` 与 HTML 自带的 `prefix` 属性同名(后者在 <input> 上没有意义,TS 会报
5
- // 「ReactNode 不能赋给 string」)。所以这里显式 Omit 掉它再重定义 —— 保住最自然的调用名。
6
- export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'prefix'> {
4
+ // 注:`prefix` 与 `size` 都与 HTML 自带的同名属性冲突(`prefix?: string`、`size?: number`,
5
+ // 而这里要的是 ReactNode 与 'sm'|'md'|'lg')。两处都是 **tsc 当场报出来的** ——
6
+ // 所以显式 Omit 掉再重定义,保住最自然的调用名,而不是改成 `inputSize` 这种妥协名。
7
+ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'prefix' | 'size'> {
7
8
  error?: string;
8
9
  /**
9
10
  * 前缀槽:图标或极短的单位符号(如货币符号)。
@@ -19,22 +20,32 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
19
20
  prefix?: React.ReactNode;
20
21
  /** 后缀槽:清除按钮、单位后缀一类。同样占真实布局空间。 */
21
22
  suffix?: React.ReactNode;
23
+ /**
24
+ * 尺寸档(第 61 轮):sm=h-9 / md=h-10(默认)/ lg=h-14。
25
+ * 舰队里手写的搜索框有三种几何,这个参数就是为它们准备的 —— **只影响有槽形态**,
26
+ * 无槽形态仍走默认高度(既有消费方零影响)。
27
+ */
28
+ size?: FieldSize;
29
+ /** 形状档:default=rounded-md / pill=rounded-full(大圆角搜索框)。同样只影响有槽形态。 */
30
+ shape?: FieldShape;
22
31
  }
23
32
 
24
33
  // 外观来自 ../internal/field-styles —— 与 @autional/ui/rhf 的绑定控件同一份,不各自维护。
25
34
  //
26
35
  // 两种渲染形态(**无槽时逐字节不变**,既有消费方零影响):
27
36
  // · 无 prefix/suffix:只有一个 <input>,外框在它自己身上(原样);
28
- // · 有槽:外框交给 wrapper,<input> 变透明并占满剩余宽度 —— 高度/圆角由调用方
29
- // 原有的 className 决定(舰队里搜索框有三种几何:py-2 / py-2.5 / py-3.5 rounded-full),
30
- // 所以这一层**不替调用方决定尺寸**。
37
+ // · 有槽:外框交给 wrapper,<input> 变透明并占满剩余宽度 —— 高度/圆角由 `size` / `shape`
38
+ // 两轴决定(第 61 轮补:舰队里搜索框有三种几何 py-2 / py-2.5 / py-3.5 + rounded-full,
39
+ // 组件层若只有一种,站点就只能各自写材质 —— 那就是这条维度存在的原因)。
40
+ // ⚠️ 调用方**不要**再传高度/内边距/圆角:同一批属性只能有一个来源,否则胜负由
41
+ // Tailwind 的生成顺序决定,而那是无声的。
31
42
  export const Input = React.forwardRef<HTMLInputElement, InputProps>(
32
- ({ className = '', error, prefix, suffix, ...props }, ref) => {
43
+ ({ className = '', error, prefix, suffix, size = 'md', shape = 'default', ...props }, ref) => {
33
44
  const hasSlot = prefix != null || suffix != null;
34
45
  return (
35
46
  <div className="w-full">
36
47
  {hasSlot ? (
37
- <div className={fieldControlClass(!!error, 'flex items-center gap-2 ' + className)}>
48
+ <div className={fieldControlClassFor(size, shape, !!error, 'items-center gap-2 ' + className)}>
38
49
  {prefix != null && (
39
50
  <span className="shrink-0 text-[var(--color-text-muted)]" aria-hidden="true">{prefix}</span>
40
51
  )}
@@ -49,4 +60,4 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
49
60
  );
50
61
  },
51
62
  );
52
- Input.displayName = 'Input';
63
+ Input.displayName = 'Input';
@@ -1,14 +1,49 @@
1
1
  // 表单控件的外观只有一份 —— Input atom 与 @autional/ui/rhf 的绑定控件都用它。
2
2
  // 各自复制一份类名串的后果不是「看起来一样」,而是「改了一处、另一处没变」:
3
3
  // 那正是这一层要消灭的东西(与 antd 组件级令牌同理,只是这里是一段 Tailwind 类)。
4
+ //
5
+ // 第 61 轮加了尺寸与形状两轴 —— 起因是舰队里手写的搜索框有**三种几何**
6
+ // (py-2 / py-2.5 / py-3.5 + rounded-full),而组件层只有一种,于是站点只能各自写材质。
7
+ // 关键纪律:**高度/内边距/圆角只由一个地方发出来**(这里),调用方的 className 不得与它冲突 ——
8
+ // 否则胜负由 Tailwind 的生成顺序决定,那是无声的。
4
9
 
5
- const BASE =
6
- 'flex w-full rounded-md border bg-[var(--color-bg-surface)] px-3 py-2 text-sm text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50';
10
+ // ⚠️ 拆 BASE 的时候差点丢掉两个状态样式(focus-visible 环、disabled)——
11
+ // 「重写一个常量的整行」时最容易漏掉的就是**行尾那几个**。它们与尺寸/形状不冲突,
12
+ // 所以留在 STRUCT 里,一处不少。
13
+ const STRUCT =
14
+ 'flex w-full border bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] ' +
15
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)] focus-visible:ring-offset-2 ' +
16
+ 'disabled:cursor-not-allowed disabled:opacity-50';
7
17
 
8
- /** 单行控件的高度。textarea 不给(它要能长高)。 */
18
+ /** 尺寸档:高度是**定值**(不是 padding 撑出来的)—— 同一行里的控件要对齐,定值才可预测。 */
19
+ export type FieldSize = 'sm' | 'md' | 'lg';
20
+ const SIZE: Record<FieldSize, string> = {
21
+ sm: 'h-9 px-3 text-sm',
22
+ md: 'h-10 px-3 text-sm',
23
+ lg: 'h-14 px-4 text-base',
24
+ };
25
+
26
+ /** 形状档。pill 是给「搜索框」一类大圆角控件用的,不是给表单控件的默认。 */
27
+ export type FieldShape = 'default' | 'pill';
28
+ const SHAPE: Record<FieldShape, string> = {
29
+ default: 'rounded-md',
30
+ pill: 'rounded-full',
31
+ };
32
+
33
+ /** 单行控件的默认高度。textarea 不给(它要能长高)。 */
9
34
  export const fieldControlHeight = 'h-10';
10
35
 
11
- export function fieldControlClass(invalid?: boolean, extra = ''): string {
36
+ export function fieldControlClassFor(
37
+ size: FieldSize = 'md',
38
+ shape: FieldShape = 'default',
39
+ invalid?: boolean,
40
+ extra = '',
41
+ ): string {
12
42
  const border = invalid ? 'border-[var(--color-danger)]' : 'border-[var(--color-border-subtle)]';
13
- return `${BASE} ${border} ${extra}`.trim();
43
+ return `${STRUCT} ${SIZE[size]} ${SHAPE[shape]} ${border} ${extra}`.trim();
44
+ }
45
+
46
+ /** 旧签名(默认 md + default)—— **逐字节不变**,既有消费方零影响。 */
47
+ export function fieldControlClass(invalid?: boolean, extra = ''): string {
48
+ return fieldControlClassFor('md', 'default', invalid, extra);
14
49
  }
@@ -2,17 +2,23 @@
2
2
 
3
3
  import React from 'react';
4
4
 
5
- // ConsolePageHeader —— 控制台页面的页头:左对齐标题 + 右侧操作槽 + 可选副标题。
5
+ // AppPageHeader —— **应用外壳里的页面页头**:左对齐标题 + 右侧操作槽 + 可选副标题。
6
6
  //
7
7
  // 为什么不是 DS 里已有的 PageHeader:那是**营销 hero**(text-center + text-3xl/sm:text-4xl),
8
- // 落地页在用;控制台页头是另一种东西(左对齐 + text-xl/font-semibold + 右侧操作槽)。
8
+ // 落地页在用;应用页头是另一种东西(左对齐 + text-xl/font-semibold + 右侧操作槽)。
9
9
  // 两者**同名不同物**,互相替换会把控制台的密度打散 —— 所以这里另立一件,PageHeader 保持原样(D5)。
10
10
  //
11
+ // 第 63 轮改名(L17):原名 ConsolePageHeader 把契约说小了 —— user 门户(面向终端用户,
12
+ // 不是「控制台」)早就是它的大用户。实测改名当时 **393 处**调用(站点 359 + 设计系统 34),
13
+ // 而 L17 登记的是 174 处:**台账里的数字也会腐**,动手前必须重数。
14
+ // 新名字跟着 AppShell 走:外壳叫什么,外壳里的页头就叫什么,与页面是不是「控制台」无关。
15
+ // 不保留旧名别名 —— 全舰队同一批迁完,留一个只被我们自己引用的旧名字只会变成死代码。
16
+ //
11
17
  // 收敛前实测(2026-10):三个控制台在 **106 个页面**里把这段页头内联写了 106 遍,
12
18
  // 包裹容器的 className 有 **11 种**(mb-4 / mb-6、有没有 justify-between、有没有响应式断点各不相同)。
13
19
  // 这里固定成一种:窄屏纵向堆叠、sm 起横向两端对齐、gap-3、下边距 mb-6 —— 与其中 55 处的多数派一致。
14
20
 
15
- export interface ConsolePageHeaderProps {
21
+ export interface AppPageHeaderProps {
16
22
  /** 页面标题。 */
17
23
  title: React.ReactNode;
18
24
  /** 标题下方的说明文字(可选)。 */
@@ -23,12 +29,12 @@ export interface ConsolePageHeaderProps {
23
29
  className?: string;
24
30
  }
25
31
 
26
- export const ConsolePageHeader = React.memo(function ConsolePageHeader({
32
+ export const AppPageHeader = React.memo(function AppPageHeader({
27
33
  title,
28
34
  description,
29
35
  actions,
30
36
  className = '',
31
- }: ConsolePageHeaderProps) {
37
+ }: AppPageHeaderProps) {
32
38
  return (
33
39
  <div
34
40
  className={`mb-6 flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between ${className}`}
@@ -23,8 +23,8 @@ export { PageContainer } from './PageContainer';
23
23
  export type { PageContainerProps } from './PageContainer';
24
24
  export { AppShell } from './AppShell';
25
25
  export type { AppShellProps } from './AppShell';
26
- export { ConsolePageHeader } from './ConsolePageHeader';
27
- export type { ConsolePageHeaderProps } from './ConsolePageHeader';
26
+ export { AppPageHeader } from './AppPageHeader';
27
+ export type { AppPageHeaderProps } from './AppPageHeader';
28
28
  export { Alert } from './Alert';
29
29
  export type { AlertProps, AlertVariant } from './Alert';
30
30
  export { Result } from './Result';