temporal-react-hook
Advanced tools
+6
-1
@@ -8,4 +8,9 @@ # Changelog | ||
| ## [Unreleased] | ||
| ## [1.6.15] - 2025-06-11 | ||
| ### Added | ||
| - Quarter unit support in `useTemporalStartOf` and `useTemporalEndOf` hooks. | ||
| - Updated `DemoUseTemporalStartEndOf` component to include **quarter** unit button. | ||
| ## [1.6.14] - 2025-06-10 | ||
@@ -12,0 +17,0 @@ |
@@ -1,3 +0,4 @@ | ||
| import { useState } from 'react'; | ||
| import useTemporalStartOf, { StartOfUnit } from '../../src/useTemporalStartOf'; | ||
| import {useState} from 'react'; | ||
| import './DemoCard.css'; | ||
| import useTemporalStartOf, {StartOfUnit} from '../../src/useTemporalStartOf'; | ||
| import useTemporalEndOf from '../../src/useTemporalEndOf'; | ||
@@ -7,71 +8,84 @@ import useTemporalDateTime from '../../src/useTemporalDateTime'; | ||
| export default function DemoUseTemporalStartEndOf() { | ||
| const startOf = useTemporalStartOf(); | ||
| const endOf = useTemporalEndOf(); | ||
| const currentDateTime = useTemporalDateTime(); | ||
| const [datetime, setDatetime] = useState(currentDateTime); | ||
| const [unit, setUnit] = useState<StartOfUnit>('day'); | ||
| const startOf = useTemporalStartOf(); | ||
| const endOf = useTemporalEndOf(); | ||
| const currentDateTime = useTemporalDateTime(); | ||
| const [datetime, setDatetime] = useState(currentDateTime); | ||
| const [unit, setUnit] = useState<StartOfUnit>('day'); | ||
| const startOfResult = startOf(datetime, unit); | ||
| const endOfResult = endOf(datetime, unit); | ||
| const startOfResult = startOf(datetime, unit); | ||
| const endOfResult = endOf(datetime, unit); | ||
| return ( | ||
| <section className="demo-card"> | ||
| <h3>useTemporalStartOf / useTemporalEndOf</h3> | ||
| <div className="demo-row"> | ||
| <b>Base Date:</b> <span className="demo-value">{datetime.toString()}</span> | ||
| <button className="demo-btn-margin" onClick={() => setDatetime(currentDateTime)}>Now</button> | ||
| <button className="demo-btn-margin" onClick={() => setDatetime(datetime.add({ days: 1 }))}>+1 day</button> | ||
| <button className="demo-btn-margin" onClick={() => setDatetime(datetime.subtract({ days: 1 }))}>-1 day</button> | ||
| </div> | ||
| <div className="demo-row"> | ||
| <b>Unit:</b> | ||
| {['year', 'month', 'week', 'day', 'hour', 'minute', 'second'].map(unit => ( | ||
| <button | ||
| key={unit} | ||
| className={`demo-btn-margin${unit === unit ? ' demo-btn-bold' : ''}`} | ||
| onClick={() => setUnit(unit as StartOfUnit)} | ||
| > | ||
| {unit} | ||
| </button> | ||
| ))} | ||
| </div> | ||
| <div className="demo-row"> | ||
| <b>Start of {unit}:</b> <span className="demo-value">{startOfResult.toString()}</span> | ||
| </div> | ||
| <div className="demo-row"> | ||
| <b>End of {unit}:</b> <span className="demo-value">{endOfResult.toString()}</span> | ||
| </div> | ||
| <div className="demo-info-card"> | ||
| <div className="demo-description"> | ||
| <strong>Description:</strong> | ||
| <span>Calculates the start or end of a specified unit (year, month, week, day) for a Temporal date/time object.</span> | ||
| </div> | ||
| <div className="demo-usage"> | ||
| <span> | ||
| <strong>useTemporalStartOf Syntax:</strong> useTemporalStartOf()<br/> | ||
| <strong>useTemporalEndOf Syntax:</strong> useTemporalEndOf()<br/> | ||
| <strong>Returns:</strong> Each hook returns a function that takes:<br/> | ||
| - date: Temporal date/time object<br/> | ||
| - unit: Unit for calculation ('year', 'month', 'week', 'day', 'hour', 'minute', 'second')<br/> | ||
| <strong>Example:</strong> | ||
| <code> | ||
| import { useTemporalStartOf, useTemporalEndOf, useTemporalDateTime } from 'temporal-react-hook';<br/> | ||
| <br/> | ||
| const startOf = useTemporalStartOf();<br/> | ||
| const endOf = useTemporalEndOf();<br/> | ||
| const now = useTemporalDateTime();<br/> | ||
| <br/> | ||
| // Get start of month<br/> | ||
| const startOfMonth = startOf(now, 'month');<br/> | ||
| // e.g., 2025-05-01T00:00:00<br/> | ||
| <br/> | ||
| // Get end of month<br/> | ||
| const endOfMonth = endOf(now, 'month');<br/> | ||
| // e.g., 2025-05-31T23:59:59.999999999 | ||
| </code> | ||
| </span> | ||
| </div> | ||
| </div> | ||
| </section> | ||
| ); | ||
| return ( | ||
| <section className="demo-card"> | ||
| <h3>useTemporalStartOf / useTemporalEndOf</h3> | ||
| <div className="demo-config-panel"> | ||
| <div className="demo-config-row"> | ||
| <b>Base Date:</b> | ||
| <span className="demo-value">{datetime.toString()}</span> | ||
| <button onClick={() => setDatetime(currentDateTime)}>Now</button> | ||
| <button onClick={() => setDatetime(datetime.add({days: 1}))}>+1 day</button> | ||
| <button onClick={() => setDatetime(datetime.subtract({days: 1}))}>-1 day</button> | ||
| </div> | ||
| </div> | ||
| <div className="demo-config-panel"> | ||
| <div className="demo-config-row"> | ||
| <b>Unit:</b> | ||
| <div style={{display: 'flex', gap: '0.5rem', flexWrap: 'wrap'}}> | ||
| {['second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'].map(u => ( | ||
| <button | ||
| key={u} | ||
| onClick={() => setUnit(u as StartOfUnit)} | ||
| style={{fontWeight: u === unit ? 'bold' : 'normal'}} | ||
| > | ||
| {u} | ||
| </button> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div className="demo-config-panel"> | ||
| <div className="demo-config-row"> | ||
| <b>Results:</b> | ||
| <div style={{display: 'flex', flexDirection: 'column', gap: '0.5rem'}}> | ||
| <div> | ||
| <b>Start of {unit}:</b> <span className="demo-value">{startOfResult.toString()}</span> | ||
| </div> | ||
| <div> | ||
| <b>End of {unit}:</b> <span className="demo-value">{endOfResult.toString()}</span> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div className="demo-info-card"> | ||
| <div className="demo-description"> | ||
| <strong>Description:</strong> | ||
| <span>Calculates the start or end of a specified unit for a Temporal date/time object.</span> | ||
| </div> | ||
| <div className="demo-usage"> | ||
| <strong>Example:</strong> | ||
| <code className="example-code"> | ||
| <pre style={{margin: 0}}>{`import { useTemporalStartOf, useTemporalEndOf, useTemporalDateTime } from 'temporal-react-hook'; | ||
| const startOf = useTemporalStartOf(); | ||
| const endOf = useTemporalEndOf(); | ||
| const now = useTemporalDateTime(); | ||
| // Get start of month | ||
| const startOfMonth = startOf(now, 'month'); | ||
| // e.g., 2025-05-01T00:00:00 | ||
| // Get end of month | ||
| const endOfMonth = endOf(now, 'month'); | ||
| // e.g., 2025-05-31T23:59:59.999999999 | ||
| // Get start and end of week | ||
| const startOfWeek = startOf(now, 'week'); // Monday 00:00:00 | ||
| const endOfWeek = endOf(now, 'week'); // Sunday 23:59:59.999999999`}</pre> | ||
| </code> | ||
| </div> | ||
| </div> | ||
| </section> | ||
| ); | ||
| } |
@@ -1,2 +0,2 @@ | ||
| import {useState} from "react"; | ||
| import {useState} from 'react'; | ||
| import useTemporalSubtract from "../../src/useTemporalSubtract"; | ||
@@ -3,0 +3,0 @@ import useTemporalDateTime from "../../src/useTemporalDateTime"; |
+1
-1
| { | ||
| "name": "temporal-react-hook", | ||
| "version": "1.6.14", | ||
| "version": "1.6.15", | ||
| "description": "A React library that provides hooks for handling date and time operations using the Temporal API", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -10,2 +10,3 @@ import { useCallback } from "react"; | ||
| */ | ||
| export default function useTemporalEndOf() { | ||
@@ -31,2 +32,9 @@ return useCallback((date: Temporal.PlainDateTime, unit: StartOfUnit): Temporal.PlainDateTime => { | ||
| } | ||
| case 'quarter': { | ||
| const month = date.month; | ||
| const quarterEndMonth = Math.floor((month - 1) / 3) * 3 + 3; | ||
| const endDate = date.with({ month: quarterEndMonth }); | ||
| const daysInMonth = endDate.daysInMonth; | ||
| return endDate.with({ day: daysInMonth, hour: 23, minute: 59, second: 59, millisecond: 999 }); | ||
| } | ||
| case 'year': | ||
@@ -33,0 +41,0 @@ return date.with({ month: 12, day: 31, hour: 23, minute: 59, second: 59, millisecond: 999 }); |
@@ -9,28 +9,47 @@ import { useCallback } from "react"; | ||
| */ | ||
| export type StartOfUnit = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'; | ||
| export type StartOfUnit = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'; | ||
| export default function useTemporalStartOf() { | ||
| return useCallback((date: Temporal.PlainDateTime, unit: StartOfUnit): Temporal.PlainDateTime => { | ||
| switch (unit) { | ||
| case 'second': | ||
| return date.with({ millisecond: 0 }); | ||
| case 'minute': | ||
| return date.with({ second: 0, millisecond: 0 }); | ||
| case 'hour': | ||
| return date.with({ minute: 0, second: 0, millisecond: 0 }); | ||
| case 'day': | ||
| return date.with({ hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| case 'week': { | ||
| const dayOfWeek = date.dayOfWeek || date.toPlainDate().dayOfWeek; // ISO: 1=Monday | ||
| const startOfWeek = date.subtract({ days: dayOfWeek - 1 }); | ||
| return startOfWeek.with({ hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| return useCallback( | ||
| ( | ||
| date: Temporal.PlainDateTime, | ||
| unit: StartOfUnit | ||
| ): Temporal.PlainDateTime => { | ||
| // operate directly on the provided ISO PlainDateTime | ||
| switch (unit) { | ||
| case 'second': | ||
| return date.with({ millisecond: 0 }); | ||
| case 'minute': | ||
| return date.with({ second: 0, millisecond: 0 }); | ||
| case 'hour': | ||
| return date.with({ minute: 0, second: 0, millisecond: 0 }); | ||
| case 'day': | ||
| return date.with({ hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| case 'week': { | ||
| const dayOfWeek = date.dayOfWeek || date.toPlainDate().dayOfWeek; // ISO: 1=Monday | ||
| const startOfWeek = date.subtract({ days: dayOfWeek - 1 }); | ||
| return startOfWeek.with({ hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| } | ||
| case 'month': | ||
| return date.with({ day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| case 'quarter': { | ||
| const month = date.month; | ||
| const quarterStartMonth = Math.floor((month - 1) / 3) * 3 + 1; | ||
| return date.with({ | ||
| month: quarterStartMonth, | ||
| day: 1, | ||
| hour: 0, | ||
| minute: 0, | ||
| second: 0, | ||
| millisecond: 0, | ||
| }); | ||
| } | ||
| case 'year': | ||
| return date.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| default: | ||
| return date; | ||
| } | ||
| case 'month': | ||
| return date.with({ day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| case 'year': | ||
| return date.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }); | ||
| default: | ||
| return date; | ||
| } | ||
| }, []); | ||
| }, | ||
| [] | ||
| ); | ||
| } |
368121
0.41%8619
0.4%