├── .prettierrc.json ├── docs ├── CNAME └── index.html ├── .prettierignore ├── config ├── vitest │ ├── package.json │ ├── vitest.setup.ts │ └── vitest.config.ts ├── vitest.setup.ts ├── static │ └── index.html ├── start.ts ├── startApp.ts ├── build.ts ├── buildApp.ts ├── utils │ ├── filesUtils.ts │ ├── colorsUtils.ts │ ├── tsUtils.ts │ ├── filterConsoleUtils.ts │ └── esbuildUtils.ts └── vitest.config.ts ├── packages ├── example │ ├── src │ │ ├── code │ │ │ ├── index.ts │ │ │ └── code.ts │ │ ├── examples │ │ │ ├── index.tsx │ │ │ ├── examples.css │ │ │ └── examples.tsx │ │ ├── reactJewishDatePickerExample │ │ │ ├── index.ts │ │ │ ├── code.tsx │ │ │ ├── ReactJewishDatePickerExample.css │ │ │ └── ReactJewishDatePickerExample.tsx │ │ ├── app.tsx │ │ ├── index.tsx │ │ ├── app.css │ │ └── index.css │ ├── config │ │ ├── vitest.config.ts │ │ └── static │ │ │ └── index.html │ ├── index.html │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── jewishDatesCore │ ├── config │ │ ├── package.json │ │ ├── vitest.config.ts │ │ ├── static │ │ │ └── index.html │ │ └── vitest.config.ts.timestamp-1741808516064-f9e8de71522fc.mjs │ ├── src │ │ ├── index.ts │ │ ├── interfaces.ts │ │ ├── jewishDateCore.ts │ │ └── __tests__ │ │ │ └── jewishDatesCore.test.tsx │ ├── app │ │ └── index.tsx │ ├── tsconfig.json │ ├── package.json │ └── README.md └── reactJewishDatePicker │ ├── src │ ├── utils │ │ ├── index.ts │ │ ├── testUtils.ts │ │ └── dateUtils.ts │ ├── index.ts │ ├── weekday.tsx │ ├── __tests__ │ │ ├── test-utils.jsx │ │ └── reactJewishDatePicker.test.tsx │ ├── interfaces.ts │ ├── reactJewishDatePicker.css │ ├── reactJewishDatePicker.tsx │ ├── navigation.tsx │ ├── day.tsx │ ├── month.css │ └── month.tsx │ ├── config │ ├── package.json │ ├── vitest.config.ts │ └── static │ │ └── index.html │ ├── app │ ├── index.css │ ├── index.tsx │ └── app.tsx │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── .yarn ├── versions │ ├── 82d3b56d.yml │ ├── 373c9408.yml │ ├── 95027668.yml │ ├── d560bff0.yml │ └── d59fb678.yml └── sdks │ ├── integrations.yml │ ├── prettier │ ├── package.json │ ├── index.cjs │ └── bin │ │ └── prettier.cjs │ └── typescript │ ├── package.json │ ├── lib │ ├── typescript.js │ ├── tsc.js │ ├── tsserver.js │ └── tsserverlibrary.js │ └── bin │ ├── tsc │ └── tsserver ├── images ├── snapshot.png ├── snapshot_new.png ├── snapshot_hebrew.png └── snapshot_english.png ├── .editorconfig ├── dev.md ├── .yarnrc.yml ├── LICENSE ├── package.json ├── .gitignore ├── .github └── workflows │ └── ci.js.yml └── README.md /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | react-jewish-datepicker.js.org -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | dist 3 | .yarn -------------------------------------------------------------------------------- /config/vitest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } -------------------------------------------------------------------------------- /packages/example/src/code/index.ts: -------------------------------------------------------------------------------- 1 | export * from './code'; -------------------------------------------------------------------------------- /packages/example/src/examples/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './examples'; -------------------------------------------------------------------------------- /packages/jewishDatesCore/config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './testUtils'; -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } -------------------------------------------------------------------------------- /.yarn/versions/82d3b56d.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - example 3 | - jewish-dates-core 4 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/app/index.css: -------------------------------------------------------------------------------- 1 | @import url('../src/reactJewishDatePicker.css'); -------------------------------------------------------------------------------- /.yarn/versions/373c9408.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - jewish-dates-core 3 | - react-jewish-datepicker 4 | -------------------------------------------------------------------------------- /.yarn/versions/95027668.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - jewish-dates-core 3 | - react-jewish-datepicker 4 | -------------------------------------------------------------------------------- /.yarn/versions/d560bff0.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - jewish-dates-core 3 | - react-jewish-datepicker 4 | -------------------------------------------------------------------------------- /.yarn/versions/d59fb678.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - jewish-dates-core 3 | - react-jewish-datepicker 4 | -------------------------------------------------------------------------------- /packages/example/src/reactJewishDatePickerExample/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ReactJewishDatePickerExample'; -------------------------------------------------------------------------------- /images/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shmulik-Kravitz/react-jewish-datepicker/HEAD/images/snapshot.png -------------------------------------------------------------------------------- /images/snapshot_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shmulik-Kravitz/react-jewish-datepicker/HEAD/images/snapshot_new.png -------------------------------------------------------------------------------- /images/snapshot_hebrew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shmulik-Kravitz/react-jewish-datepicker/HEAD/images/snapshot_hebrew.png -------------------------------------------------------------------------------- /images/snapshot_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shmulik-Kravitz/react-jewish-datepicker/HEAD/images/snapshot_english.png -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./reactJewishDatePicker"; 2 | export * from "./month"; 3 | export * from "./interfaces"; 4 | -------------------------------------------------------------------------------- /packages/example/config/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import {getConfig} from "../../../config/vitest.config"; 2 | const config = getConfig(); 3 | export default config; -------------------------------------------------------------------------------- /.yarn/sdks/integrations.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by @yarnpkg/sdks. 2 | # Manual changes might be lost! 3 | 4 | integrations: 5 | - vscode 6 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/config/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import {getConfig} from "../../../config/vitest/vitest.config"; 2 | const config = getConfig(); 3 | export default config; -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/config/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import {getConfig} from "../../../config/vitest/vitest.config"; 2 | const config = getConfig(); 3 | export default config; -------------------------------------------------------------------------------- /.yarn/sdks/prettier/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prettier", 3 | "version": "3.3.3-sdk", 4 | "main": "./index.cjs", 5 | "type": "commonjs", 6 | "bin": "./bin/prettier.cjs" 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{js,json,yml}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./interfaces"; 2 | export * from "./jewishDateCore"; 3 | import { JewishMonth as OrigJJewishMonth } from "jewish-date"; 4 | 5 | export const JewishMonth = OrigJJewishMonth; 6 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript", 3 | "version": "5.6.2-sdk", 4 | "main": "./lib/typescript.js", 5 | "type": "commonjs", 6 | "bin": { 7 | "tsc": "./bin/tsc", 8 | "tsserver": "./bin/tsserver" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /dev.md: -------------------------------------------------------------------------------- 1 | ### Run local reposetery 2 | 3 | ```console 4 | npm install --global verdaccio 5 | verdaccio 6 | 7 | npmPublishRegistry: http://localhost:4873/ 8 | 9 | npmRegistryServer: http://localhost:4873/ 10 | 11 | unsafeHttpWhitelist: 12 | - localhost 13 | ``` -------------------------------------------------------------------------------- /config/vitest.setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | import filterConsole from "./utils/filterConsoleUtils"; 3 | 4 | export const setup = () => { 5 | const disableFilter = filterConsole(['MODULE_NOT_FOUND']); 6 | }; 7 | export const teardown = () => { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /packages/example/src/app.tsx: -------------------------------------------------------------------------------- 1 | import { Examples } from './examples'; 2 | import "./app.css"; 3 | import React from "react"; 4 | 5 | function App() { 6 | 7 | return ( 8 |
9 | 10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /config/vitest/vitest.setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/vitest'; 2 | import filterConsole from "../utils/filterConsoleUtils"; 3 | 4 | export const setup = () => { 5 | const disableFilter = filterConsole(['MODULE_NOT_FOUND']); 6 | }; 7 | export const teardown = () => { 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/weekday.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from "react"; 2 | 3 | export interface WeekdayProps { 4 | value: string; 5 | } 6 | 7 | export const Weekday: FC = (props: WeekdayProps) => { 8 | return
{props.value}
; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/example/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './app' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/app/index.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | import { App } from "./app"; 3 | 4 | import "./index.css"; 5 | import "../src/reactJewishDatePicker.css"; 6 | 7 | 8 | const root = createRoot(document.getElementById("root") as HTMLElement); 9 | root.render( 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/__tests__/test-utils.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | 4 | const customRender = (ui, options) => 5 | render(ui, { ...options }); 6 | 7 | // re-export everything 8 | export * from "@testing-library/react"; 9 | 10 | // override render method 11 | export { customRender as render }; 12 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/utils/testUtils.ts: -------------------------------------------------------------------------------- 1 | export const isFromTest = () => { 2 | // console.log(process.env); 3 | return ( 4 | typeof process !== "undefined" && 5 | (process.env?.JEST_WORKER_ID !== undefined || 6 | process.env?.VITEST_WORKER_ID !== undefined) 7 | ); 8 | }; 9 | 10 | export const getTestID = (testId: string) => { 11 | return isFromTest() ? testId : undefined; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | example 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /config/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | example 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /config/start.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | import { start } from "./utils/esbuildUtils"; 4 | 5 | 6 | const rootPath = path.resolve(`.`,); 7 | 8 | const cssFilePath = path.resolve(rootPath, `app/index.css`); 9 | const entryPoints: string[] = [path.resolve(rootPath, `app/index.tsx`), fs.existsSync(cssFilePath) ? cssFilePath : ""].filter(value => value !== ""); 10 | 11 | const outDir = path.resolve(rootPath, `config/static/`); 12 | 13 | start(entryPoints, outDir); 14 | -------------------------------------------------------------------------------- /packages/example/config/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | example 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /config/startApp.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | import { start } from "./utils/esbuildUtils"; 4 | 5 | 6 | const rootPath = path.resolve(`.`,); 7 | 8 | const cssFilePath = path.resolve(rootPath, `src/index.css1`); 9 | const entryPoints: string[] = [path.resolve(rootPath, `src/index.tsx`), fs.existsSync(cssFilePath) ? cssFilePath : ""].filter(value => value !== ""); 10 | 11 | const outDir = path.resolve(rootPath, `config/static/`); 12 | 13 | start(entryPoints, outDir); 14 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/interfaces.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BasicJewishDate as BasicJewishDateCore, 3 | BasicJewishDay as BasicJewishDayCore, 4 | } from "jewish-dates-core"; 5 | 6 | export interface DateRange { 7 | startDate: Date; 8 | endDate: Date; 9 | } 10 | 11 | export interface BasicJewishDateRange { 12 | startDate: BasicJewishDate; 13 | endDate: BasicJewishDate; 14 | } 15 | 16 | export type BasicJewishDate = BasicJewishDateCore; 17 | export type BasicJewishDay = BasicJewishDayCore; 18 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/config/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | example 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/config/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | example 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/example/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .history/ 26 | 27 | .pnp.* 28 | .yarn/* 29 | !.yarn/patches 30 | !.yarn/plugins 31 | !.yarn/releases 32 | !.yarn/sdks 33 | !.yarn/versions 34 | -------------------------------------------------------------------------------- /config/build.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { build } from "./utils/esbuildUtils"; 3 | import filterConsole from "./utils/filterConsoleUtils"; 4 | 5 | const disableFilter = filterConsole(["MODULE_NOT_FOUND"]); 6 | 7 | const outPath = path.resolve(".", "dist/"); 8 | const declarationPath = path.resolve(".", "lib/"); 9 | 10 | const srcPath = path.resolve(".", "src/"); 11 | const tsconfigPath = path.resolve(".", "tsconfig.json"); 12 | // console.log({ outDir, tsconfig }); 13 | 14 | build(__dirname, tsconfigPath, srcPath, outPath, declarationPath); 15 | -------------------------------------------------------------------------------- /config/buildApp.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { buildApp } from "./utils/esbuildUtils"; 3 | import filterConsole from "./utils/filterConsoleUtils"; 4 | 5 | const disableFilter = filterConsole(["MODULE_NOT_FOUND"]); 6 | 7 | const outPath = path.resolve(".", "dist/"); 8 | const declarationPath = path.resolve(".", "lib/"); 9 | 10 | const srcPath = path.resolve(".", "src/"); 11 | const tsconfigPath = path.resolve(".", "tsconfig.json"); 12 | // console.log({ outDir, tsconfig }); 13 | 14 | buildApp(__dirname, tsconfigPath, srcPath, outPath, declarationPath); 15 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableColors: false 4 | 5 | enableGlobalCache: false 6 | 7 | logFilters: 8 | - code: YN0002 9 | level: discard 10 | - code: YN0076 11 | level: discard 12 | 13 | nodeLinker: pnp 14 | 15 | npmPublishAccess: public 16 | 17 | packageExtensions: 18 | debug@*: 19 | dependencies: 20 | supports-color: "*" 21 | vite@*: 22 | dependencies: 23 | supports-color: "*" 24 | 25 | pnpFallbackMode: all 26 | 27 | pnpMode: loose 28 | 29 | yarnPath: .yarn/releases/yarn-4.7.0.cjs 30 | -------------------------------------------------------------------------------- /packages/example/src/reactJewishDatePickerExample/code.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/prism'; 3 | import { docco } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; 4 | export interface CodeProps { 5 | code: string; 6 | } 7 | export const Code: React.FC = React.memo((props: CodeProps) => { 8 | const ref = React.useRef(null); 9 | return ( 10 | 11 | {props.code} 12 | 13 | ); 14 | }); 15 | -------------------------------------------------------------------------------- /config/utils/filesUtils.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { promisify } from "util"; 4 | const readdir = promisify(fs.readdir); 5 | const stat = promisify(fs.stat); 6 | 7 | export const getFiles = async (dir: string) => { 8 | const subDirs = await readdir(dir); 9 | const files = await Promise.all( 10 | subDirs.map(async (subDir) => { 11 | const res = path.resolve(dir, subDir); 12 | return (await stat(res)).isDirectory() ? getFiles(res) : res; 13 | }), 14 | ); 15 | return files.reduce((a, f) => a.concat(f), []); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/app/index.tsx: -------------------------------------------------------------------------------- 1 | import { BasicJewishMonthInfo, getNextMonth, getPrevMonth, JewishMonth } from "../src"; 2 | 3 | let month: BasicJewishMonthInfo = { 4 | month: JewishMonth.Tishri, 5 | year: 5782, 6 | isHebrew: true, 7 | }; 8 | for (let index = 0; index < 12; index++) { 9 | month = getNextMonth(month); 10 | console.log(month); 11 | } 12 | console.log('----------------------------------------------------------------'); 13 | for (let index = 0; index < 12; index++) { 14 | month = getPrevMonth(month); 15 | console.log(month); 16 | } 17 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "declarationDir": "build", 5 | "emitDeclarationOnly": true, 6 | "declarationMap": true, 7 | "module": "ESNext", 8 | "target": "ESNext", 9 | "lib": ["es6", "dom", "es2016", "es2017"], 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "moduleResolution": "node", 13 | "allowSyntheticDefaultImports": true, 14 | "esModuleInterop": true, 15 | "allowJs": true 16 | }, 17 | "include": ["./src/**/*", "./app/**/*", "./__test__/**/*"], 18 | "exclude": ["./node_modules/**/*", "./dist/**/*", "./yarn/**/*"], 19 | } 20 | -------------------------------------------------------------------------------- /config/utils/colorsUtils.ts: -------------------------------------------------------------------------------- 1 | export const Colors = { 2 | Reset: "\x1b[0m", 3 | Bright: "\x1b[1m", 4 | Dim: "\x1b[2m", 5 | Underscore: "\x1b[4m", 6 | Blink: "\x1b[5m", 7 | Reverse: "\x1b[7m", 8 | Hidden: "\x1b[8m", 9 | 10 | FgBlack: "\x1b[30m", 11 | FgRed: "\x1b[31m", 12 | FgGreen: "\x1b[32m", 13 | FgYellow: "\x1b[33m", 14 | FgBlue: "\x1b[34m", 15 | FgMagenta: "\x1b[35m", 16 | FgCyan: "\x1b[36m", 17 | FgWhite: "\x1b[37m", 18 | 19 | BgBlack: "\x1b[40m", 20 | BgRed: "\x1b[41m", 21 | BgGreen: "\x1b[42m", 22 | BgYellow: "\x1b[43m", 23 | BgBlue: "\x1b[44m", 24 | BgMagenta: "\x1b[45m", 25 | BgCyan: "\x1b[46m", 26 | BgWhite: "\x1b[47m", 27 | }; 28 | -------------------------------------------------------------------------------- /config/vitest/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { configDefaults, defineConfig } from 'vitest/config'; 2 | import react from '@vitejs/plugin-react'; 3 | import filterConsole from '../utils/filterConsoleUtils'; 4 | const disableFilter = filterConsole(['MODULE_NOT_FOUND']); 5 | 6 | export const getConfig = () => defineConfig({ 7 | plugins: [react()], 8 | test: { 9 | globals: true, 10 | watch: false, 11 | setupFiles: [__dirname + '/vitest.setup.ts'], 12 | environment: 'jsdom', 13 | coverage: { 14 | reporter: ['text', 'json', 'html', 'cobertura'], 15 | exclude: ['**/.pnp.*'], 16 | 17 | }, 18 | exclude: [...configDefaults.exclude, '**/.pnp.*'], 19 | }, 20 | }) -------------------------------------------------------------------------------- /packages/example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["node", "@testing-library/jest-dom"], 4 | "declaration": true, 5 | "declarationDir": "build", 6 | "emitDeclarationOnly": true, 7 | "module": "ESNext", 8 | "target": "ESNext", 9 | "lib": ["es6", "dom", "es2016", "es2017"], 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "jsx": "react", 13 | "moduleResolution": "node", 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "allowJs": true 17 | }, 18 | "include": ["./src/**/*", "./app/**/*", "./__test__/**/*"], 19 | "exclude": ["./node_modules/**/*", "./dist/**/*", "./yarn/**/*"], 20 | } 21 | -------------------------------------------------------------------------------- /config/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { configDefaults, defineConfig } from 'vitest/config'; 2 | import react from '@vitejs/plugin-react'; 3 | import filterConsole from './utils/filterConsoleUtils'; 4 | const disableFilter = filterConsole(['MODULE_NOT_FOUND']); 5 | 6 | export const getConfig = () => defineConfig({ 7 | plugins: [react()], 8 | test: { 9 | globals: true, 10 | watch: false, 11 | // globalSetup: __dirname + '/vitest.setup.ts', 12 | setupFiles: "@testing-library/jest-dom", 13 | environment: 'jsdom', 14 | coverage: { 15 | reporter: ['text', 'json', 'html', 'cobertura'], 16 | exclude: ['**/.pnp.*'], 17 | 18 | }, 19 | exclude: [...configDefaults.exclude, '**/.pnp.*'], 20 | }, 21 | }) -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["node", "@testing-library/jest-dom"], 4 | "declaration": true, 5 | "declarationDir": "build", 6 | "emitDeclarationOnly": true, 7 | "module": "ESNext", 8 | "target": "ESNext", 9 | "lib": ["es6", "dom", "es2016", "es2017"], 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "jsx": "react-jsx", 13 | "moduleResolution": "node", 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "allowJs": true 17 | }, 18 | "include": ["./src/**/*", "./app/**/*", "./__test__/**/*"], 19 | "exclude": ["./node_modules/**/*", "./dist/**/*", "./yarn/**/*"], 20 | } 21 | -------------------------------------------------------------------------------- /packages/example/src/app.css: -------------------------------------------------------------------------------- 1 | #root { 2 | width: 100vw; 3 | display: grid; 4 | } 5 | .app { 6 | display: grid; 7 | } 8 | 9 | .logo { 10 | height: 6em; 11 | padding: 1.5em; 12 | will-change: filter; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/app/app.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from "react"; 2 | import { BasicJewishDay, ReactJewishDatePicker } from "../src"; 3 | 4 | export const App: React.FC<{}> = (_props) => { 5 | const [value, setValue] = useState(new Date()); 6 | const handleClick = useCallback((day: BasicJewishDay) => { 7 | console.log(day); 8 | setValue(day.date); 9 | },[]); 10 | 11 | // const handleClick = (day: BasicJewishDay) => { 12 | // console.log(day); 13 | // setValue(day.date); 14 | // }; 15 | return ( 16 |
17 | 21 |
22 | ); 23 | }; -------------------------------------------------------------------------------- /config/utils/tsUtils.ts: -------------------------------------------------------------------------------- 1 | import { build as tscBuild} from "tsc-prog"; 2 | 3 | export async function buildDeclarations(basePath: string, tsconfigPath: string, srcPath: string, declarationsOutPath: string) { 4 | return new Promise((resolve: () => void) => { 5 | tscBuild({ 6 | basePath: basePath, // always required, used for relative paths 7 | configFilePath: tsconfigPath, // config to inherit from (optional) 8 | compilerOptions: { 9 | rootDir: srcPath, 10 | declaration: true, 11 | declarationDir: declarationsOutPath, 12 | emitDeclarationOnly: true, 13 | pretty: true, 14 | }, 15 | include: ['src/**/*'], 16 | exclude: ['src/__test__/**/*'], 17 | }); 18 | resolve() 19 | }) 20 | } -------------------------------------------------------------------------------- /packages/example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "private": true, 4 | "version": "0.0.21", 5 | "module": "true", 6 | "scripts": { 7 | "start": "yarn g:start-app", 8 | "build": "yarn g:build-app && cp -R -a -f ./config/static/. ./dist/ && yarn copy-to-docs", 9 | "copy-to-docs": "cp -R -a -f ./dist/. ../../docs/ && echo copy to docs done", 10 | "test": "echo test", 11 | "inc": "echo inc", 12 | "pub": "echo publish" 13 | }, 14 | "dependencies": { 15 | "@react-icons/all-files": "^4.1.0", 16 | "@types/react-syntax-highlighter": "^15.5.13", 17 | "dayjs": "^1.11.13", 18 | "jewish-dates-core": "workspace:*", 19 | "prism-react-renderer": "^2.4.1", 20 | "react": "^18.3.1", 21 | "react-dom": "^18.3.1", 22 | "react-jewish-datepicker": "workspace:*", 23 | "react-live": "^4.1.8", 24 | "react-syntax-highlighter": "^15.6.1" 25 | }, 26 | "devDependencies": { 27 | "esbuild": "^0.25.1", 28 | "esbuild-node-externals": "^1.18.0", 29 | "has-flag": "5.0.1", 30 | "tsc-prog": "^2.3.0", 31 | "typescript": "^5.8.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Shmulik Kravitz. 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 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/index.cjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require prettier 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real prettier your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`prettier`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/typescript.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/bin/tsc 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript/bin/tsc your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsc`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/lib/tsc.js 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript/lib/tsc.js your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript/lib/tsc.js`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/bin/tsserver 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript/bin/tsserver your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsserver`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/bin/prettier.cjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require prettier/bin/prettier.cjs 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real prettier/bin/prettier.cjs your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`prettier/bin/prettier.cjs`)); 33 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/src/interfaces.ts: -------------------------------------------------------------------------------- 1 | import * as Dayjs from "dayjs"; 2 | import { 3 | BasicJewishDate as OrigBasicJewishDate, 4 | JewishDate as OrigJewishDate, 5 | JewishMonthType as OrigJewishMonthType 6 | } from "jewish-date"; 7 | 8 | export type BasicJewishDate = OrigBasicJewishDate; 9 | export type JewishDate = OrigJewishDate; 10 | export type JewishMonthType = OrigJewishMonthType; 11 | 12 | 13 | export interface BasicJewishDay { 14 | jewishDateStr: string; 15 | jewishDateStrHebrew: string; 16 | jewishDate: JewishDate; 17 | date: Date; 18 | } 19 | 20 | export interface JewishDay extends BasicJewishDay { 21 | day: number; 22 | isCurrentMonth: boolean; 23 | dayjsDate: Dayjs.Dayjs; 24 | } 25 | 26 | export interface Month { 27 | id: string; 28 | text: string; 29 | } 30 | 31 | export interface BasicJewishMonthInfo { 32 | month: JewishMonthType; 33 | year: number; 34 | isHebrew?: boolean; 35 | } 36 | 37 | export interface JewishMonthMetadata { 38 | jewishDate: JewishDate; 39 | jewishMonth: number; 40 | startOfJewishMonth: Dayjs.Dayjs; 41 | sundayStartOfTheMonth: Dayjs.Dayjs; 42 | } 43 | 44 | export interface JewishMonthInfo { 45 | selectedDay: JewishDay; 46 | jewishYear: number; 47 | jewishMonth: number; 48 | jewishMonthString: string; 49 | days: JewishDay[]; 50 | } 51 | 52 | export interface IdText { 53 | id: string; 54 | text: string; 55 | } 56 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jewish-dates-core", 3 | "version": "2.0.24", 4 | "description": "Jewish dates core", 5 | "main": "dist/index.js", 6 | "typings": "lib/index.d.ts", 7 | "exports": { 8 | ".": { 9 | "types": "./lib/index.d.ts", 10 | "import": "./dist/mjs/index.js", 11 | "require": "./dist/index.js" 12 | } 13 | }, 14 | "files": [ 15 | "dist", 16 | "lib", 17 | "README.md" 18 | ], 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/Shmulik-Kravitz/react-jewish-datepicker.git" 22 | }, 23 | "homepage": "https://react-jewish-datepicker.js.org/", 24 | "author": "Shmulik Kravitz <29735690+Shmulik-Kravitz@users.noreply.github.com>", 25 | "license": "MIT", 26 | "scripts": { 27 | "start": "yarn g:start", 28 | "dev": "yarn g:dev", 29 | "build": "yarn g:build", 30 | "test": "yarn g:test", 31 | "inc": "yarn version patch", 32 | "pub": "npm publish --provenance --access public", 33 | "np": "np patch" 34 | }, 35 | "dependencies": { 36 | "dayjs": "^1.11.13", 37 | "jewish-date": "^2.0.19" 38 | }, 39 | "devDependencies": { 40 | "esbuild": "^0.25.1", 41 | "typescript": "^5.8.2" 42 | }, 43 | "keywords": [ 44 | "jewish", 45 | "hebrew", 46 | "date", 47 | "luach", 48 | "calendar" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /config/utils/filterConsoleUtils.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import {format} from 'node:util'; 3 | 4 | export default function filterConsole(excludePatterns: any, options?: any) { 5 | options = { 6 | console, 7 | methods: [ 8 | 'log', 9 | 'debug', 10 | // 'info', 11 | 'warn', 12 | 'error', 13 | ], 14 | ...options, 15 | }; 16 | 17 | const {console: consoleObject, methods} = options; 18 | const originalMethods = methods.map(method => consoleObject[method]); 19 | 20 | const check = string => { 21 | for (const pattern of excludePatterns) { 22 | if (typeof pattern === 'string') { 23 | if (string.includes(pattern)) { 24 | return true; 25 | } 26 | } else if (typeof pattern === 'function') { 27 | if (pattern(string)) { 28 | return true; 29 | } 30 | } else if (pattern.test(string)) { 31 | return true; 32 | } 33 | } 34 | 35 | return false; 36 | }; 37 | 38 | for (const method of methods) { 39 | const originalMethod = consoleObject[method]; 40 | 41 | consoleObject[method] = (...args) => { 42 | if (check(format(...args))) { 43 | return; 44 | } 45 | 46 | originalMethod(...args); 47 | }; 48 | 49 | // Exposed for testing 50 | if (process.env.NODE_ENV === 'test') { 51 | consoleObject[method].original = originalMethod; 52 | } 53 | } 54 | 55 | return () => { 56 | for (const [index, method] of methods.entries()) { 57 | consoleObject[method] = originalMethods[index]; 58 | } 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /packages/example/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color-scheme: light dark; 8 | color: rgba(255, 255, 255, 0.87); 9 | background-color: #242424; 10 | 11 | font-synthesis: none; 12 | text-rendering: optimizeLegibility; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | -webkit-text-size-adjust: 100%; 16 | } 17 | 18 | a { 19 | font-weight: 500; 20 | color: #646cff; 21 | text-decoration: inherit; 22 | } 23 | a:hover { 24 | color: #535bf2; 25 | } 26 | 27 | body { 28 | margin: 0; 29 | display: flex; 30 | place-items: center; 31 | min-width: 320px; 32 | min-height: 100vh; 33 | } 34 | 35 | h1 { 36 | font-size: 2.2em; 37 | line-height: 1.1; 38 | } 39 | 40 | button { 41 | border-radius: 8px; 42 | border: 1px solid transparent; 43 | padding: 0.6em 1.2em; 44 | font-size: 1em; 45 | font-weight: 500; 46 | font-family: inherit; 47 | background-color: #1a1a1a; 48 | cursor: pointer; 49 | transition: border-color 0.25s; 50 | } 51 | button:hover { 52 | border-color: #646cff; 53 | } 54 | button:focus, 55 | button:focus-visible { 56 | outline: 4px auto -webkit-focus-ring-color; 57 | } 58 | 59 | @media (prefers-color-scheme: light) { 60 | :root { 61 | color: #213547; 62 | background-color: #ffffff; 63 | } 64 | a:hover { 65 | color: #747bff; 66 | } 67 | button { 68 | background-color: #f9f9f9; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/reactJewishDatePicker.css: -------------------------------------------------------------------------------- 1 | .reactJewishDatePicker { 2 | --color: #333; 3 | --backgroundColor: #e6e6e6; 4 | position: relative; 5 | display: grid; 6 | font-family: arial; 7 | margin-bottom: 5px; 8 | cursor: pointer; 9 | } 10 | .reactJewishDatePicker .selectedDate { 11 | padding: 2px 15px 2px 5px; 12 | border: 1px solid var(--color); 13 | border-radius: 4px; 14 | user-select: none; 15 | min-height: 20px; 16 | text-align: center; 17 | position: relative; 18 | font-size: smaller; 19 | } 20 | .reactJewishDatePicker .calendarIcon { 21 | font-size: 16px; 22 | position: absolute; 23 | right: 5px; 24 | top: 4px; 25 | } 26 | .reactJewishDatePicker .monthWrapper { 27 | position: absolute; 28 | top: 32px; 29 | z-index: 1; 30 | transform: scaleY(0); 31 | transform-origin: top; 32 | transition: transform 0.26s ease; 33 | transition: max-height 0.5s ease-out; 34 | box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); 35 | transition: all 0.4s ease-in-out; 36 | width: 254px; 37 | height: 243px; 38 | border-radius: 5px; 39 | } 40 | .reactJewishDatePicker .monthWrapper.open { 41 | transform: scaleY(1); 42 | } 43 | .reactJewishDatePicker.isHebrew { 44 | direction: rtl; 45 | } 46 | .reactJewishDatePicker.isHebrew .startDay { 47 | background: cornflowerblue; 48 | border-radius: 0 7px 7px 0; 49 | color: #fff; 50 | margin: 1px 0; 51 | } 52 | .reactJewishDatePicker.isHebrew .endDay { 53 | background: cornflowerblue; 54 | border-radius: 7px 0 0 7px; 55 | color: #fff; 56 | margin: 1px 0; 57 | } -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-jewish-datepicker", 3 | "version": "2.0.24", 4 | "description": "React jewish datepicker", 5 | "main": "dist/index.js", 6 | "typings": "lib/index.d.ts", 7 | "exports": { 8 | "./package.json": "./package.json", 9 | "./dist/index.css": "./dist/index.css", 10 | ".": { 11 | "types": "./lib/index.d.ts", 12 | "import": "./dist/mjs/index.js", 13 | "require": "./dist/index.js" 14 | } 15 | }, 16 | "files": [ 17 | "dist", 18 | "lib", 19 | "README.md" 20 | ], 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/Shmulik-Kravitz/react-jewish-datepicker.git" 24 | }, 25 | "homepage": "https://react-jewish-datepicker.js.org/", 26 | "author": "Shmulik Kravitz <29735690+Shmulik-Kravitz@users.noreply.github.com>", 27 | "license": "MIT", 28 | "scripts": { 29 | "start": "yarn g:start", 30 | "dev": "yarn g:dev", 31 | "copy-md": "cp README.md ../../", 32 | "build": "yarn g:build && yarn copy-md", 33 | "test": "yarn g:test", 34 | "inc": "yarn version patch", 35 | "pub": "npm publish --provenance --access public", 36 | "np": "np patch" 37 | }, 38 | "peerDependencies": { 39 | "react": "*", 40 | "react-dom": "*" 41 | }, 42 | "dependencies": { 43 | "@react-icons/all-files": "^4.1.0", 44 | "dayjs": "^1.11.13", 45 | "jewish-date": "^2.0.19", 46 | "jewish-dates-core": "workspace:*", 47 | "use-onclickoutside": "^0.4.1" 48 | }, 49 | "devDependencies": { 50 | "esbuild": "^0.25.1", 51 | "typescript": "^5.8.2" 52 | }, 53 | "keywords": [ 54 | "jewish", 55 | "hebrew", 56 | "date", 57 | "luach", 58 | "calendar" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/utils/dateUtils.ts: -------------------------------------------------------------------------------- 1 | import Dayjs from "dayjs"; 2 | import { getGregDate, isValidDate } from "jewish-dates-core"; 3 | import { 4 | BasicJewishDate, 5 | BasicJewishDateRange, 6 | BasicJewishDay, 7 | DateRange, 8 | } from "../interfaces"; 9 | 10 | export const getDatesInOrder = ( 11 | day1: BasicJewishDay, 12 | day2: BasicJewishDay, 13 | ): BasicJewishDay[] => { 14 | if (day1 && day2) { 15 | return Dayjs(day1.date).isBefore(Dayjs(day2.date)) 16 | ? [day1, day2] 17 | : [day2, day1]; 18 | } else { 19 | return []; 20 | } 21 | }; 22 | 23 | export const getDateStringForSelectedDay = ( 24 | isRange: boolean, 25 | isHebrew: boolean, 26 | selectedDay: BasicJewishDay, 27 | startDay: BasicJewishDay, 28 | endDay: BasicJewishDay, 29 | ): string => { 30 | if (isRange) { 31 | if (startDay?.jewishDateStrHebrew) { 32 | return isHebrew 33 | ? `${startDay?.jewishDateStrHebrew} - ${ 34 | endDay?.jewishDateStrHebrew || "" 35 | }` 36 | : `${startDay?.jewishDateStr} - ${endDay?.jewishDateStr || ""}`; 37 | } else { 38 | return isHebrew ? "בחר תאריכים" : "Pick Dates"; 39 | } 40 | } else if (selectedDay) { 41 | return isHebrew 42 | ? selectedDay.jewishDateStrHebrew 43 | : selectedDay.jewishDateStr; 44 | } else { 45 | return isHebrew ? "בחר תאריך" : "Pick Date"; 46 | } 47 | }; 48 | 49 | export const isDateRange = ( 50 | object = {}, 51 | ): object is BasicJewishDateRange | DateRange => { 52 | return "startDate" in object; 53 | }; 54 | 55 | export const getDateInit = ( 56 | date: Date | BasicJewishDate | BasicJewishDateRange | DateRange, 57 | ): Date => { 58 | if (isDateRange(date)) { 59 | return isValidDate(date.startDate) 60 | ? date.startDate 61 | : getGregDate(date.startDate); 62 | } else { 63 | return isValidDate(date) ? date : getGregDate(date); 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "version": "2.0.24", 4 | "scripts": { 5 | "build": "yarn workspaces foreach --all -pt run build", 6 | "test": "yarn workspaces foreach --all -pt run test", 7 | "pub": "yarn workspaces foreach --all -pt run pub", 8 | "pub1": "yarn workspaces foreach --all -pt run pub && yarn run tag", 9 | "inc": "echo yarn workspaces foreach --all -pt run inc", 10 | "inc-version": "yarn workspaces foreach --all -pt version patch", 11 | "get-version": "node -p \"require('./packages/jewishDatesCore/package.json').version\"", 12 | "tag": "echo git tag v1.2.1", 13 | "clean": "rm -rf node_modules", 14 | "g:start": "cd $INIT_CWD && esr ../../config/start.ts", 15 | "g:start-app": "cd $INIT_CWD && esr ../../config/startApp.ts", 16 | "g:dev": "cd $INIT_CWD && esr ../../config/build.ts --watch", 17 | "g:build": "cd $INIT_CWD && yarn g:clean && esr ../../config/build.ts", 18 | "g:build-app": "cd $INIT_CWD && yarn g:clean && esr ../../config/buildApp.ts", 19 | "g:test": "cd $INIT_CWD && vitest --config ./config/vitest.config.ts --coverage", 20 | "g:clean": "cd $INIT_CWD && rm -rf dist" 21 | }, 22 | "workspaces": [ 23 | "packages/jewishDatesCore", 24 | "packages/reactJewishDatePicker", 25 | "packages/example" 26 | ], 27 | "devDependencies": { 28 | "@testing-library/dom": "^10.4.0", 29 | "@testing-library/jest-dom": "^6.6.3", 30 | "@testing-library/react": "^16.2.0", 31 | "@types/node": "^20.17.24", 32 | "@types/react": "^18.3.18", 33 | "@types/react-dom": "^18.3.5", 34 | "@vitejs/plugin-react": "^4.3.4", 35 | "@vitest/coverage-v8": "3.0.8", 36 | "esbuild": "^0.25.1", 37 | "esbuild-node-externals": "^1.18.0", 38 | "esbuild-runner": "^2.2.2", 39 | "esprima": "^4.0.1", 40 | "has-flag": "5.0.1", 41 | "jsdom": "^26.0.0", 42 | "prettier": "^3.5.3", 43 | "react": "^18.3.1", 44 | "react-dom": "^18.3.1", 45 | "rimraf": "^6.0.1", 46 | "tsc-prog": "^2.3.0", 47 | "typescript": "^5.8.2", 48 | "vite": "^6.2.7", 49 | "vitest": "^3.0.8" 50 | }, 51 | "packageManager": "yarn@4.7.0" 52 | } 53 | -------------------------------------------------------------------------------- /packages/example/src/reactJewishDatePickerExample/ReactJewishDatePickerExample.css: -------------------------------------------------------------------------------- 1 | .reactJewishDatePickerExample { 2 | text-align: start; 3 | } 4 | 5 | .switch { 6 | display: grid; 7 | grid-template-columns: 24px auto; 8 | margin-bottom: 20px; 9 | align-items: end; 10 | } 11 | 12 | .basicJewishDayInfo { 13 | margin-top: 5%; 14 | direction: ltr; 15 | } 16 | 17 | .demo { 18 | display: grid; 19 | grid-template-columns: 58% 42%; 20 | justify-content: space-between; 21 | line-height: 20px; 22 | background-color: #ffffff; 23 | border: 1px solid #d3d3d3; 24 | border-radius: 0 0 5px 5px; 25 | position: relative; 26 | margin-bottom: 40px; 27 | 28 | } 29 | .demo pre { 30 | margin: 0; 31 | border-left: 1px solid #d3e2ff; 32 | padding: 10px 15px !important; 33 | border-radius: 0 0 0 5px; 34 | } 35 | .demo pre:empty { 36 | border-left: 1px solid transparent; 37 | } 38 | code, .exsample pre { 39 | font-family: monospace !important; 40 | font-size: 14px; 41 | font-weight: 100; 42 | } 43 | 44 | .copy { 45 | position: absolute; 46 | top: 1%; 47 | right: 43%; 48 | padding: 5px 1px 2px 2px; 49 | cursor: pointer; 50 | border: 1px solid #fafafa; 51 | border-radius: 3px; 52 | transition: 0.2s ease-in-out; 53 | color: #858585; 54 | background-color: #fafafa; 55 | 56 | } 57 | 58 | .copy:hover { 59 | color: #505050; 60 | } 61 | 62 | .copy:active { 63 | transform: scale(1.01); 64 | } 65 | 66 | .example { 67 | padding: 15px; 68 | min-height: 280px; 69 | } 70 | .example.isHebrew { 71 | direction: rtl; 72 | } 73 | 74 | .example h4 { 75 | margin: 5px; 76 | } 77 | .pickerWrapper { 78 | max-width: 145px; 79 | } 80 | 81 | .pickerWrapper.isRange { 82 | max-width: 250px; 83 | } 84 | 85 | .inlineWrapper { 86 | width: 300px; 87 | height: 290px; 88 | } 89 | 90 | @media only screen and (max-width: 870px) { 91 | .demo { 92 | grid-template-columns: 100%; 93 | } 94 | .demo > pre { 95 | border-right: none; 96 | border-bottom: 1px solid #d3e2ff; 97 | border-radius: 0; 98 | } 99 | .copy { 100 | right: 1%; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | build 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # TypeScript v1 declaration files 46 | typings/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | 73 | # parcel-bundler cache (https://parceljs.org/) 74 | .cache 75 | 76 | # Next.js build output 77 | .next 78 | 79 | # Nuxt.js build / generate output 80 | .nuxt 81 | dist 82 | lib 83 | 84 | # Gatsby files 85 | .cache/ 86 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 87 | # https://nextjs.org/blog/next-9-1#public-directory-support 88 | # public 89 | 90 | # vuepress build output 91 | .vuepress/dist 92 | 93 | # Serverless directories 94 | .serverless/ 95 | 96 | # FuseBox cache 97 | .fusebox/ 98 | 99 | # DynamoDB Local files 100 | .dynamodb/ 101 | 102 | # TernJS port file 103 | .tern-port 104 | .vscode/ 105 | 106 | 107 | 108 | 109 | .yarn/* 110 | !.yarn/patches 111 | !.yarn/releases 112 | !.yarn/plugins 113 | !.yarn/sdks 114 | !.yarn/versions 115 | .pnp.* 116 | 117 | .history/ 118 | -------------------------------------------------------------------------------- /packages/example/src/examples/examples.css: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 100%; 3 | margin: 0; 4 | padding: 0; 5 | background-color: #fdfff4; 6 | } 7 | 8 | html { 9 | height: 100%; 10 | } 11 | 12 | .main { 13 | display: grid; 14 | } 15 | header { 16 | min-height: 80px; 17 | padding: 10px 10px 30px; 18 | background-color: #03045e; 19 | color: #fdfff4; 20 | } 21 | 22 | header span { 23 | font-size: 13px; 24 | color: #fdfff4; 25 | } 26 | 27 | h1 { 28 | margin: 8px 0 0; 29 | text-align: center; 30 | } 31 | 32 | .meta { 33 | padding: 10px; 34 | text-align: center; 35 | } 36 | 37 | .meta span { 38 | display: inline-block; 39 | margin: 0 5px 5px; 40 | } 41 | 42 | .meta a { 43 | padding: 0; 44 | display: inline; 45 | } 46 | 47 | .meta a:hover { 48 | background-color: unset; 49 | } 50 | 51 | .examplesContainer { 52 | margin: auto; 53 | padding: 0 10px; 54 | } 55 | 56 | .install { 57 | padding: 3px 22px 3px 6px; 58 | border: 1px solid #ccc; 59 | margin: 0; 60 | font-size: 13px; 61 | background-color: #e8e7e7; 62 | border-radius: 3px; 63 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 64 | position: relative; 65 | } 66 | 67 | .installCopy { 68 | font-size: 14px; 69 | background-color: unset; 70 | border: none; 71 | position: absolute; 72 | top: -5px; 73 | right: -13px; 74 | cursor: pointer; 75 | color: #8d8d8d; 76 | } 77 | 78 | .installCopy:hover { 79 | color: #616161; 80 | transform: scale(1.1); 81 | } 82 | 83 | .examples-h2 { 84 | margin: 45px 0 0; 85 | font-weight: 400; 86 | font-size: 30px; 87 | } 88 | 89 | .examples { 90 | display: grid; 91 | grid-template-columns: 18% 80%; 92 | justify-content: space-between; 93 | } 94 | 95 | ul { 96 | list-style: none; 97 | padding: 0; 98 | margin-top: 20px; 99 | font-size: small; 100 | border: 1px solid rgb(226, 226, 226); 101 | background-color: whitesmoke; 102 | border-radius: 5px; 103 | max-height: 100vh; 104 | position: sticky; 105 | top: 10px; 106 | } 107 | 108 | li { 109 | border-bottom: 1px solid rgb(226, 226, 226); 110 | } 111 | 112 | a { 113 | text-decoration: none; 114 | padding: 10px; 115 | display: block; 116 | color: #03045e; 117 | } 118 | 119 | a:hover { 120 | text-decoration: underline; 121 | background-color: #ccc; 122 | } 123 | 124 | .button { 125 | background-color: #e7e7e7; /* Green */ 126 | border: none; 127 | color: black; 128 | padding: 5px 20px; 129 | margin-bottom: 5px; 130 | text-align: center; 131 | cursor: pointer; 132 | width: 200px; 133 | } 134 | 135 | .examples h3 { 136 | color: #000746; 137 | margin-bottom: 5px; 138 | padding: 2px 10px 5px; 139 | font-weight: 500; 140 | border-bottom: 1px solid #f0bfff; 141 | } 142 | 143 | .tuesday { 144 | background-color: #faf733; 145 | } 146 | 147 | @media only screen and (max-width: 650px) { 148 | .examples { 149 | display: grid; 150 | grid-template-columns: 100%; 151 | } 152 | 153 | .install { 154 | font-size: 12px; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/reactJewishDatePicker.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useRef, useEffect } from "react"; 2 | import type { FC } from "react"; 3 | import useOnClickOutside from "use-onclickoutside"; 4 | import { MdDateRange } from "@react-icons/all-files/md/MdDateRange"; 5 | import { 6 | BasicJewishDay, 7 | BasicJewishDate, 8 | } from "jewish-dates-core"; 9 | import { BasicJewishDateRange, DateRange } from "./interfaces"; 10 | import { Month } from "./month"; 11 | import { getTestID } from "./utils"; 12 | 13 | import "./reactJewishDatePicker.css"; 14 | import { 15 | getDateStringForSelectedDay, 16 | } from "./utils/dateUtils"; 17 | 18 | export interface ReactJewishDatePickerProps { 19 | className?: string; 20 | onClick: (startDay: BasicJewishDay, endDay: BasicJewishDay) => void; 21 | value?: BasicJewishDate | Date | BasicJewishDateRange | DateRange; 22 | isHebrew?: boolean; 23 | canSelect?: (day: BasicJewishDay) => boolean; 24 | customizeDayStyle?: (day: BasicJewishDay) => string; 25 | isRange?: boolean; 26 | } 27 | 28 | export const ReactJewishDatePicker: FC = ( 29 | { className, value, isHebrew = false, isRange, onClick, canSelect, customizeDayStyle }: ReactJewishDatePickerProps 30 | ) => { 31 | if (typeof value === "string") { 32 | throw new Error( 33 | "ReactJewishDatePicker: The value can be BasicJewishDate or Date. for Dates use 'value={new Date()}' not 'value={Date()}" 34 | ); 35 | } 36 | 37 | const [selectedDay, setSelectedDay] = useState(); 38 | const [startDay, setStartDay] = useState(); 39 | const [endDay, setEndDay] = useState(); 40 | const [isOpen, setOpen] = useState(false); 41 | const ref = useRef(null); 42 | 43 | const [selectedDaysToDisplay, setSelectedDaysToDisplay] = useState(""); 44 | 45 | useEffect(() => { 46 | const handler = setTimeout(() => { 47 | if (selectedDay || startDay || endDay) { 48 | setSelectedDaysToDisplay(getDateStringForSelectedDay(isRange, isHebrew, selectedDay, startDay, endDay)); 49 | } 50 | }, 0); 51 | 52 | return () => clearTimeout(handler); 53 | }, [isRange, isHebrew, selectedDay, startDay, endDay]); 54 | 55 | useOnClickOutside(ref, () => { 56 | setOpen(false); 57 | }); 58 | 59 | const classNames = `reactJewishDatePicker${isHebrew ? " isHebrew" : ""} ${ 60 | className || "" 61 | }`; 62 | 63 | return ( 64 |
65 |
setOpen(!isOpen)} 68 | className={`selectedDate`} 69 | > 70 | 71 | {selectedDaysToDisplay} 72 |
73 |
74 | 87 |
88 |
89 | ); 90 | }; -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/navigation.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | getJewishMonths, 3 | getJewishYears, 4 | getPrevMonth, 5 | getNextMonth, 6 | JewishMonth, 7 | } from "jewish-dates-core"; 8 | import { getTestID } from "./utils"; 9 | import { convertNumberToHebrew } from "jewish-date"; 10 | import { useCallback, memo } from "react"; 11 | 12 | export interface NavigationProps { 13 | isHebrew?: boolean; 14 | month: string; 15 | year: number; 16 | onClick: (month: string, year: number) => void; 17 | } 18 | 19 | export const Navigation: React.FC = memo( 20 | (props: NavigationProps) => { 21 | const handlePrevious = useCallback(() => { 22 | const basicJewishMonthInfo = getPrevMonth({ 23 | month: JewishMonth[props.month], 24 | year: props.year, 25 | isHebrew: props.isHebrew, 26 | }); 27 | props.onClick(basicJewishMonthInfo.month, basicJewishMonthInfo.year); 28 | }, [props, props.month, props.year, props.isHebrew]); 29 | 30 | const handleNext = useCallback(() => { 31 | const basicJewishMonthInfo = getNextMonth({ 32 | month: JewishMonth[props.month], 33 | year: props.year, 34 | isHebrew: props.isHebrew, 35 | }); 36 | props.onClick(basicJewishMonthInfo.month, basicJewishMonthInfo.year); 37 | }, [props, props.month, props.year, props.isHebrew]); 38 | 39 | const handleMonthChange = useCallback( 40 | (e: React.SyntheticEvent) => { 41 | const month = e.currentTarget.value; 42 | props.onClick(month, props.year); 43 | }, 44 | [props, props.month, props.year] 45 | ); 46 | 47 | const handleYearChange = useCallback( 48 | (e: React.SyntheticEvent) => { 49 | const year = Number(e.currentTarget.value); 50 | props.onClick(props.month, year); 51 | }, 52 | [props, props.month, props.year] 53 | ); 54 | 55 | const months = getJewishMonths(props.year, props.isHebrew); 56 | const years = getJewishYears(props.year); 57 | 58 | return ( 59 |
60 |
65 | 66 |
67 |
68 | 85 | 86 | 100 |
101 |
106 | 107 |
108 |
109 | ); 110 | } 111 | ); 112 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/day.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | JewishDay, 4 | BasicJewishDay, 5 | JewishDate, 6 | IsJewishDatesEqual, 7 | } from "jewish-dates-core"; 8 | import { isFromTest } from "./utils"; 9 | import * as Dayjs from "dayjs"; 10 | import isBetween from "dayjs/plugin/isBetween"; 11 | import { convertNumberToHebrew } from "jewish-date"; 12 | const dayjs = Dayjs.default; 13 | dayjs.extend(isBetween); 14 | 15 | export interface DayProps extends JewishDay { 16 | isHebrew?: boolean; 17 | selectedDay: BasicJewishDay; 18 | onClick: (day: BasicJewishDay) => void; 19 | onMouseOver?: (day: BasicJewishDay) => void; 20 | canSelect?: (day: BasicJewishDay) => boolean; 21 | customizeDayStyle?: (day: BasicJewishDay) => string; 22 | isRange?: boolean; 23 | startDay: BasicJewishDay; 24 | endDay: BasicJewishDay; 25 | } 26 | 27 | const isInRange = ( 28 | date: Date, 29 | startDay: BasicJewishDay, 30 | endDay: BasicJewishDay 31 | ): boolean => { 32 | if (startDay && endDay) { 33 | const start = dayjs(startDay.date); 34 | const end = dayjs(endDay.date); 35 | return dayjs(date).isBetween(start, end); 36 | } 37 | return false; 38 | }; 39 | 40 | const isStartDay = (date: Date, startDay: BasicJewishDay): boolean => { 41 | if (startDay) { 42 | const start = dayjs(startDay.date).startOf("d"); 43 | return dayjs(date).startOf("d").isSame(start); 44 | } 45 | return false; 46 | }; 47 | 48 | const isEndDay = ( 49 | date: Date, 50 | startDay: BasicJewishDay, 51 | endDay: BasicJewishDay 52 | ): boolean => { 53 | if (endDay && startDay) { 54 | const day = dayjs(date).startOf("d"); 55 | const start = dayjs(startDay.date).startOf("d"); 56 | const end = dayjs(endDay.date).startOf("d"); 57 | return day.isSame(end) && !day.isSame(start); 58 | } 59 | return false; 60 | }; 61 | 62 | export const Day: React.FC = (props: DayProps) => { 63 | const { 64 | isHebrew, 65 | selectedDay, 66 | isCurrentMonth, 67 | day, 68 | dayjsDate, 69 | isRange, 70 | startDay, 71 | endDay, 72 | canSelect, 73 | onClick, 74 | onMouseOver, 75 | customizeDayStyle, 76 | ...basicJewishDay 77 | } = props; 78 | 79 | const handleClick = () => { 80 | props?.onClick(basicJewishDay); 81 | }; 82 | 83 | const handleMouseOver = () => { 84 | props?.onMouseOver?.(basicJewishDay); 85 | }; 86 | 87 | const dayToDisplay = isHebrew 88 | ? convertNumberToHebrew(day, false, false) 89 | : day; 90 | const title = props.isHebrew 91 | ? props.jewishDateStrHebrew 92 | : props.jewishDateStr; 93 | 94 | const otherMonthClass = !isCurrentMonth ? " otherMonth" : ""; 95 | const selectedDayClass = 96 | selectedDay && 97 | (IsJewishDatesEqual(props.jewishDate, selectedDay.jewishDate) 98 | ? " selectedDay" 99 | : ""); 100 | const disableSelectClass = 101 | canSelect && !canSelect(basicJewishDay) ? " noSelect" : ""; 102 | const isInRangClass = isInRange(props.date, startDay, endDay) 103 | ? " isInRange" 104 | : ""; 105 | const isStartDayClass = isStartDay(props.date, startDay) ? " startDay" : ""; 106 | const isEndDayClass = isEndDay(props.date, startDay, endDay) ? " endDay" : ""; 107 | const customDayClass = customizeDayStyle ? ` ${customizeDayStyle(basicJewishDay)}` : ""; 108 | const classNames = `day${otherMonthClass}${ 109 | selectedDayClass || "" 110 | }${disableSelectClass}${isInRangClass}${isStartDayClass}${isEndDayClass}${customDayClass}`; 111 | return ( 112 |
120 | {dayToDisplay} 121 |
122 | ); 123 | }; 124 | -------------------------------------------------------------------------------- /config/utils/esbuildUtils.ts: -------------------------------------------------------------------------------- 1 | // import { build as esbuild, serve, BuildOptions } from "esbuild"; 2 | import * as esbuild from "esbuild"; 3 | import nodeExternalsPlugin from "esbuild-node-externals"; 4 | import path from "path"; 5 | import { Colors } from "./colorsUtils"; 6 | import { buildDeclarations } from "./tsUtils"; 7 | import { getFiles } from "./filesUtils"; 8 | 9 | export const baseConfig: esbuild.BuildOptions = { 10 | bundle: true, 11 | sourcemap: true, 12 | // splitting: true, 13 | }; 14 | 15 | export const start = async (entryPoints: string[], outdir: string) => { 16 | const start = new Date().getTime(); 17 | const ctx = await esbuild.context({ 18 | // plugins: [pnpPlugin()], 19 | ...baseConfig, 20 | entryPoints: entryPoints, 21 | outdir: outdir 22 | }); 23 | const { host, port } = await ctx.serve({ 24 | port: 3000, 25 | servedir: "./config/static", 26 | onRequest: (args) => { 27 | // console.log(args); 28 | }, 29 | 30 | }); 31 | console.log(`http://${host}:${port}/`); 32 | console.log(`http://127.0.0.1:${port}/`); 33 | 34 | const end = new Date().getTime(); 35 | const time = end - start; 36 | console.log( 37 | Colors.FgGreen, 38 | `Started in ${(time / 1000).toFixed(5)} sec.`, 39 | Colors.Reset 40 | ); 41 | // Call "stop" on the web server to stop serving 42 | // server.stop() 43 | }; 44 | 45 | export const build = async ( 46 | bashPath: string, 47 | tsconfigPath: string, 48 | srcPath: string, 49 | outPath: string, 50 | declarationsOutPath: string 51 | ) => { 52 | const start = new Date().getTime(); 53 | const outPathEsm = path.resolve(outPath, "mjs"); 54 | const entryPoints = (await getFiles(path.join(process.cwd(), "src"))).map((file) => file.replace(process.cwd(), '.')); 55 | 56 | // console.log(entryPoints); 57 | Promise.all([ 58 | esbuild.build({ 59 | ...baseConfig, 60 | plugins: [ 61 | // pnpPlugin(), 62 | nodeExternalsPlugin(), 63 | ], 64 | entryPoints: ["./src/index.ts"], 65 | outdir: outPath, 66 | minify: true, 67 | format: "cjs", 68 | }), 69 | esbuild.build({ 70 | ...baseConfig, 71 | bundle: false, 72 | plugins: [ 73 | // pnpPlugin(), 74 | nodeExternalsPlugin(), 75 | ], 76 | entryPoints: entryPoints, 77 | outdir: outPathEsm, 78 | minify: true, 79 | format: "esm", 80 | target: "esnext", 81 | }), 82 | ]) 83 | 84 | .then(async () => { 85 | const endBuild = new Date().getTime(); 86 | const timeBuild = endBuild - start; 87 | 88 | console.log( 89 | Colors.FgGreen, 90 | `Build done in ${(timeBuild / 1000).toFixed(3)} sec.`, 91 | Colors.Reset 92 | ); 93 | 94 | // https://gist.github.com/jeremyben/4de4fdc40175d0f76892209e00ece98f 95 | await buildDeclarations( 96 | bashPath, 97 | tsconfigPath, 98 | srcPath, 99 | declarationsOutPath 100 | ); 101 | const end = new Date().getTime(); 102 | const time = end - endBuild; 103 | console.log( 104 | Colors.FgGreen, 105 | `Build declarations done in ${(time / 1000).toFixed(3)} sec.`, 106 | Colors.Reset 107 | ); 108 | }) 109 | .catch((err) => { 110 | // console.error(err.error); 111 | process.exit(1); 112 | }); 113 | }; 114 | 115 | 116 | export const buildApp = async ( 117 | bashPath: string, 118 | tsconfigPath: string, 119 | srcPath: string, 120 | outPath: string, 121 | declarationsOutPath: string 122 | ) => { 123 | const start = new Date().getTime(); 124 | 125 | 126 | // console.log(entryPoints); 127 | esbuild.build({ 128 | ...baseConfig, 129 | entryPoints: ["./src/index.tsx"], 130 | outdir: outPath, 131 | minify: true, 132 | format: "iife", 133 | }).then(async () => { 134 | const endBuild = new Date().getTime(); 135 | const timeBuild = endBuild - start; 136 | 137 | console.log( 138 | Colors.FgGreen, 139 | `Build done in ${(timeBuild / 1000).toFixed(3)} sec.`, 140 | Colors.Reset 141 | ); 142 | 143 | // https://gist.github.com/jeremyben/4de4fdc40175d0f76892209e00ece98f 144 | await buildDeclarations( 145 | bashPath, 146 | tsconfigPath, 147 | srcPath, 148 | declarationsOutPath 149 | ); 150 | const end = new Date().getTime(); 151 | const time = end - endBuild; 152 | console.log( 153 | Colors.FgGreen, 154 | `Build declarations done in ${(time / 1000).toFixed(3)} sec.`, 155 | Colors.Reset 156 | ); 157 | }) 158 | .catch((err) => { 159 | // console.error(err.error); 160 | process.exit(1); 161 | }); 162 | }; 163 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/month.css: -------------------------------------------------------------------------------- 1 | .monthContainer { 2 | --color: #333; 3 | --backgroundColor: #e6e6e6; 4 | display: grid; 5 | font-family: arial; 6 | cursor: pointer; 7 | height: 100%; 8 | width: 100%; 9 | grid-template-rows: auto auto 1fr; 10 | background-color: #fff; 11 | border: 1px solid #d6d9dd; 12 | border-radius: 5px; 13 | display: grid; 14 | } 15 | .monthContainer.isHebrew { 16 | direction: rtl; 17 | } 18 | .monthContainer.isHebrew .startDay { 19 | background: cornflowerblue; 20 | border-radius: 0 7px 7px 0; 21 | color: #fff; 22 | margin: 1px 0; 23 | } 24 | .monthContainer.isHebrew .endDay { 25 | background: cornflowerblue; 26 | border-radius: 7px 0 0 7px; 27 | color: #fff; 28 | margin: 1px 0; 29 | } 30 | .monthContainer.isHebrew .weekday, 31 | .monthContainer.isHebrew .day { 32 | font-size: 16px; 33 | padding: 0; 34 | } 35 | .monthContainer .navigation { 36 | display: grid; 37 | grid-template-columns: 22px 138px 22px; 38 | justify-content: space-between; 39 | min-height: 32px; 40 | padding: 5px; 41 | width: 100%; 42 | box-sizing: border-box; 43 | } 44 | .monthContainer .navigation .arrowRight, 45 | .monthContainer .navigation .arrowLeft { 46 | display: grid; 47 | align-items: center; 48 | justify-content: center; 49 | } 50 | .monthContainer .navigation .arrowRight span, 51 | .monthContainer .navigation .arrowLeft span { 52 | border: solid black; 53 | border-width: 0 2px 2px 0; 54 | padding: 1px; 55 | transform: rotate(-45deg); 56 | -webkit-transform: rotate(-45deg); 57 | cursor: pointer; 58 | width: 6px; 59 | height: 6px; 60 | } 61 | .monthContainer .navigation .arrowRight:hover, 62 | .monthContainer .navigation .arrowLeft:hover { 63 | background-color: var(--backgroundColor); 64 | } 65 | .monthContainer .navigation .arrowLeft span { 66 | transform: rotate(135deg); 67 | -webkit-transform: rotate(135deg); 68 | } 69 | .monthContainer .navigation .monthYearSelection { 70 | display: grid; 71 | grid-template-columns: auto auto; 72 | } 73 | .monthContainer .navigation .monthYearSelection select { 74 | border: 0px; 75 | outline: 0px; 76 | } 77 | .monthContainer .navigation .monthYearSelection select:hover { 78 | cursor: pointer; 79 | background-color: var(--backgroundColor); 80 | } 81 | .monthContainer .navigation .monthYearSelection option { 82 | background-color: #fff; 83 | } 84 | .monthContainer.isHebrew .navigation .arrowLeft span { 85 | transform: rotate(-45deg); 86 | -webkit-transform: rotate(-45deg); 87 | } 88 | .monthContainer.isHebrew .navigation .arrowRight span { 89 | transform: rotate(135deg); 90 | -webkit-transform: rotate(135deg); 91 | } 92 | .monthContainer .month { 93 | color: var(--color); 94 | grid-template-columns: repeat(7, 1fr); 95 | grid-template-rows: 1fr 1fr 1fr 1fr 1fr; 96 | z-index: 2; 97 | background-color: white; 98 | display: grid; 99 | width: 100%; 100 | height: 100%; 101 | border-radius: 5px; 102 | padding: 2px; 103 | text-align: center; 104 | box-sizing: border-box; 105 | } 106 | .monthContainer .weekdayWrapper { 107 | display: grid; 108 | grid-template-columns: repeat(7, 1fr); 109 | background-color: #001476; 110 | padding: 2px; 111 | width: 100%; 112 | box-sizing: border-box; 113 | } 114 | .monthContainer .weekday, 115 | .monthContainer .day { 116 | display: grid; 117 | margin: 1px; 118 | padding: 1px 1px 0 0; 119 | align-items: center; 120 | justify-content: center; 121 | user-select: none; 122 | border-radius: 7px; 123 | cursor: pointer; 124 | font-size: 14px; 125 | } 126 | .monthContainer .day:hover { 127 | background-color: var(--backgroundColor); 128 | } 129 | .monthContainer .day.selectedDay:hover{ 130 | background-color: rgba(100, 148, 237, 0.539); 131 | } 132 | .monthContainer .weekday { 133 | color: #fff; 134 | font-weight: bold; 135 | } 136 | .monthContainer .otherMonth { 137 | background: #fff; 138 | color: #777; 139 | } 140 | .monthContainer .selectedDay { 141 | background: cornflowerblue; 142 | color: #fff; 143 | } 144 | .monthContainer .startDay { 145 | background: cornflowerblue; 146 | border-radius: 7px 0 0 7px; 147 | color: #fff; 148 | margin: 1px 0; 149 | } 150 | .monthContainer .isInRange { 151 | background-color: #91b6fa; 152 | color: #fff; 153 | border-radius: 0; 154 | margin: 1px 0; 155 | } 156 | .monthContainer .endDay { 157 | background: cornflowerblue; 158 | border-radius: 0 7px 7px 0; 159 | color: #fff; 160 | margin: 1px 0; 161 | } 162 | .monthContainer .startDay:hover, 163 | .monthContainer .isInRange:hover, 164 | .reactJewishDatePicker .endDay:hover { 165 | background: cornflowerblue; 166 | } 167 | .reactJewishDatePicker .noSelect { 168 | cursor: not-allowed !important; 169 | background-color: #f3f3f3; 170 | } 171 | .reactJewishDatePicker .noSelect:hover { 172 | background-color: #f3f3f3; 173 | } 174 | .reactJewishDatePicker .noSelect:active { 175 | pointer-events: none; 176 | } 177 | -------------------------------------------------------------------------------- /packages/example/src/reactJewishDatePickerExample/ReactJewishDatePickerExample.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | ReactJewishDatePicker, 4 | Month, 5 | BasicJewishDay, 6 | BasicJewishDate, 7 | BasicJewishDateRange, 8 | DateRange, 9 | } from "react-jewish-datepicker"; 10 | // import { LiveProvider, LiveEditor, LiveError, LivePreview } from "react-live"; 11 | import { HiOutlineClipboard } from "@react-icons/all-files/hi/HiOutlineClipboard"; 12 | import { HiOutlineClipboardCheck } from "@react-icons/all-files/hi/HiOutlineClipboardCheck"; 13 | import { Code } from "./code"; 14 | 15 | import "./ReactJewishDatePickerExample.css"; 16 | import "../../../reactJewishDatePicker/dist/index.css"; 17 | 18 | export interface ReactJewishDatePickerExampleProps { 19 | isHebrew?: boolean; 20 | value?: BasicJewishDate | Date | BasicJewishDateRange | DateRange; 21 | canSelect?: (day: BasicJewishDay) => boolean; 22 | customizeDayStyle?: (day: BasicJewishDay) => string; 23 | isRange?: boolean; 24 | code: string; 25 | isInline?: boolean; 26 | children?: JSX.Element | JSX.Element[]; 27 | } 28 | 29 | export const ReactJewishDatePickerExample: React.FC< 30 | ReactJewishDatePickerExampleProps 31 | > = (props: ReactJewishDatePickerExampleProps) => { 32 | const [basicJewishDay, setBasicJewishDay] = React.useState< 33 | BasicJewishDay | undefined 34 | >(undefined); 35 | const [startDay, setStartDay] = React.useState( 36 | undefined 37 | ); 38 | const [endDay, setEndDay] = React.useState( 39 | undefined 40 | ); 41 | const [isCopied, setIsCopied] = React.useState(false); 42 | 43 | React.useEffect(() => { 44 | setBasicJewishDay(undefined); 45 | setStartDay(undefined); 46 | setEndDay(undefined); 47 | }, [props.value]); 48 | 49 | const copyToClipboard = () => { 50 | navigator.clipboard.writeText(props.code); 51 | setIsCopied(true); 52 | setTimeout(() => { 53 | setIsCopied(false); 54 | }, 1500); 55 | }; 56 | 57 | const isHebrew = !!props.isHebrew; 58 | // const scope = { ReactJewishDatePicker, BasicJewishDay, React }; 59 | return ( 60 |
61 | {/* 62 | 63 | 64 | 65 | */} 66 |
67 | 74 | 75 |
76 |
77 | {!props.isInline ? { 86 | setBasicJewishDay(day); 87 | } 88 | : (startDay: BasicJewishDay, endDay: BasicJewishDay) => { 89 | setStartDay(startDay); 90 | setEndDay(endDay); 91 | } 92 | } 93 | > : 94 |
95 | { 102 | setBasicJewishDay(day); 103 | } 104 | : (startDay: BasicJewishDay, endDay: BasicJewishDay) => { 105 | setStartDay(startDay); 106 | setEndDay(endDay); 107 | } 108 | } 109 | canSelect={props.canSelect} 110 | customizeDayStyle={props.customizeDayStyle} 111 | > 112 |
113 | } 114 | {props.children} 115 |
116 |
117 | {basicJewishDay ?
Day value:
: null} 118 | {startDay ?
Range value:
: null} 119 | {startDay ? ( 120 |
121 |                 

start day:

122 | {JSON.stringify(startDay, null, 2)} 123 |

end day:

124 | {JSON.stringify(endDay, null, 2)} 125 |
126 | ) : ( 127 |
{JSON.stringify(basicJewishDay, null, 2)}
128 | )} 129 |
130 |
131 |
132 |
133 | ); 134 | }; 135 | -------------------------------------------------------------------------------- /.github/workflows/ci.js.yml: -------------------------------------------------------------------------------- 1 | name: CI_CD 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build-and-test: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | 14 | - name: Use Node.js 15 | uses: actions/setup-node@v4 16 | with: 17 | node-version: 20 18 | cache: 'yarn' 19 | 20 | - name: Install 21 | run: yarn 22 | 23 | - name: Build 24 | run: yarn build 25 | 26 | - name: Test 27 | run: yarn test 28 | 29 | # - name: Code Coverage Report 30 | # uses: irongut/CodeCoverageSummary@v1.3.0 31 | # with: 32 | # filename: coverage/**/cobertura-coverage.xml 33 | # badge: true 34 | # fail_below_min: true 35 | # format: markdown 36 | # hide_branch_rate: false 37 | # hide_complexity: true 38 | # indicators: true 39 | # output: both 40 | # thresholds: '60 80' 41 | 42 | # - name: Add Coverage PR Comment 43 | # uses: marocchino/sticky-pull-request-comment@v2 44 | # if: github.event_name == 'pull_request' 45 | # with: 46 | # recreate: true 47 | # path: code-coverage-results.md 48 | 49 | - name: Upload build artifact 50 | uses: actions/upload-artifact@v4 51 | with: 52 | name: lib_core 53 | path: packages/jewishDatesCore/lib 54 | 55 | - name: Upload build artifact 56 | uses: actions/upload-artifact@v4 57 | with: 58 | name: dist_core 59 | path: packages/jewishDatesCore/dist 60 | 61 | - name: Upload build artifact 62 | uses: actions/upload-artifact@v4 63 | with: 64 | name: lib_picker 65 | path: packages/reactJewishDatePicker/lib 66 | 67 | - name: Upload build artifact 68 | uses: actions/upload-artifact@v4 69 | with: 70 | name: dist_picker 71 | path: packages/reactJewishDatePicker/dist 72 | 73 | release: 74 | runs-on: ubuntu-latest 75 | permissions: 76 | issues: write 77 | contents: write 78 | pull-requests: write 79 | deployments: write 80 | id-token: write 81 | needs: [build-and-test] 82 | if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') 83 | steps: 84 | - name: Checkout 85 | uses: actions/checkout@v4 86 | 87 | - name: Use Node.js 88 | uses: actions/setup-node@v4 89 | with: 90 | node-version: 20 91 | cache: 'yarn' 92 | 93 | - name: Install 94 | run: yarn 95 | 96 | - name: Download build artifact 97 | uses: actions/download-artifact@v4 98 | with: 99 | name: lib_core 100 | path: packages/jewishDatesCore/lib 101 | 102 | - name: Download build artifact 103 | uses: actions/download-artifact@v4 104 | with: 105 | name: dist_core 106 | path: packages/jewishDatesCore/dist 107 | 108 | - name: Download build artifact 109 | uses: actions/download-artifact@v4 110 | with: 111 | name: lib_picker 112 | path: packages/reactJewishDatePicker/lib 113 | 114 | - name: Download build artifact 115 | uses: actions/download-artifact@v4 116 | with: 117 | name: dist_picker 118 | path: packages/reactJewishDatePicker/dist 119 | 120 | 121 | - run: yarn inc-version 122 | - name: Set env $VERSION_TAG 123 | run: echo "VERSION_TAG=$(yarn get-version)" >> $GITHUB_ENV 124 | 125 | - run: git tag v$VERSION_TAG 126 | - name: Commit version 127 | run: | 128 | git config --global user.name 'Shmulik-Kravitz' 129 | git config --global user.email '29735690+Shmulik-Kravitz@users.noreply.github.com' 130 | git commit -am v$VERSION_TAG 131 | git push 132 | git push origin v$VERSION_TAG 133 | # - run: yarn npm publish --access public 134 | # - run: yarn pub 135 | # env: 136 | # YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 137 | # NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 138 | # NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 139 | 140 | # we use yarn to pack due to yarn workspaces issue with workspace:* in published package in npm 141 | - name: pack jewish-dates-core 142 | working-directory: packages/jewishDatesCore/ 143 | run: yarn pack 144 | 145 | - name: pack jewish-dates-core 146 | working-directory: packages/reactJewishDatePicker/ 147 | run: yarn pack 148 | 149 | - name: npm-publish jewish-dates-core 150 | uses: JS-DevTools/npm-publish@v3 151 | with: 152 | token: ${{ secrets.NPM_TOKEN }} 153 | package: packages/jewishDatesCore/package.tgz 154 | provenance: true 155 | 156 | - name: npm-publish react-jewish-datepicker 157 | uses: JS-DevTools/npm-publish@v3 158 | with: 159 | token: ${{ secrets.NPM_TOKEN }} 160 | package: packages/reactJewishDatePicker/package.tgz 161 | provenance: true 162 | 163 | -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/month.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useState, useRef, useEffect } from "react"; 2 | import type { FC } from "react"; 3 | import useOnClickOutside from "use-onclickoutside"; 4 | import Dayjs from "dayjs"; 5 | import { 6 | getJewishMonth, 7 | getWeekdays, 8 | getGregDate, 9 | getJewishDay, 10 | BasicJewishDay, 11 | BasicJewishDate, 12 | JewishMonth, 13 | } from "jewish-dates-core"; 14 | import { BasicJewishDateRange, DateRange } from "./interfaces"; 15 | import { Day } from "./day"; 16 | import { Weekday } from "./weekday"; 17 | import { Navigation } from "./navigation"; 18 | import { 19 | getDateInit, 20 | getDatesInOrder, 21 | isDateRange, 22 | } from "./utils/dateUtils"; 23 | 24 | import "./month.css"; 25 | 26 | export interface MonthProps { 27 | onClick: (startDay: BasicJewishDay, endDay: BasicJewishDay) => void; 28 | value?: BasicJewishDate | Date | BasicJewishDateRange | DateRange; 29 | isHebrew?: boolean; 30 | canSelect?: (day: BasicJewishDay) => boolean; 31 | customizeDayStyle?: (day: BasicJewishDay) => string; 32 | isRange?: boolean; 33 | isOpen?: boolean; 34 | setOpen?: (isOpen: boolean) => void; 35 | setSelectedDay?: (day: BasicJewishDay) => void; 36 | setStartDay?: (day: BasicJewishDay) => void; 37 | setEndDay?: (day: BasicJewishDay) => void; 38 | } 39 | 40 | export const Month: FC = ( 41 | { value, isHebrew = false, isRange, onClick, canSelect, customizeDayStyle, isOpen, setOpen, ...props }: MonthProps 42 | ) => { 43 | if (typeof value === "string") { 44 | throw new Error( 45 | "ReactJewishDatePicker: The value can be BasicJewishDate or Date. for Dates use 'value={new Date()}' not 'value={Date()}" 46 | ); 47 | } 48 | 49 | const dateInit = value ? getDateInit(value) : new Date(); 50 | const endDateInit = isDateRange(value) && getDateInit(value.endDate); 51 | 52 | const [date, setDate] = useState(dateInit); 53 | const jewishMonthInfo = getJewishMonth(date); 54 | 55 | const [selectedDay, setSelectedDay] = useState( 56 | !isRange && value && jewishMonthInfo.selectedDay 57 | ); 58 | const [startDay, setStartDay] = useState( 59 | isRange && isDateRange(value) && jewishMonthInfo.selectedDay 60 | ); 61 | const [endDay, setEndDay] = useState( 62 | isRange && isDateRange(value) && getJewishDay(Dayjs(endDateInit)) 63 | ); 64 | const [hoveredDay, setHoveredDay] = useState(null); 65 | const ref = useRef(null); 66 | 67 | useEffect(() => { 68 | const date = getDateInit(value); 69 | setDate(date); 70 | const jewishMonth = getJewishMonth(date); 71 | const start = jewishMonth.selectedDay 72 | 73 | if (isRange && isDateRange(value)) { 74 | setStartDay(start); 75 | props.setStartDay && props.setStartDay(start); 76 | const endDate = getDateInit(value.endDate); 77 | const end = getJewishDay(Dayjs(endDate)) 78 | setEndDay(end); 79 | props.setEndDay && props.setEndDay(end); 80 | } else { 81 | setSelectedDay(start); 82 | props.setSelectedDay && props.setSelectedDay(start); 83 | } 84 | }, [value]); 85 | 86 | useOnClickOutside(ref, () => { 87 | setOpen(false); 88 | }); 89 | 90 | const handleClick = useCallback((day: BasicJewishDay) => { 91 | if (isRange) { 92 | if (!startDay || endDay) { 93 | setStartDay(day); 94 | setEndDay(null); 95 | props.setStartDay && props.setStartDay(day); 96 | props.setEndDay && props.setEndDay(null); 97 | } else { 98 | const [start, end] = getDatesInOrder(startDay, day); 99 | setStartDay(start); 100 | setEndDay(end); 101 | props.setStartDay && props.setStartDay(start); 102 | props.setEndDay && props.setEndDay(end); 103 | onClick?.call(null, start, end); 104 | setOpen && setOpen(!isOpen); 105 | } 106 | } else { 107 | setSelectedDay(day); 108 | props.setSelectedDay && props.setSelectedDay(day); 109 | onClick?.call(null, day, undefined); 110 | setOpen && setOpen(!isOpen); 111 | } 112 | }, [isRange, startDay, endDay, isOpen]); 113 | 114 | const handleMouseOver = useCallback((day: BasicJewishDay) => { 115 | setHoveredDay(day); 116 | }, []); 117 | 118 | const setBasicJewishDate = (basicJewishDate: BasicJewishDate) => { 119 | const gregDate = getGregDate(basicJewishDate); 120 | setDate(gregDate); 121 | }; 122 | 123 | const handleNavigationClick = useCallback( 124 | (month: string, year: number) => { 125 | const basicJewishDate: BasicJewishDate = { 126 | year: year, 127 | monthName: JewishMonth[month], 128 | day: jewishMonthInfo.selectedDay.day, 129 | }; 130 | setBasicJewishDate(basicJewishDate); 131 | }, 132 | [JewishMonth] 133 | ); 134 | 135 | const [start, end] = getDatesInOrder(startDay, hoveredDay); 136 | const classNames = `monthContainer${isHebrew ? " isHebrew" : ""}`; 137 | return ( 138 |
139 | 145 |
146 | {getWeekdays(isHebrew).map((weekday) => { 147 | return ; 148 | })} 149 |
150 |
151 | {jewishMonthInfo.days.map((day, index) => { 152 | return ( 153 | 166 | ); 167 | })} 168 |
169 |
170 | ); 171 | }; -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/src/__tests__/reactJewishDatePicker.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { waitFor, screen } from "@testing-library/react"; 3 | import { render, fireEvent } from "./test-utils"; 4 | import { 5 | BasicJewishDate, 6 | BasicJewishDay, 7 | BasicJewishDateRange, 8 | ReactJewishDatePicker, 9 | } from ".."; 10 | import { 11 | getEngJewishMonths, 12 | dontSelectHolidays, 13 | dontSelectShabat, 14 | } from "jewish-dates-core"; 15 | import { it, expect, describe } from "vitest"; 16 | 17 | describe("jewishDatesCore", () => { 18 | it("change month", async () => { 19 | const basicJewishDate: BasicJewishDate = { 20 | day: 13, 21 | monthName: "Elul", 22 | year: 5781, 23 | }; 24 | 25 | const { container, getByText } = render( 26 | {}} 30 | /> 31 | ); 32 | 33 | await waitFor(() => { 34 | fireEvent.change(screen.getByTestId("month"), { 35 | target: { value: getEngJewishMonths()[0].id }, 36 | }); 37 | }); 38 | expect(screen.getByTestId("30 Tishri 5781")).toHaveTextContent("30"); 39 | }); 40 | 41 | it("change year", async () => { 42 | const basicJewishDate: BasicJewishDate = { 43 | day: 13, 44 | monthName: "Cheshvan", 45 | year: 5781, 46 | }; 47 | render( 48 | {}} 52 | /> 53 | ); 54 | 55 | await waitFor(() => { 56 | fireEvent.change(screen.getByTestId("year"), { target: { value: 5780 } }); 57 | }); 58 | expect(screen.getByTestId("30 Cheshvan 5780")).toHaveTextContent("30"); 59 | }); 60 | 61 | it("prev month", async () => { 62 | const basicJewishDate: BasicJewishDate = { 63 | day: 13, 64 | monthName: "Cheshvan", 65 | year: 5781, 66 | }; 67 | render( 68 | {}} 72 | /> 73 | ); 74 | 75 | await waitFor(() => { 76 | fireEvent.click(screen.getByTestId("prev")); 77 | }); 78 | expect(screen.getByTestId("30 Tishri 5781")).toHaveTextContent("30"); 79 | }); 80 | 81 | it("next month", async () => { 82 | const basicJewishDate: BasicJewishDate = { 83 | day: 13, 84 | monthName: "Cheshvan", 85 | year: 5781, 86 | }; 87 | render( 88 | {}} 92 | /> 93 | ); 94 | 95 | await waitFor(() => { 96 | fireEvent.click(screen.getByTestId("next")); 97 | }); 98 | expect(screen.getByTestId("29 Kislev 5781")).toHaveTextContent("29"); 99 | }); 100 | 101 | it("select date", async () => { 102 | const basicJewishDate: BasicJewishDate = { 103 | day: 13, 104 | monthName: "Cheshvan", 105 | year: 5781, 106 | }; 107 | render( 108 | {}} 112 | /> 113 | ); 114 | 115 | await waitFor(() => { 116 | fireEvent.click(screen.getByTestId("16 Cheshvan 5781")); 117 | }); 118 | expect(screen.getByTestId("selectedDate")).toHaveTextContent( 119 | "16 Cheshvan 5781" 120 | ); 121 | }); 122 | 123 | it("dont select holiday", async () => { 124 | const excludeHolidays = dontSelectHolidays(true); 125 | const basicJewishDate: BasicJewishDate = { 126 | day: 21, 127 | monthName: "Nisan", 128 | year: 5782, 129 | }; 130 | render( 131 | {}} 136 | /> 137 | ); 138 | 139 | expect(screen.getByTestId("21 Nisan 5782")).toHaveClass("noSelect"); 140 | }); 141 | 142 | it("dont select shabat", async () => { 143 | const basicJewishDate: BasicJewishDate = { 144 | day: 20, 145 | monthName: "Shevat", 146 | year: 5782, 147 | }; 148 | render( 149 | {}} 154 | /> 155 | ); 156 | 157 | expect(screen.getByTestId("20 Shevat 5782")).toHaveClass("noSelect"); 158 | }); 159 | 160 | it("custom day class", async () => { 161 | const basicJewishDate: BasicJewishDate = { 162 | day: 20, 163 | monthName: "Shevat", 164 | year: 5782, 165 | }; 166 | function customizeDayStyle(day: BasicJewishDay): string { 167 | if (day.date.getDay() === 6) { 168 | return "customClass"; 169 | } 170 | return ""; 171 | } 172 | render( 173 | {}} 178 | /> 179 | ); 180 | 181 | expect(screen.getByTestId("20 Shevat 5782")).toHaveClass("customClass"); 182 | }); 183 | 184 | it("select range", async () => { 185 | const basicJewishDateRange: BasicJewishDateRange = { 186 | startDate: { 187 | day: 16, 188 | monthName: "Elul", 189 | year: 5788, 190 | }, 191 | endDate: { 192 | day: 20, 193 | monthName: "Elul", 194 | year: 5788, 195 | }, 196 | }; 197 | render( 198 | {}} 203 | /> 204 | ); 205 | 206 | await waitFor(() => { 207 | () => { 208 | fireEvent.click(screen.getByTestId("16 Elul 5788")); 209 | fireEvent.click(screen.getByTestId("20 Elul 5788")); 210 | }; 211 | }); 212 | expect(screen.getByTestId("selectedDate")).toHaveTextContent( 213 | "16 Elul 5788 - 20 Elul 5788" 214 | ); 215 | }); 216 | }); 217 | -------------------------------------------------------------------------------- /packages/example/src/code/code.ts: -------------------------------------------------------------------------------- 1 | export const englishCode = (`import * as React from "react"; 2 | import { 3 | ReactJewishDatePicker, 4 | BasicJewishDay, 5 | } from "react-jewish-datepicker"; 6 | import "react-jewish-datepicker/dist/index.css"; 7 | 8 | export default function App() { 9 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 10 | const date: Date = new Date(); 11 | 12 | return ( 13 |
14 | { 17 | setBasicJewishDay(day); 18 | }} 19 | /> 20 |
21 | ); 22 | }`); 23 | 24 | export const hebrewCode = (`import * as React from "react"; 25 | import { 26 | ReactJewishDatePicker, 27 | BasicJewishDay, 28 | BasicJewishDate 29 | } from "react-jewish-datepicker"; 30 | import "react-jewish-datepicker/dist/index.css"; 31 | import { 32 | JewishMonth, 33 | } from "jewish-dates-core"; 34 | 35 | export default function App() { 36 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 37 | const basicJewishDate: BasicJewishDate = { 38 | day: 13, 39 | monthName: JewishMonth.Elul, 40 | year: 5788 41 | }; 42 | 43 | return ( 44 |
45 | { 49 | setBasicJewishDay(day); 50 | }} 51 | /> 52 |
53 | ); 54 | }`); 55 | 56 | export const dontSelectHolidayCode = (`import * as React from "react"; 57 | import { 58 | ReactJewishDatePicker, 59 | BasicJewishDay, 60 | } from "react-jewish-datepicker"; 61 | import "react-jewish-datepicker/dist/index.css"; 62 | import { dontSelectHolidays } from "jewish-dates-core"; 63 | 64 | export default function App() { 65 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 66 | const date: Date = new Date(); 67 | 68 | const isIsrael: boolean = true; 69 | const excludeHolidays = dontSelectHolidays(isIsrael); 70 | 71 | return ( 72 |
73 | { 78 | setBasicJewishDay(day); 79 | }} 80 | /> 81 |
82 | ); 83 | }`); 84 | 85 | export const dontSelectShabatCode = (`import * as React from "react"; 86 | import { 87 | ReactJewishDatePicker, 88 | BasicJewishDay, 89 | } from "react-jewish-datepicker"; 90 | import "react-jewish-datepicker/dist/index.css"; 91 | import { dontSelectShabat } from "jewish-dates-core"; 92 | 93 | export default function App() { 94 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 95 | const date: Date = new Date(); 96 | 97 | return ( 98 |
99 | { 104 | setBasicJewishDay(day); 105 | }} 106 | /> 107 |
108 | ); 109 | }`); 110 | 111 | export const dontSelectShabatAndHolidaysCode = (`import * as React from "react"; 112 | import { 113 | ReactJewishDatePicker, 114 | BasicJewishDay, 115 | } from "react-jewish-datepicker"; 116 | import "react-jewish-datepicker/dist/index.css"; 117 | import { dontSelectShabatAndHolidays } from "jewish-dates-core"; 118 | 119 | export default function App() { 120 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 121 | const date: Date = new Date(); 122 | const excludeShabatAndHolidays = dontSelectShabatAndHolidays(); 123 | 124 | return ( 125 |
126 | { 131 | setBasicJewishDay(day); 132 | }} 133 | /> 134 |
135 | ); 136 | }`); 137 | 138 | export const selectionWithinRangeCode = (`import * as React from "react"; 139 | import { 140 | ReactJewishDatePicker, 141 | BasicJewishDay, 142 | } from "react-jewish-datepicker"; 143 | import "react-jewish-datepicker/dist/index.css"; 144 | import { 145 | dontSelectOutOfRange, 146 | addDates, 147 | subtractDates 148 | } from "jewish-dates-core"; 149 | 150 | export default function App() { 151 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 152 | const date: Date = new Date(); 153 | 154 | const allowedSelectionRange = dontSelectOutOfRange(subtractDates(date, 3), addDates(date, 5)); 155 | 156 | return ( 157 |
158 | { 163 | setBasicJewishDay(day); 164 | }} 165 | /> 166 |
167 | ); 168 | }`); 169 | 170 | export const disableWithCustomFunctionCode = (`import * as React from "react"; 171 | import { 172 | ReactJewishDatePicker, 173 | BasicJewishDay, 174 | } from "react-jewish-datepicker"; 175 | import "react-jewish-datepicker/dist/index.css"; 176 | 177 | const dontSelectTuesdays = (day: BasicJewishDay): boolean => { 178 | if (day.date.getDay() === 2) { 179 | return false; 180 | } 181 | return true; 182 | } 183 | 184 | export default function App() { 185 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 186 | const date: Date = new Date(); 187 | 188 | return ( 189 |
190 | { 195 | setBasicJewishDay(day); 196 | }} 197 | /> 198 |
199 | ); 200 | }`); 201 | 202 | 203 | export const customizeDayStyleCode = (`import * as React from "react"; 204 | import { 205 | ReactJewishDatePicker, 206 | BasicJewishDay, 207 | } from "react-jewish-datepicker"; 208 | import "react-jewish-datepicker/dist/index.css"; 209 | 210 | const highlightTuesday = (day: BasicJewishDay): string => { 211 | if (day.date.getDay() === 2) { 212 | return 'tuesday'; 213 | } 214 | return ''; 215 | }; 216 | 217 | export default function App() { 218 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 219 | const date: Date = new Date(); 220 | 221 | return ( 222 |
223 | { 228 | setBasicJewishDay(day); 229 | }} 230 | /> 231 |
232 | ); 233 | }`); 234 | 235 | 236 | export const rangeCode = (`import * as React from "react"; 237 | import { 238 | ReactJewishDatePicker, 239 | BasicJewishDateRange, 240 | } from "react-jewish-datepicker"; 241 | import "react-jewish-datepicker/dist/index.css"; 242 | import { 243 | JewishMonth, 244 | } from "jewish-dates-core"; 245 | 246 | export default function App() { 247 | const [startDay, setStartDay] = React.useState(undefined); 248 | const [endDay, setEndDay] = React.useState(undefined); 249 | const basicJewishDateRange: BasicJewishDateRange = { 250 | startDate: { 251 | day: 13, 252 | monthName: JewishMonth.Elul, 253 | year: 5788, 254 | }, 255 | endDate: { 256 | day: 18, 257 | monthName: JewishMonth.Elul, 258 | year: 5788, 259 | }, 260 | }; 261 | 262 | return ( 263 |
264 | { 269 | setStartDay(startDay); 270 | setEndDay(endDay); 271 | }} 272 | /> 273 |
274 | ); 275 | }`); 276 | 277 | export const inlineVersionCode = (`import * as React from "react"; 278 | import { 279 | Month, 280 | BasicJewishDay, 281 | } from "react-jewish-datepicker"; 282 | import "react-jewish-datepicker/dist/index.css"; 283 | 284 | export default function App() { 285 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 286 | const date: Date = new Date(); 287 | 288 | return ( 289 |
290 | { 294 | setBasicJewishDay(day); 295 | }} 296 | /> 297 |
298 | ); 299 | }`); 300 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-jewish-datepicker 2 | 3 | [![npm](https://badge.fury.io/js/react-jewish-datepicker.svg)](https://www.npmjs.com/package/react-jewish-datepicker) 4 | [![CI](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/workflows/CI_CD/badge.svg?branch=master)](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/) 5 | ![license](https://badgen.net/npm/license/react-jewish-datepicker) 6 | [![size minzip](https://img.shields.io/bundlephobia/minzip/react-jewish-datepicker.svg)](https://bundlephobia.com/package/react-jewish-datepicker) 7 | ![downloads](https://badgen.net/npm/dt/react-jewish-datepicker) 8 | [![stars](https://badgen.net/github/stars/Shmulik-Kravitz/react-jewish-datepicker)](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/) 9 | 10 | 11 | ![npm](https://raw.githubusercontent.com/Shmulik-Kravitz/react-jewish-datepicker/master/images/snapshot.png) 12 | 13 | # React Jewish Date Picker 14 | 15 | General Jewish Date Picker component that works with react and supports hebrew and english. 16 | 17 | See also [demo and documentation](https://react-jewish-datepicker.js.org/) page. 18 | 19 | ## Installation 20 | 21 | ```console 22 | yarn add react-jewish-datepicker 23 | ``` 24 | 25 | Or with npm 26 | 27 | ```console 28 | npm install react-jewish-datepicker --save 29 | ``` 30 | 31 | Import the css 32 | 33 | ```JavaScript 34 | import "react-jewish-datepicker/dist/index.css"; 35 | ``` 36 | 37 | or with css 38 | 39 | ```JavaScript 40 | @import url("react-jewish-datepicker/dist/index.css"); 41 | ``` 42 | 43 | ## Usage 44 | 45 | #### TypeScript example: 46 | 47 | ```js 48 | import * as React from "react"; 49 | import { 50 | ReactJewishDatePicker, 51 | BasicJewishDay, 52 | BasicJewishDate 53 | } from "react-jewish-datepicker"; 54 | import "react-jewish-datepicker/dist/index.css"; 55 | import { 56 | JewishMonth, 57 | } from "jewish-dates-core"; 58 | 59 | export default function App() { 60 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 61 | const basicJewishDate: BasicJewishDate = { 62 | day: 13, 63 | monthName: JewishMonth.Elul, 64 | year: 5788 65 | }; 66 | 67 | return ( 68 | <> 69 |
70 | Hebrew: 71 | { 75 | setBasicJewishDay(day); 76 | }} 77 | /> 78 |
79 | 80 | ); 81 | } 82 | 83 | 84 | ``` 85 | 86 | [![Edit react-jewish-datepicker-typescript-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-jewish-datepicker-typescript-example-1myb0?fontsize=14&hidenavigation=1&theme=dark) 87 | 88 | #### JavaScript example: 89 | 90 | ```js 91 | import * as React from "react"; 92 | import { ReactJewishDatePicker, BasicJewishDay } from "react-jewish-datepicker"; 93 | import "react-jewish-datepicker/dist/index.css"; 94 | 95 | export default function App() { 96 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 97 | return ( 98 | { 102 | setBasicJewishDay(day); 103 | }} 104 | /> 105 | ); 106 | } 107 | ``` 108 | 109 | [![Edit react-jewish-datepicker-javascript-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/pedantic-gagarin-rdeov?fontsize=14&hidenavigation=1&theme=dark) 110 | 111 | ## props 112 | 113 | | Prop name | Description | Value types | 114 | | --------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | 115 | | canSelect | Accepts a function which determines whether a day is selectable | `(day: BasicJewishDay) => condition ? false : true` | 116 | | isHebrew | Optional. Whether the view language is hebrew or english, Default is `false` | `false` \| `true` | 117 | | isRange | Optional. Allow to select date ranges. Default is `false` | `false` \| `true` | 118 | | onClick | Callback when a date is selected | `(day: BasicJewishDay) => console.log(day)` \| `(startDay: BasicJewishDay, endDay: BasicJewishDay) => console.log(startDay, endDay)` | 119 | | value | Optional. Initial selected date | `Date` \| `BasicJewishDate` \| `BasicJewishDateRange` \| `DateRange` | 120 | 121 | ### `canSelect` prop 122 | 123 | The `canSelect` can take either a [`costum function`](https://react-jewish-datepicker.js.org/#disableWithCustomFunction) or one of the build-in functions as follows. 124 | 125 | #### dontSelectHolidays([isIsrael: `boolean`]) ⇒ `(day: BasicJewishDay) => boolean` 126 | 127 | Takes `isIsrael` param and returns a function which in turn is passed to the `canSelect` prop, in order to prevent holidays (corresponding with `isIsrael` param) selection. 128 | 129 | | Param | Type | Default | 130 | | ----- | ------ | ----- | 131 | | isIsrael | `boolean` | `false` | 132 | 133 | See example [here](https://react-jewish-datepicker.js.org/#disableHolidays) 134 | 135 | #### dontSelectShabat(day: `BasicJewishDay`) ⇒ `boolean` 136 | 137 | A function to be passed to the `canSelect` prop, in order to prevent shabat selection. 138 | 139 | See example [here](https://react-jewish-datepicker.js.org/#disableShabat) 140 | 141 | #### dontSelectShabatAndHolidays([isIsrael: `boolean`]) ⇒ `(day: BasicJewishDay) => boolean` 142 | 143 | Takes `isIsrael` param and returns a function to be passed to the "canSelect" prop. combines `dontSelectHolidays` and `dontSelectShabat` in order to prevent both - shabat and holidays selection. 144 | 145 | | Param | Type | Default | 146 | | ----- | ------ | ----- | 147 | | isIsrael | `boolean` | `false` | 148 | 149 | See example [here](https://react-jewish-datepicker.js.org/#disableShabatAndHolidays) 150 | 151 | #### dontSelectOutOfRange(minDate: `Date` | `null`, maxDate: `Date` | `null`) ⇒ `(day: BasicJewishDay) => boolean` 152 | 153 | Takes min date and max date and returns a function to be passed to the "canSelect" prop, in order to prevent selection out of the supplied range. 154 | 155 | You can pass a date only for one of the params and null to the other. In this case, the selectable range will be up to max date or from min date. 156 | 157 | | Param | Type | 158 | | ----- | ------ | 159 | | minDate | `Date` \| `null` | 160 | | maxDate | `Date` \| `null` | 161 | 162 | See example [here](https://react-jewish-datepicker.js.org/#selectionWithinRange) 163 | 164 | ### Helper Functions 165 | 166 | #### addDates(date: `BasicJewishDate` | `Date`, numDays: `number`) ⇒ `Date` 167 | 168 | a helper function for `dontSelectOutOfRange`. 169 | 170 | Takes a `BasicJewishDate` object or a `Date`, adds a date interval (`numDays`) to the date and then returns the new date. 171 | 172 | | Param | Type | 173 | | ----- | ------ | 174 | | date | `BasicJewishDate` \| `Date` | 175 | | numDays | `number` | 176 | 177 | See example [here](https://react-jewish-datepicker.js.org/#selectionWithinRange) 178 | 179 | #### subtractDates(date: `BasicJewishDate` | `Date`, numDays: `number`) ⇒ `Date` 180 | 181 | a helper function for `dontSelectOutOfRange`. 182 | 183 | Takes a `BasicJewishDate` object or a `Date`, subtracts a date interval (`numDays`) from the date and then returns the new date. 184 | 185 | | Param | Type | 186 | | ----- | ------ | 187 | | date | `BasicJewishDate` \| `Date` | 188 | | numDays | `number` | 189 | 190 | See example [here](https://react-jewish-datepicker.js.org/#selectionWithinRange) 191 | 192 | ### jewish-dates-core 193 | 194 | To create a jewish date picker in vue.js or angular, see our [core dependency](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/blob/master/packages/jewishDatesCore/README.md). 195 | 196 | ### jewish-date 197 | 198 | If you only need the hebrew date convertor without a date picker you can use [jewish-date](https://www.npmjs.com/package/jewish-date). 199 | 200 | 201 | ## Contributors 202 | 203 | - [Shmulik Kravitz](https://github.com/Shmulik-Kravitz) 204 | - [Sagi Tawil](https://github.com/sagi770) 205 | - [Yochanan Sheinberger](https://github.com/yochanan-sheinberger) 206 | 207 | License: [MIT](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/blob/master/LICENSE) -------------------------------------------------------------------------------- /packages/reactJewishDatePicker/README.md: -------------------------------------------------------------------------------- 1 | # react-jewish-datepicker 2 | 3 | [![npm](https://badge.fury.io/js/react-jewish-datepicker.svg)](https://www.npmjs.com/package/react-jewish-datepicker) 4 | [![CI](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/workflows/CI_CD/badge.svg?branch=master)](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/) 5 | ![license](https://badgen.net/npm/license/react-jewish-datepicker) 6 | [![size minzip](https://img.shields.io/bundlephobia/minzip/react-jewish-datepicker.svg)](https://bundlephobia.com/package/react-jewish-datepicker) 7 | ![downloads](https://badgen.net/npm/dt/react-jewish-datepicker) 8 | [![stars](https://badgen.net/github/stars/Shmulik-Kravitz/react-jewish-datepicker)](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/) 9 | 10 | 11 | ![npm](https://raw.githubusercontent.com/Shmulik-Kravitz/react-jewish-datepicker/master/images/snapshot.png) 12 | 13 | # React Jewish Date Picker 14 | 15 | General Jewish Date Picker component that works with react and supports hebrew and english. 16 | 17 | See also [demo and documentation](https://react-jewish-datepicker.js.org/) page. 18 | 19 | ## Installation 20 | 21 | ```console 22 | yarn add react-jewish-datepicker 23 | ``` 24 | 25 | Or with npm 26 | 27 | ```console 28 | npm install react-jewish-datepicker --save 29 | ``` 30 | 31 | Import the css 32 | 33 | ```JavaScript 34 | import "react-jewish-datepicker/dist/index.css"; 35 | ``` 36 | 37 | or with css 38 | 39 | ```JavaScript 40 | @import url("react-jewish-datepicker/dist/index.css"); 41 | ``` 42 | 43 | ## Usage 44 | 45 | #### TypeScript example: 46 | 47 | ```js 48 | import * as React from "react"; 49 | import { 50 | ReactJewishDatePicker, 51 | BasicJewishDay, 52 | BasicJewishDate 53 | } from "react-jewish-datepicker"; 54 | import "react-jewish-datepicker/dist/index.css"; 55 | import { 56 | JewishMonth, 57 | } from "jewish-dates-core"; 58 | 59 | export default function App() { 60 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 61 | const basicJewishDate: BasicJewishDate = { 62 | day: 13, 63 | monthName: JewishMonth.Elul, 64 | year: 5788 65 | }; 66 | 67 | return ( 68 | <> 69 |
70 | Hebrew: 71 | { 75 | setBasicJewishDay(day); 76 | }} 77 | /> 78 |
79 | 80 | ); 81 | } 82 | 83 | 84 | ``` 85 | 86 | [![Edit react-jewish-datepicker-typescript-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-jewish-datepicker-typescript-example-1myb0?fontsize=14&hidenavigation=1&theme=dark) 87 | 88 | #### JavaScript example: 89 | 90 | ```js 91 | import * as React from "react"; 92 | import { ReactJewishDatePicker, BasicJewishDay } from "react-jewish-datepicker"; 93 | import "react-jewish-datepicker/dist/index.css"; 94 | 95 | export default function App() { 96 | const [basicJewishDay, setBasicJewishDay] = React.useState(); 97 | return ( 98 | { 102 | setBasicJewishDay(day); 103 | }} 104 | /> 105 | ); 106 | } 107 | ``` 108 | 109 | [![Edit react-jewish-datepicker-javascript-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/pedantic-gagarin-rdeov?fontsize=14&hidenavigation=1&theme=dark) 110 | 111 | ## props 112 | 113 | | Prop name | Description | Value types | 114 | | --------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | 115 | | canSelect | Accepts a function which determines whether a day is selectable | `(day: BasicJewishDay) => condition ? false : true` | 116 | | isHebrew | Optional. Whether the view language is hebrew or english, Default is `false` | `false` \| `true` | 117 | | isRange | Optional. Allow to select date ranges. Default is `false` | `false` \| `true` | 118 | | onClick | Callback when a date is selected | `(day: BasicJewishDay) => console.log(day)` \| `(startDay: BasicJewishDay, endDay: BasicJewishDay) => console.log(startDay, endDay)` | 119 | | value | Optional. Initial selected date | `Date` \| `BasicJewishDate` \| `BasicJewishDateRange` \| `DateRange` | 120 | 121 | ### `canSelect` prop 122 | 123 | The `canSelect` can take either a [`costum function`](https://react-jewish-datepicker.js.org/#disableWithCustomFunction) or one of the build-in functions as follows. 124 | 125 | #### dontSelectHolidays([isIsrael: `boolean`]) ⇒ `(day: BasicJewishDay) => boolean` 126 | 127 | Takes `isIsrael` param and returns a function which in turn is passed to the `canSelect` prop, in order to prevent holidays (corresponding with `isIsrael` param) selection. 128 | 129 | | Param | Type | Default | 130 | | ----- | ------ | ----- | 131 | | isIsrael | `boolean` | `false` | 132 | 133 | See example [here](https://react-jewish-datepicker.js.org/#disableHolidays) 134 | 135 | #### dontSelectShabat(day: `BasicJewishDay`) ⇒ `boolean` 136 | 137 | A function to be passed to the `canSelect` prop, in order to prevent shabat selection. 138 | 139 | See example [here](https://react-jewish-datepicker.js.org/#disableShabat) 140 | 141 | #### dontSelectShabatAndHolidays([isIsrael: `boolean`]) ⇒ `(day: BasicJewishDay) => boolean` 142 | 143 | Takes `isIsrael` param and returns a function to be passed to the "canSelect" prop. combines `dontSelectHolidays` and `dontSelectShabat` in order to prevent both - shabat and holidays selection. 144 | 145 | | Param | Type | Default | 146 | | ----- | ------ | ----- | 147 | | isIsrael | `boolean` | `false` | 148 | 149 | See example [here](https://react-jewish-datepicker.js.org/#disableShabatAndHolidays) 150 | 151 | #### dontSelectOutOfRange(minDate: `Date` | `null`, maxDate: `Date` | `null`) ⇒ `(day: BasicJewishDay) => boolean` 152 | 153 | Takes min date and max date and returns a function to be passed to the "canSelect" prop, in order to prevent selection out of the supplied range. 154 | 155 | You can pass a date only for one of the params and null to the other. In this case, the selectable range will be up to max date or from min date. 156 | 157 | | Param | Type | 158 | | ----- | ------ | 159 | | minDate | `Date` \| `null` | 160 | | maxDate | `Date` \| `null` | 161 | 162 | See example [here](https://react-jewish-datepicker.js.org/#selectionWithinRange) 163 | 164 | ### Helper Functions 165 | 166 | #### addDates(date: `BasicJewishDate` | `Date`, numDays: `number`) ⇒ `Date` 167 | 168 | a helper function for `dontSelectOutOfRange`. 169 | 170 | Takes a `BasicJewishDate` object or a `Date`, adds a date interval (`numDays`) to the date and then returns the new date. 171 | 172 | | Param | Type | 173 | | ----- | ------ | 174 | | date | `BasicJewishDate` \| `Date` | 175 | | numDays | `number` | 176 | 177 | See example [here](https://react-jewish-datepicker.js.org/#selectionWithinRange) 178 | 179 | #### subtractDates(date: `BasicJewishDate` | `Date`, numDays: `number`) ⇒ `Date` 180 | 181 | a helper function for `dontSelectOutOfRange`. 182 | 183 | Takes a `BasicJewishDate` object or a `Date`, subtracts a date interval (`numDays`) from the date and then returns the new date. 184 | 185 | | Param | Type | 186 | | ----- | ------ | 187 | | date | `BasicJewishDate` \| `Date` | 188 | | numDays | `number` | 189 | 190 | See example [here](https://react-jewish-datepicker.js.org/#selectionWithinRange) 191 | 192 | ### jewish-dates-core 193 | 194 | To create a jewish date picker in vue.js or angular, see our [core dependency](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/blob/master/packages/jewishDatesCore/README.md). 195 | 196 | ### jewish-date 197 | 198 | If you only need the hebrew date convertor without a date picker you can use [jewish-date](https://www.npmjs.com/package/jewish-date). 199 | 200 | 201 | ## Contributors 202 | 203 | - [Shmulik Kravitz](https://github.com/Shmulik-Kravitz) 204 | - [Sagi Tawil](https://github.com/sagi770) 205 | - [Yochanan Sheinberger](https://github.com/yochanan-sheinberger) 206 | 207 | License: [MIT](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/blob/master/LICENSE) -------------------------------------------------------------------------------- /packages/jewishDatesCore/config/vitest.config.ts.timestamp-1741808516064-f9e8de71522fc.mjs: -------------------------------------------------------------------------------- 1 | // ../../config/vitest/vitest.config.ts 2 | import { configDefaults, defineConfig } from "file:///C:/Users/user/Desktop/projects/react-jewish-datepicker/.yarn/__virtual__/vitest-virtual-c947823a81/0/cache/vitest-npm-2.1.1-74ca7d77ee-5bbbc7298a.zip/node_modules/vitest/dist/config.js"; 3 | import react from "file:///C:/Users/user/Desktop/projects/react-jewish-datepicker/.yarn/__virtual__/@vitejs-plugin-react-virtual-55b8ae0383/0/cache/@vitejs-plugin-react-npm-4.3.2-e79c11d68b-9ff278942d.zip/node_modules/@vitejs/plugin-react/dist/index.mjs"; 4 | 5 | // ../../config/utils/filterConsoleUtils.ts 6 | import process from "node:process"; 7 | import { format } from "node:util"; 8 | function filterConsole(excludePatterns, options) { 9 | options = { 10 | console, 11 | methods: [ 12 | "log", 13 | "debug", 14 | // 'info', 15 | "warn", 16 | "error" 17 | ], 18 | ...options 19 | }; 20 | const { console: consoleObject, methods } = options; 21 | const originalMethods = methods.map((method) => consoleObject[method]); 22 | const check = (string) => { 23 | for (const pattern of excludePatterns) { 24 | if (typeof pattern === "string") { 25 | if (string.includes(pattern)) { 26 | return true; 27 | } 28 | } else if (typeof pattern === "function") { 29 | if (pattern(string)) { 30 | return true; 31 | } 32 | } else if (pattern.test(string)) { 33 | return true; 34 | } 35 | } 36 | return false; 37 | }; 38 | for (const method of methods) { 39 | const originalMethod = consoleObject[method]; 40 | consoleObject[method] = (...args) => { 41 | if (check(format(...args))) { 42 | return; 43 | } 44 | originalMethod(...args); 45 | }; 46 | if (process.env.NODE_ENV === "test") { 47 | consoleObject[method].original = originalMethod; 48 | } 49 | } 50 | return () => { 51 | for (const [index, method] of methods.entries()) { 52 | consoleObject[method] = originalMethods[index]; 53 | } 54 | }; 55 | } 56 | 57 | // ../../config/vitest/vitest.config.ts 58 | var __vite_injected_original_dirname = "C:\\Users\\user\\Desktop\\projects\\react-jewish-datepicker\\config\\vitest"; 59 | var disableFilter = filterConsole(["MODULE_NOT_FOUND"]); 60 | var getConfig = () => defineConfig({ 61 | plugins: [react()], 62 | test: { 63 | globals: true, 64 | watch: false, 65 | setupFiles: [__vite_injected_original_dirname + "/vitest.setup.ts"], 66 | environment: "jsdom", 67 | coverage: { 68 | reporter: ["text", "json", "html", "cobertura"], 69 | exclude: ["**/.pnp.*"] 70 | }, 71 | exclude: [...configDefaults.exclude, "**/.pnp.*"] 72 | } 73 | }); 74 | 75 | // config/vitest.config.ts 76 | var config = getConfig(); 77 | var vitest_config_default = config; 78 | export { 79 | vitest_config_default as default 80 | }; 81 | //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vY29uZmlnL3ZpdGVzdC92aXRlc3QuY29uZmlnLnRzIiwgIi4uLy4uL2NvbmZpZy91dGlscy9maWx0ZXJDb25zb2xlVXRpbHMudHMiLCAiY29uZmlnL3ZpdGVzdC5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJDOlxcXFxVc2Vyc1xcXFx1c2VyXFxcXERlc2t0b3BcXFxccHJvamVjdHNcXFxccmVhY3QtamV3aXNoLWRhdGVwaWNrZXJcXFxcY29uZmlnXFxcXHZpdGVzdFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiQzpcXFxcVXNlcnNcXFxcdXNlclxcXFxEZXNrdG9wXFxcXHByb2plY3RzXFxcXHJlYWN0LWpld2lzaC1kYXRlcGlja2VyXFxcXGNvbmZpZ1xcXFx2aXRlc3RcXFxcdml0ZXN0LmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vQzovVXNlcnMvdXNlci9EZXNrdG9wL3Byb2plY3RzL3JlYWN0LWpld2lzaC1kYXRlcGlja2VyL2NvbmZpZy92aXRlc3Qvdml0ZXN0LmNvbmZpZy50c1wiO2ltcG9ydCB7IGNvbmZpZ0RlZmF1bHRzLCBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlc3QvY29uZmlnJztcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0JztcclxuaW1wb3J0IGZpbHRlckNvbnNvbGUgZnJvbSAnLi4vdXRpbHMvZmlsdGVyQ29uc29sZVV0aWxzJztcclxuY29uc3QgZGlzYWJsZUZpbHRlciA9IGZpbHRlckNvbnNvbGUoWydNT0RVTEVfTk9UX0ZPVU5EJ10pO1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldENvbmZpZyA9ICgpID0+IGRlZmluZUNvbmZpZyh7XHJcbiAgcGx1Z2luczogW3JlYWN0KCldLFxyXG4gIHRlc3Q6IHtcclxuICAgIGdsb2JhbHM6IHRydWUsXHJcbiAgICB3YXRjaDogZmFsc2UsXHJcbiAgICBzZXR1cEZpbGVzOiBbX19kaXJuYW1lICsgJy92aXRlc3Quc2V0dXAudHMnXSxcclxuICAgIGVudmlyb25tZW50OiAnanNkb20nLFxyXG4gICAgY292ZXJhZ2U6IHtcclxuICAgICAgcmVwb3J0ZXI6IFsndGV4dCcsICdqc29uJywgJ2h0bWwnLCAnY29iZXJ0dXJhJ10sXHJcbiAgICAgIGV4Y2x1ZGU6IFsnKiovLnBucC4qJ10sXHJcbiAgICAgIFxyXG4gICAgfSxcclxuICAgIGV4Y2x1ZGU6IFsuLi5jb25maWdEZWZhdWx0cy5leGNsdWRlLCAnKiovLnBucC4qJ10sXHJcbiAgfSxcclxufSkiLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIkM6XFxcXFVzZXJzXFxcXHVzZXJcXFxcRGVza3RvcFxcXFxwcm9qZWN0c1xcXFxyZWFjdC1qZXdpc2gtZGF0ZXBpY2tlclxcXFxjb25maWdcXFxcdXRpbHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkM6XFxcXFVzZXJzXFxcXHVzZXJcXFxcRGVza3RvcFxcXFxwcm9qZWN0c1xcXFxyZWFjdC1qZXdpc2gtZGF0ZXBpY2tlclxcXFxjb25maWdcXFxcdXRpbHNcXFxcZmlsdGVyQ29uc29sZVV0aWxzLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9DOi9Vc2Vycy91c2VyL0Rlc2t0b3AvcHJvamVjdHMvcmVhY3QtamV3aXNoLWRhdGVwaWNrZXIvY29uZmlnL3V0aWxzL2ZpbHRlckNvbnNvbGVVdGlscy50c1wiO2ltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XHJcbmltcG9ydCB7Zm9ybWF0fSBmcm9tICdub2RlOnV0aWwnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZmlsdGVyQ29uc29sZShleGNsdWRlUGF0dGVybnM6IGFueSwgb3B0aW9ucz86IGFueSkge1xyXG5cdG9wdGlvbnMgPSB7XHJcblx0XHRjb25zb2xlLFxyXG5cdFx0bWV0aG9kczogW1xyXG5cdFx0XHQnbG9nJyxcclxuXHRcdFx0J2RlYnVnJyxcclxuXHRcdFx0Ly8gJ2luZm8nLFxyXG5cdFx0XHQnd2FybicsXHJcblx0XHRcdCdlcnJvcicsXHJcblx0XHRdLFxyXG5cdFx0Li4ub3B0aW9ucyxcclxuXHR9O1xyXG5cclxuXHRjb25zdCB7Y29uc29sZTogY29uc29sZU9iamVjdCwgbWV0aG9kc30gPSBvcHRpb25zO1xyXG5cdGNvbnN0IG9yaWdpbmFsTWV0aG9kcyA9IG1ldGhvZHMubWFwKG1ldGhvZCA9PiBjb25zb2xlT2JqZWN0W21ldGhvZF0pO1xyXG5cclxuXHRjb25zdCBjaGVjayA9IHN0cmluZyA9PiB7XHJcblx0XHRmb3IgKGNvbnN0IHBhdHRlcm4gb2YgZXhjbHVkZVBhdHRlcm5zKSB7XHJcblx0XHRcdGlmICh0eXBlb2YgcGF0dGVybiA9PT0gJ3N0cmluZycpIHtcclxuXHRcdFx0XHRpZiAoc3RyaW5nLmluY2x1ZGVzKHBhdHRlcm4pKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0gZWxzZSBpZiAodHlwZW9mIHBhdHRlcm4gPT09ICdmdW5jdGlvbicpIHtcclxuXHRcdFx0XHRpZiAocGF0dGVybihzdHJpbmcpKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0gZWxzZSBpZiAocGF0dGVybi50ZXN0KHN0cmluZykpIHtcclxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9O1xyXG5cclxuXHRmb3IgKGNvbnN0IG1ldGhvZCBvZiBtZXRob2RzKSB7XHJcblx0XHRjb25zdCBvcmlnaW5hbE1ldGhvZCA9IGNvbnNvbGVPYmplY3RbbWV0aG9kXTtcclxuXHJcblx0XHRjb25zb2xlT2JqZWN0W21ldGhvZF0gPSAoLi4uYXJncykgPT4ge1xyXG5cdFx0XHRpZiAoY2hlY2soZm9ybWF0KC4uLmFyZ3MpKSkge1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0b3JpZ2luYWxNZXRob2QoLi4uYXJncyk7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIEV4cG9zZWQgZm9yIHRlc3RpbmdcclxuXHRcdGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ3Rlc3QnKSB7XHJcblx0XHRcdGNvbnNvbGVPYmplY3RbbWV0aG9kXS5vcmlnaW5hbCA9IG9yaWdpbmFsTWV0aG9kO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cmV0dXJuICgpID0+IHtcclxuXHRcdGZvciAoY29uc3QgW2luZGV4LCBtZXRob2RdIG9mIG1ldGhvZHMuZW50cmllcygpKSB7XHJcblx0XHRcdGNvbnNvbGVPYmplY3RbbWV0aG9kXSA9IG9yaWdpbmFsTWV0aG9kc1tpbmRleF07XHJcblx0XHR9XHJcblx0fTtcclxufVxyXG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIkM6XFxcXFVzZXJzXFxcXHVzZXJcXFxcRGVza3RvcFxcXFxwcm9qZWN0c1xcXFxyZWFjdC1qZXdpc2gtZGF0ZXBpY2tlclxcXFxwYWNrYWdlc1xcXFxqZXdpc2hEYXRlc0NvcmVcXFxcY29uZmlnXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCJDOlxcXFxVc2Vyc1xcXFx1c2VyXFxcXERlc2t0b3BcXFxccHJvamVjdHNcXFxccmVhY3QtamV3aXNoLWRhdGVwaWNrZXJcXFxccGFja2FnZXNcXFxcamV3aXNoRGF0ZXNDb3JlXFxcXGNvbmZpZ1xcXFx2aXRlc3QuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9DOi9Vc2Vycy91c2VyL0Rlc2t0b3AvcHJvamVjdHMvcmVhY3QtamV3aXNoLWRhdGVwaWNrZXIvcGFja2FnZXMvamV3aXNoRGF0ZXNDb3JlL2NvbmZpZy92aXRlc3QuY29uZmlnLnRzXCI7aW1wb3J0IHtnZXRDb25maWd9IGZyb20gXCIuLi8uLi8uLi9jb25maWcvdml0ZXN0L3ZpdGVzdC5jb25maWdcIjtcclxuY29uc3QgY29uZmlnID0gZ2V0Q29uZmlnKCk7XHJcbmV4cG9ydCBkZWZhdWx0IGNvbmZpZzsiXSwKICAibWFwcGluZ3MiOiAiO0FBQWtaLFNBQVMsZ0JBQWdCLG9CQUFvQjtBQUMvYixPQUFPLFdBQVc7OztBQ0R1WSxPQUFPLGFBQWE7QUFDN2EsU0FBUSxjQUFhO0FBRU4sU0FBUixjQUErQixpQkFBc0IsU0FBZTtBQUMxRSxZQUFVO0FBQUEsSUFDVDtBQUFBLElBQ0EsU0FBUztBQUFBLE1BQ1I7QUFBQSxNQUNBO0FBQUE7QUFBQSxNQUVBO0FBQUEsTUFDQTtBQUFBLElBQ0Q7QUFBQSxJQUNBLEdBQUc7QUFBQSxFQUNKO0FBRUEsUUFBTSxFQUFDLFNBQVMsZUFBZSxRQUFPLElBQUk7QUFDMUMsUUFBTSxrQkFBa0IsUUFBUSxJQUFJLFlBQVUsY0FBYyxNQUFNLENBQUM7QUFFbkUsUUFBTSxRQUFRLFlBQVU7QUFDdkIsZUFBVyxXQUFXLGlCQUFpQjtBQUN0QyxVQUFJLE9BQU8sWUFBWSxVQUFVO0FBQ2hDLFlBQUksT0FBTyxTQUFTLE9BQU8sR0FBRztBQUM3QixpQkFBTztBQUFBLFFBQ1I7QUFBQSxNQUNELFdBQVcsT0FBTyxZQUFZLFlBQVk7QUFDekMsWUFBSSxRQUFRLE1BQU0sR0FBRztBQUNwQixpQkFBTztBQUFBLFFBQ1I7QUFBQSxNQUNELFdBQVcsUUFBUSxLQUFLLE1BQU0sR0FBRztBQUNoQyxlQUFPO0FBQUEsTUFDUjtBQUFBLElBQ0Q7QUFFQSxXQUFPO0FBQUEsRUFDUjtBQUVBLGFBQVcsVUFBVSxTQUFTO0FBQzdCLFVBQU0saUJBQWlCLGNBQWMsTUFBTTtBQUUzQyxrQkFBYyxNQUFNLElBQUksSUFBSSxTQUFTO0FBQ3BDLFVBQUksTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUc7QUFDM0I7QUFBQSxNQUNEO0FBRUEscUJBQWUsR0FBRyxJQUFJO0FBQUEsSUFDdkI7QUFHQSxRQUFJLFFBQVEsSUFBSSxhQUFhLFFBQVE7QUFDcEMsb0JBQWMsTUFBTSxFQUFFLFdBQVc7QUFBQSxJQUNsQztBQUFBLEVBQ0Q7QUFFQSxTQUFPLE1BQU07QUFDWixlQUFXLENBQUMsT0FBTyxNQUFNLEtBQUssUUFBUSxRQUFRLEdBQUc7QUFDaEQsb0JBQWMsTUFBTSxJQUFJLGdCQUFnQixLQUFLO0FBQUEsSUFDOUM7QUFBQSxFQUNEO0FBQ0Q7OztBRDNEQSxJQUFNLG1DQUFtQztBQUd6QyxJQUFNLGdCQUFnQixjQUFjLENBQUMsa0JBQWtCLENBQUM7QUFFakQsSUFBTSxZQUFZLE1BQU0sYUFBYTtBQUFBLEVBQzFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFBQSxFQUNqQixNQUFNO0FBQUEsSUFDSixTQUFTO0FBQUEsSUFDVCxPQUFPO0FBQUEsSUFDUCxZQUFZLENBQUMsbUNBQVksa0JBQWtCO0FBQUEsSUFDM0MsYUFBYTtBQUFBLElBQ2IsVUFBVTtBQUFBLE1BQ1IsVUFBVSxDQUFDLFFBQVEsUUFBUSxRQUFRLFdBQVc7QUFBQSxNQUM5QyxTQUFTLENBQUMsV0FBVztBQUFBLElBRXZCO0FBQUEsSUFDQSxTQUFTLENBQUMsR0FBRyxlQUFlLFNBQVMsV0FBVztBQUFBLEVBQ2xEO0FBQ0YsQ0FBQzs7O0FFbEJELElBQU0sU0FBUyxVQUFVO0FBQ3pCLElBQU8sd0JBQVE7IiwKICAibmFtZXMiOiBbXQp9Cg== 82 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsserver.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/lib/tsserver.js 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | const moduleWrapper = exports => { 32 | return wrapWithUserWrapper(moduleWrapperFn(exports)); 33 | }; 34 | 35 | const moduleWrapperFn = tsserver => { 36 | if (!process.versions.pnp) { 37 | return tsserver; 38 | } 39 | 40 | const {isAbsolute} = require(`path`); 41 | const pnpApi = require(`pnpapi`); 42 | 43 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 44 | const isPortal = str => str.startsWith("portal:/"); 45 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 46 | 47 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 48 | return `${locator.name}@${locator.reference}`; 49 | })); 50 | 51 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 52 | // doesn't understand. This layer makes sure to remove the protocol 53 | // before forwarding it to TS, and to add it back on all returned paths. 54 | 55 | function toEditorPath(str) { 56 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 57 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 58 | // We also take the opportunity to turn virtual paths into physical ones; 59 | // this makes it much easier to work with workspaces that list peer 60 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 61 | // file instances instead of the real ones. 62 | // 63 | // We only do this to modules owned by the the dependency tree roots. 64 | // This avoids breaking the resolution when jumping inside a vendor 65 | // with peer dep (otherwise jumping into react-dom would show resolution 66 | // errors on react). 67 | // 68 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 69 | if (resolved) { 70 | const locator = pnpApi.findPackageLocator(resolved); 71 | if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { 72 | str = resolved; 73 | } 74 | } 75 | 76 | str = normalize(str); 77 | 78 | if (str.match(/\.zip\//)) { 79 | switch (hostInfo) { 80 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 81 | // VSCode only adds it automatically for supported schemes, 82 | // so we have to do it manually for the `zip` scheme. 83 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 84 | // 85 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 86 | // 87 | // 2021-10-08: VSCode changed the format in 1.61. 88 | // Before | ^zip:/c:/foo/bar.zip/package.json 89 | // After | ^/zip//c:/foo/bar.zip/package.json 90 | // 91 | // 2022-04-06: VSCode changed the format in 1.66. 92 | // Before | ^/zip//c:/foo/bar.zip/package.json 93 | // After | ^/zip/c:/foo/bar.zip/package.json 94 | // 95 | // 2022-05-06: VSCode changed the format in 1.68 96 | // Before | ^/zip/c:/foo/bar.zip/package.json 97 | // After | ^/zip//c:/foo/bar.zip/package.json 98 | // 99 | case `vscode <1.61`: { 100 | str = `^zip:${str}`; 101 | } break; 102 | 103 | case `vscode <1.66`: { 104 | str = `^/zip/${str}`; 105 | } break; 106 | 107 | case `vscode <1.68`: { 108 | str = `^/zip${str}`; 109 | } break; 110 | 111 | case `vscode`: { 112 | str = `^/zip/${str}`; 113 | } break; 114 | 115 | // To make "go to definition" work, 116 | // We have to resolve the actual file system path from virtual path 117 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 118 | case `coc-nvim`: { 119 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 120 | str = resolve(`zipfile:${str}`); 121 | } break; 122 | 123 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 124 | // We have to resolve the actual file system path from virtual path, 125 | // everything else is up to neovim 126 | case `neovim`: { 127 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 128 | str = `zipfile://${str}`; 129 | } break; 130 | 131 | default: { 132 | str = `zip:${str}`; 133 | } break; 134 | } 135 | } else { 136 | str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); 137 | } 138 | } 139 | 140 | return str; 141 | } 142 | 143 | function fromEditorPath(str) { 144 | switch (hostInfo) { 145 | case `coc-nvim`: { 146 | str = str.replace(/\.zip::/, `.zip/`); 147 | // The path for coc-nvim is in format of //zipfile://.yarn/... 148 | // So in order to convert it back, we use .* to match all the thing 149 | // before `zipfile:` 150 | return process.platform === `win32` 151 | ? str.replace(/^.*zipfile:\//, ``) 152 | : str.replace(/^.*zipfile:/, ``); 153 | } break; 154 | 155 | case `neovim`: { 156 | str = str.replace(/\.zip::/, `.zip/`); 157 | // The path for neovim is in format of zipfile:////.yarn/... 158 | return str.replace(/^zipfile:\/\//, ``); 159 | } break; 160 | 161 | case `vscode`: 162 | default: { 163 | return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) 164 | } break; 165 | } 166 | } 167 | 168 | // Force enable 'allowLocalPluginLoads' 169 | // TypeScript tries to resolve plugins using a path relative to itself 170 | // which doesn't work when using the global cache 171 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 172 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 173 | // TypeScript already does local loads and if this code is running the user trusts the workspace 174 | // https://github.com/microsoft/vscode/issues/45856 175 | const ConfiguredProject = tsserver.server.ConfiguredProject; 176 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 177 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 178 | this.projectService.allowLocalPluginLoads = true; 179 | return originalEnablePluginsWithOptions.apply(this, arguments); 180 | }; 181 | 182 | // And here is the point where we hijack the VSCode <-> TS communications 183 | // by adding ourselves in the middle. We locate everything that looks 184 | // like an absolute path of ours and normalize it. 185 | 186 | const Session = tsserver.server.Session; 187 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 188 | let hostInfo = `unknown`; 189 | 190 | Object.assign(Session.prototype, { 191 | onMessage(/** @type {string | object} */ message) { 192 | const isStringMessage = typeof message === 'string'; 193 | const parsedMessage = isStringMessage ? JSON.parse(message) : message; 194 | 195 | if ( 196 | parsedMessage != null && 197 | typeof parsedMessage === `object` && 198 | parsedMessage.arguments && 199 | typeof parsedMessage.arguments.hostInfo === `string` 200 | ) { 201 | hostInfo = parsedMessage.arguments.hostInfo; 202 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { 203 | const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( 204 | // The RegExp from https://semver.org/ but without the caret at the start 205 | /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ 206 | ) ?? []).map(Number) 207 | 208 | if (major === 1) { 209 | if (minor < 61) { 210 | hostInfo += ` <1.61`; 211 | } else if (minor < 66) { 212 | hostInfo += ` <1.66`; 213 | } else if (minor < 68) { 214 | hostInfo += ` <1.68`; 215 | } 216 | } 217 | } 218 | } 219 | 220 | const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { 221 | return typeof value === 'string' ? fromEditorPath(value) : value; 222 | }); 223 | 224 | return originalOnMessage.call( 225 | this, 226 | isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) 227 | ); 228 | }, 229 | 230 | send(/** @type {any} */ msg) { 231 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 232 | return typeof value === `string` ? toEditorPath(value) : value; 233 | }))); 234 | } 235 | }); 236 | 237 | return tsserver; 238 | }; 239 | 240 | const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10)); 241 | // In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well. 242 | // Ref https://github.com/microsoft/TypeScript/pull/55326 243 | if (major > 5 || (major === 5 && minor >= 5)) { 244 | moduleWrapper(absRequire(`typescript`)); 245 | } 246 | 247 | // Defer to the real typescript/lib/tsserver.js your application uses 248 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`)); 249 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsserverlibrary.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/lib/tsserverlibrary.js 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | const moduleWrapper = exports => { 32 | return wrapWithUserWrapper(moduleWrapperFn(exports)); 33 | }; 34 | 35 | const moduleWrapperFn = tsserver => { 36 | if (!process.versions.pnp) { 37 | return tsserver; 38 | } 39 | 40 | const {isAbsolute} = require(`path`); 41 | const pnpApi = require(`pnpapi`); 42 | 43 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 44 | const isPortal = str => str.startsWith("portal:/"); 45 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 46 | 47 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 48 | return `${locator.name}@${locator.reference}`; 49 | })); 50 | 51 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 52 | // doesn't understand. This layer makes sure to remove the protocol 53 | // before forwarding it to TS, and to add it back on all returned paths. 54 | 55 | function toEditorPath(str) { 56 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 57 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 58 | // We also take the opportunity to turn virtual paths into physical ones; 59 | // this makes it much easier to work with workspaces that list peer 60 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 61 | // file instances instead of the real ones. 62 | // 63 | // We only do this to modules owned by the the dependency tree roots. 64 | // This avoids breaking the resolution when jumping inside a vendor 65 | // with peer dep (otherwise jumping into react-dom would show resolution 66 | // errors on react). 67 | // 68 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 69 | if (resolved) { 70 | const locator = pnpApi.findPackageLocator(resolved); 71 | if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { 72 | str = resolved; 73 | } 74 | } 75 | 76 | str = normalize(str); 77 | 78 | if (str.match(/\.zip\//)) { 79 | switch (hostInfo) { 80 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 81 | // VSCode only adds it automatically for supported schemes, 82 | // so we have to do it manually for the `zip` scheme. 83 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 84 | // 85 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 86 | // 87 | // 2021-10-08: VSCode changed the format in 1.61. 88 | // Before | ^zip:/c:/foo/bar.zip/package.json 89 | // After | ^/zip//c:/foo/bar.zip/package.json 90 | // 91 | // 2022-04-06: VSCode changed the format in 1.66. 92 | // Before | ^/zip//c:/foo/bar.zip/package.json 93 | // After | ^/zip/c:/foo/bar.zip/package.json 94 | // 95 | // 2022-05-06: VSCode changed the format in 1.68 96 | // Before | ^/zip/c:/foo/bar.zip/package.json 97 | // After | ^/zip//c:/foo/bar.zip/package.json 98 | // 99 | case `vscode <1.61`: { 100 | str = `^zip:${str}`; 101 | } break; 102 | 103 | case `vscode <1.66`: { 104 | str = `^/zip/${str}`; 105 | } break; 106 | 107 | case `vscode <1.68`: { 108 | str = `^/zip${str}`; 109 | } break; 110 | 111 | case `vscode`: { 112 | str = `^/zip/${str}`; 113 | } break; 114 | 115 | // To make "go to definition" work, 116 | // We have to resolve the actual file system path from virtual path 117 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 118 | case `coc-nvim`: { 119 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 120 | str = resolve(`zipfile:${str}`); 121 | } break; 122 | 123 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 124 | // We have to resolve the actual file system path from virtual path, 125 | // everything else is up to neovim 126 | case `neovim`: { 127 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 128 | str = `zipfile://${str}`; 129 | } break; 130 | 131 | default: { 132 | str = `zip:${str}`; 133 | } break; 134 | } 135 | } else { 136 | str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); 137 | } 138 | } 139 | 140 | return str; 141 | } 142 | 143 | function fromEditorPath(str) { 144 | switch (hostInfo) { 145 | case `coc-nvim`: { 146 | str = str.replace(/\.zip::/, `.zip/`); 147 | // The path for coc-nvim is in format of //zipfile://.yarn/... 148 | // So in order to convert it back, we use .* to match all the thing 149 | // before `zipfile:` 150 | return process.platform === `win32` 151 | ? str.replace(/^.*zipfile:\//, ``) 152 | : str.replace(/^.*zipfile:/, ``); 153 | } break; 154 | 155 | case `neovim`: { 156 | str = str.replace(/\.zip::/, `.zip/`); 157 | // The path for neovim is in format of zipfile:////.yarn/... 158 | return str.replace(/^zipfile:\/\//, ``); 159 | } break; 160 | 161 | case `vscode`: 162 | default: { 163 | return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) 164 | } break; 165 | } 166 | } 167 | 168 | // Force enable 'allowLocalPluginLoads' 169 | // TypeScript tries to resolve plugins using a path relative to itself 170 | // which doesn't work when using the global cache 171 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 172 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 173 | // TypeScript already does local loads and if this code is running the user trusts the workspace 174 | // https://github.com/microsoft/vscode/issues/45856 175 | const ConfiguredProject = tsserver.server.ConfiguredProject; 176 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 177 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 178 | this.projectService.allowLocalPluginLoads = true; 179 | return originalEnablePluginsWithOptions.apply(this, arguments); 180 | }; 181 | 182 | // And here is the point where we hijack the VSCode <-> TS communications 183 | // by adding ourselves in the middle. We locate everything that looks 184 | // like an absolute path of ours and normalize it. 185 | 186 | const Session = tsserver.server.Session; 187 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 188 | let hostInfo = `unknown`; 189 | 190 | Object.assign(Session.prototype, { 191 | onMessage(/** @type {string | object} */ message) { 192 | const isStringMessage = typeof message === 'string'; 193 | const parsedMessage = isStringMessage ? JSON.parse(message) : message; 194 | 195 | if ( 196 | parsedMessage != null && 197 | typeof parsedMessage === `object` && 198 | parsedMessage.arguments && 199 | typeof parsedMessage.arguments.hostInfo === `string` 200 | ) { 201 | hostInfo = parsedMessage.arguments.hostInfo; 202 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { 203 | const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( 204 | // The RegExp from https://semver.org/ but without the caret at the start 205 | /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ 206 | ) ?? []).map(Number) 207 | 208 | if (major === 1) { 209 | if (minor < 61) { 210 | hostInfo += ` <1.61`; 211 | } else if (minor < 66) { 212 | hostInfo += ` <1.66`; 213 | } else if (minor < 68) { 214 | hostInfo += ` <1.68`; 215 | } 216 | } 217 | } 218 | } 219 | 220 | const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { 221 | return typeof value === 'string' ? fromEditorPath(value) : value; 222 | }); 223 | 224 | return originalOnMessage.call( 225 | this, 226 | isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) 227 | ); 228 | }, 229 | 230 | send(/** @type {any} */ msg) { 231 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 232 | return typeof value === `string` ? toEditorPath(value) : value; 233 | }))); 234 | } 235 | }); 236 | 237 | return tsserver; 238 | }; 239 | 240 | const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10)); 241 | // In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well. 242 | // Ref https://github.com/microsoft/TypeScript/pull/55326 243 | if (major > 5 || (major === 5 && minor >= 5)) { 244 | moduleWrapper(absRequire(`typescript`)); 245 | } 246 | 247 | // Defer to the real typescript/lib/tsserverlibrary.js your application uses 248 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`)); 249 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/src/jewishDateCore.ts: -------------------------------------------------------------------------------- 1 | import { 2 | toJewishDate, 3 | toGregorianDate, 4 | formatJewishDateInHebrew, 5 | BasicJewishDate as BasicJewishDateConverter, 6 | JewishMonthType, 7 | JewishMonth as OrigJewishMonth, 8 | isLeapYear, 9 | formatJewishDate, 10 | JewishMonth, 11 | getJewishMonthsInOrder, 12 | getJewishMonthInHebrew, 13 | } from "jewish-date"; 14 | import Dayjs from "dayjs"; 15 | import { 16 | JewishDate, 17 | JewishDay, 18 | JewishMonthMetadata, 19 | JewishMonthInfo, 20 | BasicJewishMonthInfo, 21 | IdText, 22 | BasicJewishDate, 23 | BasicJewishDay, 24 | } from "./interfaces"; 25 | 26 | export function isValidDate(date: Date | BasicJewishDate): date is Date { 27 | return date && Object.prototype.toString.call(date) === "[object Date]"; 28 | } 29 | 30 | export const getHebWeekdays = (): string[] => { 31 | return ["א", "ב", "ג", "ד", "ה", "ו", "ש"]; 32 | }; 33 | 34 | export const getEngWeekdays = (): string[] => { 35 | return ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; 36 | }; 37 | 38 | export const getWeekdays = (isHebrew: boolean): string[] => { 39 | return isHebrew ? getHebWeekdays() : getEngWeekdays(); 40 | }; 41 | 42 | export const getHebJewishMonths = (): IdText[] => { 43 | return [ 44 | { 45 | id: "Tishri", 46 | text: "תשרי", 47 | }, 48 | { 49 | id: "Cheshvan", 50 | text: "חשון", 51 | }, 52 | { 53 | id: "Kislev", 54 | text: "כסלו", 55 | }, 56 | { 57 | id: "Tevet", 58 | text: "טבת", 59 | }, 60 | { 61 | id: "Shevat", 62 | text: "שבט", 63 | }, 64 | { 65 | id: "AdarI", 66 | text: "אדר א", 67 | }, 68 | { 69 | id: "AdarII", 70 | text: "אדר ב", 71 | }, 72 | { 73 | id: "Nisan", 74 | text: "ניסן", 75 | }, 76 | { 77 | id: "Iyyar", 78 | text: "אייר", 79 | }, 80 | { 81 | id: "Sivan", 82 | text: "סיון", 83 | }, 84 | { 85 | id: "Tammuz", 86 | text: "תמוז", 87 | }, 88 | { 89 | id: "Av", 90 | text: "אב", 91 | }, 92 | { 93 | id: "Elul", 94 | text: "אלול", 95 | }, 96 | ]; 97 | }; 98 | 99 | export const getEngJewishMonths = (): IdText[] => { 100 | return [ 101 | { 102 | id: "Tishri", 103 | text: "Tishri", 104 | }, 105 | { 106 | id: "Cheshvan", 107 | text: "Cheshvan", 108 | }, 109 | { 110 | id: "Kislev", 111 | text: "Kislev", 112 | }, 113 | { 114 | id: "Tevet", 115 | text: "Tevet", 116 | }, 117 | { 118 | id: "Shevat", 119 | text: "Shevat", 120 | }, 121 | { 122 | id: "AdarI", 123 | text: "AdarI", 124 | }, 125 | { 126 | id: "AdarII", 127 | text: "AdarII", 128 | }, 129 | { 130 | id: "Nisan", 131 | text: "Nisan", 132 | }, 133 | { 134 | id: "Iyyar", 135 | text: "Iyyar", 136 | }, 137 | { 138 | id: "Sivan", 139 | text: "Sivan", 140 | }, 141 | { 142 | id: "Tammuz", 143 | text: "Tammuz", 144 | }, 145 | { 146 | id: "Av", 147 | text: "Av", 148 | }, 149 | { 150 | id: "Elul", 151 | text: "Elul", 152 | }, 153 | ]; 154 | }; 155 | 156 | export const getJewishMonths = (year: number, isHebrew?: boolean): IdText[] => { 157 | const months = getJewishMonthsInOrder(year); 158 | return months.slice(1).map((month, i) => { 159 | return { 160 | id: month, 161 | text: isHebrew ? getJewishMonthInHebrew(JewishMonth[month]) : month, 162 | }; 163 | }); 164 | }; 165 | 166 | export const getJewishYears = (year: number = 5780): number[] => { 167 | const years: number[] = []; 168 | for (let i = 100; i > 0; i--) { 169 | const element = year - i; 170 | years.push(element); 171 | } 172 | years.push(year); 173 | for (let i = 1; i <= 100; i++) { 174 | const element = year + i; 175 | years.push(element); 176 | } 177 | return years; 178 | }; 179 | 180 | export const getPrevMonth = ( 181 | basicJewishMonthInfo: BasicJewishMonthInfo 182 | ): BasicJewishMonthInfo => { 183 | const result = { ...basicJewishMonthInfo }; 184 | const months = getJewishMonths( 185 | basicJewishMonthInfo.year, 186 | basicJewishMonthInfo.isHebrew 187 | ); 188 | const monthIndex = months 189 | .map((month) => month.id) 190 | .indexOf(basicJewishMonthInfo.month); 191 | if (monthIndex !== -1) { 192 | if (monthIndex === 0) { 193 | result.month = JewishMonth[months[months.length - 1].id]; 194 | result.year--; 195 | } else { 196 | result.month = JewishMonth[months[monthIndex - 1].id]; 197 | } 198 | } 199 | return result; 200 | }; 201 | 202 | export const getNextMonth = ( 203 | basicJewishMonthInfo: BasicJewishMonthInfo 204 | ): BasicJewishMonthInfo => { 205 | const result = { ...basicJewishMonthInfo }; 206 | const months = getJewishMonths(basicJewishMonthInfo.year); 207 | const monthIndex = months 208 | .map((month) => month.id) 209 | .indexOf(basicJewishMonthInfo.month); 210 | 211 | if (monthIndex !== -1) { 212 | if (monthIndex === months.length - 1) { 213 | result.month = JewishMonth[months[0].id]; 214 | result.year++; 215 | } else { 216 | result.month = JewishMonth[months[monthIndex + 1].id]; 217 | } 218 | } 219 | 220 | return result; 221 | }; 222 | 223 | export const getGregDate = (props: BasicJewishDate): Date => { 224 | if ( 225 | !props || 226 | props.monthName === OrigJewishMonth.None || 227 | props.year < 1 || 228 | props.day < 1 229 | ) { 230 | return new Date(); 231 | } 232 | 233 | // const day = new HeDate.HDate(props.day, props.monthName, props.year); 234 | // return day.greg(); 235 | const jewishDate: BasicJewishDateConverter = { 236 | day: props.day, 237 | monthName: props.monthName as unknown as JewishMonthType, 238 | year: props.year, 239 | }; 240 | const date = toGregorianDate(jewishDate); 241 | return date; 242 | }; 243 | 244 | export const getJewishMonthInfo = (date: Date): JewishMonthMetadata => { 245 | const jewishDate: JewishDate = getJewishDate(date); 246 | const startOfJewishMonth = Dayjs(date).subtract(jewishDate.day - 1, "day"); 247 | 248 | const dayOfWeek: number = Number(startOfJewishMonth.format("d")); 249 | const sundayStartOfTheMonth = startOfJewishMonth.subtract(dayOfWeek, "day"); 250 | 251 | return { 252 | jewishDate, 253 | jewishMonth: jewishDate.month, 254 | startOfJewishMonth, 255 | sundayStartOfTheMonth, 256 | }; 257 | }; 258 | 259 | export const getJewishDate = (date: Date): JewishDate => { 260 | return toJewishDate(date); 261 | }; 262 | 263 | export const IsJewishDatesEqual = ( 264 | jewishDate1: JewishDate, 265 | jewishDate2: JewishDate 266 | ): boolean => { 267 | return ( 268 | jewishDate1 && 269 | jewishDate2 && 270 | jewishDate1.day === jewishDate2.day && 271 | jewishDate1.month === jewishDate2.month && 272 | jewishDate1.year === jewishDate2.year 273 | ); 274 | }; 275 | 276 | export const getJewishDay = (dayjsDate: Dayjs.Dayjs): JewishDay => { 277 | const jewishDate: JewishDate = getJewishDate(dayjsDate.toDate()); 278 | const day: JewishDay = { 279 | day: jewishDate.day, 280 | jewishDateStr: formatJewishDate(jewishDate), 281 | jewishDateStrHebrew: formatJewishDateInHebrew(jewishDate), 282 | jewishDate: jewishDate, 283 | dayjsDate: dayjsDate, 284 | date: dayjsDate.toDate(), 285 | isCurrentMonth: false, 286 | }; 287 | 288 | return day; 289 | }; 290 | 291 | export const getJewishMonth = (date: Date): JewishMonthInfo => { 292 | const jewishMonthInfo = getJewishMonthInfo(date); 293 | const jewishMonth: JewishMonthInfo = { 294 | selectedDay: null, 295 | jewishMonth: jewishMonthInfo.jewishMonth, 296 | jewishYear: jewishMonthInfo.jewishDate.year, 297 | jewishMonthString: jewishMonthInfo.jewishDate.monthName, 298 | days: [], 299 | }; 300 | let currentDate = jewishMonthInfo.sundayStartOfTheMonth; 301 | 302 | for (let i = 0; i < 42; i++) { 303 | const day = getJewishDay(currentDate); 304 | day.isCurrentMonth = jewishMonth.jewishMonth === day.jewishDate.month; 305 | if (IsJewishDatesEqual(jewishMonthInfo.jewishDate, day.jewishDate)) { 306 | jewishMonth.selectedDay = day; 307 | } 308 | if (i < 7 || day.isCurrentMonth || day.date.getDay() > 0) { 309 | jewishMonth.days.push(day); 310 | currentDate = currentDate.add(1, "day"); 311 | } 312 | } 313 | 314 | return jewishMonth; 315 | }; 316 | 317 | export const getHolidays = (isIsrael: boolean): string[] => { 318 | const holidays = [ 319 | "1 Tishri", 320 | "2 Tishri", 321 | "10 Tishri", 322 | "15 Tishri", 323 | "22 Tishri", 324 | "15 Nisan", 325 | "21 Nisan", 326 | "6 Sivan", 327 | ]; 328 | if (!isIsrael) { 329 | holidays.push("16 Tishri", "23 Tishri", "16 Nisan", "22 Nisan", "7 Sivan"); 330 | } 331 | 332 | return holidays; 333 | }; 334 | 335 | export const dontSelectHolidays = (isIsrael?: boolean): any => { 336 | const holidays = getHolidays(isIsrael); 337 | 338 | return (day: BasicJewishDay): boolean => { 339 | return !holidays.includes( 340 | `${day.jewishDate.day} ${day.jewishDate.monthName}` 341 | ); 342 | }; 343 | }; 344 | 345 | export const dontSelectShabat = (day: BasicJewishDay): boolean => { 346 | const dayOfWeek = day.date.getDay(); 347 | 348 | return dayOfWeek !== 6; 349 | }; 350 | 351 | export const dontSelectShabatAndHolidays = (isIsrael?: boolean): any => { 352 | return (day: BasicJewishDay): boolean => { 353 | return dontSelectShabat(day) && dontSelectHolidays(isIsrael)(day); 354 | }; 355 | }; 356 | 357 | export const dontSelectOutOfRange = ( 358 | minDate: Date | null, 359 | maxDate: Date | null 360 | ): any => { 361 | const min = minDate && Dayjs(minDate).subtract(1, "day").startOf("date"); 362 | const max = maxDate && Dayjs(maxDate).add(1, "day").startOf("date"); 363 | 364 | return (day: BasicJewishDay) => { 365 | const date = Dayjs(day.date).startOf("date"); 366 | 367 | if (min && max) { 368 | return date.isAfter(min) && date.isBefore(max); 369 | } else if (min) { 370 | return date.isAfter(min); 371 | } else if (max) { 372 | return date.isBefore(max); 373 | } 374 | return false; 375 | }; 376 | }; 377 | 378 | export const addDates = ( 379 | date: BasicJewishDate | Date, 380 | numDays: number 381 | ): Date => { 382 | const formatedDate = isValidDate(date) ? date : getGregDate(date); 383 | 384 | return Dayjs(formatedDate).add(numDays, "day").toDate(); 385 | }; 386 | 387 | export const subtractDates = ( 388 | date: BasicJewishDate | Date, 389 | numDays: number 390 | ): Date => { 391 | const formatedDate = isValidDate(date) ? date : getGregDate(date); 392 | 393 | return Dayjs(formatedDate).subtract(numDays, "day").toDate(); 394 | }; 395 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/src/__tests__/jewishDatesCore.test.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | isValidDate, 3 | getHebWeekdays, 4 | getEngWeekdays, 5 | getWeekdays, 6 | getHebJewishMonths, 7 | getEngJewishMonths, 8 | getJewishMonths, 9 | getJewishYears, 10 | getPrevMonth, 11 | getNextMonth, 12 | getGregDate, 13 | getJewishMonthInfo, 14 | getJewishDate, 15 | IsJewishDatesEqual, 16 | getJewishDay, 17 | getJewishMonth, 18 | getHolidays, 19 | dontSelectHolidays, 20 | dontSelectShabat, 21 | dontSelectShabatAndHolidays, 22 | dontSelectOutOfRange, 23 | addDates, 24 | subtractDates, 25 | BasicJewishDate, 26 | BasicJewishDay, 27 | JewishMonth 28 | } from "../index"; 29 | import Dayjs from "dayjs"; 30 | import { BasicJewishMonthInfo, JewishDate } from "../interfaces"; 31 | import { it, expect, describe } from "vitest"; 32 | 33 | 34 | const basicJewishDate: BasicJewishDate = { 35 | day: 13, 36 | monthName: "Elul", 37 | year: 5781, 38 | }; 39 | describe("jewishDatesCore", () => { 40 | it("is valid date", async () => { 41 | expect(isValidDate(new Date())).toBeTruthy(); 42 | }); 43 | 44 | it("is not valid date", async () => { 45 | expect(isValidDate(basicJewishDate)).toBeFalsy(); 46 | }); 47 | 48 | const hebWeekdays = ["א", "ב", "ג", "ד", "ה", "ו", "ש"]; 49 | const engWeekdays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; 50 | 51 | it("get hebrew weekdays", async () => { 52 | expect(getHebWeekdays()).toEqual(hebWeekdays); 53 | }); 54 | 55 | it("get english weekdays", async () => { 56 | expect(getEngWeekdays()).toEqual(engWeekdays); 57 | }); 58 | 59 | it("get weekdays in hebrew", async () => { 60 | expect(getWeekdays(true)).toEqual(hebWeekdays); 61 | }); 62 | 63 | it("get weekdays in english", async () => { 64 | expect(getWeekdays(false)).toEqual(engWeekdays); 65 | }); 66 | 67 | 68 | it("get hebrew jewish months", async () => { 69 | const hebJewishMonth = [ 70 | { 71 | id: "Tishri", 72 | text: "תשרי", 73 | }, 74 | { 75 | id: "Cheshvan", 76 | text: "חשון", 77 | }, 78 | { 79 | id: "Kislev", 80 | text: "כסלו", 81 | }, 82 | { 83 | id: "Tevet", 84 | text: "טבת", 85 | }, 86 | { 87 | id: "Shevat", 88 | text: "שבט", 89 | }, 90 | { 91 | id: "AdarI", 92 | text: "אדר א", 93 | }, 94 | { 95 | id: "AdarII", 96 | text: "אדר ב", 97 | }, 98 | { 99 | id: "Nisan", 100 | text: "ניסן", 101 | }, 102 | { 103 | id: "Iyyar", 104 | text: "אייר", 105 | }, 106 | { 107 | id: "Sivan", 108 | text: "סיון", 109 | }, 110 | { 111 | id: "Tammuz", 112 | text: "תמוז", 113 | }, 114 | { 115 | id: "Av", 116 | text: "אב", 117 | }, 118 | { 119 | id: "Elul", 120 | text: "אלול", 121 | }, 122 | ]; 123 | 124 | expect(getHebJewishMonths()).toEqual(hebJewishMonth); 125 | }); 126 | 127 | it("get english jewish months", async () => { 128 | const engJewishMonth = [ 129 | { 130 | id: "Tishri", 131 | text: "Tishri", 132 | }, 133 | { 134 | id: "Cheshvan", 135 | text: "Cheshvan", 136 | }, 137 | { 138 | id: "Kislev", 139 | text: "Kislev", 140 | }, 141 | { 142 | id: "Tevet", 143 | text: "Tevet", 144 | }, 145 | { 146 | id: "Shevat", 147 | text: "Shevat", 148 | }, 149 | { 150 | id: "AdarI", 151 | text: "AdarI", 152 | }, 153 | { 154 | id: "AdarII", 155 | text: "AdarII", 156 | }, 157 | { 158 | id: "Nisan", 159 | text: "Nisan", 160 | }, 161 | { 162 | id: "Iyyar", 163 | text: "Iyyar", 164 | }, 165 | { 166 | id: "Sivan", 167 | text: "Sivan", 168 | }, 169 | { 170 | id: "Tammuz", 171 | text: "Tammuz", 172 | }, 173 | { 174 | id: "Av", 175 | text: "Av", 176 | }, 177 | { 178 | id: "Elul", 179 | text: "Elul", 180 | }, 181 | ]; 182 | 183 | expect(getEngJewishMonths()).toEqual(engJewishMonth); 184 | }); 185 | 186 | it("get jewish months - hebrew, meubar", async () => { 187 | expect(getJewishMonths(5782, true)[5].text).toBe("אדר א"); 188 | }); 189 | 190 | it("get jewish months - english, meubar", async () => { 191 | expect(getJewishMonths(5784, false)[6].text).toEqual("AdarII"); 192 | }); 193 | 194 | it("get jewish months - hebrew, not meubar", async () => { 195 | expect(getJewishMonths(5781, true)[5].text).toBe("אדר"); 196 | }); 197 | 198 | it("get jewish months - english, not meubar", async () => { 199 | expect(getJewishMonths(5783, false)[5].text).toBe("Adar"); 200 | }); 201 | 202 | it("get jewish years", async () => { 203 | expect(getJewishYears(5785)[200]).toBe(5885); 204 | expect(getJewishYears(5785)[0]).toBe(5685); 205 | }); 206 | 207 | const tishriInfo: BasicJewishMonthInfo = { 208 | isHebrew: false, 209 | month: JewishMonth.Tishri, 210 | year: 5782, 211 | }; 212 | 213 | const elulInfo: BasicJewishMonthInfo = { 214 | isHebrew: false, 215 | month: JewishMonth.Elul, 216 | year: 5781, 217 | }; 218 | 219 | it("get prev month", async () => { 220 | expect(getPrevMonth(tishriInfo)).toEqual(elulInfo); 221 | }); 222 | 223 | it("get next month", async () => { 224 | expect(getNextMonth(elulInfo)).toEqual(tishriInfo); 225 | }); 226 | 227 | it("get greg date", async () => { 228 | expect(getGregDate(basicJewishDate)).toEqual(new Date(2021, 7, 21)); 229 | }); 230 | 231 | it("get jewish month info", async () => { 232 | const jewishMonthInfo = { 233 | jewishDate: { year: 5782, month: 5, day: 25, monthName: "Shevat" }, 234 | jewishMonth: 5, 235 | startOfJewishMonth: Dayjs(new Date(2022, 0, 3)), 236 | sundayStartOfTheMonth: Dayjs(new Date(2022, 0, 2)), 237 | }; 238 | expect(getJewishMonthInfo(new Date(2022, 0, 27))).toEqual(jewishMonthInfo); 239 | }); 240 | 241 | const jewishDate: JewishDate = { 242 | day: 13, 243 | monthName: "Elul", 244 | year: 5781, 245 | month: 12, 246 | }; 247 | 248 | 249 | it("get jewish date", async () => { 250 | expect(getJewishDate(new Date(2021, 7, 21))).toEqual(jewishDate); 251 | }); 252 | 253 | const jewishDate2: JewishDate = { 254 | year: 5782, 255 | month: 5, 256 | day: 25, 257 | monthName: "Shevat", 258 | }; 259 | 260 | it("Is jewish dates equal", async () => { 261 | expect(IsJewishDatesEqual(jewishDate, jewishDate)).toBeTruthy(); 262 | }); 263 | 264 | it("Is jewish dates not equal", async () => { 265 | expect(IsJewishDatesEqual(jewishDate, jewishDate2)).toBeFalsy(); 266 | }); 267 | 268 | it("get jewish day", async () => { 269 | const date = Dayjs(new Date(2022, 0, 27)); 270 | const jewishDay = { 271 | date: date.toDate(), 272 | day: 25, 273 | dayjsDate: date, 274 | isCurrentMonth: false, 275 | jewishDate: { year: 5782, month: 5, day: 25, monthName: "Shevat" }, 276 | jewishDateStr: "25 Shevat 5782", 277 | jewishDateStrHebrew: "כ״ה שבט התשפ״ב", 278 | }; 279 | 280 | expect(getJewishDay(date)).toEqual(jewishDay); 281 | }); 282 | 283 | it("get jewish month", async () => { 284 | const date = new Date(2022, 0, 27); 285 | const jewishDay = { 286 | date: date, 287 | day: 25, 288 | dayjsDate: Dayjs(date), 289 | isCurrentMonth: true, 290 | jewishDate: { year: 5782, month: 5, day: 25, monthName: "Shevat" }, 291 | jewishDateStr: "25 Shevat 5782", 292 | jewishDateStrHebrew: "כ״ה שבט התשפ״ב", 293 | }; 294 | 295 | expect(getJewishMonth(date).jewishMonth).toBe(5); 296 | expect(getJewishMonth(date).jewishYear).toBe(5782); 297 | expect(getJewishMonth(date).jewishMonthString).toBe("Shevat"); 298 | expect(getJewishMonth(date).days[25]).toEqual(jewishDay); 299 | expect(getJewishMonth(date).selectedDay).toEqual(jewishDay); 300 | }); 301 | 302 | it("get holidays of israel", async () => { 303 | const israelHolidays = [ 304 | "1 Tishri", 305 | "2 Tishri", 306 | "10 Tishri", 307 | "15 Tishri", 308 | "22 Tishri", 309 | "15 Nisan", 310 | "21 Nisan", 311 | "6 Sivan", 312 | ]; 313 | expect(getHolidays(true)).toEqual(israelHolidays); 314 | }); 315 | 316 | it("get holidays of chul", async () => { 317 | const chulHolidays = [ 318 | "1 Tishri", 319 | "2 Tishri", 320 | "10 Tishri", 321 | "15 Tishri", 322 | "22 Tishri", 323 | "15 Nisan", 324 | "21 Nisan", 325 | "6 Sivan", 326 | "16 Tishri", 327 | "23 Tishri", 328 | "16 Nisan", 329 | "22 Nisan", 330 | "7 Sivan", 331 | ]; 332 | expect(getHolidays(false)).toEqual(chulHolidays); 333 | }); 334 | 335 | const nisan_16_5782: BasicJewishDay = { 336 | date: new Date(2022, 3, 17), 337 | jewishDate: { year: 5782, month: 7, day: 16, monthName: "Nisan" }, 338 | jewishDateStr: "16 Nisan 5782", 339 | jewishDateStrHebrew: "ט״ז ניסן התשפ״ב", 340 | }; 341 | const nisan_21_5782: BasicJewishDay = { 342 | date: new Date(2022, 3, 22), 343 | jewishDate: { year: 5782, month: 7, day: 21, monthName: "Nisan" }, 344 | jewishDateStr: "21 Nisan 5782", 345 | jewishDateStrHebrew: "כ״א ניסן התשפ״ב", 346 | }; 347 | const nisan_22_5782: BasicJewishDay = { 348 | date: new Date(2022, 3, 23), 349 | jewishDate: { year: 5782, month: 7, day: 22, monthName: "Nisan" }, 350 | jewishDateStr: "22 Nisan 5782", 351 | jewishDateStrHebrew: "כ״ב ניסן התשפ״ב", 352 | }; 353 | 354 | it("dont select holidays - israel, yom tov rishon", async () => { 355 | expect(dontSelectHolidays(true)(nisan_21_5782)).toBeFalsy(); 356 | }); 357 | 358 | it("dont select holidays - israel, yom tov sheni", async () => { 359 | expect(dontSelectHolidays(true)(nisan_22_5782)).toBeTruthy(); 360 | }); 361 | 362 | it("dont select holidays - chul, yom tov sheni", async () => { 363 | expect(dontSelectHolidays(false)(nisan_22_5782)).toBeFalsy(); 364 | }); 365 | 366 | it("dont select shabat - shabat", async () => { 367 | expect(dontSelectShabat(nisan_22_5782)).toBeFalsy(); 368 | }); 369 | 370 | it("dont select shabat - not shabat", async () => { 371 | expect(dontSelectShabat(nisan_21_5782)).toBeTruthy(); 372 | }); 373 | 374 | it("dont select shabat and holidays - israel, yom tov rishon", async () => { 375 | expect(dontSelectShabatAndHolidays(true)(nisan_21_5782)).toBeFalsy(); 376 | }); 377 | 378 | it("dont select shabat and holidays - israel, shabat and yom tov sheni", async () => { 379 | expect(dontSelectShabatAndHolidays(true)(nisan_22_5782)).toBeFalsy(); 380 | }); 381 | 382 | it("dont select shabat and holidays - israel, not shabat and yom tov sheni", async () => { 383 | expect(dontSelectShabatAndHolidays(true)(nisan_16_5782)).toBeTruthy(); 384 | }); 385 | 386 | it("dont select shabat and holidays - chul, not shabat and yom tov sheni", async () => { 387 | expect(dontSelectShabatAndHolidays(false)(nisan_16_5782)).toBeFalsy(); 388 | }); 389 | 390 | it("dont select out of range - out of range", async () => { 391 | expect( 392 | dontSelectOutOfRange( 393 | new Date(2022, 3, 17), 394 | new Date(2022, 3, 22) 395 | )(nisan_22_5782) 396 | ).toBeFalsy(); 397 | }); 398 | 399 | it("dont select out of range - within range", async () => { 400 | expect( 401 | dontSelectOutOfRange( 402 | new Date(2022, 3, 17), 403 | new Date(2022, 3, 22) 404 | )(nisan_21_5782) 405 | ).toBeTruthy(); 406 | }); 407 | 408 | it("add dates on basicJewishDate", async () => { 409 | expect(addDates(basicJewishDate, 4)).toEqual(new Date(2021, 7, 25)); 410 | }); 411 | 412 | it("add dates on Date", async () => { 413 | expect(addDates(new Date(2022, 3, 17), 3)).toEqual(new Date(2022, 3, 20)); 414 | }); 415 | 416 | it("subtract dates from basicJewishDate", async () => { 417 | expect(subtractDates(basicJewishDate, 4)).toEqual(new Date(2021, 7, 17)); 418 | }); 419 | 420 | it("subtract dates from Date", async () => { 421 | expect(subtractDates(new Date(2022, 3, 17), 3)).toEqual( 422 | new Date(2022, 3, 14) 423 | ); 424 | }); 425 | }); 426 | -------------------------------------------------------------------------------- /packages/example/src/examples/examples.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { ReactJewishDatePickerExample } from "../reactJewishDatePickerExample"; 3 | import "./examples.css"; 4 | import { 5 | BasicJewishDate, 6 | BasicJewishDay, 7 | BasicJewishDateRange, 8 | DateRange, 9 | Month, 10 | } from "react-jewish-datepicker"; 11 | import { HiOutlineClipboard } from "@react-icons/all-files/hi/HiOutlineClipboard"; 12 | import { HiOutlineClipboardCheck } from "@react-icons/all-files/hi/HiOutlineClipboardCheck"; 13 | 14 | import { 15 | dontSelectHolidays, 16 | dontSelectShabat, 17 | dontSelectShabatAndHolidays, 18 | dontSelectOutOfRange, 19 | addDates, 20 | subtractDates, 21 | JewishMonth, 22 | } from "jewish-dates-core"; 23 | 24 | import { 25 | englishCode, 26 | hebrewCode, 27 | dontSelectHolidayCode, 28 | dontSelectShabatCode, 29 | dontSelectShabatAndHolidaysCode, 30 | selectionWithinRangeCode, 31 | disableWithCustomFunctionCode, 32 | rangeCode, 33 | customizeDayStyleCode, 34 | inlineVersionCode, 35 | } from "../code"; 36 | 37 | const dontSelectTuesdays = (day: BasicJewishDay): boolean => { 38 | if (day.date.getDay() === 2) { 39 | return false; 40 | } 41 | return true; 42 | }; 43 | 44 | const highlightTuesday = (day: BasicJewishDay): string => { 45 | if (day.date.getDay() === 2) { 46 | return 'tuesday'; 47 | } 48 | return ''; 49 | }; 50 | 51 | const ExampleLinkList = [ 52 | { id: "english", title: "English View" }, 53 | { id: "hebrew", title: "Hebrew View" }, 54 | { id: "disableHolidays", title: "Holidays Selection Disabled" }, 55 | { id: "disableShabat", title: "Shabat Selection Disabled" }, 56 | { id: "disableShabatAndHolidays", title: "Shabat and Holidays Selection Disabled" }, 57 | { id: "selectionWithinRange", title: "Selection Within Range" }, 58 | { id: "disableWithCustomFunction", title: "Disable Days With Custom Function" }, 59 | { id: "customizeDayStyle", title: "Customize Day Style" }, 60 | { id: "rangePicker", title: "Range datepicker" }, 61 | { id: "inlineVersion", title: "Inline Version" }, 62 | ]; 63 | 64 | export function Examples() { 65 | const date = new Date(); 66 | const [selectedDate, setSelectedDate] = React.useState< 67 | BasicJewishDate | Date 68 | >(date); 69 | // const jewishDate = toJewishDate(date); 70 | // console.log(jewishDate); 71 | 72 | const basicJewishDate: BasicJewishDate = { 73 | day: 13, 74 | monthName: "Elul", 75 | year: 5788, 76 | }; 77 | 78 | const [dateRange, setDateRange] = React.useState< 79 | BasicJewishDateRange | DateRange 80 | >({ 81 | startDate: { 82 | day: 13, 83 | monthName: "Elul", 84 | year: 5788, 85 | }, 86 | endDate: { 87 | day: 18, 88 | monthName: "Elul", 89 | year: 5788, 90 | }, 91 | }); 92 | 93 | const handleAnchorClick = (e: React.MouseEvent, id: string) => { 94 | e.preventDefault(); 95 | window.history.replaceState(null, document.title, `#${id}`); 96 | document 97 | .getElementById(id)! 98 | .scrollIntoView({ behavior: "smooth", block: "start" }); 99 | }; 100 | 101 | const excludeHolidays = dontSelectHolidays(true); 102 | const excludeShabatAndHolidays = dontSelectShabatAndHolidays(); 103 | const allowedSelectionRange = dontSelectOutOfRange( 104 | subtractDates(date, 3), 105 | addDates(date, 5) 106 | ); 107 | const [isYarnCopied, setIsYarnCopied] = React.useState(false); 108 | const [isNpmCopied, setIsNpmCopied] = React.useState(false); 109 | 110 | const copyToClipboard = (text: string, id: string) => { 111 | navigator.clipboard.writeText(text); 112 | id === "yarn" ? setIsYarnCopied(true) : setIsNpmCopied(true); 113 | setTimeout(() => { 114 | id === "yarn" ? setIsYarnCopied(false) : setIsNpmCopied(false); 115 | }, 1500); 116 | }; 117 | 118 | return ( 119 |
120 |
121 | BH 122 |

React Jewish Datepicker

123 |
124 |
125 | 126 | 127 | 131 | 132 | 133 | 134 | 138 | 139 | 140 | 144 | 145 | 146 | 150 | 151 |
152 |
153 |
154 |

Installation

155 |

Install the package via Yarn:

156 | 157 | yarn add react-jewish-datepicker 158 | 170 | 171 |

Or via npm:

172 | 173 | npm install react-jewish-datepicker --save 174 | 189 | 190 |

Import the css

191 |

Copy the import to your project:

192 | 193 | import "react-jewish-datepicker/dist/index.css"; 194 | 209 | 210 |
211 |

Examples

212 |
213 |
214 | 226 |
227 |
228 |
229 |

English View

230 | 234 | 242 | 243 | 255 | 256 |
257 |
258 |

Hebrew View

259 | 264 |
265 |
266 |

Holidays Selection Disabled

267 | 273 |
274 |
275 |

Shabat Selection Disabled

276 | 282 |
283 |
284 |

Shabat and Holidays Selection Disabled

285 | 291 |
292 |
293 |

Selection Within Range

294 | 300 |
301 |
302 |

Disable Days With Custom Function

303 | 309 |
310 |
311 |

Customize Day Style

312 | 318 |
319 |
320 |

Range Datepicker

321 | 327 | 343 | 344 | 363 | 364 |
365 |
366 |

Inline Version

367 | 373 |
374 |
375 |
376 |
377 |
378 | ); 379 | } 380 | -------------------------------------------------------------------------------- /packages/jewishDatesCore/README.md: -------------------------------------------------------------------------------- 1 | # jewish-dates-core 2 | 3 | This package is core functionality of react-jewish-datepicker 4 | 5 | If you want to create a jewish date picker in vue.js or angular, this is the core dependency. 6 | 7 | ## Installation 8 | 9 | ```console 10 | yarn add jewish-dates-core 11 | ``` 12 | 13 | Or with npm 14 | 15 | ```console 16 | npm i jewish-dates-core --save 17 | ``` 18 | 19 | ## Functions 20 | 21 |
22 |
isValidDate
23 |

Returns whether a date is a Date object

24 |
25 |
getHebWeekdays
26 |

Returns an array of week days in hebrew

27 |
28 |
getEngWeekdays
29 |

Returns an array of week days in english

30 |
31 |
getWeekdays
32 |

Returns an array of week days

33 |
34 |
getHebJewishMonths
35 |

Returns an array of jewish months in hebrew

36 |
37 |
getEngJewishMonths
38 |

Returns an array of jewish months in english

39 |
40 |
getJewishMonths
41 |

Returns an array of jewish months according to year and language

42 |
43 |
getJewishYears
44 |

Takes a number of a jewish year and returns array of 200 years around it

45 |
46 |
getPrevMonth
47 |

Takes a BasicJewishMonthInfo object and returns the equivalent of prev month

48 |
49 |
getNextMonth
50 |

Takes a BasicJewishMonthInfo object and returns the equivalent of next month

51 |
52 |
getGregDate
53 |

Converts BasicJewishDate object to gregorian date

54 |
55 |
getJewishMonthInfo
56 |

Takes a gregorian date and returns BasicJewishMonthInfo object

57 |
58 |
formatJewishDate
59 |

Takes a BasicJewishDate object and returns a string of the date in english

60 |
61 |
formatJewishDateHebrew
62 |

Takes a BasicJewishDate object and returns a string of the date in hebrew

63 |
64 |
getJewishDate
65 |

Takes a gregorian date and returns a BasicJewishDate object

66 |
67 |
IsJewishDatesEqual
68 |

Compares jewish dates returning true if the dates match and false if not

69 |
70 |
getJewishDay
71 |

Takes a dayjs date and returns a JewishDay object

72 |
73 |
getJewishMonth
74 |

Takes a gregorian date and returns a JewishMonth object

75 |
76 |
getHolidays
77 |

Returns an array of jewish holiday dates corresponding with the isIsrael param

78 |
79 |
dontSelectHolidays
80 |

Returns a function which can be passed to the `canSelect` prop, in order to prevent holidays selection

81 |
82 |
dontSelectShabat
83 |

A function to be passed to the "canSelect" prop, in order to prevent shabat selection

84 |
85 |
dontSelectShabatAndHolidays
86 |

Returns a function to be passed to the "canSelect" prop. combines "dontSelectHolidays" and "dontSelectShabat" in order to prevent both - shabat and holidays selection

87 |
88 |
dontSelectOutOfRange
89 |

Takes min date and max date and returns a function to be passed to the "canSelect" prop, in order to prevent selection out of the supplied range

90 |
91 |
addDates
92 |

Adds days to a given date

93 |
94 |
subtractDates
95 |

Subtracts days to a given date

96 |
97 |
98 | 99 | 100 | 101 | ### isValidDate(date: `Date` | `BasicJewishDate`) ⇒ `boolean` 102 | 103 | Returns whether a date is a Date object. 104 | 105 | | Param | Type | 106 | | ----- | --------------------------- | 107 | | date | `Date` \| `BasicJewishDate` | 108 | 109 | **example:** 110 | ```js 111 | const basicJewishDate: BasicJewishDate = { 112 | day: 13, 113 | monthName: "Elul", 114 | year: 5788, 115 | }; 116 | 117 | isValidDate(basicJewishDate); // ==> false 118 | isValidDate(new Date()); // ==> true 119 | ``` 120 | 121 | 122 | 123 | ### getHebWeekdays() ⇒ `string[]` 124 | 125 | Returns an array of week days in hebrew. 126 | 127 | **example:** 128 | ```js 129 | getHebWeekdays(); // ==> ["א", "ב", "ג", "ד", "ה", "ו", "ש"] 130 | ``` 131 | 132 | 133 | 134 | ### getEngWeekdays() ⇒ `string[]` 135 | 136 | Returns an array of week days in english. 137 | 138 | **example:** 139 | ```js 140 | getEngWeekdays(); // ==> ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"] 141 | ``` 142 | 143 | 144 | 145 | ### getWeekdays(isHebrew: `boolean`) ⇒ `string[]` 146 | 147 | Returns an array of week days corresponding with the isHebrew param. 148 | 149 | | Param | Type | 150 | | -------- | --------- | 151 | | isHebrew | `boolean` | 152 | 153 | **example:** 154 | ```js 155 | getWeekdays(true); // ==> ["א", "ב", "ג", "ד", "ה", "ו", "ש"] 156 | getWeekdays(false); // ==> ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"] 157 | ``` 158 | 159 | 160 | 161 | 162 | ### getHebJewishMonthById(monthId: `string`) ⇒ `string` 163 | 164 | Takes a jewish month name in english and returns the name in hebrew. 165 | 166 | | Param | Type | 167 | | ------- | -------- | 168 | | monthId | `string` | 169 | 170 | **example:** 171 | ```js 172 | getHebJewishMonthById("Tishri"); // ==> 'תשרי' 173 | ``` 174 | 175 | 176 | 177 | ### getHebJewishMonths() ⇒ `IdText[]` 178 | 179 | Returns an array of jewish months in hebrew. 180 | 181 | **example:** 182 | ```js 183 | getHebJewishMonths(); // ==> [{id: "Tishri", text: "תשרי"}, {id: "Cheshvan", text: "חשון"} ...] 184 | ``` 185 | 186 | 187 | 188 | ### getEngJewishMonths() ⇒ `IdText[]` 189 | 190 | Returns an array of jewish months in english. 191 | 192 | **example:** 193 | ```js 194 | getEngJewishMonths(); // ==> [{id: "Tishri", text: "Tishri"}, {id: "Cheshvan", text: "Cheshvan"} ...] 195 | ``` 196 | 197 | 198 | 199 | ### getJewishMonths(year: `number`, [isHebrew?: `boolean`]) ⇒ `IdText[]` 200 | 201 | Returns an array of jewish months according to year (regular/leap) and language. 202 | 203 | | Param | Type | Default | 204 | | -------- | --------- | ------- | 205 | | year | `number` | n/a | 206 | | isHebrew | `boolean` | `false` | 207 | 208 | **example:** 209 | ```js 210 | getJewishMonths(5781, true); // ==> [... {id: "AdarI", text: "אדר"}, {id: "Nisan", text: "ניסן"} ...] regular year months in henrew 211 | getJewishMonths(5782); // ==> [... {id: "AdarI", text: "AdarI"}, {id: "AdarII", text: "AdarII"} ...] leap year months in english 212 | ``` 213 | 214 | 215 | 216 | ### getJewishYears(year: `number`) ⇒ `number[]` 217 | 218 | Takes a number of a jewish year and returns array of 200 years around it. 219 | 220 | | Param | Type | 221 | | ----- | -------- | 222 | | year | `number` | 223 | 224 | **example:** 225 | ```js 226 | getJewishYears(5781); // ==> [5681, 5682, ... 5781, ... 5880, 5881] 227 | getJewishYears(5781).length; // ==> 201 228 | ``` 229 | 230 | 231 | 232 | ### getPrevMonth(basicJewishMonthInfo: `BasicJewishMonthInfo`) ⇒ `BasicJewishMonthInfo` 233 | 234 | Takes a BasicJewishMonthInfo object and returns the equivalent of prev month. 235 | 236 | | Param | Type | 237 | | -------------------- | ---------------------- | 238 | | basicJewishMonthInfo | `BasicJewishMonthInfo` | 239 | 240 | **example:** 241 | ```js 242 | const tishriInfo: BasicJewishMonthInfo = { 243 | isHebrew: false, 244 | month: "Tishri", 245 | year: 5782, 246 | }; 247 | 248 | getPrevMonth(tishriInfo); // ==> {isHebrew: false, month: 'Elul', year: 5781} 249 | ``` 250 | 251 | 252 | 253 | ### getNextMonth(basicJewishMonthInfo: `BasicJewishMonthInfo`) ⇒ `BasicJewishMonthInfo` 254 | 255 | Takes a BasicJewishMonthInfo object and returns the equivalent of next month. 256 | 257 | | Param | Type | 258 | | -------------------- | ---------------------- | 259 | | basicJewishMonthInfo | `BasicJewishMonthInfo` | 260 | 261 | **example:** 262 | ```js 263 | const elulInfo: BasicJewishMonthInfo = { 264 | isHebrew: true, 265 | month: "Elul", 266 | year: 5781, 267 | }; 268 | 269 | getNextMonth(elulInfo); // ==> {isHebrew: true, month: 'Tishri', year: 5782} 270 | ``` 271 | 272 | 273 | 274 | ### getGregDate(props: BasicJewishDate) ⇒ `Date` 275 | 276 | Converts BasicJewishDate object to gregorian date. 277 | 278 | | Param | Type | 279 | | ----- | ----------------- | 280 | | props | `BasicJewishDate` | 281 | 282 | **example:** 283 | ```js 284 | const basicJewishDate: BasicJewishDate = { 285 | day: 13, 286 | monthName: "Elul", 287 | year: 5781, 288 | }; 289 | 290 | getGregDate(basicJewishDate); // ==> Sat Aug 21 2021 00:00:00 GMT+0300 (שעון ישראל (קיץ)) 291 | ``` 292 | 293 | 294 | 295 | ### getJewishMonthInfo(date: Date) ⇒ `JewishMonthInfo` 296 | 297 | Takes a gregorian date and returns BasicJewishMonthInfo object. 298 | 299 | | Param | Type | 300 | | ----- | ------ | 301 | | date | `Date` | 302 | 303 | **example:** 304 | ```js 305 | getJewishMonthInfo(new Date(2022, 0, 27)); /* ==> { jewishDate: {year: 5782, month: 5, day: 25, monthName: 'Shevat'}, 306 | jewishMonth: 5, 307 | startOfJewishMonth: Dayjs(new Date(2022, 0, 3)), 308 | sundayStartOfTheMonth: Dayjs(new Date(2022, 0, 2))} */ 309 | ``` 310 | 311 | 312 | 313 | ### formatJewishDate(jewishDate: `JewishDate`) ⇒ `string` 314 | 315 | Takes a BasicJewishDate object and returns a string of the date in english. 316 | 317 | | Param | Type | 318 | | ---------- | ------------ | 319 | | jewishDate | `JewishDate` | 320 | 321 | **example:** 322 | ```js 323 | const jewishDate: JewishDate = { 324 | day: 13, 325 | monthName: "Elul", 326 | year: 5781, 327 | month: 13, 328 | }; 329 | 330 | formatJewishDate(jewishDate); // ==> "13 Elul 5781" 331 | ``` 332 | 333 | 334 | 335 | ### formatJewishDateHebrew(jewishDate: `JewishDate`) ⇒ `string` 336 | 337 | Takes a BasicJewishDate object and returns a string of the date in hebrew. 338 | 339 | | Param | Type | 340 | | ---------- | ------------ | 341 | | jewishDate | `JewishDate` | 342 | 343 | **example:** 344 | ```js 345 | const jewishDate: JewishDate = { 346 | day: 13, 347 | monthName: "Elul", 348 | year: 5781, 349 | month: 13, 350 | }; 351 | 352 | formatJewishDateHebrew(jewishDate); // ==> "י״ג אלול התשפ״א" 353 | ``` 354 | 355 | 356 | 357 | ### getJewishDate(date: `Date`) ⇒ `JewishDate` 358 | 359 | Takes a gregorian date and returns a BasicJewishDate object. 360 | 361 | | Param | Type | 362 | | ----- | ------ | 363 | | date | `Date` | 364 | 365 | **example:** 366 | ```js 367 | getJewishDate(new Date(2021, 7, 21)); // ==> {day: 13, monthName: "Elul", year: 5781, month: 13} 368 | ``` 369 | 370 | 371 | 372 | ### IsJewishDatesEqual(jewishDate1: `JewishDate`, jewishDate2: `JewishDate`) ⇒ `boolean` 373 | 374 | Compares jewish dates returning true if the dates match and false if not. 375 | 376 | | Param | Type | 377 | | ----------- | ------------ | 378 | | jewishDate1 | `JewishDate` | 379 | | jewishDate2 | `JewishDate` | 380 | 381 | **example:** 382 | ```js 383 | const jewishDate1: JewishDate = { 384 | day: 13, 385 | monthName: "Elul", 386 | year: 5781, 387 | month: 13, 388 | }; 389 | const jewishDate2: JewishDate = { 390 | day: 14, 391 | monthName: "Shevat", 392 | year: 5781, 393 | month: 5, 394 | }; 395 | 396 | IsJewishDatesEqual(jewishDate1, jewishDate2); // ==> false 397 | IsJewishDatesEqual(jewishDate2, jewishDate2); // ==> true 398 | ``` 399 | 400 | 401 | 402 | ### getJewishDay(dayjsDate: `Dayjs`) ⇒ `JewishDay` 403 | 404 | Takes a gregorian date and returns a JewishMonth object. 405 | 406 | | Param | Type | 407 | | --------- | ------- | 408 | | dayjsDate | `Dayjs` | 409 | 410 | **example:** 411 | ```js 412 | const date = Dayjs(new Date(2022, 0, 27)); 413 | 414 | getJewishDay(date); /* ==> { date: 2022-01-26T22:00:00.000Z, 415 | day: 25, 416 | dayjsDate: d {'$L': 'en', '$d': 2022-01-26T22:00:00.000Z, '$y': 2022, '$M': 0, '$D': 27, '$W': 4, '$H': 0, '$m': 0, '$s': 0, '$ms': 0}, 417 | isCurrentMonth: false, 418 | jewishDate: { year: 5782, month: 5, day: 25, monthName: 'Shevat' }, 419 | jewishDateStr: '25 Shevat 5782', 420 | jewishDateStrHebrew: 'כ״ה שבט התשפ״ב'} */ 421 | ``` 422 | 423 | 424 | 425 | ### getJewishMonth(date: `Date`) ⇒ `JewishMonth` 426 | 427 | Takes a gregorian date and returns a JewishMonth object. 428 | 429 | | Param | Type | 430 | | ----- | ------ | 431 | | date | `Date` | 432 | 433 | **example:** 434 | ```js 435 | getJewishMonth(new Date(2022, 0, 27)); /* ==> selectedDay: { day: 25, jewishDateStr: '25 Shevat 5782', ...}, 436 | jewishMonth: 5, 437 | jewishYear: 5782, 438 | jewishMonthString: 'Shevat', 439 | days: [{day: 29, jewishDateStr: '29 Tevet 5782', ...}, { day: 1, jewishDateStr: '1 Shevat 5782', ...}, ...] */ 440 | ``` 441 | 442 | 443 | 444 | ### getHolidays(isIsrael: `boolean`) ⇒ `string[]` 445 | 446 | Returns an array of jewish holiday dates corresponding with the isIsrael param. 447 | 448 | | Param | Type | 449 | | ----- | ------ | 450 | | isIsrael | `boolean` | 451 | 452 | **example:** 453 | ```js 454 | getHolidays(true); // ==> ['1 Tishri', '2 Tishri', '10 Tishri', '15 Tishri', '22 Tishri', '15 Nisan', '21 Nisan', '6 Sivan'] 455 | getHolidays(false); // ==> ['1 Tishri', '2 Tishri', '10 Tishri', '15 Tishri', '22 Tishri', '15 Nisan', '21 Nisan', '6 Sivan', '16 Tishri', '23 Tishri', '16 Nisan', '22 Nisan', '7 Sivan'] 456 | ``` 457 | 458 | 459 | 460 | ### dontSelectHolidays([isIsrael: `boolean`]) ⇒ `(day: BasicJewishDay) => boolean` 461 | 462 | Returns a function which can be passed to the `canSelect` prop, in order to prevent holidays (corresponding with `isIsrael` param) selection. The returned function takes a `BasicJewishDay` object, and returns `false` if it's an holiday and `true` otherwise. 463 | 464 | | Param | Type | Default | 465 | | ----- | ------ | ----- | 466 | | isIsrael | `boolean` | `false` | 467 | 468 | **example:** 469 | full example [here](https://react-jewish-datepicker.js.org/#disableHolidays) 470 | 471 | 472 | 473 | ### dontSelectShabat(day: `BasicJewishDay`) ⇒ `boolean` 474 | 475 | A function to be passed to the `canSelect` prop, in order to prevent shabat selection. Takes a `BasicJewishDay` object, and returns `false` if it's an shabat and `true` otherwise. 476 | 477 | | Param | Type | 478 | | ----- | ------ | 479 | | day | `BasicJewishDay` | 480 | 481 | **example:** 482 | full example [here](https://react-jewish-datepicker.js.org/#disableShabat) 483 | 484 | 485 | 486 | ### dontSelectShabatAndHolidays([isIsrael: `boolean`]) ⇒ `(day: BasicJewishDay) => boolean` 487 | 488 | Returns a function to be passed to the "canSelect" prop. combines `dontSelectHolidays` and `dontSelectShabat` in order to prevent both - shabat and holidays selection. The returned function takes a `BasicJewishDay` object, and returns `false` if it's an shabat or holiday and `true` otherwise. 489 | 490 | | Param | Type | Default | 491 | | ----- | ------ | ----- | 492 | | isIsrael | `boolean` | `false` | 493 | 494 | **example:** 495 | full example [here](https://react-jewish-datepicker.js.org/#disableShabatAndHolidays) 496 | 497 | 498 | 499 | ### dontSelectOutOfRange(minDate: `Date` | `null`, maxDate: `Date` | `null`) ⇒ `(day: BasicJewishDay) => boolean` 500 | 501 | Takes min date and max date and returns a function to be passed to the "canSelect" prop, in order to prevent selection out of the supplied range. The returned function takes a `BasicJewishDay` object, and returns `true` if it's within range (min date and max date included) and `false` otherwise. 502 | 503 | You can pass a date only for one of the params and null to the other. In this case, the selectable range will be up to max date or from min date. 504 | 505 | | Param | Type | 506 | | ----- | ------ | 507 | | minDate | `Date` \| `null` | 508 | | maxDate | `Date` \| `null` | 509 | 510 | **example:** 511 | full example [here](https://react-jewish-datepicker.js.org/#selectionWithinRange) 512 | 513 | 514 | 515 | ### addDates(date: `BasicJewishDate` | `Date`, numDays: `number`) ⇒ `Date` 516 | 517 | Takes a `BasicJewishDate` object or a `Date`, adds a date interval (`numDays`) to the date and then returns the new date. 518 | 519 | | Param | Type | 520 | | ----- | ------ | 521 | | date | `BasicJewishDate` \| `Date` | 522 | | numDays | `number` | 523 | 524 | **example:** 525 | ```js 526 | const date = new Date(2022, 3, 17); 527 | 528 | addDates(date, 3)) // => Wed Apr 20 2022 00:00:00 GMT+0300 (שעון ישראל (קיץ)) 529 | ``` 530 | 531 | 532 | 533 | ### subtractDates(date: `BasicJewishDate` | `Date`, numDays: `number`) ⇒ `Date` 534 | 535 | Takes a `BasicJewishDate` object or a `Date`, subtracts a date interval (`numDays`) from the date and then returns the new date. 536 | 537 | | Param | Type | 538 | | ----- | ------ | 539 | | date | `BasicJewishDate` \| `Date` | 540 | | numDays | `number` | 541 | 542 | **example:** 543 | ```js 544 | const basicJewishDate: BasicJewishDate = { 545 | day: 13, 546 | monthName: "Elul", 547 | year: 5781, 548 | }; 549 | 550 | subtractDates(basicJewishDate, 4)) // => Tue Aug 17 2021 00:00:00 GMT+0300 (שעון ישראל (קיץ)) 551 | ``` 552 | 553 | - [Shmulik Kravitz](https://github.com/Shmulik-Kravitz) 554 | - [Sagi Tawil](https://github.com/sagi770) 555 | - [Yochanan Sheinberger](https://github.com/yochanan-sheinberger) 556 | 557 | License: [MIT](https://github.com/Shmulik-Kravitz/react-jewish-datepicker/blob/master/LICENSE). 558 | --------------------------------------------------------------------------------