Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
b85317e
fix: consolidate motion and interaction tokens
ravisuhag Jul 12, 2026
28eedbd
fix: retune the type ramp tracking and leading
ravisuhag Jul 12, 2026
e8c1165
fix: table and data-table stylesheet states
ravisuhag Jul 12, 2026
fa12492
fix(spinner): speed the loop up from 1.2s to 0.9s
ravisuhag Jul 12, 2026
9fb79c3
fix(floating-actions): margin-based centering, fade+rise entrance
ravisuhag Jul 12, 2026
d49074e
fix: guard Image's fallback re-entry, fade in loaded images/avatars
ravisuhag Jul 12, 2026
8d37501
fix: scope Headline's width:100% to the truncate variant
ravisuhag Jul 12, 2026
f5aa134
feat: give the announcement bar action button interactive states
ravisuhag Jul 12, 2026
4fa7ae4
fix: tabs standalone/plain variants glide their indicator instead of …
ravisuhag Jul 12, 2026
7b65eea
fix: ease the breadcrumb link hover
ravisuhag Jul 12, 2026
0508388
fix: align popover shadow depth with its surface size
ravisuhag Jul 12, 2026
d585271
fix: side-panel overflow:auto, document as persistent layout
ravisuhag Jul 12, 2026
57d106f
fix: give the scroll-area thumb a hover grow and grabbed state
ravisuhag Jul 12, 2026
2832db3
fix: scope preview-card inset/size transitions to viewport-morph mode
ravisuhag Jul 12, 2026
acdd909
fix: reveal sticky-header hairlines only once content scrolls under them
ravisuhag Jul 12, 2026
a011f19
fix: unify calendar day-cell radius, cross-fade the loading skeleton
ravisuhag Jul 12, 2026
8407860
fix: link hover reveals an underline instead of dimming the text
ravisuhag Jul 12, 2026
16a7831
fix: default Amount to tabular numerals
ravisuhag Jul 12, 2026
ff8969c
fix: fade the code-block copy button reveal at the fast tier
ravisuhag Jul 12, 2026
96e9ee9
fix: style selected/pressed rows, add row-state hooks to Table primitive
ravisuhag Jul 12, 2026
6f7701e
fix: distinguish toggle hover from pressed, animate content, fix disa…
ravisuhag Jul 12, 2026
684eade
fix: select popup background and multi-select indicator
ravisuhag Jul 12, 2026
c1309e8
fix: render clickable chips as real buttons
ravisuhag Jul 12, 2026
dcaaa30
fix: cross-fade the Field error and surface the DatePicker error
ravisuhag Jul 12, 2026
1409722
fix: color-picker area thumb uses transform, blocks touch scroll, fad…
ravisuhag Jul 12, 2026
1915309
fix: let sidebar collapse fade labels instead of popping them
ravisuhag Jul 12, 2026
3637c09
fix: animate callout enter and dismiss (fade + height collapse)
ravisuhag Jul 12, 2026
3759c5d
fix: rewrite tooltip motion as interruptible, symmetric transitions
ravisuhag Jul 12, 2026
64eba23
fix: reduced-motion and reduced-transparency fallbacks
ravisuhag Jul 12, 2026
ba6e47d
fix: drawer tracks swipes 1:1, tokenize exit duration, fade under red…
ravisuhag Jul 12, 2026
53b494c
fix: give number-field input real hover/focus/invalid states
ravisuhag Jul 12, 2026
535e1c8
fix: animate indeterminate Progress, move fills to transform: scaleX
ravisuhag Jul 12, 2026
a407470
fix: invalid toolbar background value, misnamed text decoration class
ravisuhag Jul 12, 2026
165da45
fix: size the data-view sort icon and flip it on sort direction
ravisuhag Jul 12, 2026
d2706f1
fix: stop CopyButton timer leak, cross-fade icon swap, announce state
ravisuhag Jul 12, 2026
5ee2c43
fix: add missing :focus-visible indicators across the library
ravisuhag Jul 12, 2026
089d06c
fix: compose motion tokens into --rs-transition-interactive, add pres…
ravisuhag Jul 12, 2026
b16de9f
fix: bring component motion in line with animation standards
ravisuhag Jul 12, 2026
1e7e7aa
fix: static caret on select and combobox triggers, tidy command overlay
ravisuhag Jul 12, 2026
5d66454
chore: drop unused eslint and np release config
ravisuhag Jul 12, 2026
91bb918
test: register CaretSortIcon in the code-block icon mock
ravisuhag Jul 12, 2026
8cfee06
chore: prune dead CSS, gate stray motion for reduced-motion, refresh …
ravisuhag Jul 12, 2026
2bbe90a
fix: dark contrast text on mint accent since mint-9/10 are light
ravisuhag Jul 14, 2026
f2862e4
fix: balance heading wrap, load full JetBrains Mono weights, drop fon…
ravisuhag Jul 14, 2026
0c7ac31
fix: make theme switcher keyboard accessible
ravisuhag Jul 14, 2026
b46ce33
fix: add keyboard support to color picker area
ravisuhag Jul 14, 2026
8ba340f
fix: make clickable data-view rows keyboard accessible
ravisuhag Jul 14, 2026
ae337cf
fix: add missing focus rings to calendar and sidebar
ravisuhag Jul 14, 2026
230a3be
fix: use theme tokens for input text and placeholder
ravisuhag Jul 14, 2026
1948b2c
fix: refine button press states and focus rings
ravisuhag Jul 14, 2026
688ef36
fix: add missing press scale to icon button
ravisuhag Jul 14, 2026
862ddd0
fix: add hairline media edge to image, avatar and code block
ravisuhag Jul 15, 2026
4ec6ef8
fix: float drawer panel and reuse icon button for its close
ravisuhag Jul 15, 2026
4800b1b
fix: align popup shadows to one elevation tier and hairline borders
ravisuhag Jul 15, 2026
f5c60cc
fix: snap sidebar nav-item highlight, ease the accordion trigger
ravisuhag Jul 15, 2026
e55e41f
fix: add press scale to announcement action and filter chip remove
ravisuhag Jul 15, 2026
02a2b05
fix: fade search clear button instead of display toggle
ravisuhag Jul 15, 2026
0bcb04a
fix: use the real Checkbox as the select multi-select indicator
ravisuhag Jul 15, 2026
eb6b8d8
fix: square up the code-block floating copy icon
ravisuhag Jul 15, 2026
760c6e5
fix: hide the DatePicker reserved error line inside filter chips
ravisuhag Jul 15, 2026
1b65cc2
fix: shake the OTP field once on invalid state
ravisuhag Jul 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .eslintrc.js

This file was deleted.

7 changes: 0 additions & 7 deletions .eslintrs.js

This file was deleted.

6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ Apsara follows an automated release process using GitHub Actions and semantic ve
# Ensure you're on the correct branch
git checkout main # for production release
# OR
git checkout develop # for release candidate
git checkout release/x.y # for release candidate

# Pull latest changes
git pull origin main # or develop
git pull origin main # or the release branch
Comment on lines +225 to +228

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clarify the git pull command for release candidate branches.

Line 228 shows git pull origin main with a comment "or the release branch", but if a maintainer is on release/x.y, running this command as-is would merge main into the release branch. The command should explicitly show the release branch variant to avoid accidental cross-branch merges.

📝 Suggested fix
   # Pull latest changes
-  git pull origin main  # or the release branch
+  git pull origin main  # for production release
+  # OR
+  git pull origin release/x.y  # for release candidate
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
git checkout release/x.y # for release candidate
# Pull latest changes
git pull origin main # or develop
git pull origin main # or the release branch
git checkout release/x.y # for release candidate
# Pull latest changes
git pull origin main # for production release
# OR
git pull origin release/x.y # for release candidate
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONTRIBUTING.md` around lines 225 - 228, Clarify the release candidate
instructions around the git pull command: show the release-branch variant
explicitly, such as pulling from origin release/x.y, instead of leaving “or the
release branch” as an ambiguous comment. Preserve the existing main-branch
command for non-release workflows.

```

2. **Create and push a tag**:
Expand Down Expand Up @@ -255,7 +255,7 @@ The release process includes these automated steps:
3. **Install** dependencies
4. **Build** the library using `pnpm ci:build`
5. **Bump version** in package.json based on the git tag
6. **Publish** to NPM using `release-it`
6. **Publish** to NPM using `pnpm publish` (both `@raystack/apsara` and `@raystack/tools-config`)
7. **Generate** GitHub release notes

### NPM Publishing
Expand Down
18 changes: 5 additions & 13 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,9 @@ apsara/
├── apps/
│ ├── www/ # Documentation website (Fumadocs)
├── packages/
│ ├── eslint-config-custom/ # Shared ESLint configuration
│ ├── plugin-vscode/ # VS Code extension for Apsara
│ ├── raystack/ # Main Apsara component library
│ └── tsconfig/ # Shared TypeScript configurations
│ └── tools-config/ # Shared Biome and TypeScript configurations
├── .github/
│ └── workflows/ # GitHub Actions for CI/CD
├── pnpm-workspace.yaml # pnpm workspace configuration
Expand Down Expand Up @@ -277,14 +276,7 @@ Configuration files:

### Common Issues

1. **ESLint Configuration Errors**:
```bash
# If you encounter ESLint parsing errors
# The build process will still work, but linting may fail
# This is a known configuration issue with the current setup
```

2. **Node.js Version Issues**:
1. **Node.js Version Issues**:
```bash
# Ensure you're using Node.js 22+
node --version
Expand All @@ -293,7 +285,7 @@ Configuration files:
nvm use 22
```

3. **pnpm Version Issues**:
2. **pnpm Version Issues**:
```bash
# Ensure you're using the correct pnpm version
pnpm --version
Expand All @@ -302,7 +294,7 @@ Configuration files:
npm install -g pnpm@9.3.0
```

4. **Build Failures**:
3. **Build Failures**:
```bash
# Clean and reinstall if builds fail
pnpm clean
Expand All @@ -311,7 +303,7 @@ Configuration files:
pnpm build:apsara
```

5. **Test Failures**:
4. **Test Failures**:
```bash
# Some tests may be failing in the current codebase
# Focus on not introducing new test failures
Expand Down
26 changes: 26 additions & 0 deletions apps/www/src/components/playground/otp-field-examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,27 @@ function ControlledOTP() {
);
}

function InvalidOTP() {
const [error, setError] = useState<string>();
return (
<Field
label='Verification code'
description='The correct code is 123456.'
error={error}
>
<OTPField
length={6}
onValueChange={() => setError(undefined)}
onValueComplete={value => {
if (value !== '123456') setError('Incorrect code. Try again.');
}}
>
{renderSlots(6)}
</OTPField>
</Field>
);
}

function CompleteOTP() {
const [submitted, setSubmitted] = useState('');
return (
Expand Down Expand Up @@ -93,6 +114,11 @@ export function OTPFieldExamples() {
<CompleteOTP />
</Flex>

<Flex direction='column' gap={9}>
<Text>Invalid (a wrong code shakes):</Text>
<InvalidOTP />
</Flex>

<Flex direction='column' gap={9}>
<Text>Disabled:</Text>
<OTPField length={6} disabled defaultValue='123'>
Expand Down
3 changes: 0 additions & 3 deletions packages/raystack/.np-config.json

This file was deleted.

115 changes: 29 additions & 86 deletions packages/raystack/README.md
Original file line number Diff line number Diff line change
@@ -1,123 +1,66 @@
# Apsara
# Apsara 🧚‍♀️

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?logo=apache)](LICENSE) [![Formatted with Biome](https://img.shields.io/badge/Formatted_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev/) [![Linted with Biome](https://img.shields.io/badge/Linted_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) [![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev)
[![npm version](https://img.shields.io/npm/v/@raystack/apsara?logo=npm&color=cb3837)](https://www.npmjs.com/package/@raystack/apsara)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?logo=apache)](LICENSE)
[![Biome](https://img.shields.io/badge/Biome-60a5fa?logo=biome&logoColor=white)](https://biomejs.dev/)

Apsara 🧚‍♀️ is an open-source React UI component library built on Base UI primitives. It provides enterprise-grade, accessible components designed for building complex data interfaces.
Apsara is an open-source React component library for building accessible, data-heavy interfaces. It is built on [Base UI](https://base-ui.com/) primitives and written in TypeScript.

<p align="center"><img width=80% src="./apps/www/public/banner.png" /></p>

## Key Features

- **Accessible Components**: Built on Base UI primitives ensuring ARIA compliance and keyboard navigation
- **Flexible Styling**: Uses vanilla CSS with HTML data-attributes for powerful theming and style customization
- **Enterprise Ready**: Designed for complex data-driven applications with components like:
- Data Tables
- Navigation Systems
- Form Controls
- Feedback Components
- **Type Safe**: Written in TypeScript with comprehensive type definitions
- **Modern Stack**: Support for React 18+ and modern development practices

## Installation
## Install

```sh
npm install @raystack/apsara
# or
pnpm add @raystack/apsara
```

Requires React 19.

## Usage

```jsx
// Add Style import in the root of the project.
// Import the styles once, at the root of your app.
import "@raystack/apsara/style.css";

// Import components
import { Button, Flex } from "@raystack/apsara";

function App() {
export default function App() {
return (
<Flex>
<Button type="primary">I am using 🧚‍♀️ Apsara!</Button>
<Button variant="solid">Hello from Apsara 🧚‍♀️</Button>
</Flex>
);
}
```

## Component Categories

### Layout

- `Box` - Basic layout container
- `Flex` - Flexbox container
- `Container` - Responsive wrapper
- `Sidebar` - Collapsible navigation panel

### Navigation

- `Breadcrumb` - Navigation breadcrumbs
- `Tabs` - Tabbed interface
- `Command` - Command palette interface

### Data Display

- `Table` - Data table component
- `Avatar` - User avatar display
- `Badge` - Status indicators
- `EmptyState` - Empty state messaging

### Forms
Icons and hooks ship as separate entry points:

- `Select` - Dropdown selection
- `Radio` - Radio button groups
- `IconButton` - Icon-only buttons

### Feedback

- `Tooltip` - Contextual tooltips
- `Callout` - Informational callouts
- `Indicator` - Status indicators

### Overlay
```jsx
import { ChevronDownIcon } from "@raystack/apsara/icons";
import { useCopyToClipboard } from "@raystack/apsara/hooks";
```

- `Popover` - Contextual overlays
- `Drawer` - Slide-out panels with swipe-to-dismiss
- `Dialog` - Modal dialogs
## What's inside

## Documentation
Over 70 components, styled with plain CSS and `data-*` attributes so you can theme them with CSS variables. A few highlights:

Visit our [documentation site](https://apsara.raystack.org) for:
- **Layout** — Box, Flex, Grid, Container, Sidebar, ScrollArea
- **Navigation** — Tabs, Breadcrumb, Command, Menu, Navbar, Toolbar
- **Data** — Table, DataTable, DataView, Avatar, Badge, Chip, Meter
- **Forms** — Input, Select, Combobox, Checkbox, Radio, Switch, Slider, Calendar, ColorPicker
- **Feedback** — Toast, Tooltip, Callout, Spinner, Indicator
- **Overlay** — Dialog, Popover, Drawer, ContextMenu

- Interactive examples
- API references
- Theme customization
- Accessibility guidelines
- Migration guides
See the [documentation site](https://apsara.raystack.org) for the full list, live examples, and API references.

## Contributing

We welcome contributions! Here's how you can help:

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

### Development Setup
Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the workflow and [DEVELOPMENT.md](./DEVELOPMENT.md) for local setup.

```sh
# Install dependencies
pnpm install

# Start development server
pnpm dev

# Run tests
pnpm test

# Build library
pnpm build
pnpm install # install dependencies
pnpm start # run the library and docs site
pnpm test # run tests
```

## License
Expand Down
21 changes: 17 additions & 4 deletions packages/raystack/components/accordion/accordion.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,20 @@
border-top: none;
}

.accordion-trigger:hover,
.accordion-trigger:focus-visible {
.accordion-trigger:hover {
background-color: var(--rs-color-background-base-primary-hover);
}

/* Trigger sits flush in a clipped container: keep the ring inside. */
.accordion-trigger:focus-visible {
outline: var(--rs-focus-ring);
outline-offset: var(--rs-focus-ring-offset-inset);
}

.accordion-trigger:active:not(:disabled) {
background-color: var(--rs-color-background-neutral-secondary);
}

.accordion-trigger:disabled {
pointer-events: none;
opacity: 0.5;
Expand Down Expand Up @@ -80,10 +89,14 @@

@media (prefers-reduced-motion: no-preference) {
.accordion-icon {
transition: transform 150ms ease-in-out;
transition: transform var(--rs-duration-fast) var(--rs-ease-in-out);
}

.accordion-content {
transition: height 150ms ease-out;
transition: height var(--rs-duration-fast) var(--rs-ease-out);
}

.accordion-trigger {
transition: var(--rs-transition-interactive);
}
}
3 changes: 3 additions & 0 deletions packages/raystack/components/amount/amount.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.amount {
font-variant-numeric: tabular-nums;
}
15 changes: 13 additions & 2 deletions packages/raystack/components/amount/amount.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { cx } from 'class-variance-authority';
import { type ComponentProps } from 'react';
import styles from './amount.module.css';

export interface AmountProps extends ComponentProps<'span'> {
/**
Expand Down Expand Up @@ -167,6 +169,7 @@ export const Amount = ({
groupDigits = true,
valueInMinorUnits = true,
hideCurrency = false,
className,
...props
}: AmountProps) => {
try {
Expand Down Expand Up @@ -265,10 +268,18 @@ export const Amount = ({
finalBaseValue
);

return <span {...props}>{formattedValue}</span>;
return (
<span {...props} className={cx(styles.amount, className)}>
{formattedValue}
</span>
);
} catch (error) {
console.error('Error formatting amount:', error);
return <span {...props}>{String(value)}</span>;
return (
<span {...props} className={cx(styles.amount, className)}>
{String(value)}
</span>
);
}
};

Expand Down
Loading
Loading