Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
092a395
feat(date): migrate to temporal polyfill
epr3 Jan 24, 2026
9a4f7f4
feat(Calendar): migrate calendar to temporal
epr3 Jan 24, 2026
384cf34
feat(DateField): migrate DateField to temporal
epr3 Jan 24, 2026
939ef76
feat(DatePicker): migrate date picker to temporal
epr3 Jan 24, 2026
fd32189
feat(DateRangeField): migrate to temporal
epr3 Jan 24, 2026
2f0e8c7
feat(RangeCalendar): migrate to temporal
epr3 Jan 24, 2026
418355d
feat(TimeField): migrate to temporal
epr3 Jan 24, 2026
28b68aa
chore: update tests & stories
epr3 Jan 24, 2026
e5987b2
fix(date): fix time zone issues on zoned date time
epr3 Feb 6, 2026
a928d67
fix(TimeField): return original object passed through
epr3 Feb 6, 2026
723818e
fix(useCalendar): fix toDate conversion
epr3 Feb 6, 2026
066b996
fix(TimeField): type check issues
epr3 Feb 6, 2026
58348e8
feat(date): migrate after rebase
epr3 Mar 21, 2026
a528a6a
chore(date): update docs
epr3 Mar 21, 2026
2e4fa72
chore(deps): remove @internationalized/date
epr3 Mar 21, 2026
27d39db
fix(date): migrate the rest of the components to Temporal
epr3 Mar 21, 2026
6e63e2d
chore(Calendar): expand typings
epr3 May 4, 2026
cda0d82
fix(date): replace invalid Temporal era check with Intl formatToParts
epr3 May 4, 2026
d714cf4
fix(DateRangeField): use static date to prevent snapshot drift
epr3 May 4, 2026
f8c6fb0
fix(comparators): off-by-one in areAllDaysBetweenValid
epr3 May 4, 2026
3a0a6bc
refactor(date): deduplicate Matcher type, import from temporal/types
epr3 May 4, 2026
e79683b
fix(YearPicker): replace DateValue with TemporalDate in test types
epr3 May 4, 2026
c348652
fix(YearPicker): normalize today to picker calendar for current year …
epr3 May 4, 2026
66cb827
fix(YearPicker): handle single date in multiple selection mode
epr3 May 4, 2026
005b9ed
fix(YearPicker): narrow TemporalDate | undefined[] to TemporalDate[]
epr3 May 4, 2026
3d94bbc
docs: add AGENTS.md files for monorepo workspaces
epr3 May 4, 2026
c20c1dd
chore(deps): bump pnpm-lock.yaml
epr3 May 4, 2026
28c44d9
fix(shared): replace DateValue with TemporalDate
epr3 May 4, 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
41 changes: 41 additions & 0 deletions .histoire/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# .histoire

## Scope
Histoire (storybook-like) environment for component development and visual testing.

## Config
- `vite.config.ts` β€” Histoire config embedded in Vite.
- `setup.ts` β€” global setup (imports styles).
- `style.css` β€” global styles for stories.
- `tailwind.config.js` β€” Tailwind tokens for story previews.

## Story Conventions
- Stories live next to components: `packages/core/src/<Component>/story/<Component>.story.vue`.
- File naming: `<Component>.story.vue` for primary stories, `_*.vue` for internal/demo components.
- Match pattern: `**/*.story.vue` (configured in `storyMatch`).
- Story tree groups: Components, Compounds, Utilities.

## When to Touch
- Adding visual stories for new components.
- Updating story themes, logos, or tree structure.
- Fixing story rendering issues (CSS, aliases, plugins).

## Commands
| Command | What |
|---|---|
| `pnpm story:dev` | Start Histoire dev server (port 6006). |
| `pnpm --filter histoire story:build` | Build static storybook. |
| `pnpm --filter histoire story:preview` | Preview built storybook. |

## Rules
- Stories are not tests; they are visual/interactive demos.
- Keep stories self-contained; import from `@/` alias (resolves to `packages/core/src`).
- Do not add business logic to stories; use `_*.vue` helper components for demos.
- Stories should demonstrate default state + key variants.

## Alias
- `@/*` β†’ `packages/core/src/*` (configured in Histoire Vite config).

## Do-Not-Edit
- `dist/` β€” build output.
- `node_modules/` β€” dependencies.
62 changes: 62 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Reka UI Monorepo

## Repo Map
| Path | Purpose |
|---|---|
| `packages/core` | Main component library (`reka-ui`). Vue 3 + TS, Vitest tests, Histoire stories. |
| `packages/plugins` | Nuxt module, auto-import resolver, namespaced exports generator. |
| `docs` | VitePress documentation site. API meta auto-generated. |
| `.histoire` | Histoire (storybook) dev environment for components. |
| `playground/*` | Vue 3 + Nuxt smoke-test apps. |

## Canonical Commands
Run from repo root. Use `pnpm --filter <workspace>` for scoped work.

| Command | What |
|---|---|
| `pnpm lint` | Lint all workspaces (ESLint + @antfu config). |
| `pnpm lint:fix` | Auto-fix lint. |
| `pnpm --filter reka-ui test` | Run Vitest suite. |
| `pnpm --filter reka-ui test-update` | Update snapshot tests. |
| `pnpm --filter reka-ui build` | Type-check + build core. |
| `pnpm --filter plugins build` | Build plugins. |
| `pnpm --filter plugins generate` | Regenerate namespaced plugin index. |
| `pnpm docs:gen` | Regenerate API meta markdown files. |
| `pnpm docs:build` | Build docs site. |
| `pnpm story:dev` | Start Histoire dev server. |

## Change-Driven Verification Matrix
| Touched Path | Must Run |
|---|---|
| `packages/core/src/**` | `pnpm --filter reka-ui test` β†’ `pnpm --filter reka-ui build` β†’ `pnpm lint` |
| `packages/core/constant/**` | `pnpm --filter plugins generate` β†’ `pnpm --filter plugins build` |
| `packages/plugins/**` | `pnpm --filter plugins build` β†’ `pnpm lint` |
| `docs/content/**` or `docs/.vitepress/**` | `pnpm docs:gen` (if API changed) β†’ `pnpm docs:build` |
| Root `package.json` / `eslint.*` / `pnpm-workspace.yaml` | `pnpm lint` + relevant workspace build/test |

## Cross-Package Sync Checklist
When modifying **public API or adding a primitive**:
1. Export from `packages/core/src/<Component>/index.ts`.
2. Re-export from `packages/core/src/index.ts`.
3. Add component names to `packages/core/constant/components.ts`.
4. Update docs page `docs/content/docs/components/<component>.md` (anatomy, API includes).
5. Run `pnpm docs:gen` to refresh `docs/content/meta/*.md`.
6. Run `pnpm --filter plugins generate` to update namespaced exports.
7. Run full verification matrix for touched paths.

## PR / Commit Rules
- Conventional commit titles required (enforced by commit-msg hook).
- Link related issue in PR body.
- Update documentation when API/behavior changes.
- CI runs: build β†’ test β†’ lint on `packages/**` changes.

## Generated / Do-Not-Edit Files
- `docs/content/meta/*.md` β€” auto-generated by `docs:gen`.
- `packages/plugins/src/namespaced/index.ts` β€” auto-generated by `plugins generate`.
- `packages/core/dist/**` β€” build output; never hand-edit.

## Tooling Notes
- EditorConfig: 2-space indent, LF, trim trailing whitespace, final newline.
- ESLint: `@antfu/eslint-config`, Vue/TS enabled, markdown overrides for docs.
- Git hooks: lint-staged (pre-commit), commitlint (commit-msg).
- Node: 22 in CI. pnpm 10.13.1.
70 changes: 70 additions & 0 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# docs

## Scope
VitePress documentation site: pages, examples, meta generation, config.

## Directory Structure
- `content/docs/components/<name>.md` β€” component docs.
- `content/docs/guides/` β€” guides (styling, dates, SSR, etc.).
- `content/docs/utilities/` β€” utility docs (composables, helpers).
- `content/meta/*.md` β€” auto-generated API tables (props, emits, slots, methods).
- `content/examples/` β€” usage examples.
- `.vitepress/config.ts` β€” sidebar/nav config.

## Doc Page Anatomy
```md
---
title: <Component Name>
description: <One-line description>
name: <kebab-case-name>
---

# <Component Name>

<Badge>Alpha</Badge> <!-- if applicable -->

<Description>
<Repeat description>
</Description>

<ComponentPreview name="<Component>" />

## Features
<Highlights :features="[...]" />

## Preface
<!-- Temporal dependency note for date/time components -->

## Installation
<InstallationTabs value="reka-ui" />

## Anatomy
<!-- Import block + template structure -->

## API Reference
<!-- @include: @/meta/<ComponentPart>.md -->
```

## Generated Files Policy
- `content/meta/*.md` β€” generated by `docs:gen`. **Do not hand-edit.**
- Run `pnpm docs:gen` after any prop/event/slot/method signature change.
- If a component is added/removed, `docs:gen` updates meta automatically.

## When to Update Sidebar/Nav
- Edit `.vitepress/config.ts` β†’ `sidebar` array.
- Group by: Form, Color, Dates, General, Utilities.
- Add `<Badge>Alpha</Badge>` or `<Badge>New</Badge>` as needed.

## Temporal Docs Consistency
- All date/time component docs must mention `temporal-polyfill`.
- Link to `docs/guides/dates` for Temporal usage patterns.
- Use `Temporal.PlainDate`, `Temporal.PlainDateTime`, `Temporal.ZonedDateTime` in examples.

## Verification Commands
- `pnpm docs:gen` β€” regenerate API meta.
- `pnpm docs:build` β€” build docs site (catches broken links/includes).
- `pnpm docs:dev` β€” local dev server (manual check).

## Do-Not-Edit
- `content/meta/*.md` β€” auto-generated.
- `node_modules/**` β€” dependencies.
4 changes: 2 additions & 2 deletions docs/components/demo/Calendar/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script setup lang="ts">
import type { CalendarRootProps } from 'reka-ui'
import { Icon } from '@iconify/vue'
import { CalendarDate } from '@internationalized/date'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'

const date = new CalendarDate(2024, 10, 3)
const date = Temporal.PlainDate.from({ year: 2024, month: 10, day: 3 })

const isDateUnavailable: CalendarRootProps['isDateUnavailable'] = (date) => {
return date.day === 17 || date.day === 18
Expand Down
4 changes: 2 additions & 2 deletions docs/components/demo/CalendarSelect/css/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { createCalendar, getLocalTimeZone, toCalendar, today } from '@internationalized/date'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot, Label, SelectContent, SelectGroup, SelectItem, SelectItemIndicator, SelectItemText, SelectLabel, SelectPortal, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectViewport } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'
import { computed, ref } from 'vue'

const preferences = [
Expand Down Expand Up @@ -47,7 +47,7 @@ function updateLocale(newLocale: string) {
locale.value = newLocale
calendar.value = pref.value!.ordering.split(' ')[0]
}
const value = computed(() => toCalendar(today(getLocalTimeZone()), createCalendar(calendar.value)))
const value = computed(() => Temporal.Now.plainDateISO(Temporal.Now.timeZoneId()).withCalendar(calendar.value))
</script>

<template>
Expand Down
4 changes: 2 additions & 2 deletions docs/components/demo/CalendarSelect/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { createCalendar, getLocalTimeZone, toCalendar, today } from '@internationalized/date'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot, Label, SelectContent, SelectGroup, SelectItem, SelectItemIndicator, SelectItemText, SelectLabel, SelectPortal, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectViewport } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'
import { computed, ref } from 'vue'

const preferences = [
Expand Down Expand Up @@ -47,7 +47,7 @@ function updateLocale(newLocale: string) {
locale.value = newLocale
calendar.value = pref.value!.ordering.split(' ')[0]
}
const value = computed(() => toCalendar(today(getLocalTimeZone()), createCalendar(calendar.value)))
const value = computed(() => Temporal.Now.plainDateISO(Temporal.Now.timeZoneId()).withCalendar(calendar.value))
</script>

<template>
Expand Down
8 changes: 4 additions & 4 deletions docs/components/demo/CalendarSwipe/css/index.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { CalendarDate } from '@internationalized/date'
import { usePointerSwipe } from '@vueuse/core'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'
import { onMounted, ref, useTemplateRef } from 'vue'
import './styles.css'

const calendarRef = useTemplateRef('calendarRef')
const date = ref(new CalendarDate(2023, 1, 1))
const date = ref(Temporal.PlainDate.from({ year: 2023, month: 1, day: 1 }))

function nextPage() {
date.value = date.value.add({ months: 1 }).copy()
date.value = date.value.add({ months: 1 })
}

function prevPage() {
date.value = date.value.subtract({ months: 1 }).copy()
date.value = date.value.subtract({ months: 1 })
}

onMounted(() => {
Expand Down
8 changes: 4 additions & 4 deletions docs/components/demo/CalendarSwipe/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { CalendarDate } from '@internationalized/date'
import { usePointerSwipe } from '@vueuse/core'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'
import { onMounted, ref, useTemplateRef } from 'vue'

const calendarRef = useTemplateRef('calendarRef')
const date = ref(new CalendarDate(2023, 1, 1))
const date = ref(Temporal.PlainDate.from({ year: 2023, month: 1, day: 1 }))

function nextPage() {
date.value = date.value.add({ months: 1 }).copy()
date.value = date.value.add({ months: 1 })
}

function prevPage() {
date.value = date.value.subtract({ months: 1 }).copy()
date.value = date.value.subtract({ months: 1 })
}

onMounted(() => {
Expand Down
9 changes: 4 additions & 5 deletions docs/components/demo/CalendarYearIncrement/css/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script setup lang="ts">
import type { DateValue } from '@internationalized/date'
import type { CalendarRootProps } from 'reka-ui'
import type { CalendarRootProps, TemporalDate } from 'reka-ui'
import { Icon } from '@iconify/vue'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'reka-ui'
import './styles.css'
Expand All @@ -9,7 +8,7 @@ const isDateUnavailable: CalendarRootProps['isDateUnavailable'] = (date) => {
return date.day === 17 || date.day === 18
}

function pagingFunc(date: DateValue, sign: -1 | 1) {
function pagingFunc(date: TemporalDate, sign: -1 | 1) {
if (sign === -1)
return date.subtract({ years: 1 })
return date.add({ years: 1 })
Expand All @@ -26,7 +25,7 @@ function pagingFunc(date: DateValue, sign: -1 | 1) {
<CalendarHeader class="CalendarHeader">
<CalendarPrev
class="CalendarNavButton"
:prev-page="(date: DateValue) => pagingFunc(date, -1)"
:prev-page="(date: TemporalDate) => pagingFunc(date, -1)"
>
<Icon
icon="radix-icons:double-arrow-left"
Expand All @@ -53,7 +52,7 @@ function pagingFunc(date: DateValue, sign: -1 | 1) {

<CalendarNext
class="CalendarNavButton"
:next-page="(date: DateValue) => pagingFunc(date, 1)"
:next-page="(date: TemporalDate) => pagingFunc(date, 1)"
>
<Icon
icon="radix-icons:double-arrow-right"
Expand Down
9 changes: 4 additions & 5 deletions docs/components/demo/CalendarYearIncrement/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
<script setup lang="ts">
import type { DateValue } from '@internationalized/date'
import type { CalendarRootProps } from 'reka-ui'
import type { CalendarRootProps, TemporalDate } from 'reka-ui'
import { Icon } from '@iconify/vue'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'reka-ui'

const isDateUnavailable: CalendarRootProps['isDateUnavailable'] = (date) => {
return date.day === 17 || date.day === 18
}

function pagingFunc(date: DateValue, sign: -1 | 1) {
function pagingFunc(date: TemporalDate, sign: -1 | 1) {
if (sign === -1)
return date.subtract({ years: 1 })
return date.add({ years: 1 })
Expand All @@ -25,7 +24,7 @@ function pagingFunc(date: DateValue, sign: -1 | 1) {
<CalendarHeader class="flex items-center justify-between">
<CalendarPrev
class="inline-flex items-center cursor-pointer text-black justify-center rounded-[9px] bg-transparent w-8 h-8 hover:bg-black hover:text-white active:scale-98 active:transition-all focus:shadow-[0_0_0_2px] focus:shadow-black"
:prev-page="(date: DateValue) => pagingFunc(date, -1)"
:prev-page="(date: TemporalDate) => pagingFunc(date, -1)"
>
<Icon
icon="radix-icons:double-arrow-left"
Expand Down Expand Up @@ -53,7 +52,7 @@ function pagingFunc(date: DateValue, sign: -1 | 1) {

<CalendarNext
class="inline-flex items-center cursor-pointer justify-center text-black rounded-[9px] bg-transparent w-8 h-8 hover:bg-black hover:text-white active:scale-98 active:transition-all focus:shadow-[0_0_0_2px] focus:shadow-black"
:next-page="(date: DateValue) => pagingFunc(date, 1)"
:next-page="(date: TemporalDate) => pagingFunc(date, 1)"
>
<Icon
icon="radix-icons:double-arrow-right"
Expand Down
4 changes: 2 additions & 2 deletions docs/components/demo/MonthPicker/css/index.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { CalendarDate } from '@internationalized/date'
import { MonthPickerCell, MonthPickerCellTrigger, MonthPickerGrid, MonthPickerGridBody, MonthPickerGridRow, MonthPickerHeader, MonthPickerHeading, MonthPickerNext, MonthPickerPrev, MonthPickerRoot } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'
import './styles.css'

const date = new CalendarDate(2024, 10, 1)
const date = Temporal.PlainDate.from({ year: 2024, month: 10, day: 1 })
</script>

<template>
Expand Down
4 changes: 2 additions & 2 deletions docs/components/demo/MonthPicker/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { CalendarDate } from '@internationalized/date'
import { MonthPickerCell, MonthPickerCellTrigger, MonthPickerGrid, MonthPickerGridBody, MonthPickerGridRow, MonthPickerHeader, MonthPickerHeading, MonthPickerNext, MonthPickerPrev, MonthPickerRoot } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'

const date = new CalendarDate(2024, 10, 1)
const date = Temporal.PlainDate.from({ year: 2024, month: 10, day: 1 })
</script>

<template>
Expand Down
6 changes: 3 additions & 3 deletions docs/components/demo/MonthRangePicker/css/index.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { CalendarDate } from '@internationalized/date'
import { MonthRangePickerCell, MonthRangePickerCellTrigger, MonthRangePickerGrid, MonthRangePickerGridBody, MonthRangePickerGridRow, MonthRangePickerHeader, MonthRangePickerHeading, MonthRangePickerNext, MonthRangePickerPrev, MonthRangePickerRoot } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'
import './styles.css'

const defaultValue = {
start: new CalendarDate(2024, 3, 1),
end: new CalendarDate(2024, 6, 1),
start: Temporal.PlainDate.from({ year: 2024, month: 3, day: 1 }),
end: Temporal.PlainDate.from({ year: 2024, month: 6, day: 1 }),
}
</script>

Expand Down
6 changes: 3 additions & 3 deletions docs/components/demo/MonthRangePicker/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { CalendarDate } from '@internationalized/date'
import { MonthRangePickerCell, MonthRangePickerCellTrigger, MonthRangePickerGrid, MonthRangePickerGridBody, MonthRangePickerGridRow, MonthRangePickerHeader, MonthRangePickerHeading, MonthRangePickerNext, MonthRangePickerPrev, MonthRangePickerRoot } from 'reka-ui'
import { Temporal } from 'temporal-polyfill'

const defaultValue = {
start: new CalendarDate(2024, 3, 1),
end: new CalendarDate(2024, 6, 1),
start: Temporal.PlainDate.from({ year: 2024, month: 3, day: 1 }),
end: Temporal.PlainDate.from({ year: 2024, month: 6, day: 1 }),
}
</script>

Expand Down
Loading
Loading