@esuiss/ui 0.5.8 → 0.6.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 +26 -11
- package/lib/init.mjs +69 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,8 +47,9 @@ export function Example() {
|
|
|
47
47
|
2. Adds the `@/*` import alias to `tsconfig.json` if it is missing.
|
|
48
48
|
3. Installs and wires up Tailwind CSS if needed (`postcss.config.mjs` for Next.js, `vite.config.ts` for Vite).
|
|
49
49
|
4. Writes the theme stylesheet to `app/globals.css` (Next.js) or `src/index.css` (Vite). It asks before replacing a stylesheet that already has content.
|
|
50
|
-
5.
|
|
51
|
-
6.
|
|
50
|
+
5. Sets up the Inter font: with `next/font/google` in the root layout (Next.js), or with `@fontsource-variable/inter` imported from the stylesheet (Vite).
|
|
51
|
+
6. Installs [`@esuiss/tailwind`](https://www.npmjs.com/package/@esuiss/tailwind), which provides the variants, animations, and utilities the components rely on.
|
|
52
|
+
7. Adds the `button` component.
|
|
52
53
|
|
|
53
54
|
## Commands
|
|
54
55
|
|
|
@@ -96,28 +97,42 @@ Your stylesheet holds the whole theme:
|
|
|
96
97
|
```css
|
|
97
98
|
@import "tailwindcss";
|
|
98
99
|
@import "@esuiss/tailwind";
|
|
100
|
+
@import "@fontsource-variable/inter";
|
|
99
101
|
|
|
100
102
|
:root {
|
|
101
|
-
--
|
|
102
|
-
--
|
|
103
|
-
--
|
|
103
|
+
--surface: oklch(1 0 0);
|
|
104
|
+
--label: oklch(0.2316 0.0038 286.09);
|
|
105
|
+
--accent: oklch(0.5629 0.1933 256.16);
|
|
106
|
+
--radius: 0.625rem;
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
.dark {
|
|
107
|
-
--
|
|
108
|
-
--
|
|
110
|
+
--surface: oklch(0 0 0);
|
|
111
|
+
--label: oklch(0.9707 0.0026 286.29);
|
|
112
|
+
--accent: oklch(0.5629 0.1933 256.16);
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
@theme inline {
|
|
112
|
-
--font-sans:
|
|
113
|
-
--color-
|
|
114
|
-
--color-
|
|
116
|
+
--font-sans: "Inter Variable", sans-serif;
|
|
117
|
+
--color-surface: var(--surface);
|
|
118
|
+
--color-label: var(--label);
|
|
119
|
+
--color-accent: var(--accent);
|
|
115
120
|
}
|
|
116
121
|
```
|
|
117
122
|
|
|
123
|
+
Colors are named by role, not by component:
|
|
124
|
+
|
|
125
|
+
- **Surfaces:** `surface`, `surface-secondary`, `surface-tertiary`, `surface-raised` (menus, dialogs, cards).
|
|
126
|
+
- **Text:** `label`, `label-secondary`, `label-tertiary`, `label-quaternary`.
|
|
127
|
+
- **Control fills:** `fill`, `fill-secondary`, `fill-tertiary`.
|
|
128
|
+
- **Lines:** `separator`, `separator-strong`.
|
|
129
|
+
- **Accent:** `accent`, `accent-hover`, `accent-pressed`, `on-accent` (text on the accent).
|
|
130
|
+
- **Links, focus and states:** `link`, `focus`, `danger`, `success`, `warning` and their `-surface` tints.
|
|
131
|
+
- **Palette:** `blue`, `green`, `orange`, `red`, `yellow`, `purple`, `pink`, `indigo`, `teal`, `mint`, `cyan`, `brown`, `gray`, used by charts.
|
|
132
|
+
|
|
118
133
|
- **Change a color:** edit its value under `:root` (light) and `.dark` (dark).
|
|
119
134
|
- **Add a color:** define it under `:root` and `.dark`, then map it in `@theme inline`, for example `--color-brand: var(--brand);`. Classes such as `bg-brand` and `text-brand` become available.
|
|
120
|
-
- **Change the font:** set `--font-sans` in `@theme inline`.
|
|
135
|
+
- **Change the font:** set `--font-sans` in `@theme inline`. Inter is loaded by default.
|
|
121
136
|
- **Corner radius:** `--radius` scales every rounded component.
|
|
122
137
|
|
|
123
138
|
## Dark mode
|
package/lib/init.mjs
CHANGED
|
@@ -39,6 +39,17 @@ const TOOLING = {
|
|
|
39
39
|
vite: ["tailwindcss", "@tailwindcss/vite", "@types/node"],
|
|
40
40
|
}
|
|
41
41
|
const MINIMUM_TAILWIND = [4, 2]
|
|
42
|
+
const FONT_IMPORT = '@import "@fontsource-variable/inter";\n'
|
|
43
|
+
const FONT_FAMILY = '--font-sans: "Inter Variable", sans-serif;'
|
|
44
|
+
const NEXT_FONT_FAMILY = "--font-sans: var(--font-sans);"
|
|
45
|
+
const NEXT_LAYOUTS = [
|
|
46
|
+
"src/app/layout.tsx",
|
|
47
|
+
"app/layout.tsx",
|
|
48
|
+
"src/app/layout.jsx",
|
|
49
|
+
"app/layout.jsx",
|
|
50
|
+
]
|
|
51
|
+
const NEXT_FONT_NOTE =
|
|
52
|
+
'Load Inter in your root layout with next/font/google: Inter({ subsets: ["latin", "latin-ext"], variable: "--font-sans" }), and add its .variable to the <html> className.'
|
|
42
53
|
|
|
43
54
|
function relative(project, file) {
|
|
44
55
|
return path.relative(project.cwd, file)
|
|
@@ -184,6 +195,62 @@ function configureVite(project) {
|
|
|
184
195
|
return manual
|
|
185
196
|
}
|
|
186
197
|
|
|
198
|
+
function stylesheetFor(project, css) {
|
|
199
|
+
if (project.framework !== "next") return css
|
|
200
|
+
return css.replace(FONT_IMPORT, "").replace(FONT_FAMILY, NEXT_FONT_FAMILY)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function configureNextFont(project) {
|
|
204
|
+
const file = NEXT_LAYOUTS.map((name) => path.join(project.cwd, name)).find(
|
|
205
|
+
existsSync
|
|
206
|
+
)
|
|
207
|
+
if (!file) return [NEXT_FONT_NOTE]
|
|
208
|
+
|
|
209
|
+
let text = readFileSync(file, "utf8")
|
|
210
|
+
if (/variable:\s*["']--font-sans["']/.test(text)) return []
|
|
211
|
+
|
|
212
|
+
const html = text.match(/<html\b[^>]*>/)
|
|
213
|
+
if (!html) return [NEXT_FONT_NOTE]
|
|
214
|
+
let tag = html[0]
|
|
215
|
+
const literal = tag.match(/className="([^"]*)"/)
|
|
216
|
+
if (literal) {
|
|
217
|
+
tag = tag.replace(
|
|
218
|
+
literal[0],
|
|
219
|
+
`className={\`\${fontSans.variable} ${literal[1]}\`}`
|
|
220
|
+
)
|
|
221
|
+
} else if (!/className=/.test(tag)) {
|
|
222
|
+
tag = tag.replace(/<html\b/, "<html className={fontSans.variable}")
|
|
223
|
+
} else {
|
|
224
|
+
return [NEXT_FONT_NOTE]
|
|
225
|
+
}
|
|
226
|
+
text = text.replace(html[0], tag)
|
|
227
|
+
|
|
228
|
+
const semi = /from\s+["'][^"']+["'];/.test(text) ? ";" : ""
|
|
229
|
+
const fontImport = text.match(
|
|
230
|
+
/import\s*\{([^}]*)\}\s*from\s*["']next\/font\/google["']/
|
|
231
|
+
)
|
|
232
|
+
if (fontImport) {
|
|
233
|
+
text = text.replace(
|
|
234
|
+
fontImport[0],
|
|
235
|
+
fontImport[0].replace(fontImport[1], `${fontImport[1].trimEnd()}, Inter `)
|
|
236
|
+
)
|
|
237
|
+
} else {
|
|
238
|
+
text = `import { Inter } from "next/font/google"${semi}\n${text}`
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const imports = [
|
|
242
|
+
...text.matchAll(/^import\s[\s\S]*?["'][^"']+["'];?[ \t]*\n/gm),
|
|
243
|
+
]
|
|
244
|
+
const last = imports.at(-1)
|
|
245
|
+
const at = last ? last.index + last[0].length : 0
|
|
246
|
+
const declaration = `\nconst fontSans = Inter({\n subsets: ["latin", "latin-ext"],\n variable: "--font-sans",\n})${semi}\n`
|
|
247
|
+
text = text.slice(0, at) + declaration + text.slice(at)
|
|
248
|
+
|
|
249
|
+
writeFileSync(file, text)
|
|
250
|
+
step(`Loaded Inter in ${relative(project, file)}`)
|
|
251
|
+
return []
|
|
252
|
+
}
|
|
253
|
+
|
|
187
254
|
function configureNext(project) {
|
|
188
255
|
const existing = POSTCSS_CONFIGS.map((name) =>
|
|
189
256
|
path.join(project.cwd, name)
|
|
@@ -230,7 +297,7 @@ export async function init(options) {
|
|
|
230
297
|
}
|
|
231
298
|
|
|
232
299
|
const registry = await fetchRegistry()
|
|
233
|
-
const css = await fetchStylesheet(registry)
|
|
300
|
+
const css = stylesheetFor(project, await fetchStylesheet(registry))
|
|
234
301
|
|
|
235
302
|
if (ensureAlias(project, sourceRoot))
|
|
236
303
|
step("Added the @/* import alias to tsconfig")
|
|
@@ -241,7 +308,7 @@ export async function init(options) {
|
|
|
241
308
|
const manual =
|
|
242
309
|
project.framework === "vite"
|
|
243
310
|
? configureVite(project)
|
|
244
|
-
: configureNext(project)
|
|
311
|
+
: [...configureNext(project), ...configureNextFont(project)]
|
|
245
312
|
|
|
246
313
|
writeFileSync(stylesheet, css)
|
|
247
314
|
step(`Wrote ${relative(project, stylesheet)}`)
|
package/package.json
CHANGED