@codelitdev/design-system 0.1.0-alpha.6 → 0.2.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
@@ -16,17 +16,17 @@ under the `alpha` dist-tag.
16
16
  > `latest` on a package's first-ever publish, regardless of `--tag` — this is
17
17
  > unavoidable until a real stable version is cut, at which point publishing it
18
18
  > moves `latest` forward automatically. Until then, **always pin the exact
19
- > version** — do not `npm install @codelitdev/design-system` bare, and do not
19
+ > version** — do not `bun add @codelitdev/design-system` bare, and do not
20
20
  > use a caret/tilde range (`^0.1.0-alpha.0` would still resolve to a
21
21
  > prerelease, which is at least explicit — but a bare install with no version
22
22
  > silently means "whatever `latest` is," which right now is this alpha).
23
23
 
24
24
  ```sh
25
- npm install @codelitdev/design-system@0.1.0-alpha.0
25
+ bun add @codelitdev/design-system@0.1.0-alpha.6
26
26
  ```
27
27
 
28
- Inside a workspace/monorepo you can still consume it as `workspace:*` when the
29
- package is vendored locally.
28
+ Platform examples consume the package as `workspace:*`. Product repositories
29
+ consume an exact published version.
30
30
 
31
31
  ## Use in a shadcn app
32
32
 
@@ -85,7 +85,7 @@ Add the registry namespace to your app's `components.json`:
85
85
  ```jsonc
86
86
  {
87
87
  "registries": {
88
- "@codelit": "https://raw.githubusercontent.com/codelitdev/design-system/main/public/r/{name}.json"
88
+ "@codelit": "https://raw.githubusercontent.com/codelitdev/platform/main/packages/design-system/public/r/{name}.json"
89
89
  }
90
90
  }
91
91
  ```
@@ -93,13 +93,13 @@ Add the registry namespace to your app's `components.json`:
93
93
  Then install components like any other shadcn component:
94
94
 
95
95
  ```sh
96
- npx shadcn@latest add @codelit/button @codelit/badge @codelit/card
96
+ bunx shadcn@latest add @codelit/button @codelit/badge @codelit/card
97
97
  ```
98
98
 
99
99
  Or install a single component directly by URL, no config:
100
100
 
101
101
  ```sh
102
- npx shadcn@latest add https://raw.githubusercontent.com/codelitdev/design-system/main/public/r/button.json
102
+ bunx shadcn@latest add https://raw.githubusercontent.com/codelitdev/platform/main/packages/design-system/public/r/button.json
103
103
  ```
104
104
 
105
105
  ### Available components
@@ -126,28 +126,28 @@ npx shadcn@latest add https://raw.githubusercontent.com/codelitdev/design-system
126
126
  Install everything at once:
127
127
 
128
128
  ```sh
129
- npx shadcn@latest add @codelit/button @codelit/icon-button @codelit/badge @codelit/card \
129
+ bunx shadcn@latest add @codelit/button @codelit/icon-button @codelit/badge @codelit/card \
130
130
  @codelit/input @codelit/textarea @codelit/label @codelit/checkbox @codelit/radio-group \
131
131
  @codelit/switch @codelit/select @codelit/tabs @codelit/dialog @codelit/dropdown-menu \
132
132
  @codelit/tooltip @codelit/toast
133
133
  ```
134
134
 
135
135
  **Maintainers:** component sources live in `registry/codelit/ui/`. After changing
136
- one, rebuild the served JSON with `pnpm registry:build` (→ `public/r/*.json`) and
136
+ one, rebuild the served JSON with `bun run registry:build` (→ `public/r/*.json`) and
137
137
  commit it — the raw-URL install serves those committed files.
138
138
 
139
139
  ## Publishing
140
140
 
141
- Prereleases go under the `alpha` dist-tag so a plain `npm install` never grabs
142
- one. **Always publish with an explicit tag** — `publishConfig.tag` is not
143
- honored by npm 11.x, so a bare `npm publish` would land on `latest`:
141
+ Prereleases go under the `alpha` dist-tag so a plain `bun add` never grabs
142
+ one. Releases are driven from the Platform root through Changesets; do not run
143
+ `bun publish` from this package directory:
144
144
 
145
145
  ```sh
146
- npm run release:alpha # → npm publish --tag alpha
147
- # add --otp=<code> if 2FA is enabled
146
+ bun run changeset
147
+ bun run release:alpha
148
148
  ```
149
149
 
150
- Verify: `npm view @codelitdev/design-system dist-tags` should show the
150
+ Verify: `bun info @codelitdev/design-system --json` should show the
151
151
  prerelease under `alpha` and leave `latest` untouched.
152
152
 
153
153
  ## License
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "@codelitdev/design-system",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.2.0",
4
4
  "description": "Shared CodeLit design tokens, Tailwind preset, and React primitives for CourseLit, MediaLit, SendLit, and FrontLit.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "CodeLit",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/codelitdev/design-system.git"
9
+ "url": "git+https://github.com/codelitdev/platform.git",
10
+ "directory": "packages/design-system"
10
11
  },
11
- "homepage": "https://github.com/codelitdev/design-system#readme",
12
+ "homepage": "https://github.com/codelitdev/platform/tree/main/packages/design-system#readme",
12
13
  "bugs": {
13
- "url": "https://github.com/codelitdev/design-system/issues"
14
+ "url": "https://github.com/codelitdev/platform/issues"
14
15
  },
15
16
  "main": "src/index.ts",
16
17
  "types": "src/index.ts",
17
18
  "scripts": {
18
19
  "check": "tsc --noEmit && esbuild src/index.ts --bundle --platform=browser --format=esm --jsx=automatic --external:react --external:react-dom --outfile=/tmp/design-system-check.js",
19
- "release:alpha": "npm run check && npm publish --tag alpha",
20
20
  "registry:build": "shadcn build"
21
21
  },
22
22
  "exports": {
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "publishConfig": {
33
33
  "access": "public",
34
- "tag": "alpha"
34
+ "tag": "latest"
35
35
  },
36
36
  "files": [
37
37
  "src",
@@ -41,7 +41,7 @@
41
41
  ],
42
42
  "devDependencies": {
43
43
  "@types/react": "^19.2.17",
44
- "@types/react-dom": "^19.2.7",
44
+ "@types/react-dom": "^19.2.5",
45
45
  "esbuild": "^0.28.1",
46
46
  "lucide-react": "^0.544.0",
47
47
  "react": "^19.2.8",
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><g fill="none" stroke="oklch(0.62 0.16 60)" stroke-width="2.6"><path d="M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z" transform="translate(0,4.5)"></path><path d="M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z" transform="translate(0,4.5) rotate(120 32 32)"></path><path d="M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z" transform="translate(0,4.5) rotate(240 32 32)"></path></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><title>CodeLit logo</title><g fill="none" stroke="oklch(0.62 0.16 60)" stroke-width="2.6"><path d="M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z" transform="translate(0,4.5)"></path><path d="M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z" transform="translate(0,4.5) rotate(120 32 32)"></path><path d="M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z" transform="translate(0,4.5) rotate(240 32 32)"></path></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><g fill="oklch(0.62 0.16 30 / 0.18)" stroke="oklch(0.62 0.16 30)" stroke-width="2.6" stroke-linejoin="round"><path d="M32,10 L38,28 L32,34 L26,28 Z"></path><path d="M32,10 L38,28 L32,34 L26,28 Z" transform="rotate(90 32 32)"></path><path d="M32,10 L38,28 L32,34 L26,28 Z" transform="rotate(180 32 32)"></path><path d="M32,10 L38,28 L32,34 L26,28 Z" transform="rotate(270 32 32)"></path></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><title>CourseLit logo</title><g fill="oklch(0.62 0.16 30 / 0.18)" stroke="oklch(0.62 0.16 30)" stroke-width="2.6" stroke-linejoin="round"><path d="M32,10 L38,28 L32,34 L26,28 Z"></path><path d="M32,10 L38,28 L32,34 L26,28 Z" transform="rotate(90 32 32)"></path><path d="M32,10 L38,28 L32,34 L26,28 Z" transform="rotate(180 32 32)"></path><path d="M32,10 L38,28 L32,34 L26,28 Z" transform="rotate(270 32 32)"></path></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><g fill="oklch(0.62 0.16 230 / 0.15)" stroke="oklch(0.62 0.16 230)" stroke-width="2.4" stroke-linejoin="round"><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(41.19,22.81) rotate(45)"></path><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(41.19,41.19) rotate(135)"></path><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(22.81,41.19) rotate(225)"></path><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(22.81,22.81) rotate(315)"></path></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><title>FrontLit logo</title><g fill="oklch(0.62 0.16 230 / 0.15)" stroke="oklch(0.62 0.16 230)" stroke-width="2.4" stroke-linejoin="round"><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(41.19,22.81) rotate(45)"></path><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(41.19,41.19) rotate(135)"></path><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(22.81,41.19) rotate(225)"></path><path d="M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z" transform="translate(22.81,22.81) rotate(315)"></path></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><g fill="oklch(0.62 0.16 300 / 0.15)" stroke="oklch(0.62 0.16 300)" stroke-width="2.6" stroke-linejoin="round"><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z"></path><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z" transform="rotate(90 32 32)"></path><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z" transform="rotate(180 32 32)"></path><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z" transform="rotate(270 32 32)"></path></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><title>MediaLit logo</title><g fill="oklch(0.62 0.16 300 / 0.15)" stroke="oklch(0.62 0.16 300)" stroke-width="2.6" stroke-linejoin="round"><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z"></path><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z" transform="rotate(90 32 32)"></path><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z" transform="rotate(180 32 32)"></path><path d="M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z" transform="rotate(270 32 32)"></path></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><g fill="none" stroke="oklch(0.62 0.16 150)" stroke-width="2.6" stroke-linecap="round" transform="translate(-2,0)"><path d="M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5"></path><path d="M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5" transform="rotate(120 32 32)"></path><path d="M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5" transform="rotate(240 32 32)"></path></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><title>SendLit logo</title><g fill="none" stroke="oklch(0.62 0.16 150)" stroke-width="2.6" stroke-linecap="round" transform="translate(-2,0)"><path d="M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5"></path><path d="M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5" transform="rotate(120 32 32)"></path><path d="M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5" transform="rotate(240 32 32)"></path></g></svg>
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import type React from "react";
4
4
 
5
5
  export interface ButtonProps {
6
6
  /** Visual style. `soft` is the accent-wash variant unique to CodeLit. */
@@ -14,7 +14,15 @@ export interface ButtonProps {
14
14
  }
15
15
 
16
16
  /** Primary action affordance. Variants: primary, secondary, outline, ghost, soft, destructive. */
17
- export function Button({ variant = "primary", size = "md", disabled, children, style, onClick, type = "button" }: ButtonProps) {
17
+ export function Button({
18
+ variant = "primary",
19
+ size = "md",
20
+ disabled,
21
+ children,
22
+ style,
23
+ onClick,
24
+ type = "button",
25
+ }: ButtonProps) {
18
26
  return (
19
27
  <button
20
28
  type={type}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import type React from "react";
4
4
 
5
5
  export interface IconButtonProps {
6
6
  variant?: "ghost" | "outline";
@@ -14,7 +14,14 @@ export interface IconButtonProps {
14
14
  }
15
15
 
16
16
  /** Square icon-only button for toolbars, table rows, headers. */
17
- export function IconButton({ variant = "ghost", size = "md", label, children, style, onClick }: IconButtonProps) {
17
+ export function IconButton({
18
+ variant = "ghost",
19
+ size = "md",
20
+ label,
21
+ children,
22
+ style,
23
+ onClick,
24
+ }: IconButtonProps) {
18
25
  return (
19
26
  <button
20
27
  type="button"
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import type React from "react";
2
2
 
3
3
  export interface BadgeProps {
4
4
  variant?: "default" | "neutral" | "success" | "warning" | "destructive" | "outline";
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import type React from "react";
2
2
 
3
3
  export interface CardProps {
4
4
  title?: React.ReactNode;
@@ -14,7 +14,14 @@ export interface TabsProps {
14
14
  }
15
15
 
16
16
  /** Tab bar. Controlled via value/onChange or uncontrolled via defaultValue. */
17
- export function Tabs({ tabs = [], value, defaultValue, onChange, variant = "segmented", style }: TabsProps) {
17
+ export function Tabs({
18
+ tabs = [],
19
+ value,
20
+ defaultValue,
21
+ onChange,
22
+ variant = "segmented",
23
+ style,
24
+ }: TabsProps) {
18
25
  const [internal, setInternal] = React.useState(defaultValue ?? tabs[0]);
19
26
  const active = value ?? internal;
20
27
  const pick = (t: string) => {
@@ -22,9 +29,20 @@ export function Tabs({ tabs = [], value, defaultValue, onChange, variant = "segm
22
29
  if (onChange) onChange(t);
23
30
  };
24
31
  return (
25
- <div className={`cl-tabs__list ${variant === "underline" ? "cl-tabs__list--underline" : ""}`} role="tablist" style={style}>
32
+ <div
33
+ className={`cl-tabs__list ${variant === "underline" ? "cl-tabs__list--underline" : ""}`}
34
+ role="tablist"
35
+ style={style}
36
+ >
26
37
  {tabs.map((t) => (
27
- <button key={t} type="button" role="tab" className="cl-tabs__trigger" data-active={String(t === active)} onClick={() => pick(t)}>
38
+ <button
39
+ key={t}
40
+ type="button"
41
+ role="tab"
42
+ className="cl-tabs__trigger"
43
+ data-active={String(t === active)}
44
+ onClick={() => pick(t)}
45
+ >
28
46
  {t}
29
47
  </button>
30
48
  ))}
@@ -12,21 +12,38 @@ export interface DialogProps {
12
12
  style?: React.CSSProperties;
13
13
  children?: React.ReactNode;
14
14
  }
15
+
15
16
  import { Button } from "../actions/Button";
16
17
 
17
18
  /** Modal dialog with scrim. Controlled: open + onClose. */
18
- export function Dialog({ open, onClose, title, description, footer, children, style }: DialogProps) {
19
+ export function Dialog({
20
+ open,
21
+ onClose,
22
+ title,
23
+ description,
24
+ footer,
25
+ children,
26
+ style,
27
+ }: DialogProps) {
19
28
  if (!open) return null;
20
29
  return (
21
30
  <div className="cl-dialog__scrim" onClick={onClose}>
22
- <div className="cl-dialog" role="dialog" aria-modal="true" style={style} onClick={(e) => e.stopPropagation()}>
31
+ <div
32
+ className="cl-dialog"
33
+ role="dialog"
34
+ aria-modal="true"
35
+ style={style}
36
+ onClick={(e) => e.stopPropagation()}
37
+ >
23
38
  {title ? <h2 className="cl-dialog__title">{title}</h2> : null}
24
39
  {description ? <p className="cl-dialog__description">{description}</p> : null}
25
40
  {children}
26
41
  <div className="cl-dialog__footer">
27
42
  {footer ?? (
28
43
  <React.Fragment>
29
- <Button variant="outline" onClick={onClose}>Cancel</Button>
44
+ <Button variant="outline" onClick={onClose}>
45
+ Cancel
46
+ </Button>
30
47
  <Button onClick={onClose}>Confirm</Button>
31
48
  </React.Fragment>
32
49
  )}
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import type React from "react";
2
2
 
3
3
  export interface LoaderProps {
4
4
  /** Which product mark to draw. Omit for the CodeLit house mark (amber). */
@@ -10,9 +10,18 @@ export interface LoaderProps {
10
10
 
11
11
  const PATHS: Record<string, { d: string; transform?: string }[]> = {
12
12
  codelit: [
13
- { d: "M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z", transform: "translate(0,4.5)" },
14
- { d: "M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z", transform: "translate(0,4.5) rotate(120 32 32)" },
15
- { d: "M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z", transform: "translate(0,4.5) rotate(240 32 32)" },
13
+ {
14
+ d: "M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z",
15
+ transform: "translate(0,4.5)",
16
+ },
17
+ {
18
+ d: "M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z",
19
+ transform: "translate(0,4.5) rotate(120 32 32)",
20
+ },
21
+ {
22
+ d: "M32,23 C27.8,19 27,12.4 32,9 C37,12.4 36.2,19 32,23 Z",
23
+ transform: "translate(0,4.5) rotate(240 32 32)",
24
+ },
16
25
  ],
17
26
  courselit: [
18
27
  { d: "M32,10 L38,28 L32,34 L26,28 Z" },
@@ -22,20 +31,47 @@ const PATHS: Record<string, { d: string; transform?: string }[]> = {
22
31
  ],
23
32
  medialit: [
24
33
  { d: "M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z" },
25
- { d: "M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z", transform: "rotate(90 32 32)" },
26
- { d: "M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z", transform: "rotate(180 32 32)" },
27
- { d: "M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z", transform: "rotate(270 32 32)" },
34
+ {
35
+ d: "M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z",
36
+ transform: "rotate(90 32 32)",
37
+ },
38
+ {
39
+ d: "M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z",
40
+ transform: "rotate(180 32 32)",
41
+ },
42
+ {
43
+ d: "M32,24 C28.8,19 28.8,13.5 32,10 C35.2,13.5 35.2,19 32,24 Z",
44
+ transform: "rotate(270 32 32)",
45
+ },
28
46
  ],
29
47
  sendlit: [
30
48
  { d: "M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5" },
31
- { d: "M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5", transform: "rotate(120 32 32)" },
32
- { d: "M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5", transform: "rotate(240 32 32)" },
49
+ {
50
+ d: "M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5",
51
+ transform: "rotate(120 32 32)",
52
+ },
53
+ {
54
+ d: "M32,32 C23,29.5 18.5,20.5 23,12.5 C26.5,17 26.5,24 31,26.5",
55
+ transform: "rotate(240 32 32)",
56
+ },
33
57
  ],
34
58
  frontlit: [
35
- { d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z", transform: "translate(41.19,22.81) rotate(45)" },
36
- { d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z", transform: "translate(41.19,41.19) rotate(135)" },
37
- { d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z", transform: "translate(22.81,41.19) rotate(225)" },
38
- { d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z", transform: "translate(22.81,22.81) rotate(315)" },
59
+ {
60
+ d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z",
61
+ transform: "translate(41.19,22.81) rotate(45)",
62
+ },
63
+ {
64
+ d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z",
65
+ transform: "translate(41.19,41.19) rotate(135)",
66
+ },
67
+ {
68
+ d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z",
69
+ transform: "translate(22.81,41.19) rotate(225)",
70
+ },
71
+ {
72
+ d: "M0,-11 C5.5,-5.5 5.5,5.5 0,11 C-5.5,5.5 -5.5,-5.5 0,-11 Z",
73
+ transform: "translate(22.81,22.81) rotate(315)",
74
+ },
39
75
  ],
40
76
  };
41
77
 
@@ -72,8 +108,14 @@ export function Loader({ product = "codelit", size = 40, style }: LoaderProps) {
72
108
  strokeLinecap={joined ? undefined : "round"}
73
109
  transform={product === "sendlit" ? "translate(-2,0)" : undefined}
74
110
  >
75
- {paths.map((p, i) => (
76
- <path key={i} d={p.d} transform={p.transform} strokeDasharray={200} className="cl-loader__path" />
111
+ {paths.map((p) => (
112
+ <path
113
+ key={`${p.d}:${p.transform ?? ""}`}
114
+ d={p.d}
115
+ transform={p.transform}
116
+ strokeDasharray={200}
117
+ className="cl-loader__path"
118
+ />
77
119
  ))}
78
120
  </g>
79
121
  </svg>
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import type React from "react";
2
2
 
3
3
  export interface ToastProps {
4
4
  variant?: "default" | "success" | "destructive";
@@ -8,9 +8,56 @@ export interface ToastProps {
8
8
  }
9
9
 
10
10
  const icons = {
11
- default: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M12 16v-4"></path><path d="M12 8h.01"></path></svg>,
12
- success: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="m9 12 2 2 4-4"></path></svg>,
13
- destructive: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M12 8v4"></path><path d="M12 16h.01"></path></svg>,
11
+ default: (
12
+ <svg
13
+ aria-hidden="true"
14
+ width="16"
15
+ height="16"
16
+ viewBox="0 0 24 24"
17
+ fill="none"
18
+ stroke="currentColor"
19
+ strokeWidth="2"
20
+ strokeLinecap="round"
21
+ strokeLinejoin="round"
22
+ >
23
+ <circle cx="12" cy="12" r="10"></circle>
24
+ <path d="M12 16v-4"></path>
25
+ <path d="M12 8h.01"></path>
26
+ </svg>
27
+ ),
28
+ success: (
29
+ <svg
30
+ aria-hidden="true"
31
+ width="16"
32
+ height="16"
33
+ viewBox="0 0 24 24"
34
+ fill="none"
35
+ stroke="currentColor"
36
+ strokeWidth="2"
37
+ strokeLinecap="round"
38
+ strokeLinejoin="round"
39
+ >
40
+ <circle cx="12" cy="12" r="10"></circle>
41
+ <path d="m9 12 2 2 4-4"></path>
42
+ </svg>
43
+ ),
44
+ destructive: (
45
+ <svg
46
+ aria-hidden="true"
47
+ width="16"
48
+ height="16"
49
+ viewBox="0 0 24 24"
50
+ fill="none"
51
+ stroke="currentColor"
52
+ strokeWidth="2"
53
+ strokeLinecap="round"
54
+ strokeLinejoin="round"
55
+ >
56
+ <circle cx="12" cy="12" r="10"></circle>
57
+ <path d="M12 8v4"></path>
58
+ <path d="M12 16h.01"></path>
59
+ </svg>
60
+ ),
14
61
  };
15
62
 
16
63
  /** Notification card. Render inside a fixed bottom-right stack in real apps. */
@@ -22,7 +22,11 @@ export function Tooltip({ label, open, children, style }: TooltipProps) {
22
22
  onMouseLeave={() => setHover(false)}
23
23
  >
24
24
  {children}
25
- {show ? <span className="cl-tooltip" role="tooltip">{label}</span> : null}
25
+ {show ? (
26
+ <span className="cl-tooltip" role="tooltip">
27
+ {label}
28
+ </span>
29
+ ) : null}
26
30
  </span>
27
31
  );
28
32
  }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import type React from "react";
4
4
 
5
5
  export interface CheckboxProps {
6
6
  label?: React.ReactNode;
@@ -14,12 +14,38 @@ export interface CheckboxProps {
14
14
  }
15
15
 
16
16
  /** Checkbox with label and optional sub-description. */
17
- export function Checkbox({ label, description, checked, defaultChecked, disabled, onChange, style }: CheckboxProps) {
17
+ export function Checkbox({
18
+ label,
19
+ description,
20
+ checked,
21
+ defaultChecked,
22
+ disabled,
23
+ onChange,
24
+ style,
25
+ }: CheckboxProps) {
18
26
  return (
19
27
  <label className={`cl-check ${disabled ? "cl-check--disabled" : ""}`} style={style}>
20
- <input type="checkbox" checked={checked} defaultChecked={defaultChecked} disabled={disabled} onChange={onChange} />
28
+ <input
29
+ type="checkbox"
30
+ checked={checked}
31
+ defaultChecked={defaultChecked}
32
+ disabled={disabled}
33
+ onChange={onChange}
34
+ />
21
35
  <span className="cl-check__box">
22
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>
36
+ <svg
37
+ aria-hidden="true"
38
+ width="12"
39
+ height="12"
40
+ viewBox="0 0 24 24"
41
+ fill="none"
42
+ stroke="currentColor"
43
+ strokeWidth="3.5"
44
+ strokeLinecap="round"
45
+ strokeLinejoin="round"
46
+ >
47
+ <path d="M20 6 9 17l-5-5"></path>
48
+ </svg>
23
49
  </span>
24
50
  {label ? (
25
51
  <span className="cl-check__label">
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import type React from "react";
4
4
 
5
5
  export interface InputProps {
6
6
  label?: React.ReactNode;
@@ -29,6 +29,7 @@ export function Input({ label, hint, error, multiline, style, ...rest }: InputPr
29
29
  );
30
30
  if (!label && !hint && !error) return control;
31
31
  return (
32
+ /* biome-ignore lint/a11y/noLabelWithoutControl: the control is rendered inside this label. */
32
33
  <label className="cl-field" style={style}>
33
34
  {label ? <span className="cl-field__label">{label}</span> : null}
34
35
  {control}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import type React from "react";
4
4
 
5
5
  export interface RadioProps {
6
6
  label?: React.ReactNode;
@@ -15,10 +15,28 @@ export interface RadioProps {
15
15
  }
16
16
 
17
17
  /** Radio button; group by sharing `name`. */
18
- export function Radio({ label, description, name, value, checked, defaultChecked, disabled, onChange, style }: RadioProps) {
18
+ export function Radio({
19
+ label,
20
+ description,
21
+ name,
22
+ value,
23
+ checked,
24
+ defaultChecked,
25
+ disabled,
26
+ onChange,
27
+ style,
28
+ }: RadioProps) {
19
29
  return (
20
30
  <label className={`cl-check ${disabled ? "cl-check--disabled" : ""}`} style={style}>
21
- <input type="radio" name={name} value={value} checked={checked} defaultChecked={defaultChecked} disabled={disabled} onChange={onChange} />
31
+ <input
32
+ type="radio"
33
+ name={name}
34
+ value={value}
35
+ checked={checked}
36
+ defaultChecked={defaultChecked}
37
+ disabled={disabled}
38
+ onChange={onChange}
39
+ />
22
40
  <span className="cl-check__box cl-check__box--radio">
23
41
  <span className="cl-check__radio-dot"></span>
24
42
  </span>
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import type React from "react";
4
4
 
5
5
  export interface SelectProps {
6
6
  label?: React.ReactNode;
@@ -21,19 +21,36 @@ export function Select({ label, hint, options = [], style, ...rest }: SelectProp
21
21
  <select {...rest}>
22
22
  {options.map((o) =>
23
23
  typeof o === "string" ? (
24
- <option key={o} value={o}>{o}</option>
24
+ <option key={o} value={o}>
25
+ {o}
26
+ </option>
25
27
  ) : (
26
- <option key={o.value} value={o.value}>{o.label}</option>
27
- )
28
+ <option key={o.value} value={o.value}>
29
+ {o.label}
30
+ </option>
31
+ ),
28
32
  )}
29
33
  </select>
30
34
  <span className="cl-select__chevron">
31
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6"></path></svg>
35
+ <svg
36
+ aria-hidden="true"
37
+ width="14"
38
+ height="14"
39
+ viewBox="0 0 24 24"
40
+ fill="none"
41
+ stroke="currentColor"
42
+ strokeWidth="2"
43
+ strokeLinecap="round"
44
+ strokeLinejoin="round"
45
+ >
46
+ <path d="m6 9 6 6 6-6"></path>
47
+ </svg>
32
48
  </span>
33
49
  </span>
34
50
  );
35
51
  if (!label && !hint) return <span style={style}>{control}</span>;
36
52
  return (
53
+ /* biome-ignore lint/a11y/noLabelWithoutControl: the select control is rendered inside this label. */
37
54
  <label className="cl-field" style={style}>
38
55
  {label ? <span className="cl-field__label">{label}</span> : null}
39
56
  {control}