@tuuject/koi-react 0.0.0-stage → 0.1.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 +73 -2
- package/dist/alert/Alert.d.ts +13 -0
- package/dist/alert/Alert.js +16 -0
- package/dist/avatar/Avatar.d.ts +7 -0
- package/dist/avatar/Avatar.js +10 -0
- package/dist/badge/Badge.d.ts +7 -0
- package/dist/badge/Badge.js +8 -0
- package/dist/button/Button.d.ts +22 -0
- package/dist/button/Button.js +28 -0
- package/dist/card/Card.d.ts +9 -0
- package/dist/card/Card.js +8 -0
- package/dist/chat-bubble/ChatBubble.d.ts +7 -0
- package/dist/chat-bubble/ChatBubble.js +7 -0
- package/dist/checkbox/Checkbox.d.ts +18 -0
- package/dist/checkbox/Checkbox.js +25 -0
- package/dist/dialog/Dialog.d.ts +13 -0
- package/dist/dialog/Dialog.js +38 -0
- package/dist/divider/Divider.d.ts +6 -0
- package/dist/divider/Divider.js +17 -0
- package/dist/field/Field.d.ts +14 -0
- package/dist/field/Field.js +19 -0
- package/dist/field/context.d.ts +5 -0
- package/dist/field/context.js +2 -0
- package/dist/icons.d.ts +26 -0
- package/dist/icons.js +46 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +30 -0
- package/dist/input/Input.d.ts +9 -0
- package/dist/input/Input.js +15 -0
- package/dist/link/Link.d.ts +11 -0
- package/dist/link/Link.js +17 -0
- package/dist/pagination/Pagination.d.ts +7 -0
- package/dist/pagination/Pagination.js +26 -0
- package/dist/panda/buildinfo.json +10442 -0
- package/dist/panda/lib.json +18 -0
- package/dist/panda/preset.mjs +3907 -0
- package/dist/progress/Progress.d.ts +7 -0
- package/dist/progress/Progress.js +17 -0
- package/dist/prose/Prose.d.ts +10 -0
- package/dist/prose/Prose.js +10 -0
- package/dist/radio-group/RadioGroup.d.ts +15 -0
- package/dist/radio-group/RadioGroup.js +26 -0
- package/dist/select/Select.d.ts +11 -0
- package/dist/select/Select.js +21 -0
- package/dist/select/SelectPanel.d.ts +24 -0
- package/dist/select/SelectPanel.js +105 -0
- package/dist/shape.d.ts +16 -0
- package/dist/shape.js +17 -0
- package/dist/skeleton/Skeleton.d.ts +8 -0
- package/dist/skeleton/Skeleton.js +8 -0
- package/dist/spinner/Spinner.d.ts +7 -0
- package/dist/spinner/Spinner.js +13 -0
- package/dist/switch/Switch.d.ts +22 -0
- package/dist/switch/Switch.js +23 -0
- package/dist/table/DataTable.d.ts +12 -0
- package/dist/table/DataTable.js +12 -0
- package/dist/table/Table.d.ts +38 -0
- package/dist/table/Table.js +45 -0
- package/dist/tabs/Tabs.d.ts +11 -0
- package/dist/tabs/Tabs.js +20 -0
- package/dist/tag/Tag.d.ts +6 -0
- package/dist/tag/Tag.js +15 -0
- package/dist/textarea/Textarea.d.ts +9 -0
- package/dist/textarea/Textarea.js +14 -0
- package/dist/toast/Toast.d.ts +23 -0
- package/dist/toast/Toast.js +80 -0
- package/dist/tooltip/Tooltip.d.ts +9 -0
- package/dist/tooltip/Tooltip.js +29 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +1 -0
- package/package.json +218 -3
- package/styled-system/css/conditions.d.ts +7 -0
- package/styled-system/css/conditions.js +32 -0
- package/styled-system/css/css.d.ts +22 -0
- package/styled-system/css/css.js +63 -0
- package/styled-system/css/cva.d.ts +5 -0
- package/styled-system/css/cva.js +51 -0
- package/styled-system/css/cx.d.ts +6 -0
- package/styled-system/css/cx.js +16 -0
- package/styled-system/css/first-that-works.d.ts +22 -0
- package/styled-system/css/first-that-works.js +1 -0
- package/styled-system/css/index.d.ts +8 -0
- package/styled-system/css/index.js +8 -0
- package/styled-system/css/keyframes.d.ts +5 -0
- package/styled-system/css/keyframes.js +8 -0
- package/styled-system/css/position-try.d.ts +5 -0
- package/styled-system/css/position-try.js +11 -0
- package/styled-system/css/sva.d.ts +3 -0
- package/styled-system/css/sva.js +49 -0
- package/styled-system/css/view-transition.d.ts +7 -0
- package/styled-system/css/view-transition.js +18 -0
- package/styled-system/helpers.d.ts +67 -0
- package/styled-system/helpers.js +624 -0
- package/styled-system/jsx/aspect-ratio.d.ts +7 -0
- package/styled-system/jsx/aspect-ratio.js +11 -0
- package/styled-system/jsx/bleed.d.ts +7 -0
- package/styled-system/jsx/bleed.js +11 -0
- package/styled-system/jsx/box.d.ts +7 -0
- package/styled-system/jsx/box.js +11 -0
- package/styled-system/jsx/center.d.ts +7 -0
- package/styled-system/jsx/center.js +11 -0
- package/styled-system/jsx/circle.d.ts +7 -0
- package/styled-system/jsx/circle.js +11 -0
- package/styled-system/jsx/container.d.ts +7 -0
- package/styled-system/jsx/container.js +11 -0
- package/styled-system/jsx/cq.d.ts +7 -0
- package/styled-system/jsx/cq.js +11 -0
- package/styled-system/jsx/create-recipe-context.d.ts +32 -0
- package/styled-system/jsx/create-recipe-context.js +38 -0
- package/styled-system/jsx/create-slot-recipe-context.d.ts +48 -0
- package/styled-system/jsx/create-slot-recipe-context.js +116 -0
- package/styled-system/jsx/divider.d.ts +7 -0
- package/styled-system/jsx/divider.js +11 -0
- package/styled-system/jsx/factory.d.ts +3 -0
- package/styled-system/jsx/factory.js +91 -0
- package/styled-system/jsx/flex.d.ts +7 -0
- package/styled-system/jsx/flex.js +11 -0
- package/styled-system/jsx/float.d.ts +7 -0
- package/styled-system/jsx/float.js +11 -0
- package/styled-system/jsx/grid-item.d.ts +7 -0
- package/styled-system/jsx/grid-item.js +11 -0
- package/styled-system/jsx/grid.d.ts +7 -0
- package/styled-system/jsx/grid.js +11 -0
- package/styled-system/jsx/helper.d.ts +34 -0
- package/styled-system/jsx/helper.js +83 -0
- package/styled-system/jsx/hstack.d.ts +7 -0
- package/styled-system/jsx/hstack.js +11 -0
- package/styled-system/jsx/index.d.ts +25 -0
- package/styled-system/jsx/index.js +24 -0
- package/styled-system/jsx/is-valid-prop.d.ts +7 -0
- package/styled-system/jsx/is-valid-prop.js +12 -0
- package/styled-system/jsx/link-overlay.d.ts +7 -0
- package/styled-system/jsx/link-overlay.js +11 -0
- package/styled-system/jsx/spacer.d.ts +7 -0
- package/styled-system/jsx/spacer.js +11 -0
- package/styled-system/jsx/square.d.ts +7 -0
- package/styled-system/jsx/square.js +11 -0
- package/styled-system/jsx/stack.d.ts +7 -0
- package/styled-system/jsx/stack.js +11 -0
- package/styled-system/jsx/visually-hidden.d.ts +7 -0
- package/styled-system/jsx/visually-hidden.js +11 -0
- package/styled-system/jsx/vstack.d.ts +7 -0
- package/styled-system/jsx/vstack.js +11 -0
- package/styled-system/jsx/wrap.d.ts +7 -0
- package/styled-system/jsx/wrap.js +11 -0
- package/styled-system/patterns/aspect-ratio.d.ts +19 -0
- package/styled-system/patterns/aspect-ratio.js +37 -0
- package/styled-system/patterns/bleed.d.ts +20 -0
- package/styled-system/patterns/bleed.js +30 -0
- package/styled-system/patterns/box.d.ts +17 -0
- package/styled-system/patterns/box.js +16 -0
- package/styled-system/patterns/center.d.ts +19 -0
- package/styled-system/patterns/center.js +22 -0
- package/styled-system/patterns/circle.d.ts +19 -0
- package/styled-system/patterns/circle.js +26 -0
- package/styled-system/patterns/container.d.ts +17 -0
- package/styled-system/patterns/container.js +26 -0
- package/styled-system/patterns/cq.d.ts +21 -0
- package/styled-system/patterns/cq.js +24 -0
- package/styled-system/patterns/divider.d.ts +22 -0
- package/styled-system/patterns/divider.js +31 -0
- package/styled-system/patterns/flex.d.ts +25 -0
- package/styled-system/patterns/flex.js +27 -0
- package/styled-system/patterns/float.d.ts +23 -0
- package/styled-system/patterns/float.js +84 -0
- package/styled-system/patterns/grid-item.d.ts +24 -0
- package/styled-system/patterns/grid-item.js +26 -0
- package/styled-system/patterns/grid.d.ts +24 -0
- package/styled-system/patterns/grid.js +30 -0
- package/styled-system/patterns/hstack.d.ts +20 -0
- package/styled-system/patterns/hstack.js +27 -0
- package/styled-system/patterns/index.d.ts +20 -0
- package/styled-system/patterns/index.js +20 -0
- package/styled-system/patterns/link-overlay.d.ts +17 -0
- package/styled-system/patterns/link-overlay.js +25 -0
- package/styled-system/patterns/runtime.js +25 -0
- package/styled-system/patterns/spacer.d.ts +20 -0
- package/styled-system/patterns/spacer.js +26 -0
- package/styled-system/patterns/square.d.ts +19 -0
- package/styled-system/patterns/square.js +25 -0
- package/styled-system/patterns/stack.d.ts +22 -0
- package/styled-system/patterns/stack.js +30 -0
- package/styled-system/patterns/visually-hidden.d.ts +17 -0
- package/styled-system/patterns/visually-hidden.js +19 -0
- package/styled-system/patterns/vstack.d.ts +20 -0
- package/styled-system/patterns/vstack.js +27 -0
- package/styled-system/patterns/wrap.d.ts +23 -0
- package/styled-system/patterns/wrap.js +26 -0
- package/styled-system/recipes/alert.d.ts +19 -0
- package/styled-system/recipes/alert.js +5 -0
- package/styled-system/recipes/avatar.d.ts +19 -0
- package/styled-system/recipes/avatar.js +5 -0
- package/styled-system/recipes/badge.d.ts +18 -0
- package/styled-system/recipes/badge.js +5 -0
- package/styled-system/recipes/button.d.ts +20 -0
- package/styled-system/recipes/button.js +5 -0
- package/styled-system/recipes/card.d.ts +19 -0
- package/styled-system/recipes/card.js +5 -0
- package/styled-system/recipes/chat-bubble.d.ts +16 -0
- package/styled-system/recipes/chat-bubble.js +5 -0
- package/styled-system/recipes/checkbox.d.ts +16 -0
- package/styled-system/recipes/checkbox.js +5 -0
- package/styled-system/recipes/dialog.d.ts +18 -0
- package/styled-system/recipes/dialog.js +5 -0
- package/styled-system/recipes/field.d.ts +16 -0
- package/styled-system/recipes/field.js +5 -0
- package/styled-system/recipes/index.d.ts +27 -0
- package/styled-system/recipes/index.js +27 -0
- package/styled-system/recipes/input.d.ts +18 -0
- package/styled-system/recipes/input.js +5 -0
- package/styled-system/recipes/link.d.ts +18 -0
- package/styled-system/recipes/link.js +5 -0
- package/styled-system/recipes/pagination.d.ts +19 -0
- package/styled-system/recipes/pagination.js +5 -0
- package/styled-system/recipes/progress.d.ts +18 -0
- package/styled-system/recipes/progress.js +5 -0
- package/styled-system/recipes/prose.d.ts +16 -0
- package/styled-system/recipes/prose.js +5 -0
- package/styled-system/recipes/radio-group.d.ts +18 -0
- package/styled-system/recipes/radio-group.js +5 -0
- package/styled-system/recipes/runtime.js +133 -0
- package/styled-system/recipes/select-panel.d.ts +18 -0
- package/styled-system/recipes/select-panel.js +5 -0
- package/styled-system/recipes/select.d.ts +18 -0
- package/styled-system/recipes/select.js +5 -0
- package/styled-system/recipes/separator.d.ts +16 -0
- package/styled-system/recipes/separator.js +5 -0
- package/styled-system/recipes/skeleton.d.ts +14 -0
- package/styled-system/recipes/skeleton.js +5 -0
- package/styled-system/recipes/spinner.d.ts +16 -0
- package/styled-system/recipes/spinner.js +5 -0
- package/styled-system/recipes/switch-recipe.d.ts +16 -0
- package/styled-system/recipes/switch-recipe.js +5 -0
- package/styled-system/recipes/table.d.ts +20 -0
- package/styled-system/recipes/table.js +5 -0
- package/styled-system/recipes/tabs.d.ts +18 -0
- package/styled-system/recipes/tabs.js +5 -0
- package/styled-system/recipes/tag.d.ts +18 -0
- package/styled-system/recipes/tag.js +5 -0
- package/styled-system/recipes/textarea.d.ts +14 -0
- package/styled-system/recipes/textarea.js +5 -0
- package/styled-system/recipes/toast.d.ts +20 -0
- package/styled-system/recipes/toast.js +5 -0
- package/styled-system/recipes/tooltip.d.ts +16 -0
- package/styled-system/recipes/tooltip.js +5 -0
- package/styled-system/tokens/index.d.ts +8 -0
- package/styled-system/tokens/index.js +18 -0
- package/styled-system/types/index.d.ts +5 -0
- package/styled-system/types/jsx.d.ts +80 -0
- package/styled-system/types/pattern.d.ts +26 -0
- package/styled-system/types/recipe.d.ts +77 -0
- package/styled-system/types/system.d.ts +1645 -0
- package/styled-system/types/tokens.d.ts +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Koi contributors
|
|
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,74 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tuuject/koi-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Koi components for React web: [Base UI](https://base-ui.com) for behavior, [Panda CSS](https://panda-css.com) v2 for styling. Buttons, inputs, select, dialog, table, toast and the rest of the Koi set, with one token source for themes and palettes.
|
|
4
|
+
|
|
5
|
+
Koi is a design system, so the package ships no prebuilt CSS. Your app's Panda build generates it from the published design system: tokens, recipes, every recipe variant and the page-level global styles.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @tuuject/koi-react @tuuject/koi-tokens react react-dom
|
|
11
|
+
pnpm add -D @pandacss/dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`@tuuject/koi-react` needs Panda CSS v2. The published artifacts are built with Panda `2.1.x`, and the package declares that peer range.
|
|
15
|
+
|
|
16
|
+
## Configure Panda CSS
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// panda.config.ts
|
|
20
|
+
import { defineConfig } from '@pandacss/dev';
|
|
21
|
+
|
|
22
|
+
export default defineConfig({
|
|
23
|
+
preflight: true,
|
|
24
|
+
// Loads @tuuject/koi-react's published preset + build info: tokens, recipes, all variants, global styles.
|
|
25
|
+
designSystem: '@tuuject/koi-react',
|
|
26
|
+
include: ['./src/**/*.{ts,tsx}'],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Add the layer order to your app's CSS entry, then let Panda's PostCSS plugin generate the CSS:
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
/* src/index.css */
|
|
34
|
+
@layer reset, base, tokens, recipes, utilities;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
// postcss.config.cjs
|
|
39
|
+
module.exports = { plugins: { '@pandacss/dev/postcss': {} } };
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Do not also add `@tuuject/koi-tokens/panda` to `presets` or scan `node_modules/@tuuject/koi-react` in `include`: `designSystem` already provides the preset, and the generated build info covers every class the components can produce.
|
|
43
|
+
|
|
44
|
+
## Theme and palette
|
|
45
|
+
|
|
46
|
+
Import the theme bootstrap before your CSS in the app entry (or inline the same file in `<head>` from a tiny build step) so the first paint already has the right theme. It sets `<html data-theme="light|dark">` and follows the OS; `<html data-palette="rose">` picks another built-in palette.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// src/main.tsx, before the CSS import
|
|
50
|
+
import '@tuuject/koi-tokens/theme-init.js';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Use
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { Button, Card, Input } from '@tuuject/koi-react';
|
|
57
|
+
import { css } from '../styled-system/css';
|
|
58
|
+
|
|
59
|
+
export function Form() {
|
|
60
|
+
return (
|
|
61
|
+
<Card>
|
|
62
|
+
<Input placeholder="昵称" />
|
|
63
|
+
<Button>保存</Button>
|
|
64
|
+
</Card>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Components use their own generated runtime; write app styles with your app's `styled-system` (it re-exports Koi's runtime and tokens).
|
|
70
|
+
|
|
71
|
+
## Links
|
|
72
|
+
|
|
73
|
+
- Repository, design spec and Storybook instructions: <https://github.com/tuuject/design>
|
|
74
|
+
- Tokens on their own, without the components: [`@tuuject/koi-tokens`](https://www.npmjs.com/package/@tuuject/koi-tokens)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AlertOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import { type AlertSlot } from '@tuuject/koi-react/styled-system/recipes';
|
|
3
|
+
import type { HTMLAttributes } from 'react';
|
|
4
|
+
import type { SlotClassNames } from '../types.js';
|
|
5
|
+
export type { AlertTone } from '@tuuject/koi-core';
|
|
6
|
+
export interface AlertProps extends AlertOwnProps, Omit<HTMLAttributes<HTMLDivElement>, keyof AlertOwnProps> {
|
|
7
|
+
classNames?: SlotClassNames<AlertSlot>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* An inline message that belongs to the page or a section. Warning and error are role="alert", info is role="status".
|
|
11
|
+
* For brief confirmations that disappear on their own, use Toast.
|
|
12
|
+
*/
|
|
13
|
+
export declare function Alert({ tone, title, icon, action, onClose, className, classNames, children, ...rest }: AlertProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { strings } from '@tuuject/koi-core';
|
|
3
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
4
|
+
import { alert } from '@tuuject/koi-react/styled-system/recipes';
|
|
5
|
+
import { CloseIcon, ErrorIcon, InfoIcon, WarningIcon } from '../icons.js';
|
|
6
|
+
const toneIcon = { info: InfoIcon, warning: WarningIcon, error: ErrorIcon };
|
|
7
|
+
/**
|
|
8
|
+
* An inline message that belongs to the page or a section. Warning and error are role="alert", info is role="status".
|
|
9
|
+
* For brief confirmations that disappear on their own, use Toast.
|
|
10
|
+
*/
|
|
11
|
+
export function Alert({ tone = 'info', title, icon, action, onClose, className, classNames, children, ...rest }) {
|
|
12
|
+
const s = alert({ tone, closable: !!onClose });
|
|
13
|
+
const Icon = toneIcon[tone] ?? InfoIcon;
|
|
14
|
+
const shownIcon = icon !== undefined ? icon : _jsx(Icon, {});
|
|
15
|
+
return (_jsxs("div", { role: tone === 'info' ? 'status' : 'alert', ...rest, className: cx(s.root, className), children: [shownIcon ? _jsx("span", { className: cx(s.icon, classNames?.icon), children: shownIcon }) : null, _jsxs("div", { className: cx(s.content, classNames?.content), children: [title ? _jsx("p", { className: cx(s.title, classNames?.title), children: title }) : null, children ? _jsx("div", { className: cx(s.body, classNames?.body), children: children }) : null, action ? _jsx("div", { className: cx(s.action, classNames?.action), children: action }) : null] }), onClose ? (_jsx("button", { type: "button", className: cx(s.close, classNames?.close), "aria-label": strings.close, title: strings.close, onClick: onClose, children: _jsx(CloseIcon, {}) })) : null] }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type AvatarOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
3
|
+
export type { AvatarShape, AvatarSize } from '@tuuject/koi-core';
|
|
4
|
+
export interface AvatarProps extends AvatarOwnProps, Omit<ComponentPropsWithRef<'span'>, keyof AvatarOwnProps | 'children'> {
|
|
5
|
+
}
|
|
6
|
+
/** A round (or rounded-square) picture of a person or site. Base UI swaps in the image once it has loaded. */
|
|
7
|
+
export declare function Avatar({ src, name, size, shape, className, ...rest }: AvatarProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Avatar as BaseAvatar } from '@base-ui/react/avatar';
|
|
3
|
+
import { initials, strings } from '@tuuject/koi-core';
|
|
4
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
5
|
+
import { avatar } from '@tuuject/koi-react/styled-system/recipes';
|
|
6
|
+
/** A round (or rounded-square) picture of a person or site. Base UI swaps in the image once it has loaded. */
|
|
7
|
+
export function Avatar({ src, name, size = 'md', shape = 'circle', className, ...rest }) {
|
|
8
|
+
const s = avatar({ size, shape });
|
|
9
|
+
return (_jsxs(BaseAvatar.Root, { role: "img", "aria-label": name || strings.avatar, ...rest, className: cx(s.root, className), children: [src ? _jsx(BaseAvatar.Image, { src: src, alt: "", className: s.image }) : null, _jsx(BaseAvatar.Fallback, { "aria-hidden": "true", className: s.fallback, children: initials(name) })] }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BadgeOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import type { HTMLAttributes } from 'react';
|
|
3
|
+
export type { BadgeTone } from '@tuuject/koi-core';
|
|
4
|
+
export interface BadgeProps extends BadgeOwnProps, Omit<HTMLAttributes<HTMLSpanElement>, keyof BadgeOwnProps> {
|
|
5
|
+
}
|
|
6
|
+
/** A small, non-interactive pill label for status or counts. For filters or removable chips, use Tag. */
|
|
7
|
+
export declare function Badge({ tone, dot, className, children, ...rest }: BadgeProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
3
|
+
import { badge } from '@tuuject/koi-react/styled-system/recipes';
|
|
4
|
+
/** A small, non-interactive pill label for status or counts. For filters or removable chips, use Tag. */
|
|
5
|
+
export function Badge({ tone = 'neutral', dot, className, children, ...rest }) {
|
|
6
|
+
const s = badge({ tone });
|
|
7
|
+
return (_jsxs("span", { ...rest, className: cx(s.root, className), children: [dot ? _jsx("span", { className: s.dot, "aria-hidden": "true" }) : null, children] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ButtonOwnProps, type IconButtonOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
3
|
+
export type { ButtonColor, ButtonVariant } from '@tuuject/koi-core';
|
|
4
|
+
type NativeButtonProps = Omit<ComponentPropsWithRef<'button'>, 'color'>;
|
|
5
|
+
type NativeAnchorProps = Omit<ComponentPropsWithRef<'a'>, 'color' | 'type'>;
|
|
6
|
+
/**
|
|
7
|
+
* Without `href`: a <button>, with every native button attribute.
|
|
8
|
+
* With `href`: an <a> (a link that looks like a button), with every native anchor attribute.
|
|
9
|
+
* A disabled or loading link renders a disabled <button> instead, as in legacy: an <a> can't be disabled.
|
|
10
|
+
*/
|
|
11
|
+
type AsButtonOrLink<Own> = (Own & Omit<NativeButtonProps, keyof Own> & {
|
|
12
|
+
href?: undefined;
|
|
13
|
+
}) | (Own & Omit<NativeAnchorProps, keyof Own> & {
|
|
14
|
+
href: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
type?: never;
|
|
17
|
+
});
|
|
18
|
+
export type ButtonProps = AsButtonOrLink<ButtonOwnProps>;
|
|
19
|
+
export declare function Button({ color, variant, size, shape, iconStart, iconEnd, fullWidth, loading, disabled, className, children, ...rest }: ButtonProps): import("react").JSX.Element;
|
|
20
|
+
export type IconButtonProps = AsButtonOrLink<IconButtonOwnProps>;
|
|
21
|
+
/** Square icon-only button. Defaults to secondary ghost, like the legacy IconButton. `href` makes it a link, as on Button. */
|
|
22
|
+
export declare function IconButton({ label, icon, color, variant, size, shape, className, ...rest }: IconButtonProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { strings } from '@tuuject/koi-core';
|
|
3
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
4
|
+
import { button } from '@tuuject/koi-react/styled-system/recipes';
|
|
5
|
+
import { useButtonShape } from '../shape.js';
|
|
6
|
+
import { Spinner } from '../spinner/Spinner.js';
|
|
7
|
+
/** Renders <a> or <button> for Button and IconButton. */
|
|
8
|
+
function Pressable({ href, disabled, type = 'button', ...rest }) {
|
|
9
|
+
if (href !== undefined && !disabled) {
|
|
10
|
+
return _jsx("a", { href: href, ...rest });
|
|
11
|
+
}
|
|
12
|
+
// Drop the anchor-only attributes when a link falls back to a disabled <button>.
|
|
13
|
+
const { target, rel, download, hrefLang, ping, referrerPolicy, ...buttonRest } = rest;
|
|
14
|
+
return _jsx("button", { type: type, disabled: disabled, ...buttonRest });
|
|
15
|
+
}
|
|
16
|
+
export function Button({ color, variant, size, shape, iconStart, iconEnd, fullWidth, loading, disabled, className, children, ...rest }) {
|
|
17
|
+
const resolvedShape = useButtonShape(shape);
|
|
18
|
+
return (_jsxs(Pressable, { ...rest, disabled: disabled || loading, "aria-busy": loading || undefined, className: cx(button({ color, variant, size, shape: resolvedShape, fullWidth }), className), children: [loading ? _jsx(Spinner, { size: size === 'lg' ? 'md' : 'sm', label: strings.processing }) : iconStart, _jsx("span", { children: children }), iconEnd] }));
|
|
19
|
+
}
|
|
20
|
+
/** Square icon-only button. Defaults to secondary ghost, like the legacy IconButton. `href` makes it a link, as on Button. */
|
|
21
|
+
export function IconButton({ label, icon, color = 'secondary', variant = 'ghost', size, shape, className, ...rest }) {
|
|
22
|
+
const resolvedShape = useButtonShape(shape);
|
|
23
|
+
return (_jsx(Pressable
|
|
24
|
+
// Before the spread so a passed title wins; Tooltip passes title={undefined} so the native one doesn't stack on it.
|
|
25
|
+
, {
|
|
26
|
+
// Before the spread so a passed title wins; Tooltip passes title={undefined} so the native one doesn't stack on it.
|
|
27
|
+
title: label, ...rest, "aria-label": label, className: cx(button({ color, variant, size, shape: resolvedShape, iconOnly: true }), className), children: icon }));
|
|
28
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CardOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import { type CardSlot } from '@tuuject/koi-react/styled-system/recipes';
|
|
3
|
+
import type { HTMLAttributes } from 'react';
|
|
4
|
+
import type { SlotClassNames } from '../types.js';
|
|
5
|
+
export interface CardProps extends CardOwnProps, Omit<HTMLAttributes<HTMLDivElement>, keyof CardOwnProps> {
|
|
6
|
+
classNames?: SlotClassNames<CardSlot>;
|
|
7
|
+
}
|
|
8
|
+
/** A rounded container that groups related content. Don't nest cards. */
|
|
9
|
+
export declare function Card({ variant, padding, title, description, media, footer, className, classNames, children, ...rest }: CardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
3
|
+
import { card } from '@tuuject/koi-react/styled-system/recipes';
|
|
4
|
+
/** A rounded container that groups related content. Don't nest cards. */
|
|
5
|
+
export function Card({ variant = 'outlined', padding = 'default', title, description, media, footer, className, classNames, children, ...rest }) {
|
|
6
|
+
const s = card({ variant, padding });
|
|
7
|
+
return (_jsxs("div", { ...rest, className: cx(s.root, className), children: [media ? _jsx("div", { className: cx(s.media, classNames?.media), children: media }) : null, title || description ? (_jsxs("div", { className: cx(s.head, classNames?.head), children: [title ? _jsx("h3", { className: cx(s.title, classNames?.title), children: title }) : null, description ? _jsx("p", { className: cx(s.description, classNames?.description), children: description }) : null] })) : null, children != null ? _jsx("div", { className: cx(s.body, classNames?.body), children: children }) : null, footer ? _jsx("div", { className: cx(s.footer, classNames?.footer), children: footer }) : null] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ChatBubbleOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
3
|
+
export type { ChatBubbleSide } from '@tuuject/koi-core';
|
|
4
|
+
export interface ChatBubbleProps extends ChatBubbleOwnProps, Omit<ComponentPropsWithRef<'div'>, keyof ChatBubbleOwnProps | 'children'> {
|
|
5
|
+
}
|
|
6
|
+
/** A chat or comment message: `received` is a muted panel, `sent` the filled action color. */
|
|
7
|
+
export declare function ChatBubble({ side, className, ...rest }: ChatBubbleProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
3
|
+
import { chatBubble } from '@tuuject/koi-react/styled-system/recipes';
|
|
4
|
+
/** A chat or comment message: `received` is a muted panel, `sent` the filled action color. */
|
|
5
|
+
export function ChatBubble({ side = 'received', className, ...rest }) {
|
|
6
|
+
return _jsx("div", { ...rest, className: cx(chatBubble({ side }), className) });
|
|
7
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CheckboxOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import { type ChangeEventHandler, type ComponentPropsWithRef } from 'react';
|
|
3
|
+
export interface CheckboxProps extends CheckboxOwnProps<Event>, Omit<ComponentPropsWithRef<'input'>, keyof CheckboxOwnProps | 'type' | 'value' | 'onChange' | 'children'> {
|
|
4
|
+
/** Submitted with the form while ticked (the native "on" when omitted). */
|
|
5
|
+
value?: string;
|
|
6
|
+
/**
|
|
7
|
+
* The legacy native handler: React's change event from the hidden input, caught as it bubbles to the row,
|
|
8
|
+
* so `event.target.checked` is the new state (`currentTarget` is the row). Runs after `onCheckedChange`.
|
|
9
|
+
*/
|
|
10
|
+
onChange?: ChangeEventHandler<HTMLInputElement>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A 16px checkbox with a label and an optional description; the whole row is the click target.
|
|
14
|
+
* Renders Base UI's `<span role="checkbox">` plus a hidden `<input type="checkbox">` that carries
|
|
15
|
+
* `id`, `name`, `value`, `required` and `form`; `ref` reaches that input. Inside a Field it picks up
|
|
16
|
+
* the error (red edge, aria-describedby), `required`, `disabled` and `id`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function Checkbox({ label, description, className, style, id, required, ref, onChange, onCheckedChange, 'aria-labelledby': labelledBy, 'aria-describedby': describedBy, ...rest }: CheckboxProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';
|
|
3
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
4
|
+
import { checkbox } from '@tuuject/koi-react/styled-system/recipes';
|
|
5
|
+
import { useContext, useId } from 'react';
|
|
6
|
+
import { KoiFieldContext } from '../field/context.js';
|
|
7
|
+
import { CheckIcon } from '../icons.js';
|
|
8
|
+
/**
|
|
9
|
+
* A 16px checkbox with a label and an optional description; the whole row is the click target.
|
|
10
|
+
* Renders Base UI's `<span role="checkbox">` plus a hidden `<input type="checkbox">` that carries
|
|
11
|
+
* `id`, `name`, `value`, `required` and `form`; `ref` reaches that input. Inside a Field it picks up
|
|
12
|
+
* the error (red edge, aria-describedby), `required`, `disabled` and `id`.
|
|
13
|
+
*/
|
|
14
|
+
export function Checkbox({ label, description, className, style, id, required, ref, onChange, onCheckedChange, 'aria-labelledby': labelledBy, 'aria-describedby': describedBy, ...rest }) {
|
|
15
|
+
const f = useContext(KoiFieldContext);
|
|
16
|
+
const s = checkbox();
|
|
17
|
+
const uid = useId();
|
|
18
|
+
const hasLabel = label != null;
|
|
19
|
+
const labelId = hasLabel ? `${uid}-label` : undefined;
|
|
20
|
+
const descId = hasLabel && description ? `${uid}-desc` : undefined;
|
|
21
|
+
// Without a label there's no row to click; a <span> also keeps Base UI from naming the box after an
|
|
22
|
+
// empty <label>, which would override an aria-label.
|
|
23
|
+
const Root = hasLabel ? 'label' : 'span';
|
|
24
|
+
return (_jsxs(Root, { className: cx(s.root, className), style: style, onChange: onChange, children: [_jsx(BaseCheckbox.Root, { ...rest, inputRef: ref, id: id ?? f?.id, required: required ?? f?.required, "aria-labelledby": labelledBy ?? labelId, "aria-describedby": cx(describedBy, descId) || undefined, onCheckedChange: onCheckedChange, className: s.control, children: _jsx(BaseCheckbox.Indicator, { keepMounted: true, className: s.indicator, children: _jsx(CheckIcon, {}) }) }), hasLabel ? (_jsxs("span", { className: s.text, children: [_jsx("span", { id: labelId, className: s.label, children: label }), descId ? (_jsx("span", { id: descId, className: s.description, children: description })) : null] })) : null] }));
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type DialogOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import { type DialogSlot } from '@tuuject/koi-react/styled-system/recipes';
|
|
3
|
+
import type { SlotClassNames } from '../types.js';
|
|
4
|
+
export interface DialogProps extends DialogOwnProps {
|
|
5
|
+
className?: string;
|
|
6
|
+
classNames?: SlotClassNames<Exclude<DialogSlot, 'popup'>>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Modal dialog. Base UI handles the portal, focus trap, Esc, outside click, scroll lock and focus return.
|
|
10
|
+
* AlertDialog differs from Dialog only in its Root (role, forced modal, no pointer dismissal); every other
|
|
11
|
+
* part is the same component, so both variants share the parts and the recipe below.
|
|
12
|
+
*/
|
|
13
|
+
export declare function Dialog({ open, onOpenChange, title, description, children, footer, size, role, dismissible, hideClose, className, classNames, }: DialogProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AlertDialog } from '@base-ui/react/alert-dialog';
|
|
3
|
+
import { Dialog as BaseDialog } from '@base-ui/react/dialog';
|
|
4
|
+
import { strings } from '@tuuject/koi-core';
|
|
5
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
6
|
+
import { dialog } from '@tuuject/koi-react/styled-system/recipes';
|
|
7
|
+
import { sizes } from '@tuuject/koi-tokens/dimensions';
|
|
8
|
+
import { useRef } from 'react';
|
|
9
|
+
import { IconButton } from '../button/Button.js';
|
|
10
|
+
import { CloseIcon } from '../icons.js';
|
|
11
|
+
import { ShapeProvider } from '../shape.js';
|
|
12
|
+
/**
|
|
13
|
+
* Modal dialog. Base UI handles the portal, focus trap, Esc, outside click, scroll lock and focus return.
|
|
14
|
+
* AlertDialog differs from Dialog only in its Root (role, forced modal, no pointer dismissal); every other
|
|
15
|
+
* part is the same component, so both variants share the parts and the recipe below.
|
|
16
|
+
*/
|
|
17
|
+
export function Dialog({ open, onOpenChange, title, description, children, footer, size, role = 'dialog', dismissible = true, hideClose, className, classNames, }) {
|
|
18
|
+
const s = dialog({ size });
|
|
19
|
+
const footerRef = useRef(null);
|
|
20
|
+
const alert = role === 'alertdialog';
|
|
21
|
+
// WAI-ARIA alertdialog: focus the least destructive action. The footer's first button is cancel by convention;
|
|
22
|
+
// without an enabled one, fall back to Base UI's default (first tabbable element).
|
|
23
|
+
const initialFocus = alert
|
|
24
|
+
? () => footerRef.current?.querySelector('button:not(:disabled), a[href]') ?? true
|
|
25
|
+
: undefined;
|
|
26
|
+
const handleOpenChange = (next) => onOpenChange(next);
|
|
27
|
+
// When a click outside doesn't close the dialog, a mousedown on the empty area around the popup would still
|
|
28
|
+
// blur the focused control and drop focus on <body> (Base UI only pulls it back on the next Tab). Keep it put.
|
|
29
|
+
const keepFocus = alert || !dismissible
|
|
30
|
+
? (event) => {
|
|
31
|
+
if (event.target === event.currentTarget) {
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
: undefined;
|
|
36
|
+
const portal = (_jsxs(BaseDialog.Portal, { children: [_jsx(BaseDialog.Backdrop, { className: cx(s.backdrop, classNames?.backdrop) }), _jsx(BaseDialog.Viewport, { className: cx(s.viewport, classNames?.viewport), onMouseDown: keepFocus, children: _jsxs(BaseDialog.Popup, { className: cx(s.popup, className), initialFocus: initialFocus, children: [title != null && _jsx(BaseDialog.Title, { className: cx(s.title, classNames?.title), children: title }), description != null && (_jsx(BaseDialog.Description, { className: cx(s.description, classNames?.description), children: description })), children != null && _jsx("div", { className: cx(s.body, classNames?.body), children: children }), footer != null && (_jsx(ShapeProvider, { shape: "rounded", children: _jsx("div", { ref: footerRef, className: cx(s.footer, classNames?.footer), children: footer }) })), !hideClose && (_jsx(BaseDialog.Close, { className: cx(s.close, classNames?.close), render: _jsx(IconButton, { label: strings.close, icon: _jsx(CloseIcon, { size: sizes['icon-lg'] }), size: "sm", shape: "rounded" }) }))] }) })] }));
|
|
37
|
+
return alert ? (_jsx(AlertDialog.Root, { open: open, onOpenChange: handleOpenChange, children: portal })) : (_jsx(BaseDialog.Root, { open: open, onOpenChange: handleOpenChange, disablePointerDismissal: !dismissible, children: portal }));
|
|
38
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DividerOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
export interface DividerProps extends DividerOwnProps {
|
|
3
|
+
className?: string;
|
|
4
|
+
}
|
|
5
|
+
/** A 1px hairline separator. Prefer spacing; add a divider only when space alone doesn't separate the groups. */
|
|
6
|
+
export declare function Divider({ orientation, label, className }: DividerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Separator } from '@base-ui/react/separator';
|
|
3
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
4
|
+
import { separator } from '@tuuject/koi-react/styled-system/recipes';
|
|
5
|
+
import { useId } from 'react';
|
|
6
|
+
/** A 1px hairline separator. Prefer spacing; add a divider only when space alone doesn't separate the groups. */
|
|
7
|
+
export function Divider({ orientation = 'horizontal', label, className }) {
|
|
8
|
+
const labelId = useId();
|
|
9
|
+
if (orientation === 'vertical') {
|
|
10
|
+
return (_jsx(Separator, { orientation: "vertical", render: _jsx("span", {}), className: cx(separator({ kind: 'vertical' }), className) }));
|
|
11
|
+
}
|
|
12
|
+
if (label != null && label !== false) {
|
|
13
|
+
// A separator's children are presentational, so the label names it instead of being lost.
|
|
14
|
+
return (_jsx(Separator, { "aria-labelledby": labelId, className: cx(separator({ kind: 'label' }), className), children: _jsx("span", { id: labelId, children: label }) }));
|
|
15
|
+
}
|
|
16
|
+
return _jsx(Separator, { className: cx(separator(), className) });
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type FieldOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import { type FieldSlot } from '@tuuject/koi-react/styled-system/recipes';
|
|
3
|
+
import { type HTMLAttributes } from 'react';
|
|
4
|
+
import type { SlotClassNames } from '../types.js';
|
|
5
|
+
export interface FieldProps extends FieldOwnProps, Omit<HTMLAttributes<HTMLDivElement>, keyof FieldOwnProps | 'id'> {
|
|
6
|
+
/** The control's id (the label points at it). Generated when omitted. */
|
|
7
|
+
id?: string;
|
|
8
|
+
classNames?: SlotClassNames<FieldSlot>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A form row: label, one control, error and help text, wired together by Base UI's Field.
|
|
12
|
+
* Stack Fields with space-4 between them.
|
|
13
|
+
*/
|
|
14
|
+
export declare function Field({ label, help, error, required, optional, id, className, classNames, children, ...rest }: FieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Field as BaseField } from '@base-ui/react/field';
|
|
3
|
+
import { strings } from '@tuuject/koi-core';
|
|
4
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
5
|
+
import { field } from '@tuuject/koi-react/styled-system/recipes';
|
|
6
|
+
import { sizes } from '@tuuject/koi-tokens/dimensions';
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { ErrorIcon } from '../icons.js';
|
|
9
|
+
import { KoiFieldContext } from './context.js';
|
|
10
|
+
/**
|
|
11
|
+
* A form row: label, one control, error and help text, wired together by Base UI's Field.
|
|
12
|
+
* Stack Fields with space-4 between them.
|
|
13
|
+
*/
|
|
14
|
+
export function Field({ label, help, error, required, optional, id, className, classNames, children, ...rest }) {
|
|
15
|
+
const s = field();
|
|
16
|
+
const hasError = error != null && error !== false && error !== '';
|
|
17
|
+
const ctx = useMemo(() => ({ id, required }), [id, required]);
|
|
18
|
+
return (_jsx(KoiFieldContext.Provider, { value: ctx, children: _jsxs(BaseField.Root, { ...rest, invalid: hasError, className: cx(s.root, className), children: [label != null ? (_jsxs(BaseField.Label, { className: cx(s.label, classNames?.label), children: [label, required ? (_jsxs("span", { className: cx(s.required, classNames?.required), "aria-hidden": "true", children: [' ', "*"] })) : null, optional ? _jsx("span", { className: cx(s.optional, classNames?.optional), children: strings.optional }) : null] })) : null, children, hasError ? (_jsxs(BaseField.Error, { match: true, className: cx(s.error, classNames?.error), render: _jsx("p", {}), children: [_jsx(ErrorIcon, { size: sizes['icon-xs'] }), _jsx("span", { children: error })] })) : null, help ? _jsx(BaseField.Description, { className: cx(s.help, classNames?.help), children: help }) : null] }) }));
|
|
19
|
+
}
|
package/dist/icons.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IconOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
3
|
+
export type { IconData, IconOwnProps } from '@tuuject/koi-core';
|
|
4
|
+
export interface IconProps extends IconOwnProps, Omit<ComponentPropsWithRef<'svg'>, keyof IconOwnProps | 'children' | 'dangerouslySetInnerHTML'> {
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Draws Iconify-format icon data (`@iconify-icons/<set>/<name>`, or a hand-written `{ body, width, height }`) as
|
|
8
|
+
* an inline SVG in currentColor. Decorative: the control around it carries the accessible name.
|
|
9
|
+
*/
|
|
10
|
+
export declare function Icon({ icon, size, ...rest }: IconProps): import("react").JSX.Element;
|
|
11
|
+
export type BuiltinIconProps = Omit<IconProps, 'icon'>;
|
|
12
|
+
export declare const CloseIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
13
|
+
export declare const CheckIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
14
|
+
export declare const ExternalIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
15
|
+
export declare const InfoIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
16
|
+
export declare const WarningIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
17
|
+
export declare const SuccessIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
18
|
+
export declare const ErrorIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
19
|
+
export declare const SearchIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
20
|
+
export declare const ChevronDownIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
21
|
+
export declare const ChevronUpIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
22
|
+
export declare const ChevronLeftIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
23
|
+
export declare const ChevronRightIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
24
|
+
export declare const SortIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
25
|
+
export declare const SortUpIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
|
26
|
+
export declare const SortDownIcon: (props: BuiltinIconProps) => import("react").JSX.Element;
|
package/dist/icons.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import arrowUpRightFromSquare from '@iconify-icons/fa7-solid/arrow-up-right-from-square';
|
|
3
|
+
import check from '@iconify-icons/fa7-solid/check';
|
|
4
|
+
import chevronDown from '@iconify-icons/fa7-solid/chevron-down';
|
|
5
|
+
import chevronLeft from '@iconify-icons/fa7-solid/chevron-left';
|
|
6
|
+
import chevronRight from '@iconify-icons/fa7-solid/chevron-right';
|
|
7
|
+
import chevronUp from '@iconify-icons/fa7-solid/chevron-up';
|
|
8
|
+
import circleCheck from '@iconify-icons/fa7-solid/circle-check';
|
|
9
|
+
import circleInfo from '@iconify-icons/fa7-solid/circle-info';
|
|
10
|
+
import circleXmark from '@iconify-icons/fa7-solid/circle-xmark';
|
|
11
|
+
import magnifyingGlass from '@iconify-icons/fa7-solid/magnifying-glass';
|
|
12
|
+
import sort from '@iconify-icons/fa7-solid/sort';
|
|
13
|
+
import sortDown from '@iconify-icons/fa7-solid/sort-down';
|
|
14
|
+
import sortUp from '@iconify-icons/fa7-solid/sort-up';
|
|
15
|
+
import triangleExclamation from '@iconify-icons/fa7-solid/triangle-exclamation';
|
|
16
|
+
import xmark from '@iconify-icons/fa7-solid/xmark';
|
|
17
|
+
import { sizes } from '@tuuject/koi-tokens/dimensions';
|
|
18
|
+
/**
|
|
19
|
+
* Draws Iconify-format icon data (`@iconify-icons/<set>/<name>`, or a hand-written `{ body, width, height }`) as
|
|
20
|
+
* an inline SVG in currentColor. Decorative: the control around it carries the accessible name.
|
|
21
|
+
*/
|
|
22
|
+
export function Icon({ icon, size = sizes.icon, ...rest }) {
|
|
23
|
+
const { body, width = 16, height = 16, left = 0, top = 0 } = icon;
|
|
24
|
+
return (_jsx("svg", { width: size, height: size, viewBox: `${left} ${top} ${width} ${height}`, "aria-hidden": "true", ...rest,
|
|
25
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: icon bodies are static SVG markup from icon packages or our own source, never user input.
|
|
26
|
+
dangerouslySetInnerHTML: { __html: body } }));
|
|
27
|
+
}
|
|
28
|
+
function builtin(icon) {
|
|
29
|
+
return (props) => _jsx(Icon, { icon: icon, ...props });
|
|
30
|
+
}
|
|
31
|
+
// The icons Koi's components draw, all Font Awesome Free Solid (CC BY 4.0).
|
|
32
|
+
export const CloseIcon = builtin(xmark);
|
|
33
|
+
export const CheckIcon = builtin(check);
|
|
34
|
+
export const ExternalIcon = builtin(arrowUpRightFromSquare);
|
|
35
|
+
export const InfoIcon = builtin(circleInfo);
|
|
36
|
+
export const WarningIcon = builtin(triangleExclamation);
|
|
37
|
+
export const SuccessIcon = builtin(circleCheck);
|
|
38
|
+
export const ErrorIcon = builtin(circleXmark);
|
|
39
|
+
export const SearchIcon = builtin(magnifyingGlass);
|
|
40
|
+
export const ChevronDownIcon = builtin(chevronDown);
|
|
41
|
+
export const ChevronUpIcon = builtin(chevronUp);
|
|
42
|
+
export const ChevronLeftIcon = builtin(chevronLeft);
|
|
43
|
+
export const ChevronRightIcon = builtin(chevronRight);
|
|
44
|
+
export const SortIcon = builtin(sort);
|
|
45
|
+
export const SortUpIcon = builtin(sortUp);
|
|
46
|
+
export const SortDownIcon = builtin(sortDown);
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { Alert, type AlertProps, type AlertTone } from './alert/Alert.js';
|
|
2
|
+
export { Avatar, type AvatarProps, type AvatarShape, type AvatarSize } from './avatar/Avatar.js';
|
|
3
|
+
export { Badge, type BadgeProps, type BadgeTone } from './badge/Badge.js';
|
|
4
|
+
export { Button, type ButtonColor, type ButtonProps, type ButtonVariant, IconButton, type IconButtonProps, } from './button/Button.js';
|
|
5
|
+
export { Card, type CardProps } from './card/Card.js';
|
|
6
|
+
export { ChatBubble, type ChatBubbleProps } from './chat-bubble/ChatBubble.js';
|
|
7
|
+
export { Checkbox, type CheckboxProps } from './checkbox/Checkbox.js';
|
|
8
|
+
export { Dialog, type DialogProps } from './dialog/Dialog.js';
|
|
9
|
+
export { Divider, type DividerProps } from './divider/Divider.js';
|
|
10
|
+
export { Field, type FieldProps } from './field/Field.js';
|
|
11
|
+
export * from './icons.js';
|
|
12
|
+
export { Input, type InputProps } from './input/Input.js';
|
|
13
|
+
export { Link, type LinkProps, type LinkVariant } from './link/Link.js';
|
|
14
|
+
export { Pagination, type PaginationProps, type PaginationVariant } from './pagination/Pagination.js';
|
|
15
|
+
export { Progress, type ProgressProps, type ProgressSize } from './progress/Progress.js';
|
|
16
|
+
export { Prose, type ProseProps, type ProseSize } from './prose/Prose.js';
|
|
17
|
+
export { RadioGroup, type RadioGroupProps, type RadioOption } from './radio-group/RadioGroup.js';
|
|
18
|
+
export { Select, type SelectOption, type SelectProps } from './select/Select.js';
|
|
19
|
+
export { SelectGroup, type SelectGroupProps, SelectItem, type SelectItemProps, type SelectOptionGroup, SelectPanel, type SelectPanelProps, SelectSeparator, } from './select/SelectPanel.js';
|
|
20
|
+
export { type ButtonShape, ShapeProvider, useButtonShape } from './shape.js';
|
|
21
|
+
export { Skeleton, type SkeletonProps } from './skeleton/Skeleton.js';
|
|
22
|
+
export { Spinner, type SpinnerProps, type SpinnerSize } from './spinner/Spinner.js';
|
|
23
|
+
export { Switch, type SwitchProps } from './switch/Switch.js';
|
|
24
|
+
export { DataTable, type DataTableColumn, type DataTableProps } from './table/DataTable.js';
|
|
25
|
+
export { Table, type TableAlign, TableBody, type TableBodyProps, TableCaption, type TableCaptionProps, TableCell, type TableCellProps, TableEmpty, type TableEmptyProps, TableFooter, type TableFooterProps, TableHeader, TableHeaderCell, type TableHeaderCellProps, type TableHeaderProps, type TableLayout, type TableProps, TableRow, type TableRowProps, type TableSortDirection, } from './table/Table.js';
|
|
26
|
+
export { type TabItem, Tabs, type TabsProps } from './tabs/Tabs.js';
|
|
27
|
+
export { Tag, type TagProps } from './tag/Tag.js';
|
|
28
|
+
export { Textarea, type TextareaProps } from './textarea/Textarea.js';
|
|
29
|
+
export { Toast, type ToastOptions, type ToastProps, ToastProvider, type ToastProviderProps, type ToastTone, useToast, } from './toast/Toast.js';
|
|
30
|
+
export { Tooltip, type TooltipProps, type TooltipSide } from './tooltip/Tooltip.js';
|
|
31
|
+
export type { ChangeDetails } from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export { Alert } from './alert/Alert.js';
|
|
2
|
+
export { Avatar } from './avatar/Avatar.js';
|
|
3
|
+
export { Badge } from './badge/Badge.js';
|
|
4
|
+
export { Button, IconButton, } from './button/Button.js';
|
|
5
|
+
export { Card } from './card/Card.js';
|
|
6
|
+
export { ChatBubble } from './chat-bubble/ChatBubble.js';
|
|
7
|
+
export { Checkbox } from './checkbox/Checkbox.js';
|
|
8
|
+
export { Dialog } from './dialog/Dialog.js';
|
|
9
|
+
export { Divider } from './divider/Divider.js';
|
|
10
|
+
export { Field } from './field/Field.js';
|
|
11
|
+
export * from './icons.js';
|
|
12
|
+
export { Input } from './input/Input.js';
|
|
13
|
+
export { Link } from './link/Link.js';
|
|
14
|
+
export { Pagination } from './pagination/Pagination.js';
|
|
15
|
+
export { Progress } from './progress/Progress.js';
|
|
16
|
+
export { Prose } from './prose/Prose.js';
|
|
17
|
+
export { RadioGroup } from './radio-group/RadioGroup.js';
|
|
18
|
+
export { Select } from './select/Select.js';
|
|
19
|
+
export { SelectGroup, SelectItem, SelectPanel, SelectSeparator, } from './select/SelectPanel.js';
|
|
20
|
+
export { ShapeProvider, useButtonShape } from './shape.js';
|
|
21
|
+
export { Skeleton } from './skeleton/Skeleton.js';
|
|
22
|
+
export { Spinner } from './spinner/Spinner.js';
|
|
23
|
+
export { Switch } from './switch/Switch.js';
|
|
24
|
+
export { DataTable } from './table/DataTable.js';
|
|
25
|
+
export { Table, TableBody, TableCaption, TableCell, TableEmpty, TableFooter, TableHeader, TableHeaderCell, TableRow, } from './table/Table.js';
|
|
26
|
+
export { Tabs } from './tabs/Tabs.js';
|
|
27
|
+
export { Tag } from './tag/Tag.js';
|
|
28
|
+
export { Textarea } from './textarea/Textarea.js';
|
|
29
|
+
export { Toast, ToastProvider, useToast, } from './toast/Toast.js';
|
|
30
|
+
export { Tooltip } from './tooltip/Tooltip.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InputOwnProps } from '@tuuject/koi-core';
|
|
2
|
+
import { type ComponentPropsWithRef } from 'react';
|
|
3
|
+
export interface InputProps extends InputOwnProps, Omit<ComponentPropsWithRef<'input'>, keyof InputOwnProps> {
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* A single-line text field. Inside a Field it picks up the label, help, error and required state;
|
|
7
|
+
* on its own, give it an aria-label.
|
|
8
|
+
*/
|
|
9
|
+
export declare function Input({ size, invalid, iconStart, iconEnd, className, id, required, disabled, ...rest }: InputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Input as BaseInput } from '@base-ui/react/input';
|
|
3
|
+
import { cx } from '@tuuject/koi-react/styled-system/css';
|
|
4
|
+
import { input } from '@tuuject/koi-react/styled-system/recipes';
|
|
5
|
+
import { useContext } from 'react';
|
|
6
|
+
import { KoiFieldContext } from '../field/context.js';
|
|
7
|
+
/**
|
|
8
|
+
* A single-line text field. Inside a Field it picks up the label, help, error and required state;
|
|
9
|
+
* on its own, give it an aria-label.
|
|
10
|
+
*/
|
|
11
|
+
export function Input({ size = 'md', invalid, iconStart, iconEnd, className, id, required, disabled, ...rest }) {
|
|
12
|
+
const f = useContext(KoiFieldContext);
|
|
13
|
+
const s = input({ size });
|
|
14
|
+
return (_jsxs("span", { className: cx(s.root, className), children: [iconStart ? _jsx("span", { className: s.icon, children: iconStart }) : null, _jsx(BaseInput, { ...rest, id: id ?? f?.id, required: required ?? f?.required, disabled: disabled, "aria-invalid": invalid && !disabled ? true : rest['aria-invalid'], className: s.el }), iconEnd ? _jsx("span", { className: s.icon, children: iconEnd }) : null] }));
|
|
15
|
+
}
|