Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9449ba5
feat(calendar-preview): foundation — root, trigger, content, grid
Shreyag02 Aug 29, 2026
0746e02
feat(calendar-preview): typable RangeInput, plus lock and validity
Shreyag02 Aug 29, 2026
461eefb
fix(calendar-preview): eight defects found auditing phase 1 and 2
Shreyag02 Aug 30, 2026
eda5d48
feat(calendar-preview): Input and Nav
Shreyag02 Aug 30, 2026
49272ec
feat(calendar-preview): GranularityTabs
Shreyag02 Aug 30, 2026
d4c974d
fix(calendar-preview): four defects from a second audit
Shreyag02 Aug 30, 2026
788d22a
feat(calendar-preview): MonthGrid
Shreyag02 Aug 30, 2026
5e3afa6
feat(calendar-preview): Footer, Apply, Cancel and commit='explicit'
Shreyag02 Aug 30, 2026
04cb90c
docs(calendar-preview): component page, demos and playground
Shreyag02 Aug 30, 2026
1fda99f
feat(calendar-preview): TimeField
Shreyag02 Aug 30, 2026
0278fc6
fix(calendar-preview): publish the types consumers need to wrap it
Shreyag02 Aug 30, 2026
85d9d2e
chore(deps): dayjs 1.11.23, @base-ui/utils 0.3.2, @base-ui/react 1.7.0
Shreyag02 Aug 30, 2026
4f8180a
chore(deps): react-day-picker 10.0.1
Shreyag02 Aug 30, 2026
d0a2ed6
fix(calendar-preview): two defects from a cross-part audit
Shreyag02 Aug 30, 2026
b7dcd48
feat(calendar-preview)!: phase 4 integrations
Shreyag02 Aug 30, 2026
326ae5c
feat(calendar-preview): Nav revert-to-default button
Shreyag02 Aug 30, 2026
d6faeb8
feat(calendar-preview): granularity-aware value and typed field
Shreyag02 Aug 30, 2026
fd4c467
feat(calendar-preview): cross-granularity parsing in the typed fields
Shreyag02 Aug 30, 2026
6498400
feat(calendar-preview): Presets and Preset
Shreyag02 Aug 30, 2026
867cbff
fix(calendar-preview): publish a missing type, and stop the drift rec…
Shreyag02 Aug 30, 2026
5fa3ce9
feat(calendar-preview): loading state
Shreyag02 Aug 30, 2026
60adf1b
chore: drop unrelated formatting churn from the diff
Shreyag02 Aug 30, 2026
04b21ef
chore: restore the two hook files the formatter kept re-churning
Shreyag02 Aug 30, 2026
b761e1e
fix(calendar-preview): seven defects from the external audit
Shreyag02 Aug 30, 2026
f4e9b9e
fix(calendar-preview): the rest of the external audit, 02 and 08–23
Shreyag02 Aug 30, 2026
10ee5e5
fix(calendar-preview): the audit's second pass, 24–28, and a range in…
Shreyag02 Aug 31, 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
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 @@ -62,7 +62,7 @@ import { DemoProps } from './types';
export default function Demo(props: DemoProps) {
const {
data,
// `...Apsara` carries the 31 icons Apsara publishes, so none of those needs
// `...Apsara` carries the 32 icons Apsara publishes, so none of those needs
// 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,
Expand Down
257 changes: 257 additions & 0 deletions apps/www/src/content/docs/components/calendar-preview/demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
'use client';

import { getPropsString } from '@/lib/utils';

export const preview = {
type: 'code',
tabs: [
{
name: 'Inline',
code: `<CalendarPreview defaultMonth={new Date(2024, 3, 1)}>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview>`
},
{
name: 'Date picker',
code: `<CalendarPreview>
<CalendarPreview.Trigger>
<CalendarPreview.Input />
</CalendarPreview.Trigger>
<CalendarPreview.Content>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview.Content>
</CalendarPreview>`
},
{
name: 'Range picker',
code: `<CalendarPreview selection="range">
<CalendarPreview.Trigger>
<CalendarPreview.RangeInput />
</CalendarPreview.Trigger>
<CalendarPreview.Content>
<CalendarPreview.Nav months={2} />
<CalendarPreview.Grid months={2} />
</CalendarPreview.Content>
</CalendarPreview>`
}
]
};

export const stateDemo = {
type: 'code',
tabs: [
{
name: 'Open state',
code: `<CalendarPreview defaultOpen onOpenChange={(open) => console.log(open)}>
<CalendarPreview.Trigger>
<CalendarPreview.Input />
</CalendarPreview.Trigger>
<CalendarPreview.Content>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview.Content>
</CalendarPreview>`
},
{
name: 'Visible month',
code: `<CalendarPreview defaultMonth={new Date(2020, 0, 1)}>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview>`
},
{
name: 'Bounds',
code: `<CalendarPreview
defaultMonth={new Date(2024, 3, 1)}
minDate={new Date(2024, 3, 10)}
maxDate={new Date(2024, 3, 20)}
>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview>`
},
{
name: 'Unavailable days',
code: `<CalendarPreview
defaultMonth={new Date(2024, 3, 1)}
isDateUnavailable={(date) => date.getDay() === 0 || date.getDay() === 6}
>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview>`
}
]
};

export const granularityDemo = {
type: 'code',
tabs: [
{
name: 'Switchable',
code: `<CalendarPreview
defaultMonth={new Date(2024, 3, 1)}
granularities={['day', 'month', 'quarter', 'half-year', 'year']}
>
<CalendarPreview.GranularityTabs />
<CalendarPreview.Nav />
<CalendarPreview.Grid />
<CalendarPreview.MonthGrid />
</CalendarPreview>`
},
{
name: 'Month only',
code: `<CalendarPreview defaultGranularity="month">
<CalendarPreview.MonthGrid />
</CalendarPreview>`
},
{
name: 'Quarter',
code: `<CalendarPreview defaultGranularity="quarter">
<CalendarPreview.MonthGrid />
</CalendarPreview>`
}
]
};

export const commitDemo = {
type: 'code',
tabs: [
{
name: 'Explicit commit',
code: `<CalendarPreview commit="explicit" defaultMonth={new Date(2024, 3, 1)} defaultOpen>
<CalendarPreview.Trigger>
<CalendarPreview.Input />
</CalendarPreview.Trigger>
<CalendarPreview.Content>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
<CalendarPreview.Footer>
<CalendarPreview.Cancel />
<CalendarPreview.Apply />
</CalendarPreview.Footer>
</CalendarPreview.Content>
</CalendarPreview>`
},
{
name: 'Locked endpoint',
code: `<CalendarPreview
selection="range"
lock="from"
defaultMonth={new Date(2024, 3, 1)}
defaultValue={{ from: new Date(2024, 3, 10), to: null }}
>
<CalendarPreview.RangeInput />
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview>`
}
]
};

export const presetDemo = {
type: 'code',
code: `<CalendarPreview selection="range" defaultMonth={new Date(2024, 3, 1)}>
<CalendarPreview.Presets>
<CalendarPreview.Preset range={{ from: new Date(2024, 3, 11), to: new Date(2024, 3, 17) }}>
Last 7 days
</CalendarPreview.Preset>
<CalendarPreview.Preset range={{ from: new Date(2024, 2, 19), to: new Date(2024, 3, 17) }}>
Last 30 days
</CalendarPreview.Preset>
<CalendarPreview.Preset range={{ from: new Date(2024, 3, 1), to: new Date(2024, 3, 30) }}>
This month
</CalendarPreview.Preset>
</CalendarPreview.Presets>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview>`
};

export const loadingDemo = {
type: 'code',
code: `<CalendarPreview loading defaultMonth={new Date(2024, 3, 1)}>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview>`
};

export const fieldDemo = {
type: 'code',
code: `<Field>
<Field.Label>Starts</Field.Label>
<CalendarPreview>
<CalendarPreview.Trigger>
<CalendarPreview.Input />
</CalendarPreview.Trigger>
<CalendarPreview.Content>
<CalendarPreview.Nav />
<CalendarPreview.Grid />
</CalendarPreview.Content>
</CalendarPreview>
<Field.Error />
</Field>`
};

export const getCode = (props: Record<string, unknown>) => {
const {
selection = 'single',
months = '1',
switchable = false,
withFooter = false,
...rest
} = props;

const monthCount = Number(months);
const rootProps = getPropsString({
...(selection !== 'single' ? { selection } : {}),
...(switchable
? { granularities: ['day', 'month', 'quarter', 'half-year', 'year'] }
: {}),
...(withFooter ? { commit: 'explicit' } : {}),
...rest
});

const input =
selection === 'range'
? '<CalendarPreview.RangeInput />'
: '<CalendarPreview.Input />';

const monthsProp = monthCount > 1 ? ` months={${monthCount}}` : '';

return `<CalendarPreview${rootProps} defaultMonth={new Date(2024, 3, 1)}>
<CalendarPreview.Trigger>
${input}
</CalendarPreview.Trigger>
<CalendarPreview.Content>
${switchable ? ' <CalendarPreview.GranularityTabs />\n' : ''} <CalendarPreview.Nav${monthsProp} />
<CalendarPreview.Grid${monthsProp} />
${switchable ? ' <CalendarPreview.MonthGrid />\n' : ''}${
withFooter
? ` <CalendarPreview.Footer>
<CalendarPreview.Cancel />
<CalendarPreview.Apply />
</CalendarPreview.Footer>\n`
: ''
} </CalendarPreview.Content>
</CalendarPreview>`;
};

export const playground = {
type: 'playground',
controls: {
selection: {
type: 'select',
options: ['single', 'range', 'multiple'],
defaultValue: 'single'
},
months: { type: 'select', options: ['1', '2'], defaultValue: '1' },
switchable: { type: 'checkbox', defaultValue: false },
withFooter: { type: 'checkbox', defaultValue: false },
disabled: { type: 'checkbox', defaultValue: false },
readOnly: { type: 'checkbox', defaultValue: false },
format: { type: 'text', initialValue: 'DD MMM YYYY' }
},
getCode
};
Loading
Loading