oink-ui 1.0.2 → 1.0.4
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/README.md +28 -0
- package/dist/core/corner.d.ts +124 -0
- package/dist/core/cornerFallback.d.ts +13 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/theme.d.ts +6 -1
- package/dist/inputs/Button.d.ts +1 -1
- package/dist/oink-ui.cjs +1 -1
- package/dist/oink-ui.css +1 -1
- package/dist/oink-ui.js +4059 -3526
- package/dist/styles/accordion.css +1 -1
- package/dist/styles/alert.css +1 -1
- package/dist/styles/app-shell.css +1 -1
- package/dist/styles/avatar.css +1 -1
- package/dist/styles/badge.css +1 -1
- package/dist/styles/base.css +1 -1
- package/dist/styles/breadcrumb.css +1 -1
- package/dist/styles/button.css +1 -1
- package/dist/styles/calendar.css +1 -1
- package/dist/styles/card.css +1 -1
- package/dist/styles/checkbox.css +1 -1
- package/dist/styles/chip.css +1 -1
- package/dist/styles/code.css +1 -1
- package/dist/styles/color-picker.css +1 -1
- package/dist/styles/color-swatches.css +1 -1
- package/dist/styles/command-palette.css +1 -1
- package/dist/styles/count.css +1 -1
- package/dist/styles/dialog.css +1 -1
- package/dist/styles/empty-state.css +1 -1
- package/dist/styles/file-drop.css +1 -1
- package/dist/styles/fill-meter.css +1 -1
- package/dist/styles/floating-card.css +1 -1
- package/dist/styles/group.css +1 -1
- package/dist/styles/hotkey.css +1 -1
- package/dist/styles/image.css +1 -1
- package/dist/styles/input.css +1 -1
- package/dist/styles/kbd.css +1 -1
- package/dist/styles/list.css +1 -1
- package/dist/styles/menu.css +1 -1
- package/dist/styles/nav.css +1 -1
- package/dist/styles/number-input.css +1 -1
- package/dist/styles/option-card.css +1 -1
- package/dist/styles/pagination.css +1 -1
- package/dist/styles/pin-input.css +1 -1
- package/dist/styles/popup.css +1 -1
- package/dist/styles/primitives.css +1 -1
- package/dist/styles/progress.css +1 -1
- package/dist/styles/radio.css +1 -1
- package/dist/styles/rating.css +1 -1
- package/dist/styles/reaction.css +1 -1
- package/dist/styles/segmented.css +1 -1
- package/dist/styles/select.css +1 -1
- package/dist/styles/skeleton.css +1 -1
- package/dist/styles/slider.css +1 -1
- package/dist/styles/spinner.css +1 -1
- package/dist/styles/split-pane.css +1 -1
- package/dist/styles/stat.css +1 -1
- package/dist/styles/steps.css +1 -1
- package/dist/styles/surface.css +1 -1
- package/dist/styles/switch.css +1 -1
- package/dist/styles/tab-bar.css +1 -1
- package/dist/styles/table.css +1 -1
- package/dist/styles/tabs.css +1 -1
- package/dist/styles/tag.css +1 -1
- package/dist/styles/textarea.css +1 -1
- package/dist/styles/timeline.css +1 -1
- package/dist/styles/toast.css +1 -1
- package/dist/styles/tooltip.css +1 -1
- package/dist/styles/tree.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,11 +73,39 @@ export function App() {
|
|
|
73
73
|
| `defaultMotion` | `'auto' \| 'full' \| 'reduced'` | `'auto'` |
|
|
74
74
|
| `locale` | `'auto' \| 'zh-CN' \| 'en-US'` — `'auto'` follows the browser language: Chinese → `zh-CN`, anything else → `en-US` | `'auto'` |
|
|
75
75
|
| `storageKey` | remember the user's choices in `localStorage` under this key | — |
|
|
76
|
+
| `cornerFallback` | draw the superellipse corners with script in engines without `corner-shape` (see [Corners](#corners)) | `true` |
|
|
76
77
|
|
|
77
78
|
With a custom accent color, the text color on top of it (ink or white) and the darker / lighter variants used for text are derived automatically. `useOink()` reads and changes the theme at runtime.
|
|
78
79
|
|
|
79
80
|
Components render the same markup on the server and the client, so they work with server rendering and static prerendering. The server can't know the visitor's language, so with `locale="auto"` the server render and the hydration pass use `en-US` and switch to the browser's language right after; if you render on the server, pass `locale` explicitly (for example from the URL or the `Accept-Language` header).
|
|
80
81
|
|
|
82
|
+
## Corners
|
|
83
|
+
|
|
84
|
+
Containers use continuous-curvature superellipse corners: `border-radius` plus `corner-shape: superellipse(1.75)` (the `--ok-corner` token), with radii multiplied by `--ok-rk` (1.45) so they look as large as their nominal size. Fully round shapes (pills, circles) stay `corner-shape: round`.
|
|
85
|
+
|
|
86
|
+
When overriding a component's shape in application CSS, override its fallback marker in the same rule, including explicit round or inherited shapes:
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
.search-button {
|
|
90
|
+
border-radius: calc(14px * var(--ok-rk));
|
|
91
|
+
corner-shape: var(--ok-corner); --ok-shape: var(--ok-corner);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
WebKit drops `corner-shape`, so omitting `--ok-shape` can retain a component's original marker (for example Button's `round`) even though its radius changed. A radius near half the control height then becomes a pill. The fallback does not infer the intended shape from radius alone.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
Only Chromium supports `corner-shape` (Chrome, Edge, WebView2). In Safari and in the `WKWebView` that Tauri uses on macOS, `OinkProvider` turns on a small script fallback that draws the same curve Chromium draws, so a Mac build looks like the Windows build. The fallback also starts in Firefox, which lacks `corner-shape` too, but it has not been checked there yet:
|
|
99
|
+
|
|
100
|
+
- It does nothing at all where `corner-shape` is supported, and nothing on the server.
|
|
101
|
+
- It finds the elements to redraw through `--ok-shape`, a non-inherited custom property every stylesheet declaration of `corner-shape` is paired with. Fully round elements keep the native `border-radius`.
|
|
102
|
+
- On those elements the native corners are squared off and then cut along the curve with `clip-path`; the parts native painting can't put on a curve — the hairline, the top highlight, borders and the focus ring — are patched in with a nine-slice SVG `border-image`. Fills, straight edges and hover / press transitions stay native; the corner patches follow transitions frame by frame. Clipped content (images, scrolling areas) is cut on the curve too.
|
|
103
|
+
- It follows mounts, unmounts, resizes, theme changes, hover, focus and running transitions. On a page with 300 rounded elements (about 1,900 elements in all) in WKWebView it costs about 13 ms once at start-up plus 8 ms for the first paint, 6–8 ms extra on a theme switch, and 1–2 ms of script per frame while 50 rounded elements resize or 10 animate their ring colour.
|
|
104
|
+
|
|
105
|
+
Without `OinkProvider`, call `installCornerFallback()` once on the client (it returns a function that removes it again; calls are reference-counted). `<OinkProvider cornerFallback={false}>` turns it off. Your own CSS gets the same treatment when it pairs the declarations: `corner-shape: var(--ok-corner); --ok-shape: var(--ok-corner);`.
|
|
106
|
+
|
|
107
|
+
Code that reads the tokens to draw matching shapes (`getComputedStyle(document.documentElement).getPropertyValue('--ok-corner')`) sees `superellipse(1.75)` and `--ok-rk: 1.45` wherever the corners are superellipses: natively in Chromium, and in other engines once the fallback is running (it marks `<html data-ok-corner-fallback>`). Before the script runs, or with the fallback turned off, those engines draw plain round corners and the tokens say `round` and `1`. `cornerShapePath()` returns the SVG path of a box with these corners, using the same Bézier construction as Chromium.
|
|
108
|
+
|
|
81
109
|
## Development
|
|
82
110
|
|
|
83
111
|
```bash
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 超椭圆圆角的几何:和 Chromium 画 `corner-shape: superellipse(K)` 用同一条曲线。
|
|
3
|
+
*
|
|
4
|
+
* · 规范里 superellipse(K) 的指数是 n = 2^K:|x|^n + |y|^n = 1。K = 1 是正圆,2 是 squircle,0 是斜切,∞ 是直角,负值内凹。
|
|
5
|
+
* · Chromium 不是逐点画这条数学曲线,而是每个角拆成两段三次贝塞尔:从直边起点到 45° 点(u = v = 2^(-1/n)),
|
|
6
|
+
* 起点把手沿直边、45° 点把手沿对角线的切线方向。把手长度(以半径为单位)下面的 HANDLES 表是从 Chromium 149
|
|
7
|
+
* 的实际渲染里拟合出来的(1000px 半径的角逐行测覆盖率,各 K 的拟合残差均方根 < 0.1px);K = 1 时 Chromium
|
|
8
|
+
* 走正圆的画法,这里也单独处理。和数学曲线相比,Chromium 的曲线最多差半径的 0.16%,我们跟 Chromium 走。
|
|
9
|
+
* · 半径的取值和缩放(盒子太小时按比例缩小全部半径)与 border-radius 完全相同。
|
|
10
|
+
* · 偏移出来的轮廓(内阴影的洞、描边外缘、outline):半径按 r ± d 增减、K 不变,原点随矩形内缩 / 外扩。
|
|
11
|
+
* Chromium 对偏移轮廓的曲率还有一点微调,在 1–4px 的发丝线和焦点环上差不到 0.1px,这里不跟。
|
|
12
|
+
*/
|
|
13
|
+
/** 四个角的曲率参数 K(左上、右上、右下、左下)。Infinity 是直角,1 是正圆 */
|
|
14
|
+
export type CornerKs = [number, number, number, number];
|
|
15
|
+
/** 一个角的水平、垂直半径 */
|
|
16
|
+
export type CornerRadius = [number, number];
|
|
17
|
+
/** 四个角的半径(左上、右上、右下、左下),和 border-*-radius 的顺序一样 */
|
|
18
|
+
export type CornerRadii = [CornerRadius, CornerRadius, CornerRadius, CornerRadius];
|
|
19
|
+
export interface Box {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
w: number;
|
|
23
|
+
h: number;
|
|
24
|
+
}
|
|
25
|
+
/** superellipse(K) 的指数 n = 2^K */
|
|
26
|
+
export declare const superellipseExponent: (k: number) => number;
|
|
27
|
+
/** 两段贝塞尔的把手长度(以半径为单位),k ≥ 0 */
|
|
28
|
+
export declare function cornerHandles(k: number): [number, number];
|
|
29
|
+
type Pt = [number, number];
|
|
30
|
+
/**
|
|
31
|
+
* 单位角上的点(u 是离左边的距离,v 是离上边的距离,都以半径为单位),从左边上的 (0, 1) 走到上边上的 (1, 0)。
|
|
32
|
+
* 返回 [起点, 控制点, 控制点, 终点, 控制点, 控制点, 终点]:两段三次贝塞尔;直角 / 斜切时退化成折线(控制点和端点重合)
|
|
33
|
+
*/
|
|
34
|
+
export declare function unitCorner(k: number): Pt[];
|
|
35
|
+
/** 规范的半径缩放:相邻两个角的半径之和超过边长时,全部半径按同一个比例缩小 */
|
|
36
|
+
export declare function clampRadii(w: number, h: number, r: CornerRadii): CornerRadii;
|
|
37
|
+
/** 半径随轮廓偏移 d(正值外扩、负值内缩):有圆角的角按 r + d 增减到不小于 0,直角保持直角 */
|
|
38
|
+
export declare function offsetRadii(r: CornerRadii, d: number): CornerRadii;
|
|
39
|
+
/** 矩形向外扩 d(负值内缩)、再平移 (dx, dy) */
|
|
40
|
+
export declare const inflate: (b: Box, d: number, dx?: number, dy?: number) => Box;
|
|
41
|
+
/**
|
|
42
|
+
* 一个闭合子路径(SVG / CSS path() 语法):盒子 b、四角半径 r、四角曲率 ks。顺时针;reverse 时逆时针(nonzero 规则下挖洞)
|
|
43
|
+
*/
|
|
44
|
+
export declare function shapePath(b: Box, r: CornerRadii, ks: CornerKs, reverse?: boolean): string;
|
|
45
|
+
/** 矩形子路径;reverse 时逆时针 */
|
|
46
|
+
export declare function rectPath(b: Box, reverse?: boolean): string;
|
|
47
|
+
/**
|
|
48
|
+
* 解析 corner-shape 的值(我们从 --ok-shape 读到的就是它):1–4 个值,顺序同 border-radius。
|
|
49
|
+
* 关键字 round / squircle / square / bevel / scoop / notch 和 superellipse(K | infinity | -infinity)。全是 round 返回 null
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseCornerShape(value: string): CornerKs | null;
|
|
52
|
+
/** 一层阴影(来自计算后的 box-shadow)。模糊忽略不计:设计里没有阴影,只有零模糊的描边和高光 */
|
|
53
|
+
export interface ShadowLayer {
|
|
54
|
+
inset: boolean;
|
|
55
|
+
dx: number;
|
|
56
|
+
dy: number;
|
|
57
|
+
spread: number;
|
|
58
|
+
color: string;
|
|
59
|
+
blur?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface OutlineLayer {
|
|
62
|
+
offset: number;
|
|
63
|
+
width: number;
|
|
64
|
+
color: string;
|
|
65
|
+
}
|
|
66
|
+
/** 一个元素(或伪元素)在回退里需要知道的全部:尺寸、半径(已缩放)、曲率、边框、阴影、outline */
|
|
67
|
+
export interface CornerDecor {
|
|
68
|
+
w: number;
|
|
69
|
+
h: number;
|
|
70
|
+
radii: CornerRadii;
|
|
71
|
+
ks: CornerKs;
|
|
72
|
+
/** 上右下左的边框宽度 */
|
|
73
|
+
border: [number, number, number, number];
|
|
74
|
+
borderColor: string;
|
|
75
|
+
shadows: ShadowLayer[];
|
|
76
|
+
outline: OutlineLayer | null;
|
|
77
|
+
/**
|
|
78
|
+
* 元素背后的颜色(最近的不透明祖先背景)。外侧装饰(outline、外阴影)离超椭圆很近时,环在 45° 附近会伸进盒子的矩形里;
|
|
79
|
+
* 那里原生画的是直角的底色,Chromium 那里露出的是背后的页面。补丁先用这个颜色盖住,再画环
|
|
80
|
+
*/
|
|
81
|
+
backdrop?: string;
|
|
82
|
+
/**
|
|
83
|
+
* 叠在这个元素上的其它部件(伪元素)的外侧装饰,在本元素坐标里的区域(outerRegions,已外扩 1px)。
|
|
84
|
+
* 这时超椭圆外紧挨着的地方可见,补丁不能越过超椭圆;并且这片区域落在盒子矩形里的部分先铺 backdrop,盖住原生直角底色
|
|
85
|
+
*/
|
|
86
|
+
attached?: string;
|
|
87
|
+
}
|
|
88
|
+
/** 颜色的不透明度:transparent、rgba(…, a)、rgb(… / a)、color(… / a);解析不了当作不透明 */
|
|
89
|
+
export declare function colorAlpha(c: string): number;
|
|
90
|
+
/** 解析计算后的 box-shadow(颜色可能在前也可能在后;长度一律是 px) */
|
|
91
|
+
export declare function parseBoxShadow(value: string): ShadowLayer[];
|
|
92
|
+
/** 外侧的装饰(外阴影、outline)伸出盒子多远 */
|
|
93
|
+
export declare function outerExtent(d: Pick<CornerDecor, 'shadows' | 'outline'>): number;
|
|
94
|
+
/**
|
|
95
|
+
* 外侧装饰在这个元素坐标里的可见区域(nonzero 子路径),供 clip-path 合并。
|
|
96
|
+
* 外阴影 = 外扩后的形状(盒内部分本来就可见);outline = 外扩到外缘的形状 + 外扩到内缘的形状(逆时针挖掉中间的缝)
|
|
97
|
+
*/
|
|
98
|
+
export declare function outerRegions(d: CornerDecor, at?: {
|
|
99
|
+
x: number;
|
|
100
|
+
y: number;
|
|
101
|
+
}, grow?: number): string;
|
|
102
|
+
/**
|
|
103
|
+
* clip-path 的路径:
|
|
104
|
+
* · 一个比盒子大 bleed 的大矩形(溢出盒子的子元素照常可见,只在四个角动刀);
|
|
105
|
+
* · 每个有圆角的角挖一个洞:从角往盒内到半径、往盒外到外侧装饰的最远处 reach;
|
|
106
|
+
* · 再把超椭圆形状本身、以及外侧装饰(outline 环、外阴影)的可见区域并回来。
|
|
107
|
+
* 原生绘制在角上是直角(回退时 border-radius 置 0),洞里只留下超椭圆和装饰的真实形状。
|
|
108
|
+
* extra 是叠在这个元素上的其它部件(伪元素)的外侧装饰,reach 要覆盖它们
|
|
109
|
+
*/
|
|
110
|
+
export declare function cornerClipPath(d: CornerDecor, bleed: number, extra?: string, extraReach?: number): string;
|
|
111
|
+
export interface CornerPaint {
|
|
112
|
+
/** SVG 源码 */
|
|
113
|
+
svg: string;
|
|
114
|
+
/** border-image-slice(也是 border-image-width,单位 px),上右下左 */
|
|
115
|
+
slice: [number, number, number, number];
|
|
116
|
+
/** border-image-outset */
|
|
117
|
+
outset: number;
|
|
118
|
+
}
|
|
119
|
+
/** 补丁缓存键里和尺寸有关的部分:能拉伸的方向不看尺寸 */
|
|
120
|
+
export declare function paintSizeKey(d: CornerDecor): string;
|
|
121
|
+
export declare function cornerPaint(d: CornerDecor): CornerPaint | null;
|
|
122
|
+
/** 把补丁写成 border-image 的值 */
|
|
123
|
+
export declare function borderImageValue(p: CornerPaint): string;
|
|
124
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** <html> 上的开关:tokens.css 据此把 --ok-corner / --ok-rk 换成超椭圆那一套 */
|
|
2
|
+
export declare const CORNER_FALLBACK_ATTR = "data-ok-corner-fallback";
|
|
3
|
+
/** 当前内核要不要回退:能确定不支持 corner-shape、并且有需要的观察器时才要 */
|
|
4
|
+
export declare function cornerFallbackNeeded(): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* 打开超椭圆回退。可以重复调用(引用计数),返回的函数撤销这一次;最后一个撤销时清掉所有观察器、属性和行内变量。
|
|
7
|
+
* 内核支持 corner-shape 或在服务端时什么都不做。OinkProvider 默认会调用它
|
|
8
|
+
*/
|
|
9
|
+
export declare function installCornerFallback(): () => void;
|
|
10
|
+
/** 回退是否正在工作 */
|
|
11
|
+
export declare const cornerFallbackActive: () => boolean;
|
|
12
|
+
/** 组件里打开回退(OinkProvider 用它)。在布局副作用里打开:首帧绘制前角就已经画好。enabled 为 false 时不打开 */
|
|
13
|
+
export declare function useCornerFallback(enabled?: boolean): void;
|
package/dist/core/index.d.ts
CHANGED
|
@@ -12,3 +12,6 @@ export * from './theme';
|
|
|
12
12
|
export * from './locale';
|
|
13
13
|
export * from './tail';
|
|
14
14
|
export * from './OinkLogo';
|
|
15
|
+
export { shapePath as cornerShapePath, cornerHandles, parseCornerShape, clampRadii as clampCornerRadii } from './corner';
|
|
16
|
+
export type { CornerKs, CornerRadii, CornerRadius } from './corner';
|
|
17
|
+
export { installCornerFallback, useCornerFallback, cornerFallbackNeeded, cornerFallbackActive } from './cornerFallback';
|
package/dist/core/theme.d.ts
CHANGED
|
@@ -44,11 +44,16 @@ export interface OinkProviderProps {
|
|
|
44
44
|
* 服务端渲染时第一帧是 en-US、注水后才换成浏览器的语言;服务端渲染的应用最好显式传入。见 LocaleProvider
|
|
45
45
|
*/
|
|
46
46
|
locale?: OinkLocaleSetting;
|
|
47
|
+
/**
|
|
48
|
+
* 不支持 `corner-shape` 的内核(Safari、macOS 上的 WKWebView、Firefox)里用脚本画出和 Chromium 一样的超椭圆圆角。默认打开;
|
|
49
|
+
* 支持 corner-shape 的内核里本来就什么都不做。见 installCornerFallback
|
|
50
|
+
*/
|
|
51
|
+
cornerFallback?: boolean;
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
54
|
* 主题、强调色、动效偏好。把结果写到 <html> 的 data-theme / data-accent / data-motion 上,
|
|
50
55
|
* 所有组件的样式都从这三个属性派生。不包 Provider 也能用组件,默认浅色 + 粉色强调。
|
|
51
56
|
*/
|
|
52
|
-
export declare function OinkProvider({ children, defaultTheme, defaultAccent, defaultMotion, storageKey, tail, locale }: OinkProviderProps): import("react").JSX.Element;
|
|
57
|
+
export declare function OinkProvider({ children, defaultTheme, defaultAccent, defaultMotion, storageKey, tail, locale, cornerFallback }: OinkProviderProps): import("react").JSX.Element;
|
|
53
58
|
/** 读写主题。没有 Provider 时返回只读的默认值,方便组件在任何地方使用 */
|
|
54
59
|
export declare function useOink(): OinkContextValue;
|
package/dist/inputs/Button.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ type IconOnlyProps = {
|
|
|
50
50
|
}));
|
|
51
51
|
export type ButtonProps = ButtonOwnProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ButtonOwnProps> & IconOnlyProps;
|
|
52
52
|
/** 按钮。全圆胶囊;传 href 渲染成链接 */
|
|
53
|
-
export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<
|
|
53
|
+
export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
|
|
54
54
|
export interface ButtonGroupProps extends HTMLAttributes<HTMLDivElement> {
|
|
55
55
|
/** 组内按钮的默认尺寸 */
|
|
56
56
|
size?: ButtonSize;
|