@purpurds/calendar 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ "moduleName": "calendar",
3
+ "exports": [
4
+ "CalendarProps",
5
+ "Calendar"
6
+ ]
7
+ };
@@ -0,0 +1 @@
1
+ .rdp-root{--rdp-accent-color: blue;--rdp-accent-background-color: #f0f0ff;--rdp-day-height: 44px;--rdp-day-width: 44px;--rdp-day_button-border-radius: 100%;--rdp-day_button-border: 2px solid transparent;--rdp-day_button-height: 42px;--rdp-day_button-width: 42px;--rdp-selected-border: 2px solid var(--rdp-accent-color);--rdp-disabled-opacity: .5;--rdp-outside-opacity: .75;--rdp-today-color: var(--rdp-accent-color);--rdp-dropdown-gap: .5rem;--rdp-months-gap: 2rem;--rdp-nav_button-disabled-opacity: .5;--rdp-nav_button-height: 2.25rem;--rdp-nav_button-width: 2.25rem;--rdp-nav-height: 2.75rem;--rdp-range_middle-background-color: var(--rdp-accent-background-color);--rdp-range_middle-color: inherit;--rdp-range_start-color: white;--rdp-range_start-background: linear-gradient(var(--rdp-gradient-direction), transparent 50%, var(--rdp-range_middle-background-color) 50%);--rdp-range_start-date-background-color: var(--rdp-accent-color);--rdp-range_end-background: linear-gradient(var(--rdp-gradient-direction), var(--rdp-range_middle-background-color) 50%, transparent 50%);--rdp-range_end-color: white;--rdp-range_end-date-background-color: var(--rdp-accent-color);--rdp-week_number-border-radius: 100%;--rdp-week_number-border: 2px solid transparent;--rdp-week_number-height: var(--rdp-day-height);--rdp-week_number-opacity: .75;--rdp-week_number-width: var(--rdp-day-width);--rdp-weeknumber-text-align: center;--rdp-weekday-opacity: .75;--rdp-weekday-padding: .5rem 0rem;--rdp-weekday-text-align: center;--rdp-gradient-direction: 90deg;--rdp-animation_duration: .3s;--rdp-animation_timing: cubic-bezier(.4, 0, .2, 1)}.rdp-root[dir=rtl]{--rdp-gradient-direction: -90deg}.rdp-root[data-broadcast-calendar=true]{--rdp-outside-opacity: unset}.rdp-root{position:relative;box-sizing:border-box}.rdp-root *{box-sizing:border-box}.rdp-day{width:var(--rdp-day-width);height:var(--rdp-day-height);text-align:center}.rdp-day_button{background:none;padding:0;margin:0;cursor:pointer;font:inherit;color:inherit;justify-content:center;align-items:center;display:flex;width:var(--rdp-day_button-width);height:var(--rdp-day_button-height);border:var(--rdp-day_button-border);border-radius:var(--rdp-day_button-border-radius)}.rdp-day_button:disabled{cursor:revert}.rdp-caption_label{z-index:1;position:relative;display:inline-flex;align-items:center;white-space:nowrap;border:0}.rdp-dropdown:focus-visible~.rdp-caption_label{outline:5px auto Highlight;outline:5px auto -webkit-focus-ring-color}.rdp-button_next,.rdp-button_previous{border:none;background:none;padding:0;margin:0;cursor:pointer;font:inherit;color:inherit;-moz-appearance:none;-webkit-appearance:none;display:inline-flex;align-items:center;justify-content:center;position:relative;appearance:none;width:var(--rdp-nav_button-width);height:var(--rdp-nav_button-height)}.rdp-button_next:disabled,.rdp-button_next[aria-disabled=true],.rdp-button_previous:disabled,.rdp-button_previous[aria-disabled=true]{cursor:revert;opacity:var(--rdp-nav_button-disabled-opacity)}.rdp-chevron{display:inline-block;fill:var(--rdp-accent-color)}.rdp-root[dir=rtl] .rdp-nav .rdp-chevron{transform:rotate(180deg);transform-origin:50%}.rdp-dropdowns{position:relative;display:inline-flex;align-items:center;gap:var(--rdp-dropdown-gap)}.rdp-dropdown{z-index:2;opacity:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;position:absolute;inset-block-start:0;inset-block-end:0;inset-inline-start:0;width:100%;margin:0;padding:0;cursor:inherit;border:none;line-height:inherit}.rdp-dropdown_root{position:relative;display:inline-flex;align-items:center}.rdp-dropdown_root[data-disabled=true] .rdp-chevron{opacity:var(--rdp-disabled-opacity)}.rdp-month_caption{display:flex;align-content:center;height:var(--rdp-nav-height);font-weight:700;font-size:large}.rdp-root[data-nav-layout=around] .rdp-month,.rdp-root[data-nav-layout=after] .rdp-month{position:relative}.rdp-root[data-nav-layout=around] .rdp-month_caption{justify-content:center;margin-inline-start:var(--rdp-nav_button-width);margin-inline-end:var(--rdp-nav_button-width);position:relative}.rdp-root[data-nav-layout=around] .rdp-button_previous{position:absolute;inset-inline-start:0;top:0;height:var(--rdp-nav-height);display:inline-flex}.rdp-root[data-nav-layout=around] .rdp-button_next{position:absolute;inset-inline-end:0;top:0;height:var(--rdp-nav-height);display:inline-flex;justify-content:center}.rdp-months{position:relative;display:flex;flex-wrap:wrap;gap:var(--rdp-months-gap);max-width:fit-content}.rdp-month_grid{border-collapse:collapse}.rdp-nav{position:absolute;inset-block-start:0;inset-inline-end:0;display:flex;align-items:center;height:var(--rdp-nav-height)}.rdp-weekday{opacity:var(--rdp-weekday-opacity);padding:var(--rdp-weekday-padding);font-weight:500;font-size:smaller;text-align:var(--rdp-weekday-text-align);text-transform:var(--rdp-weekday-text-transform)}.rdp-week_number{opacity:var(--rdp-week_number-opacity);font-weight:400;font-size:small;height:var(--rdp-week_number-height);width:var(--rdp-week_number-width);border:var(--rdp-week_number-border);border-radius:var(--rdp-week_number-border-radius);text-align:var(--rdp-weeknumber-text-align)}.rdp-today:not(.rdp-outside){color:var(--rdp-today-color)}.rdp-selected{font-weight:700;font-size:large}.rdp-selected .rdp-day_button{border:var(--rdp-selected-border)}.rdp-outside{opacity:var(--rdp-outside-opacity)}.rdp-disabled{opacity:var(--rdp-disabled-opacity)}.rdp-hidden{visibility:hidden;color:var(--rdp-range_start-color)}.rdp-range_start{background:var(--rdp-range_start-background)}.rdp-range_start .rdp-day_button{background-color:var(--rdp-range_start-date-background-color);color:var(--rdp-range_start-color)}.rdp-range_middle{background-color:var(--rdp-range_middle-background-color)}.rdp-range_middle .rdp-day_button{border-color:transparent;border:unset;border-radius:unset;color:var(--rdp-range_middle-color)}.rdp-range_end{background:var(--rdp-range_end-background);color:var(--rdp-range_end-color)}.rdp-range_end .rdp-day_button{color:var(--rdp-range_start-color);background-color:var(--rdp-range_end-date-background-color)}.rdp-range_start.rdp-range_end{background:revert}.rdp-focusable{cursor:pointer}@keyframes rdp-slide_in_left{0%{transform:translate(-100%)}to{transform:translate(0)}}@keyframes rdp-slide_in_right{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes rdp-slide_out_left{0%{transform:translate(0)}to{transform:translate(-100%)}}@keyframes rdp-slide_out_right{0%{transform:translate(0)}to{transform:translate(100%)}}.rdp-weeks_before_enter{animation:rdp-slide_in_left var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-weeks_before_exit{animation:rdp-slide_out_left var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-weeks_after_enter{animation:rdp-slide_in_right var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-weeks_after_exit{animation:rdp-slide_out_right var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-root[dir=rtl] .rdp-weeks_after_enter{animation:rdp-slide_in_left var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-root[dir=rtl] .rdp-weeks_before_exit{animation:rdp-slide_out_right var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-root[dir=rtl] .rdp-weeks_before_enter{animation:rdp-slide_in_right var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-root[dir=rtl] .rdp-weeks_after_exit{animation:rdp-slide_out_left var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}@keyframes rdp-fade_in{0%{opacity:0}to{opacity:1}}@keyframes rdp-fade_out{0%{opacity:1}to{opacity:0}}.rdp-caption_after_enter{animation:rdp-fade_in var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-caption_after_exit{animation:rdp-fade_out var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-caption_before_enter{animation:rdp-fade_in var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}.rdp-caption_before_exit{animation:rdp-fade_out var(--rdp-animation_duration) var(--rdp-animation_timing) forwards}._purpur-button_w455q_1{align-items:center;border-radius:var(--purpur-border-radius-full);border-width:0;cursor:pointer;display:inline-flex;font-size:var(--purpur-typography-scale-100);font-family:var(--purpur-typography-family-default);font-weight:var(--purpur-typography-weight-medium);gap:var(--purpur-spacing-100);justify-content:center;line-height:var(--purpur-spacing-300);outline:0;position:relative;text-decoration:none;transition:all var(--purpur-motion-duration-100) ease;width:auto}._purpur-button_w455q_1:focus:before{border-radius:var(--purpur-border-radius-full);box-shadow:0 0 0 var(--purpur-border-width-sm) var(--purpur-color-border-interactive-focus);content:"";display:block;inset:calc(var(--purpur-spacing-25) * -1);position:absolute}._purpur-button_w455q_1:focus:not(:focus-visible):before{box-shadow:none}._purpur-button_w455q_1 svg{display:block}._purpur-button--xs_w455q_33{padding:var(--purpur-spacing-50) var(--purpur-spacing-250)}._purpur-button--xs_w455q_33._purpur-button--icon-only_w455q_36{padding:var(--purpur-spacing-100)}._purpur-button--sm_w455q_39{padding:var(--purpur-spacing-100) var(--purpur-spacing-250)}._purpur-button--sm_w455q_39._purpur-button--icon-only_w455q_36{padding:var(--purpur-spacing-100)}._purpur-button--md_w455q_45{padding:var(--purpur-spacing-150) var(--purpur-spacing-300)}._purpur-button--md_w455q_45._purpur-button--icon-only_w455q_36{padding:var(--purpur-spacing-150)}._purpur-button--lg_w455q_51{padding:var(--purpur-spacing-200) var(--purpur-spacing-400)}._purpur-button--lg_w455q_51._purpur-button--icon-only_w455q_36{padding:var(--purpur-spacing-200)}._purpur-button--full-width_w455q_57{width:100%}._purpur-button--primary_w455q_60{background-color:var(--purpur-color-background-interactive-primary);color:var(--purpur-color-text-interactive-on-primary)}._purpur-button--primary_w455q_60:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-primary-hover)}._purpur-button--primary_w455q_60:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-primary-active)}._purpur-button--primary-negative_w455q_70{background-color:var(--purpur-color-background-interactive-primary-negative);color:var(--purpur-color-text-interactive-on-primary-negative)}._purpur-button--primary-negative_w455q_70:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-primary-negative-hover);border-color:var(--purpur-color-background-interactive-primary-negative-hover)}._purpur-button--primary-negative_w455q_70:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-primary-negative-active);border-color:var(--purpur-color-background-interactive-primary-negative-active)}._purpur-button--secondary_w455q_82{background-color:var(--purpur-color-background-interactive-transparent);box-shadow:inset 0 0 0 var(--purpur-border-width-xs) var(--purpur-color-border-interactive-primary);color:var(--purpur-color-text-interactive-primary)}._purpur-button--secondary_w455q_82:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-hover)}._purpur-button--secondary_w455q_82:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-active)}._purpur-button--secondary-negative_w455q_93{background-color:var(--purpur-color-background-interactive-transparent);box-shadow:inset 0 0 0 var(--purpur-border-width-xs) var(--purpur-color-border-interactive-primary-negative);color:var(--purpur-color-text-interactive-primary-negative)}._purpur-button--secondary-negative_w455q_93:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-negative-hover)}._purpur-button--secondary-negative_w455q_93:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-negative-active)}._purpur-button--expressive_w455q_104{background-color:var(--purpur-color-background-interactive-expressive);color:var(--purpur-color-text-interactive-on-expressive)}._purpur-button--expressive_w455q_104:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-expressive-hover)}._purpur-button--expressive_w455q_104:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-expressive-active)}._purpur-button--expressive-negative_w455q_114{background-color:var(--purpur-color-background-interactive-expressive-negative);color:var(--purpur-color-text-interactive-on-expressive-negative)}._purpur-button--expressive-negative_w455q_114:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-expressive-negative-hover);color:var(--purpur-color-text-interactive-on-expressive-negative-hover)}._purpur-button--expressive-negative_w455q_114:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-expressive-negative-active);color:var(--purpur-color-text-interactive-on-expressive-negative-active)}._purpur-button--negative_w455q_126._purpur-button--disabled_w455q_64{background-color:var(--purpur-color-background-interactive-disabled-negative);color:var(--purpur-color-text-weak-negative)}._purpur-button--secondary_w455q_82._purpur-button--disabled_w455q_64,._purpur-button--secondary-negative_w455q_93._purpur-button--disabled_w455q_64{box-shadow:none}._purpur-button--destructive_w455q_133{background-color:var(--purpur-color-background-interactive-destructive);color:var(--purpur-color-text-interactive-on-destructive)}._purpur-button--destructive_w455q_133:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-destructive-hover)}._purpur-button--destructive_w455q_133:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-destructive-active)}._purpur-button--destructive-negative_w455q_143{background-color:var(--purpur-color-background-interactive-destructive);color:var(--purpur-color-text-interactive-on-destructive)}._purpur-button--destructive-negative_w455q_143:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-destructive-hover)}._purpur-button--destructive-negative_w455q_143:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-destructive-active)}._purpur-button--tertiary-purple_w455q_153{background-color:var(--purpur-color-background-interactive-transparent);color:var(--purpur-color-text-interactive-primary)}._purpur-button--tertiary-purple_w455q_153._purpur-button--disabled_w455q_64{background-color:var(--purpur-color-background-interactive-transparent)}._purpur-button--tertiary-purple_w455q_153:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-hover)}._purpur-button--tertiary-purple_w455q_153:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-active)}._purpur-button--tertiary-purple-negative_w455q_166{background-color:var(--purpur-color-background-interactive-transparent);color:var(--purpur-color-text-interactive-primary-negative)}._purpur-button--tertiary-purple-negative_w455q_166._purpur-button--disabled_w455q_64{background-color:var(--purpur-color-background-interactive-transparent)}._purpur-button--tertiary-purple-negative_w455q_166:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-negative-hover);color:var(--purpur-color-text-interactive-primary-negative-hover)}._purpur-button--tertiary-purple-negative_w455q_166:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-negative-active);color:var(--purpur-color-text-interactive-primary-negative-active)}._purpur-button--text-negative_w455q_181{border-radius:0;padding-left:0;padding-right:0}._purpur-button--text-negative_w455q_181:focus-visible:before{border-radius:0}._purpur-button--text-negative_w455q_181{background-color:var(--purpur-color-background-interactive-transparent);color:var(--purpur-color-text-interactive-primary-negative)}._purpur-button--text-negative_w455q_181._purpur-button--disabled_w455q_64{background-color:var(--purpur-color-background-interactive-transparent)}._purpur-button--text-negative_w455q_181:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-negative-hover);color:var(--purpur-color-text-interactive-primary-negative-hover)}._purpur-button--text-negative_w455q_181:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-negative-active);color:var(--purpur-color-text-interactive-primary-negative-active)}._purpur-button--text_w455q_181{border-radius:0;padding-left:0;padding-right:0}._purpur-button--text_w455q_181:focus-visible:before{border-radius:0}._purpur-button--text_w455q_181{background-color:var(--purpur-color-background-interactive-transparent);color:var(--purpur-color-text-interactive-primary)}._purpur-button--text_w455q_181._purpur-button--disabled_w455q_64{background-color:var(--purpur-color-background-interactive-transparent);color:var(--purpur-color-text-weak)}._purpur-button--text_w455q_181:hover:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-hover)}._purpur-button--text_w455q_181:active:not(._purpur-button--disabled_w455q_64){background-color:var(--purpur-color-background-interactive-transparent-active)}._purpur-button--disabled_w455q_64{background-color:var(--purpur-color-background-interactive-disabled);color:var(--purpur-color-text-weak);cursor:not-allowed}._purpur-icon_8u1lq_1{display:inline-block}._purpur-icon--xxs_8u1lq_4{width:var(--purpur-spacing-150);height:var(--purpur-spacing-150)}._purpur-icon--xs_8u1lq_8{width:var(--purpur-spacing-200);height:var(--purpur-spacing-200)}._purpur-icon--sm_8u1lq_12{width:var(--purpur-spacing-250);height:var(--purpur-spacing-250)}._purpur-icon--md_8u1lq_16{width:var(--purpur-spacing-300);height:var(--purpur-spacing-300)}._purpur-icon--lg_8u1lq_20{width:var(--purpur-spacing-400);height:var(--purpur-spacing-400)}._purpur-icon--xl_8u1lq_24{width:var(--purpur-spacing-600);height:var(--purpur-spacing-600)}._root_11ee2_3{--rdp-accent-color: var(--purpur-color-text-interactive-primary);--rdp-accent-background-color: var(--purpur-color-background-interactive-primary);--rdp-day-height: var(--purpur-spacing-400);--rdp-day-width: calc(var(--purpur-spacing-400) + var(--purpur-spacing-100));--rdp-day_button-border-radius: 100%;--rdp-day_button-border: none;--rdp-day_button-height: var(--purpur-spacing-400);--rdp-day_button-width: var(--purpur-spacing-400);--rdp-selected-border: var(--purpur-spacing-25) solid var(--rdp-accent-color);--rdp-disabled-opacity: 1;--rdp-outside-opacity: 1;--rdp-today-color: var(--rdp-accent-color);--rdp-dropdown-gap: var(--purpur-spacing-100);--rdp-months-gap: var(purpur-spacing-400);--rdp-nav_button-disabled-opacity: 1;--rdp-nav_button-height: calc(var(---purpur-spacing-50) + var(--purpur-spacing-400));--rdp-nav_button-width: calc(var(---purpur-spacing-50) + var(--purpur-spacing-400));--rdp-nav-height: calc(var(---purpur-spacing-150) + var(--purpur-spacing-400));--rdp-range_middle-background-color: var(--purpur-color-background-interactive-transparent-active);--rdp-range_middle-color: inherit;--rdp-range_start-color: white;--rdp-range_start-background: linear-gradient(var(--rdp-gradient-direction), transparent 50%, var(--rdp-range_middle-background-color) 50%);--rdp-range_start-date-background-color: var(--purpur-color-background-interactive-transparent-active);--rdp-range_end-background: linear-gradient(var(--rdp-gradient-direction), var(--rdp-range_middle-background-color) 50%, transparent 50%);--rdp-range_end-color: white;--rdp-range_end-date-background-color: var(--purpur-color-background-interactive-transparent-active);--rdp-week_number-border-radius: 100%;--rdp-week_number-border: var(--purpur-spacing-25) solid transparent;--rdp-week_number-height: var(--rdp-day-height);--rdp-week_number-opacity: 1;--rdp-week_number-width: var(--rdp-day-width);--rdp-weeknumber-text-align: center;--rdp-weekday-opacity: 1;--rdp-weekday-padding: var(--purpur-spacing-100) 0;--rdp-weekday-text-align: center;--rdp-gradient-direction: 90deg;--rdp-animation_duration: .3s;--rdp-animation_timing: cubic-bezier(.4, 0, .2, 1);min-width:fit-content}._root_11ee2_3 *:focus-visible{outline-color:var(--purpur-color-border-interactive-focus)}._root_11ee2_3 table{width:100%;border-collapse:separate;border-spacing:0 var(--purpur-spacing-100)}._months_11ee2_88{max-width:none}._month_11ee2_88{width:100%}._day_button_11ee2_96{margin:0 auto;font-weight:var(--purpur-typography-weight-medium)}._day_11ee2_96{color:var(--rdp-accent-color);padding:0}._day_11ee2_96:hover:not(._selected_11ee2_105) ._day_button_11ee2_96{background-color:var(--purpur-color-background-interactive-transparent-hover);color:var(--purpur-color-text-interactive-primary-active);border-radius:50%}._month_caption_11ee2_111{height:calc(var(--purpur-spacing-400) + var(--purpur-spacing-50));color:var(--purpur-color-text-default);padding-left:var(--purpur-spacing-100);font-size:var(--purpur-typography-scale-150);font-family:var(--purpur-typography-family-default);font-weight:var(--purpur-typography-weight-medium)}._dropdown_root_11ee2_120{color:var(--rdp-accent-color)}._weekday_11ee2_124,._week_number_11ee2_125{color:var(--purpur-color-text-medium);text-transform:uppercase}._selected_11ee2_105 ._day_button_11ee2_96{color:var(--purpur-color-text-interactive-on-primary);background-color:var(--purpur-color-background-interactive-primary);border-radius:100%}._selected_11ee2_105._range_middle_11ee2_135{background-color:var(--purpur-color-background-interactive-transparent-active)}._selected_11ee2_105._range_middle_11ee2_135 ._day_button_11ee2_96{background-color:transparent;color:var(--purpur-color-text-interactive-primary-active);border-radius:0}._disabled_11ee2_144{color:var(--purpur-color-text-weak);text-decoration:line-through solid var(--purpur-color-text-weak);opacity:100%}._disabled_11ee2_144 ._day_button_11ee2_96{font-weight:var(--purpur-typography-weight-normal)}._outside_11ee2_153{color:var(--purpur-color-text-weak);opacity:100%}._outside_11ee2_153 ._day_button_11ee2_96{font-weight:var(--purpur-typography-weight-normal)}._button_next_11ee2_161,._button_previous_11ee2_162{z-index:2;border-radius:var(--purpur-border-radius-full)!important}._button_next_11ee2_161:before,._button_previous_11ee2_162:before{border-radius:var(--purpur-border-radius-full)!important}
@@ -0,0 +1,2 @@
1
+ import purpurCommon from "@purpurds/component-rig/eslint.config.mjs";
2
+ export default purpurCommon;
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@purpurds/calendar",
3
+ "version": "0.0.1",
4
+ "license": "AGPL-3.0-only",
5
+ "main": "./dist/calendar.cjs.js",
6
+ "types": "./dist/calendar.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "require": "./dist/calendar.cjs.js",
10
+ "types": "./dist/calendar.d.ts",
11
+ "default": "./dist/calendar.es.js"
12
+ },
13
+ "./styles": "./dist/styles.css",
14
+ "./metadata": "./dist/metadata.js"
15
+ },
16
+ "source": "src/calendar.tsx",
17
+ "dependencies": {
18
+ "classnames": "~2.5.0",
19
+ "react-day-picker": "~9.8.1",
20
+ "@purpurds/tokens": "7.7.0",
21
+ "@purpurds/icon": "7.7.0",
22
+ "@purpurds/button": "7.7.0"
23
+ },
24
+ "devDependencies": {
25
+ "eslint": "9.24.0",
26
+ "@storybook/react-vite": "^9.0.18",
27
+ "@testing-library/dom": "~10.4.0",
28
+ "@testing-library/jest-dom": "~6.4.0",
29
+ "@testing-library/react": "~16.2.0",
30
+ "@testing-library/user-event": "~14.5.1",
31
+ "@types/node": "20.12.12",
32
+ "@types/react-dom": "^19.0.4",
33
+ "@types/react": "^19.0.10",
34
+ "jsdom": "~22.1.0",
35
+ "lint-staged": "15.5.0",
36
+ "prettier": "~2.8.8",
37
+ "react-dom": "^19.0.0",
38
+ "react": "^19.0.0",
39
+ "storybook": "^9.0.18",
40
+ "typescript": "^5.6.3",
41
+ "vite": "^6.2.1",
42
+ "vitest": "^3.1.2",
43
+ "@purpurds/component-rig": "1.0.0"
44
+ },
45
+ "peerDependencies": {
46
+ "@types/react": "^18 || ^19",
47
+ "@types/react-dom": "^18 || ^19",
48
+ "react": "^18 || ^19",
49
+ "react-dom": "^18 || ^19"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "@types/react": {
53
+ "optional": true
54
+ },
55
+ "@types/react-dom": {
56
+ "optional": true
57
+ }
58
+ },
59
+ "scripts": {
60
+ "build:dev": "vite",
61
+ "build:watch": "vite build --watch",
62
+ "build": "vite build",
63
+ "ci:build": "rushx build",
64
+ "coverage": "vitest run --coverage",
65
+ "lint:fix": "eslint . --fix",
66
+ "lint": "lint-staged --no-stash 2>&1",
67
+ "sbdev": "rush sbdev",
68
+ "test:unit": "vitest run --passWithNoTests",
69
+ "test:watch": "vitest --watch",
70
+ "test": "rushx test:unit",
71
+ "typecheck": "tsc -p ./tsconfig.json"
72
+ }
73
+ }
@@ -0,0 +1,195 @@
1
+ /* Variables declaration */
2
+ /* prettier-ignore */
3
+ .root {
4
+ --rdp-accent-color: var(--purpur-color-text-interactive-primary);
5
+ /* The accent color used for selected days and UI elements. */
6
+ --rdp-accent-background-color: var(--purpur-color-background-interactive-primary);
7
+ /* The accent background color used for selected days and UI elements. */
8
+
9
+ --rdp-day-height: var(--purpur-spacing-400);
10
+ /* The height of the day cells. */
11
+ --rdp-day-width: calc(var(--purpur-spacing-400) + var(--purpur-spacing-100));
12
+ /* The width of the day cells. */
13
+
14
+ --rdp-day_button-border-radius: 100%;
15
+ /* The border radius of the day cells. */
16
+ --rdp-day_button-border: none;
17
+ /* The border of the day cells. */
18
+ --rdp-day_button-height: var(--purpur-spacing-400);
19
+ /* The height of the day cells. */
20
+ --rdp-day_button-width: var(--purpur-spacing-400);
21
+ /* The width of the day cells. */
22
+
23
+ --rdp-selected-border: var(--purpur-spacing-25) solid var(--rdp-accent-color);
24
+ /* The border of the selected days. */
25
+ --rdp-disabled-opacity: 1;
26
+ /* The opacity of the disabled days. */
27
+ --rdp-outside-opacity: 1;
28
+ /* The opacity of the days outside the current month. */
29
+ --rdp-today-color: var(--rdp-accent-color);
30
+ /* The color of the today's date. */
31
+
32
+ --rdp-dropdown-gap: var(--purpur-spacing-100);
33
+ /* The gap between the dropdowns used in the month captons. */
34
+
35
+ --rdp-months-gap: var(purpur-spacing-400);
36
+ /* The gap between the months in the multi-month view. */
37
+
38
+ --rdp-nav_button-disabled-opacity: 1;
39
+ /* The opacity of the disabled navigation buttons. */
40
+ --rdp-nav_button-height: calc(var(---purpur-spacing-50) + var(--purpur-spacing-400));
41
+ /* The height of the navigation buttons. */
42
+ --rdp-nav_button-width: calc(var(---purpur-spacing-50) + var(--purpur-spacing-400));
43
+ /* The width of the navigation buttons. */
44
+ --rdp-nav-height: calc(var(---purpur-spacing-150) + var(--purpur-spacing-400));
45
+ /* The height of the navigation bar. */
46
+
47
+ --rdp-range_middle-background-color: var(--purpur-color-background-interactive-transparent-active);
48
+ /* The color of the background for days in the middle of a range. */
49
+ --rdp-range_middle-color: inherit;
50
+ /* The color of the range text. */
51
+
52
+ --rdp-range_start-color: white;
53
+ /* The color of the range text. */
54
+ --rdp-range_start-background: linear-gradient(var(--rdp-gradient-direction), transparent 50%, var(--rdp-range_middle-background-color) 50%);
55
+ /* Used for the background of the start of the selected range. */
56
+ --rdp-range_start-date-background-color: var(--purpur-color-background-interactive-transparent-active);
57
+ /* The background color of the date when at the start of the selected range. */
58
+
59
+ --rdp-range_end-background: linear-gradient(var(--rdp-gradient-direction), var(--rdp-range_middle-background-color) 50%, transparent 50%);
60
+ /* Used for the background of the end of the selected range. */
61
+ --rdp-range_end-color: white;
62
+ /* The color of the range text. */
63
+ --rdp-range_end-date-background-color: var(--purpur-color-background-interactive-transparent-active);
64
+ /* The background color of the date when at the end of the selected range. */
65
+
66
+ --rdp-week_number-border-radius: 100%;
67
+ /* The border radius of the week number. */
68
+ --rdp-week_number-border: var(--purpur-spacing-25) solid transparent;
69
+ /* The border of the week number. */
70
+
71
+ --rdp-week_number-height: var(--rdp-day-height);
72
+ /* The height of the week number cells. */
73
+ --rdp-week_number-opacity: 1;
74
+ /* The opacity of the week number. */
75
+ --rdp-week_number-width: var(--rdp-day-width);
76
+ /* The width of the week number cells. */
77
+ --rdp-weeknumber-text-align: center;
78
+ /* The text alignment of the weekday cells. */
79
+
80
+ --rdp-weekday-opacity: 1;
81
+ /* The opacity of the weekday. */
82
+ --rdp-weekday-padding: var(--purpur-spacing-100) 0;
83
+ /* The padding of the weekday. */
84
+ --rdp-weekday-text-align: center;
85
+ /* The text alignment of the weekday cells. */
86
+
87
+ --rdp-gradient-direction: 90deg;
88
+
89
+ --rdp-animation_duration: 0.3s;
90
+ --rdp-animation_timing: cubic-bezier(0.4, 0, 0.2, 1);
91
+
92
+ min-width: fit-content;
93
+
94
+ *:focus-visible {
95
+ outline-color: var(--purpur-color-border-interactive-focus);
96
+ }
97
+
98
+ table {
99
+ width: 100%;
100
+ border-collapse: separate;
101
+ border-spacing: 0 var(--purpur-spacing-100);
102
+ }
103
+ }
104
+
105
+ .months {
106
+ max-width: none;
107
+ }
108
+
109
+ .month {
110
+ width: 100%;
111
+ }
112
+
113
+ .day_button {
114
+ margin: 0 auto;
115
+ font-weight: var(--purpur-typography-weight-medium);
116
+ }
117
+
118
+ .day {
119
+ color: var(--rdp-accent-color);
120
+ padding: 0;
121
+
122
+ &:hover:not(.selected) {
123
+ .day_button {
124
+ background-color: var(--purpur-color-background-interactive-transparent-hover);
125
+ color: var(--purpur-color-text-interactive-primary-active);
126
+ border-radius: 50%;
127
+ }
128
+ }
129
+ }
130
+
131
+ .month_caption {
132
+ height: calc(var(--purpur-spacing-400) + var(--purpur-spacing-50));
133
+ color: var(--purpur-color-text-default);
134
+ padding-left: var(--purpur-spacing-100);
135
+ font-size: var(--purpur-typography-scale-150);
136
+ font-family: var(--purpur-typography-family-default);
137
+ font-weight: var(--purpur-typography-weight-medium);
138
+ }
139
+
140
+ .dropdown_root {
141
+ color: var(--rdp-accent-color);
142
+ }
143
+
144
+ .weekday,
145
+ .week_number {
146
+ color: var(--purpur-color-text-medium);
147
+ text-transform: uppercase;
148
+ }
149
+
150
+ .selected {
151
+ .day_button {
152
+ color: var(--purpur-color-text-interactive-on-primary);
153
+ background-color: var(--purpur-color-background-interactive-primary);
154
+ border-radius: 100%;
155
+ }
156
+
157
+ &.range_middle {
158
+ background-color: var(--purpur-color-background-interactive-transparent-active);
159
+
160
+ .day_button {
161
+ background-color: transparent;
162
+ color: var(--purpur-color-text-interactive-primary-active);
163
+ border-radius: 0;
164
+ }
165
+ }
166
+ }
167
+
168
+ .disabled {
169
+ color: var(--purpur-color-text-weak);
170
+ text-decoration: line-through solid var(--purpur-color-text-weak);
171
+ opacity: 100%;
172
+
173
+ .day_button {
174
+ font-weight: var(--purpur-typography-weight-normal);
175
+ }
176
+ }
177
+
178
+ .outside {
179
+ color: var(--purpur-color-text-weak);
180
+ opacity: 100%;
181
+
182
+ .day_button {
183
+ font-weight: var(--purpur-typography-weight-normal);
184
+ }
185
+ }
186
+
187
+ .button_next,
188
+ .button_previous {
189
+ z-index: 2;
190
+ border-radius: var(--purpur-border-radius-full) !important;
191
+
192
+ &::before {
193
+ border-radius: var(--purpur-border-radius-full) !important;
194
+ }
195
+ }
@@ -0,0 +1,101 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks */
2
+
3
+ import React, { useState } from "react";
4
+ import type { Meta, StoryObj } from "@storybook/react";
5
+
6
+ import { Calendar, et } from "./calendar";
7
+
8
+ const meta = {
9
+ title: "Forms and Inputs/Calendar",
10
+ component: Calendar,
11
+ parameters: {
12
+ design: [
13
+ {
14
+ name: "Calendar",
15
+ type: "figma",
16
+ url: "https://www.figma.com/design/XEaIIFskrrxIBHMZDkIuIg/Purpur-DS---Component-library---guidelines?node-id=39042-5999&p=f&t=5D0qSGRGqXJgdAxm-0",
17
+ },
18
+ ],
19
+ },
20
+ args: {
21
+ mode: "single",
22
+ showWeekNumber: false,
23
+ showOutsideDays: false,
24
+ disabled: [],
25
+ },
26
+ argTypes: {
27
+ mode: {
28
+ control: { type: "radio" },
29
+ options: ["single", "range"],
30
+ },
31
+ },
32
+ decorators: (Story) => (
33
+ <div style={{ width: "20rem" }}>
34
+ <Story />
35
+ </div>
36
+ ),
37
+ } satisfies Meta<typeof Calendar>;
38
+
39
+ export default meta;
40
+ type Story = StoryObj<typeof Calendar>;
41
+
42
+ export const Showcase: Story = {
43
+ args: {
44
+ mode: "single",
45
+ disabled: [{ dayOfWeek: [0, 6] }],
46
+ showWeekNumber: true,
47
+ showOutsideDays: true,
48
+ },
49
+ };
50
+
51
+ export const Controlled: Story = {
52
+ render: (args) => {
53
+ const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date());
54
+
55
+ const handleDateSelect = (date: Date | undefined) => {
56
+ setSelectedDate(date);
57
+ };
58
+
59
+ return (
60
+ <div>
61
+ <div style={{ display: "flex", gap: "10px", marginBottom: "10px" }}>
62
+ <button
63
+ onClick={() => {
64
+ handleDateSelect(new Date());
65
+ }}
66
+ >
67
+ Select today
68
+ </button>
69
+ <button
70
+ onClick={() => {
71
+ handleDateSelect(new Date(Date.now() - 24 * 60 * 60 * 1000));
72
+ }}
73
+ >
74
+ Select yesterday
75
+ </button>
76
+ <button
77
+ onClick={() => {
78
+ handleDateSelect(new Date(Date.now() + 24 * 60 * 60 * 1000));
79
+ }}
80
+ >
81
+ Select tomorrow
82
+ </button>
83
+ </div>
84
+ <Calendar
85
+ {...args}
86
+ locale={et}
87
+ mode="single"
88
+ selected={selectedDate}
89
+ onSelect={(date: Date | undefined) => {
90
+ handleDateSelect(date);
91
+ }}
92
+ />
93
+ <p>Selected date: {selectedDate ? selectedDate.toLocaleDateString() : "None"}</p>
94
+ </div>
95
+ );
96
+ },
97
+ };
98
+
99
+ export const Range: Story = {
100
+ args: { mode: "range", numberOfMonths: 2 },
101
+ };
@@ -0,0 +1,89 @@
1
+ import React from "react";
2
+ import * as matchers from "@testing-library/jest-dom/matchers";
3
+ import { cleanup, fireEvent, render, screen } from "@testing-library/react";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+
6
+ import { Calendar } from "./calendar";
7
+
8
+ expect.extend(matchers);
9
+
10
+ describe("Calendar", () => {
11
+ afterEach(() => {
12
+ cleanup();
13
+ });
14
+
15
+ it("renders without crashing in single mode", () => {
16
+ render(
17
+ <Calendar mode="single" selected={undefined} onSelect={() => {}} data-testid="calendar" />
18
+ );
19
+ expect(screen.getByTestId("calendar")).toBeInTheDocument();
20
+ });
21
+
22
+ it("renders without crashing in range mode", () => {
23
+ render(
24
+ <Calendar mode="range" selected={undefined} onSelect={() => {}} data-testid="calendar" />
25
+ );
26
+ expect(screen.getByTestId("calendar")).toBeInTheDocument();
27
+ });
28
+
29
+ it("calls onSelect when a day is clicked in single mode", () => {
30
+ const handleSelect = vi.fn();
31
+ render(
32
+ <Calendar mode="single" selected={undefined} onSelect={handleSelect} data-testid="calendar" />
33
+ );
34
+ // Find a day button and click it
35
+ const dayButton = screen.getAllByRole("button", { name: /\d+/ })[0];
36
+ fireEvent.click(dayButton);
37
+ expect(handleSelect).toHaveBeenCalled();
38
+ });
39
+
40
+ it("calls onSelect when a day is clicked in range mode", () => {
41
+ const handleSelect = vi.fn();
42
+ render(
43
+ <Calendar mode="range" selected={undefined} onSelect={handleSelect} data-testid="calendar" />
44
+ );
45
+ // Find a day button and click it
46
+ const dayButton = screen.getAllByRole("button", { name: /\d+/ })[0];
47
+ fireEvent.click(dayButton);
48
+ expect(handleSelect).toHaveBeenCalled();
49
+ });
50
+
51
+ it("shows the selected day in single mode", () => {
52
+ const selectedDate = new Date();
53
+ render(
54
+ <Calendar mode="single" selected={selectedDate} onSelect={() => {}} data-testid="calendar" />
55
+ );
56
+ // The selected day should have aria-pressed="true"
57
+ const selectedButton = screen
58
+ .getAllByRole("button")
59
+ .find((btn) => btn.getAttribute("tabIndex") === "0");
60
+ expect(selectedButton).toBeDefined();
61
+ expect(selectedButton).toHaveTextContent(String(selectedDate.getDate()));
62
+ expect(selectedButton).toHaveAttribute("aria-label", expect.stringContaining("selected"));
63
+ });
64
+
65
+ it("applies custom data-testid", () => {
66
+ render(
67
+ <Calendar
68
+ mode="single"
69
+ selected={undefined}
70
+ onSelect={() => {}}
71
+ data-testid="custom-calendar"
72
+ />
73
+ );
74
+ expect(screen.getByTestId("custom-calendar")).toBeInTheDocument();
75
+ });
76
+
77
+ it("applies custom class names", () => {
78
+ render(
79
+ <Calendar
80
+ mode="single"
81
+ selected={undefined}
82
+ onSelect={() => {}}
83
+ data-testid="custom-calendar"
84
+ className="custom-calendar-class"
85
+ />
86
+ );
87
+ expect(screen.getByTestId("custom-calendar")).toHaveClass("custom-calendar-class");
88
+ });
89
+ });
@@ -0,0 +1,112 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import {
3
+ type DateRange,
4
+ DayPicker,
5
+ type DayPickerProps,
6
+ getDefaultClassNames,
7
+ } from "react-day-picker";
8
+ import { Button } from "@purpurds/button";
9
+ import { IconChevronLeft } from "@purpurds/icon/chevron-left";
10
+ import { IconChevronRight } from "@purpurds/icon/chevron-right";
11
+
12
+ export * from "react-day-picker/locale";
13
+
14
+ import "react-day-picker/style.css";
15
+ import "@purpurds/button/styles";
16
+ import "@purpurds/icon/styles";
17
+ import styles from "./calendar.module.scss";
18
+
19
+ type CalendarModeProps =
20
+ | {
21
+ mode: "single";
22
+ selected: Date | undefined;
23
+ onSelect: (date: Date | undefined) => void;
24
+ }
25
+ | {
26
+ mode: "range";
27
+ selected: DateRange | undefined;
28
+ onSelect: (dateRange: DateRange | undefined) => void;
29
+ };
30
+
31
+ export type CalendarProps = Omit<DayPickerProps, "mode" | "selected" | "onSelect"> &
32
+ CalendarModeProps & {
33
+ ["data-testid"]?: string;
34
+ };
35
+
36
+ /**
37
+ * Calendar component that wraps the DayPicker from react-day-picker.
38
+ * You can use react-day-picker's props to customize the calendar.
39
+ * https://daypicker.dev/api
40
+ *
41
+ * Year range is set to 20 years (10 years before today, and 10 years after today).
42
+ * This can be customized using the `startMonth` and `endMonth` props.
43
+ */
44
+ export const Calendar = (props: CalendarProps) => {
45
+ const defaultClassNames = getDefaultClassNames();
46
+
47
+ const calendarClassnames = {
48
+ ...styles,
49
+ root: `${defaultClassNames.root} ${styles.root}`,
50
+ day_button: `${defaultClassNames.day_button} ${styles.day_button}`,
51
+ day: `${defaultClassNames.day} ${styles.day}`,
52
+ weekday: `${defaultClassNames.weekday} ${styles.weekday}`,
53
+ week_number: `${defaultClassNames.week_number} ${styles.week_number}`,
54
+ month_caption: `${defaultClassNames.month_caption} ${styles.month_caption}`,
55
+ disabled: `${defaultClassNames.disabled} ${styles.disabled}`,
56
+ dropdown: `${defaultClassNames.dropdown} ${styles.dropdown}`,
57
+ years_dropdown: `${defaultClassNames.years_dropdown} ${styles.years_dropdown}`,
58
+ outside: `${defaultClassNames.outside} ${styles.outside}`,
59
+ dropdown_root: `${defaultClassNames.dropdown_root} ${styles.dropdown_root}`,
60
+ months: `${defaultClassNames.months} ${styles.months}`,
61
+ month: `${defaultClassNames.month} ${styles.month}`,
62
+ button_next: `${defaultClassNames.button_next} ${styles.button_next}`,
63
+ button_previous: `${defaultClassNames.button_previous} ${styles.button_previous}`,
64
+ };
65
+
66
+ const yearsBack = new Date().getFullYear() - 10;
67
+ const yearsForward = new Date().getFullYear() + 10;
68
+
69
+ const [month, setMonth] = useState<Date | undefined>();
70
+
71
+ useEffect(() => {
72
+ if (props.mode === "single" && props.selected instanceof Date) {
73
+ setMonth(props.selected);
74
+ } else if (
75
+ props.mode === "range" &&
76
+ props.selected &&
77
+ typeof props.selected === "object" &&
78
+ "from" in props.selected &&
79
+ props.selected.from instanceof Date
80
+ ) {
81
+ setMonth(props.selected.from);
82
+ }
83
+ }, [props.selected, props.mode]);
84
+
85
+ return (
86
+ <DayPicker
87
+ weekStartsOn={1}
88
+ captionLayout="dropdown-years"
89
+ startMonth={new Date(yearsBack, 0)}
90
+ endMonth={new Date(yearsForward, 11)}
91
+ {...props}
92
+ month={month}
93
+ onMonthChange={setMonth}
94
+ classNames={calendarClassnames}
95
+ navLayout="around"
96
+ components={{
97
+ PreviousMonthButton: (props) => (
98
+ <Button variant="text" size="sm" iconOnly {...props}>
99
+ <IconChevronLeft size="sm" />
100
+ </Button>
101
+ ),
102
+ NextMonthButton: (props) => (
103
+ <Button variant="text" size="sm" iconOnly {...props}>
104
+ <IconChevronRight size="sm" />
105
+ </Button>
106
+ ),
107
+ }}
108
+ />
109
+ );
110
+ };
111
+
112
+ Calendar.displayName = "Calendar";
@@ -0,0 +1,4 @@
1
+ declare module "*.scss" {
2
+ const styles: { [className: string]: string };
3
+ export default styles;
4
+ }