Compare commits

..
Author SHA1 Message Date
grugbraindev c2ac210002 Use Geist as the default sans font family name
Google Fonts, Bunny Fonts and Fontsource all publish the font as "Geist". "Geist Sans" is only on Fontsource, so the default token fell back to system fonts with the other providers. "Geist Sans" stays as a fallback for existing Fontsource setups. Matches shadcn/ui, which loads "Geist".
2026-10-23 09:28:43 +08:00
18 changed files with 22 additions and 189 deletions
+1 -10
View File
@@ -1,15 +1,6 @@
# Changelog
## [Unreleased]
### Added
- Added vertical separators: `<hr aria-orientation="vertical">` renders as a 1px line that fills its row.
### Fixed
- Prevented Escape from dismissing an enclosing dialog while closing an open Combobox popup.
- Fixed long Tooltip text clipping instead of showing an ellipsis across all style packs.
## Unreleased
## [1.0.2] - 2026-07-06
+4 -4
View File
@@ -24,28 +24,28 @@ const styleUrls = {
<style is:inline>
@font-face {
font-family: "Geist Sans";
font-family: "Geist";
src: url("/assets/fonts/geist/geist-sans-latin-400-normal.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Geist Sans";
font-family: "Geist";
src: url("/assets/fonts/geist/geist-sans-latin-500-normal.woff2") format("woff2");
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Geist Sans";
font-family: "Geist";
src: url("/assets/fonts/geist/geist-sans-latin-600-normal.woff2") format("woff2");
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Geist Sans";
font-family: "Geist";
src: url("/assets/fonts/geist/geist-sans-latin-700-normal.woff2") format("woff2");
font-weight: 700;
font-style: normal;
-2
View File
@@ -85,8 +85,6 @@ Combobox is input-first. The visible input filters the list; the hidden input st
</Step>
</Steps>
Pressing Escape in the input closes an open suggestions popup without dismissing an enclosing dialog. Once the popup is closed, press Escape again to dismiss the dialog.
### HTML structure
<dl>
-134
View File
@@ -1,134 +0,0 @@
# Separator
<Callout title="No dedicated component" icon="circle-alert">
There is no dedicated Separator component in Basecoat.
</Callout>
<Preview class="w-full max-w-sm">
<div class="flex flex-col gap-4 text-sm">
<div class="flex flex-col gap-1.5">
<div class="leading-none font-medium">Basecoat</div>
<div class="text-muted-foreground">Tailwind components for any web stack</div>
</div>
<hr role="separator" />
<div>A set of components you can drop into any HTML page, styled like shadcn/ui.</div>
</div>
</Preview>
## Usage
<Steps>
<Step title="Include CSS">
Import Tailwind and one full Basecoat style bundle.
```css
@import "tailwindcss";
@import "basecoat-css/vega.css";
```
Or import only the base CSS, which styles horizontal and vertical separators.
```css
@import "tailwindcss";
@import "basecoat-css/base.css";
```
Separator is a native `<hr>` and has no dedicated component CSS file.
Using CDN or bundler imports? See the [Installation page](/installation).
</Step>
<Step title="Add your separator HTML">
Use an `<hr>` with `role="separator"`. It renders as a 1px line in the `border` color, matching shadcn/ui's Separator.
```html
<hr role="separator" />
```
If the separator is purely decorative, use `role="none"` instead so assistive technologies skip it. This is what shadcn/ui's `decorative` prop does.
```html
<hr role="none" />
```
</Step>
</Steps>
## Examples
### Vertical
Add `aria-orientation="vertical"` for a vertical separator. It fills the height of its row.
<Preview>
<div class="flex h-5 items-center gap-4 text-sm">
<div>Blog</div>
<hr role="separator" aria-orientation="vertical" />
<div>Docs</div>
<hr role="separator" aria-orientation="vertical" />
<div>Source</div>
</div>
</Preview>
### Menu
Vertical separators between menu items with descriptions.
<Preview>
<div class="flex items-center gap-2 text-sm md:gap-4">
<div class="flex flex-col gap-1">
<span class="font-medium">Settings</span>
<span class="text-xs text-muted-foreground">Manage preferences</span>
</div>
<hr role="separator" aria-orientation="vertical" />
<div class="flex flex-col gap-1">
<span class="font-medium">Account</span>
<span class="text-xs text-muted-foreground">Profile & security</span>
</div>
<hr role="separator" aria-orientation="vertical" class="hidden md:block" />
<div class="hidden flex-col gap-1 md:flex">
<span class="font-medium">Help</span>
<span class="text-xs text-muted-foreground">Support & docs</span>
</div>
</div>
</Preview>
### List
Horizontal separators between list items.
<Preview class="w-full max-w-sm">
<div class="flex flex-col gap-2 text-sm">
<dl class="flex items-center justify-between">
<dt>Item 1</dt>
<dd class="text-muted-foreground">Value 1</dd>
</dl>
<hr role="separator" />
<dl class="flex items-center justify-between">
<dt>Item 2</dt>
<dd class="text-muted-foreground">Value 2</dd>
</dl>
<hr role="separator" />
<dl class="flex items-center justify-between">
<dt>Item 3</dt>
<dd class="text-muted-foreground">Value 3</dd>
</dl>
</div>
</Preview>
### RTL
Separators follow document direction. Vertical separators use a logical inline-start border, so they need no changes.
<Preview class="w-full max-w-sm">
<div dir="rtl" class="flex flex-col gap-4 text-sm">
<div class="flex flex-col gap-1.5">
<div class="leading-none font-medium">Basecoat</div>
<div class="text-muted-foreground">مكونات Tailwind لأي بيئة ويب</div>
</div>
<hr role="separator" />
<div>مجموعة من المكونات يمكنك إضافتها إلى أي صفحة HTML، بتصميم مثل shadcn/ui.</div>
</div>
</Preview>
-8
View File
@@ -53,14 +53,6 @@ Basecoat tooltips are CSS-only and text-only. This intentionally differs from sh
<button class="btn" data-variant="outline" data-tooltip="Default tooltip">Default</button>
</Preview>
### Long text
Tooltips stay on one line and truncate with an ellipsis when the text exceeds the maximum width. This intentionally differs from shadcn/ui's multiline tooltip content.
<Preview>
<button class="btn" data-variant="outline" data-tooltip="A tooltip with enough text to exceed the default maximum width and demonstrate truncation">Hover</button>
</Preview>
### Sides
<Preview>
+6 -6
View File
@@ -45,12 +45,12 @@ Learn more in the [shadcn/ui theming docs](https://ui.shadcn.com/docs/theming).
## Fonts
Basecoat does not ship web font files by default. Its font tokens prefer [Geist Sans](https://fonts.google.com/specimen/Geist) and [Geist Mono](https://fonts.google.com/specimen/Geist+Mono) when those fonts are available, then fall back to the full Tailwind default sans and mono stacks.
Basecoat does not ship web font files by default. Its font tokens prefer [Geist](https://fonts.google.com/specimen/Geist) and [Geist Mono](https://fonts.google.com/specimen/Geist+Mono) when those fonts are available, then fall back to the full Tailwind default sans and mono stacks.
Install the fonts with Fontsource:
```bash
npm install @fontsource/geist-sans @fontsource/geist-mono
npm install @fontsource/geist @fontsource/geist-mono
```
Then import the font files. Basecoat's default font tokens already reference Geist with full system fallbacks:
@@ -58,10 +58,10 @@ Then import the font files. Basecoat's default font tokens already reference Gei
```css
@import "tailwindcss";
@import "basecoat-css/sera";
@import "@fontsource/geist-sans/400.css";
@import "@fontsource/geist-sans/500.css";
@import "@fontsource/geist-sans/600.css";
@import "@fontsource/geist-sans/700.css";
@import "@fontsource/geist/400.css";
@import "@fontsource/geist/500.css";
@import "@fontsource/geist/600.css";
@import "@fontsource/geist/700.css";
@import "@fontsource/geist-mono/400.css";
@import "@fontsource/geist-mono/500.css";
@import "@fontsource/geist-mono/600.css";
-1
View File
@@ -94,7 +94,6 @@
"components/radio-group",
"components/select",
"components/scroll-area",
"components/separator",
"components/sidebar",
"components/skeleton",
"components/slider",
+1 -10
View File
@@ -84,7 +84,7 @@
}
@theme {
--font-sans: "Geist Sans", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-sans: "Geist", "Geist Sans", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
@@ -133,13 +133,4 @@
body {
@apply bg-background text-foreground overscroll-none;
}
hr:where([aria-orientation='vertical']) {
flex-shrink: 0;
align-self: stretch;
inline-size: 1px;
block-size: auto;
margin: 0;
border-block-start-width: 0;
border-inline-start-width: 1px;
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
@apply relative;
&:before {
@apply absolute block z-[60] w-fit max-w-xs origin-(--transform-origin) scale-95 truncate invisible opacity-0 transition-all pointer-events-none content-[attr(data-tooltip)];
@apply absolute z-[60] w-fit max-w-xs origin-(--transform-origin) scale-95 truncate invisible opacity-0 transition-all pointer-events-none content-[attr(data-tooltip)];
}
&:hover:before {
+1 -1
View File
@@ -1324,7 +1324,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-xl px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-xl px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-lg;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1327,7 +1327,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-none px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-none px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-none;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1312,7 +1312,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-2xl px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-2xl px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-4xl;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1321,7 +1321,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-md px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-sm;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1335,7 +1335,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-md px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-sm;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1329,7 +1329,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-xl px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-xl px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-lg;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1345,7 +1345,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-none px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-none px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-none;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1334,7 +1334,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-md px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-sm;
}
[data-tooltip][data-arrow]::after {
+1 -5
View File
@@ -390,11 +390,7 @@
}
if (event.key === 'Escape') {
if (isOpen) {
event.preventDefault();
event.stopPropagation();
root.close(true);
}
root.close(true);
return;
}