{"_id":"@amirs/datepicker","_rev":"2-1693d93c5404ab6731e85ce3f3e57169","name":"@amirs/datepicker","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@amirs/datepicker","version":"0.1.0","keywords":["react","typescript","datepicker","date-range","timeline","shadcn","radix-ui"],"license":"MIT","_id":"@amirs/datepicker@0.1.0","maintainers":[{"name":"amirs","email":"amir.saboury@gmail.com"}],"homepage":"https://github.com/amir-s/datepicker#readme","bugs":{"url":"https://github.com/amir-s/datepicker/issues"},"dist":{"shasum":"781bf8c71c610e821d7f6cee8d2f66994f5c4b11","tarball":"https://registry.npmjs.org/@amirs/datepicker/-/datepicker-0.1.0.tgz","fileCount":7,"integrity":"sha512-eXhCRRgWTiLYu+f+OpHtNtqq1TqeC22/f+QniQwmcNtE11YPnEquvVVViqZnWNQiI8cAcZyozTjexmgeLb9yrw==","signatures":[{"sig":"MEQCICnc2FAQGKtElBdk/6m653IkAqjqrLzzPV9XpQ8SJsxWAiAeqB1zbb73I+xfeZUx4S65EKarOLAaYTth3CsuTM8qUg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":158214},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles.css":"./dist/datepicker.css"},"gitHead":"95d02814377e539873f888f93328258e7d632dbf","scripts":{"dev":"vite build --watch","test":"vitest run","build":"vite build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"amirs","email":"amir.saboury@gmail.com"},"repository":{"url":"git+https://github.com/amir-s/datepicker.git","type":"git","directory":"packages/datepicker"},"_npmVersion":"11.3.0","description":"An adaptive, chart-ready timeline date range picker for React and shadcn/ui.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.0.2","dependencies":{"clsx":"^2.1.1","date-fns":"^4.4.0","lucide-react":"^1.24.0","tailwind-merge":"^3.6.0","react-day-picker":"^10.0.1","@radix-ui/react-dialog":"^1.1.19","@radix-ui/react-popover":"^1.1.19"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":"^18.2.0 || ^19.0.0","react-dom":"^18.2.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/datepicker_0.1.0_1783726004050_0.409857047705799","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@amirs/datepicker","version":"0.1.1","description":"An adaptive, chart-ready timeline date range picker for React and shadcn/ui.","license":"MIT","homepage":"https://github.com/amir-s/datepicker#readme","repository":{"type":"git","url":"git+https://github.com/amir-s/datepicker.git","directory":"packages/datepicker"},"bugs":{"url":"https://github.com/amir-s/datepicker/issues"},"keywords":["react","typescript","datepicker","date-range","timeline","shadcn","radix-ui"],"type":"module","sideEffects":["**/*.css"],"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles.css":"./dist/datepicker.css"},"publishConfig":{"access":"public"},"scripts":{"dev":"vite build --watch","build":"vite build","typecheck":"tsc --noEmit","test":"vitest run"},"peerDependencies":{"react":"^18.2.0 || ^19.0.0","react-dom":"^18.2.0 || ^19.0.0"},"dependencies":{"@radix-ui/react-dialog":"^1.1.19","@radix-ui/react-popover":"^1.1.19","clsx":"^2.1.1","date-fns":"^4.4.0","lucide-react":"^1.24.0","react-day-picker":"^10.0.1","tailwind-merge":"^3.6.0"},"_id":"@amirs/datepicker@0.1.1","gitHead":"7f2d1f218b6c70541e75cd5b0b7dba92d5b208a3","_nodeVersion":"24.0.2","_npmVersion":"11.3.0","dist":{"integrity":"sha512-PwB9DKnMZrDlSXz4eazeXMud/VcQJgIgTY1GLCXKd5uuGX4Ru1JbcRJ351MsTPkFYxU/S2Cn3IN+kT3m5abMsw==","shasum":"02985a7c17a61a56b9b8f0cce0a7199b97c7a10d","tarball":"https://registry.npmjs.org/@amirs/datepicker/-/datepicker-0.1.1.tgz","fileCount":7,"unpackedSize":158749,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIB+S9vjfL1rZPe6Uc3a8vg+UfOKR8bD21DaiUBJGOzRfAiEA+TK4gdLxtxfHZQ3LdjN1SOrvAcHq4UHLZzxuUGv8R7A="}]},"_npmUser":{"name":"amirs","email":"amir.saboury@gmail.com"},"directories":{},"maintainers":[{"name":"amirs","email":"amir.saboury@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/datepicker_0.1.1_1783748198268_0.15999228792000086"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-10T23:26:43.851Z","modified":"2026-07-11T05:36:38.531Z","0.1.0":"2026-07-10T23:26:44.161Z","0.1.1":"2026-07-11T05:36:38.414Z"},"bugs":{"url":"https://github.com/amir-s/datepicker/issues"},"license":"MIT","homepage":"https://github.com/amir-s/datepicker#readme","keywords":["react","typescript","datepicker","date-range","timeline","shadcn","radix-ui"],"repository":{"type":"git","url":"git+https://github.com/amir-s/datepicker.git","directory":"packages/datepicker"},"description":"An adaptive, chart-ready timeline date range picker for React and shadcn/ui.","maintainers":[{"name":"amirs","email":"amir.saboury@gmail.com"}],"readme":"# @amirs/datepicker\n\nA shadcn-compatible React timeline date range picker with presets, responsive\nticks, adaptive zoom, chart composition, and an accessible calendar fallback.\n\n## Inspiration and disclosure\n\nThis is an independent implementation inspired by the original\n[RangeFlow](https://rangeflow.raminmousavi.dev/) timeline range picker.\nRangeFlow's compact combination of a draggable selection, quick ranges, and a\ncalendar established the core interaction direction; this library extends it\nwith responsive ticks, adaptive and fixed zoom, controlled viewports, chart\ncomposition, and shadcn semantics.\n\nThis project was designed and built with AI assistance.\n\n## Installation\n\n```bash\nnpm install @amirs/datepicker\n```\n\nReact and React DOM are peer dependencies. React 18.2+ and React 19 are\nsupported.\n\n```tsx\nimport {\n  TimelineDateRangePicker,\n  type DatePreset,\n} from \"@amirs/datepicker\"\nimport \"@amirs/datepicker/styles.css\"\n\nconst presets: DatePreset[] = [\n  {\n    id: \"last-30-days\",\n    label: \"Last 30 days\",\n    range: today => ({\n      from: new Date(\n        today.getFullYear(),\n        today.getMonth(),\n        today.getDate() - 29,\n      ),\n      to: today,\n    }),\n  },\n]\n\nexport function DateRangeField() {\n  return (\n    <TimelineDateRangePicker\n      ariaLabel=\"Report date range\"\n      defaultValue={{\n        from: new Date(2026, 6, 1),\n        to: new Date(2026, 6, 10),\n      }}\n      presets={presets}\n    />\n  )\n}\n```\n\nDates use the native zero-based month index. Both endpoints are inclusive and\nare normalized to local calendar-day starts.\n\n## Controlled selection and viewport\n\nSelection and viewport state can be controlled separately. `onValueChange`\nruns during an interaction; `onValueCommit` runs when a drag, resize, keyboard,\npreset, or calendar interaction is committed.\n\n```tsx\nimport * as React from \"react\"\nimport {\n  TimelineDateRangePicker,\n  type DateRange,\n} from \"@amirs/datepicker\"\nimport \"@amirs/datepicker/styles.css\"\n\nexport function ControlledRange() {\n  const [value, setValue] = React.useState<DateRange>({\n    from: new Date(2026, 6, 1),\n    to: new Date(2026, 6, 10),\n  })\n  const [viewport, setViewport] = React.useState<DateRange>({\n    from: new Date(2026, 5, 15),\n    to: new Date(2026, 6, 29),\n  })\n\n  return (\n    <TimelineDateRangePicker\n      ariaLabel=\"Report date range\"\n      value={value}\n      onValueChange={setValue}\n      onValueCommit={range => console.log(\"Committed range\", range)}\n      viewport={viewport}\n      onViewportChange={setViewport}\n      zoomMode=\"fixed\"\n      showPanControls\n    />\n  )\n}\n```\n\nIn `auto` mode, the component selects the smallest configured zoom level that\nfits the committed selection and centers it. Resizing keeps the current\nviewport stable until commit. In `fixed` mode, viewport duration is preserved;\nout-of-view selections pan into view and selections longer than the viewport\nare prevented.\n\nThe built-in adaptive levels are:\n\n| Selected range | Viewport | Minimum selection |\n| --- | ---: | ---: |\n| Up to 7 days | 14 days | 1 day |\n| Up to 31 days | 45 days | 1 day |\n| Up to 92 days | 120 days | 2 days |\n| Up to 366 days | 400 days | 7 days |\n| More than 366 days | Selection + 15%, rounded to months | 30 days |\n\nSupply `zoomLevels` to replace those thresholds:\n\n```tsx\n<TimelineDateRangePicker\n  defaultValue={range}\n  zoomLevels={[\n    {\n      id: \"fortnight\",\n      maxSelectionDays: 14,\n      viewportDays: 21,\n      minSelectionDays: 1,\n    },\n    {\n      id: \"quarter\",\n      maxSelectionDays: 92,\n      viewportDays: 120,\n      minSelectionDays: 7,\n    },\n  ]}\n/>\n```\n\n## Render a chart\n\n`renderChart` is rendered behind the selection. Its helpers use the measured\ntimeline width and the active viewport, so a chart can share the picker's\ncoordinate system without reading DOM state.\n\n```tsx\n<TimelineDateRangePicker\n  defaultValue={range}\n  chartHeight={128}\n  renderChart={({ width, height, viewport, x, isInteracting }) => {\n    const points = series.filter(\n      point => point.date >= viewport.from && point.date <= viewport.to,\n    )\n    const max = Math.max(...points.map(point => point.value), 1)\n    const path = points\n      .map((point, index) => {\n        const y = height - (point.value / max) * height\n        return `${index === 0 ? \"M\" : \"L\"}${x(point.date)},${y}`\n      })\n      .join(\" \")\n\n    return (\n      <svg\n        aria-hidden=\"true\"\n        viewBox={`0 0 ${width} ${height}`}\n        preserveAspectRatio=\"none\"\n        opacity={isInteracting ? 0.7 : 1}\n      >\n        <path d={path} fill=\"none\" stroke=\"currentColor\" />\n      </svg>\n    )\n  }}\n/>\n```\n\nChart pointer events are disabled by default so the range remains draggable.\nSet `chartPointerEvents` when the rendered chart needs hover or click handling;\nthe selector and handles remain above the chart.\n\nThe render context contains:\n\n```ts\ntype TimelineChartContext = {\n  value: DateRange\n  viewport: DateRange\n  width: number\n  height: number\n  zoomLevel: string\n  isInteracting: boolean\n  x: (date: Date, align?: \"start\" | \"center\" | \"end\") => number\n  dateAt: (x: number) => Date\n}\n```\n\n## Styling and shadcn compatibility\n\nImport `@amirs/datepicker/styles.css` once. All selectors are scoped to the\ncomponent and consume shadcn semantic variables such as `--card`,\n`--card-foreground`, `--popover`, `--primary`, `--border`, `--muted`, and\n`--ring`, with fallback values for apps that do not define them.\n\nUse `className` and `style` on the root, or target individual parts with\n`classNames`:\n\n```tsx\n<TimelineDateRangePicker\n  defaultValue={range}\n  className=\"my-range-picker\"\n  classNames={{\n    timeline: \"min-h-40\",\n    selection: \"shadow-lg\",\n    tickLabel: \"font-mono\",\n  }}\n/>\n```\n\nStable `data-slot` attributes are available for every visual part:\n`root`, `header`, `date-trigger`, `preset-list`, `preset`, `timeline`, `chart`,\n`selection`, `selection-label`, `move-control`, `start-handle`, `end-handle`,\n`ticks`, `tick`, `pan-previous`, `pan-next`, `calendar-content`, `calendar`, and\n`live-region`. State is exposed through `data-state`, `data-dragging`, and\n`data-zoom-level` where applicable.\n\nFor deeper visual changes, `components` can replace the calendar, previous,\nand next icons, selection label, range handles, or tick labels while preserving\nthe component's behavior and accessible controls.\n\n## Props\n\n| Prop | Type | Purpose |\n| --- | --- | --- |\n| `value`, `defaultValue` | `DateRange` | Controlled or initial inclusive selection. |\n| `onValueChange` | `(range) => void` | Live drag, resize, keyboard, preset, and calendar updates. |\n| `onValueCommit` | `(range) => void` | Final value after an interaction. |\n| `viewport`, `defaultViewport` | `DateRange` | Controlled or initial visible timeline. |\n| `onViewportChange` | `(viewport) => void` | Receives adaptive zoom and pan updates. |\n| `zoomMode` | `\"auto\" \\| \"fixed\"` | Refit committed selections or preserve viewport duration. |\n| `zoomLevels` | `readonly ZoomLevel[]` | Replace the adaptive thresholds and minimum ranges. |\n| `presets` | `readonly DatePreset[]` | Exact static or `today`-resolved shortcuts. |\n| `today` | `Date` | Deterministic date for presets and the calendar. |\n| `minDate`, `maxDate` | `Date` | Bounds selection, viewport movement, and the calendar. |\n| `renderChart` | `(context) => ReactNode` | Render chart content behind the selector. |\n| `chartPointerEvents` | `boolean` | Enable events in chart content. |\n| `showPanControls` | `boolean` | Show previous and next viewport controls. |\n| `chartHeight` | `number` | Timeline chart area height in pixels. |\n| `locale`, `weekStartsOn` | date-fns locale, `0`–`6` | Localize labels and calendar weeks. |\n| `calendarProps` | `TimelineCalendarProps` | Forward supported React DayPicker options. |\n| `formatDateRange` | `(range, context) => ReactNode` | Replace the trigger's range text. |\n| `formatTick` | `(date, context) => string` | Replace responsive tick labels. |\n| `formatDuration` | `(days, range) => ReactNode` | Replace the selection duration label. |\n| `className`, `classNames`, `style` | styling props | Customize the root or individual slots. |\n| `components` | `TimelineDateRangePickerComponents` | Replace supported visual subcomponents. |\n| `id`, `ariaLabel` | `string` | Stable identity and accessible group label. |\n| `disabled` | `boolean` | Disable calendar, preset, pointer, and keyboard changes. |\n\nAll public prop, slot, formatter, tick, zoom, and chart types are exported from\nthe package root.\n\n## Keyboard and touch behavior\n\n- Focus the selection's move control and press an arrow key to move one day.\n- Hold Shift with an arrow key to move seven days.\n- Focus either slider handle and use the same keys to resize that endpoint.\n- Range handles expose formatted values and bounds through ARIA slider\n  semantics; committed changes are announced in a polite live region.\n- Touch targets are at least 44px. Below the mobile breakpoint, presets scroll\n  horizontally and the calendar opens as a labelled modal sheet with one month.\n\nThe picker honors `prefers-reduced-motion` by removing nonessential movement\nand crossfade transitions.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}