animal-island-ui-tailwind 0.8.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/AI_USAGE.md +708 -0
- package/DESIGN_PROMPT.md +340 -0
- package/LICENSE +21 -0
- package/README.md +209 -0
- package/dist/cjs/index.cjs +134 -0
- package/dist/es/index.js +8728 -0
- package/dist/files/cursor-icon.1ea93a65.png +0 -0
- package/dist/files/divider-line-brown.1e2cace7.svg +1 -0
- package/dist/files/divider-line-teal.e8b28b87.svg +1 -0
- package/dist/files/divider-line-white.a27273fa.png +0 -0
- package/dist/files/divider-line-yellow.838b9359.svg +1 -0
- package/dist/files/footer-sea.0e5c1ae8.svg +1 -0
- package/dist/files/footer-tree.70bf56ae.webp +0 -0
- package/dist/files/icon-camera.51fd7127.svg +7 -0
- package/dist/files/icon-chat.7cdc7b1f.svg +7 -0
- package/dist/files/icon-critterpedia.2c4ac782.svg +15 -0
- package/dist/files/icon-design.5ac514dc.svg +7 -0
- package/dist/files/icon-diy.e66a3414.svg +8 -0
- package/dist/files/icon-helicopter.6d8fe926.svg +13 -0
- package/dist/files/icon-leaf.40329f03.png +0 -0
- package/dist/files/icon-map.9182b8ee.svg +15 -0
- package/dist/files/icon-miles.defd75be.svg +11 -0
- package/dist/files/icon-shopping.e88affb9.svg +6 -0
- package/dist/files/icon-variant.711ed032.svg +13 -0
- package/dist/files/location.034ee5b1.svg +4 -0
- package/dist/files/noto-sans-sc-chinese-simplified-400-normal.e25467c8.woff2 +0 -0
- package/dist/files/noto-sans-sc-chinese-simplified-500-normal.d3553b6f.woff2 +0 -0
- package/dist/files/noto-sans-sc-chinese-simplified-700-normal.6e0a7691.woff2 +0 -0
- package/dist/files/noto-sans-sc-latin-400-normal.d0072abd.woff2 +0 -0
- package/dist/files/noto-sans-sc-latin-500-normal.df58f967.woff2 +0 -0
- package/dist/files/noto-sans-sc-latin-700-normal.11e48442.woff2 +0 -0
- package/dist/files/nunito-latin-500-normal.78b3b3a4.woff2 +0 -0
- package/dist/files/nunito-latin-700-normal.0b62b606.woff2 +0 -0
- package/dist/files/nunito-latin-900-normal.8b5d13b8.woff2 +0 -0
- package/dist/files/page.8a1e631f.svg +5 -0
- package/dist/files/select-cursor.9437140a.svg +9 -0
- package/dist/files/wave-yellow.13bac28d.svg +1 -0
- package/dist/files/wifi.7bcda569.svg +9 -0
- package/dist/files/zen-maru-gothic-japanese-500-normal.e6394930.woff2 +0 -0
- package/dist/files/zen-maru-gothic-japanese-700-normal.9734ccb5.woff2 +0 -0
- package/dist/files/zen-maru-gothic-japanese-900-normal.f626e0c9.woff2 +0 -0
- package/dist/files/zen-maru-gothic-latin-500-normal.50ac2233.woff2 +0 -0
- package/dist/files/zen-maru-gothic-latin-700-normal.22e88023.woff2 +0 -0
- package/dist/files/zen-maru-gothic-latin-900-normal.f5c2c900.woff2 +0 -0
- package/dist/index.css +1 -0
- package/dist/types/components/Button/Button.d.ts +26 -0
- package/dist/types/components/Button/index.d.ts +2 -0
- package/dist/types/components/Card/Card.d.ts +12 -0
- package/dist/types/components/Card/index.d.ts +2 -0
- package/dist/types/components/Checkbox/Checkbox.d.ts +27 -0
- package/dist/types/components/Checkbox/index.d.ts +2 -0
- package/dist/types/components/CodeBlock/CodeBlock.d.ts +5 -0
- package/dist/types/components/CodeBlock/index.d.ts +2 -0
- package/dist/types/components/Collapse/Collapse.d.ts +17 -0
- package/dist/types/components/Collapse/index.d.ts +2 -0
- package/dist/types/components/Cursor/Cursor.d.ts +6 -0
- package/dist/types/components/Cursor/index.d.ts +2 -0
- package/dist/types/components/Divider/Divider.d.ts +7 -0
- package/dist/types/components/Divider/index.d.ts +2 -0
- package/dist/types/components/Footer/Footer.d.ts +7 -0
- package/dist/types/components/Footer/index.d.ts +2 -0
- package/dist/types/components/Icon/Icon.d.ts +12 -0
- package/dist/types/components/Icon/index.d.ts +2 -0
- package/dist/types/components/Input/Input.d.ts +22 -0
- package/dist/types/components/Input/index.d.ts +2 -0
- package/dist/types/components/Loading/Loading.d.ts +10 -0
- package/dist/types/components/Loading/index.d.ts +2 -0
- package/dist/types/components/Modal/Modal.d.ts +25 -0
- package/dist/types/components/Modal/index.d.ts +2 -0
- package/dist/types/components/Phone/Phone.d.ts +4 -0
- package/dist/types/components/Phone/index.d.ts +2 -0
- package/dist/types/components/Select/Select.d.ts +14 -0
- package/dist/types/components/Select/index.d.ts +2 -0
- package/dist/types/components/Switch/Switch.d.ts +22 -0
- package/dist/types/components/Switch/index.d.ts +2 -0
- package/dist/types/components/Tabs/Tabs.d.ts +16 -0
- package/dist/types/components/Tabs/index.d.ts +2 -0
- package/dist/types/components/Time/Time.d.ts +4 -0
- package/dist/types/components/Time/index.d.ts +2 -0
- package/dist/types/components/Typewriter/Typewriter.d.ts +25 -0
- package/dist/types/components/Typewriter/index.d.ts +2 -0
- package/dist/types/index.d.ts +52 -0
- package/dist/types/utils/cn.d.ts +10 -0
- package/package.json +112 -0
- package/skill/SKILL.md +1450 -0
package/AI_USAGE.md
ADDED
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
# animal-island-ui-tailwind · AI Usage Guide (v0.8.0)
|
|
2
|
+
|
|
3
|
+
> **FOR AI CODE ASSISTANTS**: This file is the canonical, machine-readable reference for generating code that uses `animal-island-ui-tailwind`. Prefer this file over any other source. Every prop / import / default below is copied verbatim from source. Do NOT invent props.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 0. Setup (once per project)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install animal-island-ui-tailwind
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// app entry (main.tsx / _app.tsx / App.tsx)
|
|
15
|
+
import 'animal-island-ui-tailwind/style'; // MUST import BEFORE any component usage
|
|
16
|
+
// Fonts (Nunito / Noto Sans SC / Zen Maru Gothic) are auto-bundled via @fontsource.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// Peer requirements
|
|
21
|
+
react >= 19.0.0
|
|
22
|
+
react-dom >= 19.0.0
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
> Global aesthetics preset (warm-parchment + pill shapes + 3D button shadow) is applied via `animal-island-ui-tailwind/style`. The package ships the original single-bundle distribution shape: ESM + CJS + `.d.ts`, one CSS entry, and extracted assets under `dist/files`. The runtime implementation uses Tailwind CSS v4 tokens plus Radix UI primitives for accessible interactive components.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Full API (18 components)
|
|
30
|
+
|
|
31
|
+
All named exports from `animal-island-ui-tailwind`:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import {
|
|
35
|
+
Button, Input, Switch, Modal, Card, Collapse,
|
|
36
|
+
Cursor, Time, Phone, Footer, Divider, Typewriter,
|
|
37
|
+
Icon, Select, Tabs, Checkbox, CodeBlock, Loading,
|
|
38
|
+
} from 'animal-island-ui-tailwind';
|
|
39
|
+
|
|
40
|
+
// Runtime value export (icon catalogue — 10 entries)
|
|
41
|
+
import { ICON_LIST } from 'animal-island-ui-tailwind';
|
|
42
|
+
|
|
43
|
+
import type {
|
|
44
|
+
ButtonProps, ButtonType, ButtonSize, ButtonHTMLType,
|
|
45
|
+
InputProps, InputSize, InputStatus,
|
|
46
|
+
SwitchProps, SwitchSize,
|
|
47
|
+
ModalProps,
|
|
48
|
+
CardProps, CardType, CardColor,
|
|
49
|
+
CollapseProps,
|
|
50
|
+
CursorProps,
|
|
51
|
+
TimeProps,
|
|
52
|
+
PhoneProps,
|
|
53
|
+
FooterProps, FooterType,
|
|
54
|
+
DividerProps,
|
|
55
|
+
TypewriterProps,
|
|
56
|
+
IconProps, IconName,
|
|
57
|
+
SelectProps, SelectOption,
|
|
58
|
+
TabsProps, TabItem,
|
|
59
|
+
CheckboxProps, CheckboxOption, CheckboxSize,
|
|
60
|
+
CodeBlockProps, LoadingProps,
|
|
61
|
+
} from 'animal-island-ui-tailwind';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 1.1 Button
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
type ButtonType = 'primary' | 'default' | 'dashed' | 'text' | 'link';
|
|
70
|
+
type ButtonSize = 'small' | 'middle' | 'large';
|
|
71
|
+
type ButtonHTMLType = 'submit' | 'reset' | 'button';
|
|
72
|
+
|
|
73
|
+
interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
|
|
74
|
+
type?: ButtonType; // default 'default'
|
|
75
|
+
size?: ButtonSize; // default 'middle'
|
|
76
|
+
danger?: boolean; // default false
|
|
77
|
+
ghost?: boolean; // default false
|
|
78
|
+
block?: boolean; // default false
|
|
79
|
+
loading?: boolean; // default false — renders diagonal-stripe animation
|
|
80
|
+
disabled?: boolean; // default false
|
|
81
|
+
icon?: React.ReactNode;
|
|
82
|
+
htmlType?: ButtonHTMLType; // default 'button'
|
|
83
|
+
children?: React.ReactNode;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Canonical usage:
|
|
88
|
+
```tsx
|
|
89
|
+
<Button type="primary" onClick={save}>Save</Button>
|
|
90
|
+
<Button type="primary" danger loading>Deleting…</Button>
|
|
91
|
+
<Button type="dashed" icon={<PlusIcon />} size="large" block>Add</Button>
|
|
92
|
+
<Button type="text">Cancel</Button>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### 1.2 Input
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
type InputSize = 'small' | 'middle' | 'large';
|
|
101
|
+
type InputStatus = 'error' | 'warning';
|
|
102
|
+
|
|
103
|
+
interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
|
|
104
|
+
size?: InputSize; // default 'middle'
|
|
105
|
+
prefix?: React.ReactNode;
|
|
106
|
+
suffix?: React.ReactNode;
|
|
107
|
+
allowClear?: boolean; // default false
|
|
108
|
+
status?: InputStatus;
|
|
109
|
+
shadow?: boolean; // default false
|
|
110
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement>;
|
|
111
|
+
onClear?: () => void;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
<Input placeholder="Your name" allowClear />
|
|
117
|
+
<Input size="large" prefix={<SearchIcon />} value={q} onChange={e => setQ(e.target.value)} />
|
|
118
|
+
<Input status="error" suffix="@gmail.com" />
|
|
119
|
+
<Input disabled value="locked" />
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### 1.3 Switch
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
type SwitchSize = 'small' | 'default';
|
|
128
|
+
|
|
129
|
+
interface SwitchProps {
|
|
130
|
+
checked?: boolean; // controlled
|
|
131
|
+
defaultChecked?: boolean; // default false
|
|
132
|
+
size?: SwitchSize; // default 'default'
|
|
133
|
+
disabled?: boolean; // default false
|
|
134
|
+
loading?: boolean; // default false
|
|
135
|
+
checkedChildren?: React.ReactNode;
|
|
136
|
+
unCheckedChildren?: React.ReactNode;
|
|
137
|
+
onChange?: (checked: boolean) => void;
|
|
138
|
+
className?: string;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
<Switch defaultChecked onChange={v => console.log(v)} />
|
|
144
|
+
<Switch size="small" checkedChildren="ON" unCheckedChildren="OFF" />
|
|
145
|
+
<Switch loading disabled />
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### 1.4 Modal
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
interface ModalProps {
|
|
154
|
+
open: boolean; // REQUIRED
|
|
155
|
+
title?: React.ReactNode;
|
|
156
|
+
width?: number | string; // default 520
|
|
157
|
+
maskClosable?: boolean; // default true
|
|
158
|
+
footer?: React.ReactNode | null; // null = hide footer
|
|
159
|
+
onClose?: () => void;
|
|
160
|
+
onOk?: () => void;
|
|
161
|
+
children?: React.ReactNode;
|
|
162
|
+
className?: string;
|
|
163
|
+
typeSpeed?: number; // default 80 (ms/char for built-in typewriter)
|
|
164
|
+
typewriter?: boolean; // default true — body plays typewriter on open
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
const [open, setOpen] = useState(false);
|
|
170
|
+
<Modal
|
|
171
|
+
open={open}
|
|
172
|
+
title="Confirm"
|
|
173
|
+
onClose={() => setOpen(false)}
|
|
174
|
+
onOk={() => { submit(); setOpen(false); }}
|
|
175
|
+
>
|
|
176
|
+
Proceed to delete this island?
|
|
177
|
+
</Modal>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Notes:
|
|
181
|
+
- Modal already ships the required SVG blob `<clipPath id="animal-modal-clip">` internally.
|
|
182
|
+
- To disable the typewriter animation for dynamic content: `typewriter={false}`.
|
|
183
|
+
- Custom footer: pass `footer={<><Button>...</Button></>}` or `footer={null}` to hide.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### 1.5 Card
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
type CardType = 'default' | 'title' | 'dashed';
|
|
191
|
+
|
|
192
|
+
type CardColor =
|
|
193
|
+
| 'default' // rgb(247,243,223) / #725d42 text
|
|
194
|
+
| 'app-pink' // #f8a6b2 / #fff
|
|
195
|
+
| 'purple' // #b77dee / #fff
|
|
196
|
+
| 'app-blue' // #889df0 / #fff
|
|
197
|
+
| 'app-yellow' // #f7cd67 / #725d42
|
|
198
|
+
| 'app-orange' // #e59266 / #fff
|
|
199
|
+
| 'app-teal' // #82d5bb / #fff
|
|
200
|
+
| 'app-green' // #8ac68a / #fff
|
|
201
|
+
| 'app-red' // #fc736d / #fff
|
|
202
|
+
| 'lime-green' // #d1da49 / #3d5a1a
|
|
203
|
+
| 'yellow-green' // #ecdf52 / #725d42
|
|
204
|
+
| 'brown' // #9a835a / #fff
|
|
205
|
+
| 'warm-peach-pink'; // #e18c6f / #fff
|
|
206
|
+
|
|
207
|
+
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
208
|
+
type?: CardType; // default 'default'
|
|
209
|
+
color?: CardColor; // default 'default'
|
|
210
|
+
children?: React.ReactNode;
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<Card>Default parchment card</Card>
|
|
216
|
+
<Card type="title">Chapter One</Card>
|
|
217
|
+
<Card type="dashed">Draft / empty-state container</Card>
|
|
218
|
+
<Card color="app-yellow">Notification</Card>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### 1.6 Collapse
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
interface CollapseProps {
|
|
227
|
+
question: React.ReactNode; // REQUIRED — header
|
|
228
|
+
answer: React.ReactNode; // REQUIRED — body
|
|
229
|
+
defaultExpanded?: boolean; // default false
|
|
230
|
+
expanded?: boolean; // controlled mode
|
|
231
|
+
onChange?: (expanded: boolean) => void;
|
|
232
|
+
disabled?: boolean; // default false
|
|
233
|
+
className?: string;
|
|
234
|
+
style?: React.CSSProperties;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
<Collapse question="What is Animal Island?" answer="A cozy React UI kit." />
|
|
240
|
+
<Collapse defaultExpanded question="FAQ #1" answer={<p>Long rich content…</p>} />
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
> Uses pure CSS grid-row transition — no JS height measurement, safe for SSR.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### 1.7 Cursor
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
interface CursorProps {
|
|
251
|
+
children?: React.ReactNode;
|
|
252
|
+
className?: string;
|
|
253
|
+
style?: React.CSSProperties;
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Wrap the region where you want a game-style finger cursor:
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
<Cursor>
|
|
261
|
+
<App />
|
|
262
|
+
</Cursor>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
> Applies `cursor: url(...) 4 0, auto !important` to `*` descendants. Do NOT nest multiple `<Cursor>`.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### 1.8 Time
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
interface TimeProps {
|
|
273
|
+
className?: string;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
<Time /> // auto-updates every second, shows weekday + date + clock
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
No configurable props — it is a self-contained HUD widget.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
### 1.9 Phone (decorative NookPhone)
|
|
286
|
+
|
|
287
|
+
```ts
|
|
288
|
+
interface PhoneProps {
|
|
289
|
+
className?: string;
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
<Phone />
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
> Fixed size 527×788px. A decorative showcase widget: 3×3 app grid + live AM/PM clock + blinking colon + hover icon bounce. Not configurable beyond className.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
### 1.10 Footer
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
type FooterType = 'sea' | 'tree';
|
|
305
|
+
|
|
306
|
+
interface FooterProps {
|
|
307
|
+
type?: FooterType; // default 'tree'
|
|
308
|
+
className?: string;
|
|
309
|
+
style?: React.CSSProperties;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
<Footer /> {/* forest silhouette, 60px tall — default */}
|
|
315
|
+
<Footer type="sea" /> {/* ocean wave, 80px tall */}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
### 1.11 Divider
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
type DividerType = 'line-brown' | 'line-teal' | 'line-white' | 'line-yellow' | 'wave-yellow';
|
|
324
|
+
|
|
325
|
+
interface DividerProps {
|
|
326
|
+
type?: DividerType; // default 'line-brown'
|
|
327
|
+
className?: string;
|
|
328
|
+
style?: React.CSSProperties;
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
<Divider />
|
|
334
|
+
<Divider type="wave-yellow" />
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
> Height is fixed 12px. Purely decorative background-image band.
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
### 1.12 Typewriter
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
interface TypewriterProps {
|
|
345
|
+
children?: React.ReactNode; // ANY ReactNode — preserves element structure, classNames, inline styles
|
|
346
|
+
speed?: number; // ms per char, default 90
|
|
347
|
+
trigger?: unknown; // change this value to restart animation (e.g. modal openCount)
|
|
348
|
+
autoPlay?: boolean; // default true (false = show full immediately)
|
|
349
|
+
onDone?: () => void;
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
<Typewriter speed={60} onDone={() => setStep(2)}>
|
|
355
|
+
<p>Hello, <strong>traveler</strong>.</p>
|
|
356
|
+
<p>Welcome to the island.</p>
|
|
357
|
+
</Typewriter>
|
|
358
|
+
|
|
359
|
+
// Restart on modal open:
|
|
360
|
+
<Typewriter trigger={openCount}>{dialogueText}</Typewriter>
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
> Renders NO wrapper element; zero layout impact. Recursively truncates ReactNode by char count while preserving tree structure.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
### 1.13 Tabs
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
interface TabItem {
|
|
371
|
+
key: string;
|
|
372
|
+
label: React.ReactNode;
|
|
373
|
+
children: React.ReactNode;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
interface TabsProps {
|
|
377
|
+
items: TabItem[]; // REQUIRED
|
|
378
|
+
defaultActiveKey?: string; // default: first tab
|
|
379
|
+
activeKey?: string; // controlled mode
|
|
380
|
+
onChange?: (key: string) => void;
|
|
381
|
+
className?: string;
|
|
382
|
+
style?: React.CSSProperties;
|
|
383
|
+
leafAnimation?: boolean; // default true — active-tab leaf wiggle
|
|
384
|
+
shadow?: boolean; // default true — active-tab bottom shadow
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
```tsx
|
|
389
|
+
// Uncontrolled mode
|
|
390
|
+
<Tabs
|
|
391
|
+
items={[
|
|
392
|
+
{ key: 'tab1', label: '鱼类', children: <p>鲈鱼、鲷鱼...</p> },
|
|
393
|
+
{ key: 'tab2', label: '昆虫', children: <p>蝴蝶、蜻蜓...</p> },
|
|
394
|
+
]}
|
|
395
|
+
defaultActiveKey="tab1"
|
|
396
|
+
/>
|
|
397
|
+
|
|
398
|
+
// Controlled mode
|
|
399
|
+
const [activeKey, setActiveKey] = useState('tab1');
|
|
400
|
+
<Tabs
|
|
401
|
+
items={items}
|
|
402
|
+
activeKey={activeKey}
|
|
403
|
+
onChange={setActiveKey}
|
|
404
|
+
/>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
> Supports both controlled and uncontrolled modes. Smooth fade animation on tab switch.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
### 1.14 Icon
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
type IconName =
|
|
415
|
+
| 'icon-miles' | 'icon-camera' | 'icon-chat' | 'icon-critterpedia'
|
|
416
|
+
| 'icon-design' | 'icon-diy' | 'icon-helicopter'
|
|
417
|
+
| 'icon-map' | 'icon-shopping' | 'icon-variant';
|
|
418
|
+
|
|
419
|
+
interface IconProps {
|
|
420
|
+
name: IconName; // REQUIRED — one of the 10 built-in SVG icons
|
|
421
|
+
size?: number | string; // default 24 — applied to width & height
|
|
422
|
+
className?: string;
|
|
423
|
+
style?: React.CSSProperties;
|
|
424
|
+
bounce?: boolean; // default false — adds hover bounce animation
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Runtime catalogue for dynamic rendering / pickers (length = 10):
|
|
428
|
+
declare const ICON_LIST: { name: IconName; label: string }[];
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
```tsx
|
|
432
|
+
<Icon name="icon-camera" size={32} />
|
|
433
|
+
<Icon name="icon-chat" bounce />
|
|
434
|
+
{ICON_LIST.map(({ name, label }) => <Icon key={name} name={name} />)}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
> Icons are rendered as `<span>` with a background-image SVG. Use `size` (number=px, string=any CSS length) — do NOT wrap in a sized div.
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
### 1.15 Select
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
type SelectOption = { key: string; label: string };
|
|
445
|
+
|
|
446
|
+
interface SelectProps {
|
|
447
|
+
options: SelectOption[]; // REQUIRED
|
|
448
|
+
value: string; // REQUIRED — controlled-only
|
|
449
|
+
onChange: (key: string) => void; // REQUIRED
|
|
450
|
+
placeholder?: string; // default '请选择'
|
|
451
|
+
disabled?: boolean; // default false
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
```tsx
|
|
456
|
+
const [lang, setLang] = useState('zh');
|
|
457
|
+
<Select
|
|
458
|
+
value={lang}
|
|
459
|
+
onChange={setLang}
|
|
460
|
+
options={[
|
|
461
|
+
{ key: 'zh', label: '简体中文' },
|
|
462
|
+
{ key: 'en', label: 'English' },
|
|
463
|
+
{ key: 'ja', label: '日本語' },
|
|
464
|
+
]}
|
|
465
|
+
placeholder="Choose language"
|
|
466
|
+
/>
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
Notes:
|
|
470
|
+
- **Controlled only.** `value` and `onChange` are required — there is no `defaultValue`.
|
|
471
|
+
- Dropdown positioning and click-outside behavior are handled by Radix Select.
|
|
472
|
+
- `className` is applied to the trigger. There is no custom `renderOption`; style via package CSS or a wrapper class.
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
### 1.16 Checkbox
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
type CheckboxSize = 'small' | 'middle' | 'large';
|
|
480
|
+
|
|
481
|
+
interface CheckboxOption {
|
|
482
|
+
label: React.ReactNode;
|
|
483
|
+
value: string | number;
|
|
484
|
+
disabled?: boolean; // disable this option only
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
interface CheckboxProps {
|
|
488
|
+
options: CheckboxOption[]; // REQUIRED
|
|
489
|
+
value?: Array<string | number>; // controlled
|
|
490
|
+
defaultValue?: Array<string | number>; // default []
|
|
491
|
+
size?: CheckboxSize; // default 'middle'
|
|
492
|
+
disabled?: boolean; // default false — disables all
|
|
493
|
+
direction?: 'horizontal' | 'vertical'; // default 'horizontal'
|
|
494
|
+
onChange?: (values: Array<string | number>) => void;
|
|
495
|
+
className?: string;
|
|
496
|
+
style?: React.CSSProperties;
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
// Uncontrolled
|
|
502
|
+
<Checkbox
|
|
503
|
+
options={[
|
|
504
|
+
{ label: '🌊 海滩', value: 'beach' },
|
|
505
|
+
{ label: '🌳 森林', value: 'forest' },
|
|
506
|
+
{ label: '🦀 螃蟹', value: 'crab', disabled: true },
|
|
507
|
+
]}
|
|
508
|
+
defaultValue={['beach']}
|
|
509
|
+
/>
|
|
510
|
+
|
|
511
|
+
// Controlled + vertical
|
|
512
|
+
const [values, setValues] = useState<Array<string | number>>([]);
|
|
513
|
+
<Checkbox
|
|
514
|
+
options={options}
|
|
515
|
+
value={values}
|
|
516
|
+
onChange={setValues}
|
|
517
|
+
direction="vertical"
|
|
518
|
+
size="large"
|
|
519
|
+
/>
|
|
520
|
+
|
|
521
|
+
// Numeric values also allowed (string | number)
|
|
522
|
+
<Checkbox
|
|
523
|
+
options={[
|
|
524
|
+
{ label: 'Weekday', value: 1 },
|
|
525
|
+
{ label: 'Weekend', value: 2 },
|
|
526
|
+
]}
|
|
527
|
+
defaultValue={[1]}
|
|
528
|
+
/>
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
> Group-level `disabled` disables every item. Per-option `disabled` disables a single row. Checked box fills with `#19c8b9`. No indeterminate state.
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
### 1.17 CodeBlock
|
|
536
|
+
|
|
537
|
+
```ts
|
|
538
|
+
interface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {
|
|
539
|
+
code: string; // REQUIRED — raw source string
|
|
540
|
+
style?: React.CSSProperties; // merged on top of the dark preset
|
|
541
|
+
className?: string;
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
```tsx
|
|
546
|
+
<CodeBlock code={`import { Button } from 'animal-island-ui-tailwind';\n\n<Button type="primary">Go</Button>`} />
|
|
547
|
+
|
|
548
|
+
// Override theme
|
|
549
|
+
<CodeBlock
|
|
550
|
+
code={src}
|
|
551
|
+
style={{ borderRadius: 5, backgroundColor: '#242c46' }}
|
|
552
|
+
/>
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
> Renders a `<pre>` with built-in JSX/TS tokenizer. No language prop — always treated as JSX/TS. Not intended for non-JS languages. Default theme: bg `#2b2118`, border `1px solid #3d3028`, radius 20px, font-size 14, line-height 1.7.
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
### 1.18 Loading
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
interface LoadingProps {
|
|
563
|
+
className?: string;
|
|
564
|
+
style?: React.CSSProperties;
|
|
565
|
+
active?: boolean; // default true
|
|
566
|
+
}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
```tsx
|
|
570
|
+
<Loading />
|
|
571
|
+
<Loading active={isLoading} />
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
> Decorative island loading scene with built-in SVG and motion script assets. `active={false}` plays the closing mask transition and then hides the container.
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## 2. Common Recipes
|
|
579
|
+
|
|
580
|
+
### 2.1 Form row
|
|
581
|
+
|
|
582
|
+
```tsx
|
|
583
|
+
<Card>
|
|
584
|
+
<label>Email</label>
|
|
585
|
+
<Input size="large" type="email" allowClear status={invalid ? 'error' : undefined} />
|
|
586
|
+
<Switch checkedChildren="Subscribe" unCheckedChildren="Off" />
|
|
587
|
+
<Button type="primary" htmlType="submit" block>Submit</Button>
|
|
588
|
+
</Card>
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### 2.2 Confirm dialog
|
|
592
|
+
|
|
593
|
+
```tsx
|
|
594
|
+
<Modal
|
|
595
|
+
open={open}
|
|
596
|
+
title="Delete save file?"
|
|
597
|
+
onClose={close}
|
|
598
|
+
onOk={() => { remove(); close(); }}
|
|
599
|
+
footer={
|
|
600
|
+
<>
|
|
601
|
+
<Button onClick={close}>Cancel</Button>
|
|
602
|
+
<Button type="primary" danger onClick={() => { remove(); close(); }}>Delete</Button>
|
|
603
|
+
</>
|
|
604
|
+
}
|
|
605
|
+
>
|
|
606
|
+
This cannot be undone.
|
|
607
|
+
</Modal>
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### 2.3 FAQ page
|
|
611
|
+
|
|
612
|
+
```tsx
|
|
613
|
+
<Cursor>
|
|
614
|
+
<h1>FAQ</h1>
|
|
615
|
+
<Divider type="wave-yellow" />
|
|
616
|
+
{faqs.map(f => <Collapse key={f.id} question={f.q} answer={f.a} />)}
|
|
617
|
+
<Footer type="sea" />
|
|
618
|
+
</Cursor>
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### 2.4 Game-style intro
|
|
622
|
+
|
|
623
|
+
```tsx
|
|
624
|
+
<Modal open={open} onClose={close} typewriter typeSpeed={60}>
|
|
625
|
+
Welcome to Animal Island! Press <strong>OK</strong> to begin.
|
|
626
|
+
</Modal>
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
## 3. HARD RULES for AI code generation
|
|
632
|
+
|
|
633
|
+
Follow these strictly; violations are bugs:
|
|
634
|
+
|
|
635
|
+
1. **Import style only once**: `import 'animal-island-ui-tailwind/style';` at app entry. Do not re-import per component.
|
|
636
|
+
2. **Do NOT invent props.** Every prop used must appear verbatim in section 1. No `variant`, `shape`, `rounded`, `theme`, `color="primary"` etc. unless listed.
|
|
637
|
+
3. **`Modal.open` is required**; always provide a matching `onClose` or the dialog cannot be dismissed by user.
|
|
638
|
+
4. **`Collapse.question` and `Collapse.answer` are required.**
|
|
639
|
+
5. **Button `type`** values are `primary | default | dashed | text | link` — NOT `secondary`, `outline`, `ghost`. Use `ghost` prop for ghost styling.
|
|
640
|
+
6. **Switch `size`** is `'small' | 'default'` (NOT `'middle' | 'large'`). Diverges from Button/Input sizing.
|
|
641
|
+
7. **Card `color`** must be one of the 13 listed `CardColor` values. Do not pass hex codes. `type` is `'default' | 'title' | 'dashed'` — no other values.
|
|
642
|
+
8. **Divider / Footer / Phone / Time / Cursor** are primarily decorative. Prefer `className` or a wrapper for custom layout; do not invent component-specific color/size props.
|
|
643
|
+
9. **Typewriter emits no wrapper element.** Do not rely on a DOM node to style it — style the children instead.
|
|
644
|
+
10. **Icon `name` must be one of the 10 `IconName` values.** Do not pass arbitrary strings, URLs, or React nodes — only the built-in catalogue is supported.
|
|
645
|
+
11. **Select is controlled-only.** `options`, `value`, `onChange` are ALL required. Never omit `onChange` or pass `defaultValue`.
|
|
646
|
+
12. **Checkbox `size`** is `'small' | 'middle' | 'large'` (aligned with Button/Input — NOT with Switch). `options` is required; values can be `string | number`. No indeterminate state.
|
|
647
|
+
13. **CodeBlock** only highlights JSX/TS — do not pass Python/SQL/shell expecting language-specific coloring. There is no `language` prop.
|
|
648
|
+
14. **Do NOT import from deep paths** (`animal-island-ui-tailwind/lib/...`, `animal-island-ui-tailwind/src/...`). Only the package root and `animal-island-ui-tailwind/style` are public.
|
|
649
|
+
15. **TypeScript**: always import types from the package root, not from internal files.
|
|
650
|
+
16. **Controlled vs uncontrolled**: `Switch`/`Input`/`Checkbox` support both. If you pass `checked`/`value`, you must also pass `onChange`.
|
|
651
|
+
17. **Design tokens are exposed as `--animal-*` CSS custom properties by `animal-island-ui-tailwind/style`.** Prefer overriding those tokens on a wrapper or `:root`; do not import internal source files.
|
|
652
|
+
18. **Never use `style={{ borderRadius: 0 }}` or force sharp corners on any interactive element** — it breaks the design language.
|
|
653
|
+
19. **Never override the 3D bottom shadow on Button/Input/Switch** — it is the core identity.
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## 4. Where to read more
|
|
658
|
+
|
|
659
|
+
Shipped inside the npm package (available under `node_modules/animal-island-ui-tailwind/`):
|
|
660
|
+
|
|
661
|
+
- `AI_USAGE.md` — this file (AI-optimized API reference for all 18 components)
|
|
662
|
+
- `README.md` — project overview & screenshots
|
|
663
|
+
- `DESIGN_PROMPT.md` — external design-tool prompt pack
|
|
664
|
+
- `skill/SKILL.md` — installable Skills specification for the visual language
|
|
665
|
+
- `dist/types/index.d.ts` — machine-readable TypeScript types for every exported component / prop / enum
|
|
666
|
+
|
|
667
|
+
Repo-only (NOT published to npm — read on GitHub):
|
|
668
|
+
|
|
669
|
+
- `.github/workflows/*` — CI and release automation
|
|
670
|
+
- `tests/*` and `stories/*` — Storybook, Playwright, and visual parity verification
|
|
671
|
+
- GitHub: https://github.com/lifeodyssey/animal-island-ui
|
|
672
|
+
- Upstream: https://github.com/guokaigdg/animal-island-ui
|
|
673
|
+
|
|
674
|
+
**When to use which:** API shape / legal prop values → this file. Pixel-exact CSS (sizes, shadows, animations) → `SKILL.md`. Feeding another design AI → `DESIGN_PROMPT.md`.
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
## 5. Minimal boilerplate (copy-paste-ready)
|
|
679
|
+
|
|
680
|
+
```tsx
|
|
681
|
+
// main.tsx
|
|
682
|
+
import React from 'react';
|
|
683
|
+
import ReactDOM from 'react-dom/client';
|
|
684
|
+
import 'animal-island-ui-tailwind/style';
|
|
685
|
+
import App from './App';
|
|
686
|
+
|
|
687
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
```tsx
|
|
691
|
+
// App.tsx
|
|
692
|
+
import { Cursor, Button, Card, Input, Footer } from 'animal-island-ui-tailwind';
|
|
693
|
+
|
|
694
|
+
export default function App() {
|
|
695
|
+
return (
|
|
696
|
+
<Cursor>
|
|
697
|
+
<main style={{ padding: 32, maxWidth: 720, margin: '0 auto' }}>
|
|
698
|
+
<Card type="title">Animal Island</Card>
|
|
699
|
+
<Card>
|
|
700
|
+
<Input placeholder="What's on your mind?" allowClear />
|
|
701
|
+
<Button type="primary" block style={{ marginTop: 16 }}>Post</Button>
|
|
702
|
+
</Card>
|
|
703
|
+
</main>
|
|
704
|
+
<Footer type="sea" />
|
|
705
|
+
</Cursor>
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
```
|