Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion apps/www/src/app/docs/[[...slug]]/page.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
/*
The rail's inner edge, matching the one on the sidebar. It starts below the
navbar rather than at the top of the screen, because above that line the
navbar is one strip running the width of the article there is nothing
navbar is one strip running the width of the article, and there is nothing
there for the rule to divide.
*/
border-left: var(--docs-rule);
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/app/examples/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const metadata = {
* Bare examples landing page.
*
* `/examples` is a manual-QA harness for trying Apsara components in a
* full-page context the kind of thing the small doc demos can't show.
* full-page context, the kind of thing the small doc demos can't show.
* It is not linked from the public site.
*
* To add an example, drop a new route folder next to this file, e.g.
Expand Down
18 changes: 9 additions & 9 deletions apps/www/src/app/examples/timeline-stress/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
* readout counts what is actually in the DOM and times the frames the browser
* spends while scrolling, which is the number jsdom cannot produce.
*
* Toggle `virtualized` off at 10k to see the difference and expect the tab
* Toggle `virtualized` off at 10k to see the difference, and expect the tab
* to struggle, which is the point.
*/

Expand All @@ -46,13 +46,13 @@ const isoDay = (ms: number) => new Date(ms).toISOString().slice(0, 10);
/**
* Hoisted so the reference is stable. The timeline memoizes its resolved
* markers on this prop, and an inline literal would invalidate that memo on
* every commit churn this page would then report as its own frame cost.
* every commit, churn this page would then report as its own frame cost.
*/
const MARKERS: TimelineMarker[] = [
{ date: '2025-07-01', label: 'H2', variant: 'accent' }
];

/** Seeded LCG the same row count always renders the same canvas. */
/** Seeded LCG, so the same row count always renders the same canvas. */
function seededRandom(seed: number) {
let state = seed;
return () => {
Expand Down Expand Up @@ -141,7 +141,7 @@ interface Stats {
/**
* Height of a single gridline. These are pinned `top: 0; bottom: 0`, so
* unclamped they are as tall as the whole canvas and their rasterization
* cost tracks the domain rather than the viewport the dominant scroll cost
* cost tracks the domain rather than the viewport, the dominant scroll cost
* before the clamp landed. Worth watching directly: it should stay near the
* pane height, not the canvas height.
*/
Expand All @@ -150,7 +150,7 @@ interface Stats {

/**
* Worst frame over the last second of scrolling. A mean would hide exactly
* what matters one 200ms frame is a visible stall no average survives.
* what matters: one 200ms frame is a visible stall no average survives.
*
* Takes the element rather than a ref: the pane is found by query after the
* timeline paints, and assigning a ref does not re-run an effect, so a
Expand Down Expand Up @@ -228,8 +228,8 @@ export default function TimelineStressPage() {
);

/**
* The card memo compares `renderCard` by identity, so an inline arrow — what
* a consumer writes by default makes every mounted card re-render on every
* The card memo compares `renderCard` by identity, so an inline arrow, which
* a consumer writes by default, makes every mounted card re-render on every
* commit. This toggle isolates that cost from the canvas's own.
*/
const memoizedRenderCard = useCallback(
Expand All @@ -243,7 +243,7 @@ export default function TimelineStressPage() {
// a stale canvas would otherwise linger under the new settings.
const runKey = `${rowCount}-${domainDays}-${virtualized}-${onePerRow}-${grouped}`;

// biome-ignore lint/correctness/useExhaustiveDependencies: `runKey` isn't read here it's the remount signal, and re-running on it is the point.
// biome-ignore lint/correctness/useExhaustiveDependencies: `runKey` isn't read here; it's the remount signal, and re-running on it is the point.
useEffect(() => {
const start = performance.now();
// After paint, so the number covers layout of what actually mounted.
Expand Down Expand Up @@ -273,7 +273,7 @@ export default function TimelineStressPage() {
});
});
return () => cancelAnimationFrame(id);
// Re-measure whenever the run changes `runKey` also remounts the view.
// Re-measure whenever the run changes, since `runKey` also remounts the view.
}, [runKey]);

const stat = (label: string, value: string | number) => (
Expand Down
20 changes: 10 additions & 10 deletions apps/www/src/components/dataview-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ export function DataViewGroupingDemo() {
}

// ---------------------------------------------------------------------------
// Virtualized + grouping + sticky header — exercises the combined path that
// Virtualized + grouping + sticky header, exercising the combined path that
// uses the anchor pattern (single sticky element whose content swaps as you
// scroll past each group's offset).
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -527,7 +527,7 @@ export function DataViewLoadingDemo() {
}

// ---------------------------------------------------------------------------
// Per-view fields override demo Email hidden in the List view only.
// Per-view fields override demo: Email hidden in the List view only.
// ---------------------------------------------------------------------------

export function DataViewPerViewFieldsDemo() {
Expand Down Expand Up @@ -583,7 +583,7 @@ export function DataViewPerViewFieldsDemo() {
}

// ---------------------------------------------------------------------------
// Row selection demo unmanaged checkbox column + a FloatingActions bar.
// Row selection demo: unmanaged checkbox column + a FloatingActions bar.
// ---------------------------------------------------------------------------

const selectionColumn: DataViewListColumn<Person> = {
Expand Down Expand Up @@ -689,7 +689,7 @@ type Task = {
status: 'todo' | 'active' | 'done';
priority: 'High' | 'Medium' | 'Low';
/* Priority as a number. Sorting the label alphabetically gives High, Low,
Medium — this is what "sort by priority" has to mean to be useful, and it
Medium. This is what "sort by priority" has to mean to be useful, and it
is what the sort-value lane timeline lanes on. */
rank: 1 | 2 | 3;
start: string;
Expand Down Expand Up @@ -802,7 +802,7 @@ const taskFields: DataViewField<Task>[] = [
filterable: true,
filterType: 'select',
hideable: true,
// groupOrder ranks the sections when grouping by priority text sort
// groupOrder ranks the sections when grouping by priority, where text sort
// would give High, Low, Medium.
groupable: true,
showGroupCount: true,
Expand Down Expand Up @@ -849,7 +849,7 @@ const TASK_STATUS_BADGE: Record<
done: 'success'
};

/* The card interior is entirely consumer-owned — the Timeline only positions
/* The card interior is entirely consumer-owned. The Timeline only positions
the wrapper. `context.collapsed` flags spans narrower than `minCardWidth`. */
function TaskCard({
task,
Expand All @@ -859,7 +859,7 @@ function TaskCard({
context: TimelineCardContext;
}) {
// Card height is content-driven (the wrapper auto-measures, like
// DataView.List rows) fix it here so collapsed stubs match full cards.
// DataView.List rows), so fix it here and collapsed stubs match full cards.
const chrome: React.CSSProperties = {
height: 64,
boxSizing: 'border-box',
Expand Down Expand Up @@ -1031,7 +1031,7 @@ export function DataViewTimelineDemo() {
</Button>
{/* Sort can't move a card horizontally (x is time) and `auto`
packing is chronological, so Ordering is hidden. Grouping is
left in: it renders swim-lane sections try Team or Status. */}
left in: it renders swim-lane sections; try Team or Status. */}
<DataView.DisplayControls hideOrdering />
</Flex>
</DataView.Toolbar>
Expand Down Expand Up @@ -1063,7 +1063,7 @@ export function DataViewTimelineDemo() {
}

/* ── Grouped timeline demo (swim-lane sections) ────────────────────────────
`group_by` in the query is the only wiring grouping needs — the timeline
`group_by` in the query is the only wiring grouping needs. The timeline
consumes the same group rows `DataView.List` renders as section headers, so
labels, order, and counts match between the two views. Packing runs per
section, and each band pins under the axis while its section is in view. */
Expand Down Expand Up @@ -1123,7 +1123,7 @@ export function DataViewTimelineSortValueLaneDemo() {
>
<DataView.Toolbar>
<DataView.Filters />
{/* Ordering stays visible — it repositions and rebuilds lanes. */}
{/* Ordering stays visible, and repositions and rebuilds lanes. */}
<DataView.DisplayControls />
</DataView.Toolbar>
<Flex
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/demo/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function Demo(props: DemoProps) {
const {
data,
// `...Apsara` carries the 31 icons Apsara publishes, so none of those needs
// its own entry and nothing below may repeat one of their keys, because a
// its own entry, and nothing below may repeat one of their keys, because a
// later key shadows the spread. A demo that needs any other glyph names a
// lucide component from the block above and sizes it at the call site,
// which is exactly what an application does.
Expand Down
8 changes: 4 additions & 4 deletions apps/www/src/components/docs/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ type SearchItems = {
};

/* Map known page slugs to icons; everything else falls back to a generic one. */
// Section glyphs. None of these is an icon Apsara publishes — the set holds
// only what Apsara's own components draw so they come from lucide directly
// Section glyphs. None of these is an icon Apsara publishes. The set holds
// only what Apsara's own components draw, so they come from lucide directly
// and are sized at the call site.
const PAGE_ICONS: Record<string, typeof BookOpen> = {
docs: BookOpen,
Expand Down Expand Up @@ -156,7 +156,7 @@ export default function DocsSearch({ pageTree }: { pageTree: Root }) {

const items = !isSearching ? defaultItems : searchResults;

/* The `items` prop opts Command out of built-in filtering/unwrapping
/* The `items` prop opts Command out of built-in filtering/unwrapping,
results are pre-filtered by fumadocs and the grouped layout stays intact. */
const itemValues = useMemo(
() =>
Expand Down Expand Up @@ -233,7 +233,7 @@ export default function DocsSearch({ pageTree }: { pageTree: Root }) {
<EmptyState
variant='empty1'
heading='No result found'
subHeading='The keyword you’re searching for isn’t in the document—try using a different term.'
subHeading='The keyword you’re searching for isn’t in the document. Try a different term.'
icon={<WarningIcon />}
/>
)}
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/docs/sidebar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
.itemText {
overflow: visible;
}
/* Plain links: primary text in every state, no grounds — weight alone marks
/* Plain links: primary text in every state, no grounds. Weight alone marks
hover and the current page. */
.main .item {
color: var(--rs-color-foreground-base-primary);
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/docs/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function renderNode(node: Node, pathname: string): ReactNode {
node.children.length > 0
) {
// A section documented across several pages. It renders like every other
// sectionalways open with the index page listed first under its own
// section, always open, with the index page listed first under its own
// title.
return (
<Sidebar.Group
Expand Down
6 changes: 3 additions & 3 deletions apps/www/src/components/icongallery/icongallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import styles from './icongallery.module.css';
// the size, stroke and colour controls apply to all of them.
//
// The grid itself is plain elements: the icons are what the page documents, so
// their surroundings should not compete with them. The toolbar does use Apsara
// their surroundings should not compete with them. The toolbar does use Apsara,
// the colour popover is our ColorPicker, and the names come from our Tooltip.

type IconEntry = {
Expand Down Expand Up @@ -151,7 +151,7 @@ export function IconGallery() {
<Popover>
<Popover.Trigger className={styles.color}>
{/* Unset falls back to `currentColor` in CSS, which is what the
icons themselves inherit so the swatch stays honest. */}
icons themselves inherit, so the swatch stays honest. */}
<span
className={styles.swatch}
style={color ? { background: color } : undefined}
Expand Down Expand Up @@ -184,7 +184,7 @@ export function IconGallery() {
aria-label='Reset to the Apsara defaults'
>
{/* lucide direct, because a reset arrow is not a key the set
publishes so it needs the size and stroke Apsara's icons get
publishes, so it needs the size and stroke Apsara's icons get
for free. */}
<RotateCcw size={16} strokeWidth={1.5} />
</button>
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/tour-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default function TourDemo() {
</Text>
<Text size='small' variant='secondary'>
Four steps: a centered welcome, then the search box, analytics, and
notifications each anchored and spotlighted.
notifications, each anchored and spotlighted.
</Text>
<Button onClick={() => actionsRef.current?.start()}>
<Rocket size={16} strokeWidth={1.5} /> Start tour
Expand Down
6 changes: 3 additions & 3 deletions apps/www/src/content/docs/(overview)/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,6 @@ function ThemeToggle() {

## Next steps

- [Theme Overview](/docs/theme/overview) — Configure colors, spacing, and style variants
- [Button](/docs/components/button) — Start with a common component
- [DataView](/docs/dataview) — Build data-rich interfaces
- [Theme Overview](/docs/theme/overview): configure colors, spacing, and style variants
- [Button](/docs/components/button): start with a common component
- [DataView](/docs/dataview): build data-rich interfaces
24 changes: 12 additions & 12 deletions apps/www/src/content/docs/(overview)/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ Apsara is an open-source React component library that provides enterprise-grade,

## Why Apsara?

**Accessibility first** — Every component is built on proven primitives that handle ARIA attributes, focus management, and keyboard navigation correctly. You get accessible UI without the extra work.
**Accessibility first.** Every component is built on proven primitives that handle ARIA attributes, focus management, and keyboard navigation correctly. You get accessible UI without the extra work.

**Consistent design language** — A unified token system keeps the look consistent across your application. Colors, spacing, typography, and effects all follow predictable patterns that adapt automatically to light and dark modes.
**Consistent design language.** A unified token system keeps the look consistent across your application. Colors, spacing, typography, and effects all follow predictable patterns that adapt automatically to light and dark modes.

**Production ready** — Components are designed for real-world applications: data tables with sorting and filtering, command palettes, multi-select comboboxes, and complex form controls that handle edge cases gracefully.
**Production ready.** Components are designed for real-world applications: data tables with sorting and filtering, command palettes, multi-select comboboxes, and complex form controls that handle edge cases gracefully.

**Minimal footprint** — No runtime CSS-in-JS. Styles are vanilla CSS with semantic tokens, keeping your bundle lean and your performance predictable.
**Minimal footprint.** No runtime CSS-in-JS. Styles are vanilla CSS with semantic tokens, keeping your bundle lean and your performance predictable.

## Components

Expand Down Expand Up @@ -57,14 +57,14 @@ See the [Theme Overview](/docs/theme/overview) for complete documentation.

Apsara is built with:

- **[Base UI](https://base-ui.com/)** — Headless UI components from MUI
- **[TanStack Table](https://tanstack.com/table)** — Data table utilities
- **[class-variance-authority](https://cva.style/)** — Type-safe component variants
- **TypeScript** — Full type definitions for all components and props
- **[Base UI](https://base-ui.com/)**: headless UI components from MUI
- **[TanStack Table](https://tanstack.com/table)**: data table utilities
- **[class-variance-authority](https://cva.style/)**: type-safe component variants
- **TypeScript**: full type definitions for all components and props

## Next steps

- [Getting Started](/docs/getting-started) — Install Apsara and build your first component
- [Styling](/docs/styling) — Learn how to style and customize components
- [Theme Overview](/docs/theme/overview) — Learn about the theming system
- [Components](/docs/components/button) — Explore the component library
- [Getting Started](/docs/getting-started): install Apsara and build your first component
- [Styling](/docs/styling): style and customize components
- [Theme Overview](/docs/theme/overview): how the theming system works
- [Components](/docs/components/button): browse the component library
Loading
Loading