@tuuject/koi-core 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 +16 -2
- package/dist/alert.d.ts +14 -0
- package/dist/alert.js +1 -0
- package/dist/avatar.d.ts +17 -0
- package/dist/avatar.js +19 -0
- package/dist/badge.d.ts +9 -0
- package/dist/badge.js +1 -0
- package/dist/button.d.ts +32 -0
- package/dist/button.js +2 -0
- package/dist/card.d.ts +13 -0
- package/dist/card.js +1 -0
- package/dist/change-details.d.ts +16 -0
- package/dist/change-details.js +1 -0
- package/dist/chat-bubble.d.ts +12 -0
- package/dist/chat-bubble.js +1 -0
- package/dist/checkbox.d.ts +12 -0
- package/dist/checkbox.js +1 -0
- package/dist/common.d.ts +2 -0
- package/dist/common.js +1 -0
- package/dist/dialog.d.ts +21 -0
- package/dist/dialog.js +1 -0
- package/dist/divider.d.ts +7 -0
- package/dist/divider.js +1 -0
- package/dist/field.d.ts +14 -0
- package/dist/field.js +1 -0
- package/dist/icon.d.ts +22 -0
- package/dist/icon.js +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +32 -0
- package/dist/input.d.ts +14 -0
- package/dist/input.js +1 -0
- package/dist/link.d.ts +15 -0
- package/dist/link.js +1 -0
- package/dist/pagination.d.ts +26 -0
- package/dist/pagination.js +23 -0
- package/dist/progress.d.ts +13 -0
- package/dist/progress.js +1 -0
- package/dist/prose.d.ts +11 -0
- package/dist/prose.js +1 -0
- package/dist/radio-group.d.ts +20 -0
- package/dist/radio-group.js +1 -0
- package/dist/select.d.ts +72 -0
- package/dist/select.js +1 -0
- package/dist/skeleton.d.ts +5 -0
- package/dist/skeleton.js +1 -0
- package/dist/spinner.d.ts +7 -0
- package/dist/spinner.js +1 -0
- package/dist/strings.d.ts +27 -0
- package/dist/strings.js +27 -0
- package/dist/switch.d.ts +13 -0
- package/dist/switch.js +1 -0
- package/dist/table.d.ts +80 -0
- package/dist/table.js +1 -0
- package/dist/tabs.d.ts +21 -0
- package/dist/tabs.js +1 -0
- package/dist/tag.d.ts +15 -0
- package/dist/tag.js +1 -0
- package/dist/toast.d.ts +35 -0
- package/dist/toast.js +4 -0
- package/dist/tooltip.d.ts +22 -0
- package/dist/tooltip.js +1 -0
- package/package.json +35 -3
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,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tuuject/koi-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Koi's platform-neutral layer: each component's props contract (`<Name>OwnProps`), the `ChangeDetails` passed to callbacks, the UI copy in `strings`, and the pure helpers behind the components.
|
|
4
|
+
|
|
5
|
+
`@tuuject/koi-react` builds the DOM components on top of it, and a native package uses the same contracts. There is no DOM, no styling and no headless library here, so the package runs anywhere TypeScript does.
|
|
6
|
+
|
|
7
|
+
You normally get it transitively. Install it directly only if you write a Koi platform package or want the prop types without the React implementation:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @tuuject/koi-core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { ButtonOwnProps } from '@tuuject/koi-core';
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Repository and design spec: <https://github.com/tuuject/design>
|
package/dist/alert.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type AlertTone = 'info' | 'warning' | 'error';
|
|
3
|
+
export interface AlertOwnProps {
|
|
4
|
+
/** info (sky) / warning (yellow) / error (red). Default info. */
|
|
5
|
+
tone?: AlertTone;
|
|
6
|
+
title?: ReactNode;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
/** Replaces the tone icon; null hides it. */
|
|
9
|
+
icon?: ReactNode | null;
|
|
10
|
+
/** Usually a small Button, below the text. */
|
|
11
|
+
action?: ReactNode;
|
|
12
|
+
/** Shows a close button. */
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
}
|
package/dist/alert.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/avatar.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type AvatarSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
2
|
+
export type AvatarShape = 'circle' | 'square';
|
|
3
|
+
export interface AvatarOwnProps {
|
|
4
|
+
/** Image URL. While it loads, or if it fails, the initials show instead. */
|
|
5
|
+
src?: string;
|
|
6
|
+
/** Alt text and the source of the fallback initials (the first character for CJK names, otherwise up to two initials). */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** sm 28px, md 36px (default), lg 44px, xl 64px. */
|
|
9
|
+
size?: AvatarSize;
|
|
10
|
+
/** circle (default) or square (12px corners). */
|
|
11
|
+
shape?: AvatarShape;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* First character of a CJK name ("咕咕" → "咕"), else the first letters of the first and last words ("Ada Lovelace" → "AL").
|
|
15
|
+
* A mixed name keeps only its leading initial ("Koi 管理员" → "K"): "K管" reads as neither script's initials.
|
|
16
|
+
*/
|
|
17
|
+
export declare function initials(name: string | undefined): string;
|
package/dist/avatar.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First character of a CJK name ("咕咕" → "咕"), else the first letters of the first and last words ("Ada Lovelace" → "AL").
|
|
3
|
+
* A mixed name keeps only its leading initial ("Koi 管理员" → "K"): "K管" reads as neither script's initials.
|
|
4
|
+
*/
|
|
5
|
+
export function initials(name) {
|
|
6
|
+
const s = (name ?? '').trim();
|
|
7
|
+
if (!s) {
|
|
8
|
+
return '?';
|
|
9
|
+
}
|
|
10
|
+
// Code points, not UTF-16 units, so a surrogate pair isn't cut in half.
|
|
11
|
+
const first = (w) => (w ? Array.from(w)[0] : '');
|
|
12
|
+
const isCjk = (ch) => /[㐀-鿿]/.test(ch);
|
|
13
|
+
if (isCjk(first(s))) {
|
|
14
|
+
return first(s);
|
|
15
|
+
}
|
|
16
|
+
const words = s.split(/\s+/);
|
|
17
|
+
const last = words.length > 1 ? first(words[words.length - 1]) : '';
|
|
18
|
+
return (first(words[0]) + (isCjk(last) ? '' : last)).toUpperCase();
|
|
19
|
+
}
|
package/dist/badge.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type BadgeTone = 'neutral' | 'primary' | 'accent' | 'warning' | 'error' | 'solid';
|
|
3
|
+
export interface BadgeOwnProps {
|
|
4
|
+
/** Default neutral. */
|
|
5
|
+
tone?: BadgeTone;
|
|
6
|
+
/** A 6px dot in the text color before the label. */
|
|
7
|
+
dot?: boolean;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
package/dist/badge.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/button.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ControlSize } from './common.js';
|
|
3
|
+
export declare const BUTTON_COLORS: readonly ['primary', 'accent', 'secondary', 'warning', 'error'];
|
|
4
|
+
export declare const BUTTON_VARIANTS: readonly ['solid', 'soft', 'outline', 'ghost'];
|
|
5
|
+
export type ButtonColor = (typeof BUTTON_COLORS)[number];
|
|
6
|
+
export type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
|
|
7
|
+
/** pill (radius-full) or rounded (radius-lg, 8px). */
|
|
8
|
+
export type ButtonShape = 'pill' | 'rounded';
|
|
9
|
+
export interface ButtonOwnProps {
|
|
10
|
+
/** What the action means. Default primary. */
|
|
11
|
+
color?: ButtonColor;
|
|
12
|
+
/** How loud it is. Default solid. One solid button per group. */
|
|
13
|
+
variant?: ButtonVariant;
|
|
14
|
+
/** control-sm 28 / control-md 36 / control-lg 44. Default md. */
|
|
15
|
+
size?: ControlSize;
|
|
16
|
+
/** pill (radius-full) or rounded (radius-lg, 8px). Default rounded, or whatever the surrounding ShapeProvider says. */
|
|
17
|
+
shape?: ButtonShape;
|
|
18
|
+
iconStart?: ReactNode;
|
|
19
|
+
iconEnd?: ReactNode;
|
|
20
|
+
fullWidth?: boolean;
|
|
21
|
+
/** Shows a Spinner in place of iconStart, disables the button and marks it busy. */
|
|
22
|
+
loading?: boolean;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/** Square icon-only button. Defaults to secondary ghost. */
|
|
27
|
+
export interface IconButtonOwnProps extends Pick<ButtonOwnProps, 'color' | 'variant' | 'size' | 'shape' | 'disabled'> {
|
|
28
|
+
/** Required: the accessible name, also used as the tooltip. */
|
|
29
|
+
label: string;
|
|
30
|
+
icon: ReactNode;
|
|
31
|
+
children?: never;
|
|
32
|
+
}
|
package/dist/button.js
ADDED
package/dist/card.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface CardOwnProps {
|
|
3
|
+
/** outlined (default) / filled / glass (Koi's frosted panel: put it over imagery or color). */
|
|
4
|
+
variant?: 'outlined' | 'filled' | 'glass';
|
|
5
|
+
title?: ReactNode;
|
|
6
|
+
description?: ReactNode;
|
|
7
|
+
/** Full-bleed content above the head, e.g. an image. */
|
|
8
|
+
media?: ReactNode;
|
|
9
|
+
/** Actions, aligned right. */
|
|
10
|
+
footer?: ReactNode;
|
|
11
|
+
padding?: 'default' | 'none';
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
}
|
package/dist/card.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The second argument of Koi's change callbacks (`onCheckedChange`, `onChange`, `onOpenChange`). Koi's own type,
|
|
3
|
+
* not a headless library's (agent-doc/headless.md, rule 5). `E` is the platform's event: `Event` on the web, a
|
|
4
|
+
* gesture or press event on native.
|
|
5
|
+
*/
|
|
6
|
+
export interface ChangeDetails<E = unknown> {
|
|
7
|
+
/**
|
|
8
|
+
* What caused the change, e.g. `'trigger-press'`, `'escape-key'`. The values come from the headless library and
|
|
9
|
+
* can differ between versions and platforms: log them or branch on them loosely, don't rely on an exact list.
|
|
10
|
+
*/
|
|
11
|
+
reason: string;
|
|
12
|
+
/** The platform event behind the change. */
|
|
13
|
+
event: E;
|
|
14
|
+
/** Rejects the change: the component keeps its current value (or stays open / closed). */
|
|
15
|
+
cancel(): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export declare const CHAT_BUBBLE_SIDES: readonly ['received', 'sent'];
|
|
3
|
+
export type ChatBubbleSide = (typeof CHAT_BUBBLE_SIDES)[number];
|
|
4
|
+
export interface ChatBubbleOwnProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* Whose message it is. `sent` fills with `action` (and wants to sit on the right);
|
|
8
|
+
* `received` (default) is a muted panel (and wants to sit on the left). Only the look:
|
|
9
|
+
* alignment is the consumer's layout.
|
|
10
|
+
*/
|
|
11
|
+
side?: ChatBubbleSide;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CHAT_BUBBLE_SIDES = ['received', 'sent'];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ChangeDetails } from './change-details.js';
|
|
3
|
+
export interface CheckboxOwnProps<E = unknown> {
|
|
4
|
+
label?: ReactNode;
|
|
5
|
+
/** Shown under the label in text-muted. Needs a label. */
|
|
6
|
+
description?: ReactNode;
|
|
7
|
+
checked?: boolean;
|
|
8
|
+
defaultChecked?: boolean;
|
|
9
|
+
onCheckedChange?: (checked: boolean, details: ChangeDetails<E>) => void;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
readOnly?: boolean;
|
|
12
|
+
}
|
package/dist/checkbox.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/common.d.ts
ADDED
package/dist/common.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/dialog.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface DialogOwnProps {
|
|
3
|
+
open: boolean;
|
|
4
|
+
onOpenChange: (open: boolean) => void;
|
|
5
|
+
title?: ReactNode;
|
|
6
|
+
description?: ReactNode;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
/** Actions, in order: cancel (secondary ghost), then the confirming solid button. Buttons here default to shape="rounded". */
|
|
9
|
+
footer?: ReactNode;
|
|
10
|
+
/** sm 400 / md 520 / lg 720. Default md. */
|
|
11
|
+
size?: 'sm' | 'md' | 'lg';
|
|
12
|
+
/**
|
|
13
|
+
* 'alertdialog' for confirmations that need an answer: a tap outside never closes it, and focus starts on the
|
|
14
|
+
* first footer button, the least destructive action (cancel). Default 'dialog'.
|
|
15
|
+
*/
|
|
16
|
+
role?: 'dialog' | 'alertdialog';
|
|
17
|
+
/** false: a tap outside (on the backdrop) doesn't close it. Esc and the × still do. Default true; an alertdialog is never dismissed by a tap outside. */
|
|
18
|
+
dismissible?: boolean;
|
|
19
|
+
/** Hide the × button (e.g. for confirmations that need an explicit answer). */
|
|
20
|
+
hideClose?: boolean;
|
|
21
|
+
}
|
package/dist/dialog.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface DividerOwnProps {
|
|
3
|
+
/** Default horizontal. Vertical stretches to its row's height. */
|
|
4
|
+
orientation?: 'horizontal' | 'vertical';
|
|
5
|
+
/** Text centered in a horizontal divider ("或"). Ignored when vertical. */
|
|
6
|
+
label?: ReactNode;
|
|
7
|
+
}
|
package/dist/divider.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/field.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface FieldOwnProps {
|
|
3
|
+
label?: ReactNode;
|
|
4
|
+
/** Shown under the control in text-muted. */
|
|
5
|
+
help?: ReactNode;
|
|
6
|
+
/** Shown under the control in error-text; marks the control invalid. */
|
|
7
|
+
error?: ReactNode;
|
|
8
|
+
/** Adds a red asterisk and marks the control required. */
|
|
9
|
+
required?: boolean;
|
|
10
|
+
/** Appends "(选填)" to the label. */
|
|
11
|
+
optional?: boolean;
|
|
12
|
+
/** One Input, Textarea or Select; it gets the label, help and error wired to it. */
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}
|
package/dist/field.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/icon.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An icon in Iconify's data format (`IconifyIcon`): the markup inside the <svg> and its viewBox. Any Iconify
|
|
3
|
+
* set fits (`@iconify-icons/<set>/<name>`), so sets can be mixed, and a hand-drawn SVG is written the same way.
|
|
4
|
+
* Koi's own icons come from Font Awesome Free Solid (`@iconify-icons/fa7-solid`).
|
|
5
|
+
*/
|
|
6
|
+
export interface IconData {
|
|
7
|
+
/** Everything inside the <svg>, drawn in currentColor. */
|
|
8
|
+
body: string;
|
|
9
|
+
/** viewBox width. Default 16, as in Iconify. */
|
|
10
|
+
width?: number;
|
|
11
|
+
/** viewBox height. Default 16, as in Iconify. */
|
|
12
|
+
height?: number;
|
|
13
|
+
/** viewBox x origin. Default 0. */
|
|
14
|
+
left?: number;
|
|
15
|
+
/** viewBox y origin. Default 0. */
|
|
16
|
+
top?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface IconOwnProps {
|
|
19
|
+
icon: IconData;
|
|
20
|
+
/** px. The box is square and the drawing is centered in it. Default `icon` (16). */
|
|
21
|
+
size?: number;
|
|
22
|
+
}
|
package/dist/icon.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export * from './alert.js';
|
|
2
|
+
export * from './avatar.js';
|
|
3
|
+
export * from './badge.js';
|
|
4
|
+
export * from './button.js';
|
|
5
|
+
export * from './card.js';
|
|
6
|
+
export * from './chat-bubble.js';
|
|
7
|
+
export * from './change-details.js';
|
|
8
|
+
export * from './checkbox.js';
|
|
9
|
+
export * from './common.js';
|
|
10
|
+
export * from './dialog.js';
|
|
11
|
+
export * from './divider.js';
|
|
12
|
+
export * from './field.js';
|
|
13
|
+
export * from './icon.js';
|
|
14
|
+
export * from './input.js';
|
|
15
|
+
export * from './link.js';
|
|
16
|
+
export * from './pagination.js';
|
|
17
|
+
export * from './progress.js';
|
|
18
|
+
export * from './prose.js';
|
|
19
|
+
export * from './radio-group.js';
|
|
20
|
+
export * from './select.js';
|
|
21
|
+
export * from './skeleton.js';
|
|
22
|
+
export * from './spinner.js';
|
|
23
|
+
export * from './strings.js';
|
|
24
|
+
export * from './switch.js';
|
|
25
|
+
export * from './table.js';
|
|
26
|
+
export * from './tabs.js';
|
|
27
|
+
export * from './tag.js';
|
|
28
|
+
export * from './toast.js';
|
|
29
|
+
export * from './tooltip.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// @tuuject/koi-core: what every Koi platform shares. Each component's props contract (`<Name>OwnProps`), the change
|
|
2
|
+
// details its callbacks pass, the copy it writes and the pure logic behind it. No DOM, no styling, no headless
|
|
3
|
+
// library: @tuuject/koi-react adds the DOM attributes on top, a native package will add its own. Rules: agent-doc/core.md.
|
|
4
|
+
export * from './alert.js';
|
|
5
|
+
export * from './avatar.js';
|
|
6
|
+
export * from './badge.js';
|
|
7
|
+
export * from './button.js';
|
|
8
|
+
export * from './card.js';
|
|
9
|
+
export * from './chat-bubble.js';
|
|
10
|
+
export * from './change-details.js';
|
|
11
|
+
export * from './checkbox.js';
|
|
12
|
+
export * from './common.js';
|
|
13
|
+
export * from './dialog.js';
|
|
14
|
+
export * from './divider.js';
|
|
15
|
+
export * from './field.js';
|
|
16
|
+
export * from './icon.js';
|
|
17
|
+
export * from './input.js';
|
|
18
|
+
export * from './link.js';
|
|
19
|
+
export * from './pagination.js';
|
|
20
|
+
export * from './progress.js';
|
|
21
|
+
export * from './prose.js';
|
|
22
|
+
export * from './radio-group.js';
|
|
23
|
+
export * from './select.js';
|
|
24
|
+
export * from './skeleton.js';
|
|
25
|
+
export * from './spinner.js';
|
|
26
|
+
export * from './strings.js';
|
|
27
|
+
export * from './switch.js';
|
|
28
|
+
export * from './table.js';
|
|
29
|
+
export * from './tabs.js';
|
|
30
|
+
export * from './tag.js';
|
|
31
|
+
export * from './toast.js';
|
|
32
|
+
export * from './tooltip.js';
|
package/dist/input.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ControlSize } from './common.js';
|
|
3
|
+
export interface InputOwnProps {
|
|
4
|
+
/** sm 28px / md 36px / lg 44px, the same heights as Button. Default md. */
|
|
5
|
+
size?: ControlSize;
|
|
6
|
+
/** Red edge, announced as invalid. Set automatically inside a Field with an error. */
|
|
7
|
+
invalid?: boolean;
|
|
8
|
+
iconStart?: ReactNode;
|
|
9
|
+
iconEnd?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export interface TextareaOwnProps {
|
|
12
|
+
/** Red edge, announced as invalid. Set automatically inside a Field with an error. */
|
|
13
|
+
invalid?: boolean;
|
|
14
|
+
}
|
package/dist/input.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/link.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* underline (default): the blog's dashed underline and soft hover tint. plain: secondary text that turns brand on
|
|
4
|
+
* hover, no underline and no tint; for navigation rows such as breadcrumbs, where a link should read as a muted
|
|
5
|
+
* label until pointed at.
|
|
6
|
+
*/
|
|
7
|
+
export type LinkVariant = 'underline' | 'plain';
|
|
8
|
+
export interface LinkOwnProps {
|
|
9
|
+
href?: string;
|
|
10
|
+
/** Opens outside the app (a new tab on the web), with an arrow glyph and a screen-reader note. */
|
|
11
|
+
external?: boolean;
|
|
12
|
+
/** How the link is drawn. Default underline. */
|
|
13
|
+
variant?: LinkVariant;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}
|
package/dist/link.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type PaginationVariant = 'numbered' | 'simple' | 'compact';
|
|
2
|
+
export interface PaginationOwnProps {
|
|
3
|
+
/** The current page, 1-based. */
|
|
4
|
+
page: number;
|
|
5
|
+
pageCount: number;
|
|
6
|
+
/** Called with the page to go to. Choosing the current page calls it too (as legacy). */
|
|
7
|
+
onChange?: (page: number) => void;
|
|
8
|
+
/**
|
|
9
|
+
* numbered (default): prev, page numbers, next. simple: the blog's two large pills around "n / m".
|
|
10
|
+
* compact: page numbers between round icon-only prev/next, all in one tight row of circles.
|
|
11
|
+
*/
|
|
12
|
+
variant?: PaginationVariant;
|
|
13
|
+
/** Default "上一页". */
|
|
14
|
+
prevLabel?: string;
|
|
15
|
+
/** Default "下一页". */
|
|
16
|
+
nextLabel?: string;
|
|
17
|
+
/** How many neighbours to show on each side of the current page. Default 1. */
|
|
18
|
+
siblings?: number;
|
|
19
|
+
/** The navigation's accessible name. Default "分页". */
|
|
20
|
+
label?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Legacy's pageList, unchanged: the first and last page always, the current page with `sib` neighbours each side,
|
|
24
|
+
* and a gap ("…a" before, "…b" after) wherever pages are left out, even if only one is.
|
|
25
|
+
*/
|
|
26
|
+
export declare function pageList(page: number, count: number, sib: number): (number | '…a' | '…b')[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy's pageList, unchanged: the first and last page always, the current page with `sib` neighbours each side,
|
|
3
|
+
* and a gap ("…a" before, "…b" after) wherever pages are left out, even if only one is.
|
|
4
|
+
*/
|
|
5
|
+
export function pageList(page, count, sib) {
|
|
6
|
+
const out = [];
|
|
7
|
+
const lo = Math.max(2, page - sib);
|
|
8
|
+
const hi = Math.min(count - 1, page + sib);
|
|
9
|
+
out.push(1);
|
|
10
|
+
if (lo > 2) {
|
|
11
|
+
out.push('…a');
|
|
12
|
+
}
|
|
13
|
+
for (let i = lo; i <= hi; i++) {
|
|
14
|
+
out.push(i);
|
|
15
|
+
}
|
|
16
|
+
if (hi < count - 1) {
|
|
17
|
+
out.push('…b');
|
|
18
|
+
}
|
|
19
|
+
if (count > 1) {
|
|
20
|
+
out.push(count);
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type ProgressSize = 'sm' | 'md' | 'lg';
|
|
2
|
+
export interface ProgressOwnProps {
|
|
3
|
+
/** 0–`max`. Omit (or pass null) for an indeterminate bar. */
|
|
4
|
+
value?: number | null;
|
|
5
|
+
/** Default 100. */
|
|
6
|
+
max?: number;
|
|
7
|
+
/** Shown above the bar and used as its accessible name. Without it the bar is named "进度". */
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Show the rounded percentage at the end of the head row (determinate bars only). */
|
|
10
|
+
showValue?: boolean;
|
|
11
|
+
/** Track height: sm 4px, md 8px (default), lg 12px. */
|
|
12
|
+
size?: ProgressSize;
|
|
13
|
+
}
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/prose.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export declare const PROSE_SIZES: readonly ['sm', 'md'];
|
|
3
|
+
export type ProseSize = (typeof PROSE_SIZES)[number];
|
|
4
|
+
export interface ProseOwnProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* The base size everything inside scales from: `md` (default) is 16px for articles and docs, `sm` is 14px for
|
|
8
|
+
* rich text that sits among UI text (comments, descriptions, assistant replies in a dense panel).
|
|
9
|
+
*/
|
|
10
|
+
size?: ProseSize;
|
|
11
|
+
}
|
package/dist/prose.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const PROSE_SIZES = ['sm', 'md'];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ChangeDetails } from './change-details.js';
|
|
3
|
+
export interface RadioOption {
|
|
4
|
+
value: string;
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** Shown under the label in text-muted. */
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface RadioGroupOwnProps<E = unknown> {
|
|
11
|
+
options: RadioOption[];
|
|
12
|
+
value?: string;
|
|
13
|
+
defaultValue?: string;
|
|
14
|
+
/** Called with the newly chosen value. */
|
|
15
|
+
onChange?: (value: string, details: ChangeDetails<E>) => void;
|
|
16
|
+
/** Accessible name of the group (not shown). Inside a Field, the Field's label names it instead. */
|
|
17
|
+
label?: string;
|
|
18
|
+
orientation?: 'vertical' | 'horizontal';
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/select.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ChangeDetails } from './change-details.js';
|
|
3
|
+
import type { ControlSize } from './common.js';
|
|
4
|
+
export interface SelectOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface SelectOptionGroup<T extends SelectOption = SelectOption> {
|
|
10
|
+
label: string;
|
|
11
|
+
items: T[];
|
|
12
|
+
}
|
|
13
|
+
export type SelectEntry = SelectOption | SelectOptionGroup;
|
|
14
|
+
/** The option type inside `items`: the item itself, or the items of a group. */
|
|
15
|
+
export type SelectOptionOf<I> = I extends SelectOptionGroup<infer T> ? T : I;
|
|
16
|
+
/** The platform's own picker (a native <select> on the web). Its value and change handler are the platform's. */
|
|
17
|
+
export interface SelectOwnProps {
|
|
18
|
+
/** The choices. */
|
|
19
|
+
options?: SelectOption[];
|
|
20
|
+
/** A disabled first option shown until the user picks. */
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
/** sm 28px / md 36px / lg 44px, the same heights as Input and Button. Default md. */
|
|
23
|
+
size?: ControlSize;
|
|
24
|
+
/** Red edge, announced as invalid. Set automatically inside a Field with an error. */
|
|
25
|
+
invalid?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** Koi's own dropdown panel, optionally searchable. */
|
|
28
|
+
export interface SelectPanelOwnProps<I extends SelectEntry = SelectEntry, E = unknown> {
|
|
29
|
+
/** Options (`{value, label, disabled?}` plus any fields of your own), or groups of them (`{label, items}`). */
|
|
30
|
+
items: readonly I[];
|
|
31
|
+
value?: string | null;
|
|
32
|
+
defaultValue?: string | null;
|
|
33
|
+
onChange?: (value: string | null, details: ChangeDetails<E>) => void;
|
|
34
|
+
/** Shown in the trigger until something is chosen. Default "请选择". */
|
|
35
|
+
placeholder?: ReactNode;
|
|
36
|
+
/** sm 28px / md 36px / lg 44px, the same heights as Input and Button. Default md. */
|
|
37
|
+
size?: ControlSize;
|
|
38
|
+
/** Red edge, announced as invalid. Set automatically inside a Field with an error. */
|
|
39
|
+
invalid?: boolean;
|
|
40
|
+
disabled?: boolean;
|
|
41
|
+
readOnly?: boolean;
|
|
42
|
+
/** Puts a search box at the top of the panel that filters `items` by label. */
|
|
43
|
+
searchable?: boolean;
|
|
44
|
+
/** Default "搜索". Also the search box's accessible name. */
|
|
45
|
+
searchPlaceholder?: string;
|
|
46
|
+
/** Shown when the search matches nothing. Default "无匹配项". */
|
|
47
|
+
emptyText?: ReactNode;
|
|
48
|
+
/** Draws the chosen option in the trigger. Default: its label. */
|
|
49
|
+
renderValue?: (item: SelectOptionOf<I>) => ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Draws the panel. Receives the options to show (filtered by the search, empty groups dropped) in the shape
|
|
52
|
+
* `items` has; render each as a SelectItem (in SelectGroups, with SelectSeparators, around your own markup).
|
|
53
|
+
* Default: a SelectItem per option and a SelectGroup per group.
|
|
54
|
+
*/
|
|
55
|
+
children?: (items: I[]) => ReactNode;
|
|
56
|
+
open?: boolean;
|
|
57
|
+
defaultOpen?: boolean;
|
|
58
|
+
onOpenChange?: (open: boolean, details: ChangeDetails<E>) => void;
|
|
59
|
+
}
|
|
60
|
+
export interface SelectItemOwnProps {
|
|
61
|
+
/** The option's `value`. */
|
|
62
|
+
value: string;
|
|
63
|
+
/** Text for type-to-find when `children` isn't plain text. */
|
|
64
|
+
label?: string;
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
children: ReactNode;
|
|
67
|
+
}
|
|
68
|
+
export interface SelectGroupOwnProps {
|
|
69
|
+
/** The heading; it names the group for screen readers. */
|
|
70
|
+
label: ReactNode;
|
|
71
|
+
children: ReactNode;
|
|
72
|
+
}
|
package/dist/select.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/skeleton.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/spinner.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Every piece of copy a component writes on its own (labels, accessible names, defaults). Simplified Chinese, no emoji. */
|
|
2
|
+
export declare const strings: {
|
|
3
|
+
readonly close: '关闭';
|
|
4
|
+
readonly loading: '加载中';
|
|
5
|
+
/** A Button's spinner while `loading`. */
|
|
6
|
+
readonly processing: '处理中';
|
|
7
|
+
readonly avatar: '头像';
|
|
8
|
+
readonly optional: '(选填)';
|
|
9
|
+
/** Read after an external Link. */
|
|
10
|
+
readonly opensInNewWindow: '(在新窗口打开)';
|
|
11
|
+
readonly prevPage: '上一页';
|
|
12
|
+
readonly nextPage: '下一页';
|
|
13
|
+
readonly pagination: '分页';
|
|
14
|
+
readonly page: (n: number) => string;
|
|
15
|
+
readonly progress: '进度';
|
|
16
|
+
/** An indeterminate Progress's value text. */
|
|
17
|
+
readonly inProgress: '进行中';
|
|
18
|
+
readonly selectPlaceholder: '请选择';
|
|
19
|
+
readonly search: '搜索';
|
|
20
|
+
readonly noMatches: '无匹配项';
|
|
21
|
+
/** Tag's × button; the tag's label follows it. */
|
|
22
|
+
readonly remove: '移除';
|
|
23
|
+
/** An empty Table's message. */
|
|
24
|
+
readonly noData: '暂无数据';
|
|
25
|
+
/** The toast region's accessible name. */
|
|
26
|
+
readonly notifications: '通知';
|
|
27
|
+
};
|
package/dist/strings.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Every piece of copy a component writes on its own (labels, accessible names, defaults). Simplified Chinese, no emoji. */
|
|
2
|
+
export const strings = {
|
|
3
|
+
close: '关闭',
|
|
4
|
+
loading: '加载中',
|
|
5
|
+
/** A Button's spinner while `loading`. */
|
|
6
|
+
processing: '处理中',
|
|
7
|
+
avatar: '头像',
|
|
8
|
+
optional: '(选填)',
|
|
9
|
+
/** Read after an external Link. */
|
|
10
|
+
opensInNewWindow: '(在新窗口打开)',
|
|
11
|
+
prevPage: '上一页',
|
|
12
|
+
nextPage: '下一页',
|
|
13
|
+
pagination: '分页',
|
|
14
|
+
page: (n) => `第 ${n} 页`,
|
|
15
|
+
progress: '进度',
|
|
16
|
+
/** An indeterminate Progress's value text. */
|
|
17
|
+
inProgress: '进行中',
|
|
18
|
+
selectPlaceholder: '请选择',
|
|
19
|
+
search: '搜索',
|
|
20
|
+
noMatches: '无匹配项',
|
|
21
|
+
/** Tag's × button; the tag's label follows it. */
|
|
22
|
+
remove: '移除',
|
|
23
|
+
/** An empty Table's message. */
|
|
24
|
+
noData: '暂无数据',
|
|
25
|
+
/** The toast region's accessible name. */
|
|
26
|
+
notifications: '通知',
|
|
27
|
+
};
|
package/dist/switch.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ChangeDetails } from './change-details.js';
|
|
3
|
+
export interface SwitchOwnProps<E = unknown> {
|
|
4
|
+
label?: ReactNode;
|
|
5
|
+
/** On or off (controlled). */
|
|
6
|
+
checked?: boolean;
|
|
7
|
+
/** On or off at first (uncontrolled). */
|
|
8
|
+
defaultChecked?: boolean;
|
|
9
|
+
onCheckedChange?: (checked: boolean, details: ChangeDetails<E>) => void;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** Can't be switched, but still focusable. */
|
|
12
|
+
readOnly?: boolean;
|
|
13
|
+
}
|
package/dist/switch.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/table.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** Where a cell's content sits. Put numbers at `end`. */
|
|
3
|
+
export type TableAlign = 'start' | 'center' | 'end';
|
|
4
|
+
/** A column's sort state. The same shape TanStack Table's `column.getIsSorted()` returns. */
|
|
5
|
+
export type TableSortDirection = 'asc' | 'desc' | false;
|
|
6
|
+
/**
|
|
7
|
+
* How column widths are decided. `auto` (default): by content, so they shift when the content changes (a skeleton
|
|
8
|
+
* being replaced, the next page). `fixed`: by the widths you give (the header row's cells, or DataTable's column
|
|
9
|
+
* `width`); columns without one share what's left. Content that doesn't fit ends in an ellipsis.
|
|
10
|
+
*/
|
|
11
|
+
export type TableLayout = 'auto' | 'fixed';
|
|
12
|
+
/** The table itself. Its parts are plain table elements, so a headless table library can drive them directly. */
|
|
13
|
+
export interface TableOwnProps {
|
|
14
|
+
/** auto (default) / fixed. Use fixed with column widths when the rows load or page in place. */
|
|
15
|
+
layout?: TableLayout;
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
/** The header, body and footer row groups. */
|
|
19
|
+
export interface TableSectionOwnProps {
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
export type TableHeaderOwnProps = TableSectionOwnProps;
|
|
23
|
+
export type TableBodyOwnProps = TableSectionOwnProps;
|
|
24
|
+
export type TableFooterOwnProps = TableSectionOwnProps;
|
|
25
|
+
export type TableCaptionOwnProps = TableSectionOwnProps;
|
|
26
|
+
export interface TableCellOwnProps {
|
|
27
|
+
/** start (default) / center / end. */
|
|
28
|
+
align?: TableAlign;
|
|
29
|
+
/** `none` drops the 8px top and bottom padding, so a 36px control fits the 48px row. Default `default`. */
|
|
30
|
+
paddingBlock?: 'default' | 'none';
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
export interface TableHeaderCellOwnProps<E = unknown> extends TableCellOwnProps {
|
|
34
|
+
/** The column's current sort. Only shown when the column is sortable (`onSort`). */
|
|
35
|
+
sort?: TableSortDirection;
|
|
36
|
+
/**
|
|
37
|
+
* Makes the header a sort button. Called on press; the platform's event is passed through, so TanStack
|
|
38
|
+
* Table's `column.getToggleSortingHandler()` can be handed over as is. TanStack v9 returns a handler even for
|
|
39
|
+
* columns that can't sort, so pass it only when `column.getCanSort()`.
|
|
40
|
+
*/
|
|
41
|
+
onSort?: (event: E) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface TableRowOwnProps {
|
|
44
|
+
/** Fills the row with the selection tint. */
|
|
45
|
+
selected?: boolean;
|
|
46
|
+
children?: ReactNode;
|
|
47
|
+
}
|
|
48
|
+
export interface TableEmptyOwnProps {
|
|
49
|
+
/** How many columns the message spans: the table's column count. */
|
|
50
|
+
colSpan: number;
|
|
51
|
+
/** Default "暂无数据". */
|
|
52
|
+
children?: ReactNode;
|
|
53
|
+
}
|
|
54
|
+
export interface DataTableColumn<T> {
|
|
55
|
+
/** Unique within the table. */
|
|
56
|
+
key: string;
|
|
57
|
+
header: ReactNode;
|
|
58
|
+
cell: (row: T, index: number) => ReactNode;
|
|
59
|
+
align?: TableAlign;
|
|
60
|
+
/** The column's width: a number is px, a string any CSS length ('20%'). Pair with the table's `layout="fixed"`. */
|
|
61
|
+
width?: number | string;
|
|
62
|
+
/** Sample content for this column's loading placeholder, which takes its size (e.g. '¥199.00'). */
|
|
63
|
+
skeleton?: ReactNode;
|
|
64
|
+
}
|
|
65
|
+
/** A ready-made table from columns and rows. For sorting, selection or a table library, compose the Table parts instead. */
|
|
66
|
+
export interface DataTableOwnProps<T> {
|
|
67
|
+
columns: ReadonlyArray<DataTableColumn<T>>;
|
|
68
|
+
rows: readonly T[];
|
|
69
|
+
getRowKey: (row: T, index: number) => string | number;
|
|
70
|
+
/** Shows skeleton rows instead of `rows`. */
|
|
71
|
+
loading?: boolean;
|
|
72
|
+
/** How many skeleton rows to show while loading. Default 5. */
|
|
73
|
+
skeletonRows?: number;
|
|
74
|
+
/** Shown when there are no rows. Default "暂无数据". */
|
|
75
|
+
empty?: ReactNode;
|
|
76
|
+
/** The table's accessible name, read by screen readers only. */
|
|
77
|
+
caption?: ReactNode;
|
|
78
|
+
/** auto (default) / fixed. With `fixed` and column widths, columns hold still while rows load and page. */
|
|
79
|
+
layout?: TableLayout;
|
|
80
|
+
}
|
package/dist/table.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/tabs.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ChangeDetails } from './change-details.js';
|
|
3
|
+
export interface TabItem {
|
|
4
|
+
value: string;
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** The panel shown while this tab is active. Leave it out on every item for a pure segmented control. */
|
|
7
|
+
content?: ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface TabsOwnProps<E = unknown> {
|
|
11
|
+
items: TabItem[];
|
|
12
|
+
value?: string;
|
|
13
|
+
/** Defaults to the first enabled item. */
|
|
14
|
+
defaultValue?: string;
|
|
15
|
+
/** Called with the newly chosen value when the user picks a tab. */
|
|
16
|
+
onChange?: (value: string, details: ChangeDetails<E>) => void;
|
|
17
|
+
/** Accessible name of the tab list (not shown). */
|
|
18
|
+
label?: string;
|
|
19
|
+
/** Stretch the track to the container and share its width between the tabs. */
|
|
20
|
+
fullWidth?: boolean;
|
|
21
|
+
}
|
package/dist/tabs.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/tag.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface TagOwnProps<E = unknown> {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
/** A 14px icon before the label. */
|
|
5
|
+
icon?: ReactNode;
|
|
6
|
+
/** The `action-subtle` fill of a chosen filter chip. On its own it's only the look. */
|
|
7
|
+
selected?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Makes the tag a toggle for filter chips. Called with the next state when it's pressed; pass `selected` back.
|
|
10
|
+
* `E` is the platform's press event.
|
|
11
|
+
*/
|
|
12
|
+
onSelectedChange?: (selected: boolean, event: E) => void;
|
|
13
|
+
/** Shows a remove (×) button, named "移除 <label>". */
|
|
14
|
+
onRemove?: () => void;
|
|
15
|
+
}
|
package/dist/tag.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/toast.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type ToastTone = 'info' | 'success' | 'warning' | 'error';
|
|
3
|
+
/** At most this many toasts show; a newer one closes the oldest for good. */
|
|
4
|
+
export declare const TOAST_LIMIT = 4;
|
|
5
|
+
/** ms before a toast closes on its own, unless its options say otherwise. */
|
|
6
|
+
export declare const TOAST_DURATION = 4000;
|
|
7
|
+
export interface ToastOwnProps {
|
|
8
|
+
/** info and success (brand icon) / warning / error. Default info. */
|
|
9
|
+
tone?: ToastTone;
|
|
10
|
+
title?: ReactNode;
|
|
11
|
+
description?: ReactNode;
|
|
12
|
+
/** Usually a small Button, at the end of the toast. */
|
|
13
|
+
action?: ReactNode;
|
|
14
|
+
/** Shows a close button. */
|
|
15
|
+
onClose?: () => void;
|
|
16
|
+
}
|
|
17
|
+
export interface ToastOptions {
|
|
18
|
+
tone?: ToastTone;
|
|
19
|
+
title?: ReactNode;
|
|
20
|
+
description?: ReactNode;
|
|
21
|
+
action?: ReactNode;
|
|
22
|
+
/** ms before it closes on its own; 0 keeps it until it's closed. Default 4000. */
|
|
23
|
+
duration?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface ToastProviderOwnProps {
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
/** Where the stack sits, centered. Default bottom. */
|
|
28
|
+
position?: 'bottom' | 'top';
|
|
29
|
+
}
|
|
30
|
+
/** What `useToast()` returns. */
|
|
31
|
+
export interface ToastApi {
|
|
32
|
+
/** Shows a toast and returns its id. */
|
|
33
|
+
toast(options: ToastOptions): number;
|
|
34
|
+
dismiss(id: number): void;
|
|
35
|
+
}
|
package/dist/toast.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { ChangeDetails } from './change-details.js';
|
|
3
|
+
export type TooltipSide = 'top' | 'bottom';
|
|
4
|
+
export interface TooltipOwnProps<E = unknown> {
|
|
5
|
+
/** A short phrase. Never essential information or interactive content. */
|
|
6
|
+
content: ReactNode;
|
|
7
|
+
/** One focusable element (a Button, IconButton, Link…). */
|
|
8
|
+
children: ReactElement;
|
|
9
|
+
/** Preferred side; flips to the other one when there's no room. Default top. */
|
|
10
|
+
side?: TooltipSide;
|
|
11
|
+
/** Force open or closed (controlled). */
|
|
12
|
+
open?: boolean;
|
|
13
|
+
/** Open on first render, then behave as usual. */
|
|
14
|
+
defaultOpen?: boolean;
|
|
15
|
+
onOpenChange?: (open: boolean, details: ChangeDetails<E>) => void;
|
|
16
|
+
/** Milliseconds of hover before it opens. Default 0: it opens on hover, as in legacy. Keyboard focus always opens it at once. */
|
|
17
|
+
delay?: number;
|
|
18
|
+
/** Milliseconds before it closes after the pointer leaves. Default 0. */
|
|
19
|
+
closeDelay?: number;
|
|
20
|
+
/** Never open. */
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
}
|
package/dist/tooltip.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuuject/koi-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Koi's platform-neutral layer: each component's props contract, change details, UI copy and pure helpers. Shared by @tuuject/koi-react and the future native package; no DOM, no styling, no headless library.",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"react": "^19.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/react": "^19.3.0",
|
|
25
|
+
"typescript": "^7.0.2"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/tuuject/design.git",
|
|
30
|
+
"directory": "packages/core"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/tuuject/design#readme",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.build.json",
|
|
36
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
37
|
+
}
|
|
6
38
|
}
|