oink-ui 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +89 -2
- package/dist/core/FocusScope.d.ts +28 -0
- package/dist/core/Icon.d.ts +12 -0
- package/dist/core/OinkLogo.d.ts +45 -0
- package/dist/core/Portal.d.ts +8 -0
- package/dist/core/VisuallyHidden.d.ts +3 -0
- package/dist/core/color.d.ts +51 -0
- package/dist/core/hooks.d.ts +49 -0
- package/dist/core/icons.d.ts +81 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/locale.d.ts +19 -0
- package/dist/core/messages.d.ts +173 -0
- package/dist/core/motion.d.ts +46 -0
- package/dist/core/tail.d.ts +27 -0
- package/dist/core/theme.d.ts +51 -0
- package/dist/core/utils.d.ts +13 -0
- package/dist/display/Accordion.d.ts +24 -0
- package/dist/display/Alert.d.ts +22 -0
- package/dist/display/Avatar.d.ts +44 -0
- package/dist/display/Badge.d.ts +13 -0
- package/dist/display/Breadcrumb.d.ts +18 -0
- package/dist/display/Card.d.ts +59 -0
- package/dist/display/Code.d.ts +24 -0
- package/dist/display/Count.d.ts +15 -0
- package/dist/display/DescriptionList.d.ts +20 -0
- package/dist/display/EmptyState.d.ts +15 -0
- package/dist/display/Group.d.ts +41 -0
- package/dist/display/Image.d.ts +32 -0
- package/dist/display/List.d.ts +24 -0
- package/dist/display/Meter.d.ts +22 -0
- package/dist/display/Pagination.d.ts +22 -0
- package/dist/display/Progress.d.ts +33 -0
- package/dist/display/Reaction.d.ts +23 -0
- package/dist/display/Roll.d.ts +9 -0
- package/dist/display/Skeleton.d.ts +11 -0
- package/dist/display/Spinner.d.ts +18 -0
- package/dist/display/Stat.d.ts +22 -0
- package/dist/display/Steps.d.ts +20 -0
- package/dist/display/Surface.d.ts +10 -0
- package/dist/display/Table.d.ts +87 -0
- package/dist/display/Tabs.d.ts +27 -0
- package/dist/display/Tag.d.ts +14 -0
- package/dist/display/Text.d.ts +28 -0
- package/dist/display/Timeline.d.ts +20 -0
- package/dist/display/Tree.d.ts +23 -0
- package/dist/display/index.d.ts +59 -0
- package/dist/display/types.d.ts +3 -0
- package/dist/index.d.ts +7 -0
- package/dist/inputs/Button.d.ts +84 -0
- package/dist/inputs/Checkbox.d.ts +34 -0
- package/dist/inputs/Chip.d.ts +34 -0
- package/dist/inputs/ColorPicker.d.ts +22 -0
- package/dist/inputs/ColorSwatches.d.ts +20 -0
- package/dist/inputs/Field.d.ts +29 -0
- package/dist/inputs/Fieldset.d.ts +9 -0
- package/dist/inputs/FileDrop.d.ts +24 -0
- package/dist/inputs/Form.d.ts +16 -0
- package/dist/inputs/Hotkey.d.ts +19 -0
- package/dist/inputs/Input.d.ts +35 -0
- package/dist/inputs/Kbd.d.ts +13 -0
- package/dist/inputs/Label.d.ts +10 -0
- package/dist/inputs/NumberInput.d.ts +28 -0
- package/dist/inputs/OptionCard.d.ts +39 -0
- package/dist/inputs/PinInput.d.ts +25 -0
- package/dist/inputs/Radio.d.ts +33 -0
- package/dist/inputs/RangeSlider.d.ts +29 -0
- package/dist/inputs/Rating.d.ts +21 -0
- package/dist/inputs/SearchInput.d.ts +7 -0
- package/dist/inputs/Segmented.d.ts +27 -0
- package/dist/inputs/Slider.d.ts +37 -0
- package/dist/inputs/Switch.d.ts +17 -0
- package/dist/inputs/Textarea.d.ts +18 -0
- package/dist/inputs/fieldContext.d.ts +36 -0
- package/dist/inputs/index.d.ts +52 -0
- package/dist/inputs/internal.d.ts +19 -0
- package/dist/inputs/useBusy.d.ts +37 -0
- package/dist/layout/AppShell.d.ts +96 -0
- package/dist/layout/AspectRatio.d.ts +7 -0
- package/dist/layout/Box.d.ts +18 -0
- package/dist/layout/Center.d.ts +11 -0
- package/dist/layout/Container.d.ts +13 -0
- package/dist/layout/Divider.d.ts +11 -0
- package/dist/layout/Grid.d.ts +28 -0
- package/dist/layout/Inline.d.ts +20 -0
- package/dist/layout/Nav.d.ts +48 -0
- package/dist/layout/Page.d.ts +14 -0
- package/dist/layout/PageHeader.d.ts +18 -0
- package/dist/layout/ScrollArea.d.ts +15 -0
- package/dist/layout/Section.d.ts +17 -0
- package/dist/layout/Show.d.ts +28 -0
- package/dist/layout/Spacer.d.ts +8 -0
- package/dist/layout/SplitPane.d.ts +30 -0
- package/dist/layout/Stack.d.ts +15 -0
- package/dist/layout/Sticky.d.ts +14 -0
- package/dist/layout/TabBar.d.ts +54 -0
- package/dist/layout/Toolbar.d.ts +17 -0
- package/dist/layout/index.d.ts +41 -0
- package/dist/layout/internal.d.ts +7 -0
- package/dist/layout/responsive.d.ts +50 -0
- package/dist/oink-ui.cjs +1 -0
- package/dist/oink-ui.css +5 -0
- package/dist/oink-ui.js +7110 -0
- package/dist/overlays/CommandPalette.d.ts +55 -0
- package/dist/overlays/Dialog.d.ts +35 -0
- package/dist/overlays/Drawer.d.ts +17 -0
- package/dist/overlays/FloatingCard.d.ts +101 -0
- package/dist/overlays/FloatingParts.d.ts +37 -0
- package/dist/overlays/Panel.d.ts +28 -0
- package/dist/overlays/Sheet.d.ts +18 -0
- package/dist/overlays/Toast.d.ts +79 -0
- package/dist/overlays/confirm.d.ts +31 -0
- package/dist/overlays/index.d.ts +11 -0
- package/dist/overlays/origin.d.ts +42 -0
- package/dist/popups/Calendar.d.ts +48 -0
- package/dist/popups/Combobox.d.ts +48 -0
- package/dist/popups/ContextMenu.d.ts +15 -0
- package/dist/popups/DatePicker.d.ts +59 -0
- package/dist/popups/Listbox.d.ts +44 -0
- package/dist/popups/Menu.d.ts +80 -0
- package/dist/popups/Popover.d.ts +27 -0
- package/dist/popups/Popup.d.ts +31 -0
- package/dist/popups/Select.d.ts +44 -0
- package/dist/popups/Tooltip.d.ts +28 -0
- package/dist/popups/index.d.ts +20 -0
- package/dist/popups/internal.d.ts +49 -0
- package/dist/popups/usePosition.d.ts +80 -0
- package/dist/styles/accordion.css +2 -0
- package/dist/styles/alert.css +2 -0
- package/dist/styles/app-shell.css +2 -0
- package/dist/styles/avatar.css +2 -0
- package/dist/styles/badge.css +2 -0
- package/dist/styles/base.css +2 -0
- package/dist/styles/breadcrumb.css +2 -0
- package/dist/styles/button.css +2 -0
- package/dist/styles/calendar.css +2 -0
- package/dist/styles/card.css +2 -0
- package/dist/styles/checkbox.css +2 -0
- package/dist/styles/chip.css +2 -0
- package/dist/styles/code.css +2 -0
- package/dist/styles/color-picker.css +2 -0
- package/dist/styles/color-swatches.css +2 -0
- package/dist/styles/combobox.css +2 -0
- package/dist/styles/command-palette.css +2 -0
- package/dist/styles/count.css +2 -0
- package/dist/styles/description-list.css +2 -0
- package/dist/styles/dialog.css +2 -0
- package/dist/styles/empty-state.css +2 -0
- package/dist/styles/field.css +2 -0
- package/dist/styles/fieldset.css +2 -0
- package/dist/styles/file-drop.css +2 -0
- package/dist/styles/fill-meter.css +2 -0
- package/dist/styles/floating-card.css +2 -0
- package/dist/styles/form.css +2 -0
- package/dist/styles/group.css +2 -0
- package/dist/styles/hotkey.css +2 -0
- package/dist/styles/image.css +2 -0
- package/dist/styles/input.css +2 -0
- package/dist/styles/kbd.css +2 -0
- package/dist/styles/label.css +2 -0
- package/dist/styles/list.css +2 -0
- package/dist/styles/menu.css +2 -0
- package/dist/styles/meter.css +2 -0
- package/dist/styles/nav.css +2 -0
- package/dist/styles/number-input.css +2 -0
- package/dist/styles/oink-logo.css +2 -0
- package/dist/styles/option-card.css +2 -0
- package/dist/styles/page.css +2 -0
- package/dist/styles/pagination.css +2 -0
- package/dist/styles/pin-input.css +2 -0
- package/dist/styles/popover.css +2 -0
- package/dist/styles/popup.css +2 -0
- package/dist/styles/primitives.css +2 -0
- package/dist/styles/progress.css +2 -0
- package/dist/styles/radio.css +2 -0
- package/dist/styles/rating.css +2 -0
- package/dist/styles/reaction.css +2 -0
- package/dist/styles/responsive.css +2 -0
- package/dist/styles/roll.css +2 -0
- package/dist/styles/segmented.css +2 -0
- package/dist/styles/select.css +2 -0
- package/dist/styles/skeleton.css +2 -0
- package/dist/styles/slider.css +2 -0
- package/dist/styles/spinner.css +2 -0
- package/dist/styles/split-pane.css +2 -0
- package/dist/styles/stat.css +2 -0
- package/dist/styles/steps.css +2 -0
- package/dist/styles/surface.css +2 -0
- package/dist/styles/switch.css +2 -0
- package/dist/styles/tab-bar.css +2 -0
- package/dist/styles/table.css +2 -0
- package/dist/styles/tabs.css +2 -0
- package/dist/styles/tag.css +2 -0
- package/dist/styles/text.css +2 -0
- package/dist/styles/textarea.css +2 -0
- package/dist/styles/timeline.css +2 -0
- package/dist/styles/toast.css +2 -0
- package/dist/styles/toolbar.css +2 -0
- package/dist/styles/tooltip.css +2 -0
- package/dist/styles/tree.css +2 -0
- package/package.json +67 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hachiwii
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,90 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/oinkvm/oink-ui/main/.github/assets/banner-dark.png">
|
|
4
|
+
<img alt="Oink UI — soft, flat, quiet React components" src="https://raw.githubusercontent.com/oinkvm/oink-ui/main/.github/assets/banner-light.png" width="860">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://www.npmjs.com/package/oink-ui"><img alt="npm" src="https://img.shields.io/npm/v/oink-ui?color=ff6b8e"></a>
|
|
10
|
+
<a href="https://github.com/oinkvm/oink-ui/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/oinkvm/oink-ui/actions/workflows/ci.yml/badge.svg"></a>
|
|
11
|
+
<a href="./LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-1b1c22"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
# Oink UI
|
|
15
|
+
|
|
16
|
+
A soft, flat, quiet React component library: large continuous corner radii, flat surfaces with hairlines instead of shadows, an ink-and-neutral palette with one accent color, and quick, purposeful motion. Responsive and accessible out of the box, with light and dark themes.
|
|
17
|
+
|
|
18
|
+
**Docs and live examples:** https://oink-ui.hachiwii.com
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
<picture>
|
|
23
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/oinkvm/oink-ui/main/.github/assets/showcase-dark.webp">
|
|
24
|
+
<img alt="The Oink UI component showcase: inputs, a select, checkboxes, a switch, radios, a slider, a product card, buttons, a table, progress, toasts, rating, tabs and an accordion" src="https://raw.githubusercontent.com/oinkvm/oink-ui/main/.github/assets/showcase-light.webp">
|
|
25
|
+
</picture>
|
|
26
|
+
|
|
27
|
+
<img alt="Twelve common components animating in a 4 by 3 grid: Button, Input, Select, Checkbox, Switch, Slider, Tabs, DatePicker, Dialog, Menu, Tooltip and Toast" src="https://raw.githubusercontent.com/oinkvm/oink-ui/main/.github/assets/components.gif">
|
|
28
|
+
|
|
29
|
+
<img alt="The Mail example app with a three-column layout: folders, the inbox list and an open email thread" src="https://raw.githubusercontent.com/oinkvm/oink-ui/main/.github/assets/example-mail.webp">
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install oink-ui
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
React 18 or newer is a peer dependency.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
Import the styles once in your entry file, then wrap your app in `OinkProvider`:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import 'oink-ui/styles.css';
|
|
45
|
+
import { Button, OinkProvider, Toaster } from 'oink-ui';
|
|
46
|
+
|
|
47
|
+
export function App() {
|
|
48
|
+
return (
|
|
49
|
+
<OinkProvider>
|
|
50
|
+
<Button variant="primary">Get started</Button>
|
|
51
|
+
<Toaster />
|
|
52
|
+
</OinkProvider>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`oink-ui/styles.css` contains every design token (`--ok-*`) and every component's styles. To ship only what you use, import `oink-ui/styles/base.css` first and then one entry per component family, e.g. `oink-ui/styles/button.css`, `oink-ui/styles/dialog.css`. The comment at the top of each entry lists the other entries it depends on.
|
|
58
|
+
|
|
59
|
+
## Theming and locale
|
|
60
|
+
|
|
61
|
+
`OinkProvider` sets the theme, accent color, motion preference and the language of built-in strings:
|
|
62
|
+
|
|
63
|
+
| Prop | Values | Default |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `defaultTheme` | `'light' \| 'dark' \| 'system'` | `'system'` |
|
|
66
|
+
| `defaultAccent` | `'pink' \| 'orange' \| 'amber' \| 'blue' \| 'violet'` or any `#rrggbb` | `'pink'` |
|
|
67
|
+
| `defaultMotion` | `'auto' \| 'full' \| 'reduced'` | `'auto'` |
|
|
68
|
+
| `locale` | `'zh-CN' \| 'en-US'` | `'zh-CN'` |
|
|
69
|
+
| `storageKey` | remember the user's choices in `localStorage` under this key | — |
|
|
70
|
+
|
|
71
|
+
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.
|
|
72
|
+
|
|
73
|
+
Components render the same markup on the server and the client, so they work with server rendering and static prerendering.
|
|
74
|
+
|
|
75
|
+
## Development
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm install
|
|
79
|
+
npm test # vitest
|
|
80
|
+
npm run typecheck
|
|
81
|
+
npm run build # dist/: ESM + CJS, type declarations, styles.css and per-component style entries
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Component conventions (in Chinese) are in [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
85
|
+
|
|
86
|
+
Every push to `main` that changes code is released automatically as a new patch version (`1.0.x`) by [`release.yml`](./.github/workflows/release.yml); put `[skip ci]` in the commit message to skip a release.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
[MIT](./LICENSE) © Hachiwii
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReactNode, RefObject } from 'react';
|
|
2
|
+
export interface FocusScopeProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
/** 把 Tab 圈在范围内 */
|
|
5
|
+
trap?: boolean;
|
|
6
|
+
/** 挂载时把焦点移进来 */
|
|
7
|
+
autoFocus?: boolean;
|
|
8
|
+
/** 卸载时把焦点还给之前的元素;那个元素已经不在文档里时,按 restoreFocusTo 的规则找一个落脚点 */
|
|
9
|
+
restoreFocus?: boolean;
|
|
10
|
+
/** 首个聚焦目标;不传则找 [data-autofocus],再不行就是容器本身 */
|
|
11
|
+
initialFocus?: RefObject<HTMLElement | null>;
|
|
12
|
+
/** 范围容器 */
|
|
13
|
+
scopeRef: RefObject<HTMLElement | null>;
|
|
14
|
+
}
|
|
15
|
+
/** 焦点的“来处”:元素本身,加上记录当时的祖先链(元素被移除后还能顺着找回去) */
|
|
16
|
+
export interface FocusTrail {
|
|
17
|
+
target: HTMLElement | null;
|
|
18
|
+
ancestors: HTMLElement[];
|
|
19
|
+
}
|
|
20
|
+
/** 记下一个元素和它此刻的祖先链。之后元素即使被移出文档,也能回退到最近的仍存在的祖先 */
|
|
21
|
+
export declare function captureFocusTrail(target: Element | null | undefined): FocusTrail;
|
|
22
|
+
/**
|
|
23
|
+
* 把焦点还回去。原目标还在文档里就还给它;不在了(比如确认删除后那一行已经被移除)就依次回退到:
|
|
24
|
+
* 最近的仍存在的可聚焦祖先 → <main>(临时给它 tabindex="-1")→ body。返回最后拿到焦点的元素(没有动焦点时返回 null)。
|
|
25
|
+
*/
|
|
26
|
+
export declare function restoreFocusTo(trail: FocusTrail | null | undefined): HTMLElement | null;
|
|
27
|
+
/** 焦点管理:进场聚焦、Tab 循环、退场归还。不渲染额外节点,范围由 scopeRef 指定 */
|
|
28
|
+
export declare function FocusScope({ children, trap, autoFocus, restoreFocus, initialFocus, scopeRef }: FocusScopeProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SVGAttributes } from 'react';
|
|
2
|
+
import type { IconName } from './icons';
|
|
3
|
+
export interface IconProps extends Omit<SVGAttributes<SVGSVGElement>, 'name'> {
|
|
4
|
+
/** 内置图标名;也可以不传 name,直接把 <path> 写在 children 里 */
|
|
5
|
+
name?: IconName;
|
|
6
|
+
size?: number;
|
|
7
|
+
/** 有含义的图标给一个标签;不传则对读屏隐藏 */
|
|
8
|
+
label?: string;
|
|
9
|
+
filled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** 20×20 描线图标,颜色跟随文字 */
|
|
12
|
+
export declare const Icon: import("react").ForwardRefExoticComponent<IconProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* 标志(视口 32×32,整体逆时针转 8°):墨色圆角方块(左下角收得更小),
|
|
4
|
+
* 右下角压着一只强调色的猪鼻子(两个鼻孔)
|
|
5
|
+
*/
|
|
6
|
+
export declare const OINK_LOGO_INK_PATH = "M10 3H18A7 7 0 0 1 25 10V18A7 7 0 0 1 18 25H5A2 2 0 0 1 3 23V10A7 7 0 0 1 10 3Z";
|
|
7
|
+
export declare const OINK_LOGO_SNOUT: {
|
|
8
|
+
readonly x: 15.5;
|
|
9
|
+
readonly y: 15;
|
|
10
|
+
readonly width: 13.5;
|
|
11
|
+
readonly height: 10;
|
|
12
|
+
readonly rx: 5;
|
|
13
|
+
};
|
|
14
|
+
export declare const OINK_LOGO_NOSTRILS: readonly [{
|
|
15
|
+
readonly cx: 20;
|
|
16
|
+
readonly cy: 20;
|
|
17
|
+
}, {
|
|
18
|
+
readonly cx: 24.5;
|
|
19
|
+
readonly cy: 20;
|
|
20
|
+
}];
|
|
21
|
+
export interface OinkLogoProps extends HTMLAttributes<HTMLSpanElement> {
|
|
22
|
+
/** 图形的边长(px),默认 28。字标字号跟着按比例变 */
|
|
23
|
+
size?: number;
|
|
24
|
+
/** 图形右边带 “Oink UI” 字标 */
|
|
25
|
+
wordmark?: boolean;
|
|
26
|
+
/** 给读屏的名字,默认 "Oink UI"。传了 aria-hidden 时不输出 */
|
|
27
|
+
title?: string;
|
|
28
|
+
/** 出现时播一次的小动效:猪鼻子拱一下。减弱动效时直接显示终态 */
|
|
29
|
+
animated?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 单色版:整枚标志只用 currentColor(用 color 设色)。方块在鼻子周围让出一圈空隙,
|
|
32
|
+
* 鼻子是实心的、两个鼻孔镂空,所以放在任何底色上都只有「一种颜色 + 底色」。
|
|
33
|
+
* 适合强调色底、照片上、单色印刷。单色版不读 --ok-logo-ink / --ok-logo-accent / --ok-logo-nostril
|
|
34
|
+
*/
|
|
35
|
+
mono?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Oink UI 组件库的标志:墨色圆角方块 + 右下角强调色的猪鼻子。
|
|
39
|
+
* 颜色由三个 CSS 变量控制(写在 .ok-logo 或任意祖先上):
|
|
40
|
+
* · --ok-logo-ink:方块和字标,默认 currentColor(.ok-logo 的 color 是 --ok-text,深色主题自动变浅)
|
|
41
|
+
* · --ok-logo-accent:鼻子,默认跟着强调色(自定义强调色和方块对比度不够时,浅色主题换白、深色主题换墨,见 logoSnoutColors)
|
|
42
|
+
* · --ok-logo-nostril:两个鼻孔,默认跟随 --ok-logo-ink;设成底色就是镂空的效果
|
|
43
|
+
* 只要一种颜色时用 mono。
|
|
44
|
+
*/
|
|
45
|
+
export declare const OinkLogo: import("react").ForwardRefExoticComponent<OinkLogoProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface PortalProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
container?: HTMLElement | null;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** 把内容渲染到 body(或指定容器)。首帧在客户端挂载后才出现,服务端渲染安全 */
|
|
8
|
+
export declare function Portal({ children, container, disabled }: PortalProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 颜色工具:十六进制 ↔ RGB / HSV、相对亮度与对比度、OKLab 感知亮度,以及从任意颜色派生一套强调色变量。
|
|
3
|
+
* 只处理不透明的 sRGB 颜色;十六进制统一输出小写 #rrggbb。
|
|
4
|
+
*/
|
|
5
|
+
/** 0–255 */
|
|
6
|
+
export type RGB = [number, number, number];
|
|
7
|
+
/** h 0–360,s / v 0–1 */
|
|
8
|
+
export interface HSV {
|
|
9
|
+
h: number;
|
|
10
|
+
s: number;
|
|
11
|
+
v: number;
|
|
12
|
+
}
|
|
13
|
+
/** 解析 #rgb / #rrggbb(# 可省略,大小写不限);不合法返回 null */
|
|
14
|
+
export declare function parseHex(input: string): RGB | null;
|
|
15
|
+
/** 规范化成小写 #rrggbb;不合法返回 null */
|
|
16
|
+
export declare function normalizeHex(input: string): string | null;
|
|
17
|
+
export declare function toHex([r, g, b]: RGB): string;
|
|
18
|
+
export declare function rgbToHsv([r, g, b]: RGB): HSV;
|
|
19
|
+
export declare function hsvToRgb({ h, s, v }: HSV): RGB;
|
|
20
|
+
export declare const hexToHsv: (hex: string) => HSV | null;
|
|
21
|
+
export declare const hsvToHex: (hsv: HSV) => string;
|
|
22
|
+
/** WCAG 相对亮度 0–1 */
|
|
23
|
+
export declare function luminance([r, g, b]: RGB): number;
|
|
24
|
+
/** WCAG 对比度 1–21 */
|
|
25
|
+
export declare function contrastRatio(a: RGB, b: RGB): number;
|
|
26
|
+
/** 感知亮度(OKLab 的 L,0–1) */
|
|
27
|
+
export declare const perceivedLightness: (rgb: RGB) => number;
|
|
28
|
+
/** 强调色上的文字(墨色 / 白)以感知亮度为界:比它暗的颜色上用白字 */
|
|
29
|
+
export declare const ON_ACCENT_THRESHOLD = 0.65;
|
|
30
|
+
/** 猪鼻子和方块的对比度低于它就换色。五个预设里最低的是深色主题下的琥珀色(约 1.51),都保持原色 */
|
|
31
|
+
export declare const LOGO_SNOUT_MIN_CONTRAST = 1.45;
|
|
32
|
+
/**
|
|
33
|
+
* 标志上猪鼻子的颜色:平时就是强调色;和方块对比度不够时换掉——
|
|
34
|
+
* 浅色主题(墨色方块)换成白色,深色主题(纸色方块)换成墨色
|
|
35
|
+
*/
|
|
36
|
+
export declare function logoSnoutColors(hex: string): {
|
|
37
|
+
light: string;
|
|
38
|
+
dark: string;
|
|
39
|
+
};
|
|
40
|
+
/** 这个颜色上该用墨色还是白色的字 */
|
|
41
|
+
export declare function onAccentColor(hex: string): '#1b1c22' | '#ffffff';
|
|
42
|
+
/**
|
|
43
|
+
* 从任意颜色派生强调色的 CSS 变量(写在声明 data-accent="custom" 的元素上):
|
|
44
|
+
* · --ok-accent 原色
|
|
45
|
+
* · --ok-on-accent 强调色上的字:按感知亮度自动选墨色或白色
|
|
46
|
+
* · --ok-accent-deep 浅色主题下当文字用的深一档(对白底至少 4.5:1)
|
|
47
|
+
* · --ok-accent-light 深色主题下当文字用的亮一档(对深色卡片至少 4.5:1)
|
|
48
|
+
* · --ok-logo-snout-light / -dark 标志的猪鼻子在浅色 / 深色主题下的颜色(对比度不够时换成白色 / 墨色,见 logoSnoutColors)
|
|
49
|
+
* · 白字的颜色不再提亮填充(提亮会掉对比度),--ok-accent-fill 直接用原色,和预设里的蓝色一样
|
|
50
|
+
*/
|
|
51
|
+
export declare function accentVars(hex: string): Record<string, string>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useLayoutEffect } from 'react';
|
|
2
|
+
import type { MutableRefObject, Ref, RefCallback } from 'react';
|
|
3
|
+
export declare const useIsoLayoutEffect: typeof useLayoutEffect;
|
|
4
|
+
/** 引用恒定、内部永远是最新闭包的回调 */
|
|
5
|
+
export declare function useEvent<T extends (...args: never[]) => unknown>(fn: T | undefined): T;
|
|
6
|
+
/**
|
|
7
|
+
* 受控 / 非受控二合一:传了 value 就受控,否则用 defaultValue 自己管。
|
|
8
|
+
* setter 引用恒定,支持函数写法;同一批次里连续 set(c => c + 1) 会逐次累加(基于最新值,而不是渲染时的值)。
|
|
9
|
+
* onChange 在 setter 里同步调用一次,不放进 setState 的 updater(StrictMode 下 updater 会跑两遍)。
|
|
10
|
+
*/
|
|
11
|
+
export declare function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (v: T) => void): readonly [T, (next: T | ((prev: T) => T)) => void];
|
|
12
|
+
export declare function mergeRefs<T>(...refs: Array<Ref<T> | undefined>): RefCallback<T>;
|
|
13
|
+
/** 媒体查询。服务端渲染时返回 fallback */
|
|
14
|
+
export declare function useMediaQuery(query: string, fallback?: boolean): boolean;
|
|
15
|
+
/** 断点(min-width)。和 CSS 里的 --ok-bp-* 注释保持一致 */
|
|
16
|
+
export declare const BREAKPOINTS: {
|
|
17
|
+
readonly sm: 520;
|
|
18
|
+
readonly md: 768;
|
|
19
|
+
readonly lg: 1024;
|
|
20
|
+
readonly xl: 1280;
|
|
21
|
+
};
|
|
22
|
+
export type Breakpoint = keyof typeof BREAKPOINTS;
|
|
23
|
+
/** 视口是否不小于某个断点 */
|
|
24
|
+
export declare function useBreakpoint(bp: Breakpoint, fallback?: boolean): boolean;
|
|
25
|
+
export type PresenceState = 'open' | 'closed';
|
|
26
|
+
/**
|
|
27
|
+
* 进退场:open 变 false 后先把状态切到 closed,等退场过渡结束再卸载。
|
|
28
|
+
* 用法:if (!mounted) return null; <div ref={ref} data-state={state} />,CSS 里按 [data-state] 写过渡。
|
|
29
|
+
*/
|
|
30
|
+
export declare function usePresence(open: boolean, exitMs?: number): {
|
|
31
|
+
mounted: boolean;
|
|
32
|
+
state: PresenceState;
|
|
33
|
+
ref: MutableRefObject<HTMLElement | null>;
|
|
34
|
+
};
|
|
35
|
+
/** 锁住页面滚动(模态浮层打开时)。支持嵌套 */
|
|
36
|
+
export declare function useScrollLock(active: boolean): void;
|
|
37
|
+
export declare function useEscape(active: boolean, onEscape: () => void): void;
|
|
38
|
+
/** 点在若干元素之外时触发 */
|
|
39
|
+
export declare function useOutsidePress(active: boolean, refs: Array<{
|
|
40
|
+
current: HTMLElement | null;
|
|
41
|
+
}>, onOutside: (e: PointerEvent) => void): void;
|
|
42
|
+
/**
|
|
43
|
+
* 模态浮层打开期间,把 body 下除浮层之外的顶层节点对读屏和键盘隐藏(inert;不支持时退回 aria-hidden),关闭时恢复原值。
|
|
44
|
+
* 按节点计数,嵌套多层模态、乱序关闭都能正确恢复。之后才挂到 body 下的浮层(模态里打开的 Select / Menu / Tooltip / Toast)不受影响。
|
|
45
|
+
* layerRef 指向浮层自己(或它里面的任意节点):包含它的那个顶层节点不会被隐藏。
|
|
46
|
+
*/
|
|
47
|
+
export declare function useInertOthers(active: boolean, layerRef: {
|
|
48
|
+
current: Element | null;
|
|
49
|
+
}): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export declare const ICONS: {
|
|
2
|
+
readonly search: "<circle cx=\"9\" cy=\"9\" r=\"5.5\"/><path d=\"M13.2 13.2L17 17\"/>";
|
|
3
|
+
readonly check: "<path d=\"M4.500 10.500l3.500 3.500 7.500-8\"/>";
|
|
4
|
+
readonly x: "<path d=\"M5.500 5.500l9 9M14.500 5.500l-9 9\"/>";
|
|
5
|
+
readonly plus: "<path d=\"M10 4.500v11M4.500 10h11\"/>";
|
|
6
|
+
readonly minus: "<path d=\"M4.500 10h11\"/>";
|
|
7
|
+
readonly 'chevron-right': "<path d=\"M7.500 4.500L13 10l-5.500 5.500\"/>";
|
|
8
|
+
readonly 'chevron-down': "<path d=\"M4.500 7.500L10 13l5.500-5.500\"/>";
|
|
9
|
+
readonly sun: "<circle cx=\"10\" cy=\"10\" r=\"3.300\"/><path d=\"M10 2.500v1.800M10 15.700v1.800M2.500 10h1.800M15.700 10h1.800M4.700 4.700L6 6M14 14l1.300 1.300M4.700 15.300L6 14M14 6l1.300-1.300\"/>";
|
|
10
|
+
readonly moon: "<path d=\"M16.500 11.800A7 7 0 1 1 8.200 3.500a5.500 5.500 0 0 0 8.300 8.300z\"/>";
|
|
11
|
+
readonly monitor: "<rect x=\"3\" y=\"4\" width=\"14\" height=\"9.500\" rx=\"2.200\"/><path d=\"M7.500 16.500h5M10 13.500v3\"/>";
|
|
12
|
+
readonly copy: "<rect x=\"7\" y=\"7\" width=\"9.500\" height=\"9.500\" rx=\"2.500\"/><path d=\"M13 7V5.500A2 2 0 0 0 11 3.500H5.500a2 2 0 0 0-2 2V11a2 2 0 0 0 2 2H7\"/>";
|
|
13
|
+
readonly play: "<path d=\"M7 4.600v10.800a.7.700 0 0 0 1.100.600l8-5.400a.7.700 0 0 0 0-1.200l-8-5.400A.7.700 0 0 0 7 4.600z\" fill=\"currentColor\" stroke=\"none\"/>";
|
|
14
|
+
readonly replay: "<path d=\"M4.300 10a5.700 5.700 0 1 0 1.900-4.200M4 3.500v3h3\"/>";
|
|
15
|
+
readonly info: "<circle cx=\"10\" cy=\"10\" r=\"7\"/><path d=\"M10 9.300v4.200M10 6.500v.1\"/>";
|
|
16
|
+
readonly alert: "<path d=\"M10 3.500l7 12.500H3l7-12.500zM10 8.500v3.200M10 14v.1\"/>";
|
|
17
|
+
readonly bell: "<path d=\"M5.500 8.500a4.500 4.500 0 0 1 9 0c0 4 1.500 5 1.500 5H4s1.500-1 1.500-5zM8.300 16.200a1.800 1.800 0 0 0 3.400 0\"/>";
|
|
18
|
+
readonly trash: "<path d=\"M4.500 6h11M8 6V4.500h4V6M6 6l.7 8.800a1.600 1.600 0 0 0 1.600 1.500h3.400a1.600 1.600 0 0 0 1.600-1.500L14 6\"/>";
|
|
19
|
+
readonly more: "<path d=\"M5 10v.1M10 10v.1M15 10v.1\" stroke-width=\"2.600\"/>";
|
|
20
|
+
readonly download: "<path d=\"M10 3.500v9M6.500 9.500L10 13l3.500-3.500M4.500 16.500h11\"/>";
|
|
21
|
+
readonly upload: "<path d=\"M10 13V4M6.500 7.500L10 4l3.500 3.500M4.500 16.500h11\"/>";
|
|
22
|
+
readonly edit: "<path d=\"M4 16l.8-3.300L13.400 4a1.700 1.700 0 0 1 2.400 0l.2.2a1.700 1.700 0 0 1 0 2.400L7.300 15.200 4 16z\"/>";
|
|
23
|
+
readonly share: "<path d=\"M10 12.500V3.500M6.800 6.500L10 3.500l3.200 3M5 10v5a1.500 1.500 0 0 0 1.500 1.500h7A1.500 1.500 0 0 0 15 15v-5\"/>";
|
|
24
|
+
readonly mail: "<rect x=\"3\" y=\"4.800\" width=\"14\" height=\"10.500\" rx=\"2.500\"/><path d=\"M3.800 7l6.200 4.300L16.200 7\"/>";
|
|
25
|
+
readonly sparkle: "<path d=\"M10 3.500l1.700 4.800 4.800 1.700-4.800 1.700L10 16.500l-1.700-4.800L3.500 10l4.800-1.700z\"/>";
|
|
26
|
+
readonly shuffle: "<path d=\"M3.500 6h2.300c1.400 0 2.600.7 3.300 1.900l1.800 4.200c.7 1.200 1.900 1.900 3.300 1.900h2.300M14.500 4l2 2-2 2M14.500 12l2 2-2 2M3.500 14h2.300c.9 0 1.700-.3 2.300-.8M16.500 6h-2.300c-.9 0-1.700.3-2.300.8\"/>";
|
|
27
|
+
readonly sliders: "<path d=\"M3.500 6.500h6M13.500 6.500h3M3.500 13.500h3M10.500 13.500h6\"/><circle cx=\"11.500\" cy=\"6.500\" r=\"2\"/><circle cx=\"8.500\" cy=\"13.500\" r=\"2\"/>";
|
|
28
|
+
readonly home: "<path d=\"M3.5 9.2L10 3.5l6.5 5.7V15a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 15V9.2z\"/><path d=\"M8 16.5V12h4v4.5\"/>";
|
|
29
|
+
readonly user: "<circle cx=\"10\" cy=\"7\" r=\"3.2\"/><path d=\"M4 16.5c.7-2.8 3-4.3 6-4.3s5.3 1.5 6 4.3\"/>";
|
|
30
|
+
readonly users: "<circle cx=\"7.5\" cy=\"7.2\" r=\"2.8\"/><path d=\"M2.5 16c.6-2.5 2.5-3.800 5-3.800s4.400 1.300 5 3.800M12.800 4.600a2.800 2.800 0 0 1 0 5.200M14.800 12.500c1.400.5 2.300 1.700 2.700 3.500\"/>";
|
|
31
|
+
readonly settings: "<path d=\"M8.600 3h2.800l.5 2 1.800 1 2-.6 1.400 2.400-1.500 1.500v1.400l1.500 1.500-1.400 2.400-2-.6-1.800 1-.5 2H8.600l-.5-2-1.800-1-2 .6-1.400-2.400 1.500-1.500V9.300L2.900 7.800l1.400-2.400 2 .6 1.800-1z\"/><circle cx=\"10\" cy=\"10\" r=\"2.500\"/>";
|
|
32
|
+
readonly heart: "<path d=\"M10 16.500S3.500 12.700 3.500 8.200A3.700 3.700 0 0 1 10 5.900a3.700 3.700 0 0 1 6.500 2.300c0 4.500-6.500 8.300-6.500 8.300z\"/>";
|
|
33
|
+
readonly star: "<path d=\"M10 3.500l1.800 4.500 4.900.4-3.700 3.100 1.100 4.700L10 13.600l-4.100 2.600 1.100-4.700-3.700-3.100 4.900-.4z\"/>";
|
|
34
|
+
readonly cart: "<path d=\"M2.500 3.500h2l1.800 8.500h8.200l1.500-6H5\"/><circle cx=\"7.500\" cy=\"15.500\" r=\"1.200\"/><circle cx=\"13.500\" cy=\"15.500\" r=\"1.200\"/>";
|
|
35
|
+
readonly bag: "<path d=\"M4.500 7h11l-.7 8.100a1.500 1.500 0 0 1-1.500 1.400H6.700a1.500 1.500 0 0 1-1.500-1.400L4.500 7z\"/><path d=\"M7.500 9V6.500a2.500 2.500 0 0 1 5 0V9\"/>";
|
|
36
|
+
readonly grid: "<rect x=\"3.500\" y=\"3.500\" width=\"5.500\" height=\"5.500\" rx=\"1.500\"/><rect x=\"11\" y=\"3.500\" width=\"5.500\" height=\"5.500\" rx=\"1.500\"/><rect x=\"3.500\" y=\"11\" width=\"5.500\" height=\"5.500\" rx=\"1.500\"/><rect x=\"11\" y=\"11\" width=\"5.500\" height=\"5.500\" rx=\"1.500\"/>";
|
|
37
|
+
readonly list: "<path d=\"M7.500 5.500h9M7.500 10h9M7.500 14.500h9\"/><path d=\"M3.800 5.500v.1M3.800 10v.1M3.800 14.500v.1\" stroke-width=\"2.400\"/>";
|
|
38
|
+
readonly filter: "<path d=\"M3.500 4.500h13l-5 6V15l-3 1.500v-6l-5-6z\"/>";
|
|
39
|
+
readonly calendar: "<rect x=\"3.500\" y=\"4.500\" width=\"13\" height=\"12\" rx=\"2.500\"/><path d=\"M3.500 8.500h13M7 3v3M13 3v3\"/>";
|
|
40
|
+
readonly clock: "<circle cx=\"10\" cy=\"10\" r=\"7\"/><path d=\"M10 6v4l2.500 1.500\"/>";
|
|
41
|
+
readonly inbox: "<path d=\"M3.500 11l2-6a1.500 1.500 0 0 1 1.400-1h6.200a1.500 1.500 0 0 1 1.400 1l2 6v3.500A1.500 1.500 0 0 1 15 16H5a1.500 1.500 0 0 1-1.500-1.500V11z\"/><path d=\"M3.500 11H7l1 2h4l1-2h3.500\"/>";
|
|
42
|
+
readonly send: "<path d=\"M16.500 3.500L3.500 8.700l5.300 2.500 2.500 5.300 5.200-13zM8.800 11.200L12 8\"/>";
|
|
43
|
+
readonly archive: "<rect x=\"3\" y=\"4\" width=\"14\" height=\"4\" rx=\"1.200\"/><path d=\"M4.500 8v6.500A1.500 1.500 0 0 0 6 16h8a1.500 1.500 0 0 0 1.500-1.500V8M8.300 11.200h3.400\"/>";
|
|
44
|
+
readonly reply: "<path d=\"M8 5.500L3.500 10 8 14.500M3.500 10h8a5 5 0 0 1 5 5v.5\"/>";
|
|
45
|
+
readonly forward: "<path d=\"M12 5.500l4.500 4.500-4.500 4.500M16.500 10h-8a5 5 0 0 0-5 5v.5\"/>";
|
|
46
|
+
readonly paperclip: "<path d=\"M15.500 9.500l-5.700 5.700a3.540 3.540 0 0 1-5-5l6-6a2.340 2.340 0 0 1 3.300 3.300l-5.900 5.900a1.200 1.200 0 0 1-1.700-1.700l5.300-5.300\"/>";
|
|
47
|
+
readonly folder: "<path d=\"M3.500 6A1.500 1.500 0 0 1 5 4.500h3l1.800 2H15A1.500 1.500 0 0 1 16.500 8v6.500A1.500 1.500 0 0 1 15 16H5a1.500 1.500 0 0 1-1.500-1.500V6z\"/>";
|
|
48
|
+
readonly file: "<path d=\"M11.500 3.500h-5A1.500 1.500 0 0 0 5 5v10a1.500 1.500 0 0 0 1.500 1.500h7A1.500 1.500 0 0 0 15 15V7l-3.500-3.500z\"/><path d=\"M11.500 3.500V7H15\"/>";
|
|
49
|
+
readonly image: "<rect x=\"3.500\" y=\"4\" width=\"13\" height=\"12\" rx=\"2.500\"/><circle cx=\"7.500\" cy=\"8\" r=\"1.300\"/><path d=\"M4.200 13.800l3.300-3.300 3 3 2-2 3.300 3.300\"/>";
|
|
50
|
+
readonly link: "<path d=\"M8.500 11.500a3.200 3.200 0 0 0 4.500 0L15.500 9A3.200 3.200 0 0 0 11 4.500l-.8.8\"/><path d=\"M11.500 8.500a3.200 3.200 0 0 0-4.500 0L4.500 11A3.200 3.200 0 0 0 9 15.500l.8-.8\"/>";
|
|
51
|
+
readonly external: "<path d=\"M11.500 4H16v4.500M16 4l-7 7M14 11.500V15a1.500 1.500 0 0 1-1.500 1.500H5A1.500 1.500 0 0 1 3.500 15V7.500A1.500 1.500 0 0 1 5 6h3.500\"/>";
|
|
52
|
+
readonly eye: "<path d=\"M2.500 10S5.200 5 10 5s7.500 5 7.500 5-2.700 5-7.500 5-7.500-5-7.500-5z\"/><circle cx=\"10\" cy=\"10\" r=\"2.300\"/>";
|
|
53
|
+
readonly 'eye-off': "<path d=\"M8.300 5.200A7 7 0 0 1 10 5c4.800 0 7.500 5 7.500 5a12.500 12.500 0 0 1-1.900 2.500M12.900 14.300A6.500 6.500 0 0 1 10 15c-4.800 0-7.500-5-7.500-5a12.300 12.300 0 0 1 3.300-3.700M3.500 3.500l13 13M8.400 8.400a2.300 2.300 0 0 0 3.200 3.200\"/>";
|
|
54
|
+
readonly lock: "<rect x=\"4.500\" y=\"9\" width=\"11\" height=\"7.500\" rx=\"2\"/><path d=\"M7 9V6.500a3 3 0 0 1 6 0V9\"/>";
|
|
55
|
+
readonly tag: "<path d=\"M3.500 4.500v5.200a1.500 1.500 0 0 0 .4 1l5.700 5.700a1.500 1.500 0 0 0 2.100 0l4.700-4.700a1.500 1.500 0 0 0 0-2.100l-5.700-5.700a1.500 1.500 0 0 0-1-.4H4.500a1 1 0 0 0-1 1z\"/><path d=\"M7 7v.1\" stroke-width=\"2.400\"/>";
|
|
56
|
+
readonly bookmark: "<path d=\"M5.500 4.500A1.500 1.500 0 0 1 7 3h6a1.500 1.500 0 0 1 1.500 1.500v12L10 13.500l-4.500 3v-12z\"/>";
|
|
57
|
+
readonly 'chevron-left': "<path d=\"M12.500 4.500L7 10l5.500 5.500\"/>";
|
|
58
|
+
readonly 'chevron-up': "<path d=\"M4.500 12.500L10 7l5.500 5.500\"/>";
|
|
59
|
+
readonly 'arrow-left': "<path d=\"M16 10H4M8.500 5.500L4 10l4.500 4.500\"/>";
|
|
60
|
+
readonly 'arrow-right': "<path d=\"M4 10h12M11.500 5.500L16 10l-4.500 4.500\"/>";
|
|
61
|
+
readonly 'arrow-up': "<path d=\"M10 16V4M5.500 8.500L10 4l4.500 4.500\"/>";
|
|
62
|
+
readonly 'arrow-down': "<path d=\"M10 4v12M5.500 11.500L10 16l4.500-4.500\"/>";
|
|
63
|
+
readonly refresh: "<path d=\"M16 10a6 6 0 0 1-10.600 3.800M4 10a6 6 0 0 1 10.600-3.800M14.500 3v3.200h-3.200M5.500 17v-3.200h3.200\"/>";
|
|
64
|
+
readonly menu: "<path d=\"M3.500 6h13M3.500 10h13M3.500 14h13\"/>";
|
|
65
|
+
readonly close: "<path d=\"M5.500 5.500l9 9M14.500 5.500l-9 9\"/>";
|
|
66
|
+
readonly 'check-circle': "<circle cx=\"10\" cy=\"10\" r=\"7\"/><path d=\"M6.800 10.300l2.200 2.200 4.200-4.600\"/>";
|
|
67
|
+
readonly 'x-circle': "<circle cx=\"10\" cy=\"10\" r=\"7\"/><path d=\"M7.500 7.500l5 5M12.500 7.500l-5 5\"/>";
|
|
68
|
+
readonly help: "<circle cx=\"10\" cy=\"10\" r=\"7\"/><path d=\"M7.900 8a2.200 2.200 0 1 1 3.200 2c-.7.4-1.100.9-1.100 1.600M10 14v.1\"/>";
|
|
69
|
+
readonly globe: "<circle cx=\"10\" cy=\"10\" r=\"7\"/><path d=\"M3 10h14M10 3c2 2.200 3 4.500 3 7s-1 4.800-3 7c-2-2.200-3-4.500-3-7s1-4.800 3-7z\"/>";
|
|
70
|
+
readonly phone: "<rect x=\"5.500\" y=\"2.500\" width=\"9\" height=\"15\" rx=\"2.200\"/><path d=\"M9 14.500h2\"/>";
|
|
71
|
+
readonly 'credit-card': "<rect x=\"2.500\" y=\"4.500\" width=\"15\" height=\"11\" rx=\"2.200\"/><path d=\"M2.500 8.500h15M5.500 12.500h3\"/>";
|
|
72
|
+
readonly truck: "<path d=\"M4.200 13.500H2.500v-8h9v8M7.800 13.500h4.400M11.500 8.500h3l3 3v2h-1.700\"/><circle cx=\"6\" cy=\"14.500\" r=\"1.600\"/><circle cx=\"14\" cy=\"14.500\" r=\"1.600\"/>";
|
|
73
|
+
readonly chart: "<path d=\"M3.500 16.500h13M6 13.500V10M10 13.500V5M14 13.500V8\"/>";
|
|
74
|
+
readonly 'trending-up': "<path d=\"M3 14l4.500-4.500 3 3L17 6M12.500 6H17v4.500\"/>";
|
|
75
|
+
readonly 'trending-down': "<path d=\"M3 6l4.500 4.500 3-3L17 14M12.500 14H17V9.500\"/>";
|
|
76
|
+
readonly layout: "<rect x=\"3\" y=\"3.500\" width=\"14\" height=\"13\" rx=\"2.500\"/><path d=\"M3 8h14M8 8v8.500\"/>";
|
|
77
|
+
readonly sidebar: "<rect x=\"3\" y=\"3.500\" width=\"14\" height=\"13\" rx=\"2.500\"/><path d=\"M8 3.500v13\"/>";
|
|
78
|
+
readonly command: "<path d=\"M7.500 7.500h5v5h-5zM7.500 7.500h-2a2 2 0 1 1 2-2zM12.500 7.500v-2a2 2 0 1 1 2 2zM12.500 12.500h2a2 2 0 1 1-2 2zM7.500 12.500v2a2 2 0 1 1-2-2z\"/>";
|
|
79
|
+
readonly zap: "<path d=\"M11 2.500l-6.500 9H10l-1 6 6.500-9H10l1-6z\"/>";
|
|
80
|
+
};
|
|
81
|
+
export type IconName = keyof typeof ICONS;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from './utils';
|
|
2
|
+
export * from './hooks';
|
|
3
|
+
export * from './motion';
|
|
4
|
+
export * from './Portal';
|
|
5
|
+
export * from './FocusScope';
|
|
6
|
+
export * from './Icon';
|
|
7
|
+
export * from './VisuallyHidden';
|
|
8
|
+
export { ICONS } from './icons';
|
|
9
|
+
export type { IconName } from './icons';
|
|
10
|
+
export * from './color';
|
|
11
|
+
export * from './theme';
|
|
12
|
+
export * from './locale';
|
|
13
|
+
export * from './tail';
|
|
14
|
+
export * from './OinkLogo';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Messages } from './messages';
|
|
3
|
+
export type { Messages } from './messages';
|
|
4
|
+
/** 组件内置文案和日期格式用的语言 */
|
|
5
|
+
export type OinkLocale = 'zh-CN' | 'en-US';
|
|
6
|
+
/** 各语言的内置文案 */
|
|
7
|
+
export declare const OINK_MESSAGES: Record<OinkLocale, Messages>;
|
|
8
|
+
export interface LocaleProviderProps {
|
|
9
|
+
/** 不传(undefined)时沿用外层的设置,最外层是 zh-CN */
|
|
10
|
+
locale?: OinkLocale;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
/** 在这一块里切换组件内置文案的语言。可以嵌套,内层优先。OinkProvider 的 locale 就是包了一层它 */
|
|
14
|
+
export declare function LocaleProvider({ locale, children }: LocaleProviderProps): import("react").JSX.Element;
|
|
15
|
+
/** 当前语言和对应的内置文案。没有 Provider 时是 zh-CN;不认识的语言回退到 zh-CN */
|
|
16
|
+
export declare function useLocale(): {
|
|
17
|
+
locale: OinkLocale;
|
|
18
|
+
messages: Messages;
|
|
19
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 组件内置文案(默认的 aria-label、按钮文字、读屏播报、占位符、空状态……)。
|
|
3
|
+
* 每种语言一份;带参数的写成函数。组件里一律通过 useLocale().messages 取,不要写死。
|
|
4
|
+
* zh-CN 就是组件原来的文案,改动时注意测试里断言的中文。
|
|
5
|
+
*/
|
|
6
|
+
export type AvatarStatusText = Record<'online' | 'busy' | 'away' | 'offline', string>;
|
|
7
|
+
export interface Messages {
|
|
8
|
+
common: {
|
|
9
|
+
/** 关闭按钮 */
|
|
10
|
+
close: string;
|
|
11
|
+
/** 清除按钮 */
|
|
12
|
+
clear: string;
|
|
13
|
+
/** 加载器的读屏文字 */
|
|
14
|
+
loading: string;
|
|
15
|
+
/** 移除按钮 */
|
|
16
|
+
remove: string;
|
|
17
|
+
/** 读屏文字里分隔几段话的标点 */
|
|
18
|
+
separator: string;
|
|
19
|
+
};
|
|
20
|
+
avatar: {
|
|
21
|
+
status: AvatarStatusText;
|
|
22
|
+
/** “+N” 头像的名字 */
|
|
23
|
+
more: (n: number) => string;
|
|
24
|
+
/** “+N” 按钮的名字;label 是头像组的名字 */
|
|
25
|
+
moreButton: (n: number, label?: string) => string;
|
|
26
|
+
/** 浮出的成员面板的名字 */
|
|
27
|
+
panel: (total: number, label?: string) => string;
|
|
28
|
+
/** 面板底部:还有几个人没列出 */
|
|
29
|
+
rest: (n: number) => string;
|
|
30
|
+
};
|
|
31
|
+
breadcrumb: {
|
|
32
|
+
label: string;
|
|
33
|
+
/** 展开折叠的中间几级 */
|
|
34
|
+
expand: (n: number) => string;
|
|
35
|
+
};
|
|
36
|
+
code: {
|
|
37
|
+
label: string;
|
|
38
|
+
copy: string;
|
|
39
|
+
copied: string;
|
|
40
|
+
copyFailed: string;
|
|
41
|
+
};
|
|
42
|
+
pagination: {
|
|
43
|
+
label: string;
|
|
44
|
+
prev: string;
|
|
45
|
+
next: string;
|
|
46
|
+
page: (page: number) => string;
|
|
47
|
+
status: (page: number, total: number) => string;
|
|
48
|
+
};
|
|
49
|
+
reaction: {
|
|
50
|
+
label: string;
|
|
51
|
+
};
|
|
52
|
+
stat: {
|
|
53
|
+
trend: Record<'up' | 'down' | 'flat', string>;
|
|
54
|
+
};
|
|
55
|
+
steps: {
|
|
56
|
+
label: string;
|
|
57
|
+
state: Record<'complete' | 'current' | 'upcoming', string>;
|
|
58
|
+
error: string;
|
|
59
|
+
/** 每一步标题前的读屏前缀 */
|
|
60
|
+
prefix: (step: number, state: string) => string;
|
|
61
|
+
};
|
|
62
|
+
table: {
|
|
63
|
+
label: string;
|
|
64
|
+
empty: string;
|
|
65
|
+
selectAll: string;
|
|
66
|
+
/** 选择列的移动端标签 */
|
|
67
|
+
selectColumn: string;
|
|
68
|
+
selectRow: (rowLabel: string) => string;
|
|
69
|
+
/** 第一列不是文字时的行名 */
|
|
70
|
+
row: (n: number) => string;
|
|
71
|
+
selected: (n: number) => string;
|
|
72
|
+
pagination: (tableLabel: string) => string;
|
|
73
|
+
};
|
|
74
|
+
tag: {
|
|
75
|
+
remove: (text?: string) => string;
|
|
76
|
+
};
|
|
77
|
+
button: {
|
|
78
|
+
status: Record<'loading' | 'success' | 'error', string>;
|
|
79
|
+
};
|
|
80
|
+
colorPicker: {
|
|
81
|
+
label: string;
|
|
82
|
+
area: string;
|
|
83
|
+
areaRole: string;
|
|
84
|
+
areaValue: (saturation: number, brightness: number) => string;
|
|
85
|
+
hue: string;
|
|
86
|
+
hex: string;
|
|
87
|
+
eyedropper: string;
|
|
88
|
+
swatches: string;
|
|
89
|
+
};
|
|
90
|
+
fileDrop: {
|
|
91
|
+
title: string;
|
|
92
|
+
/** 选完文件后的读屏播报:accepted 个收下(只有一个时给出文件名),rejected 个不符合要求 */
|
|
93
|
+
status: (accepted: number, firstName: string, rejected: number) => string;
|
|
94
|
+
};
|
|
95
|
+
hotkey: {
|
|
96
|
+
placeholder: string;
|
|
97
|
+
recording: string;
|
|
98
|
+
spokenRecording: (recordingText: string) => string;
|
|
99
|
+
spokenCurrent: (keys: string) => string;
|
|
100
|
+
none: string;
|
|
101
|
+
};
|
|
102
|
+
/** 按键的可读名称(KeyboardEvent.key → 名字),给读屏和键帽的提示用 */
|
|
103
|
+
keyNames: Record<string, string>;
|
|
104
|
+
input: {
|
|
105
|
+
showPassword: string;
|
|
106
|
+
};
|
|
107
|
+
numberInput: {
|
|
108
|
+
decrement: string;
|
|
109
|
+
increment: string;
|
|
110
|
+
};
|
|
111
|
+
pinInput: {
|
|
112
|
+
label: string;
|
|
113
|
+
cell: (index: number, length: number) => string;
|
|
114
|
+
};
|
|
115
|
+
rangeSlider: {
|
|
116
|
+
thumbs: [string, string];
|
|
117
|
+
};
|
|
118
|
+
rating: {
|
|
119
|
+
label: string;
|
|
120
|
+
star: (n: number) => string;
|
|
121
|
+
value: (current: number, max: number) => string;
|
|
122
|
+
};
|
|
123
|
+
searchInput: {
|
|
124
|
+
placeholder: string;
|
|
125
|
+
};
|
|
126
|
+
appShell: {
|
|
127
|
+
skipLink: string;
|
|
128
|
+
sidebar: string;
|
|
129
|
+
aside: string;
|
|
130
|
+
toggleSidebar: string;
|
|
131
|
+
toggleAside: string;
|
|
132
|
+
};
|
|
133
|
+
splitPane: {
|
|
134
|
+
separator: string;
|
|
135
|
+
};
|
|
136
|
+
commandPalette: {
|
|
137
|
+
label: string;
|
|
138
|
+
placeholder: string;
|
|
139
|
+
empty: string;
|
|
140
|
+
results: (n: number) => string;
|
|
141
|
+
};
|
|
142
|
+
toast: {
|
|
143
|
+
label: string;
|
|
144
|
+
};
|
|
145
|
+
confirm: {
|
|
146
|
+
confirm: string;
|
|
147
|
+
cancel: string;
|
|
148
|
+
};
|
|
149
|
+
calendar: {
|
|
150
|
+
prevMonth: string;
|
|
151
|
+
nextMonth: string;
|
|
152
|
+
/** 接在“今天”那一格的日期名字后面 */
|
|
153
|
+
todaySuffix: string;
|
|
154
|
+
};
|
|
155
|
+
datePicker: {
|
|
156
|
+
placeholder: string;
|
|
157
|
+
dialog: string;
|
|
158
|
+
open: string;
|
|
159
|
+
rangePlaceholder: string;
|
|
160
|
+
rangeDialog: string;
|
|
161
|
+
};
|
|
162
|
+
combobox: {
|
|
163
|
+
loading: string;
|
|
164
|
+
empty: string;
|
|
165
|
+
listbox: string;
|
|
166
|
+
};
|
|
167
|
+
select: {
|
|
168
|
+
placeholder: string;
|
|
169
|
+
count: (n: number) => string;
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export declare const zhCN: Messages;
|
|
173
|
+
export declare const enUS: Messages;
|