@ekkolyth/ui 0.1.18 → 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 +77 -188
- package/dist/base.css +6 -0
- package/dist/blocks.d.ts +2 -2
- package/dist/blocks.js +3 -3
- package/dist/convex.js +1 -1
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +3 -2
- package/dist/{icon-picker-ByfHyJ7i.js → icon-picker-CwavOWKf.js} +1075 -186
- package/dist/{index-DHF8OR1R.d.ts → index-BJs5qfKG.d.ts} +65 -1
- package/dist/index-CxGQ12zb.d.ts +17 -0
- package/dist/index.d.ts +130 -75
- package/dist/index.js +525 -537
- package/dist/layout.d.ts +2 -2
- package/dist/layout.js +2 -2
- package/dist/shiki-code-CLD9RZfj.js +46 -0
- package/dist/text.d.ts +8 -1
- package/dist/text.js +49 -12
- package/dist/themes/provider.d.ts +2 -1
- package/dist/themes/provider.js +4 -4
- package/dist/{toggle-B2PFPImC.js → toggle-Bpm-ggNe.js} +2 -1
- package/dist/{use-mobile-CqHXB_Nc.js → use-mobile-C-Ak14Ip.js} +5 -5
- package/dist/use-window-scroll-margin-BQMpLEeT.js +22 -0
- package/dist/use-window-scroll-margin-BeVjX6Le.d.ts +11 -0
- package/dist/virtual-grid-BNWXDxO1.js +72 -0
- package/package.json +3 -1
- package/dist/container-BBg21poC.js +0 -10
- package/dist/index-Bwp0YMmG.d.ts +0 -5
- package/dist/shiki-code-Bg__Vnt1.js +0 -29
- package/dist/use-mobile-BVGje-2e.d.ts +0 -4
- package/dist/{loading-screen-DB3youyT.js → loading-screen-DilmTJ3J.js} +1 -1
package/README.md
CHANGED
|
@@ -1,232 +1,121 @@
|
|
|
1
1
|
# @ekkolyth/ui
|
|
2
2
|
|
|
3
|
-
Shared UI component library
|
|
3
|
+
Shared UI component library.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Peer Dependencies
|
|
12
|
-
|
|
13
|
-
- `react` ^19.2.0
|
|
14
|
-
- `react-dom` ^19.2.0
|
|
15
|
-
|
|
16
|
-
`next` is only reachable through the `/widget` compatibility entry
|
|
17
|
-
(`Widget`). It ships as an ordinary workspace dependency here; the
|
|
18
|
-
published package declares it as an **optional** peer so an app that never
|
|
19
|
-
imports `/widget` never installs it.
|
|
20
|
-
|
|
21
|
-
## Exports
|
|
22
|
-
|
|
23
|
-
| Subpath | What it is |
|
|
24
|
-
|---|---|
|
|
25
|
-
| `.` | All UI components, hooks, and utilities. Theme runtime is not here — see `/themes/provider`. |
|
|
26
|
-
| `./text` | `RichText` — renders Tiptap `JSONContent` through a node registry. |
|
|
27
|
-
| `./layout` | `Container`. |
|
|
28
|
-
| `./blocks` | `ColorPicker`, `Field`, `IconPicker`, `LoadingScreen`, `Widget`. |
|
|
29
|
-
| `./hooks` | `useIsMobile`. |
|
|
30
|
-
| `./themes/provider` | The framework-neutral theme runtime — see below. |
|
|
31
|
-
| `./themes` | Stylesheet: all seven palettes, `@import`ed. |
|
|
32
|
-
| `./themes/catpuccin/latte`, `./themes/catpuccin/frappe`, `./themes/catpuccin/macchiato`, `./themes/catpuccin/mocha`, `./themes/tokyo-night`, `./themes/ekko-os`, `./themes/ekkolyth` | Individual palette stylesheets — seven subpaths, one per palette. |
|
|
33
|
-
| `./base.css` | The base theme layer — see "Base CSS" below. |
|
|
34
|
-
|
|
35
|
-
`./widget` and `./convex` are **compatibility entries, not documented API.**
|
|
36
|
-
They exist because specific `apps/web` call sites import from them and sit
|
|
37
|
-
outside this package's edit surface; don't build new code against them.
|
|
38
|
-
|
|
39
|
-
**Components:**
|
|
40
|
-
Built on top of shadcn@latest.
|
|
41
|
-
|
|
42
|
-
```tsx
|
|
43
|
-
import { Button, Card, Dialog, useIsMobile, cn } from '@ekkolyth/ui'
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Theme Provider
|
|
47
|
-
|
|
48
|
-
One framework-neutral provider, at `@ekkolyth/ui/themes/provider`. No
|
|
49
|
-
`next-themes` — a vitest guard (`src/index.test.ts`) fails the build if
|
|
50
|
-
anything reachable from the root barrel imports it. The subpath exports:
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
import {
|
|
54
|
-
ThemeProvider,
|
|
55
|
-
ThemeScript,
|
|
56
|
-
ThemeSelect,
|
|
57
|
-
ThemeToggle,
|
|
58
|
-
Toaster,
|
|
59
|
-
useTheme,
|
|
60
|
-
} from '@ekkolyth/ui/themes/provider'
|
|
61
|
-
import type {
|
|
62
|
-
Appearance,
|
|
63
|
-
DarkThemes,
|
|
64
|
-
LightThemes,
|
|
65
|
-
ThemeContextState,
|
|
66
|
-
ThemeName,
|
|
67
|
-
ThemeProviderProps,
|
|
68
|
-
ThemeScriptProps,
|
|
69
|
-
} from '@ekkolyth/ui/themes/provider'
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**`ThemeProviderProps`:**
|
|
73
|
-
- `defaultAppearance?: Appearance` — `"light" | "dark" | "system" | "normal"`, default `"system"`. `"normal"` is a legacy alias for `"light"`.
|
|
74
|
-
- `lightTheme?: LightThemes | LightThemes[]` — light palette(s) to make available, default `"ekkolyth-light"`.
|
|
75
|
-
- `darkTheme?: DarkThemes | DarkThemes[]` — dark palette(s) to make available, default `"ekkolyth-dark"`.
|
|
76
|
-
- `storageKey?: string` — localStorage key prefix, default `"ekko-ui"`. Most apps won't need this; it matters if several frontends share a domain and need independent theme state.
|
|
77
|
-
|
|
78
|
-
**`useTheme()` returns `ThemeContextState`:**
|
|
79
|
-
- `appearance: Appearance` — the mode the user picked, before resolving `"system"`.
|
|
80
|
-
- `resolvedMode: 'light' | 'dark'` — `appearance` resolved against `matchMedia` when it's `"system"`.
|
|
81
|
-
- `resolvedTheme: ThemeName` — the palette currently applied for `resolvedMode`.
|
|
82
|
-
- `availableThemes: { light: LightThemes[], dark: DarkThemes[] }`
|
|
83
|
-
- `setAppearance: (appearance: Appearance) => void`
|
|
84
|
-
- `setSpecificTheme: (mode: 'light' | 'dark', theme: LightThemes | DarkThemes) => void`
|
|
85
|
-
|
|
86
|
-
`ThemeName` is the union of every palette (`LightThemes | DarkThemes`) —
|
|
87
|
-
which palette is showing. `Appearance` is a separate concept — light/dark/system
|
|
88
|
-
preference — deliberately a different word so the two don't get conflated at a
|
|
89
|
-
call site.
|
|
90
|
-
|
|
91
|
-
**`ThemeName` values:**
|
|
92
|
-
- `"latte" | "ekkoos-light" | "ekkolyth-light"` — light palettes
|
|
93
|
-
- `"mocha" | "frappe" | "macchiato" | "tokyo-night" | "ekkoos-dark" | "ekkolyth-dark"` — dark palettes
|
|
94
|
-
|
|
95
|
-
### `ThemeScript`
|
|
96
|
-
|
|
97
|
-
Renders a `<script>` that reads the stored appearance/palette from
|
|
98
|
-
`localStorage` and sets `data-theme` + the `.dark` class on `<html>` before
|
|
99
|
-
React hydrates. Put it in `<head>` — `app/layout.tsx` on Next.js,
|
|
100
|
-
`__root.tsx` on TanStack Start — with the same `defaultAppearance`,
|
|
101
|
-
`lightTheme`, `darkTheme`, and `storageKey` as the `<ThemeProvider>` it pairs
|
|
102
|
-
with. Skipping it doesn't break anything, it just costs one painted frame of
|
|
103
|
-
the wrong palette before the provider's own mount effect catches up.
|
|
104
|
-
|
|
105
|
-
```tsx
|
|
106
|
-
import { ThemeScript } from '@ekkolyth/ui/themes/provider'
|
|
107
|
-
|
|
108
|
-
<head>
|
|
109
|
-
<ThemeScript defaultAppearance='system' />
|
|
110
|
-
</head>
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Theme Toggle / Theme Select
|
|
114
|
-
|
|
115
|
-
```tsx
|
|
116
|
-
import { ThemeToggle, ThemeSelect } from '@ekkolyth/ui/themes/provider'
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Base CSS
|
|
120
|
-
|
|
121
|
-
`@ekkolyth/ui/base.css` is the base theme layer — 34 color tokens with
|
|
122
|
-
colourless (grayscale) defaults, the `@theme inline` mapping from those
|
|
123
|
-
tokens into Tailwind utilities, `@custom-variant dark`, and an `@layer base`
|
|
124
|
-
reset (`* { border-border outline-ring/50 }`, `body { bg-background
|
|
125
|
-
text-foreground }`). Import it after the consuming app's own
|
|
126
|
-
`@import 'tailwindcss'` and before its palette overrides:
|
|
127
|
-
|
|
128
|
-
```css
|
|
129
|
-
@import 'tailwindcss';
|
|
130
|
-
@import '@ekkolyth/ui/base.css';
|
|
131
|
-
/* app-specific palette overrides go here */
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
The export resolves to `./src/base.css`, not `./dist/base.css`, deliberately:
|
|
135
|
-
`dist/` is gitignored, so a `dist` path would leave fresh clones and git
|
|
136
|
-
worktrees unstyled until someone ran the UI package's build.
|
|
137
|
-
|
|
138
|
-
## Theme Styles
|
|
139
|
-
|
|
140
|
-
`@ekkolyth/ui/themes` is a **stylesheet entry** (a CSS `@import`, not a JS
|
|
141
|
-
module) that pulls in all seven palettes. It stands in for the app's own
|
|
142
|
-
Tailwind preamble, not the other way around — a theme picker that lets the
|
|
143
|
-
user switch palettes needs every palette present, so import it alongside the
|
|
144
|
-
three lines every consumer already writes:
|
|
145
|
-
|
|
146
|
-
```css
|
|
147
|
-
@import 'tailwindcss';
|
|
148
|
-
@import 'tw-animate-css';
|
|
149
|
-
@import '@ekkolyth/ui/base.css';
|
|
150
|
-
@import '@ekkolyth/ui/themes';
|
|
151
|
-
```
|
|
8
|
+
# inside this monorepo
|
|
9
|
+
"@ekkolyth/ui": "workspace:@ekkolyth/ui@*"
|
|
152
10
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
runtime import. Pull a single palette instead of the aggregate when an app
|
|
156
|
-
only ever shows one:
|
|
157
|
-
|
|
158
|
-
```css
|
|
159
|
-
@import '@ekkolyth/ui/themes/catpuccin/latte';
|
|
160
|
-
@import '@ekkolyth/ui/themes/tokyo-night';
|
|
161
|
-
@import '@ekkolyth/ui/themes/ekkolyth';
|
|
11
|
+
# anywhere else
|
|
12
|
+
bun add @ekkolyth/ui
|
|
162
13
|
```
|
|
163
14
|
|
|
164
|
-
|
|
15
|
+
App code MUST always import through its local package alias (`@ekkolyth/ui`),
|
|
16
|
+
never via `@ekkolyth/ui/*`. The canonical name exists only so the consuming
|
|
17
|
+
bundler can resolve package-internal references when transpiling source.
|
|
165
18
|
|
|
166
19
|
### Next.js Setup
|
|
167
20
|
|
|
168
21
|
```tsx
|
|
169
22
|
// app/layout.tsx
|
|
170
|
-
import {
|
|
171
|
-
|
|
23
|
+
import {
|
|
24
|
+
ThemeProvider,
|
|
25
|
+
ThemeScript,
|
|
26
|
+
Toaster,
|
|
27
|
+
} from "@ekkolyth/ui/themes/provider";
|
|
28
|
+
import "@ekkolyth/ui/themes";
|
|
172
29
|
|
|
173
30
|
export default function RootLayout({ children }) {
|
|
174
31
|
return (
|
|
175
32
|
<html>
|
|
176
33
|
<head>
|
|
177
|
-
<ThemeScript defaultAppearance=
|
|
34
|
+
<ThemeScript defaultAppearance="system" />
|
|
178
35
|
</head>
|
|
179
36
|
<body>
|
|
180
37
|
<ThemeProvider
|
|
181
|
-
defaultAppearance=
|
|
182
|
-
lightTheme={[
|
|
183
|
-
darkTheme={[
|
|
38
|
+
defaultAppearance="system"
|
|
39
|
+
lightTheme={["latte", "ekkolyth-light"]}
|
|
40
|
+
darkTheme={["mocha", "ekkolyth-dark"]}
|
|
184
41
|
>
|
|
185
42
|
{children}
|
|
186
43
|
<Toaster />
|
|
187
44
|
</ThemeProvider>
|
|
188
45
|
</body>
|
|
189
46
|
</html>
|
|
190
|
-
)
|
|
47
|
+
);
|
|
191
48
|
}
|
|
192
49
|
|
|
193
50
|
// app/page.tsx
|
|
194
|
-
|
|
195
|
-
import { Button } from
|
|
196
|
-
import { ThemeToggle, useTheme } from
|
|
51
|
+
("use client");
|
|
52
|
+
import { Button } from "@ekkolyth/ui";
|
|
53
|
+
import { ThemeToggle, useTheme } from "@ekkolyth/ui/themes/provider";
|
|
197
54
|
|
|
198
55
|
export default function Page() {
|
|
199
|
-
const { appearance, setAppearance } = useTheme()
|
|
56
|
+
const { appearance, setAppearance } = useTheme();
|
|
200
57
|
|
|
201
58
|
return (
|
|
202
59
|
<div>
|
|
203
60
|
<ThemeToggle />
|
|
204
|
-
<Button onClick={() => setAppearance(
|
|
205
|
-
Set Dark Mode
|
|
206
|
-
</Button>
|
|
61
|
+
<Button onClick={() => setAppearance("dark")}>Set Dark Mode</Button>
|
|
207
62
|
</div>
|
|
208
|
-
)
|
|
63
|
+
);
|
|
209
64
|
}
|
|
210
65
|
```
|
|
211
66
|
|
|
212
|
-
|
|
67
|
+
### TanStack Start Setup
|
|
213
68
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
ships.
|
|
221
|
-
4. The workflow publishes the validated tarball, commits the release state,
|
|
222
|
-
and tags the release `ui-v<version>`.
|
|
223
|
-
|
|
224
|
-
A push to `main` with no pending changeset is a no-op — `changeset version`
|
|
225
|
-
has nothing to consume, and the commit/publish steps detect the unchanged
|
|
226
|
-
manifest and stop.
|
|
69
|
+
```css
|
|
70
|
+
/* src/styles.css */
|
|
71
|
+
@import "tailwindcss";
|
|
72
|
+
@import "@ekkolyth/ui/base.css";
|
|
73
|
+
@import "@ekkolyth/ui/themes";
|
|
74
|
+
```
|
|
227
75
|
|
|
228
|
-
|
|
76
|
+
```tsx
|
|
77
|
+
// src/routes/__root.tsx
|
|
78
|
+
import {
|
|
79
|
+
createRootRoute,
|
|
80
|
+
HeadContent,
|
|
81
|
+
Outlet,
|
|
82
|
+
Scripts,
|
|
83
|
+
} from "@tanstack/react-router";
|
|
84
|
+
import {
|
|
85
|
+
ThemeProvider,
|
|
86
|
+
ThemeScript,
|
|
87
|
+
Toaster,
|
|
88
|
+
} from "@ekkolyth/ui/themes/provider";
|
|
89
|
+
import appCss from "../styles.css?url";
|
|
90
|
+
|
|
91
|
+
export const Route = createRootRoute({
|
|
92
|
+
head: () => ({ links: [{ rel: "stylesheet", href: appCss }] }),
|
|
93
|
+
component: RootLayout,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
function RootLayout() {
|
|
97
|
+
return (
|
|
98
|
+
<html suppressHydrationWarning>
|
|
99
|
+
<head>
|
|
100
|
+
<HeadContent />
|
|
101
|
+
<ThemeScript defaultAppearance="system" />
|
|
102
|
+
</head>
|
|
103
|
+
<body>
|
|
104
|
+
<ThemeProvider
|
|
105
|
+
defaultAppearance="system"
|
|
106
|
+
lightTheme={["latte", "ekkolyth-light"]}
|
|
107
|
+
darkTheme={["mocha", "ekkolyth-dark"]}
|
|
108
|
+
>
|
|
109
|
+
<Outlet />
|
|
110
|
+
<Toaster />
|
|
111
|
+
</ThemeProvider>
|
|
112
|
+
<Scripts />
|
|
113
|
+
</body>
|
|
114
|
+
</html>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
229
118
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
119
|
+
`ThemeScript` goes in `<head>` with the same props as the `ThemeProvider` it
|
|
120
|
+
pairs with — it applies the stored palette before first paint, so skipping it
|
|
121
|
+
just costs one frame of the wrong theme.
|
package/dist/base.css
CHANGED
|
@@ -179,6 +179,10 @@
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
.ts-chart-tooltip {
|
|
183
|
+
--ts-chart-tooltip-font: 500 1rem / 1.5 var(--font-sans);
|
|
184
|
+
}
|
|
185
|
+
|
|
182
186
|
.prose h1,
|
|
183
187
|
.prose h2,
|
|
184
188
|
.prose h3 {
|
|
@@ -231,7 +235,9 @@
|
|
|
231
235
|
.prose thead th,
|
|
232
236
|
.prose tbody td,
|
|
233
237
|
.prose tfoot td {
|
|
238
|
+
/* biome-ignore lint/complexity/noImportantStyles: pinned by base.css.test.ts to beat the typography plugin */
|
|
234
239
|
padding-top: 0.375rem !important;
|
|
240
|
+
/* biome-ignore lint/complexity/noImportantStyles: pinned by base.css.test.ts to beat the typography plugin */
|
|
235
241
|
padding-bottom: 0.375rem !important;
|
|
236
242
|
border-right: 1px solid color-mix(in oklab, var(--border) 40%, transparent);
|
|
237
243
|
}
|
package/dist/blocks.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as
|
|
1
|
+
import { a as ComboboxField, i as Dropzone, n as Field, o as ComboboxFieldProps, r as validate, s as ColorPicker, t as IconPicker } from "./index-BJs5qfKG.js";
|
|
2
2
|
import { n as LoadingScreenProps, t as LoadingScreen } from "./index-DsLGf2HX.js";
|
|
3
3
|
import { n as WidgetLinkProps, r as WidgetProps, t as Widget } from "./index-qji4ohJZ.js";
|
|
4
|
-
export { ColorPicker, Field, IconPicker, LoadingScreen, type LoadingScreenProps, Widget, type WidgetLinkProps, type WidgetProps, validate };
|
|
4
|
+
export { ColorPicker, ComboboxField, type ComboboxFieldProps, Dropzone, Field, IconPicker, LoadingScreen, type LoadingScreenProps, Widget, type WidgetLinkProps, type WidgetProps, validate };
|
package/dist/blocks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as LoadingScreen } from "./loading-screen-
|
|
1
|
+
import { _ as validate, at as ColorPicker, b as ComboboxField, t as IconPicker, u as Field, v as Dropzone } from "./icon-picker-CwavOWKf.js";
|
|
2
|
+
import { t as LoadingScreen } from "./loading-screen-DilmTJ3J.js";
|
|
3
3
|
import { t as Widget } from "./widget-C2vjxQms.js";
|
|
4
|
-
export { ColorPicker, Field, IconPicker, LoadingScreen, Widget, validate };
|
|
4
|
+
export { ColorPicker, ComboboxField, Dropzone, Field, IconPicker, LoadingScreen, Widget, validate };
|
package/dist/convex.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as LoadingScreen } from "./loading-screen-
|
|
1
|
+
import { t as LoadingScreen } from "./loading-screen-DilmTJ3J.js";
|
|
2
2
|
export { LoadingScreen };
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { useIsMobile };
|
|
1
|
+
import { n as useIsMobile, t as useWindowScrollMargin } from "./use-window-scroll-margin-BeVjX6Le.js";
|
|
2
|
+
export { useIsMobile, useWindowScrollMargin };
|
package/dist/hooks.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { t as useIsMobile } from "./use-mobile-
|
|
2
|
-
|
|
1
|
+
import { t as useIsMobile } from "./use-mobile-C-Ak14Ip.js";
|
|
2
|
+
import { t as useWindowScrollMargin } from "./use-window-scroll-margin-BQMpLEeT.js";
|
|
3
|
+
export { useIsMobile, useWindowScrollMargin };
|