├── .husky
├── .gitignore
├── pre-commit
└── post-merge
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── issue-template.md
│ ├── feature-request.md
│ └── bug-report.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── unit.yml
├── .prettierignore
├── docs
├── src
│ ├── styles
│ │ ├── styles.scss
│ │ ├── prism
│ │ │ ├── prism.scss
│ │ │ ├── _line-numbers.scss
│ │ │ └── _theme.scss
│ │ └── _base.scss
│ ├── examples
│ │ ├── range
│ │ │ ├── index.js
│ │ │ └── range.svelte
│ │ ├── theme
│ │ │ ├── index.js
│ │ │ └── theme.svelte
│ │ ├── single
│ │ │ ├── index.js
│ │ │ └── single.svelte
│ │ ├── presets
│ │ │ ├── index.js
│ │ │ └── presets.svelte
│ │ └── index.js
│ ├── index.js
│ ├── config.js
│ └── App.svelte
├── favicon.png
├── .gitignore
├── package.json
├── vite.config.js
└── index.html
├── src
├── index.js
├── index.d.ts
├── actions.js
├── datepicker.test.js
├── datepicker.d.ts
└── datepicker.svelte
├── .eslintignore
├── svelte.config.js
├── vitest.setup.js
├── .lintstagedrc
├── .editorconfig
├── .gitignore
├── .prettierrc.json
├── vite.config.js
├── tsconfig.json
├── CHANGELOG.md
├── .eslintrc.json
├── LICENSE
├── package.json
└── README.md
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @dysfunc
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | /src/**/*.snap.js
3 |
--------------------------------------------------------------------------------
/docs/src/styles/styles.scss:
--------------------------------------------------------------------------------
1 | @import "./base";
2 | @import "./prism/prism";
3 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as DatePicker } from './datepicker.svelte';
2 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | export { default as DatePicker } from './datepicker.svelte';
2 |
--------------------------------------------------------------------------------
/docs/src/styles/prism/prism.scss:
--------------------------------------------------------------------------------
1 | @import "./line-numbers";
2 | @import "./theme";
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | config
2 | node_modules
3 | scripts
4 | src/**/*.snap.js
5 | .eslintrc.js
6 |
--------------------------------------------------------------------------------
/docs/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svelte-plugins/datepicker/HEAD/docs/favicon.png
--------------------------------------------------------------------------------
/docs/src/examples/range/index.js:
--------------------------------------------------------------------------------
1 | export { default as RangePicker } from './range.svelte';
2 |
--------------------------------------------------------------------------------
/docs/src/examples/theme/index.js:
--------------------------------------------------------------------------------
1 | export { default as ThemePicker } from './theme.svelte';
2 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | .*
2 | !.gitignore
3 | *.log
4 |
5 | # generated
6 | build
7 | /node_modules
8 |
--------------------------------------------------------------------------------
/docs/src/examples/single/index.js:
--------------------------------------------------------------------------------
1 | export { default as SinglePicker } from './single.svelte';
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | . "$(dirname "$0")/_/husky.sh"
4 |
5 | pnpm dlx lint-staged
6 |
--------------------------------------------------------------------------------
/docs/src/examples/presets/index.js:
--------------------------------------------------------------------------------
1 | export { default as PresetsOnlyPicker } from './presets.svelte';
2 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
2 |
3 | export default {
4 | preprocess: vitePreprocess()
5 | };
6 |
--------------------------------------------------------------------------------
/docs/src/index.js:
--------------------------------------------------------------------------------
1 | import App from './app.svelte'
2 |
3 | import './styles/styles.scss';
4 |
5 | const app = new App({ target: document.body });
6 |
7 | export default app;
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/issue-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Issue
3 | about: Track a new feature, enhancement, or general task.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 | ---
8 |
--------------------------------------------------------------------------------
/vitest.setup.js:
--------------------------------------------------------------------------------
1 | import { afterEach, vi } from 'vitest';
2 | import { cleanup } from '@testing-library/svelte';
3 |
4 | import '@testing-library/jest-dom/vitest';
5 |
6 | afterEach(cleanup);
7 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "./src/**/*.{test.js,js,ts,json,svelte}": [
3 | "svelte-check --tsconfig ./tsconfig.json",
4 | "eslint -c ./.eslintrc.json --fix",
5 | "prettier --write"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/docs/src/examples/index.js:
--------------------------------------------------------------------------------
1 | export { SinglePicker } from './single';
2 | export { PresetsOnlyPicker } from './presets';
3 | export { RangePicker } from './range';
4 | export { ThemePicker } from './theme';
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | insert_final_newline = true
5 | charset = utf-8
6 | trim_trailing_whitespace = true
7 | end_of_line = lf
8 |
9 | [*.{js,json}]
10 | indent_style = space
11 | indent_size = 2
12 |
--------------------------------------------------------------------------------
/.husky/post-merge:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # git hook to run a command after `git pull` if a specified file was changed
4 | # Run `chmod +x .husky/post-merge` to make it executable then put it into `.git/hooks/`.
5 |
6 | changes="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
7 |
8 | check() {
9 | echo "$changes" | grep --quiet "$1" && eval "$2"
10 | }
11 |
12 | check package.json "pnpm install"
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .*
2 |
3 | # except
4 | !.editorconfig
5 | !.eslintignore
6 | !.eslintrc.json
7 | !.github
8 | !.gitignore
9 | !.gitkeep
10 | !.lintstagedrc
11 | !.node-version
12 | !.npmignore
13 | !.npmrc
14 | !.nvmrc
15 | !.prettierignore
16 | !.prettierrc.json
17 | !.lintstagedrc
18 | !.husky
19 | !.storybook
20 |
21 | # generated
22 | .vercel
23 | /node_modules
24 | /dist
25 | /package-lock.json
26 |
27 | # testing
28 | coverage
29 | artifacts
30 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "type": "module",
4 | "scripts": {
5 | "dev": "vite",
6 | "build": "vite build",
7 | "serve": "vite preview"
8 | },
9 | "devDependencies": {
10 | "@svelte-plugins/datepicker": "../",
11 | "@sveltejs/vite-plugin-svelte": "^3.0.1",
12 | "autoprefixer": "^10.4.16",
13 | "date-fns": "^2.30.0",
14 | "sass": "^1.69.5",
15 | "svelte": "^4.2.7",
16 | "svelte-prismjs": "^1.0.2",
17 | "vite": "^5.0.2"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "trailingComma": "none",
4 | "tabWidth": 2,
5 | "semi": true,
6 | "bracketSpacing": true,
7 | "arrowParens": "always",
8 | "singleQuote": true,
9 | "svelteSortOrder": "options-scripts-markup-styles",
10 | "svelteStrictMode": false,
11 | "svelteBracketNewLine": true,
12 | "svelteAllowShorthand": true,
13 | "plugins": ["prettier-plugin-svelte"],
14 | "overrides": [{
15 | "files": "*.svelte",
16 | "options": {
17 | "parser": "svelte"
18 | }
19 | }]
20 | }
21 |
--------------------------------------------------------------------------------
/src/actions.js:
--------------------------------------------------------------------------------
1 | export const clickOutside = (node, config = {}) => {
2 | const options = {
3 | include: [],
4 | onClickOutside: () => {},
5 | ...config
6 | };
7 |
8 | const detect = ({ target }) => {
9 | if (!node.contains(target) || options.include.some((i) => target.isSameNode(i))) {
10 | options.onClickOutside();
11 | }
12 | };
13 |
14 | document.addEventListener('click', detect, { passive: true, capture: true });
15 |
16 | return {
17 | destroy() {
18 | document.removeEventListener('click', detect);
19 | }
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/docs/src/styles/_base.scss:
--------------------------------------------------------------------------------
1 | html {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | body {
7 | box-sizing: border-box;
8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
9 | margin: 0;
10 | padding: 0;
11 | position: relative;
12 | }
13 |
14 | html,
15 | body {
16 | background-color: #fff;
17 | height: 100%;
18 | }
19 |
20 | .github-ribbon {
21 | position: fixed;
22 | right: 0;
23 | top: 0;
24 | z-index: 100;
25 | }
26 |
27 | .github-ribbon img {
28 | height: 125px !important;
29 | width: 125px !important;
30 | }
31 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import { svelte } from '@sveltejs/vite-plugin-svelte';
3 |
4 | export default defineConfig({
5 | plugins: [svelte({ emitCss: false })],
6 | test: {
7 | globals: true,
8 | environment: 'jsdom',
9 | setupFiles: ['vitest.setup.js'],
10 | testTimeout: 20000,
11 | alias: [
12 | {
13 | find: /^svelte$/,
14 | replacement: 'svelte/internal'
15 | }
16 | ],
17 | include: ['./src/**/*.test.js'],
18 | resolveSnapshotPath: (testPath, snapExtension) => testPath.replace(/\.test\.([tj]s?)/, `${snapExtension}.$1`)
19 | }
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/docs/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import { svelte } from '@sveltejs/vite-plugin-svelte';
3 | import autoprefixer from 'autoprefixer'
4 |
5 | export default defineConfig(({ command, mode }) => {
6 | const isProduction = mode === 'production'
7 |
8 | return {
9 | base: '',
10 | css: {
11 | postcss: {
12 | plugins: [
13 | autoprefixer({
14 | overrideBrowserslist: ['last 1 version', 'ie >= 11'],
15 | }),
16 | ],
17 | },
18 | },
19 | build: {
20 | minify: isProduction,
21 | outDir: 'build',
22 | },
23 | plugins: [
24 | svelte()
25 | ]
26 | }
27 | })
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/svelte/tsconfig.json",
3 | "include": [
4 | "src/**/*.d.ts"
5 | ],
6 | "exclude": [
7 | "node_modules/*",
8 | "src/**/*.test.js",
9 | "src/**/*.js",
10 | "src/**/*.svelte"
11 | ],
12 | "compilerOptions": {
13 | "baseUrl": "./",
14 | "moduleResolution": "node",
15 | "target": "es2022",
16 | "allowJs": false,
17 | "checkJs": false,
18 | "esModuleInterop": true,
19 | "forceConsistentCasingInFileNames": true,
20 | "resolveJsonModule": true,
21 | "skipLibCheck": true,
22 | "sourceMap": true,
23 | "paths": {
24 | "@svelte-plugins/datepicker": ["src/index"]
25 | },
26 | "types": ["vitest/globals"]
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest a new feature or functionality enhancement
4 | title: '✨ '
5 | labels: 'Type: Feature'
6 | assignees: ''
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [0.1.2](https://github.com/svelte-plugins/datepicker/releases/tag/v0.1.0) - 2023-11-24
9 |
10 | - 🏗 build(tooling): fix linting, formatting and precommit hooks by
11 |
12 | ## [0.1.1](https://github.com/svelte-plugins/datepicker/releases/tag/v0.1.0) - 2023-11-23
13 |
14 | - refactor(picker): updates to dev tooling and general code cleanup
15 |
16 | ## [0.1.0](https://github.com/svelte-plugins/datepicker/releases/tag/v0.1.0) - 2023-11-22
17 |
18 | - Initial release
19 |
--------------------------------------------------------------------------------
/docs/src/styles/prism/_line-numbers.scss:
--------------------------------------------------------------------------------
1 | pre[class*="language-"].line-numbers {
2 | counter-reset: linenumber;
3 | padding-left: 3.8em;
4 | position: relative;
5 | }
6 |
7 | pre[class*="language-"].line-numbers>code {
8 | position: relative;
9 | white-space: inherit;
10 | }
11 |
12 | .line-numbers .line-numbers-rows {
13 | border-right: 0;
14 | font-size: 100%;
15 | left: -3.8em;
16 | letter-spacing: -1px;
17 | position: absolute;
18 | pointer-events: none;
19 | top: 0;
20 | user-select: none;
21 | width: 3em;
22 | }
23 |
24 | .line-numbers-rows>span {
25 | counter-increment: linenumber;
26 | display: block;
27 | }
28 |
29 | .line-numbers-rows>span:before {
30 | color: #495162;
31 | content: counter(linenumber);
32 | display: block;
33 | padding-right: 0.8em;
34 | text-align: right;
35 | }
36 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es2017": true,
4 | "commonjs": true,
5 | "node": true
6 | },
7 | "parserOptions": {
8 | "ecmaVersion": 2020,
9 | "sourceType": "module"
10 | },
11 | "plugins": [
12 | "vitest"
13 | ],
14 | "extends": [
15 | "eslint:recommended",
16 | "plugin:vitest/recommended"
17 | ],
18 | "ignorePatterns": [
19 | "**/*.snap.js"
20 | ],
21 | "overrides": [
22 | {
23 | "files": [
24 | "*.ts"
25 | ],
26 | "parser": "@typescript-eslint/parser"
27 | },
28 | {
29 | "files": [
30 | "*.svelte"
31 | ],
32 | "parser": "svelte-eslint-parser"
33 | }
34 | ],
35 | "rules": {
36 | "eqeqeq": "error",
37 | "no-useless-escape": "off",
38 | "no-unused-expressions": "off",
39 | "no-inner-declarations": "off",
40 | "no-unused-vars": "off",
41 | "no-self-assign": "off",
42 | "no-undef": "off"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Report a bug to help us improve the overall user experience
4 | title: '🐛 '
5 | labels: 'Type: Bug'
6 | assignees: ''
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 |
28 | - OS: [e.g. iOS]
29 | - Browser [e.g. chrome, safari]
30 | - Version [e.g. 22]
31 |
32 | **Smartphone (please complete the following information):**
33 |
34 | - Device: [e.g. iPhone6]
35 | - OS: [e.g. iOS8.1]
36 | - Browser [e.g. stock browser, safari]
37 | - Version [e.g. 22]
38 |
39 | **Additional context**
40 | Add any other context about the problem here.
41 |
--------------------------------------------------------------------------------
/docs/src/config.js:
--------------------------------------------------------------------------------
1 | const today = new Date();
2 |
3 | export const defaultConfig = {
4 | startDate: today,
5 | endDate: today,
6 | startDateTime: '00:00',
7 | endDateTime: '00:00',
8 | today,
9 | defaultYear: today.getFullYear(),
10 | defaultMonth: today.getMonth(),
11 | startOfWeek: 0,
12 | isMultipane: false,
13 | isRange: false,
14 | isOpen: false,
15 | align: 'left',
16 | theme: '',
17 | disabledDates: [],
18 | onDayClick: () => { },
19 | onNavigationChange: () => { },
20 | showYearControls: true,
21 | showPresets: false,
22 | showTimePicker: false,
23 | enableFutureDates: false,
24 | enablePastDates: true,
25 | presetLabels: ['Today', 'Last 7 Days', 'Last 30 Days', 'Last 60 Days', 'Last 90 Days', 'Last Year'],
26 | dowLabels: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
27 | monthLabels: [
28 | 'January',
29 | 'February',
30 | 'March',
31 | 'April',
32 | 'May',
33 | 'June',
34 | 'July',
35 | 'August',
36 | 'September',
37 | 'October',
38 | 'November',
39 | 'December'
40 | ]
41 | };
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021-present Kieran Boyle
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Why these changes?**
2 |
3 | **How do we test?**
4 |
5 | **Screenshots**
6 |
7 |
38 |
--------------------------------------------------------------------------------
/.github/workflows/unit.yml:
--------------------------------------------------------------------------------
1 | name: Unit Tests
2 | on:
3 | push:
4 | branches:
5 | - main
6 | paths:
7 | - src/**
8 | pull_request:
9 | types: [opened, synchronize, reopened]
10 | jobs:
11 | tests:
12 | runs-on: ubuntu-latest
13 | name: Tests
14 | if: |
15 | (
16 | !contains(github.event.head_commit.message, '[skip ci]') &&
17 | !contains(github.event.head_commit.message, 'version bump')
18 | )
19 | steps:
20 | - name: Checkout repository
21 | uses: actions/checkout@v3
22 | - name: Install pnpm
23 | uses: pnpm/action-setup@v3
24 | with:
25 | version: 8.11
26 | - name: Install Node
27 | uses: actions/setup-node@v3
28 | with:
29 | node-version: 20
30 | cache: 'pnpm'
31 | registry-url: 'https://registry.npmjs.org'
32 | - name: Install dependencies
33 | run: pnpm install
34 | - name: Set Timezone
35 | uses: szenius/set-timezone@v1.2
36 | with:
37 | timezoneLinux: "America/Los_Angeles"
38 | timezoneMacos: "America/Los_Angeles"
39 | timezoneWindows: "Pacific Standard Time"
40 | - name: Run tests
41 | run: pnpm test
42 | - name: Upload artifacts
43 | uses: actions/upload-artifact@v4
44 | if: failure()
45 | with:
46 | name: unit-tests
47 | path: ${{ github.workspace }}/coverage/
48 | retention-days: 5
49 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @svelte-plugins/datepicker
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@svelte-plugins/datepicker",
3 | "description": "A simple datepicker component designed for Svelte.",
4 | "version": "1.0.11",
5 | "license": "MIT",
6 | "author": "Kieran Boyle (https://github.com/dysfunc)",
7 | "homepage": "https://github.com/svelte-plugins/datepicker",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/svelte-plugins/datepicker.git"
11 | },
12 | "type": "module",
13 | "types": "./dist/index.d.ts",
14 | "svelte": "./dist/index.js",
15 | "exports": {
16 | ".": {
17 | "types": "./dist/index.d.ts",
18 | "svelte": "./dist/index.js",
19 | "import": "./dist/index.js"
20 | },
21 | "./package.json": "./package.json"
22 | },
23 | "files": [
24 | "dist",
25 | "src"
26 | ],
27 | "keywords": [
28 | "datepicker",
29 | "timepicker",
30 | "daterange",
31 | "date picker",
32 | "time picker",
33 | "range picker",
34 | "date range",
35 | "calendar",
36 | "date-time",
37 | "picker",
38 | "svelte",
39 | "components",
40 | "javascript"
41 | ],
42 | "scripts": {
43 | "start": "vite & npm --prefix ./docs install && npm --prefix ./docs run dev",
44 | "build": "svelte-package --input ./src && pnpm lint:package",
45 | "build:docs": "npm --prefix ./docs run build",
46 | "deploy:docs": "pnpm build:docs && npx gh-pages -d docs/build",
47 | "check": "svelte-check --tsconfig ./tsconfig.json",
48 | "lint": "eslint -c ./.eslintrc.json --fix \"src/**/*.{test.js,js,ts,json,svelte}\"",
49 | "lint:package": "publint --strict",
50 | "format": "prettier --write \"src/**/*.{test.js,js,ts,json,svelte}\"",
51 | "test": "vitest --run --coverage",
52 | "test:watch": "vitest",
53 | "test:coverage": "vitest --run --coverage && open ./coverage/index.html"
54 | },
55 | "devDependencies": {
56 | "@sveltejs/package": "^2.2.4",
57 | "@sveltejs/vite-plugin-svelte": "^3.0.1",
58 | "@testing-library/jest-dom": "^6.4.0",
59 | "@testing-library/svelte": "^4.0.5",
60 | "@tsconfig/svelte": "^5.0.2",
61 | "@types/node": "^20.10.5",
62 | "@typescript-eslint/parser": "^6.18.1",
63 | "@vitest/coverage-v8": "^0.34.6",
64 | "eslint": "^8.54.0",
65 | "eslint-plugin-svelte": "^2.35.1",
66 | "eslint-plugin-vitest": "^0.3.10",
67 | "husky": "^6.0.0",
68 | "jsdom": "^23.0.0",
69 | "lint-staged": "^10.5.4",
70 | "prettier": "^3.1.0",
71 | "prettier-plugin-svelte": "^3.1.2",
72 | "publint": "^0.2.7",
73 | "svelte": "^4.2.8",
74 | "svelte-check": "^3.6.2",
75 | "svelte-preprocess": "^5.1.3",
76 | "typescript": "^5.2.2",
77 | "vite": "^5.0.12",
78 | "vitest": "^0.34.6"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/docs/src/examples/single/single.svelte:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 |
45 |
46 |
47 |
50 | import { DatePicker } from '@svelte-plugins/datepicker';
51 | import { format } from 'date-fns';
52 |
53 | let startDate = new Date();
54 | let dateFormat = 'MM/dd/yy';
55 | let isOpen = false;
56 |
57 | const toggleDatePicker = () => (isOpen = !isOpen);
58 |
59 | const formatDate = (dateString) => {
60 | if (isNaN(new Date(dateString))) {
61 | return '';
62 | }
63 |
64 | return dateString && format(new Date(dateString), dateFormat) || '';
65 | };
66 | let formattedStartDate = formatDate(startDate);
67 |
68 | const onChange = () => {
69 | startDate = new Date(formattedStartDate);
70 | };
71 |
72 | $: formattedStartDate = formatDate(startDate);
73 |
74 |
75 |
76 |
77 |
78 |
79 |
86 | `} />
87 |
88 |
95 |
--------------------------------------------------------------------------------
/src/datepicker.test.js:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/svelte';
2 | import DatePicker from './datepicker.svelte';
3 |
4 | const today = new Date('1/1/2020');
5 |
6 | const config = {
7 | startDate: today,
8 | endDate: today,
9 | startDateTime: '00:00',
10 | endDateTime: '00:00',
11 | startOfWeek: 0,
12 | isMultipane: false,
13 | isRange: false,
14 | isOpen: false,
15 | align: 'left',
16 | theme: '',
17 | disabledDates: [],
18 | enabledDates: [],
19 | onDayClick: () => {},
20 | showYearControls: true,
21 | showPresets: false,
22 | showTimePicker: false,
23 | enableFutureDates: false,
24 | enablePastDates: true,
25 | presetLabels: ['Today', 'Last 7 Days', 'Last 30 Days', 'Last 60 Days', 'Last 90 Days', 'Last Year'],
26 | dowLabels: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
27 | monthLabels: [
28 | 'January',
29 | 'February',
30 | 'March',
31 | 'April',
32 | 'May',
33 | 'June',
34 | 'July',
35 | 'August',
36 | 'September',
37 | 'October',
38 | 'November',
39 | 'December'
40 | ]
41 | };
42 |
43 | vi.setSystemTime(today);
44 |
45 | describe('Components: DatePicker', () => {
46 | let TestHarness;
47 |
48 | beforeEach(() => {
49 | TestHarness = (props = {}) => render(DatePicker, props);
50 | });
51 |
52 | it('should render a single datepicker', () => {
53 | const { container } = TestHarness(config);
54 | expect(container).toMatchSnapshot();
55 | });
56 |
57 | it('should render a range picker', () => {
58 | const { container } = TestHarness({ ...config, isRange: true, isMultipane: true });
59 | expect(container).toMatchSnapshot();
60 | });
61 |
62 | it('should render a date picker with time selection', () => {
63 | const { container } = TestHarness({ ...config, showTimePicker: true });
64 | expect(container).toMatchSnapshot();
65 | });
66 |
67 | it('should render a range picker with presets', () => {
68 | const { container } = TestHarness({ ...config, isRange: true, showPresets: true });
69 | expect(container).toMatchSnapshot();
70 | });
71 |
72 | it('should render a date picker without year controls', () => {
73 | const { container } = TestHarness({ ...config, showYearControls: false });
74 | expect(container).toMatchSnapshot();
75 | });
76 |
77 | it('should render a date picker with Monday as start of week', () => {
78 | const { container } = TestHarness({ ...config, startOfWeek: 1 });
79 | expect(container).toMatchSnapshot();
80 | });
81 |
82 | it('should render a date picker with my custom locale', () => {
83 | const { container } = TestHarness({
84 | ...config,
85 | dowLabels: ['Au', 'Bo', 'Cu', 'De', 'Eh', 'Fr', 'Ga'],
86 | monthLabels: [
87 | 'Qanuary',
88 | 'Webruary',
89 | 'Earch',
90 | 'Rpril',
91 | 'Tay',
92 | 'Yune',
93 | 'Uuly',
94 | 'Iugust',
95 | 'Oeptember',
96 | 'Pctober',
97 | 'Aovember',
98 | 'Secember'
99 | ]
100 | });
101 |
102 | expect(container).toMatchSnapshot();
103 | });
104 | });
105 |
--------------------------------------------------------------------------------
/src/datepicker.d.ts:
--------------------------------------------------------------------------------
1 | import type { SvelteComponent } from 'svelte';
2 |
3 | export interface DatePickerProps {
4 | /**
5 | * Represents the start date for a date picker.
6 | * @default null
7 | */
8 | startDate?: any;
9 |
10 | /**
11 | * Represents the end date for a date picker.
12 | * @default null
13 | */
14 | endDate?: any;
15 |
16 | /**
17 | * Represents the start time for the date picker (in HH:mm format).
18 | * @default '00:00'
19 | */
20 | startDateTime?: string;
21 |
22 | /**
23 | * Represents the end time for the date picker (in HH:mm format).
24 | * @default '00:00'
25 | */
26 | endDateTime?: string;
27 |
28 | /**
29 | * Represents the current date.
30 | */
31 | today?: Date;
32 |
33 | /**
34 | * Represents the default year for the date picker.
35 | */
36 | defaultYear?: number;
37 |
38 | /**
39 | * Represents the default month for the date picker.
40 | */
41 | defaultMonth?: number;
42 |
43 | /**
44 | * Represents the start day of the week (0 for Sunday, 1 for Monday, etc.).
45 | */
46 | startOfWeek?: number;
47 |
48 | /**
49 | * Indicates whether the date picker has multiple panes.
50 | */
51 | isMultipane?: boolean;
52 |
53 | /**
54 | * Indicates whether the date picker is in range mode.
55 | */
56 | isRange?: boolean;
57 |
58 | /**
59 | * Indicates whether the date picker is open.
60 | */
61 | isOpen?: boolean;
62 |
63 | /**
64 | * Specifies the alignment of the date picker (e.g., 'left', 'center', 'right').
65 | */
66 | align?: string;
67 |
68 | /**
69 | * Represents the theme of the date picker.
70 | */
71 | theme?: string;
72 |
73 | /**
74 | * An array of disabled dates.
75 | */
76 | disabledDates?: string[];
77 |
78 | /**
79 | * An array of enabled dates.
80 | */
81 | enabledDates?: string[];
82 |
83 | /**
84 | * Callback function to handle when the date change events.
85 | */
86 | onDateChange?: (event: Object) => void;
87 |
88 | /**
89 | * Callback function to handle day click events.
90 | */
91 | onDayClick?: (event: Object) => void;
92 |
93 | /**
94 | * Callback function to handle the navigation click event for months and years
95 | * @type {(event: Object) => void}
96 | */
97 | onNavigationChange?: (event: Object) => void;
98 |
99 | /**
100 | * Indicates whether the date picker should always be shown.
101 | */
102 | alwaysShow?: boolean;
103 |
104 | /**
105 | * Indicates whether year controls are displayed in the date picker.
106 | */
107 | showYearControls?: boolean;
108 |
109 | /**
110 | * Indicates whether preset options are displayed in the date picker.
111 | */
112 | showPresets?: boolean;
113 |
114 | /**
115 | * Indicates whether preset options should only be shown for range pickers.
116 | */
117 | showPresetsOnly?: boolean;
118 |
119 | /**
120 | * Indicates whether the time picker is shown in the date picker.
121 | */
122 | showTimePicker?: boolean;
123 |
124 | /**
125 | * Indicates whether future dates are enabled.
126 | */
127 | enableFutureDates?: boolean;
128 |
129 | /**
130 | * Indicates whether past dates are enabled.
131 | */
132 | enablePastDates?: boolean;
133 |
134 | /**
135 | * An array of preset date range labels.
136 | */
137 | presetLabels?: string[];
138 |
139 | /**
140 | * An array of preset date ranges with labels and start/end timestamps.
141 | */
142 | presetRanges?: Object[];
143 |
144 | /**
145 | * An array of day-of-week labels.
146 | */
147 | dowLabels?: string[];
148 |
149 | /**
150 | * An array of month labels.
151 | */
152 | monthLabels?: string[];
153 |
154 | /**
155 | * Determines if the default font "Rubik" should be loaded.
156 | */
157 | includeFont?: boolean;
158 | }
159 |
160 | export interface DatePickerEvents {
161 | [key: string]: any;
162 | }
163 |
164 | export interface DatePickerSlots {
165 | default?: {};
166 | }
167 |
168 | export default class DatePicker extends SvelteComponent {}
169 |
--------------------------------------------------------------------------------
/docs/src/styles/prism/_theme.scss:
--------------------------------------------------------------------------------
1 | code[class*="language-"],
2 | pre[class*="language-"] {
3 | background: #f3f3f3;
4 | color: #e06C75;
5 | direction: ltr;
6 | font-family: 'ui-monospace', 'SFMono-Regular', Menlo, Monaco, Consolas, 'Courier New', monospace;
7 | font-size: 13px;
8 | hyphens: none;
9 | line-height: 1.5;
10 | tab-size: 2;
11 | text-align: left;
12 | text-shadow: none;
13 | white-space: pre;
14 | word-break: normal;
15 | word-spacing: normal;
16 | }
17 |
18 | code[class*="language-"]::-moz-selection,
19 | code[class*="language-"] *::-moz-selection,
20 | pre[class*="language-"] *::-moz-selection {
21 | background: #3e4451;
22 | color: inherit;
23 | text-shadow: none;
24 | }
25 |
26 | code[class*="language-"]::selection,
27 | code[class*="language-"] *::selection,
28 | pre[class*="language-"] *::selection {
29 | background: #3e4451;
30 | color: inherit;
31 | text-shadow: none;
32 | }
33 |
34 | pre[class*="language-"] {
35 | border-radius: 0.3em;
36 | margin: 0.5em 0;
37 | overflow: auto;
38 | padding: 1em;
39 | }
40 |
41 | :not(pre)>code[class*="language-"] {
42 | border-radius: 0.3em;
43 | padding: 0.2em 0.3em;
44 | white-space: normal;
45 | }
46 |
47 | @media print {
48 | code[class*="language-"],
49 | pre[class*="language-"] {
50 | text-shadow: none;
51 | }
52 | }
53 |
54 | .token {
55 |
56 | &.comment,
57 | &.prolog,
58 | &.cdata {
59 | color: #7a7f89;
60 | }
61 |
62 | &.doctype,
63 | &.punctuation,
64 | &.entity {
65 | color: #abb2bf;
66 | }
67 |
68 | &.attr-name,
69 | &.class-name,
70 | &.boolean,
71 | &.constant,
72 | &.number,
73 | &.atrule {
74 | color: #d4b375;
75 | }
76 |
77 | &.keyword {
78 | color: #9661a9;
79 | }
80 |
81 | &.property,
82 | &.tag,
83 | &.symbol,
84 | &.deleted,
85 | &.important {
86 | color: #e06c75;
87 | }
88 |
89 | &.selector,
90 | &.string,
91 | &.char,
92 | &.builtin,
93 | &.inserted,
94 | &.regex,
95 | &.attr-value,
96 | &.attr-value>.token.punctuation {
97 | color: #98c379;
98 | }
99 |
100 | &.variable,
101 | &.operator,
102 | &.function {
103 | color: #61afef;
104 | }
105 |
106 | &.url {
107 | color: #56b6c2;
108 | }
109 |
110 | &.attr-value>.token.punctuation.attr-equals,
111 | &.special-attr>.token.attr-value>.token.value.css {
112 | color: #abb2bf;
113 | }
114 | }
115 |
116 | .language-css {
117 | .token {
118 | &.selector {
119 | color: #e06c75;
120 | }
121 |
122 | &.property {
123 | color: #abb2bf;
124 | }
125 |
126 | &.function,
127 | &.url>.token.function {
128 | color: #56b6c2;
129 | }
130 |
131 | &.token.string.url {
132 | color: #98c379;
133 | }
134 |
135 | &.important,
136 | &.atrule .token.rule {
137 | color: #c678dd;
138 | }
139 | }
140 | }
141 |
142 | .language-javascript {
143 | .token {
144 | &.operator {
145 | color: #c678dd;
146 | }
147 |
148 | &.template-string>.token.interpolation>.token.interpolation-punctuation.punctuation {
149 | color: #be5046;
150 | }
151 | }
152 | }
153 |
154 | .language-json {
155 | .token {
156 | &.operator {
157 | color: #abb2bf;
158 | }
159 |
160 | &.null.keyword {
161 | color: #d19a66;
162 | }
163 | }
164 | }
165 |
166 | .language-markdown {
167 |
168 | .token.url,
169 | .token.url>.token.operator,
170 | .token.url-reference.url>.token.string {
171 | color: #abb2bf;
172 | }
173 |
174 | .token.url>.token.content {
175 | color: #61afef;
176 | }
177 |
178 | .token.url>.token.url,
179 | .token.url-reference.url {
180 | color: #56b6c2;
181 | }
182 |
183 | .token.blockquote.punctuation,
184 | .token.hr.punctuation {
185 | color: #5c6370;
186 | font-style: italic;
187 | }
188 |
189 | .token.code-snippet {
190 | color: #98c379;
191 | }
192 |
193 | .token.bold .token.content {
194 | color: #d19a66;
195 | }
196 |
197 | .token.italic .token.content {
198 | color: #c678dd;
199 | }
200 |
201 | .token.strike .token.content,
202 | .token.strike .token.punctuation,
203 | .token.list.punctuation,
204 | .token.title.important>.token.punctuation {
205 | color: #e06c75;
206 | }
207 | }
208 |
209 | .token {
210 | &.bold {
211 | font-weight: bold;
212 | }
213 |
214 | &.comment,
215 | &.italic {
216 | font-style: italic;
217 | }
218 |
219 | &.entity {
220 | cursor: help;
221 | }
222 |
223 | &.namespace {
224 | opacity: .8;
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/docs/src/examples/presets/presets.svelte:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
62 |
63 |
64 |
65 | {#if startDate}
66 | {formattedStartDate} - {formattedEndDate}
67 | {:else}
68 | Pick a date
69 | {/if}
70 |
71 | {#if startDate}
72 |
73 |
74 |
75 | {/if}
76 |
77 |
78 |
79 |
80 |
82 | import { DatePicker } from '@svelte-plugins/datepicker';
83 | import { format } from 'date-fns';
84 |
85 | const today = new Date();
86 |
87 | const MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
88 |
89 | const getDateFromToday = (days) => {
90 | return Date.now() - days * MILLISECONDS_IN_DAY;
91 | };
92 |
93 | let startDate = getDateFromToday(29);
94 | let endDate = today;
95 | let dateFormat = 'MMM d, yyyy';
96 | let isOpen = false;
97 |
98 | let formattedStartDate = '';
99 |
100 | const onClearDates = () => {
101 | startDate = '';
102 | endDate = '';
103 | };
104 |
105 | const onDateChange = (args) => {
106 | console.log(args, 'onDateChange');
107 | };
108 |
109 | const toggleDatePicker = () => (isOpen = !isOpen);
110 |
111 | const formatDate = (dateString) => {
112 | if (isNaN(new Date(dateString))) {
113 | return '';
114 | }
115 |
116 | return dateString && format(new Date(dateString), dateFormat) || '';
117 | };
118 |
119 | $: formattedStartDate = formatDate(startDate);
120 | $: formattedEndDate = formatDate(endDate);
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | {#if startDate}
129 | {formattedStartDate} - {formattedEndDate}
130 | {:else}
131 | Pick a date
132 | {/if}
133 |
134 | {#if startDate}
135 |
136 |
137 |
138 | {/if}
139 |
140 |
141 |
142 |
143 |
165 | `} />
166 |
167 |
189 |
--------------------------------------------------------------------------------
/docs/src/examples/range/range.svelte:
--------------------------------------------------------------------------------
1 |
51 |
52 |
53 |
64 |
65 |
66 |
67 | {#if startDate}
68 | {formattedStartDate} - {formattedEndDate}
69 | {:else}
70 | Pick a date
71 | {/if}
72 |
73 | {#if startDate}
74 |
75 |
76 |
77 | {/if}
78 |
79 |
80 |
81 |
82 |
84 | import { DatePicker } from '@svelte-plugins/datepicker';
85 | import { format } from 'date-fns';
86 |
87 | const today = new Date();
88 |
89 | const MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
90 |
91 | const getDateFromToday = (days) => {
92 | return Date.now() - days * MILLISECONDS_IN_DAY;
93 | };
94 |
95 | let startDate = getDateFromToday(29);
96 | let endDate = today;
97 | let dateFormat = 'MMM d, yyyy';
98 | let isOpen = false;
99 |
100 | let formattedStartDate = '';
101 |
102 | const onClearDates = () => {
103 | startDate = '';
104 | endDate = '';
105 | };
106 |
107 | const toggleDatePicker = () => (isOpen = !isOpen);
108 |
109 | const formatDate = (dateString) => {
110 | if (isNaN(new Date(dateString))) {
111 | return '';
112 | }
113 |
114 | return dateString && format(new Date(dateString), dateFormat) || '';
115 | };
116 |
117 | $: formattedStartDate = formatDate(startDate);
118 | $: formattedEndDate = formatDate(endDate);
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | {#if startDate}
127 | {formattedStartDate} - {formattedEndDate}
128 | {:else}
129 | Pick a date
130 | {/if}
131 |
132 | {#if startDate}
133 |
134 |
135 |
136 | {/if}
137 |
138 |
139 |
140 |
141 |
163 | `} />
164 |
165 | {#if showPresets}
166 | You can customize the presets by defining your own:
167 |
168 |
190 | `} />
191 | {/if}
192 |
193 |
215 |
--------------------------------------------------------------------------------
/docs/src/examples/theme/theme.svelte:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 |
46 |
47 |
48 |
49 | {#if startDate}
50 | {formattedStartDate} - {formattedEndDate}
51 | {:else}
52 | Pick a date
53 | {/if}
54 |
55 | {#if startDate}
56 |
57 |
58 |
59 | {/if}
60 |
61 |
62 |
63 |
64 |
67 | import { DatePicker } from '@svelte-plugins/datepicker';
68 | import { format } from 'date-fns';
69 |
70 | const today = new Date();
71 |
72 | const MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
73 |
74 | const getDateFromToday = (days) => {
75 | return Date.now() - days * MILLISECONDS_IN_DAY;
76 | };
77 |
78 | let startDate = getDateFromToday(29);
79 | let endDate = today;
80 | let dateFormat = 'MMM d, yyyy';
81 | let isOpen = false;
82 |
83 | let formattedStartDate = '';
84 |
85 | const onClearDates = () => {
86 | startDate = '';
87 | endDate = '';
88 | };
89 |
90 | const toggleDatePicker = () => (isOpen = !isOpen);
91 | const formatDate = (dateString) => dateString && format(new Date(dateString), dateFormat) || '';
92 |
93 | $: formattedStartDate = formatDate(startDate);
94 | $: formattedEndDate = formatDate(endDate);
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | {#if startDate}
103 | {formattedStartDate} - {formattedEndDate}
104 | {:else}
105 | Pick a date
106 | {/if}
107 |
108 | {#if startDate}
109 |
110 |
111 |
112 | {/if}
113 |
114 |
115 |
116 |
117 |
165 | `} />
166 |
167 |
217 |
--------------------------------------------------------------------------------
/docs/src/App.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 | @svelte-plugins/datepicker (dysfunc)
18 | A simple datepicker component written in Svelte.
19 |
20 |
21 |
22 |
23 |
24 | Overview
25 |
26 | The DatePicker component allows users to easily select a date or date-range from one or more calendars.
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Props
35 |
36 |
37 |
38 | | Name |
39 | Type |
40 | Description |
41 | Default |
42 |
43 |
44 | | startDate |
45 | object |
46 | The start date string or date object. |
47 | null |
48 |
49 |
50 | | endDate |
51 | object |
52 | The end date string or date object. |
53 | null |
54 |
55 |
56 | | startDateTime |
57 | string |
58 | The start date time string in 24 hour format. |
59 | 00:00 |
60 |
61 |
62 | | endDateTime |
63 | string |
64 | The end date time string in 24 hour format. |
65 | 00:00 |
66 |
67 |
68 | | defaultYear |
69 | number |
70 | The year you want to show as the default. |
71 | {today.getFullYear()} |
72 |
73 |
74 | | align |
75 | string |
76 |
77 | The edge alignment of the datepicker.
78 | Accepted values left or right
79 | |
80 | left |
81 |
82 |
83 | | isRange |
84 | boolean |
85 | Changes the date picker into a range picker and allows start and end date selection. |
86 | false |
87 |
88 |
89 | | isMultipane |
90 | boolean |
91 | If true, two calendar months will be shown side-by-side instead of one. |
92 | false |
93 |
94 |
95 | | isOpen |
96 | boolean |
97 | If true, the picker will be shown without user interaction. |
98 | false |
99 |
100 |
101 | | showPresets |
102 | boolean |
103 | If true, the picker will show the preset ranges for selection. |
104 | false |
105 |
106 |
107 | | showPresetsOnly |
108 | boolean |
109 | If true, the preset ranges will only show. Requires range and showPreset to be set. |
110 | false |
111 |
112 |
113 | | showYearControls |
114 | boolean |
115 | If true, the picker will hide the year navigation controls. |
116 | false |
117 |
118 |
119 | | showTimePicker |
120 | boolean |
121 | If true, the picker will show the time picker. |
122 | false |
123 |
124 |
125 | | enableFutureDates |
126 | boolean |
127 | If true, the picker will allow the user to select future dates. |
128 | false |
129 |
130 |
131 | | enablePastDates |
132 | boolean |
133 | If disabled, the picker will prevent the user from selecting anything prior to today. |
134 | true |
135 |
136 |
137 | | theme |
138 | string |
139 | The theme name will be assigned to the theme data-attribute datepicker.[data-picker-theme="theme_value_here"]`. |
140 | empty |
141 |
142 |
143 | | defaultMonth |
144 | number |
145 |
146 | The month you want to show as the default.
147 | Accepted values 0-11
148 |
149 |
150 | - 0 - January
151 | - 1 - February
152 | - 2 - March
153 | - 3 - April
154 | - 4 - May
155 | - 5 - June
156 | - 6 - July
157 | - 7 - August
158 | - 8 - September
159 | - 9 - October
160 | - 10 - November
161 | - 11 - December
162 |
163 | |
164 | {today.getMonth()} |
165 |
166 |
167 | | startOfWeek |
168 | number |
169 |
170 | Defines what day will start your week.
171 | Accepted values 0-6
172 |
173 |
174 |
175 | - 0 - Sunday
176 | - 1 - Monday
177 | - 2 - Tuesday
178 | - 3 - Wednesday
179 | - 4 - Thursday
180 | - 5 - Friday
181 | - 6 - Saturday
182 |
183 | |
184 | 0 |
185 |
186 |
187 | | disabledDates |
188 | array |
189 |
190 | Determines which dates will be disabled.
191 | Accepted format 'MM/DD/YYYY'
192 |
193 |
194 |
195 |
196 | ['1/1/2023'] - Disables January 1st, 2023
197 | ['1/1/2023', '1/2/2023'] - Disables January 1st and 2nd, 2023
198 | ['1/1/2023:1/10/2023'] - Disables the range January 1st to 10th, 2023
199 |
200 | |
201 | [] |
202 |
203 |
204 | | enabledDates |
205 | array |
206 |
207 | Determines which dates will be enabled only.
208 | Accepted format 'MM/DD/YYYY'
209 |
210 |
211 |
212 |
213 | ['1/1/2023'] - Enables January 1st, 2023
214 | ['1/1/2023', '1/2/2023'] - Enables January 1st and 2nd, 2023
215 | ['1/1/2023:1/10/2023'] - Enables the range January 1st to 10th, 2023
216 |
217 | |
218 | [] |
219 |
220 |
221 | | dowLabels |
222 | array |
223 | An array of strings containing the days of the week. |
224 |
225 | [
226 |
227 | -
"Su",
228 | -
"Mo",
229 | -
"Tu",
230 | -
"We",
231 | -
"Th",
232 | -
"Fr",
233 | -
"Sa"
234 | ]
235 | |
236 |
237 |
238 | | monthLabels |
239 | array |
240 | An array of strings containing the months of the year. |
241 |
242 | [
243 |
244 | -
"January",
245 | -
"February",
246 | -
"March",
247 | -
"April",
248 | -
"May",
249 | -
"June",
250 | -
"July",
251 | -
"August",
252 | -
"September",
253 | -
"October",
254 | -
"November",
255 | -
"Decemeber"
256 | ]
257 | |
258 |
259 |
260 | | presetLabels |
261 | array |
262 | An array of strings of the default preset labels. |
263 |
264 | [
265 |
266 | -
"Today",
267 | -
"Last 7 Days",
268 | -
"Last 30 Days",
269 | -
"Last 60 Days",
270 | -
"Last 90 Days",
271 | -
"Last Year"
272 | ]
273 | |
274 |
275 |
276 | | presetRanges |
277 | array |
278 | An array of objects containing preset configurations. |
279 |
280 | [{
281 |
282 | -
"label": "string",
283 | -
"start": "Date",
284 | -
"end": "Date"
285 | }]
286 | |
287 |
288 |
289 | | includeFont |
290 | boolean |
291 | If false, the default font "Rubik" will not be loaded. |
292 | true |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 | Events
301 |
302 |
303 |
304 | | Name |
305 | Type |
306 | Description |
307 | Default |
308 |
309 |
310 | | onDateChange |
311 | function |
312 | Callback function to handle when date changes. |
313 | None |
314 |
315 |
316 | | onDayClick |
317 | function |
318 | Callback function to handle day click events. |
319 | None |
320 |
321 |
322 | | onNavigationChange |
323 | function |
324 | Callback function to handle the navigation click event for months and years. |
325 | None |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 | Examples
334 | Below are different examples of how you can configure the datepicker.
335 |
336 | Single Date
337 |
338 |
339 |
340 |
341 |
342 | Date Range
343 |
344 |
345 |
346 |
347 |
348 | Multipane Range
349 |
350 |
351 |
352 |
353 |
354 | Preset Ranges
355 |
356 |
357 |
358 |
359 |
360 | Presets Only
361 |
362 |
365 |
366 | Time Picker
367 |
368 |
369 |
370 |
371 |
372 | Disable Past dates
373 |
374 |
375 |
376 |
377 |
378 | Enable Future dates
379 |
380 |
381 |
382 |
383 |
384 | Disabled Dates
385 |
386 |
387 |
388 |
389 |
390 | Enabled Dates
391 |
392 |
393 |
394 |
395 |
396 | Theme
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
505 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @svelte-plugins/datepicker
2 |
3 | A simple datepicker component designed for Svelte.
4 |
5 | Try it in the [Svelte REPL](https://svelte.dev/repl/cae0ce6e92634878b6e1a587146decbd?version=4.2.7).
6 |
7 | ## Install
8 |
9 | ```bash
10 | # npm
11 | > npm install svelte @svelte-plugins/datepicker
12 |
13 | # pnpm
14 | > pnpm install svelte @svelte-plugins/datepicker
15 |
16 | # yarn
17 | > yarn add svelte @svelte-plugins/datepicker
18 | ```
19 |
20 | ## Using the DatePicker component
21 | ```svelte
22 |
49 |
50 |
51 |
52 |
53 |
54 |
61 | ```
62 |
63 | ## API
64 |
65 | ### Props
66 | | Prop | Description | Default |
67 | | :---------------- | :------------------------------------------------------------------------------------ | :-------------------------- |
68 | | startDate | The start date string or date object. | `object` (default: `null`)
69 | | endDate | The end date string or date object. | `object` (default: `null`)
70 | | startDateTime | The start date time string in 24 hour format. | `string` (default: `00:00`)
71 | | endDateTime | The end date time string in 24 hour format. | `string` (default: `00:00`)
72 | | defaultYear | The year you want to show as the default. | `number` (default: `2023`)
73 | | align | The edge alignment of the datepicker. | `string` (default: `left`)
74 | | enabledDates | An array of date strings to enable only. | `array` (default: [...])
75 | | disabledDates | An array of date strings to disable. | `array` (default: [...])
76 | | isRange | Changes the date picker into a range picker and allows start and end date selection. | `boolean` (default: `false`)
77 | | isMultipane | If true, two calendar months will be shown side-by-side instead of one. | `boolean` (default: `false`)
78 | | isOpen | If true, the picker will be shown without user interaction. | `boolean` (default: `false`)
79 | | showPresets | If true, the picker will show the preset ranges for selection. | `boolean` (default: `false`)
80 | | showPresetsOnly | If true, the picker will show only preset ranges. | `boolean` (default: `false`)
81 | | showYearControls | If true, the picker will hide the year navigation controls. | `boolean` (default: `false`)
82 | | showTimePicker | If true, the picker will show the time picker. | `boolean` (default: `false`)
83 | | enableFutureDates | If true, the picker will allow the user to select future dates. | `boolean` (default: `false`)
84 | | enablePastDates | If disabled, the picker will prevent the user from selecting anything prior to today. | `boolean` (default: `true`)
85 | | theme | The theme name that should be assigned to the theme data-attribute. | `string` (default: `''`)
86 | | presetRanges | The array of present configs to replace the default set with. | `array` (default: [...])
87 | | includeFont | If false, the default Rubik font will not be loaded | `boolean` (default: `true`)
88 |
89 | ### Events
90 | | Prop | Description | Default |
91 | | :----------------- | :------------------------------------------------------------------------------------ | :-------------------------- |
92 | | onDateChange | Callback function to handle date change events. | `function`
93 | | onDayClick | Callback function to handle day click events. | `function`
94 | | onNavigationChange | Callback function to handle the navigation click event for months and years | `function`
95 |
96 | ## Theming
97 | You can customize DatePicker theme using several methods:
98 | - Assign a theme class name via the `theme` property that includes all of your CSS variables overrides
99 | - Define the overrides directly using the `style` property
100 | - Override the CSS variables globally
101 |
102 | DatePicker CSS variables:
103 |
104 | ```css
105 | /**
106 | * Common Variables
107 | */
108 | --datepicker-border-color: #e8e9ea;
109 |
110 | --datepicker-border-radius-small: .125rem;
111 | --datepicker-border-radius-base: .25rem;
112 | --datepicker-border-radius-large: .5rem;
113 | --datepicker-border-radius-xlarge: .75rem;
114 | --datepicker-border-radius-xxlarge: 1rem;
115 | --datepicker-border-radius-xxxlarge: 1.125rem;
116 |
117 | --datepicker-state-active: #0087ff;
118 | --datepicker-state-hover: #e7f7fc;
119 |
120 | --datepicker-color: #21333d;
121 |
122 | --datepicker-font-family: 'Rubik', sans-serif;
123 |
124 | --datepicker-font-size-jumbo: 1.75rem;
125 | --datepicker-font-size-xxxlarge: 1.5rem;
126 | --datepicker-font-size-xxlarge: 1.375rem;
127 | --datepicker-font-size-xlarge: 1.25rem;
128 | --datepicker-font-size-large: 1.125rem;
129 | --datepicker-font-size-base: 14px;
130 | --datepicker-font-size-medium: 0.89rem;
131 | --datepicker-font-size-small: 0.75rem;
132 | --datepicker-font-size-xsmall: 0.625rem;
133 | --datepicker-font-size-xxsmall: 0.5rem;
134 | --datepicker-font-size-xxxsmall: 0.375rem;
135 | --datepicker-font-weight-thin: 100;
136 | --datepicker-font-weight-light: 300;
137 | --datepicker-font-weight-base: 400;
138 | --datepicker-font-weight-medium: 500;
139 | --datepicker-font-weight-bold: 700;
140 | --datepicker-font-weight-black: 900;
141 |
142 | --datepicker-spacing: 8px;
143 |
144 | --datepicker-margin-xsmall: calc(var(--datepicker-spacing) / 4);
145 | --datepicker-margin-small: calc(var(--datepicker-spacing) / 2);
146 | --datepicker-margin-base: var(--datepicker-spacing);
147 | --datepicker-margin-large: calc(var(--datepicker-spacing) * 2);
148 | --datepicker-margin-xlarge: calc(var(--datepicker-spacing) * 3);
149 | --datepicker-margin-xxlarge: calc(var(--datepicker-spacing) * 4);
150 | --datepicker-margin-xxxlarge: calc(var(--datepicker-spacing) * 5);
151 | --datepicker-margin-jumbo: calc(var(--datepicker-spacing) * 6);
152 |
153 | --datepicker-padding-xsmall: calc(var(--datepicker-spacing) / 4);
154 | --datepicker-padding-small: calc(var(--datepicker-spacing) / 2);
155 | --datepicker-padding-base: var(--datepicker-spacing);
156 | --datepicker-padding-large: calc(var(--datepicker-spacing) * 2);
157 | --datepicker-padding-xlarge: calc(var(--datepicker-spacing) * 3);
158 | --datepicker-padding-xxlarge: calc(var(--datepicker-spacing) * 4);
159 | --datepicker-padding-xxxlarge: calc(var(--datepicker-spacing) * 5);
160 | --datepicker-padding-jumbo: calc(var(--datepicker-spacing) * 6);
161 |
162 | /**
163 | * Container
164 | */
165 | --datepicker-container-background: #fff;
166 | --datepicker-container-border: 1px solid var(--datepicker-border-color);
167 | --datepicker-container-border-radius: 12px;
168 | --datepicker-container-box-shadow: 0 1px 20px rgba(0, 0, 0, 0.1);
169 | --datepicker-container-font-family: var(--datepicker-font-family);
170 | --datepicker-container-left: 0;
171 | --datepicker-container-position: absolute;
172 | --datepicker-container-top: 105%;
173 | --datepicker-container-width: fit-content;
174 | --datepicker-container-zindex: 99;
175 |
176 | /**
177 | * Calendar
178 | */
179 | --datepicker-calendar-border: 0;
180 | --datepicker-calendar-padding: var(--datepicker-padding-base) var(--datepicker-padding-large) var(--datepicker-padding-xlarge);
181 | --datepicker-calendar-position: relative;
182 | --datepicker-calendar-width: 310px;
183 |
184 | --datepicker-calendar-split-border: 1px solid var(--datepicker-border-color);
185 |
186 | /**
187 | * Calendar Header
188 | */
189 | --datepicker-calendar-header-align-items: center;
190 | --datepicker-calendar-header-color: var(--datepicker-color);
191 | --datepicker-calendar-header-display: flex;
192 | --datepicker-calendar-header-font-size: var(--datepicker-font-size-large);
193 | --datepicker-calendar-header-justify-content: space-between;
194 | --datepicker-calendar-header-margin: 0 0 var(--datepicker-margin-xlarge) 0;
195 | --datepicker-calendar-header-padding: var(--datepicker-padding-large) var(--datepicker-padding-base);
196 | --datepicker-calendar-header-user-select: none;
197 |
198 | /**
199 | * Calendar Header Month Navigation
200 | */
201 | --datepicker-calendar-header-month-nav-background: transparent;
202 | --datepicker-calendar-header-month-nav-background-hover: #f5f5f5;
203 | --datepicker-calendar-header-month-nav-border: 0;
204 | --datepicker-calendar-header-month-nav-cursor: pointer;
205 | --datepicker-calendar-header-month-nav-border-radius: 20px;
206 | --datepicker-calendar-header-month-nav-color: var(--datepicker-color);
207 | --datepicker-calendar-header-month-nav-cursor: pointer;
208 | --datepicker-calendar-header-month-nav-font-size: var(--datepicker-font-size-large);
209 | --datepicker-calendar-header-month-nav-height: 32px;
210 | --datepicker-calendar-header-month-nav-margin-left: -8px;
211 | --datepicker-calendar-header-month-nav-padding: var(--datepicker-padding-small);
212 | --datepicker-calendar-header-month-nav-text-align: center;
213 | --datepicker-calendar-header-month-nav-width: 32px;
214 |
215 | --datepicker-calendar-header-month-nav-icon-next-background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACLSURBVHgB7ZTLCYAwEERHbcASUpIlaAd2YDoxlmIX3ixFEwwYQQL5kCWwD94ph5mwywIMUzmLlYRBe1lXENBrT+oSgktwiepLNJ63EWkl3AOltBMCkHh/kEv5F9SCGN8IzKntEYfAdwQb0kYaHO4uoUJBBIdzOAoiKMMNQ47wDvEceA7Zrp3BMLVyA56LVFYQOkngAAAAAElFTkSuQmCC') no-repeat center center;
216 | --datepicker-calendar-header-month-nav-icon-next-background-size: 16px 16px;
217 | --datepicker-calendar-header-month-nav-icon-next-filter: invert(0);
218 | --datepicker-calendar-header-month-nav-icon-next-height: 16px;
219 | --datepicker-calendar-header-month-nav-icon-next-margin: auto;
220 | --datepicker-calendar-header-month-nav-icon-next-width: 16px;
221 |
222 | --datepicker-calendar-header-month-nav-icon-prev-background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACKSURBVHgB7ZbBDYAgDEW/xgEcgZHcQDYRJ5ER3EhHcAPtAQMHQwIiSNKXvAMH+CUNDQDDVM5kLMJCnsYBmXHDN1IgIxzO4QIZ+Ty8gT9cOuuZ3BHHQa4hGxTszVOpnoJaFMbXAk2OzvpNC+7zojYVewFcBBdRVRE9CqCR4EvWIR4JO5iC5jzD/IoLU/FXPXheCj0AAAAASUVORK5CYII=') no-repeat center center;
223 | --datepicker-calendar-header-month-nav-icon-prev-background-size: 16px 16px;
224 | --datepicker-calendar-header-month-nav-icon-prev-filter: invert(0);
225 | --datepicker-calendar-header-month-nav-icon-prev-height: 16px;
226 | --datepicker-calendar-header-month-nav-icon-prev-margin: auto;
227 | --datepicker-calendar-header-month-nav-icon-prev-width: 16px;
228 |
229 | /**
230 | * Calendar Header Text
231 | */
232 | --datepicker-calendar-header-text-align-items: center;
233 | --datepicker-calendar-header-text-color: var(--datepicker-color);
234 | --datepicker-calendar-header-text-display: flex;
235 | --datepicker-calendar-header-text-font-size: inherit;
236 | --datepicker-calendar-header-text-font-weight: var(--datepicker-font-weight-medium);
237 | --datepicker-calendar-header-text-gap: 8px;
238 |
239 | /**
240 | * Calendar Header Year Navigation Container
241 | */
242 | --datepicker-calendar-header-year-align-items: center;
243 | --datepicker-calendar-header-year-display: flex;
244 | --datepicker-calendar-header-year-flex-direction: column;
245 | --datepicker-calendar-header-year-margin: 0;
246 |
247 | /**
248 | * Calendar Header Year Navigation Controls
249 | */
250 | --datepicker-calendar-header-year-nav-display: block;
251 | --datepicker-calendar-header-year-nav-color: var(--datepicker-color);
252 | --datepicker-calendar-header-year-nav-height: 12px;
253 | --datepicker-calendar-header-year-nav-line-height: 12px;
254 | --datepicker-calendar-header-year-nav-margin: -2px 0 0 0;
255 | --datepicker-calendar-header-year-nav-padding: 0;
256 | --datepicker-calendar-header-year-nav-width: 12px;
257 | --datepicker-calendar-header-year-nav-icon-font-size: 13px;
258 |
259 | --datepicker-calendar-header-year-nav-icon-next-background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAABuSURBVHgB7c7BCYAwDIXhBy7gKB2hm9Vx3UJzqCASRWOTHvo+yDG8HyAiGt2Ef7LcLLeigyK31SsIdh4Pj9DGwyKu40u9kAht/OAe8TTuHvFm3C3iy3jziGQYv4vIMMjGcS0iwSjBWN/on4hoADu88UW4KXFVfgAAAABJRU5ErkJggg==') no-repeat center center;
260 | --datepicker-calendar-header-year-nav-icon-next-background-size: 12px 12px;
261 | --datepicker-calendar-header-year-nav-icon-next-display: block;
262 | --datepicker-calendar-header-year-nav-icon-next-filter: invert(0);
263 | --datepicker-calendar-header-year-nav-icon-next-height: 12px;
264 | --datepicker-calendar-header-year-nav-icon-next-width: 12px;
265 |
266 | --datepicker-calendar-header-year-nav-icon-prev-background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAB3SURBVHgB7dTRCYAwDATQAxdwlI6QzZpx3UIrKJSC1aS2fngP7kvi3VcBIqK/m26+S8qcssBHWu5Dynokwi5m9wIHyX5gHRGL2wAndYwoyxWN1DDi9XLLiG7lT0Z0L6+NGFZ+NWJoeW2EYjD9svy0PzACIiJqsAHF2EaCcjFGaQAAAABJRU5ErkJggg==') no-repeat center center;
267 | --datepicker-calendar-header-year-nav-icon-prev-background-size: 12px 12px;
268 | --datepicker-calendar-header-year-nav-icon-prev-display: block;
269 | --datepicker-calendar-header-year-nav-icon-prev-filter: invert(0);
270 | --datepicker-calendar-header-year-nav-icon-prev-height: 12px;
271 | --datepicker-calendar-header-year-nav-icon-prev-width: 12px;
272 |
273 | /**
274 | * Presets
275 | */
276 | --datepicker-presets-border: 1px solid var(--datepicker-border-color);
277 | --datepicker-presets-padding: 24px;
278 | --datepicker-presets-minwidth: 180px;
279 | --datepicker-presets-maxwidth: 200px;
280 |
281 | /**
282 | * Presets Button
283 | */
284 | --datepicker-presets-button-background: transparent;
285 | --datepicker-presets-button-background-hover: var(--datepicker-state-hover);
286 | --datepicker-presets-button-background-active: var(--datepicker-state-active);
287 |
288 | --datepicker-presets-button-border: 0;
289 | --datepicker-presets-button-border-radius: 40px;
290 | --datepicker-presets-button-border-radius-active: 20px;
291 |
292 | --datepicker-presets-button-color: var(--datepicker-color);
293 | --datepicker-presets-button-color-active: #fff;
294 | --datepicker-presets-button-color-hover: var(--datepicker-color);
295 | --datepicker-presets-button-color-focus: var(--datepicker-color);
296 |
297 | --datepicker-presets-button-cursor: pointer;
298 | --datepicker-presets-button-cursor-active: default;
299 |
300 | --datepicker-presets-button-font-family: var(--datepicker-font-family);
301 | --datepicker-presets-button-font-size: var(--datepicker-font-size-base);
302 | --datepicker-presets-button-font-weight-active: var(--datepicker-font-weight-medium);
303 | --datepicker-presets-button-outline-focus: 5px auto -webkit-focus-ring-color;
304 |
305 | --datepicker-presets-button-margin: var(--datepicker-margin-small) 0;
306 | --datepicker-presets-button-padding: calc(var(--datepicker-padding-base) + 2px) var(--datepicker-padding-large);
307 | --datepicker-presets-button-text-align: left;
308 | --datepicker-presets-button-zindex-focus: 10;
309 |
310 | /**
311 | * Timepicker Container
312 | */
313 | --datepicker-timepicker-container-align-items: center;
314 | --datepicker-timepicker-container-display: flex;
315 | --datepicker-timepicker-container-justify-content: space-around;
316 | --datepicker-timepicker-container-margin-bottom: var(--datepicker-margin-xlarge);
317 |
318 | /**
319 | * Timepicker Input
320 | */
321 | --datepicker-timepicker-input-border: 1px solid var(--datepicker-border-color);
322 | --datepicker-timepicker-input-border-radius: var(--datepicker-border-radius-base);
323 | --datepicker-timepicker-input-display: block;
324 | --datepicker-timepicker-input-font-family: var(--datepicker-font-family);
325 | --datepicker-timepicker-input-margin: 0 auto;
326 | --datepicker-timepicker-input-padding: var(--datepicker-padding-small) var(--datepicker-padding-base);
327 |
328 | /**
329 | * Calendar DOW (Days of Week)
330 | */
331 | --datepicker-calendar-dow-color: #8b9198;
332 | --datepicker-calendar-dow-font-size: var(--datepicker-font-size-base);
333 | --datepicker-calendar-dow-font-weight: var(--datepicker-font-weight-medium);
334 | --datepicker-calendar-dow-margin-bottom: var(--datepicker-margin-large);
335 | --datepicker-calendar-dow-text-align: center;
336 |
337 | /**
338 | * Calendar Month
339 | */
340 | --datepicker-calendar-container-display: grid;
341 | --datepicker-calendar-container-grid-template-columns: repeat(7, 1fr);
342 | --datepicker-calendar-container-grid-gap: 0;
343 | --datepicker-calendar-container-width: fit-content;
344 |
345 | /**
346 | * Calendar Day Container
347 | */
348 | --datepicker-calendar-day-container-appearance: none;
349 | --datepicker-calendar-day-container-background: inherit;
350 | --datepicker-calendar-day-container-border: 0;
351 | --datepicker-calendar-day-container-margin: 0;
352 | --datepicker-calendar-day-container-padding: 0;
353 | --datepicker-calendar-day-container-position: relative;
354 | --datepicker-calendar-day-container-text-align: center;
355 |
356 | /**
357 | * Calendar Day
358 | */
359 | --datepicker-calendar-day-align-items: center;
360 | --datepicker-calendar-day-background-hover: #f5f5f5;
361 | --datepicker-calendar-day-border: 1px solid transparent;
362 | --datepicker-calendar-day-border: 1px solid transparent;
363 | --datepicker-calendar-day-border-radius: 100%;
364 | --datepicker-calendar-day-color: #232a32;
365 | --datepicker-calendar-day-color-disabled: #b9bdc1;
366 | --datepicker-calendar-day-color-hover: #232a32;
367 | --datepicker-calendar-day-cursor: pointer;
368 | --datepicker-calendar-day-cursor-disabled: default;
369 | --datepicker-calendar-day-display: flex;
370 | --datepicker-calendar-day-height: 40px;
371 | --datepicker-calendar-day-justify-content: center;
372 | --datepicker-calendar-day-font-family: var(--datepicker-font-family);
373 | --datepicker-calendar-day-font-size: var(--datepicker-font-size-base);
374 | --datepicker-calendar-day-margin-bottom: 1px;
375 | --datepicker-calendar-day-padding: var(--datepicker-padding-base);
376 | --datepicker-calendar-day-text-align: center;
377 | --datepicker-calendar-day-width: 40px;
378 | --datepicker-calendar-day-zindex-focus: 12;
379 |
380 | /**
381 | * Calendar Days Outside of Month
382 | */
383 | --datepicker-calendar-day-other-border: 0;
384 | --datepicker-calendar-day-other-box-shadow: none;
385 | --datepicker-calendar-day-other-color: #d1d3d6;
386 |
387 | /**
388 | * Calendar Today
389 | */
390 | --datepicker-calendar-today-background: transparent;
391 | --datepicker-calendar-today-border: 1px solid #232a32;
392 | --datepicker-calendar-today-cursor: default;
393 | --datepicker-calendar-today-font-weight: var(--datepicker-font-weight-bold);
394 |
395 | /**
396 | * Calendar Range
397 | */
398 | --datepicker-calendar-range-background: var(--datepicker-state-hover);
399 | --datepicker-calendar-range-background-disabled: var(--datepicker-state-hover);
400 | --datepicker-calendar-range-border: 0;
401 | --datepicker-calendar-range-border-radius: 0;
402 | --datepicker-calendar-range-color: var(--datepicker-color);
403 | --datepicker-calendar-range-color-disabled: #ffc0b7;
404 | --datepicker-calendar-range-cursor: default;
405 | --datepicker-calendar-range-font-weight: var(--datepicker-font-weight-base);
406 |
407 | /**
408 | * Calendar Range Start & End
409 | */
410 | --datepicker-calendar-range-start-box-shadow: inset -20px 0 0 var(--datepicker-state-hover);
411 | --datepicker-calendar-range-end-box-shadow: inset 20px 0 0 var(--datepicker-state-hover);
412 | --datepicker-calendar-range-start-box-shadow-selected: inset -20px 0 0 #eceff1;
413 | --datepicker-calendar-range-end-box-shadow-selected: inset 20px 0 0 #eceff1;
414 |
415 | --datepicker-calendar-range-start-end-background: #f5f5f5;
416 | --datepicker-calendar-range-start-end-color: #232a32;
417 |
418 | /**
419 | * Calendar Range Selected
420 | */
421 | --datepicker-calendar-range-selected-background: var(--datepicker-state-active);
422 | --datepicker-calendar-range-selected-border-radius: 20px;
423 | --datepicker-calendar-range-selected-color: #fff;
424 | --datepicker-calendar-range-selected-font-weight: var(--datepicker-font-weight-medium);
425 |
426 | --datepicker-calendar-range-selected-start-border-radius: 20px;
427 |
428 | /**
429 | * Calendar Range Hover
430 | */
431 | --datepicker-calendar-range-included-background: #eceff1;
432 | --datepicker-calendar-range-included-box-shadow: inset 20px 0 0 #eceff1;
433 | --datepicker-calendar-range-included-color: #232a32;
434 | --datepicker-calendar-range-included-font-weight: var(--datepicker-font-weight-base);
435 | --datepicker-calendar-range-included-height: var(--datepicker-calendar-day-height);
436 | ```
437 |
438 | ### Using the theme property
439 |
440 | ```svelte
441 | ...
442 |
443 |
470 | ```
471 |
472 | ## Changelog
473 |
474 | [Changelog](CHANGELOG.md)
475 |
476 | ## License
477 |
478 | [MIT](LICENSE)
479 |
--------------------------------------------------------------------------------
/src/datepicker.svelte:
--------------------------------------------------------------------------------
1 |
937 |
938 |
939 |
940 |
947 | {#if isRange && showPresets}
948 |
949 | {#each presetRanges as option}
950 |
958 | {/each}
959 |
960 | {/if}
961 |
962 |
983 |
984 | {#if showTimePicker}
985 |
986 | (startDate = updateTime('start', startDate))} />
987 |
988 | {#if isRange}
989 | (endDate = updateTime('end', endDate))}
994 | />
995 | {/if}
996 |
997 | {/if}
998 |
999 |
1000 | {#each dowLabels as text, labelIndex (text)}
1001 |
{dowLabels[(labelIndex + startOfWeek) % 7]}
1002 | {/each}
1003 |
1004 | {#each { length: 6 } as week, weekIndex (weekIndex)}
1005 | {#if startDateCalendar[weekIndex]}
1006 | {#each { length: 7 } as d, dayIndex (dayIndex)}
1007 | {#if startDateCalendar[weekIndex][dayIndex] !== 0}
1008 |
1030 | {:else}
1031 |
1032 | {/if}
1033 | {/each}
1034 | {/if}
1035 | {/each}
1036 |
1037 |
1038 |
1039 | {#if isRange && isMultipane}
1040 |
1041 |
1063 |
1064 | {#if showTimePicker}
1065 |
1066 | (endDate = updateTime('end', endDate))} />
1067 |
1068 | {/if}
1069 |
1070 |
1071 | {#each dowLabels as text, labelIndex (text)}
1072 |
{dowLabels[(labelIndex + startOfWeek) % 7]}
1073 | {/each}
1074 |
1075 | {#each { length: 6 } as week, weekIndex (weekIndex)}
1076 | {#if endDateCalendar[weekIndex]}
1077 | {#each { length: 7 } as d, dayIndex (dayIndex)}
1078 | {#if endDateCalendar[weekIndex][dayIndex] !== 0}
1079 |
1101 | {:else}
1102 |
1103 | {/if}
1104 | {/each}
1105 | {/if}
1106 | {/each}
1107 |
1108 |
1109 | {/if}
1110 |
1111 |
1112 |
1113 |
1114 | {#if includeFont}
1115 |
1119 | {/if}
1120 |
1121 |
1122 |
1938 |
--------------------------------------------------------------------------------