@shapesos/clay 0.3.0 → 0.4.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/README.md CHANGED
@@ -1,45 +1,72 @@
1
- # @shapes/clay
1
+ <div align="center">
2
2
 
3
- Shapes.co design system — tokens, theming, and composable React components.
3
+ # Clay
4
4
 
5
- ## Install
5
+ **Tokens, theming, and composable React components.**
6
+
7
+ [![npm](https://img.shields.io/npm/v/@shapesos/clay?style=flat-square&color=C4A882&label=npm)](https://www.npmjs.com/package/@shapesos/clay)
8
+ [![license](https://img.shields.io/npm/l/@shapesos/clay?style=flat-square&color=C4A882)](LICENSE)
9
+ [![bundle](https://img.shields.io/bundlephobia/minzip/@shapesos/clay?style=flat-square&color=C4A882&label=gzip)](https://bundlephobia.com/package/@shapesos/clay)
10
+
11
+ </div>
12
+
13
+ ---
14
+
15
+ ## Quick Start
6
16
 
7
17
  ```bash
8
- bun add @shapes/clay
18
+ npm install @shapesos/clay
19
+ ```
20
+
21
+ ```tsx
22
+ import { colors, typographyTypes } from "@shapesos/clay/tokens";
23
+ import { Chat } from "@shapesos/clay/chat";
24
+ import { Lottie } from "@shapesos/clay/lottie";
9
25
  ```
10
26
 
11
27
  ## Entry Points
12
28
 
13
- | Import path | What you get | Peer dependencies |
14
- | --------------------- | ------------------------------------------ | -------------------------- |
15
- | `@shapes/clay/tokens` | Colors, typography, font families | **None** (pure JS) |
16
- | `@shapes/clay/chat` | Chat compound components + types | React, styled-components |
17
- | `@shapes/clay/icon` | Icon, IconButton components + types | React, styled-components |
18
- | `@shapes/clay` | Everything (convenience re-export) | React, styled-components |
29
+ Clay is tree-shakeable with multiple entry points — import only what you need.
30
+
31
+ | Import | Contents | Peer Dependencies |
32
+ | ------------------------- | ------------------------------------- | ------------------------ |
33
+ | `@shapesos/clay/tokens` | Colors, typography, font families | None (pure JS) |
34
+ | `@shapesos/clay/chat` | Chat compound components + types | React, styled-components |
35
+ | `@shapesos/clay/icon` | Icon, IconButton components + types | React, styled-components |
36
+ | `@shapesos/clay/lottie` | Lottie animation component + types | React, styled-components |
37
+ | `@shapesos/clay` | Everything (convenience re-export) | React, styled-components |
38
+
39
+ ---
19
40
 
20
- ## Usage
41
+ ## Design Tokens
21
42
 
22
- ### Design Tokens
43
+ Pure JavaScript color and typography tokens — no React required.
23
44
 
24
45
  ```typescript
25
- import { colors, typographyStyles, typographyTypes, typographyMixin } from "@shapes/clay/tokens";
46
+ import { colors, typographyStyles, typographyTypes, typographyMixin } from "@shapesos/clay/tokens";
26
47
 
27
- colors["brown-100"]; // "#171716"
48
+ // Color palette
49
+ colors["brown-100"]; // "#171716"
50
+ colors["brown-900"]; // "#F7F5F3"
28
51
 
52
+ // Typography definitions
29
53
  typographyStyles[typographyTypes.GEIST_BODY_S_REGULAR];
30
- // { fontFamily: "Geist", fontSize: 16, fontWeight: 400, lineHeight: 24, letterSpacing: -0.08 }
54
+ // => { fontFamily: "Geist", fontSize: 16, fontWeight: 400, lineHeight: 24, letterSpacing: -0.08 }
31
55
 
56
+ // CSS mixin for styled-components
32
57
  typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM);
33
- // CSS string for use in styled-components
58
+ // => CSS string ready to use in template literals
34
59
  ```
35
60
 
36
- ### Chat Components
61
+ ---
37
62
 
38
- Composable compound components assembled via a namespace:
63
+ ## Chat
64
+
65
+ Composable compound components for building chat interfaces. `Chat.Root` provides context — children consume it, giving you full control over layout.
39
66
 
40
67
  ```tsx
41
- import { Chat } from "@shapes/clay/chat";
42
- import type { ChatMessage } from "@shapes/clay/chat";
68
+ import { Chat } from "@shapesos/clay/chat";
69
+ import type { ChatMessage } from "@shapesos/clay/chat";
43
70
 
44
71
  function MyChat() {
45
72
  const [messages, setMessages] = useState<ChatMessage[]>([]);
@@ -62,29 +89,30 @@ function MyChat() {
62
89
  }
63
90
  ```
64
91
 
65
- `Chat.Root` provides context; children consume it. This lets consumers add custom elements between the message list and composer, or wrap parts in their own layout.
92
+ <details>
93
+ <summary><strong>Props Reference</strong></summary>
66
94
 
67
- #### Props
95
+ #### Chat.Root
68
96
 
69
- **Chat.Root**
97
+ | Prop | Type | Required | Description |
98
+ | ------------------ | ---------------------------------------------------------- | -------- | ---------------------------------- |
99
+ | `messages` | `ChatMessage[]` | Yes | Array of messages to display |
100
+ | `onSendMessage` | `(content: string) => void` | Yes | Called when the user sends |
101
+ | `isLoading` | `boolean` | No | Show stop button while loading |
102
+ | `onStop` | `() => void` | No | Called when the user clicks stop |
103
+ | `onCopyMessage` | `(messageId: string) => void` | No | Called when a message is copied |
104
+ | `onThumbUpClick` | `(messageId: string, isHelpful: boolean \| null) => void` | No | Thumbs up feedback |
105
+ | `onThumbDownClick` | `(messageId: string, isHelpful: boolean \| null) => void` | No | Thumbs down feedback |
70
106
 
71
- | Prop | Type | Required | Description |
72
- | ------------------ | ---------------------------------------------------------- | -------- | ----------------------------------------------- |
73
- | `messages` | `ChatMessage[]` | Yes | Array of messages to display |
74
- | `onSendMessage` | `(content: string) => void` | Yes | Called when the user sends a message |
75
- | `isLoading` | `boolean` | No | Show stop button while loading |
76
- | `onStop` | `() => void` | No | Called when the user clicks stop |
77
- | `onCopyMessage` | `(messageId: string) => void` | No | Called when a message is copied |
78
- | `onThumbUpClick` | `(messageId: string, isHelpful: boolean \| null) => void` | No | Called when thumbs up is clicked |
79
- | `onThumbDownClick` | `(messageId: string, isHelpful: boolean \| null) => void` | No | Called when thumbs down is clicked |
107
+ #### Chat.Composer
80
108
 
81
- **Chat.Composer**
109
+ | Prop | Type | Required | Default | Description |
110
+ | ------------- | -------- | -------- | ---------------------- | ----------------- |
111
+ | `placeholder` | `string` | No | `"Type a message..."` | Input placeholder |
82
112
 
83
- | Prop | Type | Required | Default | Description |
84
- | ------------- | -------- | -------- | -------------------- | ------------------ |
85
- | `placeholder` | `string` | No | `"Type a message..."` | Input placeholder |
113
+ #### Chat.MessageList
86
114
 
87
- **Chat.MessageList**no props, reads messages from context.
115
+ No props — reads messages from context.
88
116
 
89
117
  #### Data Model
90
118
 
@@ -94,15 +122,21 @@ type MessageRole = "user" | "assistant";
94
122
  interface ChatMessage {
95
123
  id: string;
96
124
  role: MessageRole;
97
- content: string; // Markdown
125
+ content: string; // Markdown supported
98
126
  isHelpful?: boolean | null;
99
127
  }
100
128
  ```
101
129
 
102
- ### Icon Components
130
+ </details>
131
+
132
+ ---
133
+
134
+ ## Icon
135
+
136
+ Render SVG icons with consistent sizing, and icon buttons with selection states.
103
137
 
104
138
  ```tsx
105
- import { Icon, IconButton } from "@shapes/clay/icon";
139
+ import { Icon, IconButton } from "@shapesos/clay/icon";
106
140
  import { IconSearch, IconCopy } from "@tabler/icons-react";
107
141
 
108
142
  <Icon icon={IconSearch} size={20} color="#333" aria-label="Search" />
@@ -110,38 +144,121 @@ import { IconSearch, IconCopy } from "@tabler/icons-react";
110
144
  <IconButton icon={IconCopy} size="small" onClick={handleCopy} aria-label="Copy" />
111
145
  ```
112
146
 
113
- #### Props
147
+ <details>
148
+ <summary><strong>Props Reference</strong></summary>
114
149
 
115
- **Icon**
150
+ #### Icon
116
151
 
117
- | Prop | Type | Required | Default | Description |
118
- | ------------ | ---------------------------------------- | -------- | ------- | ----------------------- |
152
+ | Prop | Type | Required | Default | Description |
153
+ | ------------ | ---------------------------------------- | -------- | ------- | ------------------------ |
119
154
  | `icon` | `ComponentType<SVGProps<SVGSVGElement>>` | Yes | | Icon component to render |
120
- | `size` | `number` | No | `16` | Icon size in pixels |
155
+ | `size` | `number` | No | `16` | Size in pixels |
121
156
  | `color` | `string` | No | | Icon color |
122
157
  | `className` | `string` | No | | CSS class |
123
158
  | `aria-label` | `string` | No | | Accessible label |
124
159
 
125
- **IconButton**
160
+ #### IconButton
161
+
162
+ | Prop | Type | Required | Default | Description |
163
+ | ------------ | ---------------------------------------- | -------- | --------- | ------------------------ |
164
+ | `icon` | `ComponentType<SVGProps<SVGSVGElement>>` | Yes | | Icon component to render |
165
+ | `size` | `"small" \| "medium"` | No | `"small"` | Button size |
166
+ | `isSelected` | `boolean` | No | `false` | Selected state |
167
+ | `disabled` | `boolean` | No | `false` | Disabled state |
168
+ | `onClick` | `() => void` | No | | Click handler |
169
+ | `className` | `string` | No | | CSS class |
170
+ | `aria-label` | `string` | No | | Accessible label |
171
+
172
+ </details>
173
+
174
+ ---
175
+
176
+ ## Lottie
126
177
 
127
- | Prop | Type | Required | Default | Description |
128
- | ------------ | ---------------------------------------- | -------- | --------- | -------------------------- |
129
- | `icon` | `ComponentType<SVGProps<SVGSVGElement>>` | Yes | | Icon component to render |
130
- | `size` | `"small" \| "medium"` | No | `"small"` | Button size |
131
- | `isSelected` | `boolean` | No | `false` | Selected/active state |
132
- | `disabled` | `boolean` | No | `false` | Disabled state |
133
- | `onClick` | `() => void` | No | | Click handler |
134
- | `className` | `string` | No | | CSS class |
135
- | `aria-label` | `string` | No | | Accessible label |
178
+ Render [Lottie](https://airbnb.io/lottie/) animations with declarative props, hover interactions, and imperative playback control.
136
179
 
137
- ### Types
180
+ ```tsx
181
+ import { Lottie } from "@shapesos/clay/lottie";
182
+ import animationData from "./my-animation.json";
183
+
184
+ // Basic — loops forever
185
+ <Lottie animationData={animationData} />
186
+
187
+ // Interactive — plays once, then replays on hover
188
+ <Lottie
189
+ animationData={animationData}
190
+ loop={false}
191
+ playOnHover
192
+ loopOnHover
193
+ width={80}
194
+ height={80}
195
+ />
196
+ ```
197
+
198
+ **Imperative control** via ref:
199
+
200
+ ```tsx
201
+ import type { LottieRef } from "@shapesos/clay/lottie";
202
+
203
+ const ref = useRef<LottieRef>(null);
204
+
205
+ <Lottie ref={ref} animationData={animationData} autoplay={false} />
206
+ <button onClick={() => ref.current?.play()}>Play</button>
207
+ ```
208
+
209
+ <details>
210
+ <summary><strong>Props Reference</strong></summary>
211
+
212
+ #### Lottie
213
+
214
+ | Prop | Type | Required | Default | Description |
215
+ | ------------------- | ---------------------------------------------------------------- | -------- | ------- | ------------------------------ |
216
+ | `animationData` | `LottieAnimationData` | Yes | | Lottie JSON data |
217
+ | `autoplay` | `boolean` | No | `true` | Play on mount |
218
+ | `loop` | `boolean \| number` | No | `true` | Loop forever, or N times |
219
+ | `speed` | `number` | No | `1` | Playback speed |
220
+ | `direction` | `1 \| -1` | No | `1` | Forward or reverse |
221
+ | `width` | `string \| number` | No | | Container width |
222
+ | `height` | `string \| number` | No | | Container height |
223
+ | `playOnHover` | `boolean` | No | `false` | Replay on mouse enter |
224
+ | `loopOnHover` | `boolean` | No | `false` | Loop while hovering |
225
+ | `className` | `string` | No | | CSS class |
226
+ | `aria-label` | `string` | No | | Accessible label |
227
+ | `onAnimationLoaded` | `(animation: AnimationItem) => void` | No | | Fired when animation loads |
228
+ | `onComplete` | `() => void` | No | | Fired on completion |
229
+ | `onLoopComplete` | `() => void` | No | | Fired on each loop |
230
+ | `onEnterFrame` | `(frame: { currentTime: number; totalTime: number }) => void` | No | | Fired on each frame |
231
+
232
+ #### LottieRef (imperative handle)
233
+
234
+ | Method | Description |
235
+ | ---------------------------------- | ---------------------------------- |
236
+ | `play()` | Start playback |
237
+ | `pause()` | Pause playback |
238
+ | `stop()` | Stop and reset to frame 0 |
239
+ | `goToAndPlay(value, isFrame?)` | Jump to value and play |
240
+ | `goToAndStop(value, isFrame?)` | Jump to value and stop |
241
+ | `setDirection(direction)` | Set direction (1 or -1) |
242
+ | `setSpeed(speed)` | Set playback speed |
243
+ | `getAnimationItem()` | Access underlying lottie-web instance |
244
+
245
+ </details>
246
+
247
+ ---
248
+
249
+ ## TypeScript
250
+
251
+ All components export their prop types:
138
252
 
139
253
  ```typescript
140
- import type { ColorToken, TypographyStyle, TypographyType } from "@shapes/clay/tokens";
141
- import type { ChatMessage, MessageRole, ChatContextValue } from "@shapes/clay/chat";
142
- import type { IconProps, IconButtonProps, IconButtonSize } from "@shapes/clay/icon";
254
+ import type { ColorToken, TypographyStyle, TypographyType } from "@shapesos/clay/tokens";
255
+ import type { ChatMessage, MessageRole, ChatContextValue } from "@shapesos/clay/chat";
256
+ import type { IconProps, IconButtonProps, IconButtonSize } from "@shapesos/clay/icon";
257
+ import type { LottieProps, LottieRef, LottieAnimationData } from "@shapesos/clay/lottie";
143
258
  ```
144
259
 
260
+ ---
261
+
145
262
  ## Development
146
263
 
147
264
  ```bash
@@ -150,20 +267,28 @@ cd shapes-clay
150
267
  bun install
151
268
  ```
152
269
 
153
- | Command | Description |
154
- | ------------------------ | ------------------------------------------ |
155
- | `bun run storybook` | Component playground (http://localhost:6006)|
156
- | `bun run build` | Build package (tsup) |
157
- | `bun run dev` | Build in watch mode |
158
- | `bun run test` | Run unit tests (Vitest) |
159
- | `bun run test:coverage` | Unit tests with coverage report |
160
- | `bun run test:e2e` | Run E2E tests (Playwright + Storybook) |
161
- | `bun run lint` | Lint with ESLint |
162
- | `bun run format` | Format with Prettier |
163
- | `bun run typecheck` | TypeScript strict type checking |
164
- | `bun run check` | All quality gates (lint + typecheck + test) |
165
-
166
- See [AGENTS.md](AGENTS.md) for full project structure, architecture, and conventions.
270
+ | Command | Description |
271
+ | ----------------------- | ------------------------------------------- |
272
+ | `bun run storybook` | Component playground (localhost:6006) |
273
+ | `bun run build` | Build package (tsup) |
274
+ | `bun run dev` | Build in watch mode |
275
+ | `bun run test` | Unit tests (Vitest) |
276
+ | `bun run test:coverage` | Unit tests with coverage |
277
+ | `bun run test:e2e` | E2E tests (Playwright + Storybook) |
278
+ | `bun run check` | All quality gates (lint + typecheck + test) |
279
+
280
+ ### Releasing
281
+
282
+ Clay uses [changesets](https://github.com/changesets/changesets) for versioning. When making changes:
283
+
284
+ ```bash
285
+ bunx changeset # Describe your change and its semver impact
286
+ git add .changeset/ # Commit the changeset with your PR
287
+ ```
288
+
289
+ On merge to `master`, a "Version Packages" PR is created automatically. Merging that PR publishes to npm.
290
+
291
+ ---
167
292
 
168
293
  ## License
169
294
 
package/dist/index.cjs CHANGED
@@ -16345,6 +16345,7 @@ __export(src_exports, {
16345
16345
  Chat: () => Chat,
16346
16346
  Icon: () => Icon,
16347
16347
  IconButton: () => IconButton,
16348
+ KeyboardShortcut: () => KeyboardShortcut,
16348
16349
  Lottie: () => Lottie,
16349
16350
  colors: () => colors,
16350
16351
  fontFamilies: () => fontFamilies,
@@ -17411,12 +17412,34 @@ var Chat = {
17411
17412
  Composer: ChatComposer
17412
17413
  };
17413
17414
 
17415
+ // src/keyboard-shortcut/keyboard-shortcut-styles.ts
17416
+ var import_styled_components9 = __toESM(require("styled-components"), 1);
17417
+ var Wrapper = import_styled_components9.default.div`
17418
+ display: inline-flex;
17419
+ align-items: center;
17420
+ gap: 4px;
17421
+ `;
17422
+ var Key = import_styled_components9.default.kbd`
17423
+ padding: 1px 4px;
17424
+ border-radius: 4px;
17425
+ border: 1px solid ${colors["brown-70"]};
17426
+ border-bottom-width: 2px;
17427
+ ${typographyMixin(typographyTypes.GEIST_LABEL_CAPTION_MEDIUM)};
17428
+ color: inherit;
17429
+ `;
17430
+
17431
+ // src/keyboard-shortcut/keyboard-shortcut.tsx
17432
+ var import_jsx_runtime9 = require("react/jsx-runtime");
17433
+ function KeyboardShortcut({ keys, className }) {
17434
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Wrapper, { className, children: keys.map((key2) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Key, { children: key2 }, key2)) });
17435
+ }
17436
+
17414
17437
  // src/lottie/lottie.tsx
17415
17438
  var import_react11 = require("react");
17416
17439
 
17417
17440
  // src/lottie/lottie-styles.ts
17418
- var import_styled_components9 = __toESM(require("styled-components"), 1);
17419
- var LottieContainer = import_styled_components9.default.div`
17441
+ var import_styled_components10 = __toESM(require("styled-components"), 1);
17442
+ var LottieContainer = import_styled_components10.default.div`
17420
17443
  display: inline-flex;
17421
17444
  width: ${({ $width }) => typeof $width === "number" ? `${$width}px` : $width};
17422
17445
  height: ${({ $height }) => typeof $height === "number" ? `${$height}px` : $height};
@@ -17545,7 +17568,7 @@ function createLottieRef(animationRef) {
17545
17568
  }
17546
17569
 
17547
17570
  // src/lottie/lottie.tsx
17548
- var import_jsx_runtime9 = require("react/jsx-runtime");
17571
+ var import_jsx_runtime10 = require("react/jsx-runtime");
17549
17572
  var Lottie = (0, import_react11.forwardRef)(function Lottie2({
17550
17573
  animationData: animationData2,
17551
17574
  autoplay,
@@ -17577,7 +17600,7 @@ var Lottie = (0, import_react11.forwardRef)(function Lottie2({
17577
17600
  onEnterFrame
17578
17601
  });
17579
17602
  (0, import_react11.useImperativeHandle)(ref, () => createLottieRef(animationRef), [animationRef]);
17580
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
17603
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
17581
17604
  LottieContainer,
17582
17605
  {
17583
17606
  ref: containerRef,
@@ -17594,6 +17617,7 @@ var Lottie = (0, import_react11.forwardRef)(function Lottie2({
17594
17617
  Chat,
17595
17618
  Icon,
17596
17619
  IconButton,
17620
+ KeyboardShortcut,
17597
17621
  Lottie,
17598
17622
  colors,
17599
17623
  fontFamilies,